PageRenderTime 248ms CodeModel.GetById 121ms app.highlight 114ms RepoModel.GetById 1ms app.codeStats 0ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsnum.cpp

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