Cache result of Number2String (bug 513530, r=brendan).

This commit is contained in:
Gregor Wagner 2009-09-04 16:28:30 -07:00
Родитель 27a42a3eaf
Коммит 623555909f
8 изменённых файлов: 47 добавлений и 136 удалений

Просмотреть файл

@ -867,13 +867,6 @@ JS_DestroyRuntime(JSRuntime *rt)
js_FreeRuntimeScriptState(rt);
js_FinishAtomState(rt);
/*
* Free unit string storage only after all strings have been finalized, so
* that js_FinalizeString can detect unit strings and avoid calling free
* on their chars storage.
*/
js_FinishUnitStrings(rt);
/*
* Finish the deflated string cache after the last GC and after
* calling js_FinishAtomState, which finalizes strings.

Просмотреть файл

@ -566,21 +566,6 @@ js_TraceAtomState(JSTracer *trc, JSBool allAtoms)
} else {
JS_DHashTableEnumerate(&state->stringAtoms, js_pinned_atom_tracer, trc);
}
if (rt->state != JSRTS_LANDING) {
/*
* Unit strings aren't in state->stringAtoms, so we mark any that have
* been created on demand. This bloats more than strictly necessary but
* we can't help that without putting unit atoms in state->stringAtoms,
* which is too expensive.
*/
for (uintN i = 0; i < UNIT_STRING_LIMIT; i++) {
if (JSString *str = rt->unitStrings[i]) {
JS_SET_TRACING_INDEX(trc, "unit_string_atom", i);
JS_CallTracer(trc, str, JSTRACE_STRING);
}
}
}
}
static JSDHashOperator
@ -688,10 +673,8 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
if (str->length() == 1) {
jschar c = str->chars()[0];
if (c < UNIT_STRING_LIMIT) {
JSString *str = JSString::getUnitString(cx, c);
return str ? (JSAtom *) STRING_TO_JSVAL(str) : NULL;
}
if (c < UNIT_STRING_LIMIT)
return (JSAtom *) STRING_TO_JSVAL(JSString::unitString(c));
}
state = &cx->runtime->atomState;
@ -826,10 +809,8 @@ js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
if (length == 1) {
jschar c = *chars;
if (c < UNIT_STRING_LIMIT) {
JSString *str = JSString::getUnitString(cx, c);
return str ? (JSAtom *) STRING_TO_JSVAL(str) : NULL;
}
if (c < UNIT_STRING_LIMIT)
return (JSAtom *) STRING_TO_JSVAL(JSString::unitString(c));
}
str.initFlat((jschar *)chars, length);

Просмотреть файл

