Bug 400902: using a specialized GC arena for doubles. r,a=brendan a1.9b3=mtschrep

This commit is contained in:
igor@mir2.org 2008-02-01 10:39:23 -08:00
parent 453fae2df2
commit ea03e8c6f0
14 changed files with 918 additions and 436 deletions

View File

@ -331,16 +331,19 @@ JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
break;
case 'i':
case 'j':
if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp))
*sp = js_NewWeakNumberValue(cx, (jsdouble) va_arg(ap, int32));
if (*sp == JSVAL_NULL)
goto bad;
break;
case 'u':
if (!js_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp))
*sp = js_NewWeakNumberValue(cx, (jsdouble) va_arg(ap, uint32));
if (*sp == JSVAL_NULL)
goto bad;
break;
case 'd':
case 'I':
if (!js_NewDoubleValue(cx, va_arg(ap, jsdouble), sp))
*sp = js_NewUnrootedDoubleValue(cx, va_arg(ap, jsdouble));
if (*sp == JSVAL_NULL || !js_WeaklyRootDouble(cx, *sp))
goto bad;
break;
case 's':
@ -462,7 +465,7 @@ JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
JSBool ok;
JSObject *obj;
JSString *str;
jsdouble d, *dp;
jsdouble d;
CHECK_REQUEST(cx);
switch (type) {
@ -489,10 +492,8 @@ JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
case JSTYPE_NUMBER:
ok = js_ValueToNumber(cx, v, &d);
if (ok) {
dp = js_NewDouble(cx, d, 0);
ok = (dp != NULL);
if (ok)
*vp = DOUBLE_TO_JSVAL(dp);
*vp = js_NewUnrootedDoubleValue(cx, d);
ok = *vp != JSVAL_NULL && js_WeaklyRootDouble(cx, *vp);
}
break;
case JSTYPE_BOOLEAN:
@ -1766,21 +1767,23 @@ JS_PUBLIC_API(jsdouble *)
JS_NewDouble(JSContext *cx, jsdouble d)
{
CHECK_REQUEST(cx);
return js_NewDouble(cx, d, 0);
return js_NewWeaklyRootedDouble(cx, d);
}
JS_PUBLIC_API(JSBool)
JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *vp)
{
CHECK_REQUEST(cx);
return js_NewDoubleValue(cx, d, rval);
*vp = js_NewUnrootedDoubleValue(cx, d);
return *vp != JSVAL_NULL && js_WeaklyRootDouble(cx, *vp);
}
JS_PUBLIC_API(JSBool)
JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *vp)
{
CHECK_REQUEST(cx);
return js_NewNumberValue(cx, d, rval);
*vp = js_NewWeakNumberValue(cx, d);
return vp != JSVAL_NULL;
}
#undef JS_AddRoot
@ -3051,23 +3054,21 @@ JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp,
JS_PUBLIC_API(JSBool)
JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
{
JSBool ok;
jsval value;
uintN flags;
CHECK_REQUEST(cx);
for (ok = JS_TRUE; cds->name; cds++) {
ok = js_NewNumberValue(cx, cds->dval, &value);
if (!ok)
break;
for (; cds->name; cds++) {
value = js_NewWeakNumberValue(cx, cds->dval);
if (value == JSVAL_NULL)
return JS_FALSE;
flags = cds->flags;
if (!flags)
flags = JSPROP_READONLY | JSPROP_PERMANENT;
ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, flags, 0, 0);
if (!ok)
break;
if (!DefineProperty(cx, obj, cds->name, value, NULL, NULL, flags, 0, 0))
return JS_FALSE;
}
return ok;
return JS_TRUE;
}
JS_PUBLIC_API(JSBool)

View File

