]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/Arguments.cpp
JavaScriptCore-7600.1.4.11.8.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
81345200 28#include "CopyVisitorInlines.h"
9dae56ea 29#include "JSActivation.h"
81345200 30#include "JSArgumentsIterator.h"
9dae56ea
A
31#include "JSFunction.h"
32#include "JSGlobalObject.h"
81345200 33#include "JSCInlines.h"
9dae56ea
A
34
35using namespace std;
36
37namespace JSC {
38
81345200
A
39STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(Arguments);
40
93a37866 41const ClassInfo Arguments::s_info = { "Arguments", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) };
9dae56ea 42
6fe7ccc8 43void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
9dae56ea 44{
6fe7ccc8 45 Arguments* thisObject = jsCast<Arguments*>(cell);
81345200 46 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
6fe7ccc8
A
47 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
48 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
49 JSObject::visitChildren(thisObject, visitor);
50
81345200
A
51 if (thisObject->m_registerArray) {
52 visitor.copyLater(thisObject, ArgumentsRegisterArrayCopyToken,
53 thisObject->m_registerArray.get(), thisObject->registerArraySizeInBytes());
93a37866 54 visitor.appendValues(thisObject->m_registerArray.get(), thisObject->m_numArguments);
81345200
A
55 }
56 if (thisObject->m_slowArgumentData) {
57 visitor.copyLater(thisObject, ArgumentsSlowArgumentDataCopyToken,
58 thisObject->m_slowArgumentData.get(), SlowArgumentData::sizeForNumArguments(thisObject->m_numArguments));
59 }
93a37866
A
60 visitor.append(&thisObject->m_callee);
61 visitor.append(&thisObject->m_activation);
9dae56ea
A
62}
63
81345200 64void Arguments::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token)
9dae56ea 65{
81345200
A
66 Arguments* thisObject = jsCast<Arguments*>(cell);
67 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
68
69
70 switch (token) {
71 case ArgumentsRegisterArrayCopyToken: {
72 WriteBarrier<Unknown>* registerArray = thisObject->m_registerArray.get();
73 if (!registerArray)
74 return;
75
76 if (visitor.checkIfShouldCopy(registerArray)) {
77 size_t bytes = thisObject->registerArraySizeInBytes();
78 WriteBarrier<Unknown>* newRegisterArray = static_cast<WriteBarrier<Unknown>*>(visitor.allocateNewSpace(bytes));
79 memcpy(newRegisterArray, registerArray, bytes);
80 thisObject->m_registerArray.setWithoutWriteBarrier(newRegisterArray);
81 thisObject->m_registers = newRegisterArray - CallFrame::offsetFor(1) - 1;
82 visitor.didCopy(registerArray, bytes);
83 }
84 return;
85 }
86
87 case ArgumentsSlowArgumentDataCopyToken: {
88 SlowArgumentData* slowArgumentData = thisObject->m_slowArgumentData.get();
89 if (!slowArgumentData)
90 return;
91
92 if (visitor.checkIfShouldCopy(slowArgumentData)) {
93 size_t bytes = SlowArgumentData::sizeForNumArguments(thisObject->m_numArguments);
94 SlowArgumentData* newSlowArgumentData = static_cast<SlowArgumentData*>(visitor.allocateNewSpace(bytes));
95 memcpy(newSlowArgumentData, slowArgumentData, bytes);
96 thisObject->m_slowArgumentData.setWithoutWriteBarrier(newSlowArgumentData);
97 visitor.didCopy(slowArgumentData, bytes);
98 }
99 return;
100 }
101
102 default:
103 return;
104 }
9dae56ea 105}
81345200
A
106
107static EncodedJSValue JSC_HOST_CALL argumentsFuncIterator(ExecState*);
9dae56ea 108
81345200 109void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t copyLength, int32_t firstVarArgOffset)
9dae56ea 110{
81345200
A
111 uint32_t length = copyLength + firstVarArgOffset;
112
93a37866 113 if (UNLIKELY(m_overrodeLength)) {
6fe7ccc8 114 length = min(get(exec, exec->propertyNames().length).toUInt32(exec), length);
81345200 115 for (unsigned i = firstVarArgOffset; i < length; i++)
6fe7ccc8 116 callFrame->setArgument(i, get(exec, i));
ba379fdc
A
117 return;
118 }
6fe7ccc8 119 ASSERT(length == this->length(exec));
81345200 120 for (size_t i = firstVarArgOffset; i < length; ++i) {
93a37866 121 if (JSValue value = tryGetArgument(i))
81345200 122 callFrame->setArgument(i - firstVarArgOffset, value);
ba379fdc 123 else
81345200 124 callFrame->setArgument(i - firstVarArgOffset, get(exec, i));
ba379fdc
A
125 }
126}
127
128void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
129{
93a37866 130 if (UNLIKELY(m_overrodeLength)) {
ba379fdc
A
131 unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec);
132 for (unsigned i = 0; i < length; i++)
133 args.append(get(exec, i));
134 return;
135 }
6fe7ccc8
A
136 uint32_t length = this->length(exec);
137 for (size_t i = 0; i < length; ++i) {
93a37866
A
138 if (JSValue value = tryGetArgument(i))
139 args.append(value);
9dae56ea
A
140 else
141 args.append(get(exec, i));
142 }
143}
144
81345200 145bool Arguments::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned i, PropertySlot& slot)
9dae56ea 146{
81345200 147 Arguments* thisObject = jsCast<Arguments*>(object);
93a37866 148 if (JSValue value = thisObject->tryGetArgument(i)) {
81345200 149 slot.setValue(thisObject, None, value);
9dae56ea
A
150 return true;
151 }
152
81345200 153 return JSObject::getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
14957cd0
A
154}
155
156void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
157{
93a37866 158 if (m_overrodeCaller)
14957cd0
A
159 return;
160
81345200 161 VM& vm = exec->vm();
93a37866 162 m_overrodeCaller = true;
14957cd0 163 PropertyDescriptor descriptor;
81345200
A
164 descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(vm), DontEnum | DontDelete | Accessor);
165 methodTable(exec->vm())->defineOwnProperty(this, exec, vm.propertyNames->caller, descriptor, false);
14957cd0
A
166}
167
168void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
169{
93a37866 170 if (m_overrodeCallee)
14957cd0 171 return;
81345200
A
172
173 VM& vm = exec->vm();
93a37866 174 m_overrodeCallee = true;
14957cd0 175 PropertyDescriptor descriptor;
81345200
A
176 descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(vm), DontEnum | DontDelete | Accessor);
177 methodTable(exec->vm())->defineOwnProperty(this, exec, vm.propertyNames->callee, descriptor, false);
9dae56ea
A
178}
179
81345200 180bool Arguments::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
9dae56ea 181{
81345200 182 Arguments* thisObject = jsCast<Arguments*>(object);
93a37866
A
183 unsigned i = propertyName.asIndex();
184 if (JSValue value = thisObject->tryGetArgument(i)) {
185 RELEASE_ASSERT(i < PropertyName::NotAnIndex);
81345200 186 slot.setValue(thisObject, None, value);
9dae56ea
A
187 return true;
188 }
189
93a37866 190 if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->m_overrodeLength)) {
81345200 191 slot.setValue(thisObject, DontEnum, jsNumber(thisObject->m_numArguments));
9dae56ea
A
192 return true;
193 }
194
93a37866
A
195 if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->m_overrodeCallee)) {
196 if (!thisObject->m_isStrictMode) {
81345200 197 slot.setValue(thisObject, DontEnum, thisObject->m_callee.get());
14957cd0
A
198 return true;
199 }
6fe7ccc8 200 thisObject->createStrictModeCalleeIfNecessary(exec);
9dae56ea
A
201 }
202
93a37866 203 if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode)
6fe7ccc8 204 thisObject->createStrictModeCallerIfNecessary(exec);
14957cd0 205
81345200 206 if (JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot))
f9bf01c6 207 return true;
81345200
A
208 if (propertyName == exec->propertyNames().iteratorPrivateName) {
209 VM& vm = exec->vm();
210 JSGlobalObject* globalObject = exec->lexicalGlobalObject();
211 thisObject->JSC_NATIVE_FUNCTION(exec->propertyNames().iteratorPrivateName, argumentsFuncIterator, DontEnum, 0);
212 if (JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot))
14957cd0 213 return true;
f9bf01c6 214 }
81345200 215 return false;
f9bf01c6
A
216}
217
6fe7ccc8 218void Arguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
f9bf01c6 219{
6fe7ccc8 220 Arguments* thisObject = jsCast<Arguments*>(object);
93a37866
A
221 for (unsigned i = 0; i < thisObject->m_numArguments; ++i) {
222 if (!thisObject->isArgument(i))
223 continue;
81345200 224 propertyNames.add(Identifier::from(exec, i));
6fe7ccc8 225 }
f9bf01c6 226 if (mode == IncludeDontEnumProperties) {
f9bf01c6
A
227 propertyNames.add(exec->propertyNames().callee);
228 propertyNames.add(exec->propertyNames().length);
229 }
6fe7ccc8 230 JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
f9bf01c6
A
231}
232
6fe7ccc8 233void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value, bool shouldThrow)
9dae56ea 234{
6fe7ccc8 235 Arguments* thisObject = jsCast<Arguments*>(cell);
93a37866 236 if (thisObject->trySetArgument(exec->vm(), i, value))
9dae56ea 237 return;
9dae56ea 238
81345200
A
239 PutPropertySlot slot(thisObject, shouldThrow);
240 JSObject::put(thisObject, exec, Identifier::from(exec, i), value, slot);
9dae56ea
A
241}
242
93a37866 243void Arguments::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
9dae56ea 244{
6fe7ccc8 245 Arguments* thisObject = jsCast<Arguments*>(cell);
93a37866
A
246 unsigned i = propertyName.asIndex();
247 if (thisObject->trySetArgument(exec->vm(), i, value))
9dae56ea 248 return;
9dae56ea 249
93a37866
A
250 if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) {
251 thisObject->m_overrodeLength = true;
252 thisObject->putDirect(exec->vm(), propertyName, value, DontEnum);
9dae56ea
A
253 return;
254 }
255
93a37866
A
256 if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) {
257 if (!thisObject->m_isStrictMode) {
258 thisObject->m_overrodeCallee = true;
259 thisObject->putDirect(exec->vm(), propertyName, value, DontEnum);
14957cd0
A
260 return;
261 }
6fe7ccc8 262 thisObject->createStrictModeCalleeIfNecessary(exec);
9dae56ea
A
263 }
264
93a37866 265 if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode)
6fe7ccc8 266 thisObject->createStrictModeCallerIfNecessary(exec);
14957cd0 267
6fe7ccc8 268 JSObject::put(thisObject, exec, propertyName, value, slot);
9dae56ea
A
269}
270
6fe7ccc8 271bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
9dae56ea 272{
6fe7ccc8 273 Arguments* thisObject = jsCast<Arguments*>(cell);
93a37866 274 if (i < thisObject->m_numArguments) {
6fe7ccc8
A
275 if (!Base::deletePropertyByIndex(cell, exec, i))
276 return false;
81345200 277 if (thisObject->tryDeleteArgument(exec->vm(), i))
9dae56ea 278 return true;
9dae56ea 279 }
93a37866 280 return JSObject::deletePropertyByIndex(thisObject, exec, i);
9dae56ea
A
281}
282
93a37866 283bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
9dae56ea 284{
93a37866 285 if (exec->vm().isInDefineOwnProperty())
6fe7ccc8
A
286 return Base::deleteProperty(cell, exec, propertyName);
287
288 Arguments* thisObject = jsCast<Arguments*>(cell);
93a37866
A
289 unsigned i = propertyName.asIndex();
290 if (i < thisObject->m_numArguments) {
291 RELEASE_ASSERT(i < PropertyName::NotAnIndex);
6fe7ccc8
A
292 if (!Base::deleteProperty(cell, exec, propertyName))
293 return false;
81345200 294 if (thisObject->tryDeleteArgument(exec->vm(), i))
9dae56ea 295 return true;
9dae56ea
A
296 }
297
93a37866
A
298 if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) {
299 thisObject->m_overrodeLength = true;
9dae56ea
A
300 return true;
301 }
302
93a37866
A
303 if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) {
304 if (!thisObject->m_isStrictMode) {
305 thisObject->m_overrodeCallee = true;
14957cd0
A
306 return true;
307 }
6fe7ccc8 308 thisObject->createStrictModeCalleeIfNecessary(exec);
9dae56ea 309 }
14957cd0 310
93a37866 311 if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode)
6fe7ccc8
A
312 thisObject->createStrictModeCallerIfNecessary(exec);
313
314 return JSObject::deleteProperty(thisObject, exec, propertyName);
315}
316
81345200 317bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
6fe7ccc8
A
318{
319 Arguments* thisObject = jsCast<Arguments*>(object);
93a37866
A
320 unsigned i = propertyName.asIndex();
321 if (i < thisObject->m_numArguments) {
322 RELEASE_ASSERT(i < PropertyName::NotAnIndex);
6fe7ccc8 323 // If the property is not yet present on the object, and is not yet marked as deleted, then add it now.
81345200 324 PropertySlot slot(thisObject);
93a37866
A
325 if (!thisObject->isDeletedArgument(i) && !JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) {
326 JSValue value = thisObject->tryGetArgument(i);
327 ASSERT(value);
328 object->putDirectMayBeIndex(exec, propertyName, value);
329 }
6fe7ccc8
A
330 if (!Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow))
331 return false;
332
6fe7ccc8
A
333 // From ES 5.1, 10.6 Arguments Object
334 // 5. If the value of isMapped is not undefined, then
93a37866 335 if (thisObject->isArgument(i)) {
6fe7ccc8
A
336 // a. If IsAccessorDescriptor(Desc) is true, then
337 if (descriptor.isAccessorDescriptor()) {
338 // i. Call the [[Delete]] internal method of map passing P, and false as the arguments.
81345200 339 thisObject->tryDeleteArgument(exec->vm(), i);
6fe7ccc8
A
340 } else { // b. Else
341 // i. If Desc.[[Value]] is present, then
342 // 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments.
343 if (descriptor.value())
93a37866 344 thisObject->trySetArgument(exec->vm(), i, descriptor.value());
6fe7ccc8
A
345 // ii. If Desc.[[Writable]] is present and its value is false, then
346 // 1. Call the [[Delete]] internal method of map passing P and false as arguments.
347 if (descriptor.writablePresent() && !descriptor.writable())
81345200 348 thisObject->tryDeleteArgument(exec->vm(), i);
6fe7ccc8
A
349 }
350 }
351 return true;
352 }
9dae56ea 353
93a37866
A
354 if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) {
355 thisObject->putDirect(exec->vm(), propertyName, jsNumber(thisObject->m_numArguments), DontEnum);
356 thisObject->m_overrodeLength = true;
357 } else if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) {
358 thisObject->putDirect(exec->vm(), propertyName, thisObject->m_callee.get(), DontEnum);
359 thisObject->m_overrodeCallee = true;
360 } else if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode)
6fe7ccc8
A
361 thisObject->createStrictModeCallerIfNecessary(exec);
362
363 return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
364}
365
81345200
A
366void Arguments::allocateRegisterArray(VM& vm)
367{
368 ASSERT(!m_registerArray);
369 void* backingStore;
370 if (!vm.heap.tryAllocateStorage(this, registerArraySizeInBytes(), &backingStore))
371 RELEASE_ASSERT_NOT_REACHED();
372 m_registerArray.set(vm, this, static_cast<WriteBarrier<Unknown>*>(backingStore));
373}
374
6fe7ccc8
A
375void Arguments::tearOff(CallFrame* callFrame)
376{
377 if (isTornOff())
378 return;
379
93a37866 380 if (!m_numArguments)
6fe7ccc8
A
381 return;
382
93a37866
A
383 // Must be called for the same call frame from which it was created.
384 ASSERT(bitwise_cast<WriteBarrier<Unknown>*>(callFrame) == m_registers);
385
81345200
A
386 allocateRegisterArray(callFrame->vm());
387 m_registers = m_registerArray.get() - CallFrame::offsetFor(1) - 1;
93a37866
A
388
389 // If we have a captured argument that logically aliases activation storage,
390 // but we optimize away the activation, the argument needs to tear off into
391 // our storage. The simplest way to do this is to revert it to Normal status.
81345200 392 if (m_slowArgumentData && !m_activation) {
93a37866 393 for (size_t i = 0; i < m_numArguments; ++i) {
81345200 394 if (m_slowArgumentData->slowArguments()[i].status != SlowArgument::Captured)
93a37866 395 continue;
81345200
A
396 m_slowArgumentData->slowArguments()[i].status = SlowArgument::Normal;
397 m_slowArgumentData->slowArguments()[i].index = CallFrame::argumentOffset(i);
93a37866
A
398 }
399 }
6fe7ccc8 400
81345200
A
401 for (size_t i = 0; i < m_numArguments; ++i)
402 trySetArgument(callFrame->vm(), i, callFrame->argumentAfterCapture(i));
93a37866
A
403}
404
405void Arguments::didTearOffActivation(ExecState* exec, JSActivation* activation)
406{
407 RELEASE_ASSERT(activation);
408 if (isTornOff())
409 return;
410
411 if (!m_numArguments)
412 return;
413
414 m_activation.set(exec->vm(), this, activation);
415 tearOff(exec);
416}
417
418void Arguments::tearOff(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
419{
420 if (isTornOff())
421 return;
422
423 if (!m_numArguments)
424 return;
425
81345200
A
426 allocateRegisterArray(callFrame->vm());
427 m_registers = m_registerArray.get() - CallFrame::offsetFor(1) - 1;
93a37866 428
93a37866 429 for (size_t i = 0; i < m_numArguments; ++i) {
6fe7ccc8 430 ValueRecovery& recovery = inlineCallFrame->arguments[i + 1];
81345200 431 trySetArgument(callFrame->vm(), i, recovery.recover(callFrame));
6fe7ccc8 432 }
9dae56ea 433}
81345200
A
434
435EncodedJSValue JSC_HOST_CALL argumentsFuncIterator(ExecState* exec)
436{
437 JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
438 Arguments* arguments = jsDynamicCast<Arguments*>(thisObj);
439 if (!arguments)
440 return JSValue::encode(throwTypeError(exec, "Attempted to use Arguments iterator on non-Arguments object"));
441 return JSValue::encode(JSArgumentsIterator::create(exec->vm(), exec->callee()->globalObject()->argumentsIteratorStructure(), arguments));
442}
443
9dae56ea
A
444
445} // namespace JSC