• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::info = { "Arguments", 0, 0, 0 };
39 
~Arguments()40 Arguments::~Arguments()
41 {
42     if (d->extraArguments != d->extraArgumentsFixedBuffer)
43         delete [] d->extraArguments;
44 }
45 
markChildren(MarkStack & markStack)46 void Arguments::markChildren(MarkStack& markStack)
47 {
48     JSObject::markChildren(markStack);
49 
50     if (d->registerArray)
51         markStack.appendValues(reinterpret_cast<JSValue*>(d->registerArray.get()), d->numParameters);
52 
53     if (d->extraArguments) {
54         unsigned numExtraArguments = d->numArguments - d->numParameters;
55         markStack.appendValues(reinterpret_cast<JSValue*>(d->extraArguments), numExtraArguments);
56     }
57 
58     markStack.append(d->callee);
59 
60     if (d->activation)
61         markStack.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].jsValue();
78         for (; i < d->numArguments; ++i)
79             buffer[i] = d->extraArguments[i - d->numParameters].jsValue();
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].jsValue();
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].jsValue();
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].jsValue());
123         for (; i < d->numArguments; ++i)
124             args.append(d->extraArguments[i - d->numParameters].jsValue());
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].jsValue());
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].jsValue());
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.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
149         } else
150             slot.setValue(d->extraArguments[i - d->numParameters].jsValue());
151         return true;
152     }
153 
154     return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::from(i)), slot);
155 }
156 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)157 bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
158 {
159     bool isArrayIndex;
160     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
161     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
162         if (i < d->numParameters) {
163             slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
164         } else
165             slot.setValue(d->extraArguments[i - d->numParameters].jsValue());
166         return true;
167     }
168 
169     if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
170         slot.setValue(jsNumber(exec, d->numArguments));
171         return true;
172     }
173 
174     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
175         slot.setValue(d->callee);
176         return true;
177     }
178 
179     return JSObject::getOwnPropertySlot(exec, propertyName, slot);
180 }
181 
getOwnPropertyDescriptor(ExecState * exec,const Identifier & propertyName,PropertyDescriptor & descriptor)182 bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
183 {
184     bool isArrayIndex;
185     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
186     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
187         if (i < d->numParameters) {
188             descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].jsValue(), DontEnum);
189         } else
190             descriptor.setDescriptor(d->extraArguments[i - d->numParameters].jsValue(), DontEnum);
191         return true;
192     }
193 
194     if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
195         descriptor.setDescriptor(jsNumber(exec, d->numArguments), DontEnum);
196         return true;
197     }
198 
199     if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
200         descriptor.setDescriptor(d->callee, DontEnum);
201         return true;
202     }
203 
204     return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
205 }
206 
getOwnPropertyNames(ExecState * exec,PropertyNameArray & propertyNames,EnumerationMode mode)207 void Arguments::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
208 {
209     if (mode == IncludeDontEnumProperties) {
210         for (unsigned i = 0; i < d->numArguments; ++i) {
211             if (!d->deletedArguments || !d->deletedArguments[i])
212                 propertyNames.add(Identifier(exec, UString::from(i)));
213         }
214         propertyNames.add(exec->propertyNames().callee);
215         propertyNames.add(exec->propertyNames().length);
216     }
217     JSObject::getOwnPropertyNames(exec, propertyNames, mode);
218 }
219 
put(ExecState * exec,unsigned i,JSValue value,PutPropertySlot & slot)220 void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot& slot)
221 {
222     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
223         if (i < d->numParameters)
224             d->registers[d->firstParameterIndex + i] = JSValue(value);
225         else
226             d->extraArguments[i - d->numParameters] = JSValue(value);
227         return;
228     }
229 
230     JSObject::put(exec, Identifier(exec, UString::from(i)), value, slot);
231 }
232 
put(ExecState * exec,const Identifier & propertyName,JSValue value,PutPropertySlot & slot)233 void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
234 {
235     bool isArrayIndex;
236     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
237     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
238         if (i < d->numParameters)
239             d->registers[d->firstParameterIndex + i] = JSValue(value);
240         else
241             d->extraArguments[i - d->numParameters] = JSValue(value);
242         return;
243     }
244 
245     if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
246         d->overrodeLength = true;
247         putDirect(propertyName, value, DontEnum);
248         return;
249     }
250 
251     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
252         d->overrodeCallee = true;
253         putDirect(propertyName, value, DontEnum);
254         return;
255     }
256 
257     JSObject::put(exec, propertyName, value, slot);
258 }
259 
deleteProperty(ExecState * exec,unsigned i)260 bool Arguments::deleteProperty(ExecState* exec, unsigned i)
261 {
262     if (i < d->numArguments) {
263         if (!d->deletedArguments) {
264             d->deletedArguments.set(new bool[d->numArguments]);
265             memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
266         }
267         if (!d->deletedArguments[i]) {
268             d->deletedArguments[i] = true;
269             return true;
270         }
271     }
272 
273     return JSObject::deleteProperty(exec, Identifier(exec, UString::from(i)));
274 }
275 
deleteProperty(ExecState * exec,const Identifier & propertyName)276 bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
277 {
278     bool isArrayIndex;
279     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
280     if (isArrayIndex && i < d->numArguments) {
281         if (!d->deletedArguments) {
282             d->deletedArguments.set(new bool[d->numArguments]);
283             memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
284         }
285         if (!d->deletedArguments[i]) {
286             d->deletedArguments[i] = true;
287             return true;
288         }
289     }
290 
291     if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
292         d->overrodeLength = true;
293         return true;
294     }
295 
296     if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
297         d->overrodeCallee = true;
298         return true;
299     }
300 
301     return JSObject::deleteProperty(exec, propertyName);
302 }
303 
304 } // namespace JSC
305