зеркало из https://github.com/mozilla/gecko-dev.git
- Keep interned string atoms around across zero-context episodes on a runtime,
until JS_DestroyRuntime is called (68450, r=rginda, sr=jband). - NUL-terminate tagbuf in tagify, for the HTML helpers such as string.big() (66648, r=timeless, sr=jband).
This commit is contained in:
Родитель
5c61971304
Коммит
5fcc8a1adc
|
@ -691,6 +691,7 @@ JS_DestroyRuntime(JSRuntime *rt)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
js_FinishAtomState(&rt->atomState);
|
||||
js_FinishGC(rt);
|
||||
#ifdef JS_THREADSAFE
|
||||
if (rt->gcLock)
|
||||
|
@ -3392,7 +3393,7 @@ JS_InternString(JSContext *cx, const char *s)
|
|||
JSAtom *atom;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
atom = js_Atomize(cx, s, strlen(s), ATOM_PINNED);
|
||||
atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
|
||||
if (!atom)
|
||||
return NULL;
|
||||
return ATOM_TO_STRING(atom);
|
||||
|
@ -3427,7 +3428,7 @@ JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
|
|||
JSAtom *atom;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
atom = js_AtomizeChars(cx, s, length, ATOM_PINNED);
|
||||
atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED);
|
||||
if (!atom)
|
||||
return NULL;
|
||||
return ATOM_TO_STRING(atom);
|
||||
|
|
|
@ -293,9 +293,12 @@ bad:
|
|||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* NB: cx unused; js_FinishAtomState calls us with null cx. */
|
||||
void
|
||||
js_FreeAtomState(JSContext *cx, JSAtomState *state)
|
||||
{
|
||||
if (state->interns != 0)
|
||||
return;
|
||||
state->runtime = NULL;
|
||||
JS_HashTableDestroy(state->table);
|
||||
state->table = NULL;
|
||||
|
@ -305,6 +308,29 @@ js_FreeAtomState(JSContext *cx, JSAtomState *state)
|
|||
#endif
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(intN)
|
||||
js_atom_uninterner(JSHashEntry *he, intN i, void *arg)
|
||||
{
|
||||
JSAtom *atom;
|
||||
|
||||
atom = (JSAtom *)he;
|
||||
JS_ASSERT(atom->flags & ATOM_INTERNED);
|
||||
JS_ASSERT(ATOM_IS_STRING(atom));
|
||||
js_FinalizeStringRT(arg, ATOM_TO_STRING(atom));
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
js_FinishAtomState(JSAtomState *state)
|
||||
{
|
||||
if (state->interns == 0)
|
||||
return;
|
||||
JS_HashTableEnumerateEntries(state->table, js_atom_uninterner,
|
||||
state->runtime);
|
||||
state->interns = 0;
|
||||
js_FreeAtomState(NULL, state);
|
||||
}
|
||||
|
||||
typedef struct MarkArgs {
|
||||
uintN gcflags;
|
||||
JSGCThingMarker mark;
|
||||
|
@ -320,7 +346,8 @@ js_atom_marker(JSHashEntry *he, intN i, void *arg)
|
|||
|
||||
atom = (JSAtom *)he;
|
||||
args = (MarkArgs *) arg;
|
||||
if ((atom->flags & ATOM_PINNED) || (args->gcflags & GC_KEEP_ATOMS)) {
|
||||
if ((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) ||
|
||||
(args->gcflags & GC_KEEP_ATOMS)) {
|
||||
atom->flags |= ATOM_MARK;
|
||||
key = ATOM_KEY(atom);
|
||||
if (JSVAL_IS_GCTHING(key)) {
|
||||
|
@ -352,7 +379,7 @@ js_atom_sweeper(JSHashEntry *he, intN i, void *arg)
|
|||
atom->flags &= ~ATOM_MARK;
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
JS_ASSERT((atom->flags & ATOM_PINNED) == 0);
|
||||
JS_ASSERT((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) == 0);
|
||||
atom->entry.key = NULL;
|
||||
atom->flags = 0;
|
||||
return HT_ENUMERATE_REMOVE;
|
||||
|
@ -548,7 +575,9 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
|||
}
|
||||
|
||||
atom = (JSAtom *)he;
|
||||
atom->flags |= flags & ATOM_PINNED;
|
||||
atom->flags |= flags & (ATOM_PINNED | ATOM_INTERNED);
|
||||
if (flags & ATOM_INTERNED)
|
||||
state->interns++;
|
||||
out:
|
||||
JS_UNLOCK(&state->lock,cx);
|
||||
return atom;
|
||||
|
|
|
@ -50,14 +50,15 @@
|
|||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
#define ATOM_NOCOPY 0x01 /* don't copy atom string bytes */
|
||||
#define ATOM_TMPSTR 0x02 /* internal, to avoid extra string */
|
||||
#define ATOM_PINNED 0x01 /* atom is pinned against GC */
|
||||
#define ATOM_INTERNED 0x02 /* pinned variant for JS_Intern* API */
|
||||
#define ATOM_MARK 0x04 /* atom is reachable via GC */
|
||||
#define ATOM_PINNED 0x08 /* atom is pinned against GC */
|
||||
#define ATOM_NOCOPY 0x40 /* don't copy atom string bytes */
|
||||
#define ATOM_TMPSTR 0x80 /* internal, to avoid extra string */
|
||||
|
||||
struct JSAtom {
|
||||
JSHashEntry entry; /* key is jsval, value keyword info */
|
||||
uint8 flags; /* flags, PINNED and/or MARK for now */
|
||||
uint8 flags; /* pinned, interned, and mark flags */
|
||||
int8 kwindex; /* keyword index, -1 if not keyword */
|
||||
jsatomid number; /* atom serial number and hash code */
|
||||
};
|
||||
|
@ -134,6 +135,7 @@ struct JSAtomState {
|
|||
JSRuntime *runtime; /* runtime that owns us */
|
||||
JSHashTable *table; /* hash table containing all atoms */
|
||||
jsatomid number; /* one beyond greatest atom number */
|
||||
jsatomid interns; /* number of interned strings */
|
||||
|
||||
/* Type names and value literals. */
|
||||
JSAtom *typeAtoms[JSTYPE_LIMIT];
|
||||
|
@ -232,11 +234,27 @@ extern JSBool
|
|||
js_InitAtomState(JSContext *cx, JSAtomState *state);
|
||||
|
||||
/*
|
||||
* Free and clear atom state.
|
||||
* Free and clear atom state (except for any interned string atoms).
|
||||
*/
|
||||
extern void
|
||||
js_FreeAtomState(JSContext *cx, JSAtomState *state);
|
||||
|
||||
/*
|
||||
* Interned strings are atoms that live until state's runtime is destroyed.
|
||||
* This function frees all interned string atoms, and then frees and clears
|
||||
* state's members (just as js_FreeAtomState does), unless there aren't any
|
||||
* interned strings in state -- in which case state must be "free" already.
|
||||
*
|
||||
* NB: js_FreeAtomState is called for each "last" context being destroyed in
|
||||
* a runtime, where there may yet be another context created in the runtime;
|
||||
* whereas js_FinishAtomState is called from JS_DestroyRuntime, when we know
|
||||
* that no more contexts will be created. Thus we minimize garbage during
|
||||
* context-free episodes on a runtime, while preserving atoms created by the
|
||||
* JS_Intern*String APIs for the life of the runtime.
|
||||
*/
|
||||
extern void
|
||||
js_FinishAtomState(JSAtomState *state);
|
||||
|
||||
/*
|
||||
* Atom garbage collection hooks.
|
||||
*/
|
||||
|
|
|
@ -1998,6 +1998,7 @@ tagify(JSContext *cx, JSObject *obj, jsval *argv,
|
|||
tagbuf[j++] = (jschar)end[i];
|
||||
tagbuf[j++] = '>';
|
||||
JS_ASSERT(j == taglen);
|
||||
tagbuf[j] = 0;
|
||||
|
||||
str = js_NewString(cx, tagbuf, taglen, 0);
|
||||
if (!str) {
|
||||
|
@ -2377,13 +2378,19 @@ js_hash_string_pointer(const void *key)
|
|||
|
||||
void
|
||||
js_FinalizeString(JSContext *cx, JSString *str)
|
||||
{
|
||||
js_FinalizeStringRT(cx->runtime, str);
|
||||
}
|
||||
|
||||
void
|
||||
js_FinalizeStringRT(JSRuntime *rt, JSString *str)
|
||||
{
|
||||
JSHashNumber hash;
|
||||
JSHashEntry *he, **hep;
|
||||
|
||||
JS_RUNTIME_UNMETER(cx->runtime, liveStrings);
|
||||
JS_RUNTIME_UNMETER(rt, liveStrings);
|
||||
if (str->chars) {
|
||||
JS_free(cx, str->chars);
|
||||
free(str->chars);
|
||||
str->chars = NULL;
|
||||
if (deflated_string_cache) {
|
||||
hash = js_hash_string_pointer(str);
|
||||
|
@ -2391,7 +2398,7 @@ js_FinalizeString(JSContext *cx, JSString *str)
|
|||
hep = JS_HashTableRawLookup(deflated_string_cache, hash, str);
|
||||
he = *hep;
|
||||
if (he) {
|
||||
JS_free(cx, he->value);
|
||||
free(he->value);
|
||||
JS_HashTableRawRemove(deflated_string_cache, hep, he);
|
||||
deflated_string_cache_bytes -= str->length;
|
||||
}
|
||||
|
|
|
@ -219,6 +219,9 @@ js_NewStringCopyZ(JSContext *cx, const jschar *s, uintN gcflag);
|
|||
extern void
|
||||
js_FinalizeString(JSContext *cx, JSString *str);
|
||||
|
||||
extern void
|
||||
js_FinalizeStringRT(JSRuntime *rt, JSString *str);
|
||||
|
||||
/* Wrap a string value in a String object. */
|
||||
extern JSObject *
|
||||
js_StringToObject(JSContext *cx, JSString *str);
|
||||
|
|
Загрузка…
Ссылка в новой задаче