Ignore:
Timestamp:
Apr 6, 2012, 10:31:54 AM (13 years ago)
Author:
Darin Adler
Message:

Streamline strtod and fix some related problems
https://bugs.webkit.org/show_bug.cgi?id=82857

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

  • parser/Lexer.cpp:

(JSC::Lexer<>::lex): Use parseDouble. Since we have already scanned the number
and we know it has only correct characters, leading spaces, trailing junk, and
trailing spaces are not a possibility. No need to add a trailing null character.

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::parseInt): Changed overflow based 10 case to use parseDouble. No need
to allow trailing junk since the code above already allows only numeric digits
in the string. This code path is used only in unusual cases, so it's not
optimized for 8-bit strings, but easily could be.
(JSC::jsStrDecimalLiteral): Removed the allow trailing junk argument to this
function template because all the callers are OK with trailing junk. Use the
parseDouble function. No need to copy the data into a byte buffer, because
parseDouble handles that.
(JSC::toDouble): Got rid of the DisallowTrailingJunk argument to the
jsStrDecimalLiteral function template. That's OK because this function
already checks for trailing junk and handles it appropriately. The old code
path was doing it twice.
(JSC::parseFloat): Got rid of the AllowTrailingJunk argument to the
jsStrDecimalLiteral function template; the template allows junk unconditionally.

  • runtime/LiteralParser.cpp:

(JSC::::Lexer::lexNumber): Use parseDouble. Since we have already scanned the number
and we know it has only correct characters, leading spaces, trailing junk, and
trailing spaces are not a possibility. No need to add a trailing null character.
No need to copy the data into a byte buffer, because parseDouble handles that.
We could optimize the UChar case even more because we know all the characters
are ASCII, but not doing that at this time.

Source/WebCore:

Refactoring of code covered by existing tests.

  • dom/ViewportArguments.cpp:

(WebCore::numericPrefix): Removed a confusing comment that just said
"we tolerate extra characters" in a roundabout way. Made the "ok"
argument optional. Changed to call the new version of charactersToFloat
that returns the number of characters parsed rather than using the
charactersToFloatIgnoringJunk/didReadNumber solution from before.
(WebCore::findSizeValue): Since numericPrefix is guaranteed to return 0
when it can't parse, removed the "ok" code. Also changed the unusual
syntax "float(1.0)" to just "1", which works just as well.
(WebCore::findScaleValue): Ditto.
(WebCore::findUserScalableValue): Ditto.

  • html/parser/HTMLParserIdioms.cpp:

(WebCore::parseToDoubleForNumberType): Removed an unneeded code path
and replaced it with an assertion; toDouble no longer will return infinity
or not-a-number values.

Source/WTF:

Replaced the strtod function template with a parseDouble function, eliminating
the following unneeded features:

  • need for a trailing null character and a call to strlen
  • needless conversion of string lengths from size_t to int and back that created the possibility of incorrect truncation
  • one level of function call; use inlining instead
  • construction of the StringToDoubleConverter object; it was used to pass arguments that are known at compile time
  • most of the StringToDoubleConverter::StringToDouble function's body; it was code we did not need
  • parsing of Infinity and NaN at the strtod level; added recently when we moved from the old strtod to the new one, and not needed or helpful at this level
  • multiple copies of code to narrow to single byte strings; in many cases this was done even when starting with an LChar string that is already single-byte, now we handle this with an overload of parseDouble
  • wtf/dtoa.cpp:

Removed a long comment about the original strtod function that no longer
applies since we deleted that function long ago. Removed a lot of includes.
Removed the strtod function templates and its instantiations, since they
are now replaced by the parseDouble function.
(WTF::Internal::parseDoubleFromLongString): Added.

  • wtf/dtoa.h:

Added an include of ASCIICType.h so we can use isASCII in a function in this
header. Left the heretofore unneeded include of double-conversion.h, since we
now want to use it in a function in this header. Removed the AllowTrailingJunkTag
and AllowTrailingSpacesTag enumerations and the strtod function template. Added
new parseDouble function, and inline implementation of it.

  • wtf/dtoa/double-conversion.cc: Removed quite a bit of unused code, hardcoding

all the StringToDouble function arguments that come from data members so it can
be a much smaller static member function. Also changed the types of arguments
from int to size_t.

  • wtf/dtoa/double-conversion.h: Removed most of the StringToDoubleConverter

class, leaving only the conversion function as a static member function.

  • wtf/text/StringImpl.cpp:

(WTF::StringImpl::toDouble): Got rid of didReadNumber.
(WTF::StringImpl::toFloat): Ditto.

  • wtf/text/StringImpl.h: Ditto.
  • wtf/text/WTFString.cpp:

(WTF::String::toDouble): Got rid of didReadNumber.
(WTF::String::toFloat): Ditto.
(WTF::toDoubleType): Rewrote this function to use parseDouble. Moved the code
to skip leading spaces here, because other callers of parseDouble don't want
to do that. Repurposed the check for an empty string so it's now the same
code shared by all the "parsed nothing" cases. Removed the code to convert
the buffer to ASCII for two reasons: (1) We don't need that code at all when
CharType is LChar, and (2) We now handle this through the two overloads for
the parseDouble function. Disallowing trailing junk is now handled here,
rather than inside parseDouble.
(WTF::charactersToDouble): Updated for changes to toDoubleType. Removed the
didReadNumber argument.
(WTF::charactersToFloat): Ditto. Also added overloads that return the parsed
length. These are a slightly more powerful way to do what didReadNumber was
used for before.

  • wtf/text/WTFString.h: Added comments, eliminated didReadNumber, and added

overloads of charactersToFloat that replace charactersToFloatIgnoringJunk.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r113363 r113454  
    22 *  Copyright (C) 1999-2002 Harri Porten ([email protected])
    33 *  Copyright (C) 2001 Peter Kelly ([email protected])
    4  *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
     4 *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
    55 *  Copyright (C) 2007 Cameron Zwarich ([email protected])
    66 *  Copyright (C) 2007 Maks Orlovich
     
    296296        ++p;
    297297    }
    298     if (number >= mantissaOverflowLowerBound) {
    299         if (radix == 10)
    300             number = WTF::strtod<WTF::AllowTrailingJunk, WTF::DisallowTrailingSpaces>(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), 0);
    301         else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
    302             number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix);
    303     }
    304298
    305299    // 12. If Z is empty, return NaN.
    306300    if (!sawDigit)
    307301        return std::numeric_limits<double>::quiet_NaN();
     302
     303    // Alternate code path for certain large numbers.
     304    if (number >= mantissaOverflowLowerBound) {
     305        if (radix == 10) {
     306            size_t parsedLength;
     307            number = parseDouble(s.characters() + firstDigitPosition, p - firstDigitPosition, parsedLength);
     308        } else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
     309            number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix);
     310    }
    308311
    309312    // 15. Return sign x number.
     
    357360
    358361// See ecma-262 9.3.1
    359 template <WTF::AllowTrailingJunkTag allowTrailingJunk, typename CharType>
     362template <typename CharType>
    360363static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
    361364{
    362365    ASSERT(data < end);
    363366
    364     // Copy the sting into a null-terminated byte buffer, and call strtod.
    365     Vector<char, 32> byteBuffer;
    366     for (const CharType* characters = data; characters < end; ++characters) {
    367         CharType character = *characters;
    368         byteBuffer.append(isASCII(character) ? static_cast<char>(character) : 0);
    369     }
    370     byteBuffer.append(0);
    371     char* endOfNumber;
    372     double number = WTF::strtod<allowTrailingJunk, WTF::AllowTrailingSpaces>(byteBuffer.data(), &endOfNumber);
    373 
    374     // Check if strtod found a number; if so return it.
    375     ptrdiff_t consumed = endOfNumber - byteBuffer.data();
    376     if (consumed) {
    377         data += consumed;
     367    size_t parsedLength;
     368    double number = parseDouble(data, end - data, parsedLength);
     369    if (parsedLength) {
     370        data += parsedLength;
    378371        return number;
    379372    }
     
    426419        number = jsHexIntegerLiteral(characters, endCharacters);
    427420    else
    428         number = jsStrDecimalLiteral<WTF::DisallowTrailingJunk>(characters, endCharacters);
     421        number = jsStrDecimalLiteral(characters, endCharacters);
    429422   
    430423    // Allow trailing white space.
     
    483476            return std::numeric_limits<double>::quiet_NaN();
    484477
    485         return jsStrDecimalLiteral<WTF::AllowTrailingJunk>(data, end);
     478        return jsStrDecimalLiteral(data, end);
    486479    }
    487480
     
    499492        return std::numeric_limits<double>::quiet_NaN();
    500493
    501     return jsStrDecimalLiteral<WTF::AllowTrailingJunk>(data, end);
     494    return jsStrDecimalLiteral(data, end);
    502495}
    503496
Note: See TracChangeset for help on using the changeset viewer.