@ -187,6 +187,9 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
return ok;
}
/*
* vp must be a root.
*/
static JSBool
IndexToValue(JSContext *cx, jsuint index, jsval *vp)
{
@ -194,7 +197,8 @@ IndexToValue(JSContext *cx, jsuint index, jsval *vp)
*vp = INT_TO_JSVAL(index);
return JS_TRUE;
}
return js_NewDoubleValue(cx, (jsdouble)index, vp);
*vp = js_NewUnrootedDoubleValue(cx, (jsdouble)index);
return *vp != JSVAL_NULL;
}
static JSBool
@ -334,13 +338,16 @@ SetOrDeleteArrayElement(JSContext *cx, JSObject *obj, jsuint index,
JSBool
js_SetLengthProperty(JSContext *cx, JSObject *obj, jsuint length)
{
jsval v;
jsid id;
JSTempValueRooter tvr;
JSBool ok;
if (!IndexToValue(cx, length, &v))
return JS_FALSE;
id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
return OBJ_SET_PROPERTY(cx, obj, id, &v);
JS_PUSH_SINGLE_TEMP_ROOT(cx, JSVAL_NULL, &tvr);
ok = IndexToValue(cx, length, &tvr.u.value) &&
OBJ_SET_PROPERTY(cx, obj, id, &tvr.u.value);
JS_POP_TEMP_ROOT(cx, &tvr);
return ok;
}
JSBool
@ -774,12 +781,13 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint end,
static JSBool
InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector)
{
jsval v;
jsval *vp;
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass);
if (!IndexToValue(cx, length, &v))
vp = STOBJ_FIXED_SLOT_PTR(obj, JSSLOT_ARRAY_LENGTH);
if (!IndexToValue(cx, length, vp))
return JS_FALSE;
STOBJ_SET_SLOT(obj, JSSLOT_ARRAY_LENGTH, v);
return !vector || InitArrayElements(cx, obj, 0, length, vector);
}

View File

@ -586,7 +586,7 @@ js_AtomizeDouble(JSContext *cx, jsdouble d)
gen = ++state->tablegen;
JS_UNLOCK(&state->lock, cx);
key = js_NewDouble(cx, d, 0);
key = js_NewWeaklyRootedDouble(cx, d);
if (!key)
return NULL;

View File

@ -50,12 +50,12 @@ JS_BEGIN_EXTERN_C
typedef JSUword jsbitmap_t; /* NSPR name, a la Unix system types */
typedef jsbitmap_t jsbitmap; /* JS-style scalar typedef name */
#define JS_TEST_BIT(_map,_bit) \
((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] & (1L << ((_bit) & (JS_BITS_PER_WORD-1))))
#define JS_SET_BIT(_map,_bit) \
((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] |= (1L << ((_bit) & (JS_BITS_PER_WORD-1))))
#define JS_CLEAR_BIT(_map,_bit) \
((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] &= ~(1L << ((_bit) & (JS_BITS_PER_WORD-1))))
#define JS_TEST_BIT(map,bit) ((map)[(bit) >> JS_BITS_PER_WORD_LOG2] & \
((jsbitmap)1 << ((bit)&(JS_BITS_PER_WORD-1))))
#define JS_SET_BIT(map,bit) ((map)[(bit) >> JS_BITS_PER_WORD_LOG2] |= \
((jsbitmap)1 << ((bit)&(JS_BITS_PER_WORD-1))))
#define JS_CLEAR_BIT(map,bit) ((map)[(bit) >> JS_BITS_PER_WORD_LOG2] &= \
~((jsbitmap)1 << ((bit)&(JS_BITS_PER_WORD-1))))
/*
** Compute the log of the least power of 2 greater than or equal to n

View File

@ -183,6 +183,7 @@ struct JSRuntime {
/* Garbage collector state, used by jsgc.c. */
JSGCChunkInfo *gcChunkList;
JSGCArenaList gcArenaList[GC_NUM_FREELISTS];
JSGCDoubleArenaList gcDoubleArenaList;
JSDHashTable gcRootsHash;
JSDHashTable *gcLocksHash;
jsrefcount gcKeepAtoms;
@ -765,6 +766,8 @@ struct JSContext {
/* Stack of thread-stack-allocated temporary GC roots. */
JSTempValueRooter *tempValueRooters;
JSGCDoubleCell *doubleFreeList;
/* Debug hooks associated with the current context. */
JSDebugHooks *debugHooks;
};

View File

