Commit 794f4617 authored by barraclough@apple.com's avatar barraclough@apple.com

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.

* JavaScriptCore.exp:
* runtime/Arguments.cpp:
(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.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@65588 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 74cef0e9
2010-08-17 Gavin Barraclough <barraclough@apple.com>
Reviewed by Sam Weinig.
Bug 44146 - Remove toDouble/toUInt32 methods from UString.
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.
* JavaScriptCore.exp:
* runtime/Arguments.cpp:
(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):
2010-08-17 Gavin Barraclough <barraclough@apple.com>
Reviewed by Sam Weinig.
......
......@@ -107,6 +107,7 @@ __ZN3JSC10Identifier3addEPNS_9ExecStateEPKc
__ZN3JSC10Identifier4fromEPNS_9ExecStateEi
__ZN3JSC10Identifier4fromEPNS_9ExecStateEj
__ZN3JSC10Identifier5equalEPKN3WTF10StringImplEPKc
__ZN3JSC10Identifier8toUInt32ERKNS_7UStringERb
__ZN3JSC10JSFunction4infoE
__ZN3JSC10JSFunction4nameEPNS_9ExecStateE
__ZN3JSC10throwErrorEPNS_9ExecStateENS_7JSValueE
......@@ -515,12 +516,9 @@ __ZNK3JSC7JSValue16toObjectSlowCaseEPNS_9ExecStateE
__ZNK3JSC7JSValue19synthesizePrototypeEPNS_9ExecStateE
__ZNK3JSC7JSValue20toThisObjectSlowCaseEPNS_9ExecStateE
__ZNK3JSC7JSValue9toIntegerEPNS_9ExecStateE
__ZNK3JSC7UString14toStrictUInt32EPb
__ZNK3JSC7UString4utf8Eb
__ZNK3JSC7UString5asciiEv
__ZNK3JSC7UString6substrEjj
__ZNK3JSC7UString8toUInt32EPb
__ZNK3JSC7UString8toUInt32EPbb
__ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE
__ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateEj
__ZNK3JSC8JSObject12defaultValueEPNS_9ExecStateENS_22PreferredPrimitiveTypeE
......
......@@ -45,6 +45,7 @@
#include "JSArray.h"
#include "JSByteArray.h"
#include "JSFunction.h"
#include "JSGlobalObjectFunctions.h"
#include "JSNotAnObject.h"
#include "JSPropertyNameIterator.h"
#include "JSStaticScopeObject.h"
......@@ -2814,16 +2815,16 @@ DEFINE_STUB_FUNCTION(int, op_eq)
if (cell1->isString()) {
if (src2.isInt32())
return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asInt32();
return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asInt32();
if (src2.isDouble())
return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asDouble();
return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asDouble();
if (src2.isTrue())
return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 1.0;
return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 1.0;
if (src2.isFalse())
return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 0.0;
return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 0.0;
JSCell* cell2 = asCell(src2);
if (cell2->isString())
......
......@@ -157,7 +157,7 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& sl
bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
bool isArrayIndex;
unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);
unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters) {
slot.setRegisterSlot(&d->registers[d->firstParameterIndex + i]);
......@@ -182,7 +182,7 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNa
bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
bool isArrayIndex;
unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);
unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters) {
descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].jsValue(), DontEnum);
......@@ -233,7 +233,7 @@ void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot&
void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
bool isArrayIndex;
unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);
unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
if (i < d->numParameters)
d->registers[d->firstParameterIndex + i] = JSValue(value);
......@@ -276,7 +276,7 @@ bool Arguments::deleteProperty(ExecState* exec, unsigned i)
bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
bool isArrayIndex;
unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);
unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex && i < d->numArguments) {
if (!d->deletedArguments) {
d->deletedArguments.set(new bool[d->numArguments]);
......
......@@ -168,6 +168,49 @@ struct IdentifierUCharBufferTranslator {
}
};
uint32_t Identifier::toUInt32(const UString& string, bool& ok)
{
ok = false;
unsigned length = string.length();
const UChar* characters = string.characters();
// An empty string is not a number.
if (!length)
return 0;
// Get the first character, turning it into a digit.
uint32_t value = characters[0] - '0';
if (value > 9)
return 0;
// Check for leading zeros. If the first characher is 0, then the
// length of the string must be one - e.g. "042" is not equal to "42".
if (!value && length > 1)
return 0;
while (--length) {
// Multiply value by 10, checking for overflow out of 32 bits.
if (value > 0xFFFFFFFFU / 10)
return 0;
value *= 10;
// Get the next character, turning it into a digit.
uint32_t newValue = *(++characters) - '0';
if (newValue > 9)
return 0;
// Add in the old value, checking for overflow out of 32 bits.
newValue += value;
if (newValue < value)
return 0;
value = newValue;
}
ok = true;
return value;
}
PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const UChar* s, int length)
{
if (length == 1) {
......
......@@ -59,15 +59,14 @@ namespace JSC {
static Identifier from(JSGlobalData*, unsigned y);
static Identifier from(JSGlobalData*, int y);
static Identifier from(JSGlobalData*, double y);
static uint32_t toUInt32(const UString&, bool& ok);
uint32_t toUInt32(bool& ok) const { return toUInt32(m_string, ok); }
unsigned toArrayIndex(bool& ok) const;
bool isNull() const { return m_string.isNull(); }
bool isEmpty() const { return m_string.isEmpty(); }
uint32_t toUInt32(bool* ok) const { return m_string.toUInt32(ok); }
uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const { return m_string.toUInt32(ok, tolerateEmptyString); };
uint32_t toStrictUInt32(bool* ok) const { return m_string.toStrictUInt32(ok); }
double toDouble() const { return m_string.toDouble(); }
friend bool operator==(const Identifier&, const Identifier&);
friend bool operator!=(const Identifier&, const Identifier&);
......
......@@ -273,7 +273,7 @@ bool JSArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName
}
bool isArrayIndex;
unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);
unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex)
return JSArray::getOwnPropertySlot(exec, i, slot);
......@@ -290,7 +290,7 @@ bool JSArray::getOwnPropertyDescriptor(ExecState* exec, const Identifier& proper
ArrayStorage* storage = m_storage;
bool isArrayIndex;
unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);
unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex) {
if (i >= storage->m_length)
return false;
......@@ -317,7 +317,7 @@ bool JSArray::getOwnPropertyDescriptor(ExecState* exec, const Identifier& proper
void JSArray::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
bool isArrayIndex;
unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);
unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex) {
put(exec, i, value);
return;
......@@ -475,7 +475,7 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu
bool JSArray::deleteProperty(ExecState* exec, const Identifier& propertyName)
{
bool isArrayIndex;
unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);
unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex)
return deleteProperty(exec, i);
......
......@@ -264,11 +264,11 @@ namespace JSC {
// Rule from ECMA 15.2 about what an array index is.
// Must exactly match string form of an unsigned integer, and be less than 2^32 - 1.
inline unsigned toArrayIndex(const UString& string, bool* ok)
inline unsigned Identifier::toArrayIndex(bool& ok) const
{
unsigned i = string.toStrictUInt32(ok);
unsigned i = toUInt32(ok);
if (ok && i >= 0xFFFFFFFFU)
*ok = false;
ok = false;
return i;
}
......
......@@ -60,7 +60,7 @@ PassRefPtr<Structure> JSByteArray::createStructure(JSValue prototype)
bool JSByteArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
bool ok;
unsigned index = propertyName.toUInt32(&ok, false);
unsigned index = propertyName.toUInt32(ok);
if (ok && canAccessIndex(index)) {
slot.setValue(getIndex(exec, index));
return true;
......@@ -71,7 +71,7 @@ bool JSByteArray::getOwnPropertySlot(ExecState* exec, const Identifier& property
bool JSByteArray::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
bool ok;
unsigned index = propertyName.toUInt32(&ok, false);
unsigned index = propertyName.toUInt32(ok);
if (ok && canAccessIndex(index)) {
descriptor.setDescriptor(getIndex(exec, index), DontDelete);
return true;
......@@ -91,7 +91,7 @@ bool JSByteArray::getOwnPropertySlot(ExecState* exec, unsigned propertyName, Pro
void JSByteArray::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
{
bool ok;
unsigned index = propertyName.toUInt32(&ok, false);
unsigned index = propertyName.toUInt32(ok);
if (ok) {
setIndex(exec, index, value);
return;
......
......@@ -276,23 +276,161 @@ static double parseInt(const UString& s, int radix)
return sign * number;
}
static const int SizeOfInfinity = 8;
static bool isInfinity(const UChar* data, const UChar* end)
{
return (end - data) >= SizeOfInfinity
&& data[0] == 'I'
&& data[1] == 'n'
&& data[2] == 'f'
&& data[3] == 'i'
&& data[4] == 'n'
&& data[5] == 'i'
&& data[6] == 't'
&& data[7] == 'y';
}
// See ecma-262 9.3.1
static double jsHexIntegerLiteral(const UChar*& data, const UChar* end)
{
// Hex number.
data += 2;
const UChar* firstDigitPosition = data;
double number = 0;
while (true) {
number = number * 16 + toASCIIHexValue(*data);
++data;
if (data == end)
break;
if (!isASCIIHexDigit(*data))
break;
}
if (number >= mantissaOverflowLowerBound)
number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16);
return number;
}
// See ecma-262 9.3.1
static double jsStrDecimalLiteral(const UChar*& data, const UChar* end)
{
ASSERT(data < end);
// Copy the sting into a null-terminated byte buffer, and call strtod.
Vector<char, 32> byteBuffer;
for (const UChar* characters = data; characters < end; ++characters) {
UChar character = *characters;
byteBuffer.append(isASCII(character) ? character : 0);
}
byteBuffer.append(0);
char* endOfNumber;
double number = WTF::strtod(byteBuffer.data(), &endOfNumber);
// Check if strtod found a number; if so return it.
ptrdiff_t consumed = endOfNumber - byteBuffer.data();
if (consumed) {
data += consumed;
return number;
}
// Check for [+-]?Infinity
switch (*data) {
case 'I':
if (isInfinity(data, end)) {
data += SizeOfInfinity;
return Inf;
}
break;
case '+':
if (isInfinity(data + 1, end)) {
data += SizeOfInfinity + 1;
return Inf;
}
break;
case '-':
if (isInfinity(data + 1, end)) {
data += SizeOfInfinity + 1;
return -Inf;
}
break;
}
// Not a number.
return NaN;
}
// See ecma-262 9.3.1
double jsToNumber(const UString& s)
{
unsigned size = s.length();
if (size == 1) {
UChar c = s.characters()[0];
if (isASCIIDigit(c))
return c - '0';
if (isStrWhiteSpace(c))
return 0;
return NaN;
}
const UChar* data = s.characters();
const UChar* end = data + size;
// Skip leading white space.
for (; data < end; ++data) {
if (!isStrWhiteSpace(*data))
break;
}
// Empty string.
if (data == end)
return 0.0;
double number;
if (data[0] == '0' && data + 2 < end && (data[1] | 0x20) == 'x' && isASCIIHexDigit(data[2]))
number = jsHexIntegerLiteral(data, end);
else
number = jsStrDecimalLiteral(data, end);
// Allow trailing white space.
for (; data < end; ++data) {
if (!isStrWhiteSpace(*data))
break;
}
if (data != end)
return NaN;
return number;
}
static double parseFloat(const UString& s)
{
// Check for 0x prefix here, because toDouble allows it, but we must treat it as 0.
// Need to skip any whitespace and then one + or - sign.
int length = s.length();
unsigned size = s.length();
if (size == 1) {
UChar c = s.characters()[0];
if (isASCIIDigit(c))
return c - '0';
return NaN;
}
const UChar* data = s.characters();
int p = 0;
while (p < length && isStrWhiteSpace(data[p]))
++p;
const UChar* end = data + size;
if (p < length && (data[p] == '+' || data[p] == '-'))
++p;
// Skip leading white space.
for (; data < end; ++data) {
if (!isStrWhiteSpace(*data))
break;
}
if (length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X'))
return 0;
// Empty string.
if (data == end)
return NaN;
return s.toDouble(true /*tolerant*/, false /* NaN for empty string */);
return jsStrDecimalLiteral(data, end);
}
EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
......
......@@ -55,6 +55,7 @@ namespace JSC {
double parseIntOverflow(const char*, int length, int radix);
double parseIntOverflow(const UChar*, int length, int radix);
bool isStrWhiteSpace(UChar);
double jsToNumber(const UString& s);
} // namespace JSC
......
......@@ -24,6 +24,7 @@
#include "JSString.h"
#include "JSGlobalObject.h"
#include "JSGlobalObjectFunctions.h"
#include "JSObject.h"
#include "Operations.h"
#include "StringObject.h"
......@@ -177,7 +178,7 @@ JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const
bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result)
{
result = this;
number = value(exec).toDouble();
number = jsToNumber(value(exec));
return false;
}
......@@ -188,7 +189,7 @@ bool JSString::toBoolean(ExecState*) const
double JSString::toNumber(ExecState* exec) const
{
return value(exec).toDouble();
return jsToNumber(value(exec));
}
UString JSString::toString(ExecState* exec) const
......@@ -240,7 +241,7 @@ bool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& pr
}
bool isStrictUInt32;
unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
unsigned i = propertyName.toUInt32(isStrictUInt32);
if (isStrictUInt32 && i < m_length) {
descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly);
return true;
......
......@@ -564,7 +564,7 @@ namespace JSC {
}
bool isStrictUInt32;
unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
unsigned i = propertyName.toUInt32(isStrictUInt32);
if (isStrictUInt32 && i < m_length) {
slot.setValue(getIndex(exec, i));
return true;
......
......@@ -65,7 +65,7 @@ void ObjectPrototype::put(ExecState* exec, const Identifier& propertyName, JSVal
if (m_hasNoPropertiesWithUInt32Names) {
bool isUInt32;
propertyName.toStrictUInt32(&isUInt32);
propertyName.toUInt32(isUInt32);
m_hasNoPropertiesWithUInt32Names = !isUInt32;
}
}
......
......@@ -80,7 +80,7 @@ bool StringObject::deleteProperty(ExecState* exec, const Identifier& propertyNam
if (propertyName == exec->propertyNames().length)
return false;
bool isStrictUInt32;
unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
unsigned i = propertyName.toUInt32(isStrictUInt32);
if (isStrictUInt32 && internalValue()->canGetIndex(i))
return false;
return JSObject::deleteProperty(exec, propertyName);
......
......@@ -204,215 +204,6 @@ UString UString::number(double d)
return UString(buffer, length);
}
static inline bool isInfinity(double number)
{
return number == Inf || number == -Inf;
}
static bool isInfinity(const UChar* data, const UChar* end)
{
return data + 7 < end
&& data[0] == 'I'
&& data[1] == 'n'
&& data[2] == 'f'
&& data[3] == 'i'
&& data[4] == 'n'
&& data[5] == 'i'
&& data[6] == 't'
&& data[7] == 'y';
}
double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
{
unsigned size = this->length();
if (size == 1) {
UChar c = characters()[0];
if (isASCIIDigit(c))
return c - '0';
if (isStrWhiteSpace(c) && tolerateEmptyString)
return 0;
return NaN;
}
const UChar* data = this->characters();
const UChar* end = data + size;
// Skip leading white space.
for (; data < end; ++data) {
if (!isStrWhiteSpace(*data))
break;
}
// Empty string.
if (data == end)
return tolerateEmptyString ? 0.0 : NaN;