зеркало из 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_FreeRuntimeScriptState(rt);
|
||||||
js_FinishAtomState(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
|
* Finish the deflated string cache after the last GC and after
|
||||||
* calling js_FinishAtomState, which finalizes strings.
|
* calling js_FinishAtomState, which finalizes strings.
|
||||||
|
|
|
@ -566,21 +566,6 @@ js_TraceAtomState(JSTracer *trc, JSBool allAtoms)
|
||||||
} else {
|
} else {
|
||||||
JS_DHashTableEnumerate(&state->stringAtoms, js_pinned_atom_tracer, trc);
|
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
|
static JSDHashOperator
|
||||||
|
@ -688,10 +673,8 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
||||||
|
|
||||||
if (str->length() == 1) {
|
if (str->length() == 1) {
|
||||||
jschar c = str->chars()[0];
|
jschar c = str->chars()[0];
|
||||||
if (c < UNIT_STRING_LIMIT) {
|
if (c < UNIT_STRING_LIMIT)
|
||||||
JSString *str = JSString::getUnitString(cx, c);
|
return (JSAtom *) STRING_TO_JSVAL(JSString::unitString(c));
|
||||||
return str ? (JSAtom *) STRING_TO_JSVAL(str) : NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state = &cx->runtime->atomState;
|
state = &cx->runtime->atomState;
|
||||||
|
@ -826,10 +809,8 @@ js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
|
||||||
|
|
||||||
if (length == 1) {
|
if (length == 1) {
|
||||||
jschar c = *chars;
|
jschar c = *chars;
|
||||||
if (c < UNIT_STRING_LIMIT) {
|
if (c < UNIT_STRING_LIMIT)
|
||||||
JSString *str = JSString::getUnitString(cx, c);
|
return (JSAtom *) STRING_TO_JSVAL(JSString::unitString(c));
|
||||||
return str ? (JSAtom *) STRING_TO_JSVAL(str) : NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
str.initFlat((jschar *)chars, length);
|
str.initFlat((jschar *)chars, length);
|
||||||
|
|
|
@ -485,12 +485,7 @@ struct JSRuntime {
|
||||||
uint32 deflatedStringCacheBytes;
|
uint32 deflatedStringCacheBytes;
|
||||||
#endif
|
#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 *emptyString;
|
||||||
JSString **unitStrings;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Builtin functions, lazily created and held for use by the trace recorder.
|
* 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:
|
case JSTRACE_STRING:
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
if (JSString::isStatic((JSString *)thing))
|
||||||
|
goto out;
|
||||||
flagp = THING_TO_FLAGP(thing, sizeof(JSGCThing));
|
flagp = THING_TO_FLAGP(thing, sizeof(JSGCThing));
|
||||||
JS_ASSERT((*flagp & GCF_FINAL) == 0);
|
JS_ASSERT((*flagp & GCF_FINAL) == 0);
|
||||||
JS_ASSERT(kind == MapGCFlagsToTraceKind(*flagp));
|
JS_ASSERT(kind == MapGCFlagsToTraceKind(*flagp));
|
||||||
|
@ -3233,6 +3235,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str, intN type, JSContext *cx)
|
||||||
JSStringFinalizeOp finalizer;
|
JSStringFinalizeOp finalizer;
|
||||||
|
|
||||||
JS_RUNTIME_UNMETER(rt, liveStrings);
|
JS_RUNTIME_UNMETER(rt, liveStrings);
|
||||||
|
JS_ASSERT(!JSString::isStatic(str));
|
||||||
if (str->isDependent()) {
|
if (str->isDependent()) {
|
||||||
/* A dependent string can not be external and must be valid. */
|
/* A dependent string can not be external and must be valid. */
|
||||||
JS_ASSERT(type < 0);
|
JS_ASSERT(type < 0);
|
||||||
|
@ -3244,11 +3247,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str, intN type, JSContext *cx)
|
||||||
chars = str->flatChars();
|
chars = str->flatChars();
|
||||||
valid = (chars != NULL);
|
valid = (chars != NULL);
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (IN_UNIT_STRING_SPACE_RT(rt, chars)) {
|
if (type < 0) {
|
||||||
JS_ASSERT(rt->unitStrings[*chars] == str);
|
|
||||||
JS_ASSERT(type < 0);
|
|
||||||
rt->unitStrings[*chars] = NULL;
|
|
||||||
} else if (type < 0) {
|
|
||||||
if (cx)
|
if (cx)
|
||||||
cx->free(chars);
|
cx->free(chars);
|
||||||
else
|
else
|
||||||
|
|
|
@ -860,6 +860,12 @@ NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
|
||||||
JSString * JS_FASTCALL
|
JSString * JS_FASTCALL
|
||||||
js_NumberToString(JSContext *cx, jsdouble d)
|
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);
|
return NumberToStringWithBase(cx, d, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2391,6 +2391,8 @@ static JSFunctionSpec string_methods[] = {
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include "jsstatic.cpp"
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
js_String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
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);
|
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||||
if (argc == 1 &&
|
if (argc == 1 &&
|
||||||
(code = js_ValueToUint16(cx, &argv[0])) < UNIT_STRING_LIMIT) {
|
(code = js_ValueToUint16(cx, &argv[0])) < UNIT_STRING_LIMIT) {
|
||||||
str = JSString::getUnitString(cx, code);
|
str = JSString::unitString(code);
|
||||||
if (!str)
|
if (!str)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
*vp = STRING_TO_JSVAL(str);
|
*vp = STRING_TO_JSVAL(str);
|
||||||
|
@ -2476,7 +2478,7 @@ String_fromCharCode(JSContext* cx, int32 i)
|
||||||
JS_ASSERT(JS_ON_TRACE(cx));
|
JS_ASSERT(JS_ON_TRACE(cx));
|
||||||
jschar c = (jschar)i;
|
jschar c = (jschar)i;
|
||||||
if (c < UNIT_STRING_LIMIT)
|
if (c < UNIT_STRING_LIMIT)
|
||||||
return JSString::getUnitString(cx, c);
|
return JSString::unitString(c);
|
||||||
return js_NewStringCopyN(cx, &c, 1);
|
return js_NewStringCopyN(cx, &c, 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2528,64 +2530,6 @@ js_InitDeflatedStringCache(JSRuntime *rt)
|
||||||
return JS_TRUE;
|
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
|
void
|
||||||
js_FinishRuntimeStringState(JSContext *cx)
|
js_FinishRuntimeStringState(JSContext *cx)
|
||||||
{
|
{
|
||||||
|
@ -3379,6 +3323,16 @@ js_GetStringBytes(JSContext *cx, JSString *str)
|
||||||
JSHashNumber hash;
|
JSHashNumber hash;
|
||||||
JSHashEntry *he, **hep;
|
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) {
|
if (cx) {
|
||||||
rt = cx->runtime;
|
rt = cx->runtime;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -55,35 +55,22 @@
|
||||||
|
|
||||||
JS_BEGIN_EXTERN_C
|
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_BIT(n) ((size_t)1 << (n))
|
||||||
#define JSSTRING_BITMASK(n) (JSSTRING_BIT(n) - 1)
|
#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;
|
class TraceRecorder;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
UNIT_STRING_LIMIT = 256U,
|
||||||
|
INT_STRING_LIMIT = 256U,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern JSString js_UnitStrings[];
|
||||||
|
extern JSString js_IntStrings[];
|
||||||
|
|
||||||
extern jschar *
|
extern jschar *
|
||||||
js_GetDependentStringChars(JSString *str);
|
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.
|
* The GC-thing "string" type.
|
||||||
*
|
*
|
||||||
|
@ -132,7 +119,6 @@ struct JSString {
|
||||||
friend JSString * JS_FASTCALL
|
friend JSString * JS_FASTCALL
|
||||||
js_ConcatStrings(JSContext *cx, JSString *left, JSString *right);
|
js_ConcatStrings(JSContext *cx, JSString *left, JSString *right);
|
||||||
|
|
||||||
private:
|
|
||||||
size_t mLength;
|
size_t mLength;
|
||||||
union {
|
union {
|
||||||
jschar *mChars;
|
jschar *mChars;
|
||||||
|
@ -377,8 +363,13 @@ public:
|
||||||
JS_ASSERT(isDependent() && dependentIsPrefix());
|
JS_ASSERT(isDependent() && dependentIsPrefix());
|
||||||
mBase = bstr;
|
mBase = bstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 *getUnitString(JSContext *cx, jschar c);
|
static JSString *unitString(jschar c);
|
||||||
static JSString *getUnitString(JSContext *cx, JSString *str, size_t index);
|
static JSString *getUnitString(JSContext *cx, JSString *str, size_t index);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -559,9 +550,6 @@ js_InitRuntimeStringState(JSContext *cx);
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_InitDeflatedStringCache(JSRuntime *rt);
|
js_InitDeflatedStringCache(JSRuntime *rt);
|
||||||
|
|
||||||
extern void
|
|
||||||
js_FinishUnitStrings(JSRuntime *rt);
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
js_FinishRuntimeStringState(JSContext *cx);
|
js_FinishRuntimeStringState(JSContext *cx);
|
||||||
|
|
||||||
|
|
|
@ -45,15 +45,10 @@
|
||||||
JS_BEGIN_EXTERN_C
|
JS_BEGIN_EXTERN_C
|
||||||
|
|
||||||
inline JSString *
|
inline JSString *
|
||||||
JSString::getUnitString(JSContext *cx, jschar c)
|
JSString::unitString(jschar c)
|
||||||
{
|
{
|
||||||
JS_ASSERT(c < UNIT_STRING_LIMIT);
|
JS_ASSERT(c < UNIT_STRING_LIMIT);
|
||||||
JSRuntime *rt = cx->runtime;
|
return js_UnitStrings + c;
|
||||||
JSString **unitStrings = rt->unitStrings;
|
|
||||||
JSString *ustr;
|
|
||||||
if (unitStrings && (ustr = unitStrings[c]) != NULL)
|
|
||||||
return ustr;
|
|
||||||
return js_MakeUnitString(cx, c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline JSString *
|
inline JSString *
|
||||||
|
@ -61,9 +56,9 @@ JSString::getUnitString(JSContext *cx, JSString *str, size_t index)
|
||||||
{
|
{
|
||||||
JS_ASSERT(index < str->length());
|
JS_ASSERT(index < str->length());
|
||||||
jschar c = str->chars()[index];
|
jschar c = str->chars()[index];
|
||||||
if (c >= UNIT_STRING_LIMIT)
|
if (c < UNIT_STRING_LIMIT)
|
||||||
return js_NewDependentString(cx, str, index, 1);
|
return unitString(c);
|
||||||
return getUnitString(cx, c);
|
return js_NewDependentString(cx, str, index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_END_EXTERN_C
|
JS_END_EXTERN_C
|
||||||
|
|
Загрузка…
Ссылка в новой задаче