зеркало из https://github.com/mozilla/gecko-dev.git
Cache result of Number2String (bug 513530, r=brendan).
This commit is contained in:
Родитель
27a42a3eaf
Коммит
623555909f
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче