Bug 449522 - Context menu for HTML5 <video> elements. r=gavin, ui-r=boriss
[wine-gecko.git] / js / src / jsnum.cpp
blobb4e4907afb4bdf7a67bf55bad83bfc7b43d3f82b
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
14 * License.
16 * The Original Code is Mozilla Communicator client code, released
17 * March 31, 1998.
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.
24 * Contributor(s):
25 * IBM Corp.
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.
44 #include "jsstddef.h"
45 #if defined(XP_WIN) || defined(XP_OS2)
46 #include <float.h>
47 #endif
48 #include <locale.h>
49 #include <limits.h>
50 #include <math.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include "jstypes.h"
54 #include "jsutil.h" /* Added by JSIFY */
55 #include "jsapi.h"
56 #include "jsatom.h"
57 #include "jsbuiltins.h"
58 #include "jscntxt.h"
59 #include "jsversion.h"
60 #include "jsdtoa.h"
61 #include "jsgc.h"
62 #include "jsinterp.h"
63 #include "jsnum.h"
64 #include "jsobj.h"
65 #include "jsopcode.h"
66 #include "jsprf.h"
67 #include "jsscope.h"
68 #include "jsstr.h"
70 static JSBool
71 num_isNaN(JSContext *cx, uintN argc, jsval *vp)
73 jsdouble x;
75 if (argc == 0) {
76 *vp = JSVAL_TRUE;
77 return JS_TRUE;
79 x = js_ValueToNumber(cx, &vp[2]);
80 if (JSVAL_IS_NULL(vp[2]))
81 return JS_FALSE;
82 *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x));
83 return JS_TRUE;
86 static JSBool
87 num_isFinite(JSContext *cx, uintN argc, jsval *vp)
89 jsdouble x;
91 if (argc == 0) {
92 *vp = JSVAL_FALSE;
93 return JS_TRUE;
95 x = js_ValueToNumber(cx, &vp[2]);
96 if (JSVAL_IS_NULL(vp[2]))
97 return JS_FALSE;
98 *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x));
99 return JS_TRUE;
102 static JSBool
103 num_parseFloat(JSContext *cx, uintN argc, jsval *vp)
105 JSString *str;
106 jsdouble d;
107 const jschar *bp, *end, *ep;
109 if (argc == 0) {
110 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
111 return JS_TRUE;
113 str = js_ValueToString(cx, vp[2]);
114 if (!str)
115 return JS_FALSE;
116 JSSTRING_CHARS_AND_END(str, bp, end);
117 if (!js_strtod(cx, bp, end, &ep, &d))
118 return JS_FALSE;
119 if (ep == bp) {
120 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
121 return JS_TRUE;
123 return js_NewNumberInRootedValue(cx, d, vp);
126 #ifdef JS_TRACER
127 jsdouble FASTCALL
128 js_ParseFloat(JSContext* cx, JSString* str)
130 const jschar* bp;
131 const jschar* end;
132 const jschar* ep;
133 jsdouble d;
135 JSSTRING_CHARS_AND_END(str, bp, end);
136 if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp)
137 return js_NaN;
138 return d;
140 #endif
142 /* See ECMA 15.1.2.2. */
143 static JSBool
144 num_parseInt(JSContext *cx, uintN argc, jsval *vp)
146 jsint radix;
147 JSString *str;
148 jsdouble d;
149 const jschar *bp, *end, *ep;
151 if (argc == 0) {
152 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
153 return JS_TRUE;
155 if (argc > 1) {
156 radix = js_ValueToECMAInt32(cx, &vp[3]);
157 if (JSVAL_IS_NULL(vp[3]))
158 return JS_FALSE;
159 } else {
160 radix = 0;
162 if (radix != 0 && (radix < 2 || radix > 36)) {
163 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
164 return JS_TRUE;
167 if (JSVAL_IS_INT(vp[2]) && (radix == 0 || radix == 10)) {
168 *vp = vp[2];
169 return JS_TRUE;
172 str = js_ValueToString(cx, vp[2]);
173 if (!str)
174 return JS_FALSE;
175 JSSTRING_CHARS_AND_END(str, bp, end);
176 if (!js_strtointeger(cx, bp, end, &ep, radix, &d))
177 return JS_FALSE;
178 if (ep == bp) {
179 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
180 return JS_TRUE;
182 return js_NewNumberInRootedValue(cx, d, vp);
185 #ifdef JS_TRACER
186 jsdouble FASTCALL
187 js_ParseInt(JSContext* cx, JSString* str)
189 const jschar* bp;
190 const jschar* end;
191 const jschar* ep;
192 jsdouble d;
194 JSSTRING_CHARS_AND_END(str, bp, end);
195 if (!js_strtointeger(cx, bp, end, &ep, 0, &d) || ep == bp)
196 return js_NaN;
197 return d;
200 jsdouble FASTCALL
201 js_ParseIntDouble(jsdouble d)
203 if (!JSDOUBLE_IS_FINITE(d))
204 return js_NaN;
205 return floor(d);
207 #endif
209 const char js_Infinity_str[] = "Infinity";
210 const char js_NaN_str[] = "NaN";
211 const char js_isNaN_str[] = "isNaN";
212 const char js_isFinite_str[] = "isFinite";
213 const char js_parseFloat_str[] = "parseFloat";
214 const char js_parseInt_str[] = "parseInt";
216 #ifdef JS_TRACER
218 JS_DEFINE_CALLINFO_2(DOUBLE, ParseInt, CONTEXT, STRING, 1, 1)
219 JS_DEFINE_CALLINFO_1(DOUBLE, ParseIntDouble, DOUBLE, 1, 1)
220 JS_DEFINE_CALLINFO_2(DOUBLE, ParseFloat, CONTEXT, STRING, 1, 1)
222 static const JSTraceableNative num_parseInt_trcinfo[] = {
223 { num_parseInt, &ci_ParseInt, "C", "s", INFALLIBLE | JSTN_MORE },
224 { num_parseInt, &ci_ParseIntDouble, "", "d", INFALLIBLE }
226 static const JSTraceableNative num_parseFloat_trcinfo[] = {
227 { num_parseFloat, &ci_ParseFloat, "C", "s", INFALLIBLE }
230 #endif /* JS_TRACER */
232 static JSFunctionSpec number_functions[] = {
233 JS_FN(js_isNaN_str, num_isNaN, 1,0),
234 JS_FN(js_isFinite_str, num_isFinite, 1,0),
235 JS_TN(js_parseFloat_str, num_parseFloat, 1,0, num_parseFloat_trcinfo),
236 JS_TN(js_parseInt_str, num_parseInt, 2,0, num_parseInt_trcinfo),
237 JS_FS_END
240 JSClass js_NumberClass = {
241 js_Number_str,
242 JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
243 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
244 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
245 JSCLASS_NO_OPTIONAL_MEMBERS
248 static JSBool
249 Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
251 jsval v;
252 jsdouble d;
254 if (argc != 0) {
255 d = js_ValueToNumber(cx, &argv[0]);
256 v = argv[0];
257 if (JSVAL_IS_NULL(v))
258 return JS_FALSE;
259 if (v != JSVAL_TRUE) {
260 JS_ASSERT(JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v));
261 } else {
262 if (!js_NewNumberInRootedValue(cx, d, &argv[0]))
263 return JS_FALSE;
264 v = argv[0];
266 } else {
267 v = JSVAL_ZERO;
269 if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
270 *rval = v;
271 return JS_TRUE;
273 STOBJ_SET_SLOT(obj, JSSLOT_PRIVATE, v);
274 return JS_TRUE;
277 #if JS_HAS_TOSOURCE
278 static JSBool
279 num_toSource(JSContext *cx, uintN argc, jsval *vp)
281 jsval v;
282 jsdouble d;
283 char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr;
284 char buf[64];
285 JSString *str;
287 if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v))
288 return JS_FALSE;
289 JS_ASSERT(JSVAL_IS_NUMBER(v));
290 d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
291 numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d);
292 if (!numStr) {
293 JS_ReportOutOfMemory(cx);
294 return JS_FALSE;
296 JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr);
297 str = JS_NewStringCopyZ(cx, buf);
298 if (!str)
299 return JS_FALSE;
300 *vp = STRING_TO_JSVAL(str);
301 return JS_TRUE;
303 #endif
305 /* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */
306 char *
307 js_IntToCString(jsint i, char *buf, size_t bufSize)
309 char *cp;
310 jsuint u;
312 u = (i < 0) ? -i : i;
314 cp = buf + bufSize; /* one past last buffer cell */
315 *--cp = '\0'; /* null terminate the string to be */
318 * Build the string from behind. We use multiply and subtraction
319 * instead of modulus because that's much faster.
321 do {
322 jsuint newu = u / 10;
323 *--cp = (char)(u - newu * 10) + '0';
324 u = newu;
325 } while (u != 0);
327 if (i < 0)
328 *--cp = '-';
330 JS_ASSERT(cp >= buf);
331 return cp;
334 static JSBool
335 num_toString(JSContext *cx, uintN argc, jsval *vp)
337 jsval v;
338 jsdouble d;
339 jsint base;
340 JSString *str;
342 if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v))
343 return JS_FALSE;
344 JS_ASSERT(JSVAL_IS_NUMBER(v));
345 d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
346 base = 10;
347 if (argc != 0 && !JSVAL_IS_VOID(vp[2])) {
348 base = js_ValueToECMAInt32(cx, &vp[2]);
349 if (JSVAL_IS_NULL(vp[2]))
350 return JS_FALSE;
351 if (base < 2 || base > 36) {
352 char numBuf[12];
353 char *numStr = js_IntToCString(base, numBuf, sizeof numBuf);
354 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX,
355 numStr);
356 return JS_FALSE;
359 if (base == 10) {
360 str = js_NumberToString(cx, d);
361 } else {
362 char *dStr = JS_dtobasestr(base, d);
363 if (!dStr) {
364 JS_ReportOutOfMemory(cx);
365 return JS_FALSE;
367 str = JS_NewStringCopyZ(cx, dStr);
368 free(dStr);
370 if (!str)
371 return JS_FALSE;
372 *vp = STRING_TO_JSVAL(str);
373 return JS_TRUE;
376 static JSBool
377 num_toLocaleString(JSContext *cx, uintN argc, jsval *vp)
379 char thousandsLength, decimalLength;
380 const char *numGrouping, *tmpGroup;
381 JSRuntime *rt;
382 JSString *numStr, *str;
383 const char *num, *end, *tmpSrc;
384 char *buf, *tmpDest;
385 const char *nint;
386 int digits, size, remainder, nrepeat;
389 * Create the string, move back to bytes to make string twiddling
390 * a bit easier and so we can insert platform charset seperators.
392 if (!num_toString(cx, 0, vp))
393 return JS_FALSE;
394 JS_ASSERT(JSVAL_IS_STRING(*vp));
395 numStr = JSVAL_TO_STRING(*vp);
396 num = js_GetStringBytes(cx, numStr);
397 if (!num)
398 return JS_FALSE;
401 * Find the first non-integer value, whether it be a letter as in
402 * 'Infinity', a decimal point, or an 'e' from exponential notation.
404 nint = num;
405 if (*nint == '-')
406 nint++;
407 while (*nint >= '0' && *nint <= '9')
408 nint++;
409 digits = nint - num;
410 end = num + digits;
411 if (!digits)
412 return JS_TRUE;
414 rt = cx->runtime;
415 thousandsLength = strlen(rt->thousandsSeparator);
416 decimalLength = strlen(rt->decimalSeparator);
418 /* Figure out how long resulting string will be. */
419 size = digits + (*nint ? strlen(nint + 1) + 1 : 0);
420 if (*nint == '.')
421 size += decimalLength;
423 numGrouping = tmpGroup = rt->numGrouping;
424 remainder = digits;
425 if (*num == '-')
426 remainder--;
428 while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
429 if (*tmpGroup >= remainder)
430 break;
431 size += thousandsLength;
432 remainder -= *tmpGroup;
433 tmpGroup++;
435 if (*tmpGroup == '\0' && *numGrouping != '\0') {
436 nrepeat = (remainder - 1) / tmpGroup[-1];
437 size += thousandsLength * nrepeat;
438 remainder -= nrepeat * tmpGroup[-1];
439 } else {
440 nrepeat = 0;
442 tmpGroup--;
444 buf = (char *)JS_malloc(cx, size + 1);
445 if (!buf)
446 return JS_FALSE;
448 tmpDest = buf;
449 tmpSrc = num;
451 while (*tmpSrc == '-' || remainder--)
452 *tmpDest++ = *tmpSrc++;
453 while (tmpSrc < end) {
454 strcpy(tmpDest, rt->thousandsSeparator);
455 tmpDest += thousandsLength;
456 memcpy(tmpDest, tmpSrc, *tmpGroup);
457 tmpDest += *tmpGroup;
458 tmpSrc += *tmpGroup;
459 if (--nrepeat < 0)
460 tmpGroup--;
463 if (*nint == '.') {
464 strcpy(tmpDest, rt->decimalSeparator);
465 tmpDest += decimalLength;
466 strcpy(tmpDest, nint + 1);
467 } else {
468 strcpy(tmpDest, nint);
471 if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
472 return cx->localeCallbacks->localeToUnicode(cx, buf, vp);
474 str = JS_NewString(cx, buf, size);
475 if (!str) {
476 JS_free(cx, buf);
477 return JS_FALSE;
480 *vp = STRING_TO_JSVAL(str);
481 return JS_TRUE;
484 static JSBool
485 num_valueOf(JSContext *cx, uintN argc, jsval *vp)
487 jsval v;
488 JSObject *obj;
490 v = vp[1];
491 if (JSVAL_IS_NUMBER(v)) {
492 *vp = v;
493 return JS_TRUE;
495 obj = JS_THIS_OBJECT(cx, vp);
496 if (!JS_InstanceOf(cx, obj, &js_NumberClass, vp + 2))
497 return JS_FALSE;
498 *vp = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE);
499 return JS_TRUE;
503 #define MAX_PRECISION 100
505 static JSBool
506 num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode,
507 jsint precisionMin, jsint precisionMax, jsint precisionOffset,
508 uintN argc, jsval *vp)
510 jsval v;
511 jsdouble d, precision;
512 JSString *str;
514 /* Use MAX_PRECISION+1 because precisionOffset can be 1. */
515 char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)];
516 char *numStr;
518 if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v))
519 return JS_FALSE;
520 JS_ASSERT(JSVAL_IS_NUMBER(v));
521 d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
523 if (argc == 0) {
524 precision = 0.0;
525 oneArgMode = zeroArgMode;
526 } else {
527 precision = js_ValueToNumber(cx, &vp[2]);
528 if (JSVAL_IS_NULL(vp[2]))
529 return JS_FALSE;
530 precision = js_DoubleToInteger(precision);
531 if (precision < precisionMin || precision > precisionMax) {
532 numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, precision);
533 if (!numStr)
534 JS_ReportOutOfMemory(cx);
535 else
536 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
537 return JS_FALSE;
541 numStr = JS_dtostr(buf, sizeof buf, oneArgMode, (jsint)precision + precisionOffset, d);
542 if (!numStr) {
543 JS_ReportOutOfMemory(cx);
544 return JS_FALSE;
546 str = JS_NewStringCopyZ(cx, numStr);
547 if (!str)
548 return JS_FALSE;
549 *vp = STRING_TO_JSVAL(str);
550 return JS_TRUE;
554 * In the following three implementations, we allow a larger range of precision
555 * than ECMA requires; this is permitted by ECMA-262.
557 static JSBool
558 num_toFixed(JSContext *cx, uintN argc, jsval *vp)
560 return num_to(cx, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0,
561 argc, vp);
564 static JSBool
565 num_toExponential(JSContext *cx, uintN argc, jsval *vp)
567 return num_to(cx, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0,
568 MAX_PRECISION, 1, argc, vp);
571 static JSBool
572 num_toPrecision(JSContext *cx, uintN argc, jsval *vp)
574 if (argc == 0 || JSVAL_IS_VOID(vp[2]))
575 return num_toString(cx, 0, vp);
576 return num_to(cx, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0,
577 argc, vp);
580 #ifdef JS_TRACER
582 JS_DEFINE_CALLINFO_2(STRING, NumberToString, CONTEXT, DOUBLE, 1, 1)
584 static const JSTraceableNative num_toString_trcinfo[] = {
585 { num_toString, &ci_NumberToString, "DC", "", FAIL_NULL }
588 #endif /* JS_TRACER */
590 static JSFunctionSpec number_methods[] = {
591 #if JS_HAS_TOSOURCE
592 JS_FN(js_toSource_str, num_toSource, 0,JSFUN_THISP_NUMBER),
593 #endif
594 JS_TN(js_toString_str, num_toString, 1,JSFUN_THISP_NUMBER,
595 num_toString_trcinfo),
596 JS_FN(js_toLocaleString_str, num_toLocaleString, 0,JSFUN_THISP_NUMBER),
597 JS_FN(js_valueOf_str, num_valueOf, 0,JSFUN_THISP_NUMBER),
598 JS_FN(js_toJSON_str, num_valueOf, 0,JSFUN_THISP_NUMBER),
599 JS_FN("toFixed", num_toFixed, 1,JSFUN_THISP_NUMBER),
600 JS_FN("toExponential", num_toExponential, 1,JSFUN_THISP_NUMBER),
601 JS_FN("toPrecision", num_toPrecision, 1,JSFUN_THISP_NUMBER),
602 JS_FS_END
605 /* NB: Keep this in synch with number_constants[]. */
606 enum nc_slot {
607 NC_NaN,
608 NC_POSITIVE_INFINITY,
609 NC_NEGATIVE_INFINITY,
610 NC_MAX_VALUE,
611 NC_MIN_VALUE,
612 NC_LIMIT
616 * Some to most C compilers forbid spelling these at compile time, or barf
617 * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
618 * using union jsdpun.
620 static JSConstDoubleSpec number_constants[] = {
621 {0, js_NaN_str, 0,{0,0,0}},
622 {0, "POSITIVE_INFINITY", 0,{0,0,0}},
623 {0, "NEGATIVE_INFINITY", 0,{0,0,0}},
624 {1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}},
625 {0, "MIN_VALUE", 0,{0,0,0}},
626 {0,0,0,{0,0,0}}
629 jsdouble js_NaN;
631 #if (defined XP_WIN || defined XP_OS2) && \
632 !defined WINCE && \
633 !defined __MWERKS__ && \
634 (defined _M_IX86 || \
635 (defined __GNUC__ && !defined __MINGW32__))
638 * Set the exception mask to mask all exceptions and set the FPU precision
639 * to 53 bit mantissa.
640 * On Alpha platform this is handled via Compiler option.
642 #define FIX_FPU() _control87(MCW_EM | PC_53, MCW_EM | MCW_PC)
644 #else
646 #define FIX_FPU() ((void)0)
648 #endif
650 JSBool
651 js_InitRuntimeNumberState(JSContext *cx)
653 JSRuntime *rt;
654 jsdpun u;
655 struct lconv *locale;
657 rt = cx->runtime;
658 JS_ASSERT(!rt->jsNaN);
660 FIX_FPU();
662 u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
663 u.s.lo = 0xffffffff;
664 number_constants[NC_NaN].dval = js_NaN = u.d;
665 rt->jsNaN = js_NewWeaklyRootedDouble(cx, js_NaN);
666 if (!rt->jsNaN)
667 return JS_FALSE;
669 u.s.hi = JSDOUBLE_HI32_EXPMASK;
670 u.s.lo = 0x00000000;
671 number_constants[NC_POSITIVE_INFINITY].dval = u.d;
672 rt->jsPositiveInfinity = js_NewWeaklyRootedDouble(cx, u.d);
673 if (!rt->jsPositiveInfinity)
674 return JS_FALSE;
676 u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
677 u.s.lo = 0x00000000;
678 number_constants[NC_NEGATIVE_INFINITY].dval = u.d;
679 rt->jsNegativeInfinity = js_NewWeaklyRootedDouble(cx, u.d);
680 if (!rt->jsNegativeInfinity)
681 return JS_FALSE;
683 u.s.hi = 0;
684 u.s.lo = 1;
685 number_constants[NC_MIN_VALUE].dval = u.d;
687 locale = localeconv();
688 rt->thousandsSeparator =
689 JS_strdup(cx, locale->thousands_sep ? locale->thousands_sep : "'");
690 rt->decimalSeparator =
691 JS_strdup(cx, locale->decimal_point ? locale->decimal_point : ".");
692 rt->numGrouping =
693 JS_strdup(cx, locale->grouping ? locale->grouping : "\3\0");
695 return rt->thousandsSeparator && rt->decimalSeparator && rt->numGrouping;
698 void
699 js_TraceRuntimeNumberState(JSTracer *trc)
701 JSRuntime *rt;
703 rt = trc->context->runtime;
704 if (rt->jsNaN)
705 JS_CALL_DOUBLE_TRACER(trc, rt->jsNaN, "NaN");
706 if (rt->jsPositiveInfinity)
707 JS_CALL_DOUBLE_TRACER(trc, rt->jsPositiveInfinity, "+Infinity");
708 if (rt->jsNegativeInfinity)
709 JS_CALL_DOUBLE_TRACER(trc, rt->jsNegativeInfinity, "-Infinity");
712 void
713 js_FinishRuntimeNumberState(JSContext *cx)
715 JSRuntime *rt = cx->runtime;
717 js_UnlockGCThingRT(rt, rt->jsNaN);
718 js_UnlockGCThingRT(rt, rt->jsNegativeInfinity);
719 js_UnlockGCThingRT(rt, rt->jsPositiveInfinity);
721 rt->jsNaN = NULL;
722 rt->jsNegativeInfinity = NULL;
723 rt->jsPositiveInfinity = NULL;
725 JS_free(cx, (void *)rt->thousandsSeparator);
726 JS_free(cx, (void *)rt->decimalSeparator);
727 JS_free(cx, (void *)rt->numGrouping);
728 rt->thousandsSeparator = rt->decimalSeparator = rt->numGrouping = NULL;
731 JSObject *
732 js_InitNumberClass(JSContext *cx, JSObject *obj)
734 JSObject *proto, *ctor;
735 JSRuntime *rt;
737 /* XXX must do at least once per new thread, so do it per JSContext... */
738 FIX_FPU();
740 if (!JS_DefineFunctions(cx, obj, number_functions))
741 return NULL;
743 proto = JS_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1,
744 NULL, number_methods, NULL, NULL);
745 if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
746 return NULL;
747 STOBJ_SET_SLOT(proto, JSSLOT_PRIVATE, JSVAL_ZERO);
748 if (!JS_DefineConstDoubles(cx, ctor, number_constants))
749 return NULL;
751 /* ECMA 15.1.1.1 */
752 rt = cx->runtime;
753 if (!JS_DefineProperty(cx, obj, js_NaN_str, DOUBLE_TO_JSVAL(rt->jsNaN),
754 NULL, NULL, JSPROP_PERMANENT)) {
755 return NULL;
758 /* ECMA 15.1.1.2 */
759 if (!JS_DefineProperty(cx, obj, js_Infinity_str,
760 DOUBLE_TO_JSVAL(rt->jsPositiveInfinity),
761 NULL, NULL, JSPROP_PERMANENT)) {
762 return NULL;
764 return proto;
767 JSBool
768 js_NewNumberInRootedValue(JSContext *cx, jsdouble d, jsval *vp)
770 jsint i;
772 if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
773 *vp = INT_TO_JSVAL(i);
774 return JS_TRUE;
776 return js_NewDoubleInRootedValue(cx, d, vp);
779 char *
780 js_NumberToCString(JSContext *cx, jsdouble d, char *buf, size_t bufSize)
782 jsint i;
783 char *numStr;
785 JS_ASSERT(bufSize >= DTOSTR_STANDARD_BUFFER_SIZE);
786 if (JSDOUBLE_IS_INT(d, i)) {
787 numStr = js_IntToCString(i, buf, bufSize);
788 } else {
789 numStr = JS_dtostr(buf, bufSize, DTOSTR_STANDARD, 0, d);
790 if (!numStr) {
791 JS_ReportOutOfMemory(cx);
792 return NULL;
795 return numStr;
798 JSString * JS_FASTCALL
799 js_NumberToString(JSContext *cx, jsdouble d)
801 char buf[DTOSTR_STANDARD_BUFFER_SIZE];
802 char *numStr;
804 numStr = js_NumberToCString(cx, d, buf, sizeof buf);
805 if (!numStr)
806 return NULL;
807 return JS_NewStringCopyZ(cx, numStr);
810 jsdouble
811 js_ValueToNumber(JSContext *cx, jsval *vp)
813 jsval v;
814 JSString *str;
815 const jschar *bp, *end, *ep;
816 jsdouble d, *dp;
817 JSObject *obj;
818 JSTempValueRooter tvr;
820 v = *vp;
821 for (;;) {
822 if (JSVAL_IS_INT(v))
823 return (jsdouble) JSVAL_TO_INT(v);
824 if (JSVAL_IS_DOUBLE(v))
825 return *JSVAL_TO_DOUBLE(v);
826 if (JSVAL_IS_STRING(v)) {
827 str = JSVAL_TO_STRING(v);
830 * Note that ECMA doesn't treat a string beginning with a '0' as
831 * an octal number here. This works because all such numbers will
832 * be interpreted as decimal by js_strtod and will never get
833 * passed to js_strtointeger (which would interpret them as
834 * octal).
836 JSSTRING_CHARS_AND_END(str, bp, end);
837 if ((!js_strtod(cx, bp, end, &ep, &d) ||
838 js_SkipWhiteSpace(ep, end) != end) &&
839 (!js_strtointeger(cx, bp, end, &ep, 0, &d) ||
840 js_SkipWhiteSpace(ep, end) != end)) {
841 break;
845 * JSVAL_TRUE indicates that double jsval was never constructed
846 * for the result.
848 *vp = JSVAL_TRUE;
849 return d;
851 if (JSVAL_IS_BOOLEAN(v)) {
852 if (JSVAL_TO_BOOLEAN(v)) {
853 *vp = JSVAL_ONE;
854 return 1.0;
855 } else {
856 *vp = JSVAL_ZERO;
857 return 0.0;
860 if (JSVAL_IS_NULL(v)) {
861 *vp = JSVAL_ZERO;
862 return 0.0;
864 if (JSVAL_IS_VOID(v))
865 break;
867 JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
868 obj = JSVAL_TO_OBJECT(v);
871 * vp roots obj so we cannot use it as an extra root for
872 * OBJ_DEFAULT_VALUE result when calling the hook.
874 JS_PUSH_SINGLE_TEMP_ROOT(cx, v, &tvr);
875 if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_NUMBER, &tvr.u.value))
876 obj = NULL;
877 else
878 v = *vp = tvr.u.value;
879 JS_POP_TEMP_ROOT(cx, &tvr);
880 if (!obj) {
881 *vp = JSVAL_NULL;
882 return 0.0;
884 if (!JSVAL_IS_PRIMITIVE(v))
885 break;
888 dp = cx->runtime->jsNaN;
889 *vp = DOUBLE_TO_JSVAL(dp);
890 return *dp;
893 int32
894 js_ValueToECMAInt32(JSContext *cx, jsval *vp)
896 jsval v;
897 jsdouble d;
899 v = *vp;
900 if (JSVAL_IS_INT(v))
901 return JSVAL_TO_INT(v);
902 if (JSVAL_IS_DOUBLE(v)) {
903 d = *JSVAL_TO_DOUBLE(v);
904 *vp = JSVAL_TRUE;
905 } else {
906 d = js_ValueToNumber(cx, vp);
907 if (JSVAL_IS_NULL(*vp))
908 return 0;
909 *vp = JSVAL_TRUE;
911 return js_DoubleToECMAInt32(d);
914 int32
915 js_DoubleToECMAInt32(jsdouble d)
917 int32 i;
918 jsdouble two32, two31;
920 if (!JSDOUBLE_IS_FINITE(d))
921 return 0;
923 i = (int32) d;
924 if ((jsdouble) i == d)
925 return i;
927 two32 = 4294967296.0;
928 two31 = 2147483648.0;
929 d = fmod(d, two32);
930 d = (d >= 0) ? floor(d) : ceil(d) + two32;
931 return (int32) (d >= two31 ? d - two32 : d);
934 uint32
935 js_ValueToECMAUint32(JSContext *cx, jsval *vp)
937 jsval v;
938 jsint i;
939 jsdouble d;
941 v = *vp;
942 if (JSVAL_IS_INT(v)) {
943 i = JSVAL_TO_INT(v);
944 if (i < 0)
945 *vp = JSVAL_TRUE;
946 return (uint32) i;
948 if (JSVAL_IS_DOUBLE(v)) {
949 d = *JSVAL_TO_DOUBLE(v);
950 *vp = JSVAL_TRUE;
951 } else {
952 d = js_ValueToNumber(cx, vp);
953 if (JSVAL_IS_NULL(*vp))
954 return 0;
955 *vp = JSVAL_TRUE;
957 return js_DoubleToECMAUint32(d);
960 uint32
961 js_DoubleToECMAUint32(jsdouble d)
963 int32 i;
964 JSBool neg;
965 jsdouble two32;
967 if (!JSDOUBLE_IS_FINITE(d))
968 return 0;
971 * We check whether d fits int32, not uint32, as all but the ">>>" bit
972 * manipulation bytecode stores the result as int, not uint. When the
973 * result does not fit int jsval, it will be stored as a negative double.
975 i = (int32) d;
976 if ((jsdouble) i == d)
977 return (int32)i;
979 neg = (d < 0);
980 d = floor(neg ? -d : d);
981 d = neg ? -d : d;
983 two32 = 4294967296.0;
984 d = fmod(d, two32);
986 return (uint32) (d >= 0 ? d : d + two32);
989 int32
990 js_ValueToInt32(JSContext *cx, jsval *vp)
992 jsval v;
993 jsdouble d;
995 v = *vp;
996 if (JSVAL_IS_INT(v))
997 return JSVAL_TO_INT(v);
998 d = js_ValueToNumber(cx, vp);
999 if (JSVAL_IS_NULL(*vp))
1000 return 0;
1001 if (JSVAL_IS_INT(*vp))
1002 return JSVAL_TO_INT(*vp);
1004 *vp = JSVAL_TRUE;
1005 if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
1006 js_ReportValueError(cx, JSMSG_CANT_CONVERT,
1007 JSDVG_SEARCH_STACK, v, NULL);
1008 *vp = JSVAL_NULL;
1009 return 0;
1011 return (int32) floor(d + 0.5); /* Round to nearest */
1014 uint16
1015 js_ValueToUint16(JSContext *cx, jsval *vp)
1017 jsdouble d;
1018 uint16 u;
1019 jsuint m;
1020 JSBool neg;
1022 d = js_ValueToNumber(cx, vp);
1023 if (JSVAL_IS_NULL(*vp))
1024 return 0;
1026 if (JSVAL_IS_INT(*vp)) {
1027 u = (uint16) JSVAL_TO_INT(*vp);
1028 } else if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
1029 u = (uint16) 0;
1030 } else {
1031 u = (uint16) d;
1032 if ((jsdouble) u != d) {
1033 neg = (d < 0);
1034 d = floor(neg ? -d : d);
1035 d = neg ? -d : d;
1036 m = JS_BIT(16);
1037 d = fmod(d, (double) m);
1038 if (d < 0)
1039 d += m;
1040 u = (uint16) d;
1043 *vp = INT_TO_JSVAL(u);
1044 return u;
1047 jsdouble
1048 js_DoubleToInteger(jsdouble d)
1050 JSBool neg;
1052 if (d == 0)
1053 return d;
1054 if (!JSDOUBLE_IS_FINITE(d)) {
1055 if (JSDOUBLE_IS_NaN(d))
1056 return 0;
1057 return d;
1059 neg = (d < 0);
1060 d = floor(neg ? -d : d);
1061 return neg ? -d : d;
1064 JSBool
1065 js_strtod(JSContext *cx, const jschar *s, const jschar *send,
1066 const jschar **ep, jsdouble *dp)
1068 const jschar *s1;
1069 size_t length, i;
1070 char cbuf[32];
1071 char *cstr, *istr, *estr;
1072 JSBool negative;
1073 jsdouble d;
1075 s1 = js_SkipWhiteSpace(s, send);
1076 length = send - s1;
1078 /* Use cbuf to avoid malloc */
1079 if (length >= sizeof cbuf) {
1080 cstr = (char *) JS_malloc(cx, length + 1);
1081 if (!cstr)
1082 return JS_FALSE;
1083 } else {
1084 cstr = cbuf;
1087 for (i = 0; i != length; i++) {
1088 if (s1[i] >> 8)
1089 break;
1090 cstr[i] = (char)s1[i];
1092 cstr[i] = 0;
1094 istr = cstr;
1095 if ((negative = (*istr == '-')) != 0 || *istr == '+')
1096 istr++;
1097 if (!strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
1098 d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity);
1099 estr = istr + 8;
1100 } else {
1101 int err;
1102 d = JS_strtod(cstr, &estr, &err);
1103 if (d == HUGE_VAL)
1104 d = *cx->runtime->jsPositiveInfinity;
1105 else if (d == -HUGE_VAL)
1106 d = *cx->runtime->jsNegativeInfinity;
1107 #ifdef HPUX
1108 if (d == 0.0 && negative) {
1110 * "-0", "-1e-2000" come out as positive zero
1111 * here on HPUX. Force a negative zero instead.
1113 JSDOUBLE_HI32(d) = JSDOUBLE_HI32_SIGNBIT;
1114 JSDOUBLE_LO32(d) = 0;
1116 #endif
1119 i = estr - cstr;
1120 if (cstr != cbuf)
1121 JS_free(cx, cstr);
1122 *ep = i ? s1 + i : s;
1123 *dp = d;
1124 return JS_TRUE;
1127 struct BinaryDigitReader
1129 uintN base; /* Base of number; must be a power of 2 */
1130 uintN digit; /* Current digit value in radix given by base */
1131 uintN digitMask; /* Mask to extract the next bit from digit */
1132 const jschar *digits; /* Pointer to the remaining digits */
1133 const jschar *end; /* Pointer to first non-digit */
1136 /* Return the next binary digit from the number or -1 if done */
1137 static intN GetNextBinaryDigit(struct BinaryDigitReader *bdr)
1139 intN bit;
1141 if (bdr->digitMask == 0) {
1142 uintN c;
1144 if (bdr->digits == bdr->end)
1145 return -1;
1147 c = *bdr->digits++;
1148 if ('0' <= c && c <= '9')
1149 bdr->digit = c - '0';
1150 else if ('a' <= c && c <= 'z')
1151 bdr->digit = c - 'a' + 10;
1152 else bdr->digit = c - 'A' + 10;
1153 bdr->digitMask = bdr->base >> 1;
1155 bit = (bdr->digit & bdr->digitMask) != 0;
1156 bdr->digitMask >>= 1;
1157 return bit;
1160 JSBool
1161 js_strtointeger(JSContext *cx, const jschar *s, const jschar *send,
1162 const jschar **ep, jsint base, jsdouble *dp)
1164 const jschar *s1, *start;
1165 JSBool negative;
1166 jsdouble value;
1168 s1 = js_SkipWhiteSpace(s, send);
1169 if (s1 == send)
1170 goto no_digits;
1171 if ((negative = (*s1 == '-')) != 0 || *s1 == '+') {
1172 s1++;
1173 if (s1 == send)
1174 goto no_digits;
1177 if (base == 0) {
1178 /* No base supplied, or some base that evaluated to 0. */
1179 if (*s1 == '0') {
1180 /* It's either hex or octal; only increment char if str isn't '0' */
1181 if (s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) {
1182 base = 16;
1183 s1 += 2;
1184 if (s1 == send)
1185 goto no_digits;
1186 } else {
1187 base = 8;
1189 } else {
1190 base = 10; /* Default to decimal. */
1192 } else if (base == 16) {
1193 /* If base is 16, ignore hex prefix. */
1194 if (*s1 == '0' && s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) {
1195 s1 += 2;
1196 if (s1 == send)
1197 goto no_digits;
1202 * Done with the preliminaries; find some prefix of the string that's
1203 * a number in the given base.
1205 JS_ASSERT(s1 < send);
1206 start = s1;
1207 value = 0.0;
1208 do {
1209 uintN digit;
1210 jschar c = *s1;
1211 if ('0' <= c && c <= '9')
1212 digit = c - '0';
1213 else if ('a' <= c && c <= 'z')
1214 digit = c - 'a' + 10;
1215 else if ('A' <= c && c <= 'Z')
1216 digit = c - 'A' + 10;
1217 else
1218 break;
1219 if (digit >= (uintN)base)
1220 break;
1221 value = value * base + digit;
1222 } while (++s1 != send);
1224 if (value >= 9007199254740992.0) {
1225 if (base == 10) {
1227 * If we're accumulating a decimal number and the number is >=
1228 * 2^53, then the result from the repeated multiply-add above may
1229 * be inaccurate. Call JS_strtod to get the correct answer.
1231 size_t i;
1232 size_t length = s1 - start;
1233 char *cstr = (char *) JS_malloc(cx, length + 1);
1234 char *estr;
1235 int err=0;
1237 if (!cstr)
1238 return JS_FALSE;
1239 for (i = 0; i != length; i++)
1240 cstr[i] = (char)start[i];
1241 cstr[length] = 0;
1243 value = JS_strtod(cstr, &estr, &err);
1244 if (err == JS_DTOA_ENOMEM) {
1245 JS_ReportOutOfMemory(cx);
1246 JS_free(cx, cstr);
1247 return JS_FALSE;
1249 if (err == JS_DTOA_ERANGE && value == HUGE_VAL)
1250 value = *cx->runtime->jsPositiveInfinity;
1251 JS_free(cx, cstr);
1252 } else if ((base & (base - 1)) == 0) {
1254 * The number may also be inaccurate for power-of-two bases. This
1255 * happens if the addition in value * base + digit causes a round-
1256 * down to an even least significant mantissa bit when the first
1257 * dropped bit is a one. If any of the following digits in the
1258 * number (which haven't been added in yet) are nonzero, then the
1259 * correct action would have been to round up instead of down. An
1260 * example occurs when reading the number 0x1000000000000081, which
1261 * rounds to 0x1000000000000000 instead of 0x1000000000000100.
1263 struct BinaryDigitReader bdr;
1264 intN bit, bit2;
1265 intN j;
1267 bdr.base = base;
1268 bdr.digitMask = 0;
1269 bdr.digits = start;
1270 bdr.end = s1;
1271 value = 0.0;
1273 /* Skip leading zeros. */
1274 do {
1275 bit = GetNextBinaryDigit(&bdr);
1276 } while (bit == 0);
1278 if (bit == 1) {
1279 /* Gather the 53 significant bits (including the leading 1) */
1280 value = 1.0;
1281 for (j = 52; j; j--) {
1282 bit = GetNextBinaryDigit(&bdr);
1283 if (bit < 0)
1284 goto done;
1285 value = value*2 + bit;
1287 /* bit2 is the 54th bit (the first dropped from the mantissa) */
1288 bit2 = GetNextBinaryDigit(&bdr);
1289 if (bit2 >= 0) {
1290 jsdouble factor = 2.0;
1291 intN sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */
1292 intN bit3;
1294 while ((bit3 = GetNextBinaryDigit(&bdr)) >= 0) {
1295 sticky |= bit3;
1296 factor *= 2;
1298 value += bit2 & (bit | sticky);
1299 value *= factor;
1301 done:;
1305 /* We don't worry about inaccurate numbers for any other base. */
1307 if (s1 == start) {
1308 no_digits:
1309 *dp = 0.0;
1310 *ep = s;
1311 } else {
1312 *dp = negative ? -value : value;
1313 *ep = s1;
1315 return JS_TRUE;