Bug 509857 - Get rid of DTOA_LOCK. r=jwalden.

--HG--
extra : rebase_source : bec4d9441aa2af8488a04aa8604a65b7387cda6d
This commit is contained in:
Jason Orendorff 2010-03-22 18:21:10 -05:00
parent 3e1a930003
commit 60d5805e46
10 changed files with 323 additions and 262 deletions

View File

@ -101,9 +101,10 @@
* directly -- and assumed always to succeed. Similarly, if you
* want something other than the system's free() to be called to
* recycle memory acquired from MALLOC, #define FREE to be the
* name of the alternate routine. (FREE or free is only called in
* pathological cases, e.g., in a dtoa call after a dtoa return in
* mode 3 with thousands of digits requested.)
* name of the alternate routine. (Unless you #define
* NO_GLOBAL_STATE and call destroydtoa, FREE or free is only
* called in pathological cases, e.g., in a dtoa call after a dtoa
* return in mode 3 with thousands of digits requested.)
* #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
* memory allocations from a private pool of memory when possible.
* When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes,
@ -164,6 +165,12 @@
* inexact or when it is a numeric value rounded to +-infinity).
* #define NO_ERRNO if strtod should not assign errno = ERANGE when
* the result overflows to +-Infinity or underflows to 0.
* #define NO_GLOBAL_STATE to avoid defining any non-const global or
* static variables. Instead the necessary state is stored in an
* opaque struct, DtoaState, a pointer to which must be passed to
* every entry point. Two new functions are added to the API:
* DtoaState *newdtoa(void);
* void destroydtoa(DtoaState *);
*/
#ifndef Long
@ -195,12 +202,15 @@ extern void *MALLOC(size_t);
#define MALLOC malloc
#endif
#ifndef FREE
#define FREE free
#endif
#ifndef Omit_Private_Memory
#ifndef PRIVATE_MEM
#define PRIVATE_MEM 2304
#endif
#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
#endif
#undef IEEE_Arith
@ -479,14 +489,87 @@ Bigint {
typedef struct Bigint Bigint;
static Bigint *freelist[Kmax+1];
#ifdef NO_GLOBAL_STATE
#ifdef MULTIPLE_THREADS
#error "cannot have both NO_GLOBAL_STATE and MULTIPLE_THREADS"
#endif
struct
DtoaState {
#define DECLARE_GLOBAL_STATE /* nothing */
#else
#define DECLARE_GLOBAL_STATE static
#endif
DECLARE_GLOBAL_STATE Bigint *freelist[Kmax+1];
DECLARE_GLOBAL_STATE Bigint *p5s;
#ifndef Omit_Private_Memory
DECLARE_GLOBAL_STATE double private_mem[PRIVATE_mem];
DECLARE_GLOBAL_STATE double *pmem_next
#ifndef NO_GLOBAL_STATE
= private_mem
#endif
;
#endif
#ifdef NO_GLOBAL_STATE
};
typedef struct DtoaState DtoaState;
#ifdef KR_headers
#define STATE_PARAM state,
#define STATE_PARAM_DECL DtoaState *state;
#else
#define STATE_PARAM DtoaState *state,
#endif
#define PASS_STATE state,
#define GET_STATE(field) (state->field)
static DtoaState *
newdtoa(void)
{
DtoaState *state = (DtoaState *) MALLOC(sizeof(DtoaState));
if (state) {
memset(state, 0, sizeof(DtoaState));
state->pmem_next = state->private_mem;
}
return state;
}
static void
destroydtoa
#ifdef KR_headers
(state) STATE_PARAM_DECL
#else
(DtoaState *state)
#endif
{
int i;
Bigint *v, *next;
for (i = 0; i <= Kmax; i++) {
for (v = GET_STATE(freelist)[i]; v; v = next) {
next = v->next;
#ifndef Omit_Private_Memory
if ((double*)v < GET_STATE(private_mem) ||
(double*)v >= GET_STATE(private_mem) + PRIVATE_mem)
#endif
FREE((void*)v);
}
}
FREE((void *)state);
}
#else
#define STATE_PARAM /* nothing */
#define STATE_PARAM_DECL /* nothing */
#define PASS_STATE /* nothing */
#define GET_STATE(name) name
#endif
static Bigint *
Balloc
#ifdef KR_headers
(k) int k;
(STATE_PARAM k) STATE_PARAM_DECL int k;
#else
(int k)
(STATE_PARAM int k)
#endif
{
int x;
@ -498,8 +581,8 @@ Balloc
ACQUIRE_DTOA_LOCK(0);
/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
/* but this case seems very unlikely. */
if (k <= Kmax && (rv = freelist[k]))
freelist[k] = rv->next;
if (k <= Kmax && (rv = GET_STATE(freelist)[k]))
GET_STATE(freelist)[k] = rv->next;
else {
x = 1 << k;
#ifdef Omit_Private_Memory
@ -507,9 +590,9 @@ Balloc
#else
len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
/sizeof(double);
if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
rv = (Bigint*)pmem_next;
pmem_next += len;
if (k <= Kmax && GET_STATE(pmem_next) - GET_STATE(private_mem) + len <= PRIVATE_mem) {
rv = (Bigint*)GET_STATE(pmem_next);
GET_STATE(pmem_next) += len;
}
else
rv = (Bigint*)MALLOC(len*sizeof(double));
@ -525,22 +608,18 @@ Balloc
static void
Bfree
#ifdef KR_headers
(v) Bigint *v;
(STATE_PARAM v) STATE_PARAM_DECL Bigint *v;
#else
(Bigint *v)
(STATE_PARAM Bigint *v)
#endif
{
if (v) {
if (v->k > Kmax)
#ifdef FREE
FREE((void*)v);
#else
free((void*)v);
#endif
else {
ACQUIRE_DTOA_LOCK(0);
v->next = freelist[v->k];
freelist[v->k] = v;
v->next = GET_STATE(freelist)[v->k];
GET_STATE(freelist)[v->k] = v;
FREE_DTOA_LOCK(0);
}
}
@ -552,9 +631,9 @@ y->wds*sizeof(Long) + 2*sizeof(int))
static Bigint *
multadd
#ifdef KR_headers
(b, m, a) Bigint *b; int m, a;
(STATE_PARAM b, m, a) STATE_PARAM_DECL Bigint *b; int m, a;
#else
(Bigint *b, int m, int a) /* multiply by m and add a */
(STATE_PARAM Bigint *b, int m, int a) /* multiply by m and add a */
#endif
{
int i, wds;
@ -595,9 +674,9 @@ multadd
while(++i < wds);
if (carry) {
if (wds >= b->maxwds) {
b1 = Balloc(b->k+1);
b1 = Balloc(PASS_STATE b->k+1);
Bcopy(b1, b);
Bfree(b);
Bfree(PASS_STATE b);
b = b1;
}
b->x[wds++] = (ULong) carry;
@ -609,9 +688,9 @@ multadd
static Bigint *
s2b
#ifdef KR_headers
(s, nd0, nd, y9) CONST char *s; int nd0, nd; ULong y9;
(STATE_PARAM s, nd0, nd, y9) STATE_PARAM_DECL CONST char *s; int nd0, nd; ULong y9;
#else
(CONST char *s, int nd0, int nd, ULong y9)
(STATE_PARAM CONST char *s, int nd0, int nd, ULong y9)
#endif
{
Bigint *b;
@ -621,11 +700,11 @@ s2b
x = (nd + 8) / 9;
for(k = 0, y = 1; x > y; y <<= 1, k++) ;
#ifdef Pack_32
b = Balloc(k);
b = Balloc(PASS_STATE k);
b->x[0] = y9;
b->wds = 1;
#else
b = Balloc(k+1);
b = Balloc(PASS_STATE k+1);
b->x[0] = y9 & 0xffff;
b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
#endif
@ -633,14 +712,14 @@ s2b
i = 9;
if (9 < nd0) {
s += 9;
do b = multadd(b, 10, *s++ - '0');
do b = multadd(PASS_STATE b, 10, *s++ - '0');
while(++i < nd0);
s++;
}
else
s += 10;
for(; i < nd; i++)
b = multadd(b, 10, *s++ - '0');
b = multadd(PASS_STATE b, 10, *s++ - '0');
return b;
}
@ -729,14 +808,14 @@ lo0bits
static Bigint *
i2b
#ifdef KR_headers
(i) int i;
(STATE_PARAM i) STATE_PARAM_DECL int i;
#else
(int i)
(STATE_PARAM int i)
#endif
{
Bigint *b;
b = Balloc(1);
b = Balloc(PASS_STATE 1);
b->x[0] = i;
b->wds = 1;
return b;
@ -745,9 +824,9 @@ i2b
static Bigint *
mult
#ifdef KR_headers
(a, b) Bigint *a, *b;
(STATE_PARAM a, b) STATE_PARAM_DECL Bigint *a, *b;
#else
(Bigint *a, Bigint *b)
(STATE_PARAM Bigint *a, Bigint *b)
#endif
{
Bigint *c;
@ -774,7 +853,7 @@ mult
wc = wa + wb;
if (wc > a->maxwds)
k++;
c = Balloc(k);
c = Balloc(PASS_STATE k);
for(x = c->x, xa = x + wc; x < xa; x++)
*x = 0;
xa = a->x;
@ -852,26 +931,24 @@ mult
return c;
}
static Bigint *p5s;
static Bigint *
pow5mult
#ifdef KR_headers
(b, k) Bigint *b; int k;
(STATE_PARAM b, k) STATE_PARAM_DECL Bigint *b; int k;
#else
(Bigint *b, int k)
(STATE_PARAM Bigint *b, int k)
#endif
{
Bigint *b1, *p5, *p51;
int i;
static int p05[3] = { 5, 25, 125 };
static CONST int p05[3] = { 5, 25, 125 };
if ((i = k & 3))
b = multadd(b, p05[i-1], 0);
b = multadd(PASS_STATE b, p05[i-1], 0);
if (!(k >>= 2))
return b;
if (!(p5 = p5s)) {
if (!(p5 = GET_STATE(p5s))) {
/* first time */
#ifdef MULTIPLE_THREADS
ACQUIRE_DTOA_LOCK(1);
@ -881,14 +958,14 @@ pow5mult
}
FREE_DTOA_LOCK(1);
#else
p5 = p5s = i2b(625);
p5 = GET_STATE(p5s) = i2b(PASS_STATE 625);
p5->next = 0;
#endif
}
for(;;) {
if (k & 1) {
b1 = mult(b, p5);
Bfree(b);
b1 = mult(PASS_STATE b, p5);
Bfree(PASS_STATE b);
b = b1;
}
if (!(k >>= 1))
@ -902,7 +979,7 @@ pow5mult
}
FREE_DTOA_LOCK(1);
#else
p51 = p5->next = mult(p5,p5);
p51 = p5->next = mult(PASS_STATE p5,p5);
p51->next = 0;
#endif
}
@ -914,9 +991,9 @@ pow5mult
static Bigint *
lshift
#ifdef KR_headers
(b, k) Bigint *b; int k;
(STATE_PARAM b, k) STATE_PARAM_DECL Bigint *b; int k;
#else
(Bigint *b, int k)
(STATE_PARAM Bigint *b, int k)
#endif
{
int i, k1, n, n1;
@ -932,7 +1009,7 @@ lshift
n1 = n + b->wds + 1;
for(i = b->maxwds; n1 > i; i <<= 1)
k1++;
b1 = Balloc(k1);
b1 = Balloc(PASS_STATE k1);
x1 = b1->x;
for(i = 0; i < n; i++)
*x1++ = 0;
@ -967,7 +1044,7 @@ lshift
*x1++ = *x++;
while(x < xe);
b1->wds = n1 - 1;
Bfree(b);
Bfree(PASS_STATE b);
return b1;
}
@ -1008,9 +1085,9 @@ cmp
static Bigint *
diff
#ifdef KR_headers
(a, b) Bigint *a, *b;
(STATE_PARAM a, b) STATE_PARAM_DECL Bigint *a, *b;
#else
(Bigint *a, Bigint *b)
(STATE_PARAM Bigint *a, Bigint *b)
#endif
{
Bigint *c;
@ -1027,7 +1104,7 @@ diff
i = cmp(a,b);
if (!i) {
c = Balloc(0);
c = Balloc(PASS_STATE 0);
c->wds = 1;
c->x[0] = 0;
return c;
@ -1040,7 +1117,7 @@ diff
}
else
i = 0;
c = Balloc(a->k);
c = Balloc(PASS_STATE a->k);
c->sign = i;
wa = a->wds;
xa = a->x;
@ -1214,9 +1291,9 @@ b2d
static Bigint *
d2b
#ifdef KR_headers
(d, e, bits) U d; int *e, *bits;
(STATE_PARAM d, e, bits) STATE_PARAM_DECL U d; int *e, *bits;
#else
(U d, int *e, int *bits)
(STATE_PARAM U d, int *e, int *bits)
#endif
{
Bigint *b;
@ -1235,9 +1312,9 @@ d2b
#endif
#ifdef Pack_32
b = Balloc(1);
b = Balloc(PASS_STATE 1);
#else
b = Balloc(2);
b = Balloc(PASS_STATE 2);
#endif
x = b->x;
@ -1529,9 +1606,9 @@ hexnan
static double
_strtod
#ifdef KR_headers
(s00, se) CONST char *s00; char **se;
(STATE_PARAM s00, se) STATE_PARAM_DECL CONST char *s00; char **se;
#else
(CONST char *s00, char **se)
(STATE_PARAM CONST char *s00, char **se)
#endif
{
#ifdef Avoid_Underflow
@ -1953,13 +2030,13 @@ _strtod
/* Put digits into bd: true value = bd * 10^e */
bd0 = s2b(s0, nd0, nd, y);
bd0 = s2b(PASS_STATE s0, nd0, nd, y);
for(;;) {
bd = Balloc(bd0->k);
bd = Balloc(PASS_STATE bd0->k);
Bcopy(bd, bd0);
bb = d2b(rv, &bbe, &bbbits); /* rv = bb * 2^bbe */
bs = i2b(1);
bb = d2b(PASS_STATE rv, &bbe, &bbbits); /* rv = bb * 2^bbe */
bs = i2b(PASS_STATE 1);
if (e >= 0) {
bb2 = bb5 = 0;
@ -2015,20 +2092,20 @@ _strtod
bs2 -= i;
}
if (bb5 > 0) {
bs = pow5mult(bs, bb5);
bb1 = mult(bs, bb);
Bfree(bb);
bs = pow5mult(PASS_STATE bs, bb5);
bb1 = mult(PASS_STATE bs, bb);
Bfree(PASS_STATE bb);
bb = bb1;
}
if (bb2 > 0)
bb = lshift(bb, bb2);
bb = lshift(PASS_STATE bb, bb2);
if (bd5 > 0)
bd = pow5mult(bd, bd5);
bd = pow5mult(PASS_STATE bd, bd5);
if (bd2 > 0)
bd = lshift(bd, bd2);
bd = lshift(PASS_STATE bd, bd2);
if (bs2 > 0)
bs = lshift(bs, bs2);
delta = diff(bb, bd);
bs = lshift(PASS_STATE bs, bs2);
delta = diff(PASS_STATE bb, bd);
dsign = delta->sign;
delta->sign = 0;
i = cmp(delta, bs);
@ -2060,7 +2137,7 @@ _strtod
if (y)
#endif
{
delta = lshift(delta,Log2P);
delta = lshift(PASS_STATE delta,Log2P);
if (cmp(delta, bs) <= 0)
adj = -0.5;
}
@ -2149,7 +2226,7 @@ _strtod
#endif
break;
}
delta = lshift(delta,Log2P);
delta = lshift(PASS_STATE delta,Log2P);
if (cmp(delta, bs) > 0)
goto drop_down;
break;
@ -2374,10 +2451,10 @@ _strtod
}
#endif
cont:
Bfree(bb);
Bfree(bd);
Bfree(bs);
Bfree(delta);
Bfree(PASS_STATE bb);
Bfree(PASS_STATE bd);
Bfree(PASS_STATE bs);
Bfree(PASS_STATE delta);
}
#ifdef SET_INEXACT
if (inexact) {
@ -2410,11 +2487,11 @@ _strtod
}
#endif
retfree:
Bfree(bb);
Bfree(bd);
Bfree(bs);
Bfree(bd0);
Bfree(delta);
Bfree(PASS_STATE bb);
Bfree(PASS_STATE bd);
Bfree(PASS_STATE bs);
Bfree(PASS_STATE bd0);
Bfree(PASS_STATE delta);
ret:
if (se)
*se = (char *)s;
@ -2539,15 +2616,16 @@ quorem
return q;
}
#ifndef MULTIPLE_THREADS
#if !defined(MULTIPLE_THREADS) && !defined(NO_GLOBAL_STATE)
#define USE_DTOA_RESULT 1
static char *dtoa_result;
#endif
static char *
#ifdef KR_headers
rv_alloc(i) int i;
rv_alloc(STATE_PARAM i) STATE_PARAM_DECL int i;
#else
rv_alloc(int i)
rv_alloc(STATE_PARAM int i)
#endif
{
int j, k, *r;
@ -2557,10 +2635,10 @@ rv_alloc(int i)
sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (unsigned) i;
j <<= 1)
k++;
r = (int*)Balloc(k);
r = (int*)Balloc(PASS_STATE k);
*r = k;
return
#ifndef MULTIPLE_THREADS
#ifdef USE_DTOA_RESULT
dtoa_result =
#endif
(char *)(r+1);
@ -2568,14 +2646,14 @@ rv_alloc(int i)
static char *
#ifdef KR_headers
nrv_alloc(s, rve, n) char *s, **rve; int n;
nrv_alloc(STATE_PARAM s, rve, n) STATE_PARAM_DECL char *s, **rve; int n;
#else
nrv_alloc(CONST char *s, char **rve, int n)
nrv_alloc(STATE_PARAM CONST char *s, char **rve, int n)
#endif
{
char *rv, *t;
t = rv = rv_alloc(n);
t = rv = rv_alloc(PASS_STATE n);
while((*t = *s++)) t++;
if (rve)
*rve = t;
@ -2590,15 +2668,15 @@ nrv_alloc(CONST char *s, char **rve, int n)
static void
#ifdef KR_headers
freedtoa(s) char *s;
freedtoa(STATE_PARAM s) STATE_PARAM_DECL char *s;
#else
freedtoa(char *s)
freedtoa(STATE_PARAM char *s)
#endif
{
Bigint *b = (Bigint *)((int *)s - 1);
b->maxwds = 1 << (b->k = *(int*)b);
Bfree(b);
#ifndef MULTIPLE_THREADS
Bfree(PASS_STATE b);
#ifdef USE_DTOA_RESULT
if (s == dtoa_result)
dtoa_result = 0;
#endif
@ -2641,10 +2719,10 @@ freedtoa(char *s)
static char *
dtoa
#ifdef KR_headers
(d, mode, ndigits, decpt, sign, rve)
U d; int mode, ndigits, *decpt, *sign; char **rve;
(STATE_PARAM d, mode, ndigits, decpt, sign, rve)
STATE_PARAM_DECL U d; int mode, ndigits, *decpt, *sign; char **rve;
#else
(U d, int mode, int ndigits, int *decpt, int *sign, char **rve)
(STATE_PARAM U d, int mode, int ndigits, int *decpt, int *sign, char **rve)
#endif
{
/* Arguments ndigits, decpt, sign are similar to those
@ -2705,9 +2783,9 @@ dtoa
mlo = NULL;
#endif
#ifndef MULTIPLE_THREADS
#ifdef USE_DTOA_RESULT
if (dtoa_result) {
freedtoa(dtoa_result);
freedtoa(PASS_STATE dtoa_result);
dtoa_result = 0;
}
#endif
@ -2731,9 +2809,9 @@ dtoa
*decpt = 9999;
#ifdef IEEE_Arith
if (!word1(d) && !(word0(d) & 0xfffff))
return nrv_alloc("Infinity", rve, 8);
return nrv_alloc(PASS_STATE "Infinity", rve, 8);
#endif
return nrv_alloc("NaN", rve, 3);
return nrv_alloc(PASS_STATE "NaN", rve, 3);
}
#endif
#ifdef IBM
@ -2741,7 +2819,7 @@ dtoa
#endif
if (!dval(d)) {
*decpt = 1;
return nrv_alloc("0", rve, 1);
return nrv_alloc(PASS_STATE "0", rve, 1);
}
#ifdef SET_INEXACT
@ -2758,7 +2836,7 @@ dtoa
}
#endif
b = d2b(d, &be, &bbits);
b = d2b(PASS_STATE d, &be, &bbits);
#ifdef Sudden_Underflow
i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
#else
@ -2884,7 +2962,7 @@ dtoa
if (i <= 0)
i = 1;
}
s = s0 = rv_alloc(i);
s = s0 = rv_alloc(PASS_STATE i);
#ifdef Honor_FLT_ROUNDS
if (mode > 1 && rounding != 1)
@ -3061,7 +3139,7 @@ dtoa
#endif
b2 += i;
s2 += i;
mhi = i2b(1);
mhi = i2b(PASS_STATE 1);
}
if (m2 > 0 && s2 > 0) {
i = m2 < s2 ? m2 : s2;
@ -3072,20 +3150,20 @@ dtoa
if (b5 > 0) {
if (leftright) {
if (m5 > 0) {
mhi = pow5mult(mhi, m5);
b1 = mult(mhi, b);
Bfree(b);
mhi = pow5mult(PASS_STATE mhi, m5);
b1 = mult(PASS_STATE mhi, b);
Bfree(PASS_STATE b);
b = b1;
}
if ((j = b5 - m5))
b = pow5mult(b, j);
b = pow5mult(PASS_STATE b, j);
}
else
b = pow5mult(b, b5);
b = pow5mult(PASS_STATE b, b5);
}
S = i2b(1);
S = i2b(PASS_STATE 1);
if (s5 > 0)
S = pow5mult(S, s5);
S = pow5mult(PASS_STATE S, s5);
/* Check for special case that d is a normalized power of 2. */
@ -3134,20 +3212,20 @@ dtoa
s2 += i;
}
if (b2 > 0)
b = lshift(b, b2);
b = lshift(PASS_STATE b, b2);
if (s2 > 0)
S = lshift(S, s2);
S = lshift(PASS_STATE S, s2);
if (k_check) {
if (cmp(b,S) < 0) {
k--;
b = multadd(b, 10, 0); /* we botched the k estimate */
b = multadd(PASS_STATE b, 10, 0); /* we botched the k estimate */
if (leftright)
mhi = multadd(mhi, 10, 0);
mhi = multadd(PASS_STATE mhi, 10, 0);
ilim = ilim1;
}
}
if (ilim <= 0 && (mode == 3 || mode == 5)) {
if (ilim < 0 || cmp(b,S = multadd(S,5,0)) < 0) {
if (ilim < 0 || cmp(b,S = multadd(PASS_STATE S,5,0)) < 0) {
/* no digits, fcvt style */
no_digits:
/* MOZILLA CHANGE: Always return a non-empty string. */
@ -3162,7 +3240,7 @@ dtoa
}
if (leftright) {
if (m2 > 0)
mhi = lshift(mhi, m2);
mhi = lshift(PASS_STATE mhi, m2);
/* Compute mlo -- check for special case
* that d is a normalized power of 2.
@ -3170,9 +3248,9 @@ dtoa
mlo = mhi;
if (spec_case) {
mhi = Balloc(mhi->k);
mhi = Balloc(PASS_STATE mhi->k);
Bcopy(mhi, mlo);
mhi = lshift(mhi, Log2P);
mhi = lshift(PASS_STATE mhi, Log2P);
}
for(i = 1;;i++) {
@ -3181,9 +3259,9 @@ dtoa
* that will round to d?
*/
j = cmp(b, mlo);
delta = diff(S, mhi);
delta = diff(PASS_STATE S, mhi);
j1 = delta->sign ? 1 : cmp(b, delta);
Bfree(delta);
Bfree(PASS_STATE delta);
#ifndef ROUND_BIASED
if (j1 == 0 && mode != 1 && !(word1(d) & 1)
#ifdef Honor_FLT_ROUNDS
@ -3221,7 +3299,7 @@ dtoa
}
#endif /*Honor_FLT_ROUNDS*/
if (j1 > 0) {
b = lshift(b, 1);
b = lshift(PASS_STATE b, 1);
j1 = cmp(b, S);
if ((j1 > 0 || (j1 == 0 && dig & 1))
&& dig++ == '9')
@ -3250,12 +3328,12 @@ dtoa
*s++ = dig;
if (i == ilim)
break;
b = multadd(b, 10, 0);
b = multadd(PASS_STATE b, 10, 0);
if (mlo == mhi)
mlo = mhi = multadd(mhi, 10, 0);
mlo = mhi = multadd(PASS_STATE mhi, 10, 0);
else {
mlo = multadd(mlo, 10, 0);
mhi = multadd(mhi, 10, 0);
mlo = multadd(PASS_STATE mlo, 10, 0);
mhi = multadd(PASS_STATE mhi, 10, 0);
}
}
}
@ -3270,7 +3348,7 @@ dtoa
}
if (i >= ilim)
break;
b = multadd(b, 10, 0);
b = multadd(PASS_STATE b, 10, 0);
}
/* Round off last digit */
@ -3281,7 +3359,7 @@ dtoa
case 2: goto roundoff;
}
#endif
b = lshift(b, 1);
b = lshift(PASS_STATE b, 1);
j = cmp(b, S);
if (j >= 0) { /* ECMA compatible rounding needed by Spidermonkey */
roundoff:
@ -3301,11 +3379,11 @@ dtoa
s++;
}
ret:
Bfree(S);
Bfree(PASS_STATE S);
if (mhi) {
if (mlo && mlo != mhi)
Bfree(mlo);
Bfree(mhi);
Bfree(PASS_STATE mlo);
Bfree(PASS_STATE mhi);
}
ret1:
#ifdef SET_INEXACT
@ -3319,7 +3397,7 @@ dtoa
else if (!oldinexact)
clear_inexact();
#endif
Bfree(b);
Bfree(PASS_STATE b);
*s = 0;
*decpt = k + 1;
if (rve)

View File

@ -563,11 +563,8 @@ JSRuntime::JSRuntime()
bool
JSRuntime::init(uint32 maxbytes)
{
if (!js_InitDtoa() ||
!js_InitGC(this, maxbytes) ||
!js_InitAtomState(this)) {
if (!js_InitGC(this, maxbytes) || !js_InitAtomState(this))
return false;
}
deflatedStringCache = new js::DeflatedStringCache();
if (!deflatedStringCache || !deflatedStringCache->init())
@ -757,7 +754,6 @@ JS_ShutDown(void)
reprmeter::js_DumpReprMeter();
#endif
js_FinishDtoa();
#ifdef JS_THREADSAFE
js_CleanupLocks();
#endif

View File

@ -100,7 +100,7 @@ CallStack::contains(JSStackFrame *fp)
}
#endif
void
bool
JSThreadData::init()
{
#ifdef DEBUG
@ -111,6 +111,12 @@ JSThreadData::init()
#ifdef JS_TRACER
InitJIT(&traceMonitor);
#endif
dtoaState = js_NewDtoaState();
if (!dtoaState) {
finish();
return false;
}
return true;
}
void
@ -126,6 +132,9 @@ JSThreadData::finish()
JS_ASSERT(!localRootStack);
#endif
if (dtoaState)
js_DestroyDtoaState(dtoaState);
js_FinishGSNCache(&gsnCache);
js_FinishPropertyCache(&propertyCache);
#if defined JS_TRACER
@ -190,7 +199,10 @@ NewThread(jsword id)
return NULL;
JS_INIT_CLIST(&thread->contextList);
thread->id = id;
thread->data.init();
if (!thread->data.init()) {
js_free(thread);
return NULL;
}
return thread;
}

View File

@ -50,6 +50,7 @@
#include "jslong.h"
#include "jsatom.h"
#include "jsdhash.h"
#include "jsdtoa.h"
#include "jsgc.h"
#include "jshashtable.h"
#include "jsinterp.h"
@ -555,6 +556,9 @@ struct JSThreadData {
JSEvalCacheMeter evalCacheMeter;
#endif
/* State used by dtoa.c. */
DtoaState *dtoaState;
/*
* Cache of reusable JSNativeEnumerators mapped by shape identifiers (as
* stored in scope->shape). This cache is nulled by the GC and protected
@ -569,7 +573,7 @@ struct JSThreadData {
jsuword nativeEnumCache[NATIVE_ENUM_CACHE_SIZE];
void init();
bool init();
void finish();
void mark(JSTracer *trc);
void purge(JSContext *cx);

View File

@ -2175,7 +2175,7 @@ date_toSource(JSContext *cx, uintN argc, jsval *vp)
if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime))
return JS_FALSE;
numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, utctime);
numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof buf, DTOSTR_STANDARD, 0, utctime);
if (!numStr) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;

View File

@ -49,10 +49,7 @@
#include "jsnum.h"
#include "jsbit.h"
#include "jslibmath.h"
#ifdef JS_THREADSAFE
#include "jslock.h"
#endif
#include "jscntxt.h"
#ifdef IS_LITTLE_ENDIAN
#define IEEE_8087
@ -78,46 +75,9 @@
#endif
*/
#ifdef JS_THREADSAFE
static PRLock *dtoalock;
static JSBool _dtoainited = JS_FALSE;
#define LOCK_DTOA() PR_Lock(dtoalock);
#define UNLOCK_DTOA() PR_Unlock(dtoalock)
#else
#define LOCK_DTOA()
#define UNLOCK_DTOA()
#endif
#define NO_GLOBAL_STATE
#include "dtoa.c"
JS_FRIEND_API(JSBool)
js_InitDtoa()
{
#ifdef JS_THREADSAFE
if (!_dtoainited) {
dtoalock = PR_NewLock();
JS_ASSERT(dtoalock);
_dtoainited = JS_TRUE;
}
return (dtoalock != 0);
#else
return JS_TRUE;
#endif
}
JS_FRIEND_API(void)
js_FinishDtoa()
{
#ifdef JS_THREADSAFE
if (_dtoainited) {
PR_DestroyLock(dtoalock);
dtoalock = NULL;
_dtoainited = JS_FALSE;
}
#endif
}
/* Mapping of JSDToStrMode -> js_dtoa mode */
static const uint8 dtoaModes[] = {
0, /* DTOSTR_STANDARD */
@ -126,20 +86,19 @@ static const uint8 dtoaModes[] = {
2, /* DTOSTR_EXPONENTIAL, */
2}; /* DTOSTR_PRECISION */
JS_FRIEND_API(double)
JS_strtod(const char *s00, char **se, int *err)
double
js_strtod_harder(DtoaState *state, const char *s00, char **se, int *err)
{
double retval;
if (err)
*err = 0;
LOCK_DTOA();
retval = _strtod(s00, se);
UNLOCK_DTOA();
retval = _strtod(state, s00, se);
return retval;
}
JS_FRIEND_API(char *)
JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, double dinput)
char *
js_dtostr(DtoaState *state, char *buffer, size_t bufferSize, JSDToStrMode mode, int precision,
double dinput)
{
U d;
int decPt; /* Offset of decimal point from first digit */
@ -159,24 +118,20 @@ JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, dou
if (mode == DTOSTR_FIXED && (dinput >= 1e21 || dinput <= -1e21))
mode = DTOSTR_STANDARD;
LOCK_DTOA();
dval(d) = dinput;
numBegin = dtoa(d, dtoaModes[mode], precision, &decPt, &sign, &numEnd);
numBegin = dtoa(PASS_STATE d, dtoaModes[mode], precision, &decPt, &sign, &numEnd);
if (!numBegin) {
UNLOCK_DTOA();
return NULL;
}
nDigits = numEnd - numBegin;
JS_ASSERT((size_t) nDigits <= bufferSize - 2);
if ((size_t) nDigits > bufferSize - 2) {
UNLOCK_DTOA();
return NULL;
}
memcpy(buffer + 2, numBegin, nDigits);
freedtoa(numBegin);
UNLOCK_DTOA();
freedtoa(PASS_STATE numBegin);
numBegin = buffer + 2; /* +2 leaves space for sign and/or decimal point */
numEnd = numBegin + nDigits;
*numEnd = '\0';
@ -353,8 +308,8 @@ static uint32 quorem2(Bigint *b, int32 k)
#define DTOBASESTR_BUFFER_SIZE 1078
#define BASEDIGIT(digit) ((char)(((digit) >= 10) ? 'a' - 10 + (digit) : '0' + (digit)))
JS_FRIEND_API(char *)
JS_dtobasestr(int base, double dinput)
char *
js_dtobasestr(DtoaState *state, int base, double dinput)
{
U d;
char *buffer; /* The output string */
@ -386,7 +341,6 @@ JS_dtobasestr(int base, double dinput)
return buffer;
}
LOCK_DTOA();
/* Output the integer part of d with the digits in reverse order. */
pInt = p;
dval(di) = floor(dval(d));
@ -404,14 +358,13 @@ JS_dtobasestr(int base, double dinput)
} else {
int e;
int bits; /* Number of significant bits in di; not used. */
Bigint *b = d2b(di, &e, &bits);
Bigint *b = d2b(PASS_STATE di, &e, &bits);
if (!b)
goto nomem1;
b = lshift(b, e);
b = lshift(PASS_STATE b, e);
if (!b) {
nomem1:
Bfree(b);
UNLOCK_DTOA();
Bfree(PASS_STATE b);
js_free(buffer);
return NULL;
}
@ -420,7 +373,7 @@ JS_dtobasestr(int base, double dinput)
JS_ASSERT(digit < (uint32)base);
*p++ = BASEDIGIT(digit);
} while (b->wds);
Bfree(b);
Bfree(PASS_STATE b);
}
/* Reverse the digits of the integer part of d. */
q = p-1;
@ -440,15 +393,14 @@ JS_dtobasestr(int base, double dinput)
b = s = mlo = mhi = NULL;
*p++ = '.';
b = d2b(df, &e, &bbits);
b = d2b(PASS_STATE df, &e, &bbits);
if (!b) {
nomem2:
Bfree(b);
Bfree(s);
Bfree(PASS_STATE b);
Bfree(PASS_STATE s);
if (mlo != mhi)
Bfree(mlo);
Bfree(mhi);
UNLOCK_DTOA();
Bfree(PASS_STATE mlo);
Bfree(PASS_STATE mhi);
js_free(buffer);
return NULL;
}
@ -463,7 +415,7 @@ JS_dtobasestr(int base, double dinput)
s2 += Bias + P;
/* 1/2^s2 = (nextDouble(d) - d)/2 */
JS_ASSERT(-s2 < e);
mlo = i2b(1);
mlo = i2b(PASS_STATE 1);
if (!mlo)
goto nomem2;
mhi = mlo;
@ -475,17 +427,17 @@ JS_dtobasestr(int base, double dinput)
/* The special case. Here we want to be within a quarter of the last input
significant digit instead of one half of it when the output string's value is less than d. */
s2 += Log2P;
mhi = i2b(1<<Log2P);
mhi = i2b(PASS_STATE 1<<Log2P);
if (!mhi)
goto nomem2;
}
b = lshift(b, e + s2);
b = lshift(PASS_STATE b, e + s2);
if (!b)
goto nomem2;
s = i2b(1);
s = i2b(PASS_STATE 1);
if (!s)
goto nomem2;
s = lshift(s, s2);
s = lshift(PASS_STATE s, s2);
if (!s)
goto nomem2;
/* At this point we have the following:
@ -499,20 +451,20 @@ JS_dtobasestr(int base, double dinput)
int32 j, j1;
Bigint *delta;
b = multadd(b, base, 0);
b = multadd(PASS_STATE b, base, 0);
if (!b)
goto nomem2;
digit = quorem2(b, s2);
if (mlo == mhi) {
mlo = mhi = multadd(mlo, base, 0);
mlo = mhi = multadd(PASS_STATE mlo, base, 0);
if (!mhi)
goto nomem2;
}
else {
mlo = multadd(mlo, base, 0);
mlo = multadd(PASS_STATE mlo, base, 0);
if (!mlo)
goto nomem2;
mhi = multadd(mhi, base, 0);
mhi = multadd(PASS_STATE mhi, base, 0);
if (!mhi)
goto nomem2;
}
@ -520,11 +472,11 @@ JS_dtobasestr(int base, double dinput)
/* Do we yet have the shortest string that will round to d? */
j = cmp(b, mlo);
/* j is b/2^s2 compared with mlo/2^s2. */
delta = diff(s, mhi);
delta = diff(PASS_STATE s, mhi);
if (!delta)
goto nomem2;
j1 = delta->sign ? 1 : cmp(b, delta);
Bfree(delta);
Bfree(PASS_STATE delta);
/* j1 is b/2^s2 compared with 1 - mhi/2^s2. */
#ifndef ROUND_BIASED
@ -542,7 +494,7 @@ JS_dtobasestr(int base, double dinput)
if (j1 > 0) {
/* Either dig or dig+1 would work here as the least significant digit.
Use whichever would produce an output value closer to d. */
b = lshift(b, 1);
b = lshift(PASS_STATE b, 1);
if (!b)
goto nomem2;
j1 = cmp(b, s);
@ -558,15 +510,26 @@ JS_dtobasestr(int base, double dinput)
JS_ASSERT(digit < (uint32)base);
*p++ = BASEDIGIT(digit);
} while (!done);
Bfree(b);
Bfree(s);
Bfree(PASS_STATE b);
Bfree(PASS_STATE s);
if (mlo != mhi)
Bfree(mlo);
Bfree(mhi);
Bfree(PASS_STATE mlo);
Bfree(PASS_STATE mhi);
}
JS_ASSERT(p < buffer + DTOBASESTR_BUFFER_SIZE);
*p = '\0';
UNLOCK_DTOA();
}
return buffer;
}
DtoaState *
js_NewDtoaState()
{
return newdtoa();
}
void
js_DestroyDtoaState(DtoaState *state)
{
destroydtoa(state);
}

View File

@ -48,23 +48,30 @@
JS_BEGIN_EXTERN_C
struct DtoaState;
DtoaState *
js_NewDtoaState();
void
js_DestroyDtoaState(DtoaState *state);
/*
* JS_strtod() returns as a double-precision floating-point number
* the value represented by the character string pointed to by
* s00. The string is scanned up to the first unrecognized
* character.
* If the value of se is not (char **)NULL, a pointer to
* the character terminating the scan is returned in the location pointed
* to by se. If no number can be formed, se is set to s00r, and
* zero is returned.
* js_strtod_harder() returns as a double-precision floating-point number the
* value represented by the character string pointed to by s00. The string is
* scanned up to the first unrecognized character.
*
* If se is not NULL, *se receives a pointer to the character terminating the
* scan. If no number can be formed, *se receives a pointer to the first
* unparseable character in s00, and zero is returned.
*
* *err is set to zero on success; it's set to JS_DTOA_ERANGE on range
* errors and JS_DTOA_ENOMEM on memory failure.
*/
#define JS_DTOA_ERANGE 1
#define JS_DTOA_ENOMEM 2
JS_FRIEND_API(double)
JS_strtod(const char *s00, char **se, int *err);
double
js_strtod_harder(DtoaState *state, const char *s00, char **se, int *err);
/*
* Modes for converting floating-point numbers to strings.
@ -102,8 +109,9 @@ typedef enum JSDToStrMode {
*
* Return NULL if out of memory.
*/
JS_FRIEND_API(char *)
JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, double dval);
char *
js_dtostr(DtoaState *state, char *buffer, size_t bufferSize, JSDToStrMode mode, int precision,
double dval);
/*
* Convert d to a string in the given base. The integral part of d will be printed exactly
@ -116,15 +124,8 @@ JS_dtostr(char *buffer, size_t bufferSize, JSDToStrMode mode, int precision, dou
*
* Return NULL if out of memory. If the result is not NULL, it must be released via free().
*/
JS_FRIEND_API(char *)
JS_dtobasestr(int base, double d);
/*
* Clean up any persistent RAM allocated during the execution of DtoA
* routines, and remove any locks that might have been created.
*/
JS_FRIEND_API(JSBool) js_InitDtoa(void);
JS_FRIEND_API(void) js_FinishDtoa(void);
char *
js_dtobasestr(DtoaState *state, int base, double d);
JS_END_EXTERN_C

View File

@ -321,7 +321,8 @@ num_toSource(JSContext *cx, uintN argc, jsval *vp)
return JS_FALSE;
JS_ASSERT(JSVAL_IS_NUMBER(v));
d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v);
numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d);
numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, numBuf, sizeof numBuf,
DTOSTR_STANDARD, 0, d);
if (!numStr) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
@ -575,7 +576,8 @@ num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode,
return JS_FALSE;
precision = js_DoubleToInteger(precision);
if (precision < precisionMin || precision > precisionMax) {
numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, precision);
numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof buf,
DTOSTR_STANDARD, 0, precision);
if (!numStr)
JS_ReportOutOfMemory(cx);
else
@ -584,7 +586,8 @@ num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode,
}
}
numStr = JS_dtostr(buf, sizeof buf, oneArgMode, (jsint)precision + precisionOffset, d);
numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof buf,
oneArgMode, (jsint)precision + precisionOffset, d);
if (!numStr) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
@ -847,9 +850,10 @@ NumberToCString(JSContext *cx, jsdouble d, jsint base, char *buf, size_t bufSize
numStr = IntToCString(i, base, buf, bufSize);
} else {
if (base == 10)
numStr = JS_dtostr(buf, bufSize, DTOSTR_STANDARD, 0, d);
numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, bufSize,
DTOSTR_STANDARD, 0, d);
else
numStr = JS_dtobasestr(base, d);
numStr = js_dtobasestr(JS_THREAD_DATA(cx)->dtoaState, base, d);
if (!numStr) {
JS_ReportOutOfMemory(cx);
return NULL;
@ -915,7 +919,8 @@ js_NumberValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb)
cstr = IntToCString(JSVAL_TO_INT(v), 10, arr, arrSize);
} else {
JS_ASSERT(JSVAL_IS_DOUBLE(v));
cstr = JS_dtostr(arr, arrSize, DTOSTR_STANDARD, 0, *JSVAL_TO_DOUBLE(v));
cstr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, arr, arrSize,
DTOSTR_STANDARD, 0, *JSVAL_TO_DOUBLE(v));
}
if (!cstr)
return JS_FALSE;
@ -1178,7 +1183,7 @@ js_strtod(JSContext *cx, const jschar *s, const jschar *send,
estr = istr + 8;
} else {
int err;
d = JS_strtod(cstr, &estr, &err);
d = js_strtod_harder(JS_THREAD_DATA(cx)->dtoaState, cstr, &estr, &err);
if (d == HUGE_VAL)
d = js_PositiveInfinity;
else if (d == -HUGE_VAL)
@ -1296,7 +1301,7 @@ js_strtointeger(JSContext *cx, const jschar *s, const jschar *send,
/*
* If we're accumulating a decimal number and the number is >=
* 2^53, then the result from the repeated multiply-add above may
* be inaccurate. Call JS_strtod to get the correct answer.
* be inaccurate. Call js_strtod_harder to get the correct answer.
*/
size_t i;
size_t length = s1 - start;
@ -1310,7 +1315,7 @@ js_strtointeger(JSContext *cx, const jschar *s, const jschar *send,
cstr[i] = (char)start[i];
cstr[length] = 0;
value = JS_strtod(cstr, &estr, &err);
value = js_strtod_harder(JS_THREAD_DATA(cx)->dtoaState, cstr, &estr, &err);
if (err == JS_DTOA_ENOMEM) {
JS_ReportOutOfMemory(cx);
cx->free(cstr);

View File

@ -482,7 +482,8 @@ Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, jsval *vp,
char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr;
jsdouble d = JSVAL_IS_INT(*vp) ? jsdouble(JSVAL_TO_INT(*vp)) : *JSVAL_TO_DOUBLE(*vp);
numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d);
numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, numBuf, sizeof numBuf,
DTOSTR_STANDARD, 0, d);
if (!numStr) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;

View File

@ -1107,7 +1107,8 @@ SprintDoubleValue(Sprinter *sp, jsval v, JSOp *opp)
: "1 / 0");
*opp = JSOP_DIV;
} else {
s = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, d);
s = js_dtostr(JS_THREAD_DATA(sp->context)->dtoaState, buf, sizeof buf,
DTOSTR_STANDARD, 0, d);
if (!s) {
JS_ReportOutOfMemory(sp->context);
return -1;