@ -915,7 +915,8 @@ date_now(JSContext *cx, uintN argc, jsval *vp)
JSLL_DIV(ms, us, us2ms);
JSLL_L2D(msec_time, ms);
return js_NewDoubleValue(cx, msec_time, vp);
*vp = js_NewUnrootedDoubleValue(cx, msec_time);
return *vp != JSVAL_NULL;
}
/*
@ -963,7 +964,7 @@ SetUTCTimePtr(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp)
static JSBool
SetUTCTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble t)
{
jsdouble *dp = js_NewDouble(cx, t, 0);
jsdouble *dp = js_NewWeaklyRootedDouble(cx, t);
if (!dp)
return JS_FALSE;
return SetUTCTimePtr(cx, obj, vp, dp);
@ -993,7 +994,7 @@ GetLocalTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp)
if (JSDOUBLE_IS_FINITE(result))
result = LocalTime(result);
cached = js_NewDouble(cx, result, 0);
cached = js_NewWeaklyRootedDouble(cx, result);
if (!cached)
return JS_FALSE;
@ -1543,7 +1544,8 @@ date_setYear(JSContext *cx, uintN argc, jsval *vp)
if (!JSDOUBLE_IS_FINITE(year)) {
if (!SetUTCTimePtr(cx, obj, NULL, cx->runtime->jsNaN))
return JS_FALSE;
return js_NewNumberValue(cx, *cx->runtime->jsNaN, vp);
*vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
return JS_TRUE;
}
year = js_DoubleToInteger(year);
@ -2019,7 +2021,7 @@ date_constructor(JSContext *cx, JSObject* obj)
{
jsdouble *date;
date = js_NewDouble(cx, 0.0, 0);
date = js_NewWeaklyRootedDouble(cx, 0.0);
if (!date)
return NULL;

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,7 @@
#include "jsprvtd.h"
#include "jspubtd.h"
#include "jsdhash.h"
#include "jsbit.h"
#include "jsutil.h"
JS_BEGIN_EXTERN_C
@ -182,6 +183,22 @@ struct JSGCThing {
extern void *
js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes);
/*
* GC-allocate a new jsdouble number. Returns JSVAL_NULL when the allocation
* fails. Otherwise the caller must root the result immediately after the
* the call.
*/
extern jsval
js_NewUnrootedDoubleValue(JSContext *cx, jsdouble d);
/*
* Copy double jsval to the weak root for doubles. This is the function to
* call after invoking js_NewUnrootedDoubleValue to provide at least weak
* rooting of the new double value.
*/
extern JSBool
js_WeaklyRootDouble(JSContext *cx, jsval v);
extern JSBool
js_LockGCThing(JSContext *cx, void *thing);
@ -283,6 +300,21 @@ struct JSGCArenaList {
JSGCThing *freeList; /* list of free GC things */
};
typedef union JSGCDoubleCell JSGCDoubleCell;
union JSGCDoubleCell {
double number;
JSGCDoubleCell *link;
};
JS_STATIC_ASSERT(sizeof(JSGCDoubleCell) == sizeof(double));
typedef struct JSGCDoubleArenaList {
JSGCArenaInfo *first; /* first allocated GC arena */
uint8 *nextDoubleFlags; /* bitmask with flags to check for free
things */
} JSGCDoubleArenaList;
struct JSWeakRoots {
/* Most recently created things by type, members of the GC's root set. */
void *newborn[GCX_NTYPES];
@ -304,28 +336,22 @@ JS_STATIC_ASSERT(JSVAL_NULL == 0);
#ifdef JS_GCMETER
typedef struct JSGCArenaStats {
uint32 narenas; /* number of arena in list */
uint32 maxarenas; /* maximun number of allocated arenas */
uint32 nthings; /* number of allocates JSGCThing */
uint32 maxthings; /* maximum number number of allocates JSGCThing */
uint32 totalnew; /* number of succeeded calls to js_NewGCThing */
uint32 freelen; /* freeList lengths */
uint32 recycle; /* number of things recycled through freeList */
uint32 alloc; /* allocation attempts */
uint32 localalloc; /* allocations from local lists */
uint32 retry; /* allocation retries after running the GC */
uint32 fail; /* allocation failures */
uint32 nthings; /* live GC things */
uint32 maxthings; /* maximum of live GC cells */
double totalthings; /* live GC things the GC scanned so far */
uint32 narenas; /* number of arena in list before the GC */
uint32 newarenas; /* new arenas allocated before the last GC */
uint32 livearenas; /* number of live arenas after the last GC */
uint32 maxarenas; /* maximum of allocated arenas */
uint32 totalarenas; /* total number of arenas with live things that
GC scanned so far */
uint32 totalfreelen; /* total number of things that GC put to free
list so far */
} JSGCArenaStats;
typedef struct JSGCStats {
#ifdef JS_THREADSAFE
uint32 localalloc; /* number of succeeded allocations from local lists */
#endif
uint32 alloc; /* number of allocation attempts */
uint32 retry; /* allocation attempt retries after running the GC */
uint32 retryhalt; /* allocation retries halted by the operation
callback */
uint32 fail; /* allocation failures */
uint32 finalfail; /* finalizer calls allocator failures */
uint32 lockborn; /* things born locked */
uint32 lock; /* valid lock calls */
@ -350,7 +376,8 @@ typedef struct JSGCStats {
uint32 closelater; /* number of close hooks scheduled to run */
uint32 maxcloselater; /* max number of close hooks scheduled to run */
JSGCArenaStats arenas[GC_NUM_FREELISTS];
JSGCArenaStats arenaStats[GC_NUM_FREELISTS];
JSGCArenaStats doubleArenaStats;
} JSGCStats;
extern JS_FRIEND_API(void)

View File

@ -127,7 +127,8 @@
v_ = INT_TO_JSVAL(i_); \
} else { \
SAVE_SP_AND_PC(fp); \
ok = js_NewDoubleValue(cx, d, &v_); \
v_ = js_NewUnrootedDoubleValue(cx, d); \
ok = v_ != JSVAL_NULL; \
if (!ok) \
goto out; \
} \
@ -142,7 +143,8 @@
v_ = INT_TO_JSVAL(i); \
} else { \
SAVE_SP_AND_PC(fp); \
ok = js_NewDoubleValue(cx, (jsdouble)(i), &v_); \
v_ = js_NewUnrootedDoubleValue(cx, d); \
ok = v_ != JSVAL_NULL; \
if (!ok) \
goto out; \
} \
@ -157,7 +159,8 @@
v_ = INT_TO_JSVAL(u); \
} else { \
SAVE_SP_AND_PC(fp); \
ok = js_NewDoubleValue(cx, (jsdouble)(u), &v_); \
v_ = js_NewUnrootedDoubleValue(cx, d); \
ok = v_ != JSVAL_NULL; \
if (!ok) \
goto out; \
} \
@ -3152,7 +3155,8 @@ interrupt:
#else
d = -d;
#endif
ok = js_NewNumberValue(cx, d, &rval);
rval = js_NewUnrootedDoubleValue(cx, d);
ok = rval != JSVAL_NULL;
if (!ok)
goto out;
}
@ -3166,7 +3170,8 @@ interrupt:
ok = js_ValueToNumber(cx, rval, &d);
if (!ok)
goto out;
ok = js_NewNumberValue(cx, d, &rval);
rval = js_NewUnrootedDoubleValue(cx, d);
ok = rval != JSVAL_NULL;
if (!ok)
goto out;
sp[-1] = rval;
@ -3320,18 +3325,20 @@ interrupt:
if (cs->format & JOF_POST) { \
rtmp = rval; \
if (!JSVAL_IS_NUMBER(rtmp)) { \
ok = js_NewNumberValue(cx, d, &rtmp); \
rtmp = js_NewWeakNumberValue(cx, d); \
ok = (rtmp != JSVAL_NULL); \
if (!ok) \
goto out; \
} \
*vp = rtmp; \
(cs->format & JOF_INC) ? d++ : d--; \
ok = js_NewNumberValue(cx, d, &rval); \
rval = js_NewWeakNumberValue(cx, d); \
} else { \
(cs->format & JOF_INC) ? ++d : --d; \
ok = js_NewNumberValue(cx, d, &rval); \
rval = js_NewWeakNumberValue(cx, d); \
rtmp = rval; \
} \
ok = (rval != JSVAL_NULL); \
if (!ok) \
goto out; \
JS_END_MACRO

