put_by_val_direct need to check the property is index or not for using putDirect...
[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     if (Optional<uint32_t> index = propertyName.asIndex()) {
165         if (JSValue value = thisObject->tryGetArgument(index.value())) {
166             slot.setValue(thisObject, None, value);
167             return true;
168         }
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     Optional<uint32_t> index = propertyName.asIndex();
228     if (index && thisObject->trySetArgument(exec->vm(), index.value(), 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     Optional<uint32_t> index = propertyName.asIndex();
271     if (index && index.value() < thisObject->m_numArguments) {
272         if (!Base::deleteProperty(cell, exec, propertyName))
273             return false;
274         if (thisObject->tryDeleteArgument(exec->vm(), index.value()))
275             return true;
276     }
277
278     if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) {
279         thisObject->m_overrodeLength = true;
280         return true;
281     }
282
283     if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) {
284         if (!thisObject->m_isStrictMode) {
285             thisObject->m_overrodeCallee = true;
286             return true;
287         }
288         thisObject->createStrictModeCalleeIfNecessary(exec);
289     }
290     
291     if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode)
292         thisObject->createStrictModeCallerIfNecessary(exec);
293
294     return JSObject::deleteProperty(thisObject, exec, propertyName);
295 }
296
297 bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow)
298 {
299     Arguments* thisObject = jsCast<Arguments*>(object);
300     Optional<uint32_t> optionalIndex = propertyName.asIndex();
301     if (optionalIndex && optionalIndex.value() < thisObject->m_numArguments) {
302         // If the property is not yet present on the object, and is not yet marked as deleted, then add it now.
303         uint32_t index = optionalIndex.value();
304         PropertySlot slot(thisObject);
305         if (!thisObject->isDeletedArgument(index) && !JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) {
306             JSValue value = thisObject->tryGetArgument(index);
307             ASSERT(value);
308             object->putDirectMayBeIndex(exec, propertyName, value);
309         }
310         if (!Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow))
311             return false;
312
313         // From ES 5.1, 10.6 Arguments Object
314         // 5. If the value of isMapped is not undefined, then
315         if (thisObject->isArgument(index)) {
316             // a. If IsAccessorDescriptor(Desc) is true, then
317             if (descriptor.isAccessorDescriptor()) {
318                 // i. Call the [[Delete]] internal method of map passing P, and false as the arguments.
319                 thisObject->tryDeleteArgument(exec->vm(), index);
320             } else { // b. Else
321                 // i. If Desc.[[Value]] is present, then
322                 // 1. Call the [[Put]] internal method of map passing P, Desc.[[Value]], and Throw as the arguments.
323                 if (descriptor.value())
324                     thisObject->trySetArgument(exec->vm(), index, descriptor.value());
325                 // ii. If Desc.[[Writable]] is present and its value is false, then
326                 // 1. Call the [[Delete]] internal method of map passing P and false as arguments.
327                 if (descriptor.writablePresent() && !descriptor.writable())
328                     thisObject->tryDeleteArgument(exec->vm(), index);
329             }
330         }
331         return true;
332     }
333
334     if (propertyName == exec->propertyNames().length && !thisObject->m_overrodeLength) {
335         thisObject->putDirect(exec->vm(), propertyName, jsNumber(thisObject->m_numArguments), DontEnum);
336         thisObject->m_overrodeLength = true;
337     } else if (propertyName == exec->propertyNames().callee && !thisObject->m_overrodeCallee) {
338         thisObject->putDirect(exec->vm(), propertyName, thisObject->m_callee.get(), DontEnum);
339         thisObject->m_overrodeCallee = true;
340     } else if (propertyName == exec->propertyNames().caller && thisObject->m_isStrictMode)
341         thisObject->createStrictModeCallerIfNecessary(exec);
342
343     return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
344 }
345
346 void Arguments::tearOff(CallFrame* callFrame)
347 {
348     if (isTornOff())
349         return;
350
351     if (!m_numArguments)
352         return;
353
354     // Must be called for the same call frame from which it was created.
355     ASSERT(bitwise_cast<WriteBarrier<Unknown>*>(callFrame) == m_registers);
356
357     m_registers = &registerArray() - CallFrame::offsetFor(1) - 1;
358
359     for (size_t i = 0; i < m_numArguments; ++i) {
360         if (m_slowArgumentData && m_slowArgumentData->slowArguments()[i].status == SlowArgument::Captured) {
361             m_registers[CallFrame::argumentOffset(i)].setUndefined();
362             continue;
363         }
364         trySetArgument(callFrame->vm(), i, callFrame->argumentAfterCapture(i));
365     }
366 }
367
368 void Arguments::tearOff(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
369 {
370     RELEASE_ASSERT(!inlineCallFrame->baselineCodeBlock()->needsActivation());
371     if (isTornOff())
372         return;
373     
374     if (!m_numArguments)
375         return;
376
377     m_registers = &registerArray() - CallFrame::offsetFor(1) - 1;
378
379     for (size_t i = 0; i < m_numArguments; ++i) {
380         ValueRecovery& recovery = inlineCallFrame->arguments[i + 1];
381         trySetArgument(callFrame->vm(), i, recovery.recover(callFrame));
382     }
383 }
384     
385 void Arguments::tearOffForCloning(CallFrame* callFrame)
386 {
387     ASSERT(!isTornOff());
388     
389     if (!m_numArguments)
390         return;
391     
392     // Must be called for the same call frame from which it was created.
393     ASSERT(bitwise_cast<WriteBarrier<Unknown>*>(callFrame) == m_registers);
394     
395     m_registers = &registerArray() - CallFrame::offsetFor(1) - 1;
396     
397     ASSERT(!m_slowArgumentData);
398     for (size_t i = 0; i < m_numArguments; ++i)
399         m_registers[CallFrame::argumentOffset(i)].set(callFrame->vm(), this, callFrame->argument(i));
400 }
401     
402 void Arguments::tearOffForCloning(CallFrame* callFrame, InlineCallFrame* inlineCallFrame)
403 {
404     RELEASE_ASSERT(!inlineCallFrame->baselineCodeBlock()->needsActivation());
405     ASSERT(!isTornOff());
406     
407     if (!m_numArguments)
408         return;
409     
410     m_registers = &registerArray() - CallFrame::offsetFor(1) - 1;
411     
412     ASSERT(!m_slowArgumentData);
413     for (size_t i = 0; i < m_numArguments; ++i) {
414         ValueRecovery& recovery = inlineCallFrame->arguments[i + 1];
415         m_registers[CallFrame::argumentOffset(i)].set(callFrame->vm(), this, recovery.recover(callFrame));
416     }
417 }
418
419 EncodedJSValue JSC_HOST_CALL argumentsFuncIterator(ExecState* exec)
420 {
421     JSObject* thisObj = exec->thisValue().toThis(exec, StrictMode).toObject(exec);
422     Arguments* arguments = jsDynamicCast<Arguments*>(thisObj);
423     if (!arguments)
424         return JSValue::encode(throwTypeError(exec, ASCIILiteral("Attempted to use Arguments iterator on non-Arguments object")));
425     return JSValue::encode(JSArgumentsIterator::create(exec->vm(), exec->callee()->globalObject()->argumentsIteratorStructure(), arguments));
426 }
427
428
429 } // namespace JSC