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
56 #include "jsutil.h" /* Added by JSIFY */
59 #include "jsbuiltins.h"
61 #include "jsversion.h"
73 #include "jsobjinlines.h"
74 #include "jsstrinlines.h"
78 #ifndef JS_HAVE_STDINT_H /* Native support is innocent until proven guilty. */
80 JS_STATIC_ASSERT(uint8_t(-1) == UINT8_MAX
);
81 JS_STATIC_ASSERT(uint16_t(-1) == UINT16_MAX
);
82 JS_STATIC_ASSERT(uint32_t(-1) == UINT32_MAX
);
83 JS_STATIC_ASSERT(uint64_t(-1) == UINT64_MAX
);
85 JS_STATIC_ASSERT(INT8_MAX
> INT8_MIN
);
86 JS_STATIC_ASSERT(uint8_t(INT8_MAX
) + uint8_t(1) == uint8_t(INT8_MIN
));
87 JS_STATIC_ASSERT(INT16_MAX
> INT16_MIN
);
88 JS_STATIC_ASSERT(uint16_t(INT16_MAX
) + uint16_t(1) == uint16_t(INT16_MIN
));
89 JS_STATIC_ASSERT(INT32_MAX
> INT32_MIN
);
90 JS_STATIC_ASSERT(uint32_t(INT32_MAX
) + uint32_t(1) == uint32_t(INT32_MIN
));
91 JS_STATIC_ASSERT(INT64_MAX
> INT64_MIN
);
92 JS_STATIC_ASSERT(uint64_t(INT64_MAX
) + uint64_t(1) == uint64_t(INT64_MIN
));
94 JS_STATIC_ASSERT(INTPTR_MAX
> INTPTR_MIN
);
95 JS_STATIC_ASSERT(uintptr_t(INTPTR_MAX
) + uintptr_t(1) == uintptr_t(INTPTR_MIN
));
96 JS_STATIC_ASSERT(uintptr_t(-1) == UINTPTR_MAX
);
97 JS_STATIC_ASSERT(size_t(-1) == SIZE_MAX
);
98 JS_STATIC_ASSERT(PTRDIFF_MAX
> PTRDIFF_MIN
);
99 JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MAX
) == PTRDIFF_MAX
);
100 JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MIN
) == PTRDIFF_MIN
);
101 JS_STATIC_ASSERT(uintptr_t(PTRDIFF_MAX
) + uintptr_t(1) == uintptr_t(PTRDIFF_MIN
));
103 #endif /* JS_HAVE_STDINT_H */
106 num_isNaN(JSContext
*cx
, uintN argc
, Value
*vp
)
109 vp
->setBoolean(true);
113 if (!ValueToNumber(cx
, vp
[2], &x
))
115 vp
->setBoolean(JSDOUBLE_IS_NaN(x
));
120 num_isFinite(JSContext
*cx
, uintN argc
, Value
*vp
)
123 vp
->setBoolean(false);
127 if (!ValueToNumber(cx
, vp
[2], &x
))
129 vp
->setBoolean(JSDOUBLE_IS_FINITE(x
));
134 num_parseFloat(JSContext
*cx
, uintN argc
, Value
*vp
)
138 const jschar
*bp
, *end
, *ep
;
141 vp
->setDouble(js_NaN
);
144 str
= js_ValueToString(cx
, vp
[2]);
147 str
->getCharsAndEnd(bp
, end
);
148 if (!js_strtod(cx
, bp
, end
, &ep
, &d
))
151 vp
->setDouble(js_NaN
);
159 static jsdouble FASTCALL
160 ParseFloat(JSContext
* cx
, JSString
* str
)
167 str
->getCharsAndEnd(bp
, end
);
168 if (!js_strtod(cx
, bp
, end
, &ep
, &d
) || ep
== bp
)
174 static inline jsdouble
175 DoubleToInteger(jsdouble d
)
177 if (!JSDOUBLE_IS_FINITE(d
))
186 /* See ECMA 15.1.2.2. */
188 num_parseInt(JSContext
*cx
, uintN argc
, Value
*vp
)
192 const jschar
*bp
, *end
, *ep
;
195 vp
->setDouble(js_NaN
);
200 if (!ValueToECMAInt32(cx
, vp
[3], &radix
))
205 if (radix
!= 0 && (radix
< 2 || radix
> 36)) {
206 vp
->setDouble(js_NaN
);
210 if (vp
[2].isInt32() && (radix
== 0 || radix
== 10)) {
215 if (vp
[2].isDouble() && (radix
== 0 || radix
== 10)) {
216 vp
->setDouble(DoubleToInteger(vp
[2].toDouble()));
220 str
= js_ValueToString(cx
, vp
[2]);
223 str
->getCharsAndEnd(bp
, end
);
224 if (!js_strtointeger(cx
, bp
, end
, &ep
, radix
, &d
))
227 vp
->setDouble(js_NaN
);
235 static jsdouble FASTCALL
236 ParseInt(JSContext
* cx
, JSString
* str
)
243 str
->getCharsAndEnd(bp
, end
);
244 if (!js_strtointeger(cx
, bp
, end
, &ep
, 0, &d
) || ep
== bp
)
249 static jsdouble FASTCALL
250 ParseIntDouble(jsdouble d
)
252 return DoubleToInteger(d
);
256 const char js_Infinity_str
[] = "Infinity";
257 const char js_NaN_str
[] = "NaN";
258 const char js_isNaN_str
[] = "isNaN";
259 const char js_isFinite_str
[] = "isFinite";
260 const char js_parseFloat_str
[] = "parseFloat";
261 const char js_parseInt_str
[] = "parseInt";
265 JS_DEFINE_TRCINFO_2(num_parseInt
,
266 (2, (static, DOUBLE
, ParseInt
, CONTEXT
, STRING
, 1, nanojit::ACC_NONE
)),
267 (1, (static, DOUBLE
, ParseIntDouble
, DOUBLE
, 1, nanojit::ACC_NONE
)))
269 JS_DEFINE_TRCINFO_1(num_parseFloat
,
270 (2, (static, DOUBLE
, ParseFloat
, CONTEXT
, STRING
, 1, nanojit::ACC_NONE
)))
272 #endif /* JS_TRACER */
274 static JSFunctionSpec number_functions
[] = {
275 JS_FN(js_isNaN_str
, num_isNaN
, 1,0),
276 JS_FN(js_isFinite_str
, num_isFinite
, 1,0),
277 JS_TN(js_parseFloat_str
, num_parseFloat
, 1,0, &num_parseFloat_trcinfo
),
278 JS_TN(js_parseInt_str
, num_parseInt
, 2,0, &num_parseInt_trcinfo
),
282 Class js_NumberClass
= {
284 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number
),
285 PropertyStub
, PropertyStub
, PropertyStub
, PropertyStub
,
286 EnumerateStub
, ResolveStub
, ConvertStub
, NULL
,
287 JSCLASS_NO_OPTIONAL_MEMBERS
291 Number(JSContext
*cx
, JSObject
*obj
, uintN argc
, Value
*argv
, Value
*rval
)
295 if (!ValueToNumber(cx
, &argv
[0]))
300 if (!JS_IsConstructing(cx
))
303 obj
->setPrimitiveThis(argv
[0]);
309 num_toSource(JSContext
*cx
, uintN argc
, Value
*vp
)
311 char numBuf
[DTOSTR_STANDARD_BUFFER_SIZE
], *numStr
;
316 if (!js_GetPrimitiveThis(cx
, vp
, &js_NumberClass
, &primp
))
318 double d
= primp
->toNumber();
319 numStr
= js_dtostr(JS_THREAD_DATA(cx
)->dtoaState
, numBuf
, sizeof numBuf
,
320 DTOSTR_STANDARD
, 0, d
);
322 JS_ReportOutOfMemory(cx
);
325 JS_snprintf(buf
, sizeof buf
, "(new %s(%s))", js_NumberClass
.name
, numStr
);
326 str
= JS_NewStringCopyZ(cx
, buf
);
334 /* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */
336 IntToCString(jsint i
, jsint base
, char *buf
, size_t bufSize
)
341 u
= (i
< 0) ? -i
: i
;
343 cp
= buf
+ bufSize
; /* one past last buffer cell */
344 *--cp
= '\0'; /* null terminate the string to be */
347 * Build the string from behind. We use multiply and subtraction
348 * instead of modulus because that's much faster.
353 jsuint newu
= u
/ 10;
354 *--cp
= (char)(u
- newu
* 10) + '0';
360 jsuint newu
= u
/ 16;
361 *--cp
= "0123456789abcdef"[u
- newu
* 16];
366 JS_ASSERT(base
>= 2 && base
<= 36);
368 jsuint newu
= u
/ base
;
369 *--cp
= "0123456789abcdefghijklmnopqrstuvwxyz"[u
- newu
* base
];
377 JS_ASSERT(cp
>= buf
);
381 static JSString
* JS_FASTCALL
382 js_NumberToStringWithBase(JSContext
*cx
, jsdouble d
, jsint base
);
385 num_toString(JSContext
*cx
, uintN argc
, Value
*vp
)
388 if (!js_GetPrimitiveThis(cx
, vp
, &js_NumberClass
, &primp
))
390 double d
= primp
->toNumber();
392 if (argc
!= 0 && !vp
[2].isUndefined()) {
393 if (!ValueToECMAInt32(cx
, vp
[2], &base
))
396 if (base
< 2 || base
> 36) {
398 char *numStr
= IntToCString(base
, 10, numBuf
, sizeof numBuf
);
399 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_RADIX
,
404 JSString
*str
= js_NumberToStringWithBase(cx
, d
, base
);
406 JS_ReportOutOfMemory(cx
);
414 num_toLocaleString(JSContext
*cx
, uintN argc
, Value
*vp
)
416 size_t thousandsLength
, decimalLength
;
417 const char *numGrouping
, *tmpGroup
;
420 const char *num
, *end
, *tmpSrc
;
423 int digits
, size
, remainder
, nrepeat
;
426 * Create the string, move back to bytes to make string twiddling
427 * a bit easier and so we can insert platform charset seperators.
429 if (!num_toString(cx
, 0, vp
))
431 JS_ASSERT(vp
->isString());
432 num
= js_GetStringBytes(cx
, vp
->toString());
437 * Find the first non-integer value, whether it be a letter as in
438 * 'Infinity', a decimal point, or an 'e' from exponential notation.
443 while (*nint
>= '0' && *nint
<= '9')
451 thousandsLength
= strlen(rt
->thousandsSeparator
);
452 decimalLength
= strlen(rt
->decimalSeparator
);
454 /* Figure out how long resulting string will be. */
455 size
= digits
+ (*nint
? strlen(nint
+ 1) + 1 : 0);
457 size
+= decimalLength
;
459 numGrouping
= tmpGroup
= rt
->numGrouping
;
464 while (*tmpGroup
!= CHAR_MAX
&& *tmpGroup
!= '\0') {
465 if (*tmpGroup
>= remainder
)
467 size
+= thousandsLength
;
468 remainder
-= *tmpGroup
;
471 if (*tmpGroup
== '\0' && *numGrouping
!= '\0') {
472 nrepeat
= (remainder
- 1) / tmpGroup
[-1];
473 size
+= thousandsLength
* nrepeat
;
474 remainder
-= nrepeat
* tmpGroup
[-1];
480 buf
= (char *)cx
->malloc(size
+ 1);
487 while (*tmpSrc
== '-' || remainder
--)
488 *tmpDest
++ = *tmpSrc
++;
489 while (tmpSrc
< end
) {
490 strcpy(tmpDest
, rt
->thousandsSeparator
);
491 tmpDest
+= thousandsLength
;
492 memcpy(tmpDest
, tmpSrc
, *tmpGroup
);
493 tmpDest
+= *tmpGroup
;
500 strcpy(tmpDest
, rt
->decimalSeparator
);
501 tmpDest
+= decimalLength
;
502 strcpy(tmpDest
, nint
+ 1);
504 strcpy(tmpDest
, nint
);
507 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToUnicode
)
508 return cx
->localeCallbacks
->localeToUnicode(cx
, buf
, Jsvalify(vp
));
510 str
= JS_NewString(cx
, buf
, size
);
521 num_valueOf(JSContext
*cx
, uintN argc
, Value
*vp
)
523 if (vp
[1].isNumber()) {
527 JSObject
*obj
= ComputeThisFromVp(cx
, vp
);
528 if (!InstanceOf(cx
, obj
, &js_NumberClass
, vp
+ 2))
530 *vp
= obj
->getPrimitiveThis();
535 #define MAX_PRECISION 100
538 num_to(JSContext
*cx
, JSDToStrMode zeroArgMode
, JSDToStrMode oneArgMode
,
539 jsint precisionMin
, jsint precisionMax
, jsint precisionOffset
,
540 uintN argc
, Value
*vp
)
542 /* Use MAX_PRECISION+1 because precisionOffset can be 1. */
543 char buf
[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION
+1)];
547 if (!js_GetPrimitiveThis(cx
, vp
, &js_NumberClass
, &primp
))
549 double d
= primp
->toNumber();
554 oneArgMode
= zeroArgMode
;
556 if (!ValueToNumber(cx
, vp
[2], &precision
))
558 precision
= js_DoubleToInteger(precision
);
559 if (precision
< precisionMin
|| precision
> precisionMax
) {
560 numStr
= js_dtostr(JS_THREAD_DATA(cx
)->dtoaState
, buf
, sizeof buf
,
561 DTOSTR_STANDARD
, 0, precision
);
563 JS_ReportOutOfMemory(cx
);
565 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_PRECISION_RANGE
, numStr
);
570 numStr
= js_dtostr(JS_THREAD_DATA(cx
)->dtoaState
, buf
, sizeof buf
,
571 oneArgMode
, (jsint
)precision
+ precisionOffset
, d
);
573 JS_ReportOutOfMemory(cx
);
576 JSString
*str
= JS_NewStringCopyZ(cx
, numStr
);
584 * In the following three implementations, we allow a larger range of precision
585 * than ECMA requires; this is permitted by ECMA-262.
588 num_toFixed(JSContext
*cx
, uintN argc
, Value
*vp
)
590 return num_to(cx
, DTOSTR_FIXED
, DTOSTR_FIXED
, -20, MAX_PRECISION
, 0,
595 num_toExponential(JSContext
*cx
, uintN argc
, Value
*vp
)
597 return num_to(cx
, DTOSTR_STANDARD_EXPONENTIAL
, DTOSTR_EXPONENTIAL
, 0,
598 MAX_PRECISION
, 1, argc
, vp
);
602 num_toPrecision(JSContext
*cx
, uintN argc
, Value
*vp
)
604 if (argc
== 0 || vp
[2].isUndefined())
605 return num_toString(cx
, 0, vp
);
606 return num_to(cx
, DTOSTR_STANDARD
, DTOSTR_PRECISION
, 1, MAX_PRECISION
, 0,
612 JS_DEFINE_TRCINFO_2(num_toString
,
613 (2, (extern, STRING_RETRY
, js_NumberToString
, CONTEXT
, THIS_DOUBLE
, 1,
615 (3, (static, STRING_RETRY
, js_NumberToStringWithBase
, CONTEXT
, THIS_DOUBLE
, INT32
, 1,
618 #endif /* JS_TRACER */
620 static JSFunctionSpec number_methods
[] = {
622 JS_FN(js_toSource_str
, num_toSource
, 0,JSFUN_THISP_NUMBER
),
624 JS_TN(js_toString_str
, num_toString
, 1,JSFUN_THISP_NUMBER
, &num_toString_trcinfo
),
625 JS_FN(js_toLocaleString_str
, num_toLocaleString
, 0,JSFUN_THISP_NUMBER
),
626 JS_FN(js_valueOf_str
, num_valueOf
, 0,JSFUN_THISP_NUMBER
),
627 JS_FN(js_toJSON_str
, num_valueOf
, 0,JSFUN_THISP_NUMBER
),
628 JS_FN("toFixed", num_toFixed
, 1,JSFUN_THISP_NUMBER
),
629 JS_FN("toExponential", num_toExponential
, 1,JSFUN_THISP_NUMBER
),
630 JS_FN("toPrecision", num_toPrecision
, 1,JSFUN_THISP_NUMBER
),
634 /* NB: Keep this in synch with number_constants[]. */
637 NC_POSITIVE_INFINITY
,
638 NC_NEGATIVE_INFINITY
,
645 * Some to most C compilers forbid spelling these at compile time, or barf
646 * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
647 * using union jsdpun.
649 static JSConstDoubleSpec number_constants
[] = {
650 {0, js_NaN_str
, 0,{0,0,0}},
651 {0, "POSITIVE_INFINITY", 0,{0,0,0}},
652 {0, "NEGATIVE_INFINITY", 0,{0,0,0}},
653 {1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}},
654 {0, "MIN_VALUE", 0,{0,0,0}},
659 jsdouble js_PositiveInfinity
;
660 jsdouble js_NegativeInfinity
;
662 #if (defined __GNUC__ && defined __i386__) || \
663 (defined __SUNPRO_CC && defined __i386)
666 * Set the exception mask to mask all exceptions and set the FPU precision
667 * to 53 bit mantissa (64 bit doubles).
669 inline void FIX_FPU() {
671 asm("fstcw %0" : "=m" (control
) : );
672 control
&= ~0x300; // Lower bits 8 and 9 (precision control).
673 control
|= 0x2f3; // Raise bits 0-5 (exception masks) and 9 (64-bit precision).
674 asm("fldcw %0" : : "m" (control
) );
679 #define FIX_FPU() ((void)0)
684 js_InitRuntimeNumberState(JSContext
*cx
)
686 JSRuntime
*rt
= cx
->runtime
;
691 u
.s
.hi
= JSDOUBLE_HI32_NAN
;
692 u
.s
.lo
= JSDOUBLE_LO32_NAN
;
693 number_constants
[NC_NaN
].dval
= js_NaN
= u
.d
;
694 rt
->NaNValue
.setDouble(u
.d
);
696 u
.s
.hi
= JSDOUBLE_HI32_EXPMASK
;
698 number_constants
[NC_POSITIVE_INFINITY
].dval
= js_PositiveInfinity
= u
.d
;
699 rt
->positiveInfinityValue
.setDouble(u
.d
);
701 u
.s
.hi
= JSDOUBLE_HI32_SIGNBIT
| JSDOUBLE_HI32_EXPMASK
;
703 number_constants
[NC_NEGATIVE_INFINITY
].dval
= js_NegativeInfinity
= u
.d
;
704 rt
->negativeInfinityValue
.setDouble(u
.d
);
708 number_constants
[NC_MIN_VALUE
].dval
= u
.d
;
710 #ifndef HAVE_LOCALECONV
711 rt
->thousandsSeparator
= JS_strdup(cx
, "'");
712 rt
->decimalSeparator
= JS_strdup(cx
, ".");
713 rt
->numGrouping
= JS_strdup(cx
, "\3\0");
715 struct lconv
*locale
= localeconv();
716 rt
->thousandsSeparator
=
717 JS_strdup(cx
, locale
->thousands_sep
? locale
->thousands_sep
: "'");
718 rt
->decimalSeparator
=
719 JS_strdup(cx
, locale
->decimal_point
? locale
->decimal_point
: ".");
721 JS_strdup(cx
, locale
->grouping
? locale
->grouping
: "\3\0");
724 return rt
->thousandsSeparator
&& rt
->decimalSeparator
&& rt
->numGrouping
;
728 js_FinishRuntimeNumberState(JSContext
*cx
)
730 JSRuntime
*rt
= cx
->runtime
;
732 cx
->free((void *) rt
->thousandsSeparator
);
733 cx
->free((void *) rt
->decimalSeparator
);
734 cx
->free((void *) rt
->numGrouping
);
735 rt
->thousandsSeparator
= rt
->decimalSeparator
= rt
->numGrouping
= NULL
;
739 js_InitNumberClass(JSContext
*cx
, JSObject
*obj
)
741 JSObject
*proto
, *ctor
;
744 /* XXX must do at least once per new thread, so do it per JSContext... */
747 if (!JS_DefineFunctions(cx
, obj
, number_functions
))
750 proto
= js_InitClass(cx
, obj
, NULL
, &js_NumberClass
, Number
, 1,
751 NULL
, number_methods
, NULL
, NULL
);
752 if (!proto
|| !(ctor
= JS_GetConstructor(cx
, proto
)))
754 proto
->setPrimitiveThis(Int32Value(0));
755 if (!JS_DefineConstDoubles(cx
, ctor
, number_constants
))
760 if (!JS_DefineProperty(cx
, obj
, js_NaN_str
, Jsvalify(rt
->NaNValue
),
761 JS_PropertyStub
, JS_PropertyStub
,
762 JSPROP_PERMANENT
| JSPROP_READONLY
)) {
767 if (!JS_DefineProperty(cx
, obj
, js_Infinity_str
, Jsvalify(rt
->positiveInfinityValue
),
768 JS_PropertyStub
, JS_PropertyStub
,
769 JSPROP_PERMANENT
| JSPROP_READONLY
)) {
776 * Convert a number to C string. The buf must be large enough to accommodate
777 * the result, including '-' and '\0', if base == 10 or d is an integer that
778 * fits in 32 bits. The caller must free the resulting pointer if it does not
782 NumberToCString(JSContext
*cx
, jsdouble d
, jsint base
, char *buf
, size_t bufSize
)
787 JS_ASSERT(bufSize
>= DTOSTR_STANDARD_BUFFER_SIZE
);
788 if (JSDOUBLE_IS_INT32(d
, &i
)) {
789 numStr
= IntToCString(i
, base
, buf
, bufSize
);
792 numStr
= js_dtostr(JS_THREAD_DATA(cx
)->dtoaState
, buf
, bufSize
,
793 DTOSTR_STANDARD
, 0, d
);
795 numStr
= js_dtobasestr(JS_THREAD_DATA(cx
)->dtoaState
, base
, d
);
797 JS_ReportOutOfMemory(cx
);
804 JSString
* JS_FASTCALL
805 js_IntToString(JSContext
*cx
, jsint i
)
807 if (jsuint(i
) < INT_STRING_LIMIT
)
808 return JSString::intString(i
);
811 return JS_NewStringCopyZ(cx
, IntToCString(i
, 10, buf
, sizeof buf
));
814 static JSString
* JS_FASTCALL
815 js_NumberToStringWithBase(JSContext
*cx
, jsdouble d
, jsint base
)
818 * The longest possible result here that would need to fit in buf is
819 * (-0x80000000).toString(2), which has length 33. (This can produce
820 * longer results, but in those cases buf is not used; see comment at
828 * Caller is responsible for error reporting. When called from trace,
829 * returning NULL here will cause us to fall of trace and then retry
830 * from the interpreter (which will report the error).
832 if (base
< 2 || base
> 36)
836 if (JSDOUBLE_IS_INT32(d
, &i
)) {
837 if (base
== 10 && jsuint(i
) < INT_STRING_LIMIT
)
838 return JSString::intString(i
);
839 if (jsuint(i
) < jsuint(base
)) {
841 return JSString::intString(i
);
842 return JSString::unitString(jschar('a' + i
- 10));
845 JSThreadData
*data
= JS_THREAD_DATA(cx
);
846 if (data
->dtoaCache
.s
&& data
->dtoaCache
.base
== base
&& data
->dtoaCache
.d
== d
)
847 return data
->dtoaCache
.s
;
848 numStr
= NumberToCString(cx
, d
, base
, buf
, sizeof buf
);
851 s
= JS_NewStringCopyZ(cx
, numStr
);
852 if (!(numStr
>= buf
&& numStr
< buf
+ sizeof buf
))
854 data
->dtoaCache
.base
= base
;
855 data
->dtoaCache
.d
= d
;
856 data
->dtoaCache
.s
= s
;
860 JSString
* JS_FASTCALL
861 js_NumberToString(JSContext
*cx
, jsdouble d
)
863 return js_NumberToStringWithBase(cx
, d
, 10);
867 js_NumberValueToCharBuffer(JSContext
*cx
, const Value
&v
, JSCharBuffer
&cb
)
869 /* Convert to C-string. */
870 static const size_t arrSize
= DTOSTR_STANDARD_BUFFER_SIZE
;
874 cstr
= IntToCString(v
.toInt32(), 10, arr
, arrSize
);
876 cstr
= js_dtostr(JS_THREAD_DATA(cx
)->dtoaState
, arr
, arrSize
,
877 DTOSTR_STANDARD
, 0, v
.toDouble());
883 * Inflate to jschar string. The input C-string characters are < 127, so
884 * even if jschars are UTF-8, all chars should map to one jschar.
886 size_t cstrlen
= strlen(cstr
);
887 JS_ASSERT(cstrlen
< arrSize
);
888 size_t sizeBefore
= cb
.length();
889 if (!cb
.growByUninitialized(cstrlen
))
891 jschar
*appendBegin
= cb
.begin() + sizeBefore
;
893 size_t oldcstrlen
= cstrlen
;
896 js_InflateStringToBuffer(cx
, cstr
, cstrlen
, appendBegin
, &cstrlen
);
897 JS_ASSERT(ok
&& cstrlen
== oldcstrlen
);
904 ValueToNumberSlow(JSContext
*cx
, Value v
, double *out
)
906 JS_ASSERT(!v
.isNumber());
907 goto skip_int_double
;
915 jsdouble d
= StringToNumberType
<jsdouble
>(cx
, v
.toString());
916 if (JSDOUBLE_IS_NaN(d
))
936 JS_ASSERT(v
.isObject());
937 if (!DefaultValue(cx
, &v
.toObject(), JSTYPE_NUMBER
, &v
))
948 ValueToECMAInt32Slow(JSContext
*cx
, const Value
&v
, int32_t *out
)
950 JS_ASSERT(!v
.isInt32());
955 if (!ValueToNumberSlow(cx
, v
, &d
))
958 *out
= js_DoubleToECMAInt32(d
);
963 ValueToECMAUint32Slow(JSContext
*cx
, const Value
&v
, uint32_t *out
)
965 JS_ASSERT(!v
.isInt32());
970 if (!ValueToNumberSlow(cx
, v
, &d
))
973 *out
= js_DoubleToECMAUint32(d
);
980 js_DoubleToECMAUint32(jsdouble d
)
986 if (!JSDOUBLE_IS_FINITE(d
))
990 * We check whether d fits int32, not uint32, as all but the ">>>" bit
991 * manipulation bytecode stores the result as int, not uint. When the
992 * result does not fit int Value, it will be stored as a negative double.
995 if ((jsdouble
) i
== d
)
999 d
= floor(neg
? -d
: d
);
1002 two32
= 4294967296.0;
1005 return (uint32
) (d
>= 0 ? d
: d
+ two32
);
1011 ValueToInt32Slow(JSContext
*cx
, const Value
&v
, int32_t *out
)
1013 JS_ASSERT(!v
.isInt32());
1017 } else if (!ValueToNumberSlow(cx
, v
, &d
)) {
1021 if (JSDOUBLE_IS_NaN(d
) || d
<= -2147483649.0 || 2147483648.0 <= d
) {
1022 js_ReportValueError(cx
, JSMSG_CANT_CONVERT
,
1023 JSDVG_SEARCH_STACK
, v
, NULL
);
1026 *out
= (int32
) floor(d
+ 0.5); /* Round to nearest */
1031 ValueToUint16Slow(JSContext
*cx
, const Value
&v
, uint16_t *out
)
1033 JS_ASSERT(!v
.isInt32());
1037 } else if (!ValueToNumberSlow(cx
, v
, &d
)) {
1041 if (d
== 0 || !JSDOUBLE_IS_FINITE(d
)) {
1046 uint16 u
= (uint16
) d
;
1047 if ((jsdouble
)u
== d
) {
1053 d
= floor(neg
? -d
: d
);
1055 jsuint m
= JS_BIT(16);
1056 d
= fmod(d
, (double) m
);
1059 *out
= (uint16_t) d
;
1063 } /* namespace js */
1066 js_strtod(JSContext
*cx
, const jschar
*s
, const jschar
*send
,
1067 const jschar
**ep
, jsdouble
*dp
)
1072 char *cstr
, *istr
, *estr
;
1076 s1
= js_SkipWhiteSpace(s
, send
);
1079 /* Use cbuf to avoid malloc */
1080 if (length
>= sizeof cbuf
) {
1081 cstr
= (char *) cx
->malloc(length
+ 1);
1088 for (i
= 0; i
!= length
; i
++) {
1091 cstr
[i
] = (char)s1
[i
];
1096 if ((negative
= (*istr
== '-')) != 0 || *istr
== '+')
1098 if (*istr
== 'I' && !strncmp(istr
, js_Infinity_str
, sizeof js_Infinity_str
- 1)) {
1099 d
= negative
? js_NegativeInfinity
: js_PositiveInfinity
;
1103 d
= js_strtod_harder(JS_THREAD_DATA(cx
)->dtoaState
, cstr
, &estr
, &err
);
1105 d
= js_PositiveInfinity
;
1106 else if (d
== -HUGE_VAL
)
1107 d
= js_NegativeInfinity
;
1113 *ep
= i
? s1
+ i
: s
;
1118 struct BinaryDigitReader
1120 uintN base
; /* Base of number; must be a power of 2 */
1121 uintN digit
; /* Current digit value in radix given by base */
1122 uintN digitMask
; /* Mask to extract the next bit from digit */
1123 const jschar
*digits
; /* Pointer to the remaining digits */
1124 const jschar
*end
; /* Pointer to first non-digit */
1127 /* Return the next binary digit from the number or -1 if done */
1128 static intN
GetNextBinaryDigit(struct BinaryDigitReader
*bdr
)
1132 if (bdr
->digitMask
== 0) {
1135 if (bdr
->digits
== bdr
->end
)
1139 if ('0' <= c
&& c
<= '9')
1140 bdr
->digit
= c
- '0';
1141 else if ('a' <= c
&& c
<= 'z')
1142 bdr
->digit
= c
- 'a' + 10;
1144 bdr
->digit
= c
- 'A' + 10;
1145 bdr
->digitMask
= bdr
->base
>> 1;
1147 bit
= (bdr
->digit
& bdr
->digitMask
) != 0;
1148 bdr
->digitMask
>>= 1;
1153 js_strtointeger(JSContext
*cx
, const jschar
*s
, const jschar
*send
,
1154 const jschar
**ep
, jsint base
, jsdouble
*dp
)
1156 const jschar
*s1
, *start
;
1160 s1
= js_SkipWhiteSpace(s
, send
);
1163 if ((negative
= (*s1
== '-')) != 0 || *s1
== '+') {
1170 /* No base supplied, or some base that evaluated to 0. */
1172 /* It's either hex or octal; only increment char if str isn't '0' */
1173 if (s1
+ 1 != send
&& (s1
[1] == 'X' || s1
[1] == 'x')) {
1182 base
= 10; /* Default to decimal. */
1184 } else if (base
== 16) {
1185 /* If base is 16, ignore hex prefix. */
1186 if (*s1
== '0' && s1
+ 1 != send
&& (s1
[1] == 'X' || s1
[1] == 'x')) {
1194 * Done with the preliminaries; find some prefix of the string that's
1195 * a number in the given base.
1197 JS_ASSERT(s1
< send
);
1203 if ('0' <= c
&& c
<= '9')
1205 else if ('a' <= c
&& c
<= 'z')
1206 digit
= c
- 'a' + 10;
1207 else if ('A' <= c
&& c
<= 'Z')
1208 digit
= c
- 'A' + 10;
1211 if (digit
>= (uintN
)base
)
1213 value
= value
* base
+ digit
;
1214 } while (++s1
!= send
);
1216 if (value
>= 9007199254740992.0) {
1219 * If we're accumulating a decimal number and the number is >=
1220 * 2^53, then the result from the repeated multiply-add above may
1221 * be inaccurate. Call js_strtod_harder to get the correct answer.
1224 size_t length
= s1
- start
;
1225 char *cstr
= (char *) cx
->malloc(length
+ 1);
1231 for (i
= 0; i
!= length
; i
++)
1232 cstr
[i
] = (char)start
[i
];
1235 value
= js_strtod_harder(JS_THREAD_DATA(cx
)->dtoaState
, cstr
, &estr
, &err
);
1236 if (err
== JS_DTOA_ENOMEM
) {
1237 JS_ReportOutOfMemory(cx
);
1241 if (err
== JS_DTOA_ERANGE
&& value
== HUGE_VAL
)
1242 value
= js_PositiveInfinity
;
1244 } else if ((base
& (base
- 1)) == 0) {
1246 * The number may also be inaccurate for power-of-two bases. This
1247 * happens if the addition in value * base + digit causes a round-
1248 * down to an even least significant mantissa bit when the first
1249 * dropped bit is a one. If any of the following digits in the
1250 * number (which haven't been added in yet) are nonzero, then the
1251 * correct action would have been to round up instead of down. An
1252 * example occurs when reading the number 0x1000000000000081, which
1253 * rounds to 0x1000000000000000 instead of 0x1000000000000100.
1255 struct BinaryDigitReader bdr
;
1260 bdr
.digit
= 0; // shut GCC up
1266 /* Skip leading zeros. */
1268 bit
= GetNextBinaryDigit(&bdr
);
1272 /* Gather the 53 significant bits (including the leading 1) */
1274 for (j
= 52; j
; j
--) {
1275 bit
= GetNextBinaryDigit(&bdr
);
1278 value
= value
*2 + bit
;
1280 /* bit2 is the 54th bit (the first dropped from the mantissa) */
1281 bit2
= GetNextBinaryDigit(&bdr
);
1283 jsdouble factor
= 2.0;
1284 intN sticky
= 0; /* sticky is 1 if any bit beyond the 54th is 1 */
1287 while ((bit3
= GetNextBinaryDigit(&bdr
)) >= 0) {
1291 value
+= bit2
& (bit
| sticky
);
1298 /* We don't worry about inaccurate numbers for any other base. */
1305 *dp
= negative
? -value
: value
;