/[jscoverage]/trunk/js/jsnum.cpp
ViewVC logotype

Contents of /trunk/js/jsnum.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 507 - (show annotations)
Sun Jan 10 07:23:34 2010 UTC (9 years, 8 months ago) by siliconforks
File size: 39065 byte(s)
Update SpiderMonkey from Firefox 3.6rc1.

1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 *
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/
10 *
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.
15 *
16 * The Original Code is Mozilla Communicator client code, released
17 * March 31, 1998.
18 *
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.
23 *
24 * Contributor(s):
25 * IBM Corp.
26 *
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.
38 *
39 * ***** END LICENSE BLOCK ***** */
40
41 #define __STDC_LIMIT_MACROS
42
43 /*
44 * JS number type and wrapper class.
45 */
46 #ifdef XP_OS2
47 #define _PC_53 PC_53
48 #define _MCW_EM MCW_EM
49 #define _MCW_PC MCW_PC
50 #endif
51 #include <locale.h>
52 #include <limits.h>
53 #include <math.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include "jstypes.h"
57 #include "jsstdint.h"
58 #include "jsutil.h" /* Added by JSIFY */
59 #include "jsapi.h"
60 #include "jsatom.h"
61 #include "jsbuiltins.h"
62 #include "jscntxt.h"
63 #include "jsversion.h"
64 #include "jsdtoa.h"
65 #include "jsgc.h"
66 #include "jsinterp.h"
67 #include "jsnum.h"
68 #include "jsobj.h"
69 #include "jsopcode.h"
70 #include "jsprf.h"
71 #include "jsscope.h"
72 #include "jsstr.h"
73 #include "jsstrinlines.h"
74 #include "jsvector.h"
75
76
77 #ifndef JS_HAVE_STDINT_H /* Native support is innocent until proven guilty. */
78
79 JS_STATIC_ASSERT(uint8_t(-1) == UINT8_MAX);
80 JS_STATIC_ASSERT(uint16_t(-1) == UINT16_MAX);
81 JS_STATIC_ASSERT(uint32_t(-1) == UINT32_MAX);
82 JS_STATIC_ASSERT(uint64_t(-1) == UINT64_MAX);
83
84 JS_STATIC_ASSERT(INT8_MAX > INT8_MIN);
85 JS_STATIC_ASSERT(uint8_t(INT8_MAX) + uint8_t(1) == uint8_t(INT8_MIN));
86 JS_STATIC_ASSERT(INT16_MAX > INT16_MIN);
87 JS_STATIC_ASSERT(uint16_t(INT16_MAX) + uint16_t(1) == uint16_t(INT16_MIN));
88 JS_STATIC_ASSERT(INT32_MAX > INT32_MIN);
89 JS_STATIC_ASSERT(uint32_t(INT32_MAX) + uint32_t(1) == uint32_t(INT32_MIN));
90 JS_STATIC_ASSERT(INT64_MAX > INT64_MIN);
91 JS_STATIC_ASSERT(uint64_t(INT64_MAX) + uint64_t(1) == uint64_t(INT64_MIN));
92
93 JS_STATIC_ASSERT(INTPTR_MAX > INTPTR_MIN);
94 JS_STATIC_ASSERT(uintptr_t(INTPTR_MAX) + uintptr_t(1) == uintptr_t(INTPTR_MIN));
95 JS_STATIC_ASSERT(uintptr_t(-1) == UINTPTR_MAX);
96 JS_STATIC_ASSERT(size_t(-1) == SIZE_MAX);
97 JS_STATIC_ASSERT(PTRDIFF_MAX > PTRDIFF_MIN);
98 JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MAX) == PTRDIFF_MAX);
99 JS_STATIC_ASSERT(ptrdiff_t(PTRDIFF_MIN) == PTRDIFF_MIN);
100 JS_STATIC_ASSERT(uintptr_t(PTRDIFF_MAX) + uintptr_t(1) == uintptr_t(PTRDIFF_MIN));
101
102 #endif /* JS_HAVE_STDINT_H */
103
104 static JSBool
105 num_isNaN(JSContext *cx, uintN argc, jsval *vp)
106 {
107 jsdouble x;
108
109 if (argc == 0) {
110 *vp = JSVAL_TRUE;
111 return JS_TRUE;
112 }
113 x = js_ValueToNumber(cx, &vp[2]);
114 if (JSVAL_IS_NULL(vp[2]))
115 return JS_FALSE;
116 *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x));
117 return JS_TRUE;
118 }
119
120 static JSBool
121 num_isFinite(JSContext *cx, uintN argc, jsval *vp)
122 {
123 jsdouble x;
124
125 if (argc == 0) {
126 *vp = JSVAL_FALSE;
127 return JS_TRUE;
128 }
129 x = js_ValueToNumber(cx, &vp[2]);
130 if (JSVAL_IS_NULL(vp[2]))
131 return JS_FALSE;
132 *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x));
133 return JS_TRUE;
134 }
135
136 static JSBool
137 num_parseFloat(JSContext *cx, uintN argc, jsval *vp)
138 {
139 JSString *str;
140 jsdouble d;
141 const jschar *bp, *end, *ep;
142
143 if (argc == 0) {
144 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
145 return JS_TRUE;
146 }
147 str = js_ValueToString(cx, vp[2]);
148 if (!str)
149 return JS_FALSE;
150 str->getCharsAndEnd(bp, end);
151 if (!js_strtod(cx, bp, end, &ep, &d))
152 return JS_FALSE;
153 if (ep == bp) {
154 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
155 return JS_TRUE;
156 }
157 return js_NewNumberInRootedValue(cx, d, vp);
158 }
159
160 #ifdef JS_TRACER
161 static jsdouble FASTCALL
162 ParseFloat(JSContext* cx, JSString* str)
163 {
164 const jschar* bp;
165 const jschar* end;
166 const jschar* ep;
167 jsdouble d;
168
169 str->getCharsAndEnd(bp, end);
170 if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp)
171 return js_NaN;
172 return d;
173 }
174 #endif
175
176 /* See ECMA 15.1.2.2. */
177 static JSBool
178 num_parseInt(JSContext *cx, uintN argc, jsval *vp)
179 {
180 jsint radix;
181 JSString *str;
182 jsdouble d;
183 const jschar *bp, *end, *ep;
184
185 if (argc == 0) {
186 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
187 return JS_TRUE;
188 }
189 if (argc > 1) {
190 radix = js_ValueToECMAInt32(cx, &vp[3]);
191 if (JSVAL_IS_NULL(vp[3]))
192 return JS_FALSE;
193 } else {
194 radix = 0;
195 }
196 if (radix != 0 && (radix < 2 || radix > 36)) {
197 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
198 return JS_TRUE;
199 }
200
201 if (JSVAL_IS_INT(vp[2]) && (radix == 0 || radix == 10)) {
202 *vp = vp[2];
203 return JS_TRUE;
204 }
205
206 str = js_ValueToString(cx, vp[2]);
207 if (!str)
208 return JS_FALSE;
209 str->getCharsAndEnd(bp, end);
210 if (!js_strtointeger(cx, bp, end, &ep, radix, &d))
211 return JS_FALSE;
212 if (ep == bp) {
213 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
214 return JS_TRUE;
215 }
216 return js_NewNumberInRootedValue(cx, d, vp);
217 }
218
219 #ifdef JS_TRACER
220 static jsdouble FASTCALL
221 ParseInt(JSContext* cx, JSString* str)
222 {
223 const jschar* bp;
224 const jschar* end;
225 const jschar* ep;
226 jsdouble d;
227
228 str->getCharsAndEnd(bp, end);
229 if (!js_strtointeger(cx, bp, end, &ep, 0, &d) || ep == bp)
230 return js_NaN;
231 return d;
232 }
233
234 static jsdouble FASTCALL
235 ParseIntDouble(jsdouble d)
236 {
237 if (!JSDOUBLE_IS_FINITE(d))
238 return js_NaN;
239 if (d > 0)
240 return floor(d);
241 if (d < 0)
242 return -floor(-d);
243 return 0;
244 }
245 #endif
246
247 const char js_Infinity_str[] = "Infinity";
248 const char js_NaN_str[] = "NaN";
249 const char js_isNaN_str[] = "isNaN";
250 const char js_isFinite_str[] = "isFinite";
251 const char js_parseFloat_str[] = "parseFloat";
252 const char js_parseInt_str[] = "parseInt";
253
254 #ifdef JS_TRACER
255
256 JS_DEFINE_TRCINFO_2(num_parseInt,
257 (2, (static, DOUBLE, ParseInt, CONTEXT, STRING, 1, 1)),
258 (1, (static, DOUBLE, ParseIntDouble, DOUBLE, 1, 1)))
259
260 JS_DEFINE_TRCINFO_1(num_parseFloat,
261 (2, (static, DOUBLE, ParseFloat, CONTEXT, STRING, 1, 1)))
262
263 #endif /* JS_TRACER */
264
265 static JSFunctionSpec number_functions[] = {
266 JS_FN(js_isNaN_str, num_isNaN, 1,0),
267 JS_FN(js_isFinite_str, num_isFinite, 1,0),
268 JS_TN(js_parseFloat_str, num_parseFloat, 1,0, &num_parseFloat_trcinfo),
269 JS_TN(js_parseInt_str, num_parseInt, 2,0, &num_parseInt_trcinfo),
270 JS_FS_END
271 };
272
273 JSClass js_NumberClass = {
274 js_Number_str,
275 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
276 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
277 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL,
278 JSCLASS_NO_OPTIONAL_MEMBERS
279 };
280
281 static JSBool
282 Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
283 {
284 jsval v;
285 jsdouble d;
286
287 if (argc != 0) {
288 d = js_ValueToNumber(cx, &argv[0]);
289 v = argv[0];
290 if (JSVAL_IS_NULL(v))
291 return JS_FALSE;
292 if (v != JSVAL_TRUE) {
293 JS_ASSERT(JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v));
294 } else {
295 if (!js_NewNumberInRootedValue(cx, d, &argv[0]))
296 return JS_FALSE;
297 v = argv[0];
298 }
299 } else {
300 v = JSVAL_ZERO;
301 }
302 if (!JS_IsConstructing(cx))
303 *rval = v;
304 else
305 obj->fslots[JSSLOT_PRIMITIVE_THIS] = v;
306 return true;
307 }
308
309 #if JS_HAS_TOSOURCE
310 static JSBool
311 num_toSource(JSContext *cx, uintN argc, jsval *vp)
312 {
313 jsval v;
314 jsdouble d;
315 char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr;
316 char buf[64];
317 JSString *str;
318
319 if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v))
320 return JS_FALSE;
321 JS_ASSERT(JSVAL_IS_NUMBER(v));
322 d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
323 numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d);
324 if (!numStr) {
325 JS_ReportOutOfMemory(cx);
326 return JS_FALSE;
327 }
328 JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr);
329 str = JS_NewStringCopyZ(cx, buf);
330 if (!str)
331 return JS_FALSE;
332 *vp = STRING_TO_JSVAL(str);
333 return JS_TRUE;
334 }
335 #endif
336
337 /* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */
338 static char *
339 IntToCString(jsint i, jsint base, char *buf, size_t bufSize)
340 {
341 char *cp;
342 jsuint u;
343
344 u = (i < 0) ? -i : i;
345
346 cp = buf + bufSize; /* one past last buffer cell */
347 *--cp = '\0'; /* null terminate the string to be */
348
349 /*
350 * Build the string from behind. We use multiply and subtraction
351 * instead of modulus because that's much faster.
352 */
353 switch (base) {
354 case 10:
355 do {
356 jsuint newu = u / 10;
357 *--cp = (char)(u - newu * 10) + '0';
358 u = newu;
359 } while (u != 0);
360 break;
361 case 16:
362 do {
363 jsuint newu = u / 16;
364 *--cp = "0123456789abcdef"[u - newu * 16];
365 u = newu;
366 } while (u != 0);
367 break;
368 default:
369 JS_ASSERT(base >= 2 && base <= 36);
370 do {
371 jsuint newu = u / base;
372 *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[u - newu * base];
373 u = newu;
374 } while (u != 0);
375 break;
376 }
377 if (i < 0)
378 *--cp = '-';
379
380 JS_ASSERT(cp >= buf);
381 return cp;
382 }
383
384 static JSBool
385 num_toString(JSContext *cx, uintN argc, jsval *vp)
386 {
387 jsval v;
388 jsdouble d;
389 jsint base;
390 JSString *str;
391
392 if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v))
393 return JS_FALSE;
394 JS_ASSERT(JSVAL_IS_NUMBER(v));
395 d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
396 base = 10;
397 if (argc != 0 && !JSVAL_IS_VOID(vp[2])) {
398 base = js_ValueToECMAInt32(cx, &vp[2]);
399 if (JSVAL_IS_NULL(vp[2]))
400 return JS_FALSE;
401 if (base < 2 || base > 36) {
402 char numBuf[12];
403 char *numStr = IntToCString(base, 10, numBuf, sizeof numBuf);
404 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX,
405 numStr);
406 return JS_FALSE;
407 }
408 }
409 if (base == 10) {
410 str = js_NumberToString(cx, d);
411 } else {
412 char *dStr = JS_dtobasestr(base, d);
413 if (!dStr) {
414 JS_ReportOutOfMemory(cx);
415 return JS_FALSE;
416 }
417 str = JS_NewStringCopyZ(cx, dStr);
418 js_free(dStr);
419 }
420 if (!str)
421 return JS_FALSE;
422 *vp = STRING_TO_JSVAL(str);
423 return JS_TRUE;
424 }
425
426 static JSBool
427 num_toLocaleString(JSContext *cx, uintN argc, jsval *vp)
428 {
429 char thousandsLength, decimalLength;
430 const char *numGrouping, *tmpGroup;
431 JSRuntime *rt;
432 JSString *numStr, *str;
433 const char *num, *end, *tmpSrc;
434 char *buf, *tmpDest;
435 const char *nint;
436 int digits, size, remainder, nrepeat;
437
438 /*
439 * Create the string, move back to bytes to make string twiddling
440 * a bit easier and so we can insert platform charset seperators.
441 */
442 if (!num_toString(cx, 0, vp))
443 return JS_FALSE;
444 JS_ASSERT(JSVAL_IS_STRING(*vp));
445 numStr = JSVAL_TO_STRING(*vp);
446 num = js_GetStringBytes(cx, numStr);
447 if (!num)
448 return JS_FALSE;
449
450 /*
451 * Find the first non-integer value, whether it be a letter as in
452 * 'Infinity', a decimal point, or an 'e' from exponential notation.
453 */
454 nint = num;
455 if (*nint == '-')
456 nint++;
457 while (*nint >= '0' && *nint <= '9')
458 nint++;
459 digits = nint - num;
460 end = num + digits;
461 if (!digits)
462 return JS_TRUE;
463
464 rt = cx->runtime;
465 thousandsLength = strlen(rt->thousandsSeparator);
466 decimalLength = strlen(rt->decimalSeparator);
467
468 /* Figure out how long resulting string will be. */
469 size = digits + (*nint ? strlen(nint + 1) + 1 : 0);
470 if (*nint == '.')
471 size += decimalLength;
472
473 numGrouping = tmpGroup = rt->numGrouping;
474 remainder = digits;
475 if (*num == '-')
476 remainder--;
477
478 while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
479 if (*tmpGroup >= remainder)
480 break;
481 size += thousandsLength;
482 remainder -= *tmpGroup;
483 tmpGroup++;
484 }
485 if (*tmpGroup == '\0' && *numGrouping != '\0') {
486 nrepeat = (remainder - 1) / tmpGroup[-1];
487 size += thousandsLength * nrepeat;
488 remainder -= nrepeat * tmpGroup[-1];
489 } else {
490 nrepeat = 0;
491 }
492 tmpGroup--;
493
494 buf = (char *)cx->malloc(size + 1);
495 if (!buf)
496 return JS_FALSE;
497
498 tmpDest = buf;
499 tmpSrc = num;
500
501 while (*tmpSrc == '-' || remainder--)
502 *tmpDest++ = *tmpSrc++;
503 while (tmpSrc < end) {
504 strcpy(tmpDest, rt->thousandsSeparator);
505 tmpDest += thousandsLength;
506 memcpy(tmpDest, tmpSrc, *tmpGroup);
507 tmpDest += *tmpGroup;
508 tmpSrc += *tmpGroup;
509 if (--nrepeat < 0)
510 tmpGroup--;
511 }
512
513 if (*nint == '.') {
514 strcpy(tmpDest, rt->decimalSeparator);
515 tmpDest += decimalLength;
516 strcpy(tmpDest, nint + 1);
517 } else {
518 strcpy(tmpDest, nint);
519 }
520
521 if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
522 return cx->localeCallbacks->localeToUnicode(cx, buf, vp);
523
524 str = JS_NewString(cx, buf, size);
525 if (!str) {
526 cx->free(buf);
527 return JS_FALSE;
528 }
529
530 *vp = STRING_TO_JSVAL(str);
531 return JS_TRUE;
532 }
533
534 static JSBool
535 num_valueOf(JSContext *cx, uintN argc, jsval *vp)
536 {
537 jsval v;
538 JSObject *obj;
539
540 v = vp[1];
541 if (JSVAL_IS_NUMBER(v)) {
542 *vp = v;
543 return JS_TRUE;
544 }
545 obj = JS_THIS_OBJECT(cx, vp);
546 if (!JS_InstanceOf(cx, obj, &js_NumberClass, vp + 2))
547 return JS_FALSE;
548 *vp = obj->fslots[JSSLOT_PRIMITIVE_THIS];
549 return JS_TRUE;
550 }
551
552
553 #define MAX_PRECISION 100
554
555 static JSBool
556 num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode,
557 jsint precisionMin, jsint precisionMax, jsint precisionOffset,
558 uintN argc, jsval *vp)
559 {
560 jsval v;
561 jsdouble d, precision;
562 JSString *str;
563
564 /* Use MAX_PRECISION+1 because precisionOffset can be 1. */
565 char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)];
566 char *numStr;
567
568 if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v))
569 return JS_FALSE;
570 JS_ASSERT(JSVAL_IS_NUMBER(v));
571 d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
572
573 if (argc == 0) {
574 precision = 0.0;
575 oneArgMode = zeroArgMode;
576 } else {
577 precision = js_ValueToNumber(cx, &vp[2]);
578 if (JSVAL_IS_NULL(vp[2]))
579 return JS_FALSE;
580 precision = js_DoubleToInteger(precision);
581 if (precision < precisionMin || precision > precisionMax) {
582 numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, precision);
583 if (!numStr)
584 JS_ReportOutOfMemory(cx);
585 else
586 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
587 return JS_FALSE;
588 }
589 }
590
591 numStr = JS_dtostr(buf, sizeof buf, oneArgMode, (jsint)precision + precisionOffset, d);
592 if (!numStr) {
593 JS_ReportOutOfMemory(cx);
594 return JS_FALSE;
595 }
596 str = JS_NewStringCopyZ(cx, numStr);
597 if (!str)
598 return JS_FALSE;
599 *vp = STRING_TO_JSVAL(str);
600 return JS_TRUE;
601 }
602
603 /*
604 * In the following three implementations, we allow a larger range of precision
605 * than ECMA requires; this is permitted by ECMA-262.
606 */
607 static JSBool
608 num_toFixed(JSContext *cx, uintN argc, jsval *vp)
609 {
610 return num_to(cx, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0,
611 argc, vp);
612 }
613
614 static JSBool
615 num_toExponential(JSContext *cx, uintN argc, jsval *vp)
616 {
617 return num_to(cx, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0,
618 MAX_PRECISION, 1, argc, vp);
619 }
620
621 static JSBool
622 num_toPrecision(JSContext *cx, uintN argc, jsval *vp)
623 {
624 if (argc == 0 || JSVAL_IS_VOID(vp[2]))
625 return num_toString(cx, 0, vp);
626 return num_to(cx, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0,
627 argc, vp);
628 }
629
630 #ifdef JS_TRACER
631
632 JS_DEFINE_TRCINFO_1(num_toString,
633 (2, (extern, STRING_RETRY, js_NumberToString, CONTEXT, THIS_DOUBLE, 1, 1)))
634
635 #endif /* JS_TRACER */
636
637 static JSFunctionSpec number_methods[] = {
638 #if JS_HAS_TOSOURCE
639 JS_FN(js_toSource_str, num_toSource, 0,JSFUN_THISP_NUMBER),
640 #endif
641 JS_TN(js_toString_str, num_toString, 1,JSFUN_THISP_NUMBER, &num_toString_trcinfo),
642 JS_FN(js_toLocaleString_str, num_toLocaleString, 0,JSFUN_THISP_NUMBER),
643 JS_FN(js_valueOf_str, num_valueOf, 0,JSFUN_THISP_NUMBER),
644 JS_FN(js_toJSON_str, num_valueOf, 0,JSFUN_THISP_NUMBER),
645 JS_FN("toFixed", num_toFixed, 1,JSFUN_THISP_NUMBER),
646 JS_FN("toExponential", num_toExponential, 1,JSFUN_THISP_NUMBER),
647 JS_FN("toPrecision", num_toPrecision, 1,JSFUN_THISP_NUMBER),
648 JS_FS_END
649 };
650
651 /* NB: Keep this in synch with number_constants[]. */
652 enum nc_slot {
653 NC_NaN,
654 NC_POSITIVE_INFINITY,
655 NC_NEGATIVE_INFINITY,
656 NC_MAX_VALUE,
657 NC_MIN_VALUE,
658 NC_LIMIT
659 };
660
661 /*
662 * Some to most C compilers forbid spelling these at compile time, or barf
663 * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
664 * using union jsdpun.
665 */
666 static JSConstDoubleSpec number_constants[] = {
667 {0, js_NaN_str, 0,{0,0,0}},
668 {0, "POSITIVE_INFINITY", 0,{0,0,0}},
669 {0, "NEGATIVE_INFINITY", 0,{0,0,0}},
670 {1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}},
671 {0, "MIN_VALUE", 0,{0,0,0}},
672 {0,0,0,{0,0,0}}
673 };
674
675 jsdouble js_NaN;
676
677
678 #if (defined __GNUC__ && defined __i386__)
679
680 /*
681 * Set the exception mask to mask all exceptions and set the FPU precision
682 * to 53 bit mantissa (64 bit doubles).
683 */
684 inline void FIX_FPU() {
685 short control;
686 asm("fstcw %0" : "=m" (control) : );
687 control &= ~0x300; // Lower bits 8 and 9 (precision control).
688 control |= 0x2f3; // Raise bits 0-5 (exception masks) and 9 (64-bit precision).
689 asm("fldcw %0" : : "m" (control) );
690 }
691
692 #else
693
694 #define FIX_FPU() ((void)0)
695
696 #endif
697
698 JSBool
699 js_InitRuntimeNumberState(JSContext *cx)
700 {
701 JSRuntime *rt;
702 jsdpun u;
703 struct lconv *locale;
704
705 rt = cx->runtime;
706 JS_ASSERT(!rt->jsNaN);
707
708 FIX_FPU();
709
710 u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
711 u.s.lo = 0xffffffff;
712 number_constants[NC_NaN].dval = js_NaN = u.d;
713 rt->jsNaN = js_NewWeaklyRootedDouble(cx, js_NaN);
714 if (!rt->jsNaN)
715 return JS_FALSE;
716
717 u.s.hi = JSDOUBLE_HI32_EXPMASK;
718 u.s.lo = 0x00000000;
719 number_constants[NC_POSITIVE_INFINITY].dval = u.d;
720 rt->jsPositiveInfinity = js_NewWeaklyRootedDouble(cx, u.d);
721 if (!rt->jsPositiveInfinity)
722 return JS_FALSE;
723
724 u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
725 u.s.lo = 0x00000000;
726 number_constants[NC_NEGATIVE_INFINITY].dval = u.d;
727 rt->jsNegativeInfinity = js_NewWeaklyRootedDouble(cx, u.d);
728 if (!rt->jsNegativeInfinity)
729 return JS_FALSE;
730
731 u.s.hi = 0;
732 u.s.lo = 1;
733 number_constants[NC_MIN_VALUE].dval = u.d;
734
735 locale = localeconv();
736 rt->thousandsSeparator =
737 JS_strdup(cx, locale->thousands_sep ? locale->thousands_sep : "'");
738 rt->decimalSeparator =
739 JS_strdup(cx, locale->decimal_point ? locale->decimal_point : ".");
740 rt->numGrouping =
741 JS_strdup(cx, locale->grouping ? locale->grouping : "\3\0");
742
743 return rt->thousandsSeparator && rt->decimalSeparator && rt->numGrouping;
744 }
745
746 void
747 js_TraceRuntimeNumberState(JSTracer *trc)
748 {
749 JSRuntime *rt;
750
751 rt = trc->context->runtime;
752 if (rt->jsNaN)
753 JS_CALL_DOUBLE_TRACER(trc, rt->jsNaN, "NaN");
754 if (rt->jsPositiveInfinity)
755 JS_CALL_DOUBLE_TRACER(trc, rt->jsPositiveInfinity, "+Infinity");
756 if (rt->jsNegativeInfinity)
757 JS_CALL_DOUBLE_TRACER(trc, rt->jsNegativeInfinity, "-Infinity");
758 }
759
760 void
761 js_FinishRuntimeNumberState(JSContext *cx)
762 {
763 JSRuntime *rt = cx->runtime;
764
765 rt->jsNaN = NULL;
766 rt->jsNegativeInfinity = NULL;
767 rt->jsPositiveInfinity = NULL;
768
769 cx->free((void *)rt->thousandsSeparator);
770 cx->free((void *)rt->decimalSeparator);
771 cx->free((void *)rt->numGrouping);
772 rt->thousandsSeparator = rt->decimalSeparator = rt->numGrouping = NULL;
773 }
774
775 JSObject *
776 js_InitNumberClass(JSContext *cx, JSObject *obj)
777 {
778 JSObject *proto, *ctor;
779 JSRuntime *rt;
780
781 /* XXX must do at least once per new thread, so do it per JSContext... */
782 FIX_FPU();
783
784 if (!JS_DefineFunctions(cx, obj, number_functions))
785 return NULL;
786
787 proto = JS_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1,
788 NULL, number_methods, NULL, NULL);
789 if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
790 return NULL;
791 proto->fslots[JSSLOT_PRIMITIVE_THIS] = JSVAL_ZERO;
792 if (!JS_DefineConstDoubles(cx, ctor, number_constants))
793 return NULL;
794
795 /* ECMA 15.1.1.1 */
796 rt = cx->runtime;
797 if (!JS_DefineProperty(cx, obj, js_NaN_str, DOUBLE_TO_JSVAL(rt->jsNaN),
798 NULL, NULL, JSPROP_PERMANENT)) {
799 return NULL;
800 }
801
802 /* ECMA 15.1.1.2 */
803 if (!JS_DefineProperty(cx, obj, js_Infinity_str,
804 DOUBLE_TO_JSVAL(rt->jsPositiveInfinity),
805 NULL, NULL, JSPROP_PERMANENT)) {
806 return NULL;
807 }
808 return proto;
809 }
810
811 JSBool
812 js_NewNumberInRootedValue(JSContext *cx, jsdouble d, jsval *vp)
813 {
814 jsint i;
815
816 if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
817 *vp = INT_TO_JSVAL(i);
818 return JS_TRUE;
819 }
820 return js_NewDoubleInRootedValue(cx, d, vp);
821 }
822
823 JSBool
824 js_NewWeaklyRootedNumber(JSContext *cx, jsdouble d, jsval *rval)
825 {
826 jsint i;
827 if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
828 *rval = INT_TO_JSVAL(i);
829 return JS_TRUE;
830 }
831 return JS_NewDoubleValue(cx, d, rval);
832 }
833
834 /*
835 * Convert a number to C string. The buf must be large enough to accommodate
836 * the result, including '-' and '\0', if base == 10 or d is an integer that
837 * fits in 32 bits. The caller must free the resulting pointer if it does not
838 * point into buf.
839 */
840 static char *
841 NumberToCString(JSContext *cx, jsdouble d, jsint base, char *buf, size_t bufSize)
842 {
843 jsint i;
844 char *numStr;
845
846 JS_ASSERT(bufSize >= DTOSTR_STANDARD_BUFFER_SIZE);
847 if (JSDOUBLE_IS_INT(d, i)) {
848 numStr = IntToCString(i, base, buf, bufSize);
849 } else {
850 if (base == 10)
851 numStr = JS_dtostr(buf, bufSize, DTOSTR_STANDARD, 0, d);
852 else
853 numStr = JS_dtobasestr(base, d);
854 if (!numStr) {
855 JS_ReportOutOfMemory(cx);
856 return NULL;
857 }
858 }
859 return numStr;
860 }
861
862 static JSString *
863 NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
864 {
865 /*
866 * The longest possible result here that would need to fit in buf is
867 * (-0x80000000).toString(2), which has length 33. (This can produce
868 * longer results, but in those cases buf is not used; see comment at
869 * NumberToCString.)
870 */
871 char buf[34];
872 char *numStr;
873 JSString *s;
874
875 if (base < 2 || base > 36)
876 return NULL;
877 numStr = NumberToCString(cx, d, base, buf, sizeof buf);
878 if (!numStr)
879 return NULL;
880 s = JS_NewStringCopyZ(cx, numStr);
881 if (!(numStr >= buf && numStr < buf + sizeof buf))
882 js_free(numStr);
883 return s;
884 }
885
886 JSString * JS_FASTCALL
887 js_NumberToString(JSContext *cx, jsdouble d)
888 {
889 jsint i;
890
891 if (JSDOUBLE_IS_INT(d, i) && jsuint(i) < INT_STRING_LIMIT)
892 return JSString::intString(i);
893 return NumberToStringWithBase(cx, d, 10);
894 }
895
896 JSBool JS_FASTCALL
897 js_NumberValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb)
898 {
899 /* Convert to C-string. */
900 static const size_t arrSize = DTOSTR_STANDARD_BUFFER_SIZE;
901 char arr[arrSize];
902 const char *cstr;
903 if (JSVAL_IS_INT(v)) {
904 cstr = IntToCString(JSVAL_TO_INT(v), 10, arr, arrSize);
905 } else {
906 JS_ASSERT(JSVAL_IS_DOUBLE(v));
907 cstr = JS_dtostr(arr, arrSize, DTOSTR_STANDARD, 0, *JSVAL_TO_DOUBLE(v));
908 }
909 if (!cstr)
910 return JS_FALSE;
911
912 /*
913 * Inflate to jschar string. The input C-string characters are < 127, so
914 * even if jschars are UTF-8, all chars should map to one jschar.
915 */
916 size_t cstrlen = strlen(cstr);
917 JS_ASSERT(cstrlen < arrSize);
918 size_t sizeBefore = cb.length();
919 if (!cb.growBy(cstrlen))
920 return JS_FALSE;
921 jschar *appendBegin = cb.begin() + sizeBefore;
922 #ifdef DEBUG
923 size_t oldcstrlen = cstrlen;
924 JSBool ok =
925 #endif
926 js_InflateStringToBuffer(cx, cstr, cstrlen, appendBegin, &cstrlen);
927 JS_ASSERT(ok && cstrlen == oldcstrlen);
928 return JS_TRUE;
929 }
930
931 jsdouble
932 js_ValueToNumber(JSContext *cx, jsval *vp)
933 {
934 jsval v;
935 JSString *str;
936 const jschar *bp, *end, *ep;
937 jsdouble d, *dp;
938 JSObject *obj;
939
940 v = *vp;
941 for (;;) {
942 if (JSVAL_IS_INT(v))
943 return (jsdouble) JSVAL_TO_INT(v);
944 if (JSVAL_IS_DOUBLE(v))
945 return *JSVAL_TO_DOUBLE(v);
946 if (JSVAL_IS_STRING(v)) {
947 str = JSVAL_TO_STRING(v);
948
949 /*
950 * Note that ECMA doesn't treat a string beginning with a '0' as
951 * an octal number here. This works because all such numbers will
952 * be interpreted as decimal by js_strtod and will never get
953 * passed to js_strtointeger (which would interpret them as
954 * octal).
955 */
956 str->getCharsAndEnd(bp, end);
957
958 /* ECMA doesn't allow signed hex numbers (bug 273467). */
959 bp = js_SkipWhiteSpace(bp, end);
960 if (bp + 2 < end && (*bp == '-' || *bp == '+') &&
961 bp[1] == '0' && (bp[2] == 'X' || bp[2] == 'x')) {
962 break;
963 }
964
965 if ((!js_strtod(cx, bp, end, &ep, &d) ||
966 js_SkipWhiteSpace(ep, end) != end) &&
967 (!js_strtointeger(cx, bp, end, &ep, 0, &d) ||
968 js_SkipWhiteSpace(ep, end) != end)) {
969 break;
970 }
971
972 /*
973 * JSVAL_TRUE indicates that double jsval was never constructed
974 * for the result.
975 */
976 *vp = JSVAL_TRUE;
977 return d;
978 }
979 if (JSVAL_IS_BOOLEAN(v)) {
980 if (JSVAL_TO_BOOLEAN(v)) {
981 *vp = JSVAL_ONE;
982 return 1.0;
983 } else {
984 *vp = JSVAL_ZERO;
985 return 0.0;
986 }
987 }
988 if (JSVAL_IS_NULL(v)) {
989 *vp = JSVAL_ZERO;
990 return 0.0;
991 }
992 if (JSVAL_IS_VOID(v))
993 break;
994
995 JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
996 obj = JSVAL_TO_OBJECT(v);
997
998 /*
999 * vp roots obj so we cannot use it as an extra root for
1000 * obj->defaultValue result when calling the hook.
1001 */
1002 JSAutoTempValueRooter tvr(cx, v);
1003 if (!obj->defaultValue(cx, JSTYPE_NUMBER, tvr.addr()))
1004 obj = NULL;
1005 else
1006 v = *vp = tvr.value();
1007 if (!obj) {
1008 *vp = JSVAL_NULL;
1009 return 0.0;
1010 }
1011 if (!JSVAL_IS_PRIMITIVE(v))
1012 break;
1013 }
1014
1015 dp = cx->runtime->jsNaN;
1016 *vp = DOUBLE_TO_JSVAL(dp);
1017 return *dp;
1018 }
1019
1020 int32
1021 js_ValueToECMAInt32(JSContext *cx, jsval *vp)
1022 {
1023 jsval v;
1024 jsdouble d;
1025
1026 v = *vp;
1027 if (JSVAL_IS_INT(v))
1028 return JSVAL_TO_INT(v);
1029 if (JSVAL_IS_DOUBLE(v)) {
1030 d = *JSVAL_TO_DOUBLE(v);
1031 *vp = JSVAL_TRUE;
1032 } else {
1033 d = js_ValueToNumber(cx, vp);
1034 if (JSVAL_IS_NULL(*vp))
1035 return 0;
1036 *vp = JSVAL_TRUE;
1037 }
1038 return js_DoubleToECMAInt32(d);
1039 }
1040
1041 uint32
1042 js_ValueToECMAUint32(JSContext *cx, jsval *vp)
1043 {
1044 jsval v;
1045 jsint i;
1046 jsdouble d;
1047
1048 v = *vp;
1049 if (JSVAL_IS_INT(v)) {
1050 i = JSVAL_TO_INT(v);
1051 if (i < 0)
1052 *vp = JSVAL_TRUE;
1053 return (uint32) i;
1054 }
1055 if (JSVAL_IS_DOUBLE(v)) {
1056 d = *JSVAL_TO_DOUBLE(v);
1057 *vp = JSVAL_TRUE;
1058 } else {
1059 d = js_ValueToNumber(cx, vp);
1060 if (JSVAL_IS_NULL(*vp))
1061 return 0;
1062 *vp = JSVAL_TRUE;
1063 }
1064 return js_DoubleToECMAUint32(d);
1065 }
1066
1067 uint32
1068 js_DoubleToECMAUint32(jsdouble d)
1069 {
1070 int32 i;
1071 JSBool neg;
1072 jsdouble two32;
1073
1074 if (!JSDOUBLE_IS_FINITE(d))
1075 return 0;
1076
1077 /*
1078 * We check whether d fits int32, not uint32, as all but the ">>>" bit
1079 * manipulation bytecode stores the result as int, not uint. When the
1080 * result does not fit int jsval, it will be stored as a negative double.
1081 */
1082 i = (int32) d;
1083 if ((jsdouble) i == d)
1084 return (int32)i;
1085
1086 neg = (d < 0);
1087 d = floor(neg ? -d : d);
1088 d = neg ? -d : d;
1089
1090 two32 = 4294967296.0;
1091 d = fmod(d, two32);
1092
1093 return (uint32) (d >= 0 ? d : d + two32);
1094 }
1095
1096 int32
1097 js_ValueToInt32(JSContext *cx, jsval *vp)
1098 {
1099 jsval v;
1100 jsdouble d;
1101
1102 v = *vp;
1103 if (JSVAL_IS_INT(v))
1104 return JSVAL_TO_INT(v);
1105 d = js_ValueToNumber(cx, vp);
1106 if (JSVAL_IS_NULL(*vp))
1107 return 0;
1108 if (JSVAL_IS_INT(*vp))
1109 return JSVAL_TO_INT(*vp);
1110
1111 *vp = JSVAL_TRUE;
1112 if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
1113 js_ReportValueError(cx, JSMSG_CANT_CONVERT,
1114 JSDVG_SEARCH_STACK, v, NULL);
1115 *vp = JSVAL_NULL;
1116 return 0;
1117 }
1118 return (int32) floor(d + 0.5); /* Round to nearest */
1119 }
1120
1121 uint16
1122 js_ValueToUint16(JSContext *cx, jsval *vp)
1123 {
1124 jsdouble d;
1125 uint16 u;
1126 jsuint m;
1127 JSBool neg;
1128
1129 d = js_ValueToNumber(cx, vp);
1130 if (JSVAL_IS_NULL(*vp))
1131 return 0;
1132
1133 if (JSVAL_IS_INT(*vp)) {
1134 u = (uint16) JSVAL_TO_INT(*vp);
1135 } else if (d == 0 || !JSDOUBLE_IS_FINITE(d)) {
1136 u = (uint16) 0;
1137 } else {
1138 u = (uint16) d;
1139 if ((jsdouble) u != d) {
1140 neg = (d < 0);
1141 d = floor(neg ? -d : d);
1142 d = neg ? -d : d;
1143 m = JS_BIT(16);
1144 d = fmod(d, (double) m);
1145 if (d < 0)
1146 d += m;
1147 u = (uint16) d;
1148 }
1149 }
1150 *vp = INT_TO_JSVAL(u);
1151 return u;
1152 }
1153
1154 JSBool
1155 js_strtod(JSContext *cx, const jschar *s, const jschar *send,
1156 const jschar **ep, jsdouble *dp)
1157 {
1158 const jschar *s1;
1159 size_t length, i;
1160 char cbuf[32];
1161 char *cstr, *istr, *estr;
1162 JSBool negative;
1163 jsdouble d;
1164
1165 s1 = js_SkipWhiteSpace(s, send);
1166 length = send - s1;
1167
1168 /* Use cbuf to avoid malloc */
1169 if (length >= sizeof cbuf) {
1170 cstr = (char *) cx->malloc(length + 1);
1171 if (!cstr)
1172 return JS_FALSE;
1173 } else {
1174 cstr = cbuf;
1175 }
1176
1177 for (i = 0; i != length; i++) {
1178 if (s1[i] >> 8)
1179 break;
1180 cstr[i] = (char)s1[i];
1181 }
1182 cstr[i] = 0;
1183
1184 istr = cstr;
1185 if ((negative = (*istr == '-')) != 0 || *istr == '+')
1186 istr++;
1187 if (*istr == 'I' && !strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
1188 d = *(negative ? cx->runtime->jsNegativeInfinity : cx->runtime->jsPositiveInfinity);
1189 estr = istr + 8;
1190 } else {
1191 int err;
1192 d = JS_strtod(cstr, &estr, &err);
1193 if (d == HUGE_VAL)
1194 d = *cx->runtime->jsPositiveInfinity;
1195 else if (d == -HUGE_VAL)
1196 d = *cx->runtime->jsNegativeInfinity;
1197 }
1198
1199 i = estr - cstr;
1200 if (cstr != cbuf)
1201 cx->free(cstr);
1202 *ep = i ? s1 + i : s;
1203 *dp = d;
1204 return JS_TRUE;
1205 }
1206
1207 struct BinaryDigitReader
1208 {
1209 uintN base; /* Base of number; must be a power of 2 */
1210 uintN digit; /* Current digit value in radix given by base */
1211 uintN digitMask; /* Mask to extract the next bit from digit */
1212 const jschar *digits; /* Pointer to the remaining digits */
1213 const jschar *end; /* Pointer to first non-digit */
1214 };
1215
1216 /* Return the next binary digit from the number or -1 if done */
1217 static intN GetNextBinaryDigit(struct BinaryDigitReader *bdr)
1218 {
1219 intN bit;
1220
1221 if (bdr->digitMask == 0) {
1222 uintN c;
1223
1224 if (bdr->digits == bdr->end)
1225 return -1;
1226
1227 c = *bdr->digits++;
1228 if ('0' <= c && c <= '9')
1229 bdr->digit = c - '0';
1230 else if ('a' <= c && c <= 'z')
1231 bdr->digit = c - 'a' + 10;
1232 else
1233 bdr->digit = c - 'A' + 10;
1234 bdr->digitMask = bdr->base >> 1;
1235 }
1236 bit = (bdr->digit & bdr->digitMask) != 0;
1237 bdr->digitMask >>= 1;
1238 return bit;
1239 }
1240
1241 JSBool
1242 js_strtointeger(JSContext *cx, const jschar *s, const jschar *send,
1243 const jschar **ep, jsint base, jsdouble *dp)
1244 {
1245 const jschar *s1, *start;
1246 JSBool negative;
1247 jsdouble value;
1248
1249 s1 = js_SkipWhiteSpace(s, send);
1250 if (s1 == send)
1251 goto no_digits;
1252 if ((negative = (*s1 == '-')) != 0 || *s1 == '+') {
1253 s1++;
1254 if (s1 == send)
1255 goto no_digits;
1256 }
1257
1258 if (base == 0) {
1259 /* No base supplied, or some base that evaluated to 0. */
1260 if (*s1 == '0') {
1261 /* It's either hex or octal; only increment char if str isn't '0' */
1262 if (s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) {
1263 base = 16;
1264 s1 += 2;
1265 if (s1 == send)
1266 goto no_digits;
1267 } else {
1268 base = 8;
1269 }
1270 } else {
1271 base = 10; /* Default to decimal. */
1272 }
1273 } else if (base == 16) {
1274 /* If base is 16, ignore hex prefix. */
1275 if (*s1 == '0' && s1 + 1 != send && (s1[1] == 'X' || s1[1] == 'x')) {
1276 s1 += 2;
1277 if (s1 == send)
1278 goto no_digits;
1279 }
1280 }
1281
1282 /*
1283 * Done with the preliminaries; find some prefix of the string that's
1284 * a number in the given base.
1285 */
1286 JS_ASSERT(s1 < send);
1287 start = s1;
1288 value = 0.0;
1289 do {
1290 uintN digit;
1291 jschar c = *s1;
1292 if ('0' <= c && c <= '9')
1293 digit = c - '0';
1294 else if ('a' <= c && c <= 'z')
1295 digit = c - 'a' + 10;
1296 else if ('A' <= c && c <= 'Z')
1297 digit = c - 'A' + 10;
1298 else
1299 break;
1300 if (digit >= (uintN)base)
1301 break;
1302 value = value * base + digit;
1303 } while (++s1 != send);
1304
1305 if (value >= 9007199254740992.0) {
1306 if (base == 10) {
1307 /*
1308 * If we're accumulating a decimal number and the number is >=
1309 * 2^53, then the result from the repeated multiply-add above may
1310 * be inaccurate. Call JS_strtod to get the correct answer.
1311 */
1312 size_t i;
1313 size_t length = s1 - start;
1314 char *cstr = (char *) cx->malloc(length + 1);
1315 char *estr;
1316 int err=0;
1317
1318 if (!cstr)
1319 return JS_FALSE;
1320 for (i = 0; i != length; i++)
1321 cstr[i] = (char)start[i];
1322 cstr[length] = 0;
1323
1324 value = JS_strtod(cstr, &estr, &err);
1325 if (err == JS_DTOA_ENOMEM) {
1326 JS_ReportOutOfMemory(cx);
1327 cx->free(cstr);
1328 return JS_FALSE;
1329 }
1330 if (err == JS_DTOA_ERANGE && value == HUGE_VAL)
1331 value = *cx->runtime->jsPositiveInfinity;
1332 cx->free(cstr);
1333 } else if ((base & (base - 1)) == 0) {
1334 /*
1335 * The number may also be inaccurate for power-of-two bases. This
1336 * happens if the addition in value * base + digit causes a round-
1337 * down to an even least significant mantissa bit when the first
1338 * dropped bit is a one. If any of the following digits in the
1339 * number (which haven't been added in yet) are nonzero, then the
1340 * correct action would have been to round up instead of down. An
1341 * example occurs when reading the number 0x1000000000000081, which
1342 * rounds to 0x1000000000000000 instead of 0x1000000000000100.
1343 */
1344 struct BinaryDigitReader bdr;
1345 intN bit, bit2;
1346 intN j;
1347
1348 bdr.base = base;
1349 bdr.digitMask = 0;
1350 bdr.digits = start;
1351 bdr.end = s1;
1352 value = 0.0;
1353
1354 /* Skip leading zeros. */
1355 do {
1356 bit = GetNextBinaryDigit(&bdr);
1357 } while (bit == 0);
1358
1359 if (bit == 1) {
1360 /* Gather the 53 significant bits (including the leading 1) */
1361 value = 1.0;
1362 for (j = 52; j; j--) {
1363 bit = GetNextBinaryDigit(&bdr);
1364 if (bit < 0)
1365 goto done;
1366 value = value*2 + bit;
1367 }
1368 /* bit2 is the 54th bit (the first dropped from the mantissa) */
1369 bit2 = GetNextBinaryDigit(&bdr);
1370 if (bit2 >= 0) {
1371 jsdouble factor = 2.0;
1372 intN sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */
1373 intN bit3;
1374
1375 while ((bit3 = GetNextBinaryDigit(&bdr)) >= 0) {
1376 sticky |= bit3;
1377 factor *= 2;
1378 }
1379 value += bit2 & (bit | sticky);
1380 value *= factor;
1381 }
1382 done:;
1383 }
1384 }
1385 }
1386 /* We don't worry about inaccurate numbers for any other base. */
1387
1388 if (s1 == start) {
1389 no_digits:
1390 *dp = 0.0;
1391 *ep = s;
1392 } else {
1393 *dp = negative ? -value : value;
1394 *ep = s1;
1395 }
1396 return JS_TRUE;
1397 }

  ViewVC Help
Powered by ViewVC 1.1.24