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
markChildren(MarkStack & markStack)46 void Arguments::markChildren(MarkStack& markStack)
47 {
48 JSObject::markChildren(markStack);
49
50 if (d->registerArray)
51 markStack.appendValues(d->registerArray.get(), d->numParameters);
52
53 if (d->extraArguments) {
54 unsigned numExtraArguments = d->numArguments - d->numParameters;
55 markStack.appendValues(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].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