diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index e4fc1b8553fb..91ee00f02988 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -533,8 +533,6 @@ JSThreadData::purge(JSContext *cx) /* FIXME: bug 506341. */ propertyCache.purge(cx); - - dtoaCache.s = NULL; } #ifdef JS_THREADSAFE diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 18dc62a2a7e5..789ea75f537e 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -892,20 +892,6 @@ struct JSThreadData { /* State used by dtoa.c. */ DtoaState *dtoaState; - /* - * A single-entry cache for some base-10 double-to-string conversions. - * This helps date-format-xparb.js. It also avoids skewing the results - * for v8-splay.js when measured by the SunSpider harness, where the splay - * tree initialization (which includes many repeated double-to-string - * conversions) is erroneously included in the measurement; see bug - * 562553. - */ - struct { - jsdouble d; - jsint base; - JSString *s; // if s==NULL, d and base are not valid - } dtoaCache; - /* Base address of the native stack for the current thread. */ jsuword *nativeStackBase; diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 537cd73bddc1..1a0389f75a3f 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -451,6 +451,7 @@ void JSCompartment::purge(JSContext *cx) { freeLists.purge(); + dtoaCache.purge(); /* Destroy eval'ed scripts. */ js_DestroyScriptsToGC(cx, this); diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index a8882adc03e9..8ac777bec301 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -332,6 +332,33 @@ class NativeIterCache { } }; +/* + * A single-entry cache for some base-10 double-to-string conversions. This + * helps date-format-xparb.js. It also avoids skewing the results for + * v8-splay.js when measured by the SunSpider harness, where the splay tree + * initialization (which includes many repeated double-to-string conversions) + * is erroneously included in the measurement; see bug 562553. + */ +class DtoaCache { + double d; + jsint base; + JSString *s; // if s==NULL, d and base are not valid + public: + DtoaCache() : s(NULL) {} + void purge() { s = NULL; } + + JSString *lookup(jsint base, double d) { + return this->s && base == this->base && d == this->d ? this->s : NULL; + } + + void cache(jsint base, double d, JSString *s) { + this->base = base; + this->d = d; + this->s = s; + } + +}; + } /* namespace js */ struct JS_FRIEND_API(JSCompartment) { @@ -401,6 +428,8 @@ struct JS_FRIEND_API(JSCompartment) { void setGCLastBytes(size_t lastBytes); + js::DtoaCache dtoaCache; + private: js::MathCache *mathCache; diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index e6c0c0a889c3..7fab6209ae03 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -603,17 +603,15 @@ js_IntToString(JSContext *cx, int32 si) if (si >= 0) { if (si < INT_STRING_LIMIT) return JSString::intString(si); - if (si < 100) - return JSString::length2String(si); ui = si; } else { ui = uint32(-si); JS_ASSERT_IF(si == INT32_MIN, ui == uint32(INT32_MAX) + 1); } - JSThreadData *data = JS_THREAD_DATA(cx); - if (data->dtoaCache.s && data->dtoaCache.base == 10 && data->dtoaCache.d == si) - return data->dtoaCache.s; + JSCompartment *c = cx->compartment; + if (JSString *str = c->dtoaCache.lookup(10, si)) + return str; JSShortString *str = js_NewGCShortString(cx); if (!str) @@ -638,9 +636,7 @@ js_IntToString(JSContext *cx, int32 si) str->initAtOffsetInBuffer(cp, end - cp); JSString *ret = str->header(); - data->dtoaCache.base = 10; - data->dtoaCache.d = si; - data->dtoaCache.s = ret; + c->dtoaCache.cache(10, si, ret); return ret; } @@ -1156,7 +1152,6 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base) ToCStringBuf cbuf; char *numStr; JSString *s; - JSThreadData *data; /* * Caller is responsible for error reporting. When called from trace, @@ -1166,6 +1161,8 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base) if (base < 2 || base > 36) return NULL; + JSCompartment *c = cx->compartment; + int32_t i; if (JSDOUBLE_IS_INT32(d, &i)) { if (base == 10 && jsuint(i) < INT_STRING_LIMIT) @@ -1176,16 +1173,14 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base) return JSString::unitString(jschar('a' + i - 10)); } - data = JS_THREAD_DATA(cx); - if (data->dtoaCache.s && data->dtoaCache.base == base && data->dtoaCache.d == d) - return data->dtoaCache.s; + if (JSString *str = c->dtoaCache.lookup(base, d)) + return str; numStr = IntToCString(&cbuf, i, base); JS_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize); } else { - data = JS_THREAD_DATA(cx); - if (data->dtoaCache.s && data->dtoaCache.base == base && data->dtoaCache.d == d) - return data->dtoaCache.s; + if (JSString *str = c->dtoaCache.lookup(base, d)) + return str; numStr = FracNumberToCString(cx, &cbuf, d, base); if (!numStr) { @@ -1200,10 +1195,7 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base) s = js_NewStringCopyZ(cx, numStr); - data->dtoaCache.base = base; - data->dtoaCache.d = d; - data->dtoaCache.s = s; - + c->dtoaCache.cache(base, d, s); return s; }