зеркало из https://github.com/mozilla/gecko-dev.git
Bug 722788 - Use integer math to parse sufficiently-small decimal numbers in JSON text. r=waldo
--HG-- extra : rebase_source : 8bd72909ce94b65ce68b8cb3b64b42948fe24026
This commit is contained in:
Родитель
c2b6007224
Коммит
e893b8a32a
|
@ -174,6 +174,24 @@ ComputeAccurateBinaryBaseInteger(const jschar *start, const jschar *end, int bas
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
js::ParseDecimalNumber(const JS::TwoByteChars chars)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(chars.length() > 0);
|
||||||
|
uint64_t dec = 0;
|
||||||
|
RangedPtr<jschar> s = chars.start(), end = chars.end();
|
||||||
|
do {
|
||||||
|
jschar c = *s;
|
||||||
|
MOZ_ASSERT('0' <= c && c <= '9');
|
||||||
|
uint8_t digit = c - '0';
|
||||||
|
uint64_t next = dec * 10 + digit;
|
||||||
|
MOZ_ASSERT(next < DOUBLE_INTEGRAL_PRECISION_LIMIT,
|
||||||
|
"next value won't be an integrally-precise double");
|
||||||
|
dec = next;
|
||||||
|
} while (++s < end);
|
||||||
|
return static_cast<double>(dec);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
js::GetPrefixInteger(JSContext *cx, const jschar *start, const jschar *end, int base,
|
js::GetPrefixInteger(JSContext *cx, const jschar *start, const jschar *end, int base,
|
||||||
const jschar **endp, double *dp)
|
const jschar **endp, double *dp)
|
||||||
|
|
|
@ -108,6 +108,15 @@ NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base = 10);
|
||||||
*/
|
*/
|
||||||
const double DOUBLE_INTEGRAL_PRECISION_LIMIT = uint64_t(1) << 53;
|
const double DOUBLE_INTEGRAL_PRECISION_LIMIT = uint64_t(1) << 53;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse a decimal number encoded in |chars|. The decimal number must be
|
||||||
|
* sufficiently small that it will not overflow the integrally-precise range of
|
||||||
|
* the double type -- that is, the number will be smaller than
|
||||||
|
* DOUBLE_INTEGRAL_PRECISION_LIMIT
|
||||||
|
*/
|
||||||
|
extern double
|
||||||
|
ParseDecimalNumber(const JS::TwoByteChars chars);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute the positive integer of the given base described immediately at the
|
* Compute the positive integer of the given base described immediately at the
|
||||||
* start of the range [start, end) -- no whitespace-skipping, no magical
|
* start of the range [start, end) -- no whitespace-skipping, no magical
|
||||||
|
|
|
@ -222,8 +222,18 @@ JSONParser::readNumber()
|
||||||
|
|
||||||
/* Fast path: no fractional or exponent part. */
|
/* Fast path: no fractional or exponent part. */
|
||||||
if (current == end || (*current != '.' && *current != 'e' && *current != 'E')) {
|
if (current == end || (*current != '.' && *current != 'e' && *current != 'E')) {
|
||||||
const jschar *dummy;
|
TwoByteChars chars(digitStart.get(), current - digitStart);
|
||||||
|
if (chars.length() < strlen("9007199254740992")) {
|
||||||
|
// If the decimal number is shorter than the length of 2**53, (the
|
||||||
|
// largest number a double can represent with integral precision),
|
||||||
|
// parse it using a decimal-only parser. This comparison is
|
||||||
|
// conservative but faster than a fully-precise check.
|
||||||
|
double d = ParseDecimalNumber(chars);
|
||||||
|
return numberToken(negative ? -d : d);
|
||||||
|
}
|
||||||
|
|
||||||
double d;
|
double d;
|
||||||
|
const jschar *dummy;
|
||||||
if (!GetPrefixInteger(cx, digitStart.get(), current.get(), 10, &dummy, &d))
|
if (!GetPrefixInteger(cx, digitStart.get(), current.get(), 10, &dummy, &d))
|
||||||
return token(OOM);
|
return token(OOM);
|
||||||
JS_ASSERT(current == dummy);
|
JS_ASSERT(current == dummy);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче