1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla Communicator client code, released
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * JS number type and wrapper class.
46 #define _MCW_EM MCW_EM
47 #define _MCW_PC MCW_PC
59 #include "jsbuiltins.h"
61 #include "jsversion.h"
74 #include "jsinterpinlines.h"
75 #include "jsobjinlines.h"
76 #include "jsstrinlines.h"
80 #ifndef JS_HAVE_STDINT_H /* Native support is innocent until proven guilty. */
82 JS_STATIC_ASSERT(uint8_t(-1) == UINT8_MAX
);
83 JS_STATIC_ASSERT(uint16_t(-1) == UINT16_MAX
);
84 JS_STATIC_ASSERT(uint32_t(-1) == UINT32_MAX
);
85 JS_STATIC_ASSERT(uint64_t(-1) == UINT64_MAX
);
87 JS_STATIC_ASSERT(INT8_MAX
> INT8_MIN
);
88 JS_STATIC_ASSERT(uint8_t(INT8_MAX
) + uint8_t(1) == uint8_t(INT8_MIN
));
89 JS_STATIC_ASSERT(INT16_MAX
> INT16_MIN
);
90 JS_STATIC_ASSERT(uint16_t(INT16_MAX
) + uint16_t(1) == uint16_t(INT16_MIN
));
91 JS_STATIC_ASSERT(INT32_MAX
> INT32_MIN
);
92 JS_STATIC_ASSERT(uint32_t(INT32_MAX
) + uint32_t(1) == uint32_t(INT32_MIN
));
93 JS_STATIC_ASSERT(INT64_MAX
> INT64_MIN
);
94 JS_STATIC_ASSERT(uint64_t(INT64_MAX
) + uint64_t(1) == uint64_t(INT64_MIN
));
96 JS_STATIC_ASSERT(INTPTR_MAX
> INTPTR_MIN
);
97 JS_STATIC_ASSERT(uintptr_t(INTPTR_MAX
) + uintptr_t(1) == uintptr_t(INTPTR_MIN
));
98 JS_STATIC_ASSERT(uintptr_t(-1) == UINTPTR_MAX
);
99 JS_STATIC_ASSERT(size_t(-1) == SIZE_MAX
);
100 JS_STATIC_ASSERT(PTRDIFF_MAX
> PTRDIFF_MIN
);
101 JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MAX
) == PTRDIFF_MAX
);
102 JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MIN
) == PTRDIFF_MIN
);
103 JS_STATIC_ASSERT(uintptr_t(PTRDIFF_MAX
) + uintptr_t(1) == uintptr_t(PTRDIFF_MIN
));
105 #endif /* JS_HAVE_STDINT_H */
108 * If we're accumulating a decimal number and the number is >= 2^53, then the
109 * fast result from the loop in GetPrefixInteger may be inaccurate. Call
110 * js_strtod_harder to get the correct answer.
113 ComputeAccurateDecimalInteger(JSContext
*cx
, const jschar
*start
, const jschar
*end
, jsdouble
*dp
)
115 size_t length
= end
- start
;
116 char *cstr
= static_cast<char *>(cx
->malloc(length
+ 1));
120 for (size_t i
= 0; i
< length
; i
++) {
121 char c
= char(start
[i
]);
122 JS_ASSERT(('0' <= c
&& c
<= '9') || ('a' <= c
&& c
<= 'z') || ('A' <= c
&& c
<= 'Z'));
129 *dp
= js_strtod_harder(JS_THREAD_DATA(cx
)->dtoaState
, cstr
, &estr
, &err
);
130 if (err
== JS_DTOA_ENOMEM
) {
131 JS_ReportOutOfMemory(cx
);
135 if (err
== JS_DTOA_ERANGE
&& *dp
== HUGE_VAL
)
136 *dp
= js_PositiveInfinity
;
141 class BinaryDigitReader
143 const int base
; /* Base of number; must be a power of 2 */
144 int digit
; /* Current digit value in radix given by base */
145 int digitMask
; /* Mask to extract the next bit from digit */
146 const jschar
*start
; /* Pointer to the remaining digits */
147 const jschar
*end
; /* Pointer to first non-digit */
150 BinaryDigitReader(int base
, const jschar
*start
, const jschar
*end
)
151 : base(base
), digit(0), digitMask(0), start(start
), end(end
)
155 /* Return the next binary digit from the number, or -1 if done. */
157 if (digitMask
== 0) {
162 JS_ASSERT(('0' <= c
&& c
<= '9') || ('a' <= c
&& c
<= 'z') || ('A' <= c
&& c
<= 'Z'));
163 if ('0' <= c
&& c
<= '9')
165 else if ('a' <= c
&& c
<= 'z')
166 digit
= c
- 'a' + 10;
168 digit
= c
- 'A' + 10;
169 digitMask
= base
>> 1;
172 int bit
= (digit
& digitMask
) != 0;
179 * The fast result might also have been inaccurate for power-of-two bases. This
180 * happens if the addition in value * 2 + digit causes a round-down to an even
181 * least significant mantissa bit when the first dropped bit is a one. If any
182 * of the following digits in the number (which haven't been added in yet) are
183 * nonzero, then the correct action would have been to round up instead of
184 * down. An example occurs when reading the number 0x1000000000000081, which
185 * rounds to 0x1000000000000000 instead of 0x1000000000000100.
188 ComputeAccurateBinaryBaseInteger(JSContext
*cx
, const jschar
*start
, const jschar
*end
, int base
)
190 BinaryDigitReader
bdr(base
, start
, end
);
192 /* Skip leading zeroes. */
195 bit
= bdr
.nextDigit();
198 JS_ASSERT(bit
== 1); // guaranteed by GetPrefixInteger
200 /* Gather the 53 significant bits (including the leading 1). */
201 jsdouble value
= 1.0;
202 for (int j
= 52; j
> 0; j
--) {
203 bit
= bdr
.nextDigit();
206 value
= value
* 2 + bit
;
209 /* bit2 is the 54th bit (the first dropped from the mantissa). */
210 int bit2
= bdr
.nextDigit();
212 jsdouble factor
= 2.0;
213 int sticky
= 0; /* sticky is 1 if any bit beyond the 54th is 1 */
216 while ((bit3
= bdr
.nextDigit()) >= 0) {
220 value
+= bit2
& (bit
| sticky
);
230 GetPrefixInteger(JSContext
*cx
, const jschar
*start
, const jschar
*end
, int base
,
231 const jschar
**endp
, jsdouble
*dp
)
233 JS_ASSERT(start
<= end
);
234 JS_ASSERT(2 <= base
&& base
<= 36);
236 const jschar
*s
= start
;
238 for (; s
< end
; s
++) {
241 if ('0' <= c
&& c
<= '9')
243 else if ('a' <= c
&& c
<= 'z')
244 digit
= c
- 'a' + 10;
245 else if ('A' <= c
&& c
<= 'Z')
246 digit
= c
- 'A' + 10;
251 d
= d
* base
+ digit
;
257 /* If we haven't reached the limit of integer precision, we're done. */
258 if (d
< DOUBLE_INTEGRAL_PRECISION_LIMIT
)
262 * Otherwise compute the correct integer from the prefix of valid digits
263 * if we're computing for base ten or a power of two. Don't worry about
264 * other bases; see 15.1.2.2 step 13.
267 return ComputeAccurateDecimalInteger(cx
, start
, s
, dp
);
268 if ((base
& (base
- 1)) == 0)
269 *dp
= ComputeAccurateBinaryBaseInteger(cx
, start
, s
, base
);
277 num_isNaN(JSContext
*cx
, uintN argc
, Value
*vp
)
280 vp
->setBoolean(true);
284 if (!ValueToNumber(cx
, vp
[2], &x
))
286 vp
->setBoolean(JSDOUBLE_IS_NaN(x
));
291 num_isFinite(JSContext
*cx
, uintN argc
, Value
*vp
)
294 vp
->setBoolean(false);
298 if (!ValueToNumber(cx
, vp
[2], &x
))
300 vp
->setBoolean(JSDOUBLE_IS_FINITE(x
));
305 num_parseFloat(JSContext
*cx
, uintN argc
, Value
*vp
)
309 const jschar
*bp
, *end
, *ep
;
312 vp
->setDouble(js_NaN
);
315 str
= js_ValueToString(cx
, vp
[2]);
318 bp
= str
->getChars(cx
);
321 end
= bp
+ str
->length();
322 if (!js_strtod(cx
, bp
, end
, &ep
, &d
))
325 vp
->setDouble(js_NaN
);
333 static jsdouble FASTCALL
334 ParseFloat(JSContext
* cx
, JSString
* str
)
336 TraceMonitor
*tm
= JS_TRACE_MONITOR_ON_TRACE(cx
);
338 const jschar
*bp
= str
->getChars(cx
);
343 const jschar
*end
= bp
+ str
->length();
347 if (!js_strtod(cx
, bp
, end
, &ep
, &d
) || ep
== bp
)
354 ParseIntStringHelper(JSContext
*cx
, const jschar
*ws
, const jschar
*end
, int maybeRadix
,
355 bool stripPrefix
, jsdouble
*dp
)
357 JS_ASSERT(maybeRadix
== 0 || (2 <= maybeRadix
&& maybeRadix
<= 36));
358 JS_ASSERT(ws
<= end
);
360 const jschar
*s
= js_SkipWhiteSpace(ws
, end
);
364 /* 15.1.2.2 steps 3-4. */
365 bool negative
= (s
!= end
&& s
[0] == '-');
367 /* 15.1.2.2 step 5. */
368 if (s
!= end
&& (s
[0] == '-' || s
[0] == '+'))
371 /* 15.1.2.2 step 9. */
372 int radix
= maybeRadix
;
374 if (end
- s
>= 2 && s
[0] == '0' && (s
[1] != 'x' && s
[1] != 'X')) {
376 * Non-standard: ES5 requires that parseInt interpret leading-zero
377 * strings not starting with "0x" or "0X" as decimal (absent an
378 * explicitly specified non-zero radix), but we continue to
379 * interpret such strings as octal, as per ES3 and web practice.
387 /* 15.1.2.2 step 10. */
389 if (end
- s
>= 2 && s
[0] == '0' && (s
[1] == 'x' || s
[1] == 'X')) {
395 /* 15.1.2.2 steps 11-14. */
396 const jschar
*actualEnd
;
397 if (!GetPrefixInteger(cx
, s
, end
, radix
, &actualEnd
, dp
))
407 ParseIntDoubleHelper(jsdouble d
)
409 if (!JSDOUBLE_IS_FINITE(d
))
418 /* See ECMA 15.1.2.2. */
420 num_parseInt(JSContext
*cx
, uintN argc
, Value
*vp
)
422 /* Fast paths and exceptional cases. */
424 vp
->setDouble(js_NaN
);
428 if (argc
== 1 || (vp
[3].isInt32() && (vp
[3].toInt32() == 0 || vp
[3].toInt32() == 10))) {
429 if (vp
[2].isInt32()) {
433 if (vp
[2].isDouble()) {
434 vp
->setDouble(ParseIntDoubleHelper(vp
[2].toDouble()));
440 JSString
*inputString
= js_ValueToString(cx
, vp
[2]);
443 vp
[2].setString(inputString
);
445 /* 15.1.2.2 steps 6-8. */
446 bool stripPrefix
= true;
449 if (!ValueToECMAInt32(cx
, vp
[3], &radix
))
452 if (radix
< 2 || radix
> 36) {
453 vp
->setDouble(js_NaN
);
461 /* Steps 2-5, 9-14. */
462 const jschar
*ws
= inputString
->getChars(cx
);
465 const jschar
*end
= ws
+ inputString
->length();
468 if (!ParseIntStringHelper(cx
, ws
, end
, radix
, stripPrefix
, &number
))
472 vp
->setNumber(number
);
477 static jsdouble FASTCALL
478 ParseInt(JSContext
* cx
, JSString
* str
)
480 TraceMonitor
*tm
= JS_TRACE_MONITOR_ON_TRACE(cx
);
482 const jschar
*start
= str
->getChars(cx
);
487 const jschar
*end
= start
+ str
->length();
490 if (!ParseIntStringHelper(cx
, start
, end
, 0, true, &d
)) {
497 static jsdouble FASTCALL
498 ParseIntDouble(jsdouble d
)
500 return ParseIntDoubleHelper(d
);
504 const char js_Infinity_str
[] = "Infinity";
505 const char js_NaN_str
[] = "NaN";
506 const char js_isNaN_str
[] = "isNaN";
507 const char js_isFinite_str
[] = "isFinite";
508 const char js_parseFloat_str
[] = "parseFloat";
509 const char js_parseInt_str
[] = "parseInt";
513 JS_DEFINE_TRCINFO_2(num_parseInt
,
514 (2, (static, DOUBLE_FAIL
, ParseInt
, CONTEXT
, STRING
,1, nanojit::ACCSET_NONE
)),
515 (1, (static, DOUBLE
, ParseIntDouble
, DOUBLE
, 1, nanojit::ACCSET_NONE
)))
517 JS_DEFINE_TRCINFO_1(num_parseFloat
,
518 (2, (static, DOUBLE_FAIL
, ParseFloat
, CONTEXT
, STRING
, 1, nanojit::ACCSET_NONE
)))
520 #endif /* JS_TRACER */
522 static JSFunctionSpec number_functions
[] = {
523 JS_FN(js_isNaN_str
, num_isNaN
, 1,0),
524 JS_FN(js_isFinite_str
, num_isFinite
, 1,0),
525 JS_TN(js_parseFloat_str
, num_parseFloat
, 1,0, &num_parseFloat_trcinfo
),
526 JS_TN(js_parseInt_str
, num_parseInt
, 2,0, &num_parseInt_trcinfo
),
530 Class js_NumberClass
= {
532 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number
),
533 PropertyStub
, /* addProperty */
534 PropertyStub
, /* delProperty */
535 PropertyStub
, /* getProperty */
536 StrictPropertyStub
, /* setProperty */
543 Number(JSContext
*cx
, uintN argc
, Value
*vp
)
545 /* Sample JS_CALLEE before clobbering. */
546 bool isConstructing
= IsConstructing(vp
);
549 if (!ValueToNumber(cx
, &vp
[2]))
559 JSObject
*obj
= NewBuiltinClassInstance(cx
, &js_NumberClass
);
562 obj
->setPrimitiveThis(vp
[0]);
569 num_toSource(JSContext
*cx
, uintN argc
, Value
*vp
)
572 if (!GetPrimitiveThis(cx
, vp
, &d
))
576 char *numStr
= NumberToCString(cx
, &cbuf
, d
);
578 JS_ReportOutOfMemory(cx
);
583 JS_snprintf(buf
, sizeof buf
, "(new %s(%s))", js_NumberClass
.name
, numStr
);
584 JSString
*str
= js_NewStringCopyZ(cx
, buf
);
592 ToCStringBuf::ToCStringBuf() :dbuf(NULL
)
594 JS_STATIC_ASSERT(sbufSize
>= DTOSTR_STANDARD_BUFFER_SIZE
);
597 ToCStringBuf::~ToCStringBuf()
603 JSString
* JS_FASTCALL
604 js_IntToString(JSContext
*cx
, int32 si
)
608 if (si
< INT_STRING_LIMIT
)
609 return JSString::intString(si
);
613 JS_ASSERT_IF(si
== INT32_MIN
, ui
== uint32(INT32_MAX
) + 1);
616 JSCompartment
*c
= cx
->compartment
;
617 if (JSString
*str
= c
->dtoaCache
.lookup(10, si
))
620 JSShortString
*str
= js_NewGCShortString(cx
);
624 /* +1, since MAX_SHORT_STRING_LENGTH does not count the null char. */
625 JS_STATIC_ASSERT(JSShortString::MAX_SHORT_STRING_LENGTH
+ 1 >= sizeof("-2147483648"));
627 jschar
*end
= str
->getInlineStorageBeforeInit() + JSShortString::MAX_SHORT_STRING_LENGTH
;
632 jsuint newui
= ui
/ 10, digit
= ui
% 10; /* optimizers are our friends */
640 str
->initAtOffsetInBuffer(cp
, end
- cp
);
642 JSString
*ret
= str
->header();
643 c
->dtoaCache
.cache(10, si
, ret
);
647 /* Returns a non-NULL pointer to inside cbuf. */
649 IntToCString(ToCStringBuf
*cbuf
, jsint i
, jsint base
= 10)
654 u
= (i
< 0) ? -i
: i
;
656 cp
= cbuf
->sbuf
+ cbuf
->sbufSize
; /* one past last buffer cell */
657 *--cp
= '\0'; /* null terminate the string to be */
660 * Build the string from behind. We use multiply and subtraction
661 * instead of modulus because that's much faster.
666 jsuint newu
= u
/ 10;
667 *--cp
= (char)(u
- newu
* 10) + '0';
673 jsuint newu
= u
/ 16;
674 *--cp
= "0123456789abcdef"[u
- newu
* 16];
679 JS_ASSERT(base
>= 2 && base
<= 36);
681 jsuint newu
= u
/ base
;
682 *--cp
= "0123456789abcdefghijklmnopqrstuvwxyz"[u
- newu
* base
];
690 JS_ASSERT(cp
>= cbuf
->sbuf
);
694 static JSString
* JS_FASTCALL
695 js_NumberToStringWithBase(JSContext
*cx
, jsdouble d
, jsint base
);
698 num_toString(JSContext
*cx
, uintN argc
, Value
*vp
)
701 if (!GetPrimitiveThis(cx
, vp
, &d
))
705 if (argc
!= 0 && !vp
[2].isUndefined()) {
706 if (!ValueToECMAInt32(cx
, vp
[2], &base
))
709 if (base
< 2 || base
> 36) {
711 char *numStr
= IntToCString(&cbuf
, base
); /* convert the base itself to a string */
713 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_RADIX
,
718 JSString
*str
= js_NumberToStringWithBase(cx
, d
, base
);
720 JS_ReportOutOfMemory(cx
);
728 num_toLocaleString(JSContext
*cx
, uintN argc
, Value
*vp
)
730 size_t thousandsLength
, decimalLength
;
731 const char *numGrouping
, *tmpGroup
;
734 const char *num
, *end
, *tmpSrc
;
737 int digits
, buflen
, remainder
, nrepeat
;
740 * Create the string, move back to bytes to make string twiddling
741 * a bit easier and so we can insert platform charset seperators.
743 if (!num_toString(cx
, 0, vp
))
745 JS_ASSERT(vp
->isString());
746 JSAutoByteString
numBytes(cx
, vp
->toString());
749 num
= numBytes
.ptr();
754 * Find the first non-integer value, whether it be a letter as in
755 * 'Infinity', a decimal point, or an 'e' from exponential notation.
760 while (*nint
>= '0' && *nint
<= '9')
768 thousandsLength
= strlen(rt
->thousandsSeparator
);
769 decimalLength
= strlen(rt
->decimalSeparator
);
771 /* Figure out how long resulting string will be. */
772 buflen
= strlen(num
);
774 buflen
+= decimalLength
- 1; /* -1 to account for existing '.' */
776 numGrouping
= tmpGroup
= rt
->numGrouping
;
781 while (*tmpGroup
!= CHAR_MAX
&& *tmpGroup
!= '\0') {
782 if (*tmpGroup
>= remainder
)
784 buflen
+= thousandsLength
;
785 remainder
-= *tmpGroup
;
788 if (*tmpGroup
== '\0' && *numGrouping
!= '\0') {
789 nrepeat
= (remainder
- 1) / tmpGroup
[-1];
790 buflen
+= thousandsLength
* nrepeat
;
791 remainder
-= nrepeat
* tmpGroup
[-1];
797 buf
= (char *)cx
->malloc(buflen
+ 1);
804 while (*tmpSrc
== '-' || remainder
--) {
805 JS_ASSERT(tmpDest
- buf
< buflen
);
806 *tmpDest
++ = *tmpSrc
++;
808 while (tmpSrc
< end
) {
809 JS_ASSERT(tmpDest
- buf
+ ptrdiff_t(thousandsLength
) <= buflen
);
810 strcpy(tmpDest
, rt
->thousandsSeparator
);
811 tmpDest
+= thousandsLength
;
812 JS_ASSERT(tmpDest
- buf
+ *tmpGroup
<= buflen
);
813 memcpy(tmpDest
, tmpSrc
, *tmpGroup
);
814 tmpDest
+= *tmpGroup
;
821 JS_ASSERT(tmpDest
- buf
+ ptrdiff_t(decimalLength
) <= buflen
);
822 strcpy(tmpDest
, rt
->decimalSeparator
);
823 tmpDest
+= decimalLength
;
824 JS_ASSERT(tmpDest
- buf
+ ptrdiff_t(strlen(nint
+ 1)) <= buflen
);
825 strcpy(tmpDest
, nint
+ 1);
827 JS_ASSERT(tmpDest
- buf
+ ptrdiff_t(strlen(nint
)) <= buflen
);
828 strcpy(tmpDest
, nint
);
831 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToUnicode
) {
832 JSBool ok
= cx
->localeCallbacks
->localeToUnicode(cx
, buf
, Jsvalify(vp
));
837 str
= js_NewStringCopyN(cx
, buf
, buflen
);
847 js_num_valueOf(JSContext
*cx
, uintN argc
, Value
*vp
)
850 if (!GetPrimitiveThis(cx
, vp
, &d
))
858 #define MAX_PRECISION 100
861 num_to(JSContext
*cx
, JSDToStrMode zeroArgMode
, JSDToStrMode oneArgMode
,
862 jsint precisionMin
, jsint precisionMax
, jsint precisionOffset
,
863 uintN argc
, Value
*vp
)
865 /* Use MAX_PRECISION+1 because precisionOffset can be 1. */
866 char buf
[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION
+1)];
870 if (!GetPrimitiveThis(cx
, vp
, &d
))
876 oneArgMode
= zeroArgMode
;
878 if (!ValueToNumber(cx
, vp
[2], &precision
))
880 precision
= js_DoubleToInteger(precision
);
881 if (precision
< precisionMin
|| precision
> precisionMax
) {
883 numStr
= IntToCString(&cbuf
, jsint(precision
));
885 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_PRECISION_RANGE
, numStr
);
890 numStr
= js_dtostr(JS_THREAD_DATA(cx
)->dtoaState
, buf
, sizeof buf
,
891 oneArgMode
, (jsint
)precision
+ precisionOffset
, d
);
893 JS_ReportOutOfMemory(cx
);
896 JSString
*str
= js_NewStringCopyZ(cx
, numStr
);
904 * In the following three implementations, we allow a larger range of precision
905 * than ECMA requires; this is permitted by ECMA-262.
908 num_toFixed(JSContext
*cx
, uintN argc
, Value
*vp
)
910 return num_to(cx
, DTOSTR_FIXED
, DTOSTR_FIXED
, -20, MAX_PRECISION
, 0,
915 num_toExponential(JSContext
*cx
, uintN argc
, Value
*vp
)
917 return num_to(cx
, DTOSTR_STANDARD_EXPONENTIAL
, DTOSTR_EXPONENTIAL
, 0, MAX_PRECISION
, 1,
922 num_toPrecision(JSContext
*cx
, uintN argc
, Value
*vp
)
924 if (argc
== 0 || vp
[2].isUndefined())
925 return num_toString(cx
, 0, vp
);
926 return num_to(cx
, DTOSTR_STANDARD
, DTOSTR_PRECISION
, 1, MAX_PRECISION
, 0,
932 JS_DEFINE_TRCINFO_2(num_toString
,
933 (2, (extern, STRING_RETRY
, js_NumberToString
, CONTEXT
, THIS_DOUBLE
,
934 1, nanojit::ACCSET_NONE
)),
935 (3, (static, STRING_RETRY
, js_NumberToStringWithBase
, CONTEXT
, THIS_DOUBLE
, INT32
,
936 1, nanojit::ACCSET_NONE
)))
938 #endif /* JS_TRACER */
940 static JSFunctionSpec number_methods
[] = {
942 JS_FN(js_toSource_str
, num_toSource
, 0, 0),
944 JS_TN(js_toString_str
, num_toString
, 1, 0, &num_toString_trcinfo
),
945 JS_FN(js_toLocaleString_str
, num_toLocaleString
, 0, 0),
946 JS_FN(js_valueOf_str
, js_num_valueOf
, 0, 0),
947 JS_FN(js_toJSON_str
, js_num_valueOf
, 0, 0),
948 JS_FN("toFixed", num_toFixed
, 1, 0),
949 JS_FN("toExponential", num_toExponential
, 1, 0),
950 JS_FN("toPrecision", num_toPrecision
, 1, 0),
954 /* NB: Keep this in synch with number_constants[]. */
957 NC_POSITIVE_INFINITY
,
958 NC_NEGATIVE_INFINITY
,
965 * Some to most C compilers forbid spelling these at compile time, or barf
966 * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
967 * using union jsdpun.
969 static JSConstDoubleSpec number_constants
[] = {
970 {0, js_NaN_str
, 0,{0,0,0}},
971 {0, "POSITIVE_INFINITY", 0,{0,0,0}},
972 {0, "NEGATIVE_INFINITY", 0,{0,0,0}},
973 {1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}},
974 {0, "MIN_VALUE", 0,{0,0,0}},
979 jsdouble js_PositiveInfinity
;
980 jsdouble js_NegativeInfinity
;
982 #if (defined __GNUC__ && defined __i386__) || \
983 (defined __SUNPRO_CC && defined __i386)
986 * Set the exception mask to mask all exceptions and set the FPU precision
987 * to 53 bit mantissa (64 bit doubles).
989 inline void FIX_FPU() {
991 asm("fstcw %0" : "=m" (control
) : );
992 control
&= ~0x300; // Lower bits 8 and 9 (precision control).
993 control
|= 0x2f3; // Raise bits 0-5 (exception masks) and 9 (64-bit precision).
994 asm("fldcw %0" : : "m" (control
) );
999 #define FIX_FPU() ((void)0)
1004 js_InitRuntimeNumberState(JSContext
*cx
)
1006 JSRuntime
*rt
= cx
->runtime
;
1011 u
.s
.hi
= JSDOUBLE_HI32_NAN
;
1012 u
.s
.lo
= JSDOUBLE_LO32_NAN
;
1013 number_constants
[NC_NaN
].dval
= js_NaN
= u
.d
;
1014 rt
->NaNValue
.setDouble(u
.d
);
1016 u
.s
.hi
= JSDOUBLE_HI32_EXPMASK
;
1017 u
.s
.lo
= 0x00000000;
1018 number_constants
[NC_POSITIVE_INFINITY
].dval
= js_PositiveInfinity
= u
.d
;
1019 rt
->positiveInfinityValue
.setDouble(u
.d
);
1021 u
.s
.hi
= JSDOUBLE_HI32_SIGNBIT
| JSDOUBLE_HI32_EXPMASK
;
1022 u
.s
.lo
= 0x00000000;
1023 number_constants
[NC_NEGATIVE_INFINITY
].dval
= js_NegativeInfinity
= u
.d
;
1024 rt
->negativeInfinityValue
.setDouble(u
.d
);
1028 number_constants
[NC_MIN_VALUE
].dval
= u
.d
;
1030 #ifndef HAVE_LOCALECONV
1031 const char* thousands_sep
= getenv("LOCALE_THOUSANDS_SEP");
1032 const char* decimal_point
= getenv("LOCALE_DECIMAL_POINT");
1033 const char* grouping
= getenv("LOCALE_GROUPING");
1035 rt
->thousandsSeparator
=
1036 JS_strdup(cx
, thousands_sep
? thousands_sep
: "'");
1037 rt
->decimalSeparator
=
1038 JS_strdup(cx
, decimal_point
? decimal_point
: ".");
1040 JS_strdup(cx
, grouping
? grouping
: "\3\0");
1042 struct lconv
*locale
= localeconv();
1043 rt
->thousandsSeparator
=
1044 JS_strdup(cx
, locale
->thousands_sep
? locale
->thousands_sep
: "'");
1045 rt
->decimalSeparator
=
1046 JS_strdup(cx
, locale
->decimal_point
? locale
->decimal_point
: ".");
1048 JS_strdup(cx
, locale
->grouping
? locale
->grouping
: "\3\0");
1051 return rt
->thousandsSeparator
&& rt
->decimalSeparator
&& rt
->numGrouping
;
1055 js_FinishRuntimeNumberState(JSContext
*cx
)
1057 JSRuntime
*rt
= cx
->runtime
;
1059 cx
->free((void *) rt
->thousandsSeparator
);
1060 cx
->free((void *) rt
->decimalSeparator
);
1061 cx
->free((void *) rt
->numGrouping
);
1062 rt
->thousandsSeparator
= rt
->decimalSeparator
= rt
->numGrouping
= NULL
;
1066 js_InitNumberClass(JSContext
*cx
, JSObject
*obj
)
1068 JSObject
*proto
, *ctor
;
1071 /* XXX must do at least once per new thread, so do it per JSContext... */
1074 if (!JS_DefineFunctions(cx
, obj
, number_functions
))
1077 proto
= js_InitClass(cx
, obj
, NULL
, &js_NumberClass
, Number
, 1,
1078 NULL
, number_methods
, NULL
, NULL
);
1079 if (!proto
|| !(ctor
= JS_GetConstructor(cx
, proto
)))
1081 proto
->setPrimitiveThis(Int32Value(0));
1082 if (!JS_DefineConstDoubles(cx
, ctor
, number_constants
))
1087 if (!JS_DefineProperty(cx
, obj
, js_NaN_str
, Jsvalify(rt
->NaNValue
),
1088 JS_PropertyStub
, JS_StrictPropertyStub
,
1089 JSPROP_PERMANENT
| JSPROP_READONLY
)) {
1094 if (!JS_DefineProperty(cx
, obj
, js_Infinity_str
, Jsvalify(rt
->positiveInfinityValue
),
1095 JS_PropertyStub
, JS_StrictPropertyStub
,
1096 JSPROP_PERMANENT
| JSPROP_READONLY
)) {
1103 namespace internal
{
1104 extern char* DoubleToCString(double v
, char* buffer
, int buflen
);
1111 FracNumberToCString(JSContext
*cx
, ToCStringBuf
*cbuf
, jsdouble d
, jsint base
= 10)
1116 JS_ASSERT(!JSDOUBLE_IS_INT32(d
, &_
));
1123 * This is V8's implementation of the algorithm described in the
1126 * Printing floating-point numbers quickly and accurately with integers.
1127 * Florian Loitsch, PLDI 2010.
1129 * It fails on a small number of cases, whereupon we fall back to
1130 * js_dtostr() (which uses David Gay's dtoa).
1132 numStr
= v8::internal::DoubleToCString(d
, cbuf
->sbuf
, cbuf
->sbufSize
);
1134 numStr
= js_dtostr(JS_THREAD_DATA(cx
)->dtoaState
, cbuf
->sbuf
, cbuf
->sbufSize
,
1135 DTOSTR_STANDARD
, 0, d
);
1137 numStr
= cbuf
->dbuf
= js_dtobasestr(JS_THREAD_DATA(cx
)->dtoaState
, base
, d
);
1143 NumberToCString(JSContext
*cx
, ToCStringBuf
*cbuf
, jsdouble d
, jsint base
/* = 10*/)
1146 return (JSDOUBLE_IS_INT32(d
, &i
))
1147 ? IntToCString(cbuf
, i
, base
)
1148 : FracNumberToCString(cx
, cbuf
, d
, base
);
1153 static JSString
* JS_FASTCALL
1154 js_NumberToStringWithBase(JSContext
*cx
, jsdouble d
, jsint base
)
1161 * Caller is responsible for error reporting. When called from trace,
1162 * returning NULL here will cause us to fall of trace and then retry
1163 * from the interpreter (which will report the error).
1165 if (base
< 2 || base
> 36)
1168 JSCompartment
*c
= cx
->compartment
;
1171 if (JSDOUBLE_IS_INT32(d
, &i
)) {
1172 if (base
== 10 && jsuint(i
) < INT_STRING_LIMIT
)
1173 return JSString::intString(i
);
1174 if (jsuint(i
) < jsuint(base
)) {
1176 return JSString::intString(i
);
1177 return JSString::unitString(jschar('a' + i
- 10));
1180 if (JSString
*str
= c
->dtoaCache
.lookup(base
, d
))
1183 numStr
= IntToCString(&cbuf
, i
, base
);
1184 JS_ASSERT(!cbuf
.dbuf
&& numStr
>= cbuf
.sbuf
&& numStr
< cbuf
.sbuf
+ cbuf
.sbufSize
);
1186 if (JSString
*str
= c
->dtoaCache
.lookup(base
, d
))
1189 numStr
= FracNumberToCString(cx
, &cbuf
, d
, base
);
1191 JS_ReportOutOfMemory(cx
);
1194 JS_ASSERT_IF(base
== 10,
1195 !cbuf
.dbuf
&& numStr
>= cbuf
.sbuf
&& numStr
< cbuf
.sbuf
+ cbuf
.sbufSize
);
1196 JS_ASSERT_IF(base
!= 10,
1197 cbuf
.dbuf
&& cbuf
.dbuf
== numStr
);
1200 s
= js_NewStringCopyZ(cx
, numStr
);
1202 c
->dtoaCache
.cache(base
, d
, s
);
1206 JSString
* JS_FASTCALL
1207 js_NumberToString(JSContext
*cx
, jsdouble d
)
1209 return js_NumberToStringWithBase(cx
, d
, 10);
1215 NumberToString(JSContext
*cx
, jsdouble d
)
1217 if (JSString
*str
= js_NumberToStringWithBase(cx
, d
, 10))
1218 return str
->assertIsFlat();
1223 NumberValueToStringBuffer(JSContext
*cx
, const Value
&v
, StringBuffer
&sb
)
1225 /* Convert to C-string. */
1229 cstr
= IntToCString(&cbuf
, v
.toInt32());
1231 cstr
= NumberToCString(cx
, &cbuf
, v
.toDouble());
1233 JS_ReportOutOfMemory(cx
);
1239 * Inflate to jschar string. The input C-string characters are < 127, so
1240 * even if jschars are UTF-8, all chars should map to one jschar.
1242 size_t cstrlen
= strlen(cstr
);
1243 JS_ASSERT(!cbuf
.dbuf
&& cstrlen
< cbuf
.sbufSize
);
1244 return sb
.appendInflated(cstr
, cstrlen
);
1248 ValueToNumberSlow(JSContext
*cx
, Value v
, double *out
)
1250 JS_ASSERT(!v
.isNumber());
1251 goto skip_int_double
;
1254 *out
= v
.toNumber();
1259 return StringToNumberType
<jsdouble
>(cx
, v
.toString(), out
);
1260 if (v
.isBoolean()) {
1261 if (v
.toBoolean()) {
1272 if (v
.isUndefined())
1275 JS_ASSERT(v
.isObject());
1276 if (!DefaultValue(cx
, &v
.toObject(), JSTYPE_NUMBER
, &v
))
1287 ValueToECMAInt32Slow(JSContext
*cx
, const Value
&v
, int32_t *out
)
1289 JS_ASSERT(!v
.isInt32());
1294 if (!ValueToNumberSlow(cx
, v
, &d
))
1297 *out
= js_DoubleToECMAInt32(d
);
1302 ValueToECMAUint32Slow(JSContext
*cx
, const Value
&v
, uint32_t *out
)
1304 JS_ASSERT(!v
.isInt32());
1309 if (!ValueToNumberSlow(cx
, v
, &d
))
1312 *out
= js_DoubleToECMAUint32(d
);
1316 } /* namespace js */
1319 js_DoubleToECMAUint32(jsdouble d
)
1325 if (!JSDOUBLE_IS_FINITE(d
))
1329 * We check whether d fits int32, not uint32, as all but the ">>>" bit
1330 * manipulation bytecode stores the result as int, not uint. When the
1331 * result does not fit int Value, it will be stored as a negative double.
1334 if ((jsdouble
) i
== d
)
1338 d
= floor(neg
? -d
: d
);
1341 two32
= 4294967296.0;
1344 return (uint32
) (d
>= 0 ? d
: d
+ two32
);
1350 ValueToInt32Slow(JSContext
*cx
, const Value
&v
, int32_t *out
)
1352 JS_ASSERT(!v
.isInt32());
1356 } else if (!ValueToNumberSlow(cx
, v
, &d
)) {
1360 if (JSDOUBLE_IS_NaN(d
) || d
<= -2147483649.0 || 2147483648.0 <= d
) {
1361 js_ReportValueError(cx
, JSMSG_CANT_CONVERT
,
1362 JSDVG_SEARCH_STACK
, v
, NULL
);
1365 *out
= (int32
) floor(d
+ 0.5); /* Round to nearest */
1370 ValueToUint16Slow(JSContext
*cx
, const Value
&v
, uint16_t *out
)
1372 JS_ASSERT(!v
.isInt32());
1376 } else if (!ValueToNumberSlow(cx
, v
, &d
)) {
1380 if (d
== 0 || !JSDOUBLE_IS_FINITE(d
)) {
1385 uint16 u
= (uint16
) d
;
1386 if ((jsdouble
)u
== d
) {
1392 d
= floor(neg
? -d
: d
);
1394 jsuint m
= JS_BIT(16);
1395 d
= fmod(d
, (double) m
);
1398 *out
= (uint16_t) d
;
1402 } /* namespace js */
1405 js_strtod(JSContext
*cx
, const jschar
*s
, const jschar
*send
,
1406 const jschar
**ep
, jsdouble
*dp
)
1411 char *cstr
, *istr
, *estr
;
1415 s1
= js_SkipWhiteSpace(s
, send
);
1418 /* Use cbuf to avoid malloc */
1419 if (length
>= sizeof cbuf
) {
1420 cstr
= (char *) cx
->malloc(length
+ 1);
1427 for (i
= 0; i
!= length
; i
++) {
1430 cstr
[i
] = (char)s1
[i
];
1435 if ((negative
= (*istr
== '-')) != 0 || *istr
== '+')
1437 if (*istr
== 'I' && !strncmp(istr
, js_Infinity_str
, sizeof js_Infinity_str
- 1)) {
1438 d
= negative
? js_NegativeInfinity
: js_PositiveInfinity
;
1442 d
= js_strtod_harder(JS_THREAD_DATA(cx
)->dtoaState
, cstr
, &estr
, &err
);
1444 d
= js_PositiveInfinity
;
1445 else if (d
== -HUGE_VAL
)
1446 d
= js_NegativeInfinity
;
1452 *ep
= i
? s1
+ i
: s
;