diff --git a/mozilla/js/src/js.c b/mozilla/js/src/js.c index 7526b062f6d..3a4851f093c 100644 --- a/mozilla/js/src/js.c +++ b/mozilla/js/src/js.c @@ -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 { diff --git a/mozilla/js/src/jsapi.c b/mozilla/js/src/jsapi.c index 0328975264f..f793f0b21a5 100644 --- a/mozilla/js/src/jsapi.c +++ b/mozilla/js/src/jsapi.c @@ -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) diff --git a/mozilla/js/src/jsatom.c b/mozilla/js/src/jsatom.c index 8df02aa2f25..8b63bc5d5f3 100644 --- a/mozilla/js/src/jsatom.c +++ b/mozilla/js/src/jsatom.c @@ -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) { diff --git a/mozilla/js/src/jsatom.h b/mozilla/js/src/jsatom.h index 75901ae85c4..a4819df38d9 100644 --- a/mozilla/js/src/jsatom.h +++ b/mozilla/js/src/jsatom.h @@ -43,6 +43,7 @@ * JS atom table. */ #include +#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 diff --git a/mozilla/js/src/jsbool.c b/mozilla/js/src/jsbool.c index 778426006c8..ae8520eeaa1 100644 --- a/mozilla/js/src/jsbool.c +++ b/mozilla/js/src/jsbool.c @@ -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; diff --git a/mozilla/js/src/jscntxt.c b/mozilla/js/src/jscntxt.c index 84916039244..27c6a60f259 100644 --- a/mozilla/js/src/jscntxt.c +++ b/mozilla/js/src/jscntxt.c @@ -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); diff --git a/mozilla/js/src/jscntxt.h b/mozilla/js/src/jscntxt.h index a97d3fe4a00..e8cce7adaf8 100644 --- a/mozilla/js/src/jscntxt.h +++ b/mozilla/js/src/jscntxt.h @@ -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; diff --git a/mozilla/js/src/jsgc.c b/mozilla/js/src/jsgc.c index b040d989019..fbec1199aed 100644 --- a/mozilla/js/src/jsgc.c +++ b/mozilla/js/src/jsgc.c @@ -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 diff --git a/mozilla/js/src/jsinterp.c b/mozilla/js/src/jsinterp.c index b875ad3c993..a5542723479 100644 --- a/mozilla/js/src/jsinterp.c +++ b/mozilla/js/src/jsinterp.c @@ -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)) { diff --git a/mozilla/js/src/jsobj.c b/mozilla/js/src/jsobj.c index e9ea012deb0..a8748ac6aed 100644 --- a/mozilla/js/src/jsobj.c +++ b/mozilla/js/src/jsobj.c @@ -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: diff --git a/mozilla/js/src/jsopcode.c b/mozilla/js/src/jsopcode.c index b8c29df573a..c09b3b994a4 100644 --- a/mozilla/js/src/jsopcode.c +++ b/mozilla/js/src/jsopcode.c @@ -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; } diff --git a/mozilla/js/src/jsxml.c b/mozilla/js/src/jsxml.c index 3d0e04c92ed..313d3fbb030 100644 --- a/mozilla/js/src/jsxml.c +++ b/mozilla/js/src/jsxml.c @@ -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; }