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