View File

@ -165,7 +165,8 @@ math_atan2(JSContext *cx, uintN argc, jsval *vp)
z = fd_copysign(M_PI / 4, x);
if (y < 0)
z *= 3;
return js_NewDoubleValue(cx, z, vp);
*vp = js_NewUnrootedDoubleValue(cx, z);
return *vp != JSVAL_NULL;
}
#endif
z = fd_atan2(x, y);

View File

@ -167,7 +167,6 @@ static JSBool
Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
jsdouble d;
jsval v;
if (argc != 0) {
if (!js_ValueToNumber(cx, argv[0], &d))
@ -175,14 +174,10 @@ Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
} else {
d = 0.0;
}
if (!js_NewNumberValue(cx, d, &v))
return JS_FALSE;
if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
*rval = v;
return JS_TRUE;
}
OBJ_SET_SLOT(cx, obj, JSSLOT_PRIVATE, v);
return JS_TRUE;
return js_NewNumberValue(cx, d,
!(cx->fp->flags & JSFRAME_CONSTRUCTING)
? rval
: STOBJ_FIXED_SLOT_PTR(obj, JSSLOT_PRIVATE));
}
#if JS_HAS_TOSOURCE
@ -538,6 +533,7 @@ js_InitRuntimeNumberState(JSContext *cx)
{
JSRuntime *rt;
jsdpun u;
jsval v;
struct lconv *locale;
rt = cx->runtime;
@ -548,23 +544,26 @@ js_InitRuntimeNumberState(JSContext *cx)
u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK;
u.s.lo = 0xffffffff;
number_constants[NC_NaN].dval = NaN = u.d;
rt->jsNaN = js_NewDouble(cx, NaN, GCF_LOCK);
if (!rt->jsNaN)
v = js_NewUnrootedDoubleValue(cx, NaN);
if (v == JSVAL_NULL)
return JS_FALSE;
rt->jsNaN = JSVAL_TO_DOUBLE(v);
u.s.hi = JSDOUBLE_HI32_EXPMASK;
u.s.lo = 0x00000000;
number_constants[NC_POSITIVE_INFINITY].dval = u.d;
rt->jsPositiveInfinity = js_NewDouble(cx, u.d, GCF_LOCK);
if (!rt->jsPositiveInfinity)
v = js_NewUnrootedDoubleValue(cx, u.d);
if (v == JSVAL_NULL)
return JS_FALSE;
rt->jsPositiveInfinity = JSVAL_TO_DOUBLE(v);
u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK;
u.s.lo = 0x00000000;
number_constants[NC_NEGATIVE_INFINITY].dval = u.d;
rt->jsNegativeInfinity = js_NewDouble(cx, u.d, GCF_LOCK);
if (!rt->jsNegativeInfinity)
v = js_NewUnrootedDoubleValue(cx, u.d);
if (v == JSVAL_NULL)
return JS_FALSE;
rt->jsNegativeInfinity = JSVAL_TO_DOUBLE(v);
u.s.hi = 0;
u.s.lo = 1;
@ -581,15 +580,25 @@ js_InitRuntimeNumberState(JSContext *cx)
return rt->thousandsSeparator && rt->decimalSeparator && rt->numGrouping;
}
void
js_TraceRuntimeNumberState(JSTracer *trc)
{
JSRuntime *rt;
rt = trc->context->runtime;
if (rt->jsNaN)
JS_CALL_DOUBLE_TRACER(trc, rt->jsNaN, "NaN");
if (rt->jsPositiveInfinity)
JS_CALL_DOUBLE_TRACER(trc, rt->jsPositiveInfinity, "+Infinity");
if (rt->jsNegativeInfinity)
JS_CALL_DOUBLE_TRACER(trc, rt->jsNegativeInfinity, "-Infinity");
}
void
js_FinishRuntimeNumberState(JSContext *cx)
{
JSRuntime *rt = cx->runtime;
js_UnlockGCThingRT(rt, rt->jsNaN);
js_UnlockGCThingRT(rt, rt->jsNegativeInfinity);
js_UnlockGCThingRT(rt, rt->jsPositiveInfinity);
rt->jsNaN = NULL;
rt->jsNegativeInfinity = NULL;
rt->jsPositiveInfinity = NULL;
@ -637,47 +646,41 @@ js_InitNumberClass(JSContext *cx, JSObject *obj)
}
jsdouble *
js_NewDouble(JSContext *cx, jsdouble d, uintN gcflag)
js_NewWeaklyRootedDouble(JSContext *cx, jsdouble d)
{
jsdouble *dp;
jsval v;
dp = (jsdouble *) js_NewGCThing(cx, gcflag | GCX_DOUBLE, sizeof(jsdouble));
if (!dp)
v = js_NewUnrootedDoubleValue(cx, d);
if (v == JSVAL_NULL || !js_WeaklyRootDouble(cx, v))
return NULL;
*dp = d;
return dp;
}
void
js_FinalizeDouble(JSContext *cx, jsdouble *dp)
{
*dp = NaN;
return JSVAL_TO_DOUBLE(v);
}
JSBool
js_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
{
jsdouble *dp;
dp = js_NewDouble(cx, d, 0);
if (!dp)
return JS_FALSE;
*rval = DOUBLE_TO_JSVAL(dp);
return JS_TRUE;
}
JSBool
js_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
js_NewNumberValue(JSContext *cx, jsdouble d, jsval *vp)
{
jsint i;
if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
*rval = INT_TO_JSVAL(i);
} else {
if (!js_NewDoubleValue(cx, d, rval))
return JS_FALSE;
*vp = INT_TO_JSVAL(i);
return JS_TRUE;
}
return JS_TRUE;
*vp = js_NewUnrootedDoubleValue(cx, d);
return *vp != JSVAL_VOID;
}
jsval
js_NewWeakNumberValue(JSContext *cx, jsdouble d)
{
jsint i;
jsval v;
if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i))
return INT_TO_JSVAL(i);
v = js_NewUnrootedDoubleValue(cx, d);
if (v != JSVAL_NULL && !js_WeaklyRootDouble(cx, v))
v = JSVAL_NULL;
return v;
}
char *