@ -485,12 +485,7 @@ struct JSRuntime {
uint32 deflatedStringCacheBytes;
#endif
/*
* Empty and unit-length strings held for use by this runtime's contexts.
* The unitStrings array and its elements are created on demand.
*/
JSString *emptyString;
JSString **unitStrings;
/*
* Builtin functions, lazily created and held for use by the trace recorder.

Просмотреть файл

@ -2638,6 +2638,8 @@ JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
case JSTRACE_STRING:
for (;;) {
if (JSString::isStatic((JSString *)thing))
goto out;
flagp = THING_TO_FLAGP(thing, sizeof(JSGCThing));
JS_ASSERT((*flagp & GCF_FINAL) == 0);
JS_ASSERT(kind == MapGCFlagsToTraceKind(*flagp));
@ -3233,6 +3235,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str, intN type, JSContext *cx)
JSStringFinalizeOp finalizer;
JS_RUNTIME_UNMETER(rt, liveStrings);
JS_ASSERT(!JSString::isStatic(str));
if (str->isDependent()) {
/* A dependent string can not be external and must be valid. */
JS_ASSERT(type < 0);
@ -3244,11 +3247,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str, intN type, JSContext *cx)
chars = str->flatChars();
valid = (chars != NULL);
if (valid) {
if (IN_UNIT_STRING_SPACE_RT(rt, chars)) {
JS_ASSERT(rt->unitStrings[*chars] == str);
JS_ASSERT(type < 0);
rt->unitStrings[*chars] = NULL;
} else if (type < 0) {
if (type < 0) {
if (cx)
cx->free(chars);
else

Просмотреть файл

@ -860,6 +860,12 @@ NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
JSString * JS_FASTCALL
js_NumberToString(JSContext *cx, jsdouble d)
{
jsint i;
if (JSDOUBLE_IS_INT(d, i)) {
if (jsuint(i) < INT_STRING_LIMIT)
return &js_IntStrings[i];
}
return NumberToStringWithBase(cx, d, 10);
}

Просмотреть файл

@ -2391,6 +2391,8 @@ static JSFunctionSpec string_methods[] = {
JS_FS_END
};
#include "jsstatic.cpp"
JSBool
js_String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
@ -2442,7 +2444,7 @@ str_fromCharCode(JSContext *cx, uintN argc, jsval *vp)
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
if (argc == 1 &&
(code = js_ValueToUint16(cx, &argv[0])) < UNIT_STRING_LIMIT) {
str = JSString::getUnitString(cx, code);
str = JSString::unitString(code);
if (!str)
return JS_FALSE;
*vp = STRING_TO_JSVAL(str);
@ -2476,7 +2478,7 @@ String_fromCharCode(JSContext* cx, int32 i)
JS_ASSERT(JS_ON_TRACE(cx));
jschar c = (jschar)i;
if (c < UNIT_STRING_LIMIT)
return JSString::getUnitString(cx, c);
return JSString::unitString(c);
return js_NewStringCopyN(cx, &c, 1);
}
#endif
@ -2528,64 +2530,6 @@ js_InitDeflatedStringCache(JSRuntime *rt)
return JS_TRUE;
}
JSString *
js_MakeUnitString(JSContext *cx, jschar c)
{
jschar *cp, i;
JSRuntime *rt;
JSString **sp;
JS_ASSERT(c < UNIT_STRING_LIMIT);
rt = cx->runtime;
if (!rt->unitStrings) {
sp = (JSString **) js_calloc(UNIT_STRING_LIMIT * sizeof(JSString *) +
UNIT_STRING_LIMIT * 2 * sizeof(jschar));
if (!sp) {
JS_ReportOutOfMemory(cx);
return NULL;
}
cp = UNIT_STRING_SPACE(sp);
for (i = 0; i < UNIT_STRING_LIMIT; i++) {
*cp = i;
cp += 2;
}
JS_LOCK_GC(rt);
if (!rt->unitStrings) {
rt->unitStrings = sp;
JS_UNLOCK_GC(rt);
} else {
JS_UNLOCK_GC(rt);
js_free(sp);
}
}
if (!rt->unitStrings[c]) {
JSString *str;
cp = UNIT_STRING_SPACE_RT(rt);
str = js_NewString(cx, cp + 2 * c, 1);
if (!str)
return NULL;
JS_LOCK_GC(rt);
if (!rt->unitStrings[c]) {
str->flatSetAtomized();
rt->unitStrings[c] = str;
}
#ifdef DEBUG
else
str->initFlat(NULL, 0); /* avoid later assertion (bug 479381) */
#endif
JS_UNLOCK_GC(rt);
}
return rt->unitStrings[c];
}
void
js_FinishUnitStrings(JSRuntime *rt)
{
js_free(rt->unitStrings);
rt->unitStrings = NULL;
}
void
js_FinishRuntimeStringState(JSContext *cx)
{
@ -3379,6 +3323,16 @@ js_GetStringBytes(JSContext *cx, JSString *str)
JSHashNumber hash;
JSHashEntry *he, **hep;
if (JSString::isStatic(str)) {
#ifdef IS_LITTLE_ENDIAN
/* Unit string data is {c, 0, 0, 0} so we can just cast. */
return (char *)str->chars();
#else
/* Unit string data is {0, c, 0, 0} so we can point into the middle. */
return (char *)str->chars() + 1;
#endif
}
if (cx) {
rt = cx->runtime;
} else {

Просмотреть файл

@ -55,35 +55,22 @@
JS_BEGIN_EXTERN_C
/*
* Maximum character code for which we will create a pinned unit string on
* demand -- see JSRuntime.unitStrings in jscntxt.h.
*/
#define UNIT_STRING_LIMIT 256U
#define JSSTRING_BIT(n) ((size_t)1 << (n))
#define JSSTRING_BITMASK(n) (JSSTRING_BIT(n) - 1)
#define UNIT_STRING_SPACE(sp) ((jschar *) ((sp) + UNIT_STRING_LIMIT))
#define UNIT_STRING_SPACE_RT(rt) UNIT_STRING_SPACE((rt)->unitStrings)
#define IN_UNIT_STRING_SPACE(sp,cp) \
((size_t)((cp) - UNIT_STRING_SPACE(sp)) < 2 * UNIT_STRING_LIMIT)
#define IN_UNIT_STRING_SPACE_RT(rt,cp) \
IN_UNIT_STRING_SPACE((rt)->unitStrings, cp)
class TraceRecorder;
enum {
UNIT_STRING_LIMIT = 256U,
INT_STRING_LIMIT = 256U,
};
extern JSString js_UnitStrings[];
extern JSString js_IntStrings[];
extern jschar *
js_GetDependentStringChars(JSString *str);
/*
* Make the independent string containing only the character code c, which must
* be less than UNIT_STRING_LIMIT, and cache it in the runtime.
*/
extern JSString *
js_MakeUnitString(JSContext *cx, jschar c);
/*
* The GC-thing "string" type.
*
@ -132,7 +119,6 @@ struct JSString {
friend JSString * JS_FASTCALL
js_ConcatStrings(JSContext *cx, JSString *left, JSString *right);
private:
size_t mLength;
union {
jschar *mChars;
@ -378,7 +364,12 @@ public:
mBase = bstr;
}
static JSString *getUnitString(JSContext *cx, jschar c);
static inline bool isStatic(JSString *s) {
return (s >= js_UnitStrings && s < &js_UnitStrings[UNIT_STRING_LIMIT]) ||
(s >= js_IntStrings && s < &js_IntStrings[INT_STRING_LIMIT]);
}
static JSString *unitString(jschar c);
static JSString *getUnitString(JSContext *cx, JSString *str, size_t index);
};
@ -559,9 +550,6 @@ js_InitRuntimeStringState(JSContext *cx);
extern JSBool
js_InitDeflatedStringCache(JSRuntime *rt);
extern void
js_FinishUnitStrings(JSRuntime *rt);
extern void
js_FinishRuntimeStringState(JSContext *cx);

Просмотреть файл

@ -45,15 +45,10 @@
JS_BEGIN_EXTERN_C
inline JSString *
JSString::getUnitString(JSContext *cx, jschar c)
JSString::unitString(jschar c)
{
JS_ASSERT(c < UNIT_STRING_LIMIT);
JSRuntime *rt = cx->runtime;
JSString **unitStrings = rt->unitStrings;
JSString *ustr;
if (unitStrings && (ustr = unitStrings[c]) != NULL)
return ustr;
return js_MakeUnitString(cx, c);
return js_UnitStrings + c;
}
inline JSString *
@ -61,9 +56,9 @@ JSString::getUnitString(JSContext *cx, JSString *str, size_t index)
{
JS_ASSERT(index < str->length());
jschar c = str->chars()[index];
if (c >= UNIT_STRING_LIMIT)
return js_NewDependentString(cx, str, index, 1);
return getUnitString(cx, c);
if (c < UNIT_STRING_LIMIT)
return unitString(c);
return js_NewDependentString(cx, str, index, 1);
}
JS_END_EXTERN_C