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
put(ExecState * exec,unsigned i,JSValue value,PutPropertySlot & slot)182 void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot& slot)
183 {
184 if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
185 if (i < d->numParameters)
186 d->registers[d->firstParameterIndex + i] = JSValue(value);
187 else
188 d->extraArguments[i - d->numParameters] = JSValue(value);
189 return;
190 }
191
192 JSObject::put(exec, Identifier(exec, UString::from(i)), value, slot);
193 }
194
put(ExecState * exec,const Identifier & propertyName,JSValue value,PutPropertySlot & slot)195 void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
196 {
197 bool isArrayIndex;
198 unsigned i = propertyName.toArrayIndex(&isArrayIndex);
199 if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
200 if (i < d->numParameters)
201 d->registers[d->firstParameterIndex + i] = JSValue(value);
202 else
203 d->extraArguments[i - d->numParameters] = JSValue(value);
204 return;
205 }
206
207 if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
208 d->overrodeLength = true;
209 putDirect(propertyName, value, DontEnum);
210 return;
211 }
212
213 if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
214 d->overrodeCallee = true;
215 putDirect(propertyName, value, DontEnum);
216 return;
217 }
218
219 JSObject::put(exec, propertyName, value, slot);
220 }
221
deleteProperty(ExecState * exec,unsigned i)222 bool Arguments::deleteProperty(ExecState* exec, unsigned i)
223 {
224 if (i < d->numArguments) {
225 if (!d->deletedArguments) {
226 d->deletedArguments.set(new bool[d->numArguments]);
227 memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
228 }
229 if (!d->deletedArguments[i]) {
230 d->deletedArguments[i] = true;
231 return true;
232 }
233 }
234
235 return JSObject::deleteProperty(exec, Identifier(exec, UString::from(i)));
236 }
237
deleteProperty(ExecState * exec,const Identifier & propertyName)238 bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
239 {
240 bool isArrayIndex;
241 unsigned i = propertyName.toArrayIndex(&isArrayIndex);
242 if (isArrayIndex && i < d->numArguments) {
243 if (!d->deletedArguments) {
244 d->deletedArguments.set(new bool[d->numArguments]);
245 memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
246 }
247 if (!d->deletedArguments[i]) {
248 d->deletedArguments[i] = true;
249 return true;
250 }
251 }
252
253 if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
254 d->overrodeLength = true;
255 return true;
256 }
257
258 if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
259 d->overrodeCallee = true;
260 return true;
261 }
262
263 return JSObject::deleteProperty(exec, propertyName);
264 }
265
266 } // namespace JSC
267