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

Annotation of /trunk/js/jsnum.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 460 - (hide annotations)
Sat Sep 26 23:15:22 2009 UTC (11 years ago) by siliconforks
File size: 37768 byte(s)
Upgrade to SpiderMonkey from Firefox 3.5.3.

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

  ViewVC Help
Powered by ViewVC 1.1.24