View File

@ -146,6 +146,9 @@ typedef union jsdpun {
extern JSBool
js_InitRuntimeNumberState(JSContext *cx);
extern void
js_TraceRuntimeNumberState(JSTracer *trc);
extern void
js_FinishRuntimeNumberState(JSContext *cx);
@ -165,18 +168,29 @@ extern const char js_isFinite_str[];
extern const char js_parseFloat_str[];
extern const char js_parseInt_str[];
/* GC-allocate a new JS number. */
extern jsdouble *
js_NewDouble(JSContext *cx, jsdouble d, uintN gcflag);
extern void
js_FinalizeDouble(JSContext *cx, jsdouble *dp);
extern JSBool
js_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval);
/*
* Create a new double value corresponding to d. The result is weakly rooted.
*/
extern jsdouble *
js_NewWeaklyRootedDouble(JSContext *cx, jsdouble d);
/*
* Set *vp to int or double value corresponding to d.
*
* vp must be a root.
*/
extern JSBool
js_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval);
js_NewNumberValue(JSContext *cx, jsdouble d, jsval *vp);
/*
* If d is int, return it as jsval. Otherwise allocate a new double, weakly
* root and return it as jsval. Returns JSVAL_NULL when the allocation fails.
*/
extern jsval
js_NewWeakNumberValue(JSContext *cx, jsdouble d);
/* Convert a number to a GC'ed string. */
extern JSString *

View File

@ -142,6 +142,9 @@ struct JSObject {
#define STOBJ_NSLOTS(obj) \
((obj)->dslots ? (uint32)(obj)->dslots[-1] : (uint32)JS_INITIAL_NSLOTS)
#define STOBJ_FIXED_SLOT_PTR(obj, slot) \
(JS_ASSERT((slot) < JS_INITIAL_NSLOTS), &(obj)->fslots[(slot)])
#define STOBJ_GET_SLOT(obj,slot) \
((slot) < JS_INITIAL_NSLOTS \
? (obj)->fslots[(slot)] \

View File

@ -4319,7 +4319,7 @@ js_SetLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex)
{
jsval v;
return js_NewNumberValue(cx, lastIndex, &v) &&
JS_SetReservedSlot(cx, obj, 0, v);
v = js_NewWeakNumberValue(cx, lastIndex);
return v != JSVAL_NULL && JS_SetReservedSlot(cx, obj, 0, v);
}