Changeset 65588 in webkit for trunk/JavaScriptCore
- Timestamp:
- Aug 18, 2010, 12:41:22 AM (15 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 18 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r65571 r65588 1 2010-08-17 Gavin Barraclough <[email protected]> 2 3 Reviewed by Sam Weinig. 4 5 Bug 44146 - Remove toDouble/toUInt32 methods from UString. 6 7 These methods all implement JavaScript language specific behaviour, and as such 8 are not suited to being on a generic string object. They are also inefficient 9 and incorrectly used, refactor & cleanup. Uses of these methods really divide 10 out into two cases. 11 12 ToNumber: 13 Uses of toDouble from JSString and from parseFloat are implementing ecma's 14 ToNumber conversion from strings (see ecma-262 9.3.1), so UString::toDouble 15 should largely just be moved out to a global jsToNumber function. ToNumber is 16 capable of recognizing either decimal or hexadecimal numbers, but parseFloat 17 should only recognize decimal values. This is currently handled by testing for 18 hexadecimal before calling toDouble, which should unnecessary - instead we can 19 just split out the two parts to the grammar into separate functions. Also, 20 strtod recognizes a set of literals (nan, inf, and infinity - all with any 21 capitalization) - which are not defined by any of the specs we are implementing. 22 To handle this we need to perform additional work in toDouble to convert the 23 unsupported cases of infinities back to NaNs. Instead we should simply remove 24 support for this literals from strtod. This should provide a more desirable 25 behaviour for all clients of strtod. 26 27 Indexed properties: 28 Uses of the toStrictUInt32 methods are were all converting property names to 29 indices, and all uses of toUInt32 were incorrect; in all cases we should have 30 been calling toUInt32. This error results in some incorrect behaviour in the 31 DOM (accessing property "0 " of a NodeList should fail; it currently does not). 32 Move this method onto Identifier (our canonical property name), and make it 33 always perform a strict conversion. Add a layout test to check NodeList does 34 convert indexed property names correctly. 35 36 * JavaScriptCore.exp: 37 * runtime/Arguments.cpp: 38 (JSC::Arguments::getOwnPropertySlot): 39 (JSC::Arguments::getOwnPropertyDescriptor): 40 (JSC::Arguments::put): 41 (JSC::Arguments::deleteProperty): 42 * runtime/Identifier.cpp: 43 (JSC::Identifier::toUInt32): 44 * runtime/Identifier.h: 45 (JSC::Identifier::toUInt32): 46 * runtime/JSArray.cpp: 47 (JSC::JSArray::getOwnPropertySlot): 48 (JSC::JSArray::getOwnPropertyDescriptor): 49 (JSC::JSArray::put): 50 (JSC::JSArray::deleteProperty): 51 * runtime/JSArray.h: 52 (JSC::Identifier::toArrayIndex): 53 * runtime/JSByteArray.cpp: 54 (JSC::JSByteArray::getOwnPropertySlot): 55 (JSC::JSByteArray::getOwnPropertyDescriptor): 56 (JSC::JSByteArray::put): 57 * runtime/JSGlobalObjectFunctions.cpp: 58 (JSC::isInfinity): 59 (JSC::jsHexIntegerLiteral): 60 (JSC::jsStrDecimalLiteral): 61 (JSC::jsToNumber): 62 (JSC::parseFloat): 63 * runtime/JSGlobalObjectFunctions.h: 64 * runtime/JSString.cpp: 65 (JSC::JSString::getPrimitiveNumber): 66 (JSC::JSString::toNumber): 67 (JSC::JSString::getStringPropertyDescriptor): 68 * runtime/JSString.h: 69 (JSC::JSString::getStringPropertySlot): 70 * runtime/ObjectPrototype.cpp: 71 (JSC::ObjectPrototype::put): 72 * runtime/StringObject.cpp: 73 (JSC::StringObject::deleteProperty): 74 * runtime/UString.cpp: 75 * runtime/UString.h: 76 * wtf/dtoa.cpp: 77 (WTF::strtod): 78 1 79 2010-08-17 Gavin Barraclough <[email protected]> 2 80 -
trunk/JavaScriptCore/JavaScriptCore.exp
r65468 r65588 108 108 __ZN3JSC10Identifier4fromEPNS_9ExecStateEj 109 109 __ZN3JSC10Identifier5equalEPKN3WTF10StringImplEPKc 110 __ZN3JSC10Identifier8toUInt32ERKNS_7UStringERb 110 111 __ZN3JSC10JSFunction4infoE 111 112 __ZN3JSC10JSFunction4nameEPNS_9ExecStateE … … 516 517 __ZNK3JSC7JSValue20toThisObjectSlowCaseEPNS_9ExecStateE 517 518 __ZNK3JSC7JSValue9toIntegerEPNS_9ExecStateE 518 __ZNK3JSC7UString14toStrictUInt32EPb519 519 __ZNK3JSC7UString4utf8Eb 520 520 __ZNK3JSC7UString5asciiEv 521 521 __ZNK3JSC7UString6substrEjj 522 __ZNK3JSC7UString8toUInt32EPb523 __ZNK3JSC7UString8toUInt32EPbb524 522 __ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE 525 523 __ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateEj -
trunk/JavaScriptCore/jit/JITStubs.cpp
r65311 r65588 46 46 #include "JSByteArray.h" 47 47 #include "JSFunction.h" 48 #include "JSGlobalObjectFunctions.h" 48 49 #include "JSNotAnObject.h" 49 50 #include "JSPropertyNameIterator.h" … … 2815 2816 if (cell1->isString()) { 2816 2817 if (src2.isInt32()) 2817 return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asInt32();2818 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asInt32(); 2818 2819 2819 2820 if (src2.isDouble()) 2820 return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asDouble();2821 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asDouble(); 2821 2822 2822 2823 if (src2.isTrue()) 2823 return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 1.0;2824 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 1.0; 2824 2825 2825 2826 if (src2.isFalse()) 2826 return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 0.0;2827 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 0.0; 2827 2828 2828 2829 JSCell* cell2 = asCell(src2); -
trunk/JavaScriptCore/runtime/Arguments.cpp
r65305 r65588 158 158 { 159 159 bool isArrayIndex; 160 unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);160 unsigned i = propertyName.toArrayIndex(isArrayIndex); 161 161 if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { 162 162 if (i < d->numParameters) { … … 183 183 { 184 184 bool isArrayIndex; 185 unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);185 unsigned i = propertyName.toArrayIndex(isArrayIndex); 186 186 if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { 187 187 if (i < d->numParameters) { … … 234 234 { 235 235 bool isArrayIndex; 236 unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);236 unsigned i = propertyName.toArrayIndex(isArrayIndex); 237 237 if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { 238 238 if (i < d->numParameters) … … 277 277 { 278 278 bool isArrayIndex; 279 unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);279 unsigned i = propertyName.toArrayIndex(isArrayIndex); 280 280 if (isArrayIndex && i < d->numArguments) { 281 281 if (!d->deletedArguments) { -
trunk/JavaScriptCore/runtime/Identifier.cpp
r65104 r65588 169 169 }; 170 170 171 uint32_t Identifier::toUInt32(const UString& string, bool& ok) 172 { 173 ok = false; 174 175 unsigned length = string.length(); 176 const UChar* characters = string.characters(); 177 178 // An empty string is not a number. 179 if (!length) 180 return 0; 181 182 // Get the first character, turning it into a digit. 183 uint32_t value = characters[0] - '0'; 184 if (value > 9) 185 return 0; 186 187 // Check for leading zeros. If the first characher is 0, then the 188 // length of the string must be one - e.g. "042" is not equal to "42". 189 if (!value && length > 1) 190 return 0; 191 192 while (--length) { 193 // Multiply value by 10, checking for overflow out of 32 bits. 194 if (value > 0xFFFFFFFFU / 10) 195 return 0; 196 value *= 10; 197 198 // Get the next character, turning it into a digit. 199 uint32_t newValue = *(++characters) - '0'; 200 if (newValue > 9) 201 return 0; 202 203 // Add in the old value, checking for overflow out of 32 bits. 204 newValue += value; 205 if (newValue < value) 206 return 0; 207 value = newValue; 208 } 209 210 ok = true; 211 return value; 212 } 213 171 214 PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const UChar* s, int length) 172 215 { -
trunk/JavaScriptCore/runtime/Identifier.h
r65478 r65588 60 60 static Identifier from(JSGlobalData*, int y); 61 61 static Identifier from(JSGlobalData*, double y); 62 62 63 static uint32_t toUInt32(const UString&, bool& ok); 64 uint32_t toUInt32(bool& ok) const { return toUInt32(m_string, ok); } 65 unsigned toArrayIndex(bool& ok) const; 66 63 67 bool isNull() const { return m_string.isNull(); } 64 68 bool isEmpty() const { return m_string.isEmpty(); } 65 66 uint32_t toUInt32(bool* ok) const { return m_string.toUInt32(ok); }67 uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const { return m_string.toUInt32(ok, tolerateEmptyString); };68 uint32_t toStrictUInt32(bool* ok) const { return m_string.toStrictUInt32(ok); }69 double toDouble() const { return m_string.toDouble(); }70 69 71 70 friend bool operator==(const Identifier&, const Identifier&); -
trunk/JavaScriptCore/runtime/JSArray.cpp
r65311 r65588 274 274 275 275 bool isArrayIndex; 276 unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);276 unsigned i = propertyName.toArrayIndex(isArrayIndex); 277 277 if (isArrayIndex) 278 278 return JSArray::getOwnPropertySlot(exec, i, slot); … … 291 291 292 292 bool isArrayIndex; 293 unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);293 unsigned i = propertyName.toArrayIndex(isArrayIndex); 294 294 if (isArrayIndex) { 295 295 if (i >= storage->m_length) … … 318 318 { 319 319 bool isArrayIndex; 320 unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);320 unsigned i = propertyName.toArrayIndex(isArrayIndex); 321 321 if (isArrayIndex) { 322 322 put(exec, i, value); … … 476 476 { 477 477 bool isArrayIndex; 478 unsigned i = toArrayIndex(propertyName.ustring(), &isArrayIndex);478 unsigned i = propertyName.toArrayIndex(isArrayIndex); 479 479 if (isArrayIndex) 480 480 return deleteProperty(exec, i); -
trunk/JavaScriptCore/runtime/JSArray.h
r65305 r65588 265 265 // Rule from ECMA 15.2 about what an array index is. 266 266 // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1. 267 inline unsigned toArrayIndex(const UString& string, bool* ok)268 { 269 unsigned i = string.toStrictUInt32(ok);267 inline unsigned Identifier::toArrayIndex(bool& ok) const 268 { 269 unsigned i = toUInt32(ok); 270 270 if (ok && i >= 0xFFFFFFFFU) 271 *ok = false;271 ok = false; 272 272 return i; 273 273 } -
trunk/JavaScriptCore/runtime/JSByteArray.cpp
r54022 r65588 61 61 { 62 62 bool ok; 63 unsigned index = propertyName.toUInt32( &ok, false);63 unsigned index = propertyName.toUInt32(ok); 64 64 if (ok && canAccessIndex(index)) { 65 65 slot.setValue(getIndex(exec, index)); … … 72 72 { 73 73 bool ok; 74 unsigned index = propertyName.toUInt32( &ok, false);74 unsigned index = propertyName.toUInt32(ok); 75 75 if (ok && canAccessIndex(index)) { 76 76 descriptor.setDescriptor(getIndex(exec, index), DontDelete); … … 92 92 { 93 93 bool ok; 94 unsigned index = propertyName.toUInt32( &ok, false);94 unsigned index = propertyName.toUInt32(ok); 95 95 if (ok) { 96 96 setIndex(exec, index, value); -
trunk/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
r65305 r65588 277 277 } 278 278 279 static const int SizeOfInfinity = 8; 280 281 static bool isInfinity(const UChar* data, const UChar* end) 282 { 283 return (end - data) >= SizeOfInfinity 284 && data[0] == 'I' 285 && data[1] == 'n' 286 && data[2] == 'f' 287 && data[3] == 'i' 288 && data[4] == 'n' 289 && data[5] == 'i' 290 && data[6] == 't' 291 && data[7] == 'y'; 292 } 293 294 // See ecma-262 9.3.1 295 static double jsHexIntegerLiteral(const UChar*& data, const UChar* end) 296 { 297 // Hex number. 298 data += 2; 299 const UChar* firstDigitPosition = data; 300 double number = 0; 301 while (true) { 302 number = number * 16 + toASCIIHexValue(*data); 303 ++data; 304 if (data == end) 305 break; 306 if (!isASCIIHexDigit(*data)) 307 break; 308 } 309 if (number >= mantissaOverflowLowerBound) 310 number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16); 311 312 return number; 313 } 314 315 // See ecma-262 9.3.1 316 static double jsStrDecimalLiteral(const UChar*& data, const UChar* end) 317 { 318 ASSERT(data < end); 319 320 // Copy the sting into a null-terminated byte buffer, and call strtod. 321 Vector<char, 32> byteBuffer; 322 for (const UChar* characters = data; characters < end; ++characters) { 323 UChar character = *characters; 324 byteBuffer.append(isASCII(character) ? character : 0); 325 } 326 byteBuffer.append(0); 327 char* endOfNumber; 328 double number = WTF::strtod(byteBuffer.data(), &endOfNumber); 329 330 // Check if strtod found a number; if so return it. 331 ptrdiff_t consumed = endOfNumber - byteBuffer.data(); 332 if (consumed) { 333 data += consumed; 334 return number; 335 } 336 337 // Check for [+-]?Infinity 338 switch (*data) { 339 case 'I': 340 if (isInfinity(data, end)) { 341 data += SizeOfInfinity; 342 return Inf; 343 } 344 break; 345 346 case '+': 347 if (isInfinity(data + 1, end)) { 348 data += SizeOfInfinity + 1; 349 return Inf; 350 } 351 break; 352 353 case '-': 354 if (isInfinity(data + 1, end)) { 355 data += SizeOfInfinity + 1; 356 return -Inf; 357 } 358 break; 359 } 360 361 // Not a number. 362 return NaN; 363 } 364 365 // See ecma-262 9.3.1 366 double jsToNumber(const UString& s) 367 { 368 unsigned size = s.length(); 369 370 if (size == 1) { 371 UChar c = s.characters()[0]; 372 if (isASCIIDigit(c)) 373 return c - '0'; 374 if (isStrWhiteSpace(c)) 375 return 0; 376 return NaN; 377 } 378 379 const UChar* data = s.characters(); 380 const UChar* end = data + size; 381 382 // Skip leading white space. 383 for (; data < end; ++data) { 384 if (!isStrWhiteSpace(*data)) 385 break; 386 } 387 388 // Empty string. 389 if (data == end) 390 return 0.0; 391 392 double number; 393 if (data[0] == '0' && data + 2 < end && (data[1] | 0x20) == 'x' && isASCIIHexDigit(data[2])) 394 number = jsHexIntegerLiteral(data, end); 395 else 396 number = jsStrDecimalLiteral(data, end); 397 398 // Allow trailing white space. 399 for (; data < end; ++data) { 400 if (!isStrWhiteSpace(*data)) 401 break; 402 } 403 if (data != end) 404 return NaN; 405 406 return number; 407 } 408 279 409 static double parseFloat(const UString& s) 280 410 { 281 // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0. 282 // Need to skip any whitespace and then one + or - sign. 283 int length = s.length(); 411 unsigned size = s.length(); 412 413 if (size == 1) { 414 UChar c = s.characters()[0]; 415 if (isASCIIDigit(c)) 416 return c - '0'; 417 return NaN; 418 } 419 284 420 const UChar* data = s.characters(); 285 int p = 0; 286 while (p < length && isStrWhiteSpace(data[p])) 287 ++p; 288 289 if (p < length && (data[p] == '+' || data[p] == '-')) 290 ++p; 291 292 if (length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) 293 return 0; 294 295 return s.toDouble(true /*tolerant*/, false /* NaN for empty string */); 421 const UChar* end = data + size; 422 423 // Skip leading white space. 424 for (; data < end; ++data) { 425 if (!isStrWhiteSpace(*data)) 426 break; 427 } 428 429 // Empty string. 430 if (data == end) 431 return NaN; 432 433 return jsStrDecimalLiteral(data, end); 296 434 } 297 435 -
trunk/JavaScriptCore/runtime/JSGlobalObjectFunctions.h
r63120 r65588 56 56 double parseIntOverflow(const UChar*, int length, int radix); 57 57 bool isStrWhiteSpace(UChar); 58 double jsToNumber(const UString& s); 58 59 59 60 } // namespace JSC -
trunk/JavaScriptCore/runtime/JSString.cpp
r65468 r65588 25 25 26 26 #include "JSGlobalObject.h" 27 #include "JSGlobalObjectFunctions.h" 27 28 #include "JSObject.h" 28 29 #include "Operations.h" … … 178 179 { 179 180 result = this; 180 number = value(exec).toDouble();181 number = jsToNumber(value(exec)); 181 182 return false; 182 183 } … … 189 190 double JSString::toNumber(ExecState* exec) const 190 191 { 191 return value(exec).toDouble();192 return jsToNumber(value(exec)); 192 193 } 193 194 … … 241 242 242 243 bool isStrictUInt32; 243 unsigned i = propertyName.to StrictUInt32(&isStrictUInt32);244 unsigned i = propertyName.toUInt32(isStrictUInt32); 244 245 if (isStrictUInt32 && i < m_length) { 245 246 descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly); -
trunk/JavaScriptCore/runtime/JSString.h
r65305 r65588 565 565 566 566 bool isStrictUInt32; 567 unsigned i = propertyName.to StrictUInt32(&isStrictUInt32);567 unsigned i = propertyName.toUInt32(isStrictUInt32); 568 568 if (isStrictUInt32 && i < m_length) { 569 569 slot.setValue(getIndex(exec, i)); -
trunk/JavaScriptCore/runtime/ObjectPrototype.cpp
r60762 r65588 66 66 if (m_hasNoPropertiesWithUInt32Names) { 67 67 bool isUInt32; 68 propertyName.to StrictUInt32(&isUInt32);68 propertyName.toUInt32(isUInt32); 69 69 m_hasNoPropertiesWithUInt32Names = !isUInt32; 70 70 } -
trunk/JavaScriptCore/runtime/StringObject.cpp
r65177 r65588 81 81 return false; 82 82 bool isStrictUInt32; 83 unsigned i = propertyName.to StrictUInt32(&isStrictUInt32);83 unsigned i = propertyName.toUInt32(isStrictUInt32); 84 84 if (isStrictUInt32 && internalValue()->canGetIndex(i)) 85 85 return false; -
trunk/JavaScriptCore/runtime/UString.cpp
r65478 r65588 205 205 } 206 206 207 static inline bool isInfinity(double number)208 {209 return number == Inf || number == -Inf;210 }211 212 static bool isInfinity(const UChar* data, const UChar* end)213 {214 return data + 7 < end215 && data[0] == 'I'216 && data[1] == 'n'217 && data[2] == 'f'218 && data[3] == 'i'219 && data[4] == 'n'220 && data[5] == 'i'221 && data[6] == 't'222 && data[7] == 'y';223 }224 225 double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const226 {227 unsigned size = this->length();228 229 if (size == 1) {230 UChar c = characters()[0];231 if (isASCIIDigit(c))232 return c - '0';233 if (isStrWhiteSpace(c) && tolerateEmptyString)234 return 0;235 return NaN;236 }237 238 const UChar* data = this->characters();239 const UChar* end = data + size;240 241 // Skip leading white space.242 for (; data < end; ++data) {243 if (!isStrWhiteSpace(*data))244 break;245 }246 247 // Empty string.248 if (data == end)249 return tolerateEmptyString ? 0.0 : NaN;250 251 double number;252 253 if (data[0] == '0' && data + 2 < end && (data[1] | 0x20) == 'x' && isASCIIHexDigit(data[2])) {254 // Hex number.255 data += 2;256 const UChar* firstDigitPosition = data;257 number = 0;258 while (true) {259 number = number * 16 + toASCIIHexValue(*data);260 ++data;261 if (data == end)262 break;263 if (!isASCIIHexDigit(*data))264 break;265 }266 if (number >= mantissaOverflowLowerBound)267 number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16);268 } else {269 // Decimal number.270 271 // Put into a null-terminated byte buffer.272 Vector<char, 32> byteBuffer;273 for (const UChar* characters = data; characters < end; ++characters) {274 UChar character = *characters;275 byteBuffer.append(isASCII(character) ? character : 0);276 }277 byteBuffer.append(0);278 279 char* byteBufferEnd;280 number = WTF::strtod(byteBuffer.data(), &byteBufferEnd);281 const UChar* pastNumber = data + (byteBufferEnd - byteBuffer.data());282 283 if ((number || pastNumber != data) && !isInfinity(number))284 data = pastNumber;285 else {286 // We used strtod() to do the conversion. However, strtod() handles287 // infinite values slightly differently than JavaScript in that it288 // converts the string "inf" with any capitalization to infinity,289 // whereas the ECMA spec requires that it be converted to NaN.290 291 double signedInfinity = Inf;292 if (data < end) {293 if (*data == '+')294 data++;295 else if (*data == '-') {296 signedInfinity = -Inf;297 data++;298 }299 }300 if (isInfinity(data, end)) {301 number = signedInfinity;302 data += 8;303 } else if (isInfinity(number) && data < end && (*data | 0x20) != 'i')304 data = pastNumber;305 else306 return NaN;307 }308 }309 310 // Look for trailing junk.311 if (!tolerateTrailingJunk) {312 // Allow trailing white space.313 for (; data < end; ++data) {314 if (!isStrWhiteSpace(*data))315 break;316 }317 if (data != end)318 return NaN;319 }320 321 return number;322 }323 324 double UString::toDouble(bool tolerateTrailingJunk) const325 {326 return toDouble(tolerateTrailingJunk, true);327 }328 329 double UString::toDouble() const330 {331 return toDouble(false, true);332 }333 334 uint32_t UString::toUInt32(bool* ok) const335 {336 double d = toDouble();337 bool b = true;338 339 if (d != static_cast<uint32_t>(d)) {340 b = false;341 d = 0;342 }343 344 if (ok)345 *ok = b;346 347 return static_cast<uint32_t>(d);348 }349 350 uint32_t UString::toUInt32(bool* ok, bool tolerateEmptyString) const351 {352 double d = toDouble(false, tolerateEmptyString);353 bool b = true;354 355 if (d != static_cast<uint32_t>(d)) {356 b = false;357 d = 0;358 }359 360 if (ok)361 *ok = b;362 363 return static_cast<uint32_t>(d);364 }365 366 uint32_t UString::toStrictUInt32(bool* ok) const367 {368 if (ok)369 *ok = false;370 371 // Empty string is not OK.372 unsigned len = m_impl->length();373 if (len == 0)374 return 0;375 const UChar* p = m_impl->characters();376 unsigned short c = p[0];377 378 // If the first digit is 0, only 0 itself is OK.379 if (c == '0') {380 if (len == 1 && ok)381 *ok = true;382 return 0;383 }384 385 // Convert to UInt32, checking for overflow.386 uint32_t i = 0;387 while (1) {388 // Process character, turning it into a digit.389 if (c < '0' || c > '9')390 return 0;391 const unsigned d = c - '0';392 393 // Multiply by 10, checking for overflow out of 32 bits.394 if (i > 0xFFFFFFFFU / 10)395 return 0;396 i *= 10;397 398 // Add in the digit, checking for overflow out of 32 bits.399 const unsigned max = 0xFFFFFFFFU - d;400 if (i > max)401 return 0;402 i += d;403 404 // Handle end of string.405 if (--len == 0) {406 if (ok)407 *ok = true;408 return i;409 }410 411 // Get next character.412 c = *(++p);413 }414 }415 416 207 UString UString::substr(unsigned pos, unsigned len) const 417 208 { -
trunk/JavaScriptCore/runtime/UString.h
r65479 r65588 107 107 size_t reverseFind(const UString& str, unsigned start = UINT_MAX) const 108 108 { return m_impl ? m_impl->reverseFind(str.impl(), start) : notFound; } 109 110 double toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const;111 double toDouble(bool tolerateTrailingJunk) const;112 double toDouble() const;113 114 uint32_t toUInt32(bool* ok = 0) const;115 uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const;116 uint32_t toStrictUInt32(bool* ok = 0) const;117 109 118 110 UString substr(unsigned pos = 0, unsigned len = UINT_MAX) const; -
trunk/JavaScriptCore/wtf/dtoa.cpp
r64706 r65588 89 89 * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, 90 90 * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. 91 * #define INFNAN_CHECK on IEEE systems to cause strtod to check for92 * Infinity and NaN (case insensitively). On some systems (e.g.,93 * some HP systems), it may be necessary to #define NAN_WORD094 * appropriately -- to the most significant word of a quiet NaN.95 * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)96 * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,97 * strtod also accepts (case insensitively) strings of the form98 * NaN(x), where x is a string of hexadecimal digits and spaces;99 * if there is only one string of hexadecimal digits, it is taken100 * for the 52 fraction bits of the resulting NaN; if there are two101 * or more strings of hex digits, the first is for the high 20 bits,102 * the second and subsequent for the low 32 bits, with intervening103 * white space ignored; but if this results in none of the 52104 * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0105 * and NAN_WORD1 are used instead.106 91 * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that 107 92 * avoids underflows on inputs whose result does not underflow. … … 167 152 #endif 168 153 169 #define INFNAN_CHECK170 #define No_Hex_NaN171 172 154 #if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_ARM) != 1 173 155 Exactly one of IEEE_8087, IEEE_ARM or IEEE_MC68k should be defined. … … 1041 1023 #define n_bigtens 5 1042 1024 1043 #if defined(INFNAN_CHECK)1044 1045 #ifndef NAN_WORD01046 #define NAN_WORD0 0x7ff800001047 #endif1048 1049 #ifndef NAN_WORD11050 #define NAN_WORD1 01051 #endif1052 1053 static int match(const char** sp, const char* t)1054 {1055 int c, d;1056 const char* s = *sp;1057 1058 while ((d = *t++)) {1059 if ((c = *++s) >= 'A' && c <= 'Z')1060 c += 'a' - 'A';1061 if (c != d)1062 return 0;1063 }1064 *sp = s + 1;1065 return 1;1066 }1067 1068 #ifndef No_Hex_NaN1069 static void hexnan(U* rvp, const char** sp)1070 {1071 uint32_t c, x[2];1072 const char* s;1073 int havedig, udx0, xshift;1074 1075 x[0] = x[1] = 0;1076 havedig = xshift = 0;1077 udx0 = 1;1078 s = *sp;1079 while ((c = *(const unsigned char*)++s)) {1080 if (c >= '0' && c <= '9')1081 c -= '0';1082 else if (c >= 'a' && c <= 'f')1083 c += 10 - 'a';1084 else if (c >= 'A' && c <= 'F')1085 c += 10 - 'A';1086 else if (c <= ' ') {1087 if (udx0 && havedig) {1088 udx0 = 0;1089 xshift = 1;1090 }1091 continue;1092 } else if (/*(*/ c == ')' && havedig) {1093 *sp = s + 1;1094 break;1095 } else1096 return; /* invalid form: don't change *sp */1097 havedig = 1;1098 if (xshift) {1099 xshift = 0;1100 x[0] = x[1];1101 x[1] = 0;1102 }1103 if (udx0)1104 x[0] = (x[0] << 4) | (x[1] >> 28);1105 x[1] = (x[1] << 4) | c;1106 }1107 if ((x[0] &= 0xfffff) || x[1]) {1108 word0(rvp) = Exp_mask | x[0];1109 word1(rvp) = x[1];1110 }1111 }1112 #endif /*No_Hex_NaN*/1113 #endif /* INFNAN_CHECK */1114 1115 1025 double strtod(const char* s00, char** se) 1116 1026 { … … 1237 1147 if (!nd) { 1238 1148 if (!nz && !nz0) { 1239 #ifdef INFNAN_CHECK1240 /* Check for Nan and Infinity */1241 switch (c) {1242 case 'i':1243 case 'I':1244 if (match(&s, "nf")) {1245 --s;1246 if (!match(&s, "inity"))1247 ++s;1248 word0(&rv) = 0x7ff00000;1249 word1(&rv) = 0;1250 goto ret;1251 }1252 break;1253 case 'n':1254 case 'N':1255 if (match(&s, "an")) {1256 word0(&rv) = NAN_WORD0;1257 word1(&rv) = NAN_WORD1;1258 #ifndef No_Hex_NaN1259 if (*s == '(') /*)*/1260 hexnan(&rv, &s);1261 #endif1262 goto ret;1263 }1264 }1265 #endif /* INFNAN_CHECK */1266 1149 ret0: 1267 1150 s = s00;
Note:
See TracChangeset
for help on using the changeset viewer.