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