1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 * JS number type and wrapper class.
13 #include "mozilla/FloatingPoint.h"
14 #include "mozilla/PodOperations.h"
15 #include "mozilla/RangedPtr.h"
17 #ifdef HAVE_LOCALECONV
23 #include "double-conversion.h"
31 #include "vm/GlobalObject.h"
32 #include "vm/NumericConversions.h"
33 #include "vm/StringBuffer.h"
35 #include "jsatominlines.h"
37 #include "vm/NumberObject-inl.h"
38 #include "vm/String-inl.h"
41 using namespace js::types
;
44 using mozilla::ArrayLength
;
45 using mozilla::MinNumberValue
;
46 using mozilla::NegativeInfinity
;
47 using mozilla::PodCopy
;
48 using mozilla::PositiveInfinity
;
49 using mozilla::RangedPtr
;
51 using JS::AutoCheckCannotGC
;
55 * If we're accumulating a decimal number and the number is >= 2^53, then the
56 * fast result from the loop in Get{Prefix,Decimal}Integer may be inaccurate.
57 * Call js_strtod_harder to get the correct answer.
59 template <typename CharT
>
61 ComputeAccurateDecimalInteger(ThreadSafeContext
*cx
, const CharT
*start
, const CharT
*end
,
64 size_t length
= end
- start
;
65 ScopedJSFreePtr
<char> cstr(cx
->pod_malloc
<char>(length
+ 1));
69 for (size_t i
= 0; i
< length
; i
++) {
70 char c
= char(start
[i
]);
71 JS_ASSERT(('0' <= c
&& c
<= '9') || ('a' <= c
&& c
<= 'z') || ('A' <= c
&& c
<= 'Z'));
78 *dp
= js_strtod_harder(cx
->dtoaState(), cstr
, &estr
, &err
);
79 if (err
== JS_DTOA_ENOMEM
) {
80 js_ReportOutOfMemory(cx
);
89 template <typename CharT
>
90 class BinaryDigitReader
92 const int base
; /* Base of number; must be a power of 2 */
93 int digit
; /* Current digit value in radix given by base */
94 int digitMask
; /* Mask to extract the next bit from digit */
95 const CharT
*start
; /* Pointer to the remaining digits */
96 const CharT
*end
; /* Pointer to first non-digit */
99 BinaryDigitReader(int base
, const CharT
*start
, const CharT
*end
)
100 : base(base
), digit(0), digitMask(0), start(start
), end(end
)
104 /* Return the next binary digit from the number, or -1 if done. */
106 if (digitMask
== 0) {
111 JS_ASSERT(('0' <= c
&& c
<= '9') || ('a' <= c
&& c
<= 'z') || ('A' <= c
&& c
<= 'Z'));
112 if ('0' <= c
&& c
<= '9')
114 else if ('a' <= c
&& c
<= 'z')
115 digit
= c
- 'a' + 10;
117 digit
= c
- 'A' + 10;
118 digitMask
= base
>> 1;
121 int bit
= (digit
& digitMask
) != 0;
127 } /* anonymous namespace */
130 * The fast result might also have been inaccurate for power-of-two bases. This
131 * happens if the addition in value * 2 + digit causes a round-down to an even
132 * least significant mantissa bit when the first dropped bit is a one. If any
133 * of the following digits in the number (which haven't been added in yet) are
134 * nonzero, then the correct action would have been to round up instead of
135 * down. An example occurs when reading the number 0x1000000000000081, which
136 * rounds to 0x1000000000000000 instead of 0x1000000000000100.
138 template <typename CharT
>
140 ComputeAccurateBinaryBaseInteger(const CharT
*start
, const CharT
*end
, int base
)
142 BinaryDigitReader
<CharT
> bdr(base
, start
, end
);
144 /* Skip leading zeroes. */
147 bit
= bdr
.nextDigit();
150 JS_ASSERT(bit
== 1); // guaranteed by Get{Prefix,Decimal}Integer
152 /* Gather the 53 significant bits (including the leading 1). */
154 for (int j
= 52; j
> 0; j
--) {
155 bit
= bdr
.nextDigit();
158 value
= value
* 2 + bit
;
161 /* bit2 is the 54th bit (the first dropped from the mantissa). */
162 int bit2
= bdr
.nextDigit();
165 int sticky
= 0; /* sticky is 1 if any bit beyond the 54th is 1 */
168 while ((bit3
= bdr
.nextDigit()) >= 0) {
172 value
+= bit2
& (bit
| sticky
);
179 template <typename CharT
>
181 js::ParseDecimalNumber(const mozilla::Range
<const CharT
> chars
)
183 MOZ_ASSERT(chars
.length() > 0);
185 RangedPtr
<const CharT
> s
= chars
.start(), end
= chars
.end();
188 MOZ_ASSERT('0' <= c
&& c
<= '9');
189 uint8_t digit
= c
- '0';
190 uint64_t next
= dec
* 10 + digit
;
191 MOZ_ASSERT(next
< DOUBLE_INTEGRAL_PRECISION_LIMIT
,
192 "next value won't be an integrally-precise double");
195 return static_cast<double>(dec
);
199 js::ParseDecimalNumber(const mozilla::Range
<const Latin1Char
> chars
);
202 js::ParseDecimalNumber(const mozilla::Range
<const jschar
> chars
);
204 template <typename CharT
>
206 js::GetPrefixInteger(ThreadSafeContext
*cx
, const CharT
*start
, const CharT
*end
, int base
,
207 const CharT
**endp
, double *dp
)
209 JS_ASSERT(start
<= end
);
210 JS_ASSERT(2 <= base
&& base
<= 36);
212 const CharT
*s
= start
;
214 for (; s
< end
; s
++) {
217 if ('0' <= c
&& c
<= '9')
219 else if ('a' <= c
&& c
<= 'z')
220 digit
= c
- 'a' + 10;
221 else if ('A' <= c
&& c
<= 'Z')
222 digit
= c
- 'A' + 10;
227 d
= d
* base
+ digit
;
233 /* If we haven't reached the limit of integer precision, we're done. */
234 if (d
< DOUBLE_INTEGRAL_PRECISION_LIMIT
)
238 * Otherwise compute the correct integer from the prefix of valid digits
239 * if we're computing for base ten or a power of two. Don't worry about
240 * other bases; see 15.1.2.2 step 13.
243 return ComputeAccurateDecimalInteger(cx
, start
, s
, dp
);
245 if ((base
& (base
- 1)) == 0)
246 *dp
= ComputeAccurateBinaryBaseInteger(start
, s
, base
);
252 js::GetPrefixInteger(ThreadSafeContext
*cx
, const jschar
*start
, const jschar
*end
, int base
,
253 const jschar
**endp
, double *dp
);
256 js::GetPrefixInteger(ThreadSafeContext
*cx
, const Latin1Char
*start
, const Latin1Char
*end
,
257 int base
, const Latin1Char
**endp
, double *dp
);
260 js::GetDecimalInteger(ExclusiveContext
*cx
, const jschar
*start
, const jschar
*end
, double *dp
)
262 JS_ASSERT(start
<= end
);
264 const jschar
*s
= start
;
266 for (; s
< end
; s
++) {
268 JS_ASSERT('0' <= c
&& c
<= '9');
275 // If we haven't reached the limit of integer precision, we're done.
276 if (d
< DOUBLE_INTEGRAL_PRECISION_LIMIT
)
279 // Otherwise compute the correct integer from the prefix of valid digits.
280 return ComputeAccurateDecimalInteger(cx
, start
, s
, dp
);
284 num_parseFloat(JSContext
*cx
, unsigned argc
, Value
*vp
)
286 CallArgs args
= CallArgsFromVp(argc
, vp
);
288 if (args
.length() == 0) {
289 args
.rval().setNaN();
293 JSString
*str
= ToString
<CanGC
>(cx
, args
[0]);
297 JSLinearString
*linear
= str
->ensureLinear(cx
);
302 AutoCheckCannotGC nogc
;
303 if (linear
->hasLatin1Chars()) {
304 const Latin1Char
*begin
= linear
->latin1Chars(nogc
);
305 const Latin1Char
*end
;
306 if (!js_strtod(cx
, begin
, begin
+ linear
->length(), &end
, &d
))
311 const jschar
*begin
= linear
->twoByteChars(nogc
);
313 if (!js_strtod(cx
, begin
, begin
+ linear
->length(), &end
, &d
))
319 args
.rval().setDouble(d
);
323 template <typename CharT
>
325 ParseIntImpl(JSContext
*cx
, const CharT
*chars
, size_t length
, bool stripPrefix
, int32_t radix
,
329 const CharT
*end
= chars
+ length
;
330 const CharT
*s
= SkipSpace(chars
, end
);
332 MOZ_ASSERT(chars
<= s
);
333 MOZ_ASSERT(s
<= end
);
336 bool negative
= (s
!= end
&& s
[0] == '-');
339 if (s
!= end
&& (s
[0] == '-' || s
[0] == '+'))
344 if (end
- s
>= 2 && s
[0] == '0' && (s
[1] == 'x' || s
[1] == 'X')) {
351 const CharT
*actualEnd
;
353 if (!GetPrefixInteger(cx
, s
, end
, radix
, &actualEnd
, &d
))
359 *res
= negative
? -d
: d
;
365 js::num_parseInt(JSContext
*cx
, unsigned argc
, Value
*vp
)
367 CallArgs args
= CallArgsFromVp(argc
, vp
);
369 /* Fast paths and exceptional cases. */
370 if (args
.length() == 0) {
371 args
.rval().setNaN();
375 if (args
.length() == 1 ||
376 (args
[1].isInt32() && (args
[1].toInt32() == 0 || args
[1].toInt32() == 10))) {
377 if (args
[0].isInt32()) {
378 args
.rval().set(args
[0]);
383 * Step 1 is |inputString = ToString(string)|. When string >=
384 * 1e21, ToString(string) is in the form "NeM". 'e' marks the end of
385 * the word, which would mean the result of parseInt(string) should be |N|.
387 * To preserve this behaviour, we can't use the fast-path when string >
388 * 1e21, or else the result would be |NeM|.
390 * The same goes for values smaller than 1.0e-6, because the string would be in
391 * the form of "Ne-M".
393 if (args
[0].isDouble()) {
394 double d
= args
[0].toDouble();
395 if (1.0e-6 < d
&& d
< 1.0e21
) {
396 args
.rval().setNumber(floor(d
));
399 if (-1.0e21
< d
&& d
< -1.0e-6) {
400 args
.rval().setNumber(-floor(-d
));
404 args
.rval().setInt32(0);
411 RootedString
inputString(cx
, ToString
<CanGC
>(cx
, args
[0]));
414 args
[0].setString(inputString
);
417 bool stripPrefix
= true;
419 if (!args
.hasDefined(1)) {
422 if (!ToInt32(cx
, args
[1], &radix
))
427 if (radix
< 2 || radix
> 36) {
428 args
.rval().setNaN();
436 JSLinearString
*linear
= inputString
->ensureLinear(cx
);
440 AutoCheckCannotGC nogc
;
441 size_t length
= inputString
->length();
443 if (linear
->hasLatin1Chars()) {
444 if (!ParseIntImpl(cx
, linear
->latin1Chars(nogc
), length
, stripPrefix
, radix
, &number
))
447 if (!ParseIntImpl(cx
, linear
->twoByteChars(nogc
), length
, stripPrefix
, radix
, &number
))
451 args
.rval().setNumber(number
);
455 static const JSFunctionSpec number_functions
[] = {
456 JS_SELF_HOSTED_FN(js_isNaN_str
, "Global_isNaN", 1,0),
457 JS_SELF_HOSTED_FN(js_isFinite_str
, "Global_isFinite", 1,0),
458 JS_FN(js_parseFloat_str
, num_parseFloat
, 1,0),
459 JS_FN(js_parseInt_str
, num_parseInt
, 2,0),
463 const Class
NumberObject::class_
= {
465 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number
),
466 JS_PropertyStub
, /* addProperty */
467 JS_DeletePropertyStub
, /* delProperty */
468 JS_PropertyStub
, /* getProperty */
469 JS_StrictPropertyStub
, /* setProperty */
476 Number(JSContext
*cx
, unsigned argc
, Value
*vp
)
478 CallArgs args
= CallArgsFromVp(argc
, vp
);
480 /* Sample JS_CALLEE before clobbering. */
481 bool isConstructing
= args
.isConstructing();
483 if (args
.length() > 0) {
484 if (!ToNumber(cx
, args
[0]))
486 args
.rval().set(args
[0]);
488 args
.rval().setInt32(0);
494 JSObject
*obj
= NumberObject::create(cx
, args
.rval().toNumber());
497 args
.rval().setObject(*obj
);
501 MOZ_ALWAYS_INLINE
bool
502 IsNumber(HandleValue v
)
504 return v
.isNumber() || (v
.isObject() && v
.toObject().is
<NumberObject
>());
508 Extract(const Value
&v
)
512 return v
.toObject().as
<NumberObject
>().unbox();
516 MOZ_ALWAYS_INLINE
bool
517 num_toSource_impl(JSContext
*cx
, CallArgs args
)
519 double d
= Extract(args
.thisv());
522 if (!sb
.append("(new Number(") ||
523 !NumberValueToStringBuffer(cx
, NumberValue(d
), sb
) ||
529 JSString
*str
= sb
.finishString();
532 args
.rval().setString(str
);
537 num_toSource(JSContext
*cx
, unsigned argc
, Value
*vp
)
539 CallArgs args
= CallArgsFromVp(argc
, vp
);
540 return CallNonGenericMethod
<IsNumber
, num_toSource_impl
>(cx
, args
);
544 ToCStringBuf::ToCStringBuf() :dbuf(nullptr)
546 JS_STATIC_ASSERT(sbufSize
>= DTOSTR_STANDARD_BUFFER_SIZE
);
549 ToCStringBuf::~ToCStringBuf()
555 static JSFlatString
*
556 LookupDtoaCache(ThreadSafeContext
*cx
, double d
)
558 if (!cx
->isExclusiveContext())
561 if (JSCompartment
*comp
= cx
->asExclusiveContext()->compartment()) {
562 if (JSFlatString
*str
= comp
->dtoaCache
.lookup(10, d
))
571 CacheNumber(ThreadSafeContext
*cx
, double d
, JSFlatString
*str
)
573 if (!cx
->isExclusiveContext())
576 if (JSCompartment
*comp
= cx
->asExclusiveContext()->compartment())
577 comp
->dtoaCache
.cache(10, d
, str
);
581 static JSFlatString
*
582 LookupInt32ToString(ThreadSafeContext
*cx
, int32_t si
)
584 if (si
>= 0 && StaticStrings::hasInt(si
))
585 return cx
->staticStrings().getInt(si
);
587 return LookupDtoaCache(cx
, si
);
590 template <typename T
>
593 BackfillInt32InBuffer(int32_t si
, T
*buffer
, size_t size
, size_t *length
)
595 uint32_t ui
= Abs(si
);
596 JS_ASSERT_IF(si
== INT32_MIN
, ui
== uint32_t(INT32_MAX
) + 1);
598 RangedPtr
<T
> end(buffer
+ size
- 1, buffer
, size
);
600 RangedPtr
<T
> start
= BackfillIndexInCharBuffer(ui
, end
);
604 *length
= end
- start
;
608 template <AllowGC allowGC
>
610 js::Int32ToString(ThreadSafeContext
*cx
, int32_t si
)
612 if (JSFlatString
*str
= LookupInt32ToString(cx
, si
))
615 Latin1Char buffer
[JSFatInlineString::MAX_LENGTH_LATIN1
+ 1];
617 Latin1Char
*start
= BackfillInt32InBuffer(si
, buffer
, ArrayLength(buffer
), &length
);
619 mozilla::Range
<const Latin1Char
> chars(start
, length
);
620 JSInlineString
*str
= NewFatInlineString
<allowGC
>(cx
, chars
);
624 CacheNumber(cx
, si
, str
);
628 template JSFlatString
*
629 js::Int32ToString
<CanGC
>(ThreadSafeContext
*cx
, int32_t si
);
631 template JSFlatString
*
632 js::Int32ToString
<NoGC
>(ThreadSafeContext
*cx
, int32_t si
);
635 js::Int32ToAtom(ExclusiveContext
*cx
, int32_t si
)
637 if (JSFlatString
*str
= LookupInt32ToString(cx
, si
))
638 return js::AtomizeString(cx
, str
);
640 char buffer
[JSFatInlineString::MAX_LENGTH_TWO_BYTE
+ 1];
642 char *start
= BackfillInt32InBuffer(si
, buffer
, JSFatInlineString::MAX_LENGTH_TWO_BYTE
+ 1, &length
);
644 JSAtom
*atom
= Atomize(cx
, start
, length
);
648 CacheNumber(cx
, si
, atom
);
652 /* Returns a non-nullptr pointer to inside cbuf. */
654 Int32ToCString(ToCStringBuf
*cbuf
, int32_t i
, size_t *len
, int base
= 10)
658 RangedPtr
<char> cp(cbuf
->sbuf
+ ToCStringBuf::sbufSize
- 1, cbuf
->sbuf
, ToCStringBuf::sbufSize
);
659 char *end
= cp
.get();
662 /* Build the string from behind. */
665 cp
= BackfillIndexInCharBuffer(u
, cp
);
669 unsigned newu
= u
/ 16;
670 *--cp
= "0123456789abcdef"[u
- newu
* 16];
675 JS_ASSERT(base
>= 2 && base
<= 36);
677 unsigned newu
= u
/ base
;
678 *--cp
= "0123456789abcdefghijklmnopqrstuvwxyz"[u
- newu
* base
];
686 *len
= end
- cp
.get();
690 template <AllowGC allowGC
>
691 static JSString
* JS_FASTCALL
692 js_NumberToStringWithBase(ThreadSafeContext
*cx
, double d
, int base
);
694 MOZ_ALWAYS_INLINE
bool
695 num_toString_impl(JSContext
*cx
, CallArgs args
)
697 JS_ASSERT(IsNumber(args
.thisv()));
699 double d
= Extract(args
.thisv());
702 if (args
.hasDefined(0)) {
704 if (!ToInteger(cx
, args
[0], &d2
))
707 if (d2
< 2 || d2
> 36) {
708 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_BAD_RADIX
);
714 JSString
*str
= js_NumberToStringWithBase
<CanGC
>(cx
, d
, base
);
716 JS_ReportOutOfMemory(cx
);
719 args
.rval().setString(str
);
724 js_num_toString(JSContext
*cx
, unsigned argc
, Value
*vp
)
726 CallArgs args
= CallArgsFromVp(argc
, vp
);
727 return CallNonGenericMethod
<IsNumber
, num_toString_impl
>(cx
, args
);
731 MOZ_ALWAYS_INLINE
bool
732 num_toLocaleString_impl(JSContext
*cx
, CallArgs args
)
734 JS_ASSERT(IsNumber(args
.thisv()));
736 double d
= Extract(args
.thisv());
738 Rooted
<JSString
*> str(cx
, js_NumberToStringWithBase
<CanGC
>(cx
, d
, 10));
740 JS_ReportOutOfMemory(cx
);
745 * Create the string, move back to bytes to make string twiddling
746 * a bit easier and so we can insert platform charset seperators.
748 JSAutoByteString
numBytes(cx
, str
);
751 const char *num
= numBytes
.ptr();
756 * Find the first non-integer value, whether it be a letter as in
757 * 'Infinity', a decimal point, or an 'e' from exponential notation.
759 const char *nint
= num
;
762 while (*nint
>= '0' && *nint
<= '9')
764 int digits
= nint
- num
;
765 const char *end
= num
+ digits
;
767 args
.rval().setString(str
);
771 JSRuntime
*rt
= cx
->runtime();
772 size_t thousandsLength
= strlen(rt
->thousandsSeparator
);
773 size_t decimalLength
= strlen(rt
->decimalSeparator
);
775 /* Figure out how long resulting string will be. */
776 int buflen
= strlen(num
);
778 buflen
+= decimalLength
- 1; /* -1 to account for existing '.' */
780 const char *numGrouping
;
781 const char *tmpGroup
;
782 numGrouping
= tmpGroup
= rt
->numGrouping
;
783 int remainder
= digits
;
787 while (*tmpGroup
!= CHAR_MAX
&& *tmpGroup
!= '\0') {
788 if (*tmpGroup
>= remainder
)
790 buflen
+= thousandsLength
;
791 remainder
-= *tmpGroup
;
796 if (*tmpGroup
== '\0' && *numGrouping
!= '\0') {
797 nrepeat
= (remainder
- 1) / tmpGroup
[-1];
798 buflen
+= thousandsLength
* nrepeat
;
799 remainder
-= nrepeat
* tmpGroup
[-1];
805 char *buf
= cx
->pod_malloc
<char>(buflen
+ 1);
810 const char *tmpSrc
= num
;
812 while (*tmpSrc
== '-' || remainder
--) {
813 JS_ASSERT(tmpDest
- buf
< buflen
);
814 *tmpDest
++ = *tmpSrc
++;
816 while (tmpSrc
< end
) {
817 JS_ASSERT(tmpDest
- buf
+ ptrdiff_t(thousandsLength
) <= buflen
);
818 strcpy(tmpDest
, rt
->thousandsSeparator
);
819 tmpDest
+= thousandsLength
;
820 JS_ASSERT(tmpDest
- buf
+ *tmpGroup
<= buflen
);
821 js_memcpy(tmpDest
, tmpSrc
, *tmpGroup
);
822 tmpDest
+= *tmpGroup
;
829 JS_ASSERT(tmpDest
- buf
+ ptrdiff_t(decimalLength
) <= buflen
);
830 strcpy(tmpDest
, rt
->decimalSeparator
);
831 tmpDest
+= decimalLength
;
832 JS_ASSERT(tmpDest
- buf
+ ptrdiff_t(strlen(nint
+ 1)) <= buflen
);
833 strcpy(tmpDest
, nint
+ 1);
835 JS_ASSERT(tmpDest
- buf
+ ptrdiff_t(strlen(nint
)) <= buflen
);
836 strcpy(tmpDest
, nint
);
839 if (cx
->runtime()->localeCallbacks
&& cx
->runtime()->localeCallbacks
->localeToUnicode
) {
840 Rooted
<Value
> v(cx
, StringValue(str
));
841 bool ok
= !!cx
->runtime()->localeCallbacks
->localeToUnicode(cx
, buf
, &v
);
848 str
= NewStringCopyN
<CanGC
>(cx
, buf
, buflen
);
853 args
.rval().setString(str
);
858 num_toLocaleString(JSContext
*cx
, unsigned argc
, Value
*vp
)
860 CallArgs args
= CallArgsFromVp(argc
, vp
);
861 return CallNonGenericMethod
<IsNumber
, num_toLocaleString_impl
>(cx
, args
);
863 #endif /* !EXPOSE_INTL_API */
865 MOZ_ALWAYS_INLINE
bool
866 num_valueOf_impl(JSContext
*cx
, CallArgs args
)
868 JS_ASSERT(IsNumber(args
.thisv()));
869 args
.rval().setNumber(Extract(args
.thisv()));
874 js_num_valueOf(JSContext
*cx
, unsigned argc
, Value
*vp
)
876 CallArgs args
= CallArgsFromVp(argc
, vp
);
877 return CallNonGenericMethod
<IsNumber
, num_valueOf_impl
>(cx
, args
);
880 static const unsigned MAX_PRECISION
= 100;
883 ComputePrecisionInRange(JSContext
*cx
, int minPrecision
, int maxPrecision
, HandleValue v
,
887 if (!ToInteger(cx
, v
, &prec
))
889 if (minPrecision
<= prec
&& prec
<= maxPrecision
) {
890 *precision
= int(prec
);
895 if (char *numStr
= NumberToCString(cx
, &cbuf
, prec
, 10))
896 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, nullptr, JSMSG_PRECISION_RANGE
, numStr
);
901 DToStrResult(JSContext
*cx
, double d
, JSDToStrMode mode
, int precision
, CallArgs args
)
903 char buf
[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION
+ 1)];
904 char *numStr
= js_dtostr(cx
->mainThread().dtoaState
, buf
, sizeof buf
, mode
, precision
, d
);
906 JS_ReportOutOfMemory(cx
);
909 JSString
*str
= NewStringCopyZ
<CanGC
>(cx
, numStr
);
912 args
.rval().setString(str
);
917 * In the following three implementations, we allow a larger range of precision
918 * than ECMA requires; this is permitted by ECMA-262.
920 MOZ_ALWAYS_INLINE
bool
921 num_toFixed_impl(JSContext
*cx
, CallArgs args
)
923 JS_ASSERT(IsNumber(args
.thisv()));
926 if (args
.length() == 0) {
929 if (!ComputePrecisionInRange(cx
, -20, MAX_PRECISION
, args
[0], &precision
))
933 return DToStrResult(cx
, Extract(args
.thisv()), DTOSTR_FIXED
, precision
, args
);
937 num_toFixed(JSContext
*cx
, unsigned argc
, Value
*vp
)
939 CallArgs args
= CallArgsFromVp(argc
, vp
);
940 return CallNonGenericMethod
<IsNumber
, num_toFixed_impl
>(cx
, args
);
943 MOZ_ALWAYS_INLINE
bool
944 num_toExponential_impl(JSContext
*cx
, CallArgs args
)
946 JS_ASSERT(IsNumber(args
.thisv()));
950 if (!args
.hasDefined(0)) {
951 mode
= DTOSTR_STANDARD_EXPONENTIAL
;
954 mode
= DTOSTR_EXPONENTIAL
;
955 if (!ComputePrecisionInRange(cx
, 0, MAX_PRECISION
, args
[0], &precision
))
959 return DToStrResult(cx
, Extract(args
.thisv()), mode
, precision
+ 1, args
);
963 num_toExponential(JSContext
*cx
, unsigned argc
, Value
*vp
)
965 CallArgs args
= CallArgsFromVp(argc
, vp
);
966 return CallNonGenericMethod
<IsNumber
, num_toExponential_impl
>(cx
, args
);
969 MOZ_ALWAYS_INLINE
bool
970 num_toPrecision_impl(JSContext
*cx
, CallArgs args
)
972 JS_ASSERT(IsNumber(args
.thisv()));
974 double d
= Extract(args
.thisv());
976 if (!args
.hasDefined(0)) {
977 JSString
*str
= js_NumberToStringWithBase
<CanGC
>(cx
, d
, 10);
979 JS_ReportOutOfMemory(cx
);
982 args
.rval().setString(str
);
987 if (!ComputePrecisionInRange(cx
, 1, MAX_PRECISION
, args
[0], &precision
))
990 return DToStrResult(cx
, d
, DTOSTR_PRECISION
, precision
, args
);
994 num_toPrecision(JSContext
*cx
, unsigned argc
, Value
*vp
)
996 CallArgs args
= CallArgsFromVp(argc
, vp
);
997 return CallNonGenericMethod
<IsNumber
, num_toPrecision_impl
>(cx
, args
);
1000 static const JSFunctionSpec number_methods
[] = {
1002 JS_FN(js_toSource_str
, num_toSource
, 0, 0),
1004 JS_FN(js_toString_str
, js_num_toString
, 1, 0),
1006 JS_SELF_HOSTED_FN(js_toLocaleString_str
, "Number_toLocaleString", 0,0),
1008 JS_FN(js_toLocaleString_str
, num_toLocaleString
, 0,0),
1010 JS_FN(js_valueOf_str
, js_num_valueOf
, 0, 0),
1011 JS_FN("toFixed", num_toFixed
, 1, 0),
1012 JS_FN("toExponential", num_toExponential
, 1, 0),
1013 JS_FN("toPrecision", num_toPrecision
, 1, 0),
1017 // ES6 draft ES6 15.7.3.12
1019 Number_isInteger(JSContext
*cx
, unsigned argc
, Value
*vp
)
1021 CallArgs args
= CallArgsFromVp(argc
, vp
);
1022 if (args
.length() < 1 || !args
[0].isNumber()) {
1023 args
.rval().setBoolean(false);
1026 Value val
= args
[0];
1027 args
.rval().setBoolean(val
.isInt32() ||
1028 (mozilla::IsFinite(val
.toDouble()) &&
1029 ToInteger(val
.toDouble()) == val
.toDouble()));
1034 static const JSFunctionSpec number_static_methods
[] = {
1035 JS_SELF_HOSTED_FN("isFinite", "Number_isFinite", 1,0),
1036 JS_FN("isInteger", Number_isInteger
, 1, 0),
1037 JS_SELF_HOSTED_FN("isNaN", "Number_isNaN", 1,0),
1038 JS_SELF_HOSTED_FN("isSafeInteger", "Number_isSafeInteger", 1,0),
1039 JS_FN("parseFloat", num_parseFloat
, 1, 0),
1040 JS_FN("parseInt", num_parseInt
, 2, 0),
1045 /* NB: Keep this in synch with number_constants[]. */
1048 NC_POSITIVE_INFINITY
,
1049 NC_NEGATIVE_INFINITY
,
1052 NC_MAX_SAFE_INTEGER
,
1053 NC_MIN_SAFE_INTEGER
,
1059 * Some to most C compilers forbid spelling these at compile time, or barf
1060 * if you try, so all but MAX_VALUE are set up by InitRuntimeNumberState
1061 * using union jsdpun.
1063 static JSConstDoubleSpec number_constants
[] = {
1064 {0, "NaN", 0,{0,0,0}},
1065 {0, "POSITIVE_INFINITY", 0,{0,0,0}},
1066 {0, "NEGATIVE_INFINITY", 0,{0,0,0}},
1067 {1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}},
1068 {0, "MIN_VALUE", 0,{0,0,0}},
1069 /* ES6 (April 2014 draft) 20.1.2.6 */
1070 {9007199254740991, "MAX_SAFE_INTEGER", 0,{0,0,0}},
1071 /* ES6 (April 2014 draft) 20.1.2.10 */
1072 {-9007199254740991, "MIN_SAFE_INTEGER", 0,{0,0,0}},
1073 /* ES6 (May 2013 draft) 15.7.3.7 */
1074 {2.2204460492503130808472633361816e-16, "EPSILON", 0,{0,0,0}},
1079 * Set the exception mask to mask all exceptions and set the FPU precision
1080 * to 53 bit mantissa (64 bit doubles).
1085 #if (defined __GNUC__ && defined __i386__) || \
1086 (defined __SUNPRO_CC && defined __i386)
1088 asm("fstcw %0" : "=m" (control
) : );
1089 control
&= ~0x300; // Lower bits 8 and 9 (precision control).
1090 control
|= 0x2f3; // Raise bits 0-5 (exception masks) and 9 (64-bit precision).
1091 asm("fldcw %0" : : "m" (control
) );
1096 js::InitRuntimeNumberState(JSRuntime
*rt
)
1101 * Our NaN must be one particular canonical value, because we rely on NaN
1102 * encoding for our value representation. See Value.h.
1104 number_constants
[NC_NaN
].dval
= GenericNaN();
1106 number_constants
[NC_POSITIVE_INFINITY
].dval
= mozilla::PositiveInfinity
<double>();
1107 number_constants
[NC_NEGATIVE_INFINITY
].dval
= mozilla::NegativeInfinity
<double>();
1109 number_constants
[NC_MIN_VALUE
].dval
= MinNumberValue
<double>();
1111 // XXX If EXPOSE_INTL_API becomes true all the time at some point,
1112 // js::InitRuntimeNumberState is no longer fallible, and we should
1113 // change its return type.
1114 #if !EXPOSE_INTL_API
1115 /* Copy locale-specific separators into the runtime strings. */
1116 const char *thousandsSeparator
, *decimalPoint
, *grouping
;
1117 #ifdef HAVE_LOCALECONV
1118 struct lconv
*locale
= localeconv();
1119 thousandsSeparator
= locale
->thousands_sep
;
1120 decimalPoint
= locale
->decimal_point
;
1121 grouping
= locale
->grouping
;
1123 thousandsSeparator
= getenv("LOCALE_THOUSANDS_SEP");
1124 decimalPoint
= getenv("LOCALE_DECIMAL_POINT");
1125 grouping
= getenv("LOCALE_GROUPING");
1127 if (!thousandsSeparator
)
1128 thousandsSeparator
= "'";
1135 * We use single malloc to get the memory for all separator and grouping
1138 size_t thousandsSeparatorSize
= strlen(thousandsSeparator
) + 1;
1139 size_t decimalPointSize
= strlen(decimalPoint
) + 1;
1140 size_t groupingSize
= strlen(grouping
) + 1;
1142 char *storage
= js_pod_malloc
<char>(thousandsSeparatorSize
+
1148 js_memcpy(storage
, thousandsSeparator
, thousandsSeparatorSize
);
1149 rt
->thousandsSeparator
= storage
;
1150 storage
+= thousandsSeparatorSize
;
1152 js_memcpy(storage
, decimalPoint
, decimalPointSize
);
1153 rt
->decimalSeparator
= storage
;
1154 storage
+= decimalPointSize
;
1156 js_memcpy(storage
, grouping
, groupingSize
);
1157 rt
->numGrouping
= grouping
;
1158 #endif /* !EXPOSE_INTL_API */
1162 #if !EXPOSE_INTL_API
1164 js::FinishRuntimeNumberState(JSRuntime
*rt
)
1167 * The free also releases the memory for decimalSeparator and numGrouping
1170 char *storage
= const_cast<char *>(rt
->thousandsSeparator
);
1176 js_InitNumberClass(JSContext
*cx
, HandleObject obj
)
1178 JS_ASSERT(obj
->isNative());
1180 /* XXX must do at least once per new thread, so do it per JSContext... */
1183 Rooted
<GlobalObject
*> global(cx
, &obj
->as
<GlobalObject
>());
1185 RootedObject
numberProto(cx
, global
->createBlankPrototype(cx
, &NumberObject::class_
));
1188 numberProto
->as
<NumberObject
>().setPrimitiveValue(0);
1190 RootedFunction
ctor(cx
);
1191 ctor
= global
->createConstructor(cx
, Number
, cx
->names().Number
, 1);
1195 if (!LinkConstructorAndPrototype(cx
, ctor
, numberProto
))
1198 /* Add numeric constants (MAX_VALUE, NaN, &c.) to the Number constructor. */
1199 if (!JS_DefineConstDoubles(cx
, ctor
, number_constants
))
1202 if (!DefinePropertiesAndFunctions(cx
, ctor
, nullptr, number_static_methods
))
1205 if (!DefinePropertiesAndFunctions(cx
, numberProto
, nullptr, number_methods
))
1208 if (!JS_DefineFunctions(cx
, global
, number_functions
))
1211 RootedValue
valueNaN(cx
, cx
->runtime()->NaNValue
);
1212 RootedValue
valueInfinity(cx
, cx
->runtime()->positiveInfinityValue
);
1214 /* ES5 15.1.1.1, 15.1.1.2 */
1215 if (!DefineNativeProperty(cx
, global
, cx
->names().NaN
, valueNaN
,
1216 JS_PropertyStub
, JS_StrictPropertyStub
,
1217 JSPROP_PERMANENT
| JSPROP_READONLY
) ||
1218 !DefineNativeProperty(cx
, global
, cx
->names().Infinity
, valueInfinity
,
1219 JS_PropertyStub
, JS_StrictPropertyStub
,
1220 JSPROP_PERMANENT
| JSPROP_READONLY
))
1225 if (!GlobalObject::initBuiltinConstructor(cx
, global
, JSProto_Number
, ctor
, numberProto
))
1232 FracNumberToCString(ThreadSafeContext
*cx
, ToCStringBuf
*cbuf
, double d
, int base
= 10)
1237 JS_ASSERT(!mozilla::NumberIsInt32(d
, &_
));
1244 * This is V8's implementation of the algorithm described in the
1247 * Printing floating-point numbers quickly and accurately with integers.
1248 * Florian Loitsch, PLDI 2010.
1250 const double_conversion::DoubleToStringConverter
&converter
1251 = double_conversion::DoubleToStringConverter::EcmaScriptConverter();
1252 double_conversion::StringBuilder
builder(cbuf
->sbuf
, cbuf
->sbufSize
);
1253 converter
.ToShortest(d
, &builder
);
1254 numStr
= builder
.Finalize();
1256 numStr
= cbuf
->dbuf
= js_dtobasestr(cx
->dtoaState(), base
, d
);
1262 js::NumberToCString(JSContext
*cx
, ToCStringBuf
*cbuf
, double d
, int base
/* = 10*/)
1266 return mozilla::NumberIsInt32(d
, &i
)
1267 ? Int32ToCString(cbuf
, i
, &len
, base
)
1268 : FracNumberToCString(cx
, cbuf
, d
, base
);
1271 template <AllowGC allowGC
>
1272 static JSString
* JS_FASTCALL
1273 js_NumberToStringWithBase(ThreadSafeContext
*cx
, double d
, int base
)
1279 * Caller is responsible for error reporting. When called from trace,
1280 * returning nullptr here will cause us to fall of trace and then retry
1281 * from the interpreter (which will report the error).
1283 if (base
< 2 || base
> 36)
1286 JSCompartment
*comp
= cx
->isExclusiveContext()
1287 ? cx
->asExclusiveContext()->compartment()
1291 if (mozilla::NumberIsInt32(d
, &i
)) {
1292 if (base
== 10 && StaticStrings::hasInt(i
))
1293 return cx
->staticStrings().getInt(i
);
1294 if (unsigned(i
) < unsigned(base
)) {
1296 return cx
->staticStrings().getInt(i
);
1297 jschar c
= 'a' + i
- 10;
1298 JS_ASSERT(StaticStrings::hasUnit(c
));
1299 return cx
->staticStrings().getUnit(c
);
1303 if (JSFlatString
*str
= comp
->dtoaCache
.lookup(base
, d
))
1308 numStr
= Int32ToCString(&cbuf
, i
, &len
, base
);
1309 JS_ASSERT(!cbuf
.dbuf
&& numStr
>= cbuf
.sbuf
&& numStr
< cbuf
.sbuf
+ cbuf
.sbufSize
);
1312 if (JSFlatString
*str
= comp
->dtoaCache
.lookup(base
, d
))
1316 numStr
= FracNumberToCString(cx
, &cbuf
, d
, base
);
1318 js_ReportOutOfMemory(cx
);
1321 JS_ASSERT_IF(base
== 10,
1322 !cbuf
.dbuf
&& numStr
>= cbuf
.sbuf
&& numStr
< cbuf
.sbuf
+ cbuf
.sbufSize
);
1323 JS_ASSERT_IF(base
!= 10,
1324 cbuf
.dbuf
&& cbuf
.dbuf
== numStr
);
1327 JSFlatString
*s
= NewStringCopyZ
<allowGC
>(cx
, numStr
);
1330 comp
->dtoaCache
.cache(base
, d
, s
);
1335 template <AllowGC allowGC
>
1337 js::NumberToString(ThreadSafeContext
*cx
, double d
)
1339 return js_NumberToStringWithBase
<allowGC
>(cx
, d
, 10);
1343 js::NumberToString
<CanGC
>(ThreadSafeContext
*cx
, double d
);
1346 js::NumberToString
<NoGC
>(ThreadSafeContext
*cx
, double d
);
1349 js::NumberToAtom(ExclusiveContext
*cx
, double d
)
1352 if (mozilla::NumberIsInt32(d
, &si
))
1353 return Int32ToAtom(cx
, si
);
1355 if (JSFlatString
*str
= LookupDtoaCache(cx
, d
))
1356 return AtomizeString(cx
, str
);
1359 char *numStr
= FracNumberToCString(cx
, &cbuf
, d
);
1361 js_ReportOutOfMemory(cx
);
1364 JS_ASSERT(!cbuf
.dbuf
&& numStr
>= cbuf
.sbuf
&& numStr
< cbuf
.sbuf
+ cbuf
.sbufSize
);
1366 size_t length
= strlen(numStr
);
1367 JSAtom
*atom
= Atomize(cx
, numStr
, length
);
1371 CacheNumber(cx
, d
, atom
);
1377 js::NumberToString(JSContext
*cx
, double d
)
1379 if (JSString
*str
= js_NumberToStringWithBase
<CanGC
>(cx
, d
, 10))
1380 return &str
->asFlat();
1385 js::IndexToString(JSContext
*cx
, uint32_t index
)
1387 if (StaticStrings::hasUint(index
))
1388 return cx
->staticStrings().getUint(index
);
1390 JSCompartment
*c
= cx
->compartment();
1391 if (JSFlatString
*str
= c
->dtoaCache
.lookup(10, index
))
1394 Latin1Char buffer
[JSFatInlineString::MAX_LENGTH_LATIN1
+ 1];
1395 RangedPtr
<Latin1Char
> end(buffer
+ JSFatInlineString::MAX_LENGTH_LATIN1
,
1396 buffer
, JSFatInlineString::MAX_LENGTH_LATIN1
+ 1);
1398 RangedPtr
<Latin1Char
> start
= BackfillIndexInCharBuffer(index
, end
);
1400 mozilla::Range
<const Latin1Char
> chars(start
.get(), end
- start
);
1401 JSInlineString
*str
= NewFatInlineString
<CanGC
>(cx
, chars
);
1405 c
->dtoaCache
.cache(10, index
, str
);
1410 js::NumberValueToStringBuffer(JSContext
*cx
, const Value
&v
, StringBuffer
&sb
)
1412 /* Convert to C-string. */
1417 cstr
= Int32ToCString(&cbuf
, v
.toInt32(), &cstrlen
);
1418 JS_ASSERT(cstrlen
== strlen(cstr
));
1420 cstr
= NumberToCString(cx
, &cbuf
, v
.toDouble());
1422 JS_ReportOutOfMemory(cx
);
1425 cstrlen
= strlen(cstr
);
1429 * Inflate to jschar string. The input C-string characters are < 127, so
1430 * even if jschars are UTF-8, all chars should map to one jschar.
1432 JS_ASSERT(!cbuf
.dbuf
&& cstrlen
< cbuf
.sbufSize
);
1433 return sb
.append(cstr
, cstrlen
);
1436 template <typename CharT
>
1438 CharsToNumber(ThreadSafeContext
*cx
, const CharT
*chars
, size_t length
, double *result
)
1442 if ('0' <= c
&& c
<= '9')
1444 else if (unicode::IsSpace(c
))
1447 *result
= GenericNaN();
1451 const CharT
*end
= chars
+ length
;
1452 const CharT
*bp
= SkipSpace(chars
, end
);
1454 /* ECMA doesn't allow signed hex numbers (bug 273467). */
1455 if (end
- bp
>= 2 && bp
[0] == '0' && (bp
[1] == 'x' || bp
[1] == 'X')) {
1457 * It's probably a hex number. Accept if there's at least one hex
1458 * digit after the 0x, and if no non-whitespace characters follow all
1461 const CharT
*endptr
;
1463 if (!GetPrefixInteger(cx
, bp
+ 2, end
, 16, &endptr
, &d
) ||
1465 SkipSpace(endptr
, end
) != end
)
1467 *result
= GenericNaN();
1475 * Note that ECMA doesn't treat a string beginning with a '0' as
1476 * an octal number here. This works because all such numbers will
1477 * be interpreted as decimal by js_strtod. Also, any hex numbers
1478 * that have made it here (which can only be negative ones) will
1479 * be treated as 0 without consuming the 'x' by js_strtod.
1483 if (!js_strtod(cx
, bp
, end
, &ep
, &d
)) {
1484 *result
= GenericNaN();
1488 if (SkipSpace(ep
, end
) != end
)
1489 *result
= GenericNaN();
1497 js::StringToNumber(ThreadSafeContext
*cx
, JSString
*str
, double *result
)
1499 AutoCheckCannotGC nogc
;
1500 ScopedThreadSafeStringInspector
inspector(str
);
1501 if (!inspector
.ensureChars(cx
, nogc
))
1504 return inspector
.hasLatin1Chars()
1505 ? CharsToNumber(cx
, inspector
.latin1Chars(), str
->length(), result
)
1506 : CharsToNumber(cx
, inspector
.twoByteChars(), str
->length(), result
);
1510 js::NonObjectToNumberSlow(ThreadSafeContext
*cx
, Value v
, double *out
)
1512 JS_ASSERT(!v
.isNumber());
1513 JS_ASSERT(!v
.isObject());
1516 return StringToNumber(cx
, v
.toString(), out
);
1517 if (v
.isBoolean()) {
1518 *out
= v
.toBoolean() ? 1.0 : 0.0;
1526 JS_ReportErrorNumber(cx
->asJSContext(), js_GetErrorMessage
, nullptr, JSMSG_SYMBOL_TO_NUMBER
);
1530 JS_ASSERT(v
.isUndefined());
1531 *out
= GenericNaN();
1536 js::ToNumberSlow(ExclusiveContext
*cx
, Value v
, double *out
)
1538 JS_ASSERT(!v
.isNumber());
1539 goto skip_int_double
;
1542 *out
= v
.toNumber();
1548 return NonObjectToNumberSlow(cx
, v
, out
);
1550 if (!cx
->isJSContext())
1553 RootedValue
v2(cx
, v
);
1554 if (!ToPrimitive(cx
->asJSContext(), JSTYPE_NUMBER
, &v2
))
1561 *out
= GenericNaN();
1566 js::ToNumberSlow(JSContext
*cx
, Value v
, double *out
)
1568 return ToNumberSlow(static_cast<ExclusiveContext
*>(cx
), v
, out
);
1572 * Convert a value to an int64_t, according to the WebIDL rules for long long
1573 * conversion. Return converted value in *out on success, false on failure.
1576 js::ToInt64Slow(JSContext
*cx
, const HandleValue v
, int64_t *out
)
1578 JS_ASSERT(!v
.isInt32());
1583 if (!ToNumberSlow(cx
, v
, &d
))
1591 * Convert a value to an uint64_t, according to the WebIDL rules for unsigned long long
1592 * conversion. Return converted value in *out on success, false on failure.
1595 js::ToUint64Slow(JSContext
*cx
, const HandleValue v
, uint64_t *out
)
1597 JS_ASSERT(!v
.isInt32());
1602 if (!ToNumberSlow(cx
, v
, &d
))
1609 template <typename ContextType
,
1610 bool (*ToNumberSlowFn
)(ContextType
*, Value
, double *),
1613 ToInt32SlowImpl(ContextType
*cx
, const ValueType v
, int32_t *out
)
1615 JS_ASSERT(!v
.isInt32());
1620 if (!ToNumberSlowFn(cx
, v
, &d
))
1628 js::ToInt32Slow(JSContext
*cx
, const HandleValue v
, int32_t *out
)
1630 return ToInt32SlowImpl
<JSContext
, ToNumberSlow
>(cx
, v
, out
);
1634 js::NonObjectToInt32Slow(ThreadSafeContext
*cx
, const Value
&v
, int32_t *out
)
1636 return ToInt32SlowImpl
<ThreadSafeContext
, NonObjectToNumberSlow
>(cx
, v
, out
);
1639 template <typename ContextType
,
1640 bool (*ToNumberSlowFn
)(ContextType
*, Value
, double *),
1643 ToUint32SlowImpl(ContextType
*cx
, const ValueType v
, uint32_t *out
)
1645 JS_ASSERT(!v
.isInt32());
1650 if (!ToNumberSlowFn(cx
, v
, &d
))
1658 js::ToUint32Slow(JSContext
*cx
, const HandleValue v
, uint32_t *out
)
1660 return ToUint32SlowImpl
<JSContext
, ToNumberSlow
>(cx
, v
, out
);
1664 js::NonObjectToUint32Slow(ThreadSafeContext
*cx
, const Value
&v
, uint32_t *out
)
1666 return ToUint32SlowImpl
<ThreadSafeContext
, NonObjectToNumberSlow
>(cx
, v
, out
);
1670 js::ToUint16Slow(JSContext
*cx
, const HandleValue v
, uint16_t *out
)
1672 JS_ASSERT(!v
.isInt32());
1676 } else if (!ToNumberSlow(cx
, v
, &d
)) {
1680 if (d
== 0 || !mozilla::IsFinite(d
)) {
1685 uint16_t u
= (uint16_t) d
;
1686 if ((double)u
== d
) {
1692 d
= floor(neg
? -d
: d
);
1694 unsigned m
= JS_BIT(16);
1695 d
= fmod(d
, (double) m
);
1698 *out
= (uint16_t) d
;
1702 template <typename CharT
>
1704 js_strtod(ThreadSafeContext
*cx
, const CharT
*begin
, const CharT
*end
, const CharT
**dEnd
,
1707 const CharT
*s
= SkipSpace(begin
, end
);
1708 size_t length
= end
- s
;
1710 Vector
<char, 32> chars(cx
);
1711 if (!chars
.growByUninitialized(length
+ 1))
1715 for (; i
< length
; i
++) {
1723 /* Try to parse +Infinity, -Infinity or Infinity. */
1725 char *afterSign
= chars
.begin();
1726 bool negative
= (*afterSign
== '-');
1727 if (negative
|| *afterSign
== '+')
1730 if (*afterSign
== 'I' && !strncmp(afterSign
, "Infinity", 8)) {
1731 *d
= negative
? NegativeInfinity
<double>() : PositiveInfinity
<double>();
1732 *dEnd
= s
+ (afterSign
- chars
.begin()) + 8;
1737 /* Everything else. */
1740 *d
= js_strtod_harder(cx
->dtoaState(), chars
.begin(), &ep
, &err
);
1742 MOZ_ASSERT(ep
>= chars
.begin());
1744 if (ep
== chars
.begin())
1747 *dEnd
= s
+ (ep
- chars
.begin());
1753 js_strtod(ThreadSafeContext
*cx
, const jschar
*begin
, const jschar
*end
, const jschar
**dEnd
,
1757 js_strtod(ThreadSafeContext
*cx
, const Latin1Char
*begin
, const Latin1Char
*end
,
1758 const Latin1Char
**dEnd
, double *d
);