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

Annotation of /trunk/js/jsnum.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

1 siliconforks 507 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 siliconforks 332 *
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 siliconforks 507 #define __STDC_LIMIT_MACROS
42    
43 siliconforks 332 /*
44     * JS number type and wrapper class.
45     */
46 siliconforks 460 #ifdef XP_OS2
47     #define _PC_53 PC_53
48     #define _MCW_EM MCW_EM
49     #define _MCW_PC MCW_PC
50     #endif
51 siliconforks 332 #include <locale.h>
52     #include <limits.h>
53     #include <math.h>
54     #include <stdlib.h>
55     #include <string.h>
56     #include "jstypes.h"
57 siliconforks 507 #include "jsstdint.h"
58 siliconforks 332 #include "jsutil.h" /* Added by JSIFY */
59     #include "jsapi.h"
60     #include "jsatom.h"
61 siliconforks 399 #include "jsbuiltins.h"
62 siliconforks 332 #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 siliconforks 507 #include "jsstrinlines.h"
74     #include "jsvector.h"
75 siliconforks 332
76 siliconforks 507
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 siliconforks 332 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 siliconforks 399 static JSBool
137     num_parseFloat(JSContext *cx, uintN argc, jsval *vp)
138 siliconforks 332 {
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 siliconforks 507 str->getCharsAndEnd(bp, end);
151 siliconforks 332 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 siliconforks 399 #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 siliconforks 507 str->getCharsAndEnd(bp, end);
170 siliconforks 399 if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp)
171     return js_NaN;
172     return d;
173     }
174     #endif
175    
176 siliconforks 332 /* See ECMA 15.1.2.2. */
177 siliconforks 399 static JSBool
178     num_parseInt(JSContext *cx, uintN argc, jsval *vp)
179 siliconforks 332 {
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 siliconforks 507 str->getCharsAndEnd(bp, end);
210 siliconforks 332 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 siliconforks 399 #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 siliconforks 507 str->getCharsAndEnd(bp, end);
229 siliconforks 399 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 siliconforks 507 if (d > 0)
240     return floor(d);
241     if (d < 0)
242     return -floor(-d);
243     return 0;
244 siliconforks 399 }
245     #endif
246    
247 siliconforks 332 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 siliconforks 399 #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 siliconforks 332 static JSFunctionSpec number_functions[] = {
266 siliconforks 399 JS_FN(js_isNaN_str, num_isNaN, 1,0),
267     JS_FN(js_isFinite_str, num_isFinite, 1,0),
268 siliconforks 507 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 siliconforks 332 JS_FS_END
271     };
272    
273     JSClass js_NumberClass = {
274     js_Number_str,
275 siliconforks 507 JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
276 siliconforks 332 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
277 siliconforks 507 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL,
278 siliconforks 332 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 siliconforks 507 if (!JS_IsConstructing(cx))
303 siliconforks 332 *rval = v;
304 siliconforks 507 else
305     obj->fslots[JSSLOT_PRIMITIVE_THIS] = v;
306     return true;
307 siliconforks 332 }
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 siliconforks 460 static char *
339     IntToCString(jsint i, jsint base, char *buf, size_t bufSize)
340 siliconforks 332 {
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 siliconforks 399 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 siliconforks 332 if (i < 0)
378     *--cp = '-';
379    
380     JS_ASSERT(cp >= buf);
381     return cp;
382     }
383    
384 siliconforks 399 static JSBool
385     num_toString(JSContext *cx, uintN argc, jsval *vp)
386 siliconforks 332 {
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 siliconforks 460 char *numStr = IntToCString(base, 10, numBuf, sizeof numBuf);
404 siliconforks 332 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 siliconforks 507 js_free(dStr);
419 siliconforks 332 }
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 siliconforks 399 if (!num_toString(cx, 0, vp))
443 siliconforks 332 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 siliconforks 507 buf = (char *)cx->malloc(size + 1);
495 siliconforks 332 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 siliconforks 507 cx->free(buf);
527 siliconforks 332 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 siliconforks 507 *vp = obj->fslots[JSSLOT_PRIMITIVE_THIS];
549 siliconforks 332 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 siliconforks 399 return num_toString(cx, 0, vp);
626 siliconforks 332 return num_to(cx, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0,
627     argc, vp);
628     }
629    
630 siliconforks 399 #ifdef JS_TRACER
631    
632 siliconforks 507 JS_DEFINE_TRCINFO_1(num_toString,
633     (2, (extern, STRING_RETRY, js_NumberToString, CONTEXT, THIS_DOUBLE, 1, 1)))
634 siliconforks 399
635     #endif /* JS_TRACER */
636    
637 siliconforks 332 static JSFunctionSpec number_methods[] = {
638     #if JS_HAS_TOSOURCE
639 siliconforks 399 JS_FN(js_toSource_str, num_toSource, 0,JSFUN_THISP_NUMBER),
640 siliconforks 332 #endif
641 siliconforks 507 JS_TN(js_toString_str, num_toString, 1,JSFUN_THISP_NUMBER, &num_toString_trcinfo),
642 siliconforks 399 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 siliconforks 332 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 siliconforks 507 #if (defined __GNUC__ && defined __i386__)
679    
680 siliconforks 332 /*
681     * Set the exception mask to mask all exceptions and set the FPU precision
682 siliconforks 507 * to 53 bit mantissa (64 bit doubles).
683 siliconforks 332 */
684 siliconforks 507 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 siliconforks 332
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 siliconforks 507 cx->free((void *)rt->thousandsSeparator);
770     cx->free((void *)rt->decimalSeparator);
771     cx->free((void *)rt->numGrouping);
772 siliconforks 332 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 siliconforks 507 proto->fslots[JSSLOT_PRIMITIVE_THIS] = JSVAL_ZERO;
792 siliconforks 332 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 siliconforks 460 JSBool
824     js_NewWeaklyRootedNumber(JSContext *cx, jsdouble d, jsval *rval)
825 siliconforks 332 {
826     jsint i;
827 siliconforks 460 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 siliconforks 332 char *numStr;
845    
846     JS_ASSERT(bufSize >= DTOSTR_STANDARD_BUFFER_SIZE);
847     if (JSDOUBLE_IS_INT(d, i)) {
848 siliconforks 460 numStr = IntToCString(i, base, buf, bufSize);
849 siliconforks 332 } else {
850 siliconforks 399 if (base == 10)
851     numStr = JS_dtostr(buf, bufSize, DTOSTR_STANDARD, 0, d);
852     else
853     numStr = JS_dtobasestr(base, d);
854 siliconforks 332 if (!numStr) {
855     JS_ReportOutOfMemory(cx);
856     return NULL;
857     }
858     }
859     return numStr;
860     }
861    
862 siliconforks 507 static JSString *
863 siliconforks 399 NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
864 siliconforks 332 {
865 siliconforks 460 /*
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 siliconforks 332 char *numStr;
873 siliconforks 460 JSString *s;
874 siliconforks 332
875 siliconforks 399 if (base < 2 || base > 36)
876     return NULL;
877 siliconforks 460 numStr = NumberToCString(cx, d, base, buf, sizeof buf);
878 siliconforks 332 if (!numStr)
879     return NULL;
880 siliconforks 460 s = JS_NewStringCopyZ(cx, numStr);
881     if (!(numStr >= buf && numStr < buf + sizeof buf))
882 siliconforks 507 js_free(numStr);
883 siliconforks 460 return s;
884 siliconforks 332 }
885    
886 siliconforks 399 JSString * JS_FASTCALL
887     js_NumberToString(JSContext *cx, jsdouble d)
888     {
889 siliconforks 507 jsint i;
890    
891     if (JSDOUBLE_IS_INT(d, i) && jsuint(i) < INT_STRING_LIMIT)
892     return JSString::intString(i);
893 siliconforks 399 return NumberToStringWithBase(cx, d, 10);
894     }
895    
896 siliconforks 507 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 siliconforks 332 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 siliconforks 507 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 siliconforks 332 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 siliconforks 507 * obj->defaultValue result when calling the hook.
1001 siliconforks 332 */
1002 siliconforks 507 JSAutoTempValueRooter tvr(cx, v);
1003     if (!obj->defaultValue(cx, JSTYPE_NUMBER, tvr.addr()))
1004 siliconforks 332 obj = NULL;
1005     else
1006 siliconforks 507 v = *vp = tvr.value();
1007 siliconforks 332 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 siliconforks 507 cstr = (char *) cx->malloc(length + 1);
1171 siliconforks 332 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 siliconforks 507 if (*istr == 'I' && !strncmp(istr, js_Infinity_str, sizeof js_Infinity_str - 1)) {
1188 siliconforks 332 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 siliconforks 507 cx->free(cstr);
1202 siliconforks 332 *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 siliconforks 507 else
1233     bdr->digit = c - 'A' + 10;
1234 siliconforks 332 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 siliconforks 507 char *cstr = (char *) cx->malloc(length + 1);
1315 siliconforks 332 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 siliconforks 507 cx->free(cstr);
1328 siliconforks 332 return JS_FALSE;
1329     }
1330     if (err == JS_DTOA_ERANGE && value == HUGE_VAL)
1331     value = *cx->runtime->jsPositiveInfinity;
1332 siliconforks 507 cx->free(cstr);
1333 siliconforks 332 } 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