Bug 387481, bug 389063: multithreading atom fixes and cleanups. r=brendan
git-svn-id: svn://10.0.0.236/trunk@231579 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
9a22d5458f
commit
8c7384c4bc
@ -1019,7 +1019,7 @@ SrcNotes(JSContext *cx, JSScript *script)
|
||||
const char *bytes;
|
||||
|
||||
atomIndex = (jsatomid) js_GetSrcNoteOffset(sn, 0);
|
||||
atom = js_GetAtom(cx, &script->atomMap, atomIndex);
|
||||
JS_GET_SCRIPT_ATOM(script, atomIndex, atom);
|
||||
bytes = js_AtomToPrintableString(cx, atom);
|
||||
fprintf(gOutFile, " atom %u (%s)", (uintN)atomIndex, bytes);
|
||||
break;
|
||||
@ -1267,28 +1267,6 @@ Tracing(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
typedef struct DumpAtomArgs {
|
||||
JSContext *cx;
|
||||
FILE *fp;
|
||||
} DumpAtomArgs;
|
||||
|
||||
static int
|
||||
DumpAtom(JSHashEntry *he, int i, void *arg)
|
||||
{
|
||||
DumpAtomArgs *args = (DumpAtomArgs *)arg;
|
||||
FILE *fp = args->fp;
|
||||
JSAtom *atom = (JSAtom *)he;
|
||||
|
||||
fprintf(fp, "%3d %08x ", i, (uintN)he->keyHash);
|
||||
if (ATOM_IS_STRING(atom))
|
||||
fprintf(fp, "\"%s\"\n", js_AtomToPrintableString(args->cx, atom));
|
||||
else if (ATOM_IS_INT(atom))
|
||||
fprintf(fp, "%ld\n", (long)ATOM_TO_INT(atom));
|
||||
else
|
||||
fprintf(fp, "%.16g\n", *ATOM_TO_DOUBLE(atom));
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
static void
|
||||
DumpScope(JSContext *cx, JSObject *obj, FILE *fp)
|
||||
{
|
||||
@ -1347,19 +1325,7 @@ DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
JS_DumpArenaStats(stdout);
|
||||
#endif
|
||||
} else if (strcmp(bytes, "atom") == 0) {
|
||||
DumpAtomArgs args;
|
||||
|
||||
fprintf(gOutFile, "\natom table contents:\n");
|
||||
args.cx = cx;
|
||||
args.fp = stdout;
|
||||
JS_HashTableEnumerateEntries(cx->runtime->atomState.table,
|
||||
DumpAtom,
|
||||
&args);
|
||||
#ifdef HASHMETER
|
||||
JS_HashTableDumpMeter(cx->runtime->atomState.table,
|
||||
DumpAtom,
|
||||
stdout);
|
||||
#endif
|
||||
js_DumpAtoms(cx, gOutFile);
|
||||
} else if (strcmp(bytes, "global") == 0) {
|
||||
DumpScope(cx, cx->globalObject, stdout);
|
||||
} else {
|
||||
|
||||
@ -648,7 +648,7 @@ JS_GetTypeName(JSContext *cx, JSType type)
|
||||
{
|
||||
if ((uintN)type >= (uintN)JSTYPE_LIMIT)
|
||||
return NULL;
|
||||
return js_type_strs[type];
|
||||
return JS_TYPE_STR(type);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
@ -703,6 +703,8 @@ JS_NewRuntime(uint32 maxbytes)
|
||||
|
||||
if (!js_InitGC(rt, maxbytes))
|
||||
goto bad;
|
||||
if (!js_InitAtomState(rt))
|
||||
goto bad;
|
||||
#ifdef JS_THREADSAFE
|
||||
if (!js_InitThreadPrivateIndex(js_ThreadDestructorCB))
|
||||
goto bad;
|
||||
@ -764,7 +766,7 @@ JS_DestroyRuntime(JSRuntime *rt)
|
||||
#endif
|
||||
|
||||
js_FreeRuntimeScriptState(rt);
|
||||
js_FinishAtomState(&rt->atomState);
|
||||
js_FinishAtomState(rt);
|
||||
js_FinishGC(rt);
|
||||
#ifdef JS_THREADSAFE
|
||||
if (rt->gcLock)
|
||||
|
||||
@ -63,38 +63,94 @@ js_AtomToPrintableString(JSContext *cx, JSAtom *atom)
|
||||
return js_ValueToPrintableString(cx, ATOM_KEY(atom));
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep this in sync with jspubtd.h -- an assertion below will insist that
|
||||
* its length match the JSType enum's JSTYPE_LIMIT limit value.
|
||||
*/
|
||||
const char *js_type_strs[] = {
|
||||
"undefined",
|
||||
js_object_str,
|
||||
"function",
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
"null",
|
||||
"xml",
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(JSTYPE_LIMIT ==
|
||||
sizeof js_type_strs / sizeof js_type_strs[0]);
|
||||
|
||||
const char *js_boolean_strs[] = {
|
||||
js_false_str,
|
||||
js_true_str
|
||||
};
|
||||
|
||||
#define JS_PROTO(name,code,init) const char js_##name##_str[] = #name;
|
||||
#include "jsproto.tbl"
|
||||
#undef JS_PROTO
|
||||
|
||||
const char *js_proto_strs[JSProto_LIMIT] = {
|
||||
/*
|
||||
* Names for common atoms defined in JSAtomState starting from
|
||||
* JSAtomState.emptyAtom until JSAtomState.lazy.
|
||||
*
|
||||
* The elements of the array after the first empty string define strings
|
||||
* corresponding to JSType enumerators from jspubtd.h and to two boolean
|
||||
* literals, false and true. The following assert insists that JSType defines
|
||||
* exactly 8 types.
|
||||
*/
|
||||
JS_STATIC_ASSERT(JSTYPE_LIMIT == 8);
|
||||
const char *const js_common_atom_names[] = {
|
||||
"", /* emptyAtom */
|
||||
js_undefined_str, /* typeAtoms[JSTYPE_VOID] */
|
||||
js_object_str, /* typeAtoms[JSTYPE_OBJECT] */
|
||||
js_function_str, /* typeAtoms[JSTYPE_FUNCTION] */
|
||||
"string", /* typeAtoms[JSTYPE_STRING] */
|
||||
"number", /* typeAtoms[JSTYPE_NUMBER] */
|
||||
"boolean", /* typeAtoms[JSTYPE_BOOLEAN] */
|
||||
js_null_str, /* typeAtoms[JSTYPE_NULL] */
|
||||
"xml", /* typeAtoms[JSTYPE_XML] */
|
||||
js_false_str, /* booleanAtoms[0] */
|
||||
js_true_str, /* booleanAtoms[1] */
|
||||
js_null_str, /* nullAtom */
|
||||
|
||||
#define JS_PROTO(name,code,init) js_##name##_str,
|
||||
#include "jsproto.tbl"
|
||||
#undef JS_PROTO
|
||||
|
||||
js_anonymous_str, /* anonymousAtom */
|
||||
js_arguments_str, /* argumentsAtom */
|
||||
js_arity_str, /* arityAtom */
|
||||
js_callee_str, /* calleeAtom */
|
||||
js_caller_str, /* callerAtom */
|
||||
js_class_prototype_str, /* classPrototypeAtom */
|
||||
js_constructor_str, /* constructorAtom */
|
||||
js_count_str, /* countAtom */
|
||||
js_each_str, /* eachAtom */
|
||||
js_eval_str, /* evalAtom */
|
||||
js_fileName_str, /* fileNameAtom */
|
||||
js_get_str, /* getAtom */
|
||||
js_getter_str, /* getterAtom */
|
||||
js_index_str, /* indexAtom */
|
||||
js_input_str, /* inputAtom */
|
||||
js_iterator_str, /* iteratorAtom */
|
||||
js_length_str, /* lengthAtom */
|
||||
js_lineNumber_str, /* lineNumberAtom */
|
||||
js_message_str, /* messageAtom */
|
||||
js_name_str, /* nameAtom */
|
||||
js_next_str, /* nextAtom */
|
||||
js_noSuchMethod_str, /* noSuchMethodAtom */
|
||||
js_parent_str, /* parentAtom */
|
||||
js_proto_str, /* protoAtom */
|
||||
js_set_str, /* setAtom */
|
||||
js_setter_str, /* setterAtom */
|
||||
js_stack_str, /* stackAtom */
|
||||
js_toLocaleString_str, /* toLocaleStringAtom */
|
||||
js_toSource_str, /* toSourceAtom */
|
||||
js_toString_str, /* toStringAtom */
|
||||
js_valueOf_str, /* valueOfAtom */
|
||||
"(void 0)", /* void0Atom */
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
js_etago_str, /* etagoAtom */
|
||||
js_namespace_str, /* namespaceAtom */
|
||||
js_ptagc_str, /* ptagcAtom */
|
||||
js_qualifier_str, /* qualifierAtom */
|
||||
js_space_str, /* spaceAtom */
|
||||
js_stago_str, /* stagoAtom */
|
||||
js_star_str, /* starAtom */
|
||||
js_starQualifier_str, /* starQualifierAtom */
|
||||
js_tagc_str, /* tagcAtom */
|
||||
js_xml_str, /* xmlAtom */
|
||||
#endif
|
||||
|
||||
#ifdef NARCISSUS
|
||||
js_call_str, /* callAtom */
|
||||
js_construct_str, /* constructAtom */
|
||||
js_hasInstance_str, /* hasInstanceAtom */
|
||||
js_ExecutionContext_str, /* ExecutionContextAtom */
|
||||
js_current_str, /* currentAtom */
|
||||
#endif
|
||||
};
|
||||
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) * sizeof(JSAtom *) ==
|
||||
LAZY_ATOM_OFFSET_START - ATOM_OFFSET_START);
|
||||
|
||||
const char js_anonymous_str[] = "anonymous";
|
||||
const char js_arguments_str[] = "arguments";
|
||||
@ -127,6 +183,7 @@ const char js_stack_str[] = "stack";
|
||||
const char js_toSource_str[] = "toSource";
|
||||
const char js_toString_str[] = "toString";
|
||||
const char js_toLocaleString_str[] = "toLocaleString";
|
||||
const char js_undefined_str[] = "undefined";
|
||||
const char js_valueOf_str[] = "valueOf";
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
@ -221,16 +278,11 @@ JS_STATIC_DLL_CALLBACK(JSHashEntry *)
|
||||
js_alloc_atom(void *priv, const void *key)
|
||||
{
|
||||
JSAtom *atom;
|
||||
#ifdef JS_THREADSAFE
|
||||
JSAtomState *state = (JSAtomState *) priv;
|
||||
#endif
|
||||
|
||||
atom = (JSAtom *) malloc(sizeof(JSAtom));
|
||||
if (!atom)
|
||||
return NULL;
|
||||
#ifdef JS_THREADSAFE
|
||||
state->tablegen++;
|
||||
#endif
|
||||
((JSAtomState *)priv)->tablegen++;
|
||||
atom->entry.key = key;
|
||||
atom->entry.value = NULL;
|
||||
atom->flags = 0;
|
||||
@ -242,9 +294,7 @@ js_free_atom(void *priv, JSHashEntry *he, uintN flag)
|
||||
{
|
||||
if (flag != HT_FREE_ENTRY)
|
||||
return;
|
||||
#ifdef JS_THREADSAFE
|
||||
((JSAtomState *)priv)->tablegen++;
|
||||
#endif
|
||||
free(he);
|
||||
}
|
||||
|
||||
@ -256,133 +306,33 @@ static JSHashAllocOps atom_alloc_ops = {
|
||||
#define JS_ATOM_HASH_SIZE 1024
|
||||
|
||||
JSBool
|
||||
js_InitAtomState(JSContext *cx, JSAtomState *state)
|
||||
js_InitAtomState(JSRuntime *rt)
|
||||
{
|
||||
JSAtomState *state = &rt->atomState;
|
||||
|
||||
/*
|
||||
* The caller must zero the state before calling this function.
|
||||
*/
|
||||
JS_ASSERT(!state->table);
|
||||
JS_ASSERT(state->tablegen == 0);
|
||||
|
||||
state->table = JS_NewHashTable(JS_ATOM_HASH_SIZE, js_hash_atom_key,
|
||||
js_compare_atom_keys, js_compare_stub,
|
||||
&atom_alloc_ops, state);
|
||||
if (!state->table) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
if (!state->table)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
state->runtime = cx->runtime;
|
||||
#ifdef JS_THREADSAFE
|
||||
js_InitLock(&state->lock);
|
||||
state->tablegen = 0;
|
||||
#endif
|
||||
|
||||
if (!js_InitPinnedAtoms(cx, state)) {
|
||||
js_FreeAtomState(cx, state);
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_InitPinnedAtoms(JSContext *cx, JSAtomState *state)
|
||||
{
|
||||
uintN i;
|
||||
|
||||
#define FROB(lval,str) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (!(state->lval = js_Atomize(cx, str, strlen(str), ATOM_PINNED))) \
|
||||
return JS_FALSE; \
|
||||
JS_END_MACRO
|
||||
|
||||
FROB(emptyAtom, "");
|
||||
|
||||
for (i = 0; i < JSTYPE_LIMIT; i++)
|
||||
FROB(typeAtoms[i], js_type_strs[i]);
|
||||
|
||||
for (i = 0; i < JSProto_LIMIT; i++)
|
||||
FROB(classAtoms[i], js_proto_strs[i]);
|
||||
|
||||
FROB(booleanAtoms[0], js_false_str);
|
||||
FROB(booleanAtoms[1], js_true_str);
|
||||
FROB(nullAtom, js_null_str);
|
||||
|
||||
FROB(anonymousAtom, js_anonymous_str);
|
||||
FROB(argumentsAtom, js_arguments_str);
|
||||
FROB(arityAtom, js_arity_str);
|
||||
FROB(calleeAtom, js_callee_str);
|
||||
FROB(callerAtom, js_caller_str);
|
||||
FROB(classPrototypeAtom, js_class_prototype_str);
|
||||
FROB(constructorAtom, js_constructor_str);
|
||||
FROB(countAtom, js_count_str);
|
||||
FROB(eachAtom, js_each_str);
|
||||
FROB(evalAtom, js_eval_str);
|
||||
FROB(fileNameAtom, js_fileName_str);
|
||||
FROB(getAtom, js_get_str);
|
||||
FROB(getterAtom, js_getter_str);
|
||||
FROB(indexAtom, js_index_str);
|
||||
FROB(inputAtom, js_input_str);
|
||||
FROB(iteratorAtom, js_iterator_str);
|
||||
FROB(lengthAtom, js_length_str);
|
||||
FROB(lineNumberAtom, js_lineNumber_str);
|
||||
FROB(messageAtom, js_message_str);
|
||||
FROB(nameAtom, js_name_str);
|
||||
FROB(nextAtom, js_next_str);
|
||||
FROB(noSuchMethodAtom, js_noSuchMethod_str);
|
||||
FROB(parentAtom, js_parent_str);
|
||||
FROB(protoAtom, js_proto_str);
|
||||
FROB(setAtom, js_set_str);
|
||||
FROB(setterAtom, js_setter_str);
|
||||
FROB(stackAtom, js_stack_str);
|
||||
FROB(toSourceAtom, js_toSource_str);
|
||||
FROB(toStringAtom, js_toString_str);
|
||||
FROB(toLocaleStringAtom, js_toLocaleString_str);
|
||||
FROB(valueOfAtom, js_valueOf_str);
|
||||
FROB(void0Atom, "(void 0)");
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
FROB(etagoAtom, js_etago_str);
|
||||
FROB(namespaceAtom, js_namespace_str);
|
||||
FROB(ptagcAtom, js_ptagc_str);
|
||||
FROB(qualifierAtom, js_qualifier_str);
|
||||
FROB(spaceAtom, js_space_str);
|
||||
FROB(stagoAtom, js_stago_str);
|
||||
FROB(starAtom, js_star_str);
|
||||
FROB(starQualifierAtom, js_starQualifier_str);
|
||||
FROB(tagcAtom, js_tagc_str);
|
||||
FROB(xmlAtom, js_xml_str);
|
||||
#endif
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
FROB(closeAtom, js_close_str);
|
||||
#endif
|
||||
|
||||
#ifdef NARCISSUS
|
||||
FROB(callAtom, js_call_str);
|
||||
FROB(constructAtom, js_construct_str);
|
||||
FROB(hasInstanceAtom, js_hasInstance_str);
|
||||
FROB(ExecutionContextAtom, js_ExecutionContext_str);
|
||||
FROB(currentAtom, js_current_str);
|
||||
#endif
|
||||
|
||||
#undef FROB
|
||||
|
||||
memset(&state->lazy, 0, sizeof state->lazy);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* NB: cx unused; js_FinishAtomState calls us with null cx. */
|
||||
void
|
||||
js_FreeAtomState(JSContext *cx, JSAtomState *state)
|
||||
{
|
||||
if (state->table)
|
||||
JS_HashTableDestroy(state->table);
|
||||
#ifdef JS_THREADSAFE
|
||||
js_FinishLock(&state->lock);
|
||||
#endif
|
||||
memset(state, 0, sizeof *state);
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(intN)
|
||||
js_atom_uninterner(JSHashEntry *he, intN i, void *arg)
|
||||
{
|
||||
JSAtom *atom;
|
||||
JSRuntime *rt;
|
||||
JSRuntime *rt;
|
||||
|
||||
atom = (JSAtom *)he;
|
||||
rt = (JSRuntime *)arg;
|
||||
@ -392,13 +342,68 @@ js_atom_uninterner(JSHashEntry *he, intN i, void *arg)
|
||||
}
|
||||
|
||||
void
|
||||
js_FinishAtomState(JSAtomState *state)
|
||||
js_FinishAtomState(JSRuntime *rt)
|
||||
{
|
||||
if (!state->table)
|
||||
JSAtomState *state = &rt->atomState;
|
||||
|
||||
if (!state->table) {
|
||||
/*
|
||||
* state->table is null when JS_NewRuntime fails and calls
|
||||
* JS_DestroyRuntime on a partially initialized runtime.
|
||||
*/
|
||||
return;
|
||||
JS_HashTableEnumerateEntries(state->table, js_atom_uninterner,
|
||||
state->runtime);
|
||||
js_FreeAtomState(NULL, state);
|
||||
}
|
||||
|
||||
JS_HashTableEnumerateEntries(state->table, js_atom_uninterner, rt);
|
||||
JS_HashTableDestroy(state->table);
|
||||
#ifdef JS_THREADSAFE
|
||||
js_FinishLock(&state->lock);
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
memset(state, JS_FREE_PATTERN, sizeof *state);
|
||||
#endif
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_InitCommonAtoms(JSContext *cx)
|
||||
{
|
||||
JSAtomState *state = &cx->runtime->atomState;
|
||||
uintN i;
|
||||
JSAtom **atoms;
|
||||
|
||||
atoms = (JSAtom **)((uint8 *)state + ATOM_OFFSET_START);
|
||||
for (i = 0; i < JS_ARRAY_LENGTH(js_common_atom_names); i++, atoms++) {
|
||||
*atoms = js_Atomize(cx, js_common_atom_names[i],
|
||||
strlen(js_common_atom_names[i]), ATOM_PINNED);
|
||||
if (!*atoms)
|
||||
return JS_FALSE;
|
||||
}
|
||||
JS_ASSERT((uint8 *)atoms - (uint8 *)state == LAZY_ATOM_OFFSET_START);
|
||||
memset(atoms, 0, ATOM_OFFSET_LIMIT - LAZY_ATOM_OFFSET_START);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(intN)
|
||||
js_atom_unpinner(JSHashEntry *he, intN i, void *arg)
|
||||
{
|
||||
JSAtom *atom;
|
||||
|
||||
atom = (JSAtom *)he;
|
||||
atom->flags &= ~ATOM_PINNED;
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
js_FinishCommonAtoms(JSContext *cx)
|
||||
{
|
||||
JSAtomState *state = &cx->runtime->atomState;
|
||||
|
||||
JS_HashTableEnumerateEntries(state->table, js_atom_unpinner, NULL);
|
||||
#ifdef DEBUG
|
||||
memset((uint8 *)state + ATOM_OFFSET_START, JS_FREE_PATTERN,
|
||||
ATOM_OFFSET_LIMIT - ATOM_OFFSET_START);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -456,13 +461,10 @@ JS_STATIC_DLL_CALLBACK(intN)
|
||||
js_atom_sweeper(JSHashEntry *he, intN i, void *arg)
|
||||
{
|
||||
JSAtom *atom;
|
||||
JSAtomState *state;
|
||||
|
||||
atom = (JSAtom *)he;
|
||||
if (atom->flags & ATOM_MARK) {
|
||||
atom->flags &= ~ATOM_MARK;
|
||||
state = (JSAtomState *)arg;
|
||||
state->liveAtoms++;
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
JS_ASSERT((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) == 0);
|
||||
@ -472,28 +474,11 @@ js_atom_sweeper(JSHashEntry *he, intN i, void *arg)
|
||||
}
|
||||
|
||||
void
|
||||
js_SweepAtomState(JSAtomState *state)
|
||||
js_SweepAtomState(JSContext *cx)
|
||||
{
|
||||
state->liveAtoms = 0;
|
||||
if (state->table)
|
||||
JS_HashTableEnumerateEntries(state->table, js_atom_sweeper, state);
|
||||
}
|
||||
JSAtomState *state = &cx->runtime->atomState;
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(intN)
|
||||
js_atom_unpinner(JSHashEntry *he, intN i, void *arg)
|
||||
{
|
||||
JSAtom *atom;
|
||||
|
||||
atom = (JSAtom *)he;
|
||||
atom->flags &= ~ATOM_PINNED;
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
js_UnpinPinnedAtoms(JSAtomState *state)
|
||||
{
|
||||
if (state->table)
|
||||
JS_HashTableEnumerateEntries(state->table, js_atom_unpinner, NULL);
|
||||
JS_HashTableEnumerateEntries(state->table, js_atom_sweeper, NULL);
|
||||
}
|
||||
|
||||
static JSAtom *
|
||||
@ -511,15 +496,14 @@ AtomizeHashedKey(JSContext *cx, jsval key, JSHashNumber keyHash)
|
||||
if ((he = *hep) == NULL) {
|
||||
he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
|
||||
if (!he) {
|
||||
JS_UNLOCK(&state->lock,cx);
|
||||
JS_ReportOutOfMemory(cx);
|
||||
atom = NULL;
|
||||
goto out;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
atom = (JSAtom *)he;
|
||||
cx->weakRoots.lastAtom = atom;
|
||||
out:
|
||||
JS_UNLOCK(&state->lock,cx);
|
||||
return atom;
|
||||
}
|
||||
@ -531,51 +515,49 @@ out:
|
||||
JSAtom *
|
||||
js_AtomizeDouble(JSContext *cx, jsdouble d)
|
||||
{
|
||||
char buf[2 * ALIGNMENT(double)];
|
||||
jsdouble *dp;
|
||||
JSHashNumber keyHash;
|
||||
jsval key;
|
||||
JSAtomState *state;
|
||||
JSHashTable *table;
|
||||
JSHashEntry *he, **hep;
|
||||
uint32 gen;
|
||||
JSAtom *atom;
|
||||
char buf[2 * ALIGNMENT(double)];
|
||||
|
||||
dp = ALIGN(buf, double);
|
||||
*dp = d;
|
||||
keyHash = HASH_DOUBLE(dp);
|
||||
key = DOUBLE_TO_JSVAL(dp);
|
||||
state = &cx->runtime->atomState;
|
||||
JS_LOCK(&state->lock, cx);
|
||||
table = state->table;
|
||||
|
||||
JS_LOCK(&state->lock, cx);
|
||||
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
|
||||
if ((he = *hep) == NULL) {
|
||||
#ifdef JS_THREADSAFE
|
||||
uint32 gen = state->tablegen;
|
||||
#endif
|
||||
JS_UNLOCK(&state->lock,cx);
|
||||
gen = state->tablegen;
|
||||
JS_UNLOCK(&state->lock, cx);
|
||||
|
||||
if (!js_NewDoubleValue(cx, d, &key))
|
||||
return NULL;
|
||||
|
||||
JS_LOCK(&state->lock, cx);
|
||||
#ifdef JS_THREADSAFE
|
||||
if (state->tablegen != gen) {
|
||||
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
|
||||
if ((he = *hep) != NULL) {
|
||||
atom = (JSAtom *)he;
|
||||
goto out;
|
||||
}
|
||||
if ((he = *hep) != NULL)
|
||||
goto finish;
|
||||
}
|
||||
#endif
|
||||
he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
|
||||
if (!he) {
|
||||
JS_UNLOCK(&state->lock, cx);
|
||||
JS_ReportOutOfMemory(cx);
|
||||
atom = NULL;
|
||||
goto out;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
atom = (JSAtom *)he;
|
||||
cx->weakRoots.lastAtom = atom;
|
||||
out:
|
||||
JS_UNLOCK(&state->lock,cx);
|
||||
return atom;
|
||||
}
|
||||
@ -590,66 +572,66 @@ JSAtom *
|
||||
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
||||
{
|
||||
JSHashNumber keyHash;
|
||||
jsval key;
|
||||
void *key;
|
||||
JSAtomState *state;
|
||||
JSHashTable *table;
|
||||
JSHashEntry *he, **hep;
|
||||
uint32 gen;
|
||||
JSString *hashed;
|
||||
JSAtom *atom;
|
||||
|
||||
keyHash = js_HashString(str);
|
||||
if (flags & ATOM_HIDDEN)
|
||||
keyHash ^= HIDDEN_ATOM_SUBSPACE_KEYHASH;
|
||||
key = STRING_TO_JSVAL(str);
|
||||
key = (void *)STRING_TO_JSVAL(str);
|
||||
state = &cx->runtime->atomState;
|
||||
JS_LOCK(&state->lock, cx);
|
||||
table = state->table;
|
||||
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
|
||||
|
||||
JS_LOCK(&state->lock, cx);
|
||||
hep = JS_HashTableRawLookup(table, keyHash, key);
|
||||
if ((he = *hep) == NULL) {
|
||||
#ifdef JS_THREADSAFE
|
||||
uint32 gen = state->tablegen;
|
||||
gen = state->tablegen;
|
||||
JS_UNLOCK(&state->lock, cx);
|
||||
#endif
|
||||
|
||||
if (flags & ATOM_TMPSTR) {
|
||||
str = (flags & ATOM_NOCOPY)
|
||||
? js_NewString(cx, str->chars, str->length, 0)
|
||||
: js_NewStringCopyN(cx, str->chars, str->length);
|
||||
if (!str)
|
||||
return NULL;
|
||||
key = STRING_TO_JSVAL(str);
|
||||
if (flags & ATOM_NOCOPY) {
|
||||
hashed = js_NewString(cx, str->chars, str->length, 0);
|
||||
if (!hashed)
|
||||
return NULL;
|
||||
|
||||
/* Transfer ownership of str->chars to GC-controlled string. */
|
||||
str->chars = NULL;
|
||||
} else {
|
||||
hashed = js_NewStringCopyN(cx, str->chars, str->length);
|
||||
if (!hashed)
|
||||
return NULL;
|
||||
}
|
||||
key = (void *)STRING_TO_JSVAL(hashed);
|
||||
} else {
|
||||
JS_ASSERT((flags & ATOM_NOCOPY) == 0);
|
||||
if (!JS_MakeStringImmutable(cx, str))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_LOCK(&state->lock, cx);
|
||||
if (state->tablegen != gen) {
|
||||
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
|
||||
if ((he = *hep) != NULL) {
|
||||
atom = (JSAtom *)he;
|
||||
if (flags & ATOM_NOCOPY)
|
||||
str->chars = NULL;
|
||||
goto out;
|
||||
}
|
||||
hep = JS_HashTableRawLookup(table, keyHash, key);
|
||||
if ((he = *hep) != NULL)
|
||||
goto finish;
|
||||
}
|
||||
#endif
|
||||
|
||||
he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
|
||||
he = JS_HashTableRawAdd(table, hep, keyHash, key, NULL);
|
||||
if (!he) {
|
||||
if (flags & ATOM_NOCOPY)
|
||||
str->chars = NULL;
|
||||
JS_UNLOCK(&state->lock, cx);
|
||||
JS_ReportOutOfMemory(cx);
|
||||
atom = NULL;
|
||||
goto out;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
atom = (JSAtom *)he;
|
||||
atom->flags |= flags & (ATOM_PINNED | ATOM_INTERNED | ATOM_HIDDEN);
|
||||
cx->weakRoots.lastAtom = atom;
|
||||
out:
|
||||
JS_UNLOCK(&state->lock,cx);
|
||||
JS_UNLOCK(&state->lock, cx);
|
||||
return atom;
|
||||
}
|
||||
|
||||
@ -689,7 +671,7 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
|
||||
str->chars = chars;
|
||||
str->length = inflatedLength;
|
||||
atom = js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
|
||||
if (chars != inflated && (!atom || ATOM_TO_STRING(atom)->chars != chars))
|
||||
if (chars != inflated && str->chars)
|
||||
JS_free(cx, chars);
|
||||
return atom;
|
||||
}
|
||||
@ -753,6 +735,39 @@ js_ValueToStringAtom(JSContext *cx, jsval v)
|
||||
return js_AtomizeString(cx, str, 0);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(int)
|
||||
atom_dumper(JSHashEntry *he, int i, void *arg)
|
||||
{
|
||||
FILE *fp = (FILE *)arg;
|
||||
JSAtom *atom = (JSAtom *)he;
|
||||
|
||||
fprintf(fp, "%3u %08x ", (uintN)i, (uintN)he->keyHash);
|
||||
if (ATOM_IS_STRING(atom))
|
||||
js_FileEscapedString(fp, ATOM_TO_STRING(atom), '"');
|
||||
else if (ATOM_IS_INT(atom))
|
||||
fprintf(fp, "%ld", (long)ATOM_TO_INT(atom));
|
||||
else
|
||||
fprintf(fp, "%.16g", *ATOM_TO_DOUBLE(atom));
|
||||
putc('\n', fp);
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js_DumpAtoms(JSContext *cx, FILE *fp)
|
||||
{
|
||||
JSAtomState *state = &cx->runtime->atomState;
|
||||
|
||||
fprintf(fp, "\natom table contents:\n");
|
||||
JS_HashTableEnumerateEntries(state->table, atom_dumper, fp);
|
||||
#ifdef HASHMETER
|
||||
JS_HashTableDumpMeter(state->table, atom_dumper, fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(JSHashNumber)
|
||||
js_hash_atom_ptr(const void *key)
|
||||
{
|
||||
@ -863,25 +878,6 @@ js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al)
|
||||
return ale;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSAtom *)
|
||||
js_GetAtom(JSContext *cx, JSAtomMap *map, jsatomid i)
|
||||
{
|
||||
JSAtom *atom;
|
||||
static JSAtom dummy;
|
||||
|
||||
JS_ASSERT(map->vector && i < map->length);
|
||||
if (!map->vector || i >= map->length) {
|
||||
char numBuf[12];
|
||||
JS_snprintf(numBuf, sizeof numBuf, "%lu", (unsigned long)i);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_ATOMIC_NUMBER, numBuf);
|
||||
return &dummy;
|
||||
}
|
||||
atom = map->vector[i];
|
||||
JS_ASSERT(atom);
|
||||
return atom;
|
||||
}
|
||||
|
||||
JS_STATIC_DLL_CALLBACK(intN)
|
||||
js_map_atom(JSHashEntry *he, intN i, void *arg)
|
||||
{
|
||||
|
||||
@ -43,6 +43,7 @@
|
||||
* JS atom table.
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include "jsconfig.h"
|
||||
#include "jstypes.h"
|
||||
#include "jshash.h" /* Added by JSIFY */
|
||||
#include "jsapi.h"
|
||||
@ -155,9 +156,23 @@ struct JSAtomMap {
|
||||
};
|
||||
|
||||
struct JSAtomState {
|
||||
JSRuntime *runtime; /* runtime that owns us */
|
||||
JSHashTable *table; /* hash table containing all atoms */
|
||||
jsatomid liveAtoms; /* number of live atoms after last GC */
|
||||
|
||||
uint32 tablegen; /* number of atoms mutations to
|
||||
optimize hashing */
|
||||
#ifdef JS_THREADSAFE
|
||||
JSThinLock lock;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* From this point until the end of struct definition the struct must
|
||||
* contain only JSAtom fields. We use this to access the storage occupied
|
||||
* by the common atoms in js_FinishCommonAtoms.
|
||||
*
|
||||
* js_common_atom_names defined in jsatom.c contains C strings for atoms
|
||||
* in the order of atom fields here. Therefore you must update that array
|
||||
* if you change member order here.
|
||||
*/
|
||||
|
||||
/* The rt->emptyString atom, see jsstr.c's js_InitRuntimeStringState. */
|
||||
JSAtom *emptyAtom;
|
||||
@ -177,11 +192,9 @@ struct JSAtomState {
|
||||
JSAtom *calleeAtom;
|
||||
JSAtom *callerAtom;
|
||||
JSAtom *classPrototypeAtom;
|
||||
JSAtom *closeAtom;
|
||||
JSAtom *constructorAtom;
|
||||
JSAtom *countAtom;
|
||||
JSAtom *eachAtom;
|
||||
JSAtom *etagoAtom;
|
||||
JSAtom *evalAtom;
|
||||
JSAtom *fileNameAtom;
|
||||
JSAtom *getAtom;
|
||||
@ -193,27 +206,39 @@ struct JSAtomState {
|
||||
JSAtom *lineNumberAtom;
|
||||
JSAtom *messageAtom;
|
||||
JSAtom *nameAtom;
|
||||
JSAtom *namespaceAtom;
|
||||
JSAtom *nextAtom;
|
||||
JSAtom *noSuchMethodAtom;
|
||||
JSAtom *parentAtom;
|
||||
JSAtom *protoAtom;
|
||||
JSAtom *ptagcAtom;
|
||||
JSAtom *qualifierAtom;
|
||||
JSAtom *setAtom;
|
||||
JSAtom *setterAtom;
|
||||
JSAtom *spaceAtom;
|
||||
JSAtom *stackAtom;
|
||||
JSAtom *stagoAtom;
|
||||
JSAtom *starAtom;
|
||||
JSAtom *starQualifierAtom;
|
||||
JSAtom *tagcAtom;
|
||||
JSAtom *toLocaleStringAtom;
|
||||
JSAtom *toSourceAtom;
|
||||
JSAtom *toStringAtom;
|
||||
JSAtom *valueOfAtom;
|
||||
JSAtom *void0Atom;
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
JSAtom *etagoAtom;
|
||||
JSAtom *namespaceAtom;
|
||||
JSAtom *ptagcAtom;
|
||||
JSAtom *qualifierAtom;
|
||||
JSAtom *spaceAtom;
|
||||
JSAtom *stagoAtom;
|
||||
JSAtom *starAtom;
|
||||
JSAtom *starQualifierAtom;
|
||||
JSAtom *tagcAtom;
|
||||
JSAtom *xmlAtom;
|
||||
#endif
|
||||
|
||||
#ifdef NARCISSUS
|
||||
JSAtom *callAtom;
|
||||
JSAtom *constructAtom;
|
||||
JSAtom *hasInstanceAtom;
|
||||
JSAtom *ExecutionContextAtom;
|
||||
JSAtom *currentAtom;
|
||||
#endif
|
||||
|
||||
/* Less frequently used atoms, pinned lazily by JS_ResolveStandardClass. */
|
||||
struct {
|
||||
@ -243,20 +268,16 @@ struct JSAtomState {
|
||||
JSAtom *unwatchAtom;
|
||||
JSAtom *watchAtom;
|
||||
} lazy;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JSThinLock lock;
|
||||
volatile uint32 tablegen;
|
||||
#endif
|
||||
#ifdef NARCISSUS
|
||||
JSAtom *callAtom;
|
||||
JSAtom *constructAtom;
|
||||
JSAtom *hasInstanceAtom;
|
||||
JSAtom *ExecutionContextAtom;
|
||||
JSAtom *currentAtom;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define ATOM_OFFSET_START offsetof(JSAtomState, emptyAtom)
|
||||
#define LAZY_ATOM_OFFSET_START offsetof(JSAtomState, lazy)
|
||||
#define ATOM_OFFSET_LIMIT (sizeof(JSAtomState))
|
||||
|
||||
/* Start and limit offsets should correspond to atoms. */
|
||||
JS_STATIC_ASSERT(ATOM_OFFSET_START % sizeof(JSAtom *) == 0);
|
||||
JS_STATIC_ASSERT(ATOM_OFFSET_LIMIT % sizeof(JSAtom *) == 0);
|
||||
|
||||
#define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom)
|
||||
#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
|
||||
#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name])
|
||||
@ -264,11 +285,22 @@ struct JSAtomState {
|
||||
#define CLASS_ATOM(cx,name) \
|
||||
((cx)->runtime->atomState.classAtoms[JSProto_##name])
|
||||
|
||||
/* Well-known predefined strings and their atoms. */
|
||||
extern const char *js_type_strs[];
|
||||
extern const char *js_boolean_strs[];
|
||||
extern const char *js_proto_strs[];
|
||||
extern const char *const js_common_atom_names[];
|
||||
|
||||
/*
|
||||
* Macros to access C strings for JSType and boolean literals together with
|
||||
* checks that type names and booleans starts from index 1 and 1+JSTYPE_LIMIT
|
||||
* correspondingly.
|
||||
*/
|
||||
#define JS_TYPE_STR(type) (js_common_atom_names[1 + (type)])
|
||||
#define JS_BOOLEAN_STR(type) (js_common_atom_names[1 + JSTYPE_LIMIT + (type)])
|
||||
|
||||
JS_STATIC_ASSERT(1 * sizeof(JSAtom *) ==
|
||||
offsetof(JSAtomState, typeAtoms) - ATOM_OFFSET_START);
|
||||
JS_STATIC_ASSERT((1 + JSTYPE_LIMIT) * sizeof(JSAtom *) ==
|
||||
offsetof(JSAtomState, booleanAtoms) - ATOM_OFFSET_START);
|
||||
|
||||
/* Well-known predefined C strings. */
|
||||
#define JS_PROTO(name,code,init) extern const char js_##name##_str[];
|
||||
#include "jsproto.tbl"
|
||||
#undef JS_PROTO
|
||||
@ -315,6 +347,7 @@ extern const char js_tagc_str[];
|
||||
extern const char js_toSource_str[];
|
||||
extern const char js_toString_str[];
|
||||
extern const char js_toLocaleString_str[];
|
||||
extern const char js_undefined_str[];
|
||||
extern const char js_valueOf_str[];
|
||||
extern const char js_xml_str[];
|
||||
|
||||
@ -327,33 +360,19 @@ extern const char js_current_str[];
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize atom state. Return true on success, false with an out of
|
||||
* memory error report on failure.
|
||||
* Initialize atom state. Return true on success, false on failure to allocate
|
||||
* memory. The caller must zero rt->atomState before calling this function and
|
||||
* only call it after js_InitGC successfully returns.
|
||||
*/
|
||||
extern JSBool
|
||||
js_InitAtomState(JSContext *cx, JSAtomState *state);
|
||||
js_InitAtomState(JSRuntime *rt);
|
||||
|
||||
/*
|
||||
* Free and clear atom state (except for any interned string atoms).
|
||||
* Free and clear atom state including any interned string atoms. This
|
||||
* function must be called before js_FinishGC.
|
||||
*/
|
||||
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);
|
||||
js_FinishAtomState(JSRuntime *rt);
|
||||
|
||||
/*
|
||||
* Atom tracing and garbage collection hooks.
|
||||
@ -366,13 +385,13 @@ extern void
|
||||
js_TraceLockedAtoms(JSTracer *trc, JSBool allAtoms);
|
||||
|
||||
extern void
|
||||
js_SweepAtomState(JSAtomState *state);
|
||||
js_SweepAtomState(JSContext *cx);
|
||||
|
||||
extern JSBool
|
||||
js_InitPinnedAtoms(JSContext *cx, JSAtomState *state);
|
||||
js_InitCommonAtoms(JSContext *cx);
|
||||
|
||||
extern void
|
||||
js_UnpinPinnedAtoms(JSAtomState *state);
|
||||
js_FinishCommonAtoms(JSContext *cx);
|
||||
|
||||
/*
|
||||
* Find or create the atom for a double value. Return null on failure to
|
||||
@ -413,18 +432,19 @@ js_AtomizePrimitiveValue(JSContext *cx, jsval v);
|
||||
extern JSAtom *
|
||||
js_ValueToStringAtom(JSContext *cx, jsval v);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
js_DumpAtoms(JSContext *cx, FILE *fp);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Assign atom an index and insert it on al.
|
||||
*/
|
||||
extern JSAtomListElement *
|
||||
js_IndexAtom(JSContext *cx, JSAtom *atom, JSAtomList *al);
|
||||
|
||||
/*
|
||||
* Get the atom with index i from map.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSAtom *)
|
||||
js_GetAtom(JSContext *cx, JSAtomMap *map, jsatomid i);
|
||||
|
||||
/*
|
||||
* For all unmapped atoms recorded in al, add a mapping from the atom's index
|
||||
* to its address. map->length must already be set to the number of atoms in
|
||||
|
||||
@ -77,7 +77,7 @@ bool_toSource(JSContext *cx, uintN argc, jsval *vp)
|
||||
JS_ASSERT(JSVAL_IS_BOOLEAN(v));
|
||||
JS_snprintf(buf, sizeof buf, "(new %s(%s))",
|
||||
js_BooleanClass.name,
|
||||
js_boolean_strs[JSVAL_TO_BOOLEAN(v) ? 1 : 0]);
|
||||
JS_BOOLEAN_STR(JSVAL_TO_BOOLEAN(v)));
|
||||
str = JS_NewStringCopyZ(cx, buf);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
|
||||
@ -279,16 +279,13 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_BeginRequest(cx);
|
||||
#endif
|
||||
ok = js_InitCommonAtoms(cx);
|
||||
|
||||
/*
|
||||
* Both atomState and the scriptFilenameTable may be left over from a
|
||||
* previous episode of non-zero contexts alive in rt, so don't re-init
|
||||
* either table if it's not necessary. Just repopulate atomState with
|
||||
* well-known internal atoms, and with the reserved identifiers added
|
||||
* by the scanner.
|
||||
* scriptFilenameTable may be left over from a previous episode of
|
||||
* non-zero contexts alive in rt, so don't re-init the table if it's
|
||||
* not necessary.
|
||||
*/
|
||||
ok = (rt->atomState.liveAtoms == 0)
|
||||
? js_InitAtomState(cx, &rt->atomState)
|
||||
: js_InitPinnedAtoms(cx, &rt->atomState);
|
||||
if (ok && !rt->scriptFilenameTable)
|
||||
ok = js_InitRuntimeScriptState(rt);
|
||||
if (ok)
|
||||
@ -373,8 +370,8 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||
js_FinishRuntimeNumberState(cx);
|
||||
js_FinishRuntimeStringState(cx);
|
||||
|
||||
/* Unpin all pinned atoms before final GC. */
|
||||
js_UnpinPinnedAtoms(&rt->atomState);
|
||||
/* Unpin all common atoms before final GC. */
|
||||
js_FinishCommonAtoms(cx);
|
||||
|
||||
/* Clear debugging state to remove GC roots. */
|
||||
JS_ClearAllTraps(cx);
|
||||
@ -408,11 +405,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||
if (last) {
|
||||
js_GC(cx, GC_LAST_CONTEXT);
|
||||
|
||||
/* Try to free atom state, now that no unrooted scripts survive. */
|
||||
if (rt->atomState.liveAtoms == 0)
|
||||
js_FreeAtomState(cx, &rt->atomState);
|
||||
|
||||
/* Also free the script filename table if it exists and is empty. */
|
||||
/* Free the script filename table if it exists and is empty. */
|
||||
if (rt->scriptFilenameTable && rt->scriptFilenameTable->nentries == 0)
|
||||
js_FinishRuntimeScriptState(rt);
|
||||
|
||||
|
||||
@ -224,9 +224,6 @@ struct JSRuntime {
|
||||
JSTraceDataOp gcExtraRootsTraceOp;
|
||||
void *gcExtraRootsData;
|
||||
|
||||
/* Literal table maintained by jsatom.c functions. */
|
||||
JSAtomState atomState;
|
||||
|
||||
/* Random number generator state, used by jsmath.c. */
|
||||
JSBool rngInitialized;
|
||||
int64 rngMultiplier;
|
||||
@ -386,6 +383,9 @@ struct JSRuntime {
|
||||
#define JS_GSN_CACHE(cx) ((cx)->runtime->gsnCache)
|
||||
#endif
|
||||
|
||||
/* Literal table maintained by jsatom.c functions. */
|
||||
JSAtomState atomState;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Function invocation metering. */
|
||||
jsrefcount inlineCalls;
|
||||
|
||||
@ -2455,7 +2455,7 @@ restart:
|
||||
* referenced from dead property ids.
|
||||
*/
|
||||
js_SweepScopeProperties(cx);
|
||||
js_SweepAtomState(&rt->atomState);
|
||||
js_SweepAtomState(cx);
|
||||
|
||||
/*
|
||||
* Sweep script filenames after sweeping functions in the generic loop
|
||||
|
||||
@ -697,7 +697,7 @@ typedef struct CallKey {
|
||||
/* Compensate for typeof null == "object" brain damage. */
|
||||
#define JSTYPE_NULL JSTYPE_LIMIT
|
||||
#define TYPEOF(cx,v) (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
|
||||
#define TYPENAME(t) (((t) == JSTYPE_NULL) ? js_null_str : js_type_strs[t])
|
||||
#define TYPENAME(t) (((t) == JSTYPE_NULL) ? js_null_str : JS_TYPE_STR(t))
|
||||
#define NTYPEHIST (JSTYPE_LIMIT + 1)
|
||||
|
||||
typedef struct CallValue {
|
||||
@ -970,13 +970,13 @@ LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv)
|
||||
cstr = "";
|
||||
switch (TYPEOF(cx, argval)) {
|
||||
case JSTYPE_VOID:
|
||||
cstr = js_type_strs[JSTYPE_VOID];
|
||||
cstr = js_undefined_str;
|
||||
break;
|
||||
case JSTYPE_NULL:
|
||||
cstr = js_null_str;
|
||||
break;
|
||||
case JSTYPE_BOOLEAN:
|
||||
cstr = js_boolean_strs[JSVAL_TO_BOOLEAN(argval)];
|
||||
cstr = JS_BOOLEAN_STR(JSVAL_TO_BOOLEAN(argval));
|
||||
break;
|
||||
case JSTYPE_NUMBER:
|
||||
if (JSVAL_IS_INT(argval)) {
|
||||
|
||||
@ -3962,7 +3962,7 @@ js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
|
||||
JSDVG_SEARCH_STACK, save, str,
|
||||
(hint == JSTYPE_VOID)
|
||||
? "primitive type"
|
||||
: js_type_strs[hint]);
|
||||
: JS_TYPE_STR(hint));
|
||||
return JS_FALSE;
|
||||
}
|
||||
out:
|
||||
|
||||
@ -1760,6 +1760,14 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
#define LOAD_REGEXP(PCOFF) \
|
||||
GET_REGEXP_FROM_BYTECODE(jp->script, pc, PCOFF, obj)
|
||||
|
||||
#define GET_SOURCE_NOTE_ATOM(sn, atom) \
|
||||
JS_BEGIN_MACRO \
|
||||
jsatomid atomIndex_ = (jsatomid) js_GetSrcNoteOffset((sn), 0); \
|
||||
\
|
||||
LOCAL_ASSERT(atomIndex_ < jp->script->atomMap.length); \
|
||||
(atom) = jp->script->atomMap.vector[atomIndex_]; \
|
||||
JS_END_MACRO
|
||||
|
||||
/*
|
||||
* Get atom from jp->script's atom map, quote/escape its string appropriately
|
||||
* into rval, and select fmt from the quoted and unquoted alternatives.
|
||||
@ -2047,8 +2055,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
break;
|
||||
|
||||
case SRC_LABEL:
|
||||
atom = js_GetAtom(cx, &jp->script->atomMap,
|
||||
(jsatomid) js_GetSrcNoteOffset(sn, 0));
|
||||
GET_SOURCE_NOTE_ATOM(sn, atom);
|
||||
jp->indent -= 4;
|
||||
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
|
||||
if (!rval)
|
||||
@ -2059,8 +2066,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
break;
|
||||
|
||||
case SRC_LABELBRACE:
|
||||
atom = js_GetAtom(cx, &jp->script->atomMap,
|
||||
(jsatomid) js_GetSrcNoteOffset(sn, 0));
|
||||
GET_SOURCE_NOTE_ATOM(sn, atom);
|
||||
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
|
||||
if (!rval)
|
||||
return NULL;
|
||||
@ -2903,8 +2909,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
break;
|
||||
|
||||
case SRC_CONT2LABEL:
|
||||
atom = js_GetAtom(cx, &jp->script->atomMap,
|
||||
(jsatomid) js_GetSrcNoteOffset(sn, 0));
|
||||
GET_SOURCE_NOTE_ATOM(sn, atom);
|
||||
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
|
||||
if (!rval)
|
||||
return NULL;
|
||||
@ -2917,8 +2922,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
break;
|
||||
|
||||
case SRC_BREAK2LABEL:
|
||||
atom = js_GetAtom(cx, &jp->script->atomMap,
|
||||
(jsatomid) js_GetSrcNoteOffset(sn, 0));
|
||||
GET_SOURCE_NOTE_ATOM(sn, atom);
|
||||
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0);
|
||||
if (!rval)
|
||||
return NULL;
|
||||
@ -4000,10 +4004,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
sn = js_GetSrcNote(jp->script, pc2);
|
||||
if (sn) {
|
||||
LOCAL_ASSERT(SN_TYPE(sn) == SRC_LABEL);
|
||||
table[j].label =
|
||||
js_GetAtom(cx, &jp->script->atomMap,
|
||||
(jsatomid)
|
||||
js_GetSrcNoteOffset(sn, 0));
|
||||
GET_SOURCE_NOTE_ATOM(sn, table[j].label);
|
||||
}
|
||||
table[j].key = INT_TO_JSVAL(low + i);
|
||||
table[j].offset = off2;
|
||||
@ -4060,9 +4061,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
sn = js_GetSrcNote(jp->script, pc2);
|
||||
if (sn) {
|
||||
LOCAL_ASSERT(SN_TYPE(sn) == SRC_LABEL);
|
||||
table[k].label =
|
||||
js_GetAtom(cx, &jp->script->atomMap, (jsatomid)
|
||||
js_GetSrcNoteOffset(sn, 0));
|
||||
GET_SOURCE_NOTE_ATOM(sn, table[k].label);
|
||||
} else {
|
||||
table[k].label = NULL;
|
||||
}
|
||||
|
||||
@ -2483,7 +2483,7 @@ GetNamespace(JSContext *cx, JSXMLQName *qn, const JSXMLArray *inScopeNSes)
|
||||
qn->prefix
|
||||
? js_ValueToPrintableString(cx,
|
||||
STRING_TO_JSVAL(qn->prefix))
|
||||
: js_type_strs[JSTYPE_VOID]);
|
||||
: js_undefined_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -3047,9 +3047,7 @@ ToXMLString(JSContext *cx, jsval v)
|
||||
if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_XML_CONVERSION,
|
||||
js_type_strs[JSVAL_IS_NULL(v)
|
||||
? JSTYPE_NULL
|
||||
: JSTYPE_VOID]);
|
||||
JSVAL_IS_NULL(v) ? js_null_str : js_undefined_str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user