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