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 = { .className: "Arguments" , .parentClass: 0, .staticPropHashTable: 0, .classPropHashTableGetterFunction: 0 }; |
39 | |
40 | Arguments::~Arguments() |
41 | { |
42 | if (d->extraArguments != d->extraArgumentsFixedBuffer) |
43 | delete [] d->extraArguments; |
44 | } |
45 | |
46 | void Arguments::markChildren(MarkStack& markStack) |
47 | { |
48 | JSObject::markChildren(markStack); |
49 | |
50 | if (d->registerArray) |
51 | markStack.appendValues(values: reinterpret_cast<JSValue*>(d->registerArray.get()), count: d->numParameters); |
52 | |
53 | if (d->extraArguments) { |
54 | unsigned = d->numArguments - d->numParameters; |
55 | markStack.appendValues(values: reinterpret_cast<JSValue*>(d->extraArguments), count: numExtraArguments); |
56 | } |
57 | |
58 | markStack.append(cell: d->callee); |
59 | |
60 | if (d->activation) |
61 | markStack.append(cell: d->activation); |
62 | } |
63 | |
64 | void Arguments::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSize) |
65 | { |
66 | if (UNLIKELY(d->overrodeLength)) { |
67 | unsigned length = min(a: get(exec, propertyName: exec->propertyNames().length).toUInt32(exec), b: maxSize); |
68 | for (unsigned i = 0; i < length; i++) |
69 | buffer[i] = get(exec, propertyName: i); |
70 | return; |
71 | } |
72 | |
73 | if (LIKELY(!d->deletedArguments)) { |
74 | unsigned parametersLength = min(a: min(a: d->numParameters, b: d->numArguments), b: 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(a: min(a: d->numParameters, b: d->numArguments), b: 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, propertyName: 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, propertyName: i); |
96 | } |
97 | } |
98 | |
99 | void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) |
100 | { |
101 | if (UNLIKELY(d->overrodeLength)) { |
102 | unsigned length = get(exec, propertyName: exec->propertyNames().length).toUInt32(exec); |
103 | for (unsigned i = 0; i < length; i++) |
104 | args.append(v: get(exec, propertyName: i)); |
105 | return; |
106 | } |
107 | |
108 | if (LIKELY(!d->deletedArguments)) { |
109 | if (LIKELY(!d->numParameters)) { |
110 | args.initialize(buffer: d->extraArguments, size: d->numArguments); |
111 | return; |
112 | } |
113 | |
114 | if (d->numParameters == d->numArguments) { |
115 | args.initialize(buffer: &d->registers[d->firstParameterIndex], size: d->numArguments); |
116 | return; |
117 | } |
118 | |
119 | unsigned parametersLength = min(a: d->numParameters, b: d->numArguments); |
120 | unsigned i = 0; |
121 | for (; i < parametersLength; ++i) |
122 | args.append(v: d->registers[d->firstParameterIndex + i].jsValue()); |
123 | for (; i < d->numArguments; ++i) |
124 | args.append(v: d->extraArguments[i - d->numParameters].jsValue()); |
125 | return; |
126 | } |
127 | |
128 | unsigned parametersLength = min(a: d->numParameters, b: d->numArguments); |
129 | unsigned i = 0; |
130 | for (; i < parametersLength; ++i) { |
131 | if (!d->deletedArguments[i]) |
132 | args.append(v: d->registers[d->firstParameterIndex + i].jsValue()); |
133 | else |
134 | args.append(v: get(exec, propertyName: i)); |
135 | } |
136 | for (; i < d->numArguments; ++i) { |
137 | if (!d->deletedArguments[i]) |
138 | args.append(v: d->extraArguments[i - d->numParameters].jsValue()); |
139 | else |
140 | args.append(v: get(exec, propertyName: i)); |
141 | } |
142 | } |
143 | |
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, propertyName: Identifier(exec, UString::from(i)), slot); |
155 | } |
156 | |
157 | bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) |
158 | { |
159 | bool isArrayIndex; |
160 | unsigned i = propertyName.toArrayIndex(ok: &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, i: 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 | |
182 | bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) |
183 | { |
184 | bool isArrayIndex; |
185 | unsigned i = propertyName.toArrayIndex(ok: &isArrayIndex); |
186 | if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { |
187 | if (i < d->numParameters) { |
188 | descriptor.setDescriptor(value: d->registers[d->firstParameterIndex + i].jsValue(), attributes: DontEnum); |
189 | } else |
190 | descriptor.setDescriptor(value: d->extraArguments[i - d->numParameters].jsValue(), attributes: DontEnum); |
191 | return true; |
192 | } |
193 | |
194 | if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) { |
195 | descriptor.setDescriptor(value: jsNumber(exec, i: d->numArguments), attributes: DontEnum); |
196 | return true; |
197 | } |
198 | |
199 | if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) { |
200 | descriptor.setDescriptor(value: d->callee, attributes: DontEnum); |
201 | return true; |
202 | } |
203 | |
204 | return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); |
205 | } |
206 | |
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: Identifier(exec, UString::from(i))); |
213 | } |
214 | propertyNames.add(identifier: exec->propertyNames().callee); |
215 | propertyNames.add(identifier: exec->propertyNames().length); |
216 | } |
217 | JSObject::getOwnPropertyNames(exec, propertyNames, mode); |
218 | } |
219 | |
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, propertyName: Identifier(exec, UString::from(i)), value, slot); |
231 | } |
232 | |
233 | void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) |
234 | { |
235 | bool isArrayIndex; |
236 | unsigned i = propertyName.toArrayIndex(ok: &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, attributes: DontEnum); |
248 | return; |
249 | } |
250 | |
251 | if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) { |
252 | d->overrodeCallee = true; |
253 | putDirect(propertyName, value, attributes: DontEnum); |
254 | return; |
255 | } |
256 | |
257 | JSObject::put(exec, propertyName, value, slot); |
258 | } |
259 | |
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(s: d->deletedArguments.get(), c: 0, n: 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, propertyName: Identifier(exec, UString::from(i))); |
274 | } |
275 | |
276 | bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName) |
277 | { |
278 | bool isArrayIndex; |
279 | unsigned i = propertyName.toArrayIndex(ok: &isArrayIndex); |
280 | if (isArrayIndex && i < d->numArguments) { |
281 | if (!d->deletedArguments) { |
282 | d->deletedArguments.set(new bool[d->numArguments]); |
283 | memset(s: d->deletedArguments.get(), c: 0, n: 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 | |