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 
32 using namespace std;
33 
34 namespace JSC {
35 
36 ASSERT_CLASS_FITS_IN_CELL(Arguments);
37 
38 const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0 };
39 
~Arguments()40 Arguments::~Arguments()
41 {
42     if (d->extraArguments != d->extraArgumentsFixedBuffer)
43         delete [] d->extraArguments;
44 }
45 
visitChildren(SlotVisitor & visitor)46 void Arguments::visitChildren(SlotVisitor& visitor)
47 {
48     JSObject::visitChildren(visitor);
49 
50     if (d->registerArray)
51         visitor.appendValues(d->registerArray.get(), d->numParameters);
52 
53     if (d->extraArguments) {
54         unsigned numExtraArguments = d->numArguments - d->numParameters;
55         visitor.appendValues(d->extraArguments, numExtraArguments);
56     }
57 
58     visitor.append(&d->callee);
59 
60     if (d->activation)
61         visitor.append(&d->activation);
62 }
63 
copyToRegisters(ExecState * exec,Register * buffer,uint32_t maxSize)64 void Arguments::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize)
65 {
66     if (UNLIKELY(d->overrodeLength)) {
67         unsigned length = min(get(exec, exec->propertyNames().length).toUInt32(exec), maxSize);
68         for (unsigned i = 0; i < length; i++)
69             buffer[i] = get(exec, i);
70         return;
71     }
72 
73     if (LIKELY(!d->deletedArguments)) {
74         unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize);
75         unsigned i = 0;
76         for (; i < parametersLength; ++i)
77             buffer[i] = d->registers[d->firstParameterIndex + i].get();
78         for (; i < d->numArguments; ++i)
79             buffer[i] = d->extraArguments[i - d->numParameters].get();
80         return;
81     }
82 
83     unsigned parametersLength = min(min(d->numParameters, d->numArguments), maxSize);
84     unsigned i = 0;
85     for (; i < parametersLength; ++i) {
86         if (!d->deletedArguments[i])
87             buffer[i] = d->registers[d->firstParameterIndex + i].get();
88         else
89             buffer[i] = get(exec, i);
90     }
91     for (; i < d->numArguments; ++i) {
92         if (!d->deletedArguments[i])
93             buffer[i] = d->extraArguments[i - d->numParameters].get();
94         else
95             buffer[i] = get(exec, i);
96     }
97 }
98 
fillArgList(ExecState * exec,MarkedArgumentBuffer & args)99 void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
100 {
101     if (UNLIKELY(d->overrodeLength)) {
102         unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec);
103         for (unsigned i = 0; i < length; i++)
104             args.append(get(exec, i));
105         return;
106     }
107 
108     if (LIKELY(!d->deletedArguments)) {
109         if (LIKELY(!d->numParameters)) {
110             args.initialize(d->extraArguments, d->numArguments);
111             return;
112         }
113 
114         if (d->numParameters == d->numArguments) {
115             args.initialize(&d->registers[d->firstParameterIndex], d->numArguments);
116             return;
117         }
118 
119         unsigned parametersLength = min(d->numParameters, d->numArguments);
120         unsigned i = 0;
121         for (; i < parametersLength; ++i)
122             args.append(d->registers[d->firstParameterIndex + i].get());
123         for (; i < d->numArguments; ++i)
124             args.append(d->extraArguments[i - d->numParameters].get());
125         return;
126     }
127 
128     unsigned parametersLength = min(d->numParameters, d->numArguments);
129     unsigned i = 0;
130     for (; i < parametersLength; ++i) {
131         if (!d->deletedArguments[i])
132             args.append(d->registers[d->firstParameterIndex + i].get());
133         else
134             args.append(get(exec, i));
135     }
136     for (; i < d->numArguments; ++i) {
137         if (!d->deletedArguments[i])
138             args.append(d->extraArguments[i - d->numParameters].get());
139         else
140             args.append(get(exec, i));
141     }
142 }
143 
getOwnPropertySlot(ExecState * exec,unsigned i,PropertySlot & slot)144 bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
145 {
146     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
147         if (i < d->numParameters) {
148             slot.setValue(d->registers[d->firstParameterIndex + i].get());
149         } else
150             slot.setValue(d->extraArguments[i - d->numParameters].get());
151         return true;
152     }
153 
154     return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::number(i)), slot);
155 }
156 
createStrictModeCallerIfNecessary(ExecState * exec)157 void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
158 {
159     if (d->overrodeCaller)
160         return;
161 
162     d->overrodeCaller = true;
163     PropertyDescriptor descriptor;
164     JSValue thrower = createTypeErrorFunction(exec, "Unable to access caller of strict mode function");
165     descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
166     defineOwnProperty(exec, exec->propertyNames().caller, descriptor, false);
167 }
168 
createStrictModeCalleeIfNecessary(ExecState * exec)169 void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
170 {
171     if (d->overrodeCallee)
172         return;
173 
174     d->overrodeCallee = true;
175     PropertyDescriptor descriptor;
176     JSValue thrower = createTypeErrorFunction(exec, "Unable to access callee of strict mode function");
177     descriptor.setAccessorDescriptor(thrower, thrower, DontEnum | DontDelete | Getter | Setter);
178     defineOwnProperty(exec, exec->propertyNames().callee, descriptor, false);
179 }
180 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)181 bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
182 {
183     bool isArrayIndex;
184     unsigned i = propertyName.toArrayIndex(isArrayIndex);
185     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
186         if (i < d->numParameters) {
187             slot.setValue(d->registers[d->firstParameterIndex + i].get());
188         } else
189             slot.setValue(d->extraArguments[i - d->numParameters].get());
190         return true;
191     }
192 
193     if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
194         slot.setValue(jsNumber(d->numArguments));
195         return true;
196     }
197 
198     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
199         if (!d->isStrictMode) {
200             slot.setValue(d->callee.get());
201             return true;
202         }
203         createStrictModeCalleeIfNecessary(exec);
204     }
205 
206     if (propertyName == exec->propertyNames().caller && d->isStrictMode)
207         createStrictModeCallerIfNecessary(exec);
208 
209     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
210 }
211 
getOwnPropertyDescriptor(ExecState * exec,const Identifier & propertyName,PropertyDescriptor & descriptor)212 bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
213 {
214     bool isArrayIndex;
215     unsigned i = propertyName.toArrayIndex(isArrayIndex);
216     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
217         if (i < d->numParameters) {
218             descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].get(), DontEnum);
219         } else
220             descriptor.setDescriptor(d->extraArguments[i - d->numParameters].get(), DontEnum);
221         return true;
222     }
223 
224     if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
225         descriptor.setDescriptor(jsNumber(d->numArguments), DontEnum);
226         return true;
227     }
228 
229     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
230         if (!d->isStrictMode) {
231             descriptor.setDescriptor(d->callee.get(), DontEnum);
232             return true;
233         }
234         createStrictModeCalleeIfNecessary(exec);
235     }
236 
237     if (propertyName == exec->propertyNames().caller && d->isStrictMode)
238         createStrictModeCallerIfNecessary(exec);
239 
240     return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
241 }
242 
getOwnPropertyNames(ExecState * exec,PropertyNameArray & propertyNames,EnumerationMode mode)243 void Arguments::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
244 {
245     if (mode == IncludeDontEnumProperties) {
246         for (unsigned i = 0; i < d->numArguments; ++i) {
247             if (!d->deletedArguments || !d->deletedArguments[i])
248                 propertyNames.add(Identifier(exec, UString::number(i)));
249         }
250         propertyNames.add(exec->propertyNames().callee);
251         propertyNames.add(exec->propertyNames().length);
252     }
253     JSObject::getOwnPropertyNames(exec, propertyNames, mode);
254 }
255 
put(ExecState * exec,unsigned i,JSValue value)256 void Arguments::put(ExecState* exec, unsigned i, JSValue value)
257 {
258     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
259         if (i < d->numParameters)
260             d->registers[d->firstParameterIndex + i].set(exec->globalData(), d->activation ? static_cast<JSCell*>(d->activation.get()) : static_cast<JSCell*>(this), value);
261         else
262             d->extraArguments[i - d->numParameters].set(exec->globalData(), this, value);
263         return;
264     }
265 
266     PutPropertySlot slot;
267     JSObject::put(exec, Identifier(exec, UString::number(i)), value, slot);
268 }
269 
put(ExecState * exec,const Identifier & propertyName,JSValue value,PutPropertySlot & slot)270 void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
271 {
272     bool isArrayIndex;
273     unsigned i = propertyName.toArrayIndex(isArrayIndex);
274     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
275         if (i < d->numParameters)
276             d->registers[d->firstParameterIndex + i].set(exec->globalData(), d->activation ? static_cast<JSCell*>(d->activation.get()) : static_cast<JSCell*>(this), value);
277         else
278             d->extraArguments[i - d->numParameters].set(exec->globalData(), this, value);
279         return;
280     }
281 
282     if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
283         d->overrodeLength = true;
284         putDirect(exec->globalData(), propertyName, value, DontEnum);
285         return;
286     }
287 
288     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
289         if (!d->isStrictMode) {
290             d->overrodeCallee = true;
291             putDirect(exec->globalData(), propertyName, value, DontEnum);
292             return;
293         }
294         createStrictModeCalleeIfNecessary(exec);
295     }
296 
297     if (propertyName == exec->propertyNames().caller && d->isStrictMode)
298         createStrictModeCallerIfNecessary(exec);
299 
300     JSObject::put(exec, propertyName, value, slot);
301 }
302 
deleteProperty(ExecState * exec,unsigned i)303 bool Arguments::deleteProperty(ExecState* exec, unsigned i)
304 {
305     if (i < d->numArguments) {
306         if (!d->deletedArguments) {
307             d->deletedArguments = adoptArrayPtr(new bool[d->numArguments]);
308             memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
309         }
310         if (!d->deletedArguments[i]) {
311             d->deletedArguments[i] = true;
312             return true;
313         }
314     }
315 
316     return JSObject::deleteProperty(exec, Identifier(exec, UString::number(i)));
317 }
318 
deleteProperty(ExecState * exec,const Identifier & propertyName)319 bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
320 {
321     bool isArrayIndex;
322     unsigned i = propertyName.toArrayIndex(isArrayIndex);
323     if (isArrayIndex && i < d->numArguments) {
324         if (!d->deletedArguments) {
325             d->deletedArguments = adoptArrayPtr(new bool[d->numArguments]);
326             memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
327         }
328         if (!d->deletedArguments[i]) {
329             d->deletedArguments[i] = true;
330             return true;
331         }
332     }
333 
334     if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
335         d->overrodeLength = true;
336         return true;
337     }
338 
339     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
340         if (!d->isStrictMode) {
341             d->overrodeCallee = true;
342             return true;
343         }
344         createStrictModeCalleeIfNecessary(exec);
345     }
346 
347     if (propertyName == exec->propertyNames().caller && !d->isStrictMode)
348         createStrictModeCallerIfNecessary(exec);
349 
350     return JSObject::deleteProperty(exec, propertyName);
351 }
352 
353 } // namespace JSC
354