source: webkit/trunk/JavaScriptCore/runtime/Arguments.cpp@ 47780

Last change on this file since 47780 was 47780, checked in by [email protected], 16 years ago

[ES5] Implement getOwnPropertyDescriptor
https://bugs.webkit.org/show_bug.cgi?id=28724

Reviewed by Gavin Barraclough.

JavaScriptCore:
Implement the core runtime support for getOwnPropertyDescriptor.
This adds a virtual getOwnPropertyDescriptor method to every class
that implements getOwnPropertySlot that shadows the behaviour of
getOwnPropertySlot. The alternative would be to make getOwnPropertySlot
(or PropertySlots in general) provide property attribute information,
but quick testing showed this to be a regression.

WebCore:
Implement the WebCore side of getOwnPropertyDescriptor. This
requires a custom implementation of getOwnPropertyDescriptor
for every class with a custom implementation of getOwnPropertySlot.

The bindings generator has been updated to generate appropriate
versions of getOwnPropertyDescriptor for the general case where
a custom getOwnPropertyDescriptor is not needed. ES5 is vague
about how getOwnPropertyDescriptor should work in the context of
"host" functions with polymorphic GetOwnProperty, so it seems
okay that occasionally we "guess" what attributes -- eg. determining
whether a property is writable.

Test: fast/js/getOwnPropertyDescriptor.html

  • Property svn:eol-style set to native
File size: 9.8 KB
Line 
1/*
2 * Copyright (C) 1999-2002 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Cameron Zwarich ([email protected])
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
32using namespace std;
33
34namespace JSC {
35
36ASSERT_CLASS_FITS_IN_CELL(Arguments);
37
38const ClassInfo Arguments::info = { "Arguments", 0, 0, 0 };
39
40Arguments::~Arguments()
41{
42 if (d->extraArguments != d->extraArgumentsFixedBuffer)
43 delete [] d->extraArguments;
44}
45
46void 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
64void 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
99void 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
144bool 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
157bool 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
182bool 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
207void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot& slot)
208{
209 if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
210 if (i < d->numParameters)
211 d->registers[d->firstParameterIndex + i] = JSValue(value);
212 else
213 d->extraArguments[i - d->numParameters] = JSValue(value);
214 return;
215 }
216
217 JSObject::put(exec, Identifier(exec, UString::from(i)), value, slot);
218}
219
220void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
221{
222 bool isArrayIndex;
223 unsigned i = propertyName.toArrayIndex(&isArrayIndex);
224 if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
225 if (i < d->numParameters)
226 d->registers[d->firstParameterIndex + i] = JSValue(value);
227 else
228 d->extraArguments[i - d->numParameters] = JSValue(value);
229 return;
230 }
231
232 if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
233 d->overrodeLength = true;
234 putDirect(propertyName, value, DontEnum);
235 return;
236 }
237
238 if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
239 d->overrodeCallee = true;
240 putDirect(propertyName, value, DontEnum);
241 return;
242 }
243
244 JSObject::put(exec, propertyName, value, slot);
245}
246
247bool Arguments::deleteProperty(ExecState* exec, unsigned i)
248{
249 if (i < d->numArguments) {
250 if (!d->deletedArguments) {
251 d->deletedArguments.set(new bool[d->numArguments]);
252 memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
253 }
254 if (!d->deletedArguments[i]) {
255 d->deletedArguments[i] = true;
256 return true;
257 }
258 }
259
260 return JSObject::deleteProperty(exec, Identifier(exec, UString::from(i)));
261}
262
263bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
264{
265 bool isArrayIndex;
266 unsigned i = propertyName.toArrayIndex(&isArrayIndex);
267 if (isArrayIndex && i < d->numArguments) {
268 if (!d->deletedArguments) {
269 d->deletedArguments.set(new bool[d->numArguments]);
270 memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
271 }
272 if (!d->deletedArguments[i]) {
273 d->deletedArguments[i] = true;
274 return true;
275 }
276 }
277
278 if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
279 d->overrodeLength = true;
280 return true;
281 }
282
283 if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
284 d->overrodeCallee = true;
285 return true;
286 }
287
288 return JSObject::deleteProperty(exec, propertyName);
289}
290
291} // namespace JSC
Note: See TracBrowser for help on using the repository browser.