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

Last change on this file since 67583 was 65588, checked in by [email protected], 15 years ago

Bug 44146 - Remove toDouble/toUInt32 methods from UString.

Reviewed by Sam Weinig.

JavaScriptCore:

These methods all implement JavaScript language specific behaviour, and as such
are not suited to being on a generic string object. They are also inefficient
and incorrectly used, refactor & cleanup. Uses of these methods really divide
out into two cases.

ToNumber:
Uses of toDouble from JSString and from parseFloat are implementing ecma's
ToNumber conversion from strings (see ecma-262 9.3.1), so UString::toDouble
should largely just be moved out to a global jsToNumber function. ToNumber is
capable of recognizing either decimal or hexadecimal numbers, but parseFloat
should only recognize decimal values. This is currently handled by testing for
hexadecimal before calling toDouble, which should unnecessary - instead we can
just split out the two parts to the grammar into separate functions. Also,
strtod recognizes a set of literals (nan, inf, and infinity - all with any
capitalization) - which are not defined by any of the specs we are implementing.
To handle this we need to perform additional work in toDouble to convert the
unsupported cases of infinities back to NaNs. Instead we should simply remove
support for this literals from strtod. This should provide a more desirable
behaviour for all clients of strtod.

Indexed properties:
Uses of the toStrictUInt32 methods are were all converting property names to
indices, and all uses of toUInt32 were incorrect; in all cases we should have
been calling toUInt32. This error results in some incorrect behaviour in the
DOM (accessing property "0 " of a NodeList should fail; it currently does not).
Move this method onto Identifier (our canonical property name), and make it
always perform a strict conversion. Add a layout test to check NodeList does
convert indexed property names correctly.

(JSC::Arguments::getOwnPropertySlot):
(JSC::Arguments::getOwnPropertyDescriptor):
(JSC::Arguments::put):
(JSC::Arguments::deleteProperty):

  • runtime/Identifier.cpp:

(JSC::Identifier::toUInt32):

  • runtime/Identifier.h:

(JSC::Identifier::toUInt32):

  • runtime/JSArray.cpp:

(JSC::JSArray::getOwnPropertySlot):
(JSC::JSArray::getOwnPropertyDescriptor):
(JSC::JSArray::put):
(JSC::JSArray::deleteProperty):

  • runtime/JSArray.h:

(JSC::Identifier::toArrayIndex):

  • runtime/JSByteArray.cpp:

(JSC::JSByteArray::getOwnPropertySlot):
(JSC::JSByteArray::getOwnPropertyDescriptor):
(JSC::JSByteArray::put):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::isInfinity):
(JSC::jsHexIntegerLiteral):
(JSC::jsStrDecimalLiteral):
(JSC::jsToNumber):
(JSC::parseFloat):

  • runtime/JSGlobalObjectFunctions.h:
  • runtime/JSString.cpp:

(JSC::JSString::getPrimitiveNumber):
(JSC::JSString::toNumber):
(JSC::JSString::getStringPropertyDescriptor):

  • runtime/JSString.h:

(JSC::JSString::getStringPropertySlot):

  • runtime/ObjectPrototype.cpp:

(JSC::ObjectPrototype::put):

  • runtime/StringObject.cpp:

(JSC::StringObject::deleteProperty):

  • runtime/UString.cpp:
  • runtime/UString.h:
  • wtf/dtoa.cpp:

(WTF::strtod):

WebCore:

These methods all implement JavaScript language specific behaviour, and as such
are not suited to being on a generic string object. They are also inefficient
and incorrectly used, refactor & cleanup. Uses of these methods really divide
out into two cases.

ToNumber:
Uses of toDouble from JSString and from parseFloat are implementing ecma's
ToNumber conversion from strings (see ecma-262 9.3.1), so UString::toDouble
should largely just be moved out to a global jsToNumber function. ToNumber is
capable of recognizing either decimal or hexadecimal numbers, but parseFloat
should only recognize decimal values. This is currently handled by testing for
hexadecimal before calling toDouble, which should unnecessary - instead we can
just split out the two parts to the grammar into separate functions. Also,
strtod recognizes a set of literals (nan, inf, and infinity - all with any
capitalization) - which are not defined by any of the specs we are implementing.
To handle this we need to perform additional work in toDouble to convert the
unsupported cases of infinities back to NaNs. Instead we should simply remove
support for this literals from strtod. This should provide a more desirable
behaviour for all clients of strtod.

Indexed properties:
Uses of the toStrictUInt32 methods are were all converting property names to
indices, and all uses of toUInt32 were incorrect; in all cases we should have
been calling toUInt32. This error results in some incorrect behaviour in the
DOM (accessing property "0 " of a NodeList should fail; it currently does not).
Move this method onto Identifier (our canonical property name), and make it
always perform a strict conversion. Add a layout test to check NodeList does
convert indexed property names correctly.

Test: fast/dom/NodeList/nodelist-item-with-index.html

  • WebCore.xcodeproj/project.pbxproj:
  • bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::getOwnPropertySlot):
(WebCore::JSDOMWindow::getOwnPropertyDescriptor):

  • bindings/js/JSHTMLAllCollectionCustom.cpp:

(WebCore::callHTMLAllCollection):
(WebCore::JSHTMLAllCollection::item):

  • bindings/js/JSHTMLCollectionCustom.cpp:

(WebCore::callHTMLCollection):
(WebCore::JSHTMLCollection::item):

  • bindings/js/JSNodeListCustom.cpp:

(WebCore::callNodeList):

  • bindings/scripts/CodeGeneratorJS.pm:
  • bridge/runtime_array.cpp:

(JSC::RuntimeArray::getOwnPropertySlot):
(JSC::RuntimeArray::getOwnPropertyDescriptor):
(JSC::RuntimeArray::put):

LayoutTests:

Test that indexing into nodelists works correctly, particularly
wrt indices passed as strings that contain whitespace.

  • fast/dom/NodeList/nodelist-item-with-index-expected.txt: Added.
  • fast/dom/NodeList/nodelist-item-with-index.html: Added.
  • Property svn:eol-style set to native
File size: 10.3 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::number(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::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(exec, UString::number(i)));
213 }
214 propertyNames.add(exec->propertyNames().callee);
215 propertyNames.add(exec->propertyNames().length);
216 }
217 JSObject::getOwnPropertyNames(exec, propertyNames, mode);
218}
219
220void 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, Identifier(exec, UString::number(i)), value, slot);
231}
232
233void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
234{
235 bool isArrayIndex;
236 unsigned i = propertyName.toArrayIndex(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, DontEnum);
248 return;
249 }
250
251 if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
252 d->overrodeCallee = true;
253 putDirect(propertyName, value, DontEnum);
254 return;
255 }
256
257 JSObject::put(exec, propertyName, value, slot);
258}
259
260bool 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(d->deletedArguments.get(), 0, 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, Identifier(exec, UString::number(i)));
274}
275
276bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
277{
278 bool isArrayIndex;
279 unsigned i = propertyName.toArrayIndex(isArrayIndex);
280 if (isArrayIndex && i < d->numArguments) {
281 if (!d->deletedArguments) {
282 d->deletedArguments.set(new bool[d->numArguments]);
283 memset(d->deletedArguments.get(), 0, 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
Note: See TracBrowser for help on using the repository browser.