Bug 331456: Cache of deflated string bytes is per runtime now. To preserve
API compatibility JS_GetStringBytes(JSString *str) calls newly introduced js_GetGCStringRuntime(JSString *str) to extract JSRuntime* instance based on the layout of GC structures. r=brendan
This commit is contained in:
Родитель
04cfde2d6f
Коммит
703d1c3337
|
@ -663,8 +663,6 @@ JS_NewRuntime(uint32 maxbytes)
|
|||
JS_END_MACRO;
|
||||
#endif /* DEBUG */
|
||||
|
||||
if (!js_InitStringGlobals())
|
||||
return NULL;
|
||||
rt = (JSRuntime *) malloc(sizeof(JSRuntime));
|
||||
if (!rt)
|
||||
return NULL;
|
||||
|
@ -764,7 +762,6 @@ JS_ShutDown(void)
|
|||
{
|
||||
JS_ArenaShutDown();
|
||||
js_FinishDtoa();
|
||||
js_FreeStringGlobals();
|
||||
#ifdef JS_THREADSAFE
|
||||
js_CleanupLocks();
|
||||
#endif
|
||||
|
@ -4259,7 +4256,7 @@ JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
|
|||
}
|
||||
|
||||
/* Hand off bytes to the deflated string cache, if possible. */
|
||||
if (!js_SetStringBytes(str, bytes, nbytes))
|
||||
if (!js_SetStringBytes(cx->runtime, str, bytes, nbytes))
|
||||
JS_free(cx, bytes);
|
||||
return str;
|
||||
}
|
||||
|
@ -4356,9 +4353,11 @@ JS_InternUCString(JSContext *cx, const jschar *s)
|
|||
JS_PUBLIC_API(char *)
|
||||
JS_GetStringBytes(JSString *str)
|
||||
{
|
||||
JSRuntime *rt;
|
||||
char *bytes;
|
||||
|
||||
bytes = js_GetStringBytes(str);
|
||||
rt = js_GetGCStringRuntime(str);
|
||||
bytes = js_GetStringBytes(rt, str);
|
||||
return bytes ? bytes : "";
|
||||
}
|
||||
|
||||
|
|
|
@ -134,6 +134,14 @@ struct JSRuntime {
|
|||
jsdouble *jsNegativeInfinity;
|
||||
jsdouble *jsPositiveInfinity;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JSLock *deflatedStringCacheLock;
|
||||
#endif
|
||||
JSHashTable *deflatedStringCache;
|
||||
#ifdef DEBUG
|
||||
uint32 deflatedStringCacheBytes;
|
||||
#endif
|
||||
|
||||
/* Empty string held for use by this runtime's contexts. */
|
||||
JSString *emptyString;
|
||||
|
||||
|
|
|
@ -1116,7 +1116,7 @@ js_ReportUncaughtException(JSContext *cx)
|
|||
} else {
|
||||
if (vp)
|
||||
vp[1] = STRING_TO_JSVAL(str);
|
||||
bytes = js_GetStringBytes(str);
|
||||
bytes = js_GetStringBytes(cx->runtime, str);
|
||||
}
|
||||
ok = JS_TRUE;
|
||||
|
||||
|
|
|
@ -198,6 +198,9 @@ struct JSGCArena {
|
|||
#define PAGE_INDEX(pi) \
|
||||
((size_t)((pi)->offsetInArena >> GC_PAGE_SHIFT))
|
||||
|
||||
#define THING_TO_PAGE(thing) \
|
||||
((JSGCPageInfo *)((jsuword)(thing) & ~GC_PAGE_MASK))
|
||||
|
||||
/*
|
||||
* Given a thing size n, return the size of the gap from the page start before
|
||||
* the first thing. We know that any n not a power of two packs from
|
||||
|
@ -299,17 +302,33 @@ FinishGCArenaList(JSGCArenaList *arenaList)
|
|||
uint8 *
|
||||
js_GetGCThingFlags(void *thing)
|
||||
{
|
||||
jsuword pageAddress, offsetInArena, thingIndex;
|
||||
JSGCPageInfo *pi;
|
||||
jsuword offsetInArena, thingIndex;
|
||||
|
||||
pageAddress = (jsuword)thing & ~GC_PAGE_MASK;
|
||||
offsetInArena = ((JSGCPageInfo *)pageAddress)->offsetInArena;
|
||||
pi = THING_TO_PAGE(thing);
|
||||
offsetInArena = pi->offsetInArena;
|
||||
JS_ASSERT(offsetInArena < GC_THINGS_SIZE);
|
||||
thingIndex = ((offsetInArena & ~GC_PAGE_MASK) |
|
||||
((jsuword)thing & GC_PAGE_MASK)) / sizeof(JSGCThing);
|
||||
JS_ASSERT(thingIndex < GC_PAGE_SIZE);
|
||||
if (thingIndex >= (offsetInArena & GC_PAGE_MASK))
|
||||
thingIndex += GC_THINGS_SIZE;
|
||||
return (uint8 *)(pageAddress - offsetInArena + thingIndex);
|
||||
return (uint8 *)pi - offsetInArena + thingIndex;
|
||||
}
|
||||
|
||||
JSRuntime*
|
||||
js_GetGCStringRuntime(JSString *str)
|
||||
{
|
||||
JSGCPageInfo *pi;
|
||||
JSGCArenaList *list;
|
||||
|
||||
pi = THING_TO_PAGE(str);
|
||||
list = PAGE_TO_ARENA(pi)->list;
|
||||
|
||||
JS_ASSERT(list->thingSize == sizeof(JSGCThing));
|
||||
JS_ASSERT(GC_FREELIST_INDEX(sizeof(JSGCThing)) == 0);
|
||||
|
||||
return (JSRuntime *)((uint8 *)list - offsetof(JSRuntime, gcArenaList));
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -1425,7 +1444,7 @@ AddThingToUnscannedBag(JSRuntime *rt, void *thing, uint8 *flagp)
|
|||
rt->gcStats.maxunscanned = rt->gcUnscannedBagSize);
|
||||
#endif
|
||||
|
||||
pi = (JSGCPageInfo *) ((jsuword)thing & ~GC_PAGE_MASK);
|
||||
pi = THING_TO_PAGE(thing);
|
||||
arena = PAGE_TO_ARENA(pi);
|
||||
thingSize = arena->list->thingSize;
|
||||
GET_GAP_AND_CHUNK_SPAN(thingSize, thingsPerUnscannedChunk, pageGap);
|
||||
|
@ -2106,7 +2125,7 @@ restart:
|
|||
thing = (JSGCThing *)(firstPage + offset);
|
||||
*flagp = (uint8)(flags | GCF_FINAL);
|
||||
if (type >= GCX_EXTERNAL_STRING)
|
||||
js_PurgeDeflatedStringCache((JSString *)thing);
|
||||
js_PurgeDeflatedStringCache(rt, (JSString *)thing);
|
||||
finalizer(cx, thing);
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,13 @@ JS_BEGIN_EXTERN_C
|
|||
extern uint8 *
|
||||
js_GetGCThingFlags(void *thing);
|
||||
|
||||
/*
|
||||
* The sole purpose of the function is to preserve public API compatibility
|
||||
* in JS_GetStringBytes which takes only single JSString* argument.
|
||||
*/
|
||||
JSRuntime*
|
||||
js_GetGCStringRuntime(JSString *str);
|
||||
|
||||
/* These are compatible with JSDHashEntryStub. */
|
||||
struct JSGCRootHashEntry {
|
||||
JSDHashEntryHdr hdr;
|
||||
|
|
|
@ -309,7 +309,7 @@ num_toLocaleString(JSContext *cx, JSObject *obj, uintN argc,
|
|||
return JS_FALSE;
|
||||
JS_ASSERT(JSVAL_IS_STRING(*rval));
|
||||
numStr = JSVAL_TO_STRING(*rval);
|
||||
num = js_GetStringBytes(numStr);
|
||||
num = js_GetStringBytes(cx->runtime, numStr);
|
||||
|
||||
/* Find bit before the decimal. */
|
||||
dec = strchr(num, '.');
|
||||
|
|
|
@ -633,7 +633,7 @@ ReportNoReturnValue(JSContext *cx, JSTokenStream *ts)
|
|||
|
||||
fun = cx->fp->fun;
|
||||
if (fun->atom) {
|
||||
char *name = js_GetStringBytes(ATOM_TO_STRING(fun->atom));
|
||||
char *name = js_GetStringBytes(cx->runtime, ATOM_TO_STRING(fun->atom));
|
||||
ok = js_ReportCompileErrorNumber(cx, ts,
|
||||
JSREPORT_TS |
|
||||
JSREPORT_WARNING |
|
||||
|
|
115
js/src/jsstr.c
115
js/src/jsstr.c
|
@ -2426,43 +2426,6 @@ static JSFunctionSpec string_static_methods[] = {
|
|||
{0,0,0,0,0}
|
||||
};
|
||||
|
||||
static JSHashTable *deflated_string_cache;
|
||||
#ifdef DEBUG
|
||||
static uint32 deflated_string_cache_bytes;
|
||||
#endif
|
||||
#ifdef JS_THREADSAFE
|
||||
static JSLock *deflated_string_cache_lock;
|
||||
#endif
|
||||
|
||||
JSBool
|
||||
js_InitStringGlobals(void)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
/* Must come through here once in primordial thread to init safely! */
|
||||
if (!deflated_string_cache_lock) {
|
||||
deflated_string_cache_lock = JS_NEW_LOCK();
|
||||
if (!deflated_string_cache_lock)
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
js_FreeStringGlobals()
|
||||
{
|
||||
if (deflated_string_cache) {
|
||||
JS_HashTableDestroy(deflated_string_cache);
|
||||
deflated_string_cache = NULL;
|
||||
}
|
||||
#ifdef JS_THREADSAFE
|
||||
if (deflated_string_cache_lock) {
|
||||
JS_DESTROY_LOCK(deflated_string_cache_lock);
|
||||
deflated_string_cache_lock = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_InitRuntimeStringState(JSContext *cx)
|
||||
{
|
||||
|
@ -2471,21 +2434,38 @@ js_InitRuntimeStringState(JSContext *cx)
|
|||
JSAtom *atom;
|
||||
|
||||
rt = cx->runtime;
|
||||
JS_ASSERT(!rt->emptyString);
|
||||
|
||||
/* Initialize string cache */
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(!rt->deflatedStringCacheLock);
|
||||
rt->deflatedStringCacheLock = JS_NEW_LOCK();
|
||||
if (!rt->deflatedStringCacheLock)
|
||||
return JS_FALSE;
|
||||
#endif
|
||||
|
||||
/* Make a permanently locked empty string. */
|
||||
JS_ASSERT(!rt->emptyString);
|
||||
empty = js_NewStringCopyN(cx, js_empty_ucstr, 0, GCF_LOCK);
|
||||
if (!empty)
|
||||
return JS_FALSE;
|
||||
goto bad;
|
||||
|
||||
/* Atomize it for scripts that use '' + x to convert x to string. */
|
||||
atom = js_AtomizeString(cx, empty, ATOM_PINNED);
|
||||
if (!atom)
|
||||
return JS_FALSE;
|
||||
goto bad;
|
||||
|
||||
rt->emptyString = empty;
|
||||
rt->atomState.emptyAtom = atom;
|
||||
|
||||
return JS_TRUE;
|
||||
|
||||
bad:
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_DESTROY_LOCK(rt->deflatedStringCacheLock);
|
||||
rt->deflatedStringCacheLock = NULL;
|
||||
#endif
|
||||
return JS_FALSE;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2495,6 +2475,17 @@ js_FinishRuntimeStringState(JSContext *cx)
|
|||
|
||||
js_UnlockGCThingRT(rt, rt->emptyString);
|
||||
rt->emptyString = NULL;
|
||||
|
||||
if (rt->deflatedStringCache) {
|
||||
JS_HashTableDestroy(rt->deflatedStringCache);
|
||||
rt->deflatedStringCache = NULL;
|
||||
}
|
||||
#ifdef JS_THREADSAFE
|
||||
if (rt->deflatedStringCacheLock) {
|
||||
JS_DESTROY_LOCK(rt->deflatedStringCacheLock);
|
||||
rt->deflatedStringCacheLock = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
JSObject *
|
||||
|
@ -2673,26 +2664,26 @@ js_hash_string_pointer(const void *key)
|
|||
}
|
||||
|
||||
void
|
||||
js_PurgeDeflatedStringCache(JSString *str)
|
||||
js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str)
|
||||
{
|
||||
JSHashNumber hash;
|
||||
JSHashEntry *he, **hep;
|
||||
|
||||
if (!deflated_string_cache)
|
||||
if (!rt->deflatedStringCache)
|
||||
return;
|
||||
|
||||
hash = js_hash_string_pointer(str);
|
||||
JS_ACQUIRE_LOCK(deflated_string_cache_lock);
|
||||
hep = JS_HashTableRawLookup(deflated_string_cache, hash, str);
|
||||
JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
|
||||
hep = JS_HashTableRawLookup(rt->deflatedStringCache, hash, str);
|
||||
he = *hep;
|
||||
if (he) {
|
||||
#ifdef DEBUG
|
||||
deflated_string_cache_bytes -= JSSTRING_LENGTH(str);
|
||||
rt->deflatedStringCacheBytes -= JSSTRING_LENGTH(str);
|
||||
#endif
|
||||
free(he->value);
|
||||
JS_HashTableRawRemove(deflated_string_cache, hep, he);
|
||||
JS_HashTableRawRemove(rt->deflatedStringCache, hep, he);
|
||||
}
|
||||
JS_RELEASE_LOCK(deflated_string_cache_lock);
|
||||
JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2719,7 +2710,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str)
|
|||
free(str->chars);
|
||||
}
|
||||
if (valid) {
|
||||
js_PurgeDeflatedStringCache(str);
|
||||
js_PurgeDeflatedStringCache(rt, str);
|
||||
str->chars = NULL;
|
||||
}
|
||||
str->length = 0;
|
||||
|
@ -2749,7 +2740,7 @@ js_ValueToPrintableString(JSContext *cx, jsval v)
|
|||
str = js_QuoteString(cx, str, 0);
|
||||
if (!str)
|
||||
return NULL;
|
||||
bytes = js_GetStringBytes(str);
|
||||
bytes = js_GetStringBytes(cx->runtime, str);
|
||||
if (!bytes)
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return bytes;
|
||||
|
@ -3189,31 +3180,31 @@ js_DeflateString(JSContext *cx, const jschar *chars, size_t length)
|
|||
#endif
|
||||
|
||||
static JSHashTable *
|
||||
GetDeflatedStringCache(void)
|
||||
GetDeflatedStringCache(JSRuntime *rt)
|
||||
{
|
||||
JSHashTable *cache;
|
||||
|
||||
cache = deflated_string_cache;
|
||||
cache = rt->deflatedStringCache;
|
||||
if (!cache) {
|
||||
cache = JS_NewHashTable(8, js_hash_string_pointer,
|
||||
JS_CompareValues, JS_CompareValues,
|
||||
NULL, NULL);
|
||||
deflated_string_cache = cache;
|
||||
rt->deflatedStringCache = cache;
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_SetStringBytes(JSString *str, char *bytes, size_t length)
|
||||
js_SetStringBytes(JSRuntime *rt, JSString *str, char *bytes, size_t length)
|
||||
{
|
||||
JSHashTable *cache;
|
||||
JSBool ok;
|
||||
JSHashNumber hash;
|
||||
JSHashEntry **hep;
|
||||
|
||||
JS_ACQUIRE_LOCK(deflated_string_cache_lock);
|
||||
JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
|
||||
|
||||
cache = GetDeflatedStringCache();
|
||||
cache = GetDeflatedStringCache(rt);
|
||||
if (!cache) {
|
||||
ok = JS_FALSE;
|
||||
} else {
|
||||
|
@ -3223,25 +3214,25 @@ js_SetStringBytes(JSString *str, char *bytes, size_t length)
|
|||
ok = JS_HashTableRawAdd(cache, hep, hash, str, bytes) != NULL;
|
||||
#ifdef DEBUG
|
||||
if (ok)
|
||||
deflated_string_cache_bytes += length;
|
||||
rt->deflatedStringCacheBytes += length;
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_RELEASE_LOCK(deflated_string_cache_lock);
|
||||
JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
|
||||
return ok;
|
||||
}
|
||||
|
||||
char *
|
||||
js_GetStringBytes(JSString *str)
|
||||
js_GetStringBytes(JSRuntime *rt, JSString *str)
|
||||
{
|
||||
JSHashTable *cache;
|
||||
char *bytes;
|
||||
JSHashNumber hash;
|
||||
JSHashEntry *he, **hep;
|
||||
|
||||
JS_ACQUIRE_LOCK(deflated_string_cache_lock);
|
||||
JS_ACQUIRE_LOCK(rt->deflatedStringCacheLock);
|
||||
|
||||
cache = GetDeflatedStringCache();
|
||||
cache = GetDeflatedStringCache(rt);
|
||||
if (!cache) {
|
||||
bytes = NULL;
|
||||
} else {
|
||||
|
@ -3260,7 +3251,7 @@ js_GetStringBytes(JSString *str)
|
|||
if (bytes) {
|
||||
if (JS_HashTableRawAdd(cache, hep, hash, str, bytes)) {
|
||||
#ifdef DEBUG
|
||||
deflated_string_cache_bytes += JSSTRING_LENGTH(str);
|
||||
rt->deflatedStringCacheBytes += JSSTRING_LENGTH(str);
|
||||
#endif
|
||||
} else {
|
||||
free(bytes);
|
||||
|
@ -3270,7 +3261,7 @@ js_GetStringBytes(JSString *str)
|
|||
}
|
||||
}
|
||||
|
||||
JS_RELEASE_LOCK(deflated_string_cache_lock);
|
||||
JS_RELEASE_LOCK(rt->deflatedStringCacheLock);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
|
|
@ -294,16 +294,6 @@ typedef enum JSCharType {
|
|||
#define JS7_UNHEX(c) (uintN)(isdigit(c) ? (c) - '0' : 10 + tolower(c) - 'a')
|
||||
#define JS7_ISLET(c) ((c) < 128 && isalpha(c))
|
||||
|
||||
/* Initialize truly global state associated with JS strings. */
|
||||
extern JSBool
|
||||
js_InitStringGlobals(void);
|
||||
|
||||
extern void
|
||||
js_FreeStringGlobals(void);
|
||||
|
||||
extern void
|
||||
js_PurgeDeflatedStringCache(JSString *str);
|
||||
|
||||
/* Initialize per-runtime string state for the first context in the runtime. */
|
||||
extern JSBool
|
||||
js_InitRuntimeStringState(JSContext *cx);
|
||||
|
@ -463,14 +453,18 @@ js_DeflateStringToBuffer(JSContext* cx, const jschar *chars, size_t charsLength,
|
|||
* successful association, false on out of memory.
|
||||
*/
|
||||
extern JSBool
|
||||
js_SetStringBytes(JSString *str, char *bytes, size_t length);
|
||||
js_SetStringBytes(JSRuntime *rt, JSString *str, char *bytes, size_t length);
|
||||
|
||||
/*
|
||||
* Find or create a deflated string cache entry for str that contains its
|
||||
* characters chopped from Unicode code points into bytes.
|
||||
*/
|
||||
extern char *
|
||||
js_GetStringBytes(JSString *str);
|
||||
js_GetStringBytes(JSRuntime *rt, JSString *str);
|
||||
|
||||
/* Remove a deflated string cache entry associated with str if any. */
|
||||
extern void
|
||||
js_PurgeDeflatedStringCache(JSRuntime *rt, JSString *str);
|
||||
|
||||
JSBool
|
||||
js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
|
|
|
@ -7677,7 +7677,7 @@ js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, JSString *str2)
|
|||
* Reallocating str (because we know it has no other references) requires
|
||||
* purging any deflated string cached for it.
|
||||
*/
|
||||
js_PurgeDeflatedStringCache(str);
|
||||
js_PurgeDeflatedStringCache(cx->runtime, str);
|
||||
|
||||
str->chars = chars;
|
||||
str->length = newlen;
|
||||
|
|
Загрузка…
Ссылка в новой задаче