Bug 386265: using double kashing for atoms. r=brendan

This commit is contained in:
igor@mir2.org 2007-08-11 13:25:16 -07:00
Родитель 0e2dd9e951
Коммит db0f3d53a2
20 изменённых файлов: 611 добавлений и 638 удалений

Просмотреть файл

@ -966,9 +966,9 @@ SrcNotes(JSContext *cx, JSScript *script)
jssrcnote *notes, *sn;
JSSrcNoteType type;
const char *name;
jsatomid atomIndex;
uint32 index;
JSAtom *atom;
JSString *str;
fprintf(gOutFile, "\nSource notes:\n");
offset = 0;
@ -1015,20 +1015,19 @@ SrcNotes(JSContext *cx, JSScript *script)
case SRC_LABEL:
case SRC_LABELBRACE:
case SRC_BREAK2LABEL:
case SRC_CONT2LABEL: {
const char *bytes;
atomIndex = (jsatomid) js_GetSrcNoteOffset(sn, 0);
JS_GET_SCRIPT_ATOM(script, atomIndex, atom);
bytes = js_AtomToPrintableString(cx, atom);
fprintf(gOutFile, " atom %u (%s)", (uintN)atomIndex, bytes);
case SRC_CONT2LABEL:
index = js_GetSrcNoteOffset(sn, 0);
JS_GET_SCRIPT_ATOM(script, index, atom);
JS_ASSERT(ATOM_IS_STRING(atom));
str = ATOM_TO_STRING(atom);
fprintf(gOutFile, " atom %u (", index);
js_FileEscapedString(gOutFile, str, 0);
putc(')', gOutFile);
break;
}
case SRC_FUNCDEF: {
const char *bytes;
JSObject *obj;
JSFunction *fun;
JSString *str;
index = js_GetSrcNoteOffset(sn, 0);
JS_GET_SCRIPT_OBJECT(script, index, obj);
@ -1273,23 +1272,35 @@ DumpScope(JSContext *cx, JSObject *obj, FILE *fp)
uintN i;
JSScope *scope;
JSScopeProperty *sprop;
jsval v;
JSString *str;
i = 0;
scope = OBJ_SCOPE(obj);
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
if (SCOPE_HAD_MIDDLE_DELETE(scope) && !SCOPE_HAS_PROPERTY(scope, sprop))
continue;
fprintf(fp, "%3u %p", i, (void *)sprop);
if (JSID_IS_INT(sprop->id)) {
fprintf(fp, " [%ld]", (long)JSVAL_TO_INT(sprop->id));
} else if (JSID_IS_ATOM(sprop->id)) {
JSAtom *atom = JSID_TO_ATOM(sprop->id);
fprintf(fp, " \"%s\"", js_AtomToPrintableString(cx, atom));
} else {
jsval v = OBJECT_TO_JSVAL(JSID_TO_OBJECT(sprop->id));
fprintf(fp, " \"%s\"", js_ValueToPrintableString(cx, v));
}
fprintf(fp, "%3u %p ", i, (void *)sprop);
v = ID_TO_VALUE(sprop->id);
if (JSID_IS_INT(sprop->id)) {
fprintf(fp, "[%ld]", (long)JSVAL_TO_INT(v));
} else {
if (JSID_IS_ATOM(sprop->id)) {
str = JSVAL_TO_STRING(v);
} else if (JSID_IS_HIDDEN(sprop->id)) {
str = JSVAL_TO_STRING(v);
fputs("hidden ", fp);
} else {
JS_ASSERT(JSID_IS_OBJECT(sprop->id));
str = js_ValueToString(cx, v);
fputs("object ", fp);
}
if (!str)
fputs("<error>", fp);
else
js_FileEscapedString(fp, str, '"');
}
#define DUMP_ATTR(name) if (sprop->attrs & JSPROP_##name) fputs(" " #name, fp)
DUMP_ATTR(ENUMERATE);
DUMP_ATTR(READONLY);

Просмотреть файл

@ -1305,7 +1305,7 @@ StdNameToAtom(JSContext *cx, JSStdName *stdn)
if (!atom) {
name = stdn->name;
if (name) {
atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
atom = js_Atomize(cx, name, strlen(name), 0);
OFFSET_TO_ATOM(cx->runtime, offset) = atom;
}
}
@ -1964,10 +1964,6 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
name = "function";
break;
case JSTRACE_ATOM:
name = "atom";
break;
#if JS_HAS_XML_SUPPORT
case JSTRACE_NAMESPACE:
name = "namespace";
@ -2028,21 +2024,8 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
break;
}
case JSTRACE_ATOM:
{
JSAtom *atom = (JSAtom *)thing;
if (ATOM_IS_INT(atom))
JS_snprintf(buf, bufsize, "%d", ATOM_TO_INT(atom));
else if (ATOM_IS_STRING(atom))
js_PutEscapedString(buf, bufsize, ATOM_TO_STRING(atom), 0);
else
JS_snprintf(buf, bufsize, "object");
break;
}
#if JS_HAS_XML_SUPPORT
case GCX_NAMESPACE:
case JSTRACE_NAMESPACE:
{
JSXMLNamespace *ns = (JSXMLNamespace *)thing;
@ -2059,7 +2042,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
break;
}
case GCX_QNAME:
case JSTRACE_QNAME:
{
JSXMLQName *qn = (JSXMLQName *)thing;
@ -2084,7 +2067,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc,
break;
}
case GCX_XML:
case JSTRACE_XML:
{
extern const char *js_xml_class_str[];
JSXML *xml = (JSXML *)thing;
@ -2897,7 +2880,7 @@ JS_GetConstructor(JSContext *cx, JSObject *proto)
JS_PUBLIC_API(JSBool)
JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
{
JS_ASSERT(((jsid)obj & JSID_TAGMASK) == 0);
JS_ASSERT(JSID_IS_OBJECT(obj));
*idp = OBJECT_TO_JSID(obj);
return JS_TRUE;
}

Просмотреть файл

@ -212,98 +212,138 @@ const char js_ExecutionContext_str[] = "ExecutionContext";
const char js_current_str[] = "current";
#endif
#define HASH_DOUBLE(dp) ((JSDOUBLE_HI32(*dp) ^ JSDOUBLE_LO32(*dp)))
/*
* JSAtomState.doubleAtoms and JSAtomState.stringAtoms hashtable entry. To
* support pinned and interned string atoms, we use the lowest bits of the
* keyAndFlags field to store ATOM_PINNED and ATOM_INTERNED flags.
*/
typedef struct JSAtomHashEntry {
JSDHashEntryHdr hdr;
jsuword keyAndFlags;
} JSAtomHashEntry;
JS_STATIC_DLL_CALLBACK(JSHashNumber)
js_hash_atom_key(const void *key)
#define ATOM_ENTRY_FLAG_MASK (ATOM_PINNED | ATOM_INTERNED)
JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JSVAL_ALIGN);
/*
* Helper macros to access and modify JSAtomHashEntry.
*/
#define TO_ATOM_ENTRY(hdr) ((JSAtomHashEntry *) hdr)
#define ATOM_ENTRY_KEY(entry) \
((void *)((entry)->keyAndFlags & ~ATOM_ENTRY_FLAG_MASK))
#define ATOM_ENTRY_FLAGS(entry) \
((uintN)((entry)->keyAndFlags & ATOM_ENTRY_FLAG_MASK))
#define INIT_ATOM_ENTRY(entry, key) \
((void)((entry)->keyAndFlags = (jsuword)(key)))
#define ADD_ATOM_ENTRY_FLAGS(entry, flags) \
((void)((entry)->keyAndFlags |= (jsuword)(flags)))
#define CLEAR_ATOM_ENTRY_FLAGS(entry, flags) \
((void)((entry)->keyAndFlags &= ~(jsuword)(flags)))
static const JSDHashTableOps DoubleHashOps;
static const JSDHashTableOps StringHashOps;
#define IS_DOUBLE_TABLE(table) ((table)->ops == &DoubleHashOps)
#define IS_STRING_TABLE(table) ((table)->ops == &StringHashOps)
#define IS_INITIALIZED_STATE(state) IS_DOUBLE_TABLE(&(state)->doubleAtoms)
JS_STATIC_DLL_CALLBACK(JSDHashNumber)
HashDouble(JSDHashTable *table, const void *key)
{
jsval v;
jsdouble *dp;
jsdouble d;
v = (jsval)key;
if (JSVAL_IS_STRING(v))
return js_HashString(JSVAL_TO_STRING(v));
if (JSVAL_IS_DOUBLE(v)) {
dp = JSVAL_TO_DOUBLE(v);
return HASH_DOUBLE(dp);
}
JS_ASSERT(JSVAL_IS_INT(v) || v == JSVAL_TRUE || v == JSVAL_FALSE ||
v == JSVAL_NULL || v == JSVAL_VOID);
return (JSHashNumber)v;
JS_ASSERT(IS_DOUBLE_TABLE(table));
d = *(jsdouble *)key;
return JSDOUBLE_HI32(d) ^ JSDOUBLE_LO32(d);
}
JS_STATIC_DLL_CALLBACK(intN)
js_compare_atom_keys(const void *k1, const void *k2)
JS_STATIC_DLL_CALLBACK(JSDHashNumber)
HashString(JSDHashTable *table, const void *key)
{
jsval v1, v2;
JS_ASSERT(IS_STRING_TABLE(table));
return js_HashString((JSString *)key);
}
v1 = (jsval)k1, v2 = (jsval)k2;
if (JSVAL_IS_STRING(v1) && JSVAL_IS_STRING(v2))
return js_EqualStrings(JSVAL_TO_STRING(v1), JSVAL_TO_STRING(v2));
if (JSVAL_IS_DOUBLE(v1) && JSVAL_IS_DOUBLE(v2)) {
double d1 = *JSVAL_TO_DOUBLE(v1);
double d2 = *JSVAL_TO_DOUBLE(v2);
if (JSDOUBLE_IS_NaN(d1))
return JSDOUBLE_IS_NaN(d2);
JS_STATIC_DLL_CALLBACK(JSBool)
MatchDouble(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key)
{
JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
jsdouble d1, d2;
JS_ASSERT(IS_DOUBLE_TABLE(table));
if (entry->keyAndFlags == 0) {
/* See comments in MatchString. */
return JS_FALSE;
}
d1 = *(jsdouble *)ATOM_ENTRY_KEY(entry);
d2 = *(jsdouble *)key;
if (JSDOUBLE_IS_NaN(d1))
return JSDOUBLE_IS_NaN(d2);
#if defined(XP_WIN)
/* XXX MSVC miscompiles such that (NaN == 0) */
if (JSDOUBLE_IS_NaN(d2))
return JS_FALSE;
/* XXX MSVC miscompiles such that (NaN == 0) */
if (JSDOUBLE_IS_NaN(d2))
return JS_FALSE;
#endif
return d1 == d2;
return d1 == d2;
}
JS_STATIC_DLL_CALLBACK(JSBool)
MatchString(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key)
{
JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
JS_ASSERT(IS_STRING_TABLE(table));
if (entry->keyAndFlags == 0) {
/*
* This happens when js_AtomizeString adds a new hash entry and
* releases the lock but before it takes the lock the second time to
* initialize keyAndFlags for the entry.
*
* We always return false for such entries so JS_DHashTableOperate
* never finds them. We clean them during GC's sweep phase.
*
* It means that with a contested lock or when GC is triggered outside
* the lock we may end up adding two entries, but this is a price for
* simpler code.
*/
return JS_FALSE;
}
return v1 == v2;
return js_EqualStrings((JSString *)ATOM_ENTRY_KEY(entry), (JSString *)key);
}
JS_STATIC_DLL_CALLBACK(int)
js_compare_stub(const void *v1, const void *v2)
{
return 1;
}
/* These next two are exported to jsscript.c and used similarly there. */
void * JS_DLL_CALLBACK
js_alloc_table_space(void *priv, size_t size)
{
return malloc(size);
}
void JS_DLL_CALLBACK
js_free_table_space(void *priv, void *item)
{
free(item);
}
JS_STATIC_DLL_CALLBACK(JSHashEntry *)
js_alloc_atom(void *priv, const void *key)
{
JSAtom *atom;
atom = (JSAtom *) malloc(sizeof(JSAtom));
if (!atom)
return NULL;
((JSAtomState *)priv)->tablegen++;
atom->entry.key = key;
atom->entry.value = NULL;
atom->flags = 0;
return &atom->entry;
}
JS_STATIC_DLL_CALLBACK(void)
js_free_atom(void *priv, JSHashEntry *he, uintN flag)
{
if (flag != HT_FREE_ENTRY)
return;
((JSAtomState *)priv)->tablegen++;
free(he);
}
static JSHashAllocOps atom_alloc_ops = {
js_alloc_table_space, js_free_table_space,
js_alloc_atom, js_free_atom
static const JSDHashTableOps DoubleHashOps = {
JS_DHashAllocTable,
JS_DHashFreeTable,
HashDouble,
MatchDouble,
JS_DHashMoveEntryStub,
JS_DHashClearEntryStub,
JS_DHashFinalizeStub,
NULL
};
#define JS_ATOM_HASH_SIZE 1024
static const JSDHashTableOps StringHashOps = {
JS_DHashAllocTable,
JS_DHashFreeTable,
HashString,
MatchString,
JS_DHashMoveEntryStub,
JS_DHashClearEntryStub,
JS_DHashFinalizeStub,
NULL
};
/*
* For a browser build from 2007-08-09 after the browser starts up there are
* just 55 double atoms, but over 15000 string atoms. Not to penalize more
* economical embeddings allocating too much memory initially we initialize
* atomized strings with just 1K entries.
*/
#define JS_STRING_HASH_COUNT 1024
#define JS_DOUBLE_HASH_COUNT 64
JSBool
js_InitAtomState(JSRuntime *rt)
@ -313,32 +353,50 @@ js_InitAtomState(JSRuntime *rt)
/*
* The caller must zero the state before calling this function.
*/
JS_ASSERT(!state->table);
JS_ASSERT(!state->stringAtoms.ops);
JS_ASSERT(!state->doubleAtoms.ops);
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)
if (!JS_DHashTableInit(&state->stringAtoms, &StringHashOps,
NULL, sizeof(JSAtomHashEntry),
JS_DHASH_DEFAULT_CAPACITY(JS_STRING_HASH_COUNT))) {
state->stringAtoms.ops = NULL;
return JS_FALSE;
}
JS_ASSERT(IS_STRING_TABLE(&state->stringAtoms));
if (!JS_DHashTableInit(&state->doubleAtoms, &DoubleHashOps,
NULL, sizeof(JSAtomHashEntry),
JS_DHASH_DEFAULT_CAPACITY(JS_DOUBLE_HASH_COUNT))) {
state->doubleAtoms.ops = NULL;
JS_DHashTableFinish(&state->stringAtoms);
state->stringAtoms.ops = NULL;
return JS_FALSE;
}
JS_ASSERT(IS_DOUBLE_TABLE(&state->doubleAtoms));
#ifdef JS_THREADSAFE
js_InitLock(&state->lock);
#endif
JS_ASSERT(IS_INITIALIZED_STATE(state));
return JS_TRUE;
}
JS_STATIC_DLL_CALLBACK(intN)
js_atom_uninterner(JSHashEntry *he, intN i, void *arg)
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
js_string_uninterner(JSDHashTable *table, JSDHashEntryHdr *hdr,
uint32 number, void *arg)
{
JSAtom *atom;
JSRuntime *rt;
JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
JSRuntime *rt = (JSRuntime *)arg;
atom = (JSAtom *)he;
rt = (JSRuntime *)arg;
if (ATOM_IS_STRING(atom))
js_FinalizeStringRT(rt, ATOM_TO_STRING(atom));
return HT_ENUMERATE_NEXT;
/*
* Any string entry that remains at this point must be initialized, as the
* last GC should clean any uninitialized ones.
*/
JS_ASSERT(IS_STRING_TABLE(table));
JS_ASSERT(entry->keyAndFlags != 0);
js_FinalizeStringRT(rt, (JSString *)ATOM_ENTRY_KEY(entry));
return JS_DHASH_NEXT;
}
void
@ -346,16 +404,18 @@ js_FinishAtomState(JSRuntime *rt)
{
JSAtomState *state = &rt->atomState;
if (!state->table) {
if (!IS_INITIALIZED_STATE(state)) {
/*
* state->table is null when JS_NewRuntime fails and calls
* JS_DestroyRuntime on a partially initialized runtime.
* We are called with uninitialized state when JS_NewRuntime fails and
* calls JS_DestroyRuntime on a partially initialized runtime.
*/
return;
}
JS_HashTableEnumerateEntries(state->table, js_atom_uninterner, rt);
JS_HashTableDestroy(state->table);
JS_DHashTableEnumerate(&state->stringAtoms, js_string_uninterner, rt);
JS_DHashTableFinish(&state->stringAtoms);
JS_DHashTableFinish(&state->doubleAtoms);
#ifdef JS_THREADSAFE
js_FinishLock(&state->lock);
#endif
@ -371,7 +431,7 @@ js_InitCommonAtoms(JSContext *cx)
uintN i;
JSAtom **atoms;
atoms = (JSAtom **)((uint8 *)state + ATOM_OFFSET_START);
atoms = COMMON_ATOMS_START(state);
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);
@ -384,14 +444,13 @@ js_InitCommonAtoms(JSContext *cx)
return JS_TRUE;
}
JS_STATIC_DLL_CALLBACK(intN)
js_atom_unpinner(JSHashEntry *he, intN i, void *arg)
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
js_atom_unpinner(JSDHashTable *table, JSDHashEntryHdr *hdr,
uint32 number, void *arg)
{
JSAtom *atom;
atom = (JSAtom *)he;
atom->flags &= ~ATOM_PINNED;
return HT_ENUMERATE_NEXT;
JS_ASSERT(IS_STRING_TABLE(table));
CLEAR_ATOM_ENTRY_FLAGS(TO_ATOM_ENTRY(hdr), ATOM_PINNED);
return JS_DHASH_NEXT;
}
void
@ -399,78 +458,83 @@ js_FinishCommonAtoms(JSContext *cx)
{
JSAtomState *state = &cx->runtime->atomState;
JS_HashTableEnumerateEntries(state->table, js_atom_unpinner, NULL);
JS_DHashTableEnumerate(&state->stringAtoms, js_atom_unpinner, NULL);
#ifdef DEBUG
memset((uint8 *)state + ATOM_OFFSET_START, JS_FREE_PATTERN,
memset(COMMON_ATOMS_START(state), JS_FREE_PATTERN,
ATOM_OFFSET_LIMIT - ATOM_OFFSET_START);
#endif
}
void
js_TraceAtom(JSTracer *trc, JSAtom *atom)
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
js_locked_atom_tracer(JSDHashTable *table, JSDHashEntryHdr *hdr,
uint32 number, void *arg)
{
jsval key;
JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
JSTracer *trc = (JSTracer *)arg;
key = ATOM_KEY(atom);
JS_CALL_VALUE_TRACER(trc, key, "key");
if (atom->flags & ATOM_HIDDEN)
JS_CALL_TRACER(trc, atom->entry.value, JSTRACE_ATOM, "hidden");
}
typedef struct TraceArgs {
JSBool allAtoms;
JSTracer *trc;
} TraceArgs;
JS_STATIC_DLL_CALLBACK(intN)
js_locked_atom_tracer(JSHashEntry *he, intN i, void *arg)
{
JSAtom *atom;
TraceArgs *args;
atom = (JSAtom *)he;
args = (TraceArgs *)arg;
if ((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) || args->allAtoms) {
JS_SET_TRACING_INDEX(args->trc,
(atom->flags & ATOM_PINNED)
? "pinned_atom"
: (atom->flags & ATOM_INTERNED)
? "interned_atom"
: "locked_atom",
(size_t)i);
JS_CallTracer(args->trc, atom, JSTRACE_ATOM);
if (entry->keyAndFlags == 0) {
/* Ignore uninitialized entries during tracing. */
return JS_DHASH_NEXT;
}
return HT_ENUMERATE_NEXT;
JS_SET_TRACING_INDEX(trc, "locked_atom", (size_t)number);
JS_CallTracer(trc, ATOM_ENTRY_KEY(entry),
IS_STRING_TABLE(table) ? JSTRACE_STRING : JSTRACE_DOUBLE);
return JS_DHASH_NEXT;
}
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
js_pinned_atom_tracer(JSDHashTable *table, JSDHashEntryHdr *hdr,
uint32 number, void *arg)
{
JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
JSTracer *trc = (JSTracer *)arg;
uintN flags = ATOM_ENTRY_FLAGS(entry);
JS_ASSERT(IS_STRING_TABLE(table));
if (flags & (ATOM_PINNED | ATOM_INTERNED)) {
JS_SET_TRACING_INDEX(trc,
flags & ATOM_PINNED
? "pinned_atom"
: "interned_atom",
(size_t)number);
JS_CallTracer(trc, ATOM_ENTRY_KEY(entry), JSTRACE_STRING);
}
return JS_DHASH_NEXT;
}
void
js_TraceLockedAtoms(JSTracer *trc, JSBool allAtoms)
js_TraceAtomState(JSTracer *trc, JSBool allAtoms)
{
JSAtomState *state;
TraceArgs args;
state = &trc->context->runtime->atomState;
if (!state->table)
return;
args.allAtoms = allAtoms;
args.trc = trc;
JS_HashTableEnumerateEntries(state->table, js_locked_atom_tracer, &args);
if (allAtoms) {
JS_DHashTableEnumerate(&state->doubleAtoms, js_locked_atom_tracer, trc);
JS_DHashTableEnumerate(&state->stringAtoms, js_locked_atom_tracer, trc);
} else {
JS_DHashTableEnumerate(&state->stringAtoms, js_pinned_atom_tracer, trc);
}
}
JS_STATIC_DLL_CALLBACK(intN)
js_atom_sweeper(JSHashEntry *he, intN i, void *arg)
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
js_atom_sweeper(JSDHashTable *table, JSDHashEntryHdr *hdr,
uint32 number, void *arg)
{
JSAtom *atom;
JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
JSContext *cx = (JSContext *)arg;
atom = (JSAtom *)he;
if (atom->flags & ATOM_MARK) {
atom->flags &= ~ATOM_MARK;
return HT_ENUMERATE_NEXT;
/* Remove uninitialized entries. */
if (entry->keyAndFlags == 0)
return JS_DHASH_REMOVE;
if (ATOM_ENTRY_FLAGS(entry) & (ATOM_PINNED | ATOM_INTERNED)) {
/* Pinned or interned key cannot be finalized. */
JS_ASSERT(!js_IsAboutToBeFinalized(cx, ATOM_ENTRY_KEY(entry)));
} else if (js_IsAboutToBeFinalized(cx, ATOM_ENTRY_KEY(entry))) {
/* Remove entries with things about to be GC'ed. */
return JS_DHASH_REMOVE;
}
JS_ASSERT((atom->flags & (ATOM_PINNED | ATOM_INTERNED)) == 0);
atom->entry.key = atom->entry.value = NULL;
atom->flags = 0;
return HT_ENUMERATE_REMOVE;
return JS_DHASH_NEXT;
}
void
@ -478,170 +542,148 @@ js_SweepAtomState(JSContext *cx)
{
JSAtomState *state = &cx->runtime->atomState;
JS_HashTableEnumerateEntries(state->table, js_atom_sweeper, NULL);
JS_DHashTableEnumerate(&state->doubleAtoms, js_atom_sweeper, cx);
JS_DHashTableEnumerate(&state->stringAtoms, js_atom_sweeper, cx);
/*
* Optimize for simplicity and mutate tablegen even if the sweeper has not
* removed any entries.
*/
state->tablegen++;
}
static JSAtom *
AtomizeHashedKey(JSContext *cx, jsval key, JSHashNumber keyHash)
{
JSAtomState *state;
JSHashTable *table;
JSHashEntry *he, **hep;
JSAtom *atom;
state = &cx->runtime->atomState;
JS_LOCK(&state->lock, cx);
table = state->table;
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
if ((he = *hep) == NULL) {
he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
if (!he) {
JS_UNLOCK(&state->lock,cx);
JS_ReportOutOfMemory(cx);
return NULL;
}
}
atom = (JSAtom *)he;
cx->weakRoots.lastAtom = atom;
JS_UNLOCK(&state->lock,cx);
return atom;
}
/* Worst-case alignment grain and aligning macro for 2x-sized buffer. */
#define ALIGNMENT(t) JS_MAX(JSVAL_ALIGN, sizeof(t))
#define ALIGN(b,t) ((t*) &(b)[ALIGNMENT(t) - (jsuword)(b) % ALIGNMENT(t)])
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;
JSDHashTable *table;
JSAtomHashEntry *entry;
uint32 gen;
JSAtom *atom;
jsdouble *key;
jsval v;
dp = ALIGN(buf, double);
*dp = d;
keyHash = HASH_DOUBLE(dp);
key = DOUBLE_TO_JSVAL(dp);
state = &cx->runtime->atomState;
table = state->table;
table = &state->doubleAtoms;
JS_LOCK(&state->lock, cx);
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
if ((he = *hep) == NULL) {
gen = state->tablegen;
entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, &d, JS_DHASH_ADD));
if (!entry)
goto failed_hash_add;
if (entry->keyAndFlags == 0) {
gen = ++state->tablegen;
JS_UNLOCK(&state->lock, cx);
if (!js_NewDoubleValue(cx, d, &key))
key = js_NewDouble(cx, d, 0);
if (!key)
return NULL;
JS_LOCK(&state->lock, cx);
if (state->tablegen != gen) {
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
if ((he = *hep) != NULL)
if (state->tablegen == gen) {
JS_ASSERT(entry->keyAndFlags == 0);
} else {
entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, key,
JS_DHASH_ADD));
if (!entry)
goto failed_hash_add;
if (entry->keyAndFlags != 0)
goto finish;
++state->tablegen;
}
he = JS_HashTableRawAdd(table, hep, keyHash, (void *)key, NULL);
if (!he) {
JS_UNLOCK(&state->lock, cx);
JS_ReportOutOfMemory(cx);
return NULL;
}
INIT_ATOM_ENTRY(entry, key);
}
finish:
atom = (JSAtom *)he;
cx->weakRoots.lastAtom = atom;
v = DOUBLE_TO_JSVAL((jsdouble *)ATOM_ENTRY_KEY(entry));
cx->weakRoots.lastAtom = v;
JS_UNLOCK(&state->lock,cx);
return atom;
}
/*
* To put an atom into the hidden subspace. XOR its keyHash with this value,
* which is (sqrt(2)-1) in 32-bit fixed point.
*/
#define HIDDEN_ATOM_SUBSPACE_KEYHASH 0x6A09E667
return (JSAtom *)v;
failed_hash_add:
JS_UNLOCK(&state->lock,cx);
JS_ReportOutOfMemory(cx);
return NULL;
}
JSAtom *
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
{
JSHashNumber keyHash;
void *key;
JSAtomState *state;
JSHashTable *table;
JSHashEntry *he, **hep;
JSDHashTable *table;
JSAtomHashEntry *entry;
JSString *key;
uint32 gen;
JSString *hashed;
JSAtom *atom;
jsval v;
keyHash = js_HashString(str);
if (flags & ATOM_HIDDEN)
keyHash ^= HIDDEN_ATOM_SUBSPACE_KEYHASH;
key = (void *)STRING_TO_JSVAL(str);
JS_ASSERT((flags &
~(ATOM_PINNED | ATOM_INTERNED | ATOM_TMPSTR | ATOM_NOCOPY))
== 0);
state = &cx->runtime->atomState;
table = state->table;
table = &state->stringAtoms;
JS_LOCK(&state->lock, cx);
hep = JS_HashTableRawLookup(table, keyHash, key);
if ((he = *hep) == NULL) {
entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, str, JS_DHASH_ADD));
if (!entry)
goto failed_hash_add;
if (entry->keyAndFlags == 0) {
++state->tablegen;
gen = state->tablegen;
JS_UNLOCK(&state->lock, cx);
if (flags & ATOM_TMPSTR) {
if (flags & ATOM_NOCOPY) {
hashed = js_NewString(cx, str->chars, str->length, 0);
if (!hashed)
key = js_NewString(cx, str->chars, str->length, 0);
if (!key)
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)
key = js_NewStringCopyN(cx, str->chars, str->length);
if (!key)
return NULL;
}
key = (void *)STRING_TO_JSVAL(hashed);
} else {
JS_ASSERT((flags & ATOM_NOCOPY) == 0);
if (!JS_MakeStringImmutable(cx, str))
return NULL;
key = str;
}
JS_LOCK(&state->lock, cx);
if (state->tablegen != gen) {
hep = JS_HashTableRawLookup(table, keyHash, key);
if ((he = *hep) != NULL)
if (state->tablegen == gen) {
JS_ASSERT(entry->keyAndFlags == 0);
} else {
entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, key,
JS_DHASH_ADD));
if (!entry)
goto failed_hash_add;
if (entry->keyAndFlags != 0)
goto finish;
++state->tablegen;
}
he = JS_HashTableRawAdd(table, hep, keyHash, key, NULL);
if (!he) {
JS_UNLOCK(&state->lock, cx);
JS_ReportOutOfMemory(cx);
return NULL;
}
INIT_ATOM_ENTRY(entry, key);
}
finish:
atom = (JSAtom *)he;
atom->flags |= flags & (ATOM_PINNED | ATOM_INTERNED | ATOM_HIDDEN);
cx->weakRoots.lastAtom = atom;
ADD_ATOM_ENTRY_FLAGS(entry, flags & (ATOM_PINNED | ATOM_INTERNED));
v = STRING_TO_JSVAL((JSString *)ATOM_ENTRY_KEY(entry));
cx->weakRoots.lastAtom = v;
JS_UNLOCK(&state->lock, cx);
return atom;
return (JSAtom *)v;
failed_hash_add:
JS_UNLOCK(&state->lock,cx);
JS_ReportOutOfMemory(cx);
return NULL;
}
JS_FRIEND_API(JSAtom *)
js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
{
jschar *chars;
JSString *str;
JSString str;
JSAtom *atom;
char buf[2 * ALIGNMENT(JSString)];
/*
* Avoiding the malloc in js_InflateString on shorter strings saves us
@ -666,12 +708,10 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
flags |= ATOM_NOCOPY;
}
str = ALIGN(buf, JSString);
str->chars = chars;
str->length = inflatedLength;
atom = js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
if (chars != inflated && str->chars)
str.chars = chars;
str.length = inflatedLength;
atom = js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
if (chars != inflated && str.chars)
JS_free(cx, chars);
return atom;
}
@ -679,49 +719,54 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
JS_FRIEND_API(JSAtom *)
js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
{
JSString *str;
char buf[2 * ALIGNMENT(JSString)];
JSString str;
str = ALIGN(buf, JSString);
str->chars = (jschar *)chars;
str->length = length;
return js_AtomizeString(cx, str, ATOM_TMPSTR | flags);
str.chars = (jschar *)chars;
str.length = length;
return js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
}
JSAtom *
js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
{
JSString *str;
char buf[2 * ALIGNMENT(JSString)];
JSHashNumber keyHash;
jsval key;
JSString str, *str2;
JSAtomState *state;
JSHashTable *table;
JSHashEntry **hep;
JSDHashEntryHdr *hdr;
str = ALIGN(buf, JSString);
str->chars = (jschar *)chars;
str->length = length;
keyHash = js_HashString(str);
key = STRING_TO_JSVAL(str);
str.chars = (jschar *)chars;
str.length = length;
state = &cx->runtime->atomState;
JS_LOCK(&state->lock, cx);
table = state->table;
hep = JS_HashTableRawLookup(table, keyHash, (void *)key);
hdr = JS_DHashTableOperate(&state->stringAtoms, &str, JS_DHASH_LOOKUP);
str2 = JS_DHASH_ENTRY_IS_BUSY(hdr)
? (JSString *)ATOM_ENTRY_KEY(TO_ATOM_ENTRY(hdr))
: NULL;
JS_UNLOCK(&state->lock, cx);
return (hep) ? (JSAtom *)*hep : NULL;
return str2 ? (JSAtom *)STRING_TO_JSVAL(str2) : NULL;
}
JSAtom *
js_AtomizePrimitiveValue(JSContext *cx, jsval v)
JSBool
js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp)
{
if (JSVAL_IS_STRING(v))
return js_AtomizeString(cx, JSVAL_TO_STRING(v), 0);
if (JSVAL_IS_DOUBLE(v))
return js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(v));
JS_ASSERT(JSVAL_IS_INT(v) || v == JSVAL_TRUE || v == JSVAL_FALSE ||
v == JSVAL_NULL || v == JSVAL_VOID);
return AtomizeHashedKey(cx, v, (JSHashNumber)v);
JSAtom *atom;
if (JSVAL_IS_STRING(v)) {
atom = js_AtomizeString(cx, JSVAL_TO_STRING(v), 0);
if (!atom)
return JS_FALSE;
} else if (JSVAL_IS_DOUBLE(v)) {
atom = js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(v));
if (!atom)
return JS_FALSE;
} else {
JS_ASSERT(JSVAL_IS_INT(v) || v == JSVAL_TRUE || v == JSVAL_FALSE ||
v == JSVAL_NULL || v == JSVAL_VOID);
atom = (JSAtom *)v;
}
*atomp = atom;
return JS_TRUE;
}
JSAtom *
@ -737,21 +782,36 @@ js_ValueToStringAtom(JSContext *cx, jsval v)
#ifdef DEBUG
JS_STATIC_DLL_CALLBACK(int)
atom_dumper(JSHashEntry *he, int i, void *arg)
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
atom_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr,
uint32 number, void *arg)
{
JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
FILE *fp = (FILE *)arg;
JSAtom *atom = (JSAtom *)he;
void *key;
uintN flags;
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));
fprintf(fp, "%3u %08x ", number, (uintN)entry->hdr.keyHash);
if (entry->keyAndFlags == 0) {
fputs("<uninitialized>", fp);
} else {
key = ATOM_ENTRY_KEY(entry);
if (IS_DOUBLE_TABLE(table)) {
fprintf(fp, "%.16g", *(jsdouble *)key);
} else {
JS_ASSERT(IS_STRING_TABLE(table));
js_FileEscapedString(fp, (JSString *)key, '"');
}
flags = ATOM_ENTRY_FLAGS(entry);
if (flags != 0) {
fputs((flags & (ATOM_PINNED | ATOM_INTERNED))
? " pinned | interned"
: (flags & ATOM_PINNED) ? " pinned" : " interned",
fp);
}
}
putc('\n', fp);
return HT_ENUMERATE_NEXT;
return JS_DHASH_NEXT;
}
JS_FRIEND_API(void)
@ -759,11 +819,19 @@ 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);
fprintf(fp, "stringAtoms table contents:\n");
JS_DHashTableEnumerate(&state->stringAtoms, atom_dumper, fp);
#ifdef JS_DHASHMETER
JS_DHashTableDumpMeter(&state->stringAtoms, atom_dumper, fp);
#endif
putc('\n', fp);
fprintf(fp, "doubleAtoms table contents:\n");
JS_DHashTableEnumerate(&state->doubleAtoms, atom_dumper, fp);
#ifdef JS_DHASHMETER
JS_DHashTableDumpMeter(&state->doubleAtoms, atom_dumper, fp);
#endif
putc('\n', fp);
}
#endif

Просмотреть файл

@ -46,6 +46,7 @@
#include "jsconfig.h"
#include "jstypes.h"
#include "jshash.h" /* Added by JSIFY */
#include "jsdhash.h"
#include "jsapi.h"
#include "jsprvtd.h"
#include "jspubtd.h"
@ -56,28 +57,16 @@
JS_BEGIN_EXTERN_C
#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_HIDDEN 0x08 /* atom is in special hidden subspace */
#define ATOM_NOCOPY 0x40 /* don't copy atom string bytes */
#define ATOM_TMPSTR 0x80 /* internal, to avoid extra string */
#define ATOM_PINNED 0x1 /* atom is pinned against GC */
#define ATOM_INTERNED 0x2 /* pinned variant for JS_Intern* API */
#define ATOM_NOCOPY 0x4 /* don't copy atom string bytes */
#define ATOM_TMPSTR 0x8 /* internal, to avoid extra string */
struct JSAtom {
JSHashEntry entry; /* key is jsval or unhidden atom
if ATOM_HIDDEN */
uint32 flags; /* pinned, interned, and mark flags */
};
#define ATOM_KEY(atom) ((jsval)(atom)->entry.key)
#define ATOM_IS_INT(atom) JSVAL_IS_INT(ATOM_KEY(atom))
#define ATOM_TO_INT(atom) JSVAL_TO_INT(ATOM_KEY(atom))
#define ATOM_KEY(atom) ((jsval)(atom))
#define ATOM_IS_DOUBLE(atom) JSVAL_IS_DOUBLE(ATOM_KEY(atom))
#define ATOM_TO_DOUBLE(atom) JSVAL_TO_DOUBLE(ATOM_KEY(atom))
#define ATOM_IS_STRING(atom) JSVAL_IS_STRING(ATOM_KEY(atom))
#define ATOM_TO_STRING(atom) JSVAL_TO_STRING(ATOM_KEY(atom))
#define ATOM_IS_BOOLEAN(atom) JSVAL_IS_BOOLEAN(ATOM_KEY(atom))
#define ATOM_TO_BOOLEAN(atom) JSVAL_TO_BOOLEAN(ATOM_KEY(atom))
JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4);
JS_STATIC_ASSERT(sizeof(JSAtom *) == JS_BYTES_PER_WORD);
@ -156,8 +145,8 @@ struct JSAtomMap {
};
struct JSAtomState {
JSHashTable *table; /* hash table containing all atoms */
JSDHashTable stringAtoms; /* hash table with shared strings */
JSDHashTable doubleAtoms; /* hash table with shared doubles */
uint32 tablegen; /* number of atoms mutations to
optimize hashing */
#ifdef JS_THREADSAFE
@ -274,6 +263,9 @@ struct JSAtomState {
#define LAZY_ATOM_OFFSET_START offsetof(JSAtomState, lazy)
#define ATOM_OFFSET_LIMIT (sizeof(JSAtomState))
#define COMMON_ATOMS_START(state) \
(JSAtom **)((uint8 *)(state) + ATOM_OFFSET_START)
/* 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);
@ -379,10 +371,7 @@ js_FinishAtomState(JSRuntime *rt);
*/
extern void
js_TraceAtom(JSTracer *trc, JSAtom *atom);
extern void
js_TraceLockedAtoms(JSTracer *trc, JSBool allAtoms);
js_TraceAtomState(JSTracer *trc, JSBool allAtoms);
extern void
js_SweepAtomState(JSContext *cx);
@ -423,8 +412,8 @@ js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length);
/*
* This variant handles all primitive values.
*/
extern JSAtom *
js_AtomizePrimitiveValue(JSContext *cx, jsval v);
JSBool
js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp);
/*
* Convert v to an atomized string.

Просмотреть файл

@ -1472,7 +1472,7 @@ GetAtomTotalSize(JSContext *cx, JSAtom *atom)
{
size_t nbytes;
nbytes = sizeof *atom;
nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub);
if (ATOM_IS_STRING(atom)) {
nbytes += sizeof(JSString);
nbytes += (ATOM_TO_STRING(atom)->length + 1) * sizeof(jschar);

Просмотреть файл

@ -3145,8 +3145,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
if (pn3->pn_type == TOK_DEFAULT)
continue;
atom = js_AtomizePrimitiveValue(cx, pn3->pn_val);
if (!atom)
if (!js_AtomizePrimitiveValue(cx, pn3->pn_val, &atom))
goto bad;
ale = js_IndexAtom(cx, atom, &cg->atomList);
if (!ale)

Просмотреть файл

@ -754,7 +754,7 @@ call_enumerate(JSContext *cx, JSObject *obj)
JSScopeProperty *sprop, *cprop;
JSPropertyOp getter;
jsval *vec;
JSAtom *atom;
jsid id;
JSProperty *prop;
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
@ -793,12 +793,8 @@ call_enumerate(JSContext *cx, JSObject *obj)
continue;
/* Trigger reflection by looking up the unhidden atom for sprop->id. */
JS_ASSERT(JSID_IS_ATOM(sprop->id));
atom = JSID_TO_ATOM(sprop->id);
JS_ASSERT(atom->flags & ATOM_HIDDEN);
atom = (JSAtom *) atom->entry.value;
if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop))
id = JSID_UNHIDE_NAME(sprop->id);
if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
return JS_FALSE;
/*
@ -1248,24 +1244,6 @@ fun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
}
}
static void
fun_finalize(JSContext *cx, JSObject *obj)
{
JSFunction *fun;
/* No valid function object should lack private data, but check anyway. */
fun = (JSFunction *) JS_GetPrivate(cx, obj);
if (!fun)
return;
/*
* This works because obj is finalized before JSFunction. See
* comments in js_GC before the finalization loop.
*/
if (fun->object == obj)
fun->object = NULL;
}
#if JS_HAS_XDR
#include "jsxdrapi.h"
@ -1380,7 +1358,14 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
? JSXDR_FUNCONST
: JSXDR_FUNVAR;
userid = INT_TO_JSVAL(sprop->shortid);
propAtom = JSID_TO_ATOM(sprop->id);
/*
* sprop->id here represents hidden names so we unhide it and
* encode as an atom. During decoding we read the atom and use
* js_AddHiddenProperty to reconstruct sprop with the hidden
* id.
*/
propAtom = JSID_TO_ATOM(JSID_UNHIDE_NAME(sprop->id));
if (!JS_XDRUint32(xdr, &type) ||
!JS_XDRUint32(xdr, &userid) ||
!js_XDRCStringAtom(xdr, &propAtom)) {
@ -1503,7 +1488,7 @@ fun_trace(JSTracer *trc, JSObject *obj)
if (fun->object != obj)
JS_CALL_TRACER(trc, fun->object, JSTRACE_OBJECT, "object");
if (fun->atom)
JS_CALL_TRACER(trc, fun->atom, JSTRACE_ATOM, "atom");
JS_CALL_STRING_TRACER(trc, ATOM_TO_STRING(fun->atom), "atom");
if (FUN_INTERPRETED(fun) && fun->u.i.script)
js_TraceScript(trc, fun->u.i.script);
}
@ -1533,7 +1518,7 @@ JS_FRIEND_DATA(JSClass) js_FunctionClass = {
JS_PropertyStub, JS_PropertyStub,
fun_getProperty, JS_PropertyStub,
fun_enumerate, (JSResolveOp)fun_resolve,
fun_convert, fun_finalize,
fun_convert, JS_FinalizeStub,
NULL, NULL,
NULL, NULL,
fun_xdrObject, fun_hasInstance,

Просмотреть файл

@ -263,11 +263,13 @@ static uint8 GCTypeToTraceKindMap[GCX_NTYPES] = {
};
/*
* Ensure that GC-allocated JSFunction and JSObject would go to different
* lists so we can easily finalize JSObject before JSFunction. See comments
* in js_GC.
* Ensure that JSObject is allocated from a different GC-list rather than
* jsdouble and JSString so we can easily finalize JSObject before these 2
* types of GC things. See comments in js_GC.
*/
JS_STATIC_ASSERT(GC_FREELIST_INDEX(sizeof(JSFunction)) !=
JS_STATIC_ASSERT(GC_FREELIST_INDEX(sizeof(JSString)) !=
GC_FREELIST_INDEX(sizeof(JSObject)));
JS_STATIC_ASSERT(GC_FREELIST_INDEX(sizeof(jsdouble)) !=
GC_FREELIST_INDEX(sizeof(JSObject)));
/*
@ -1460,10 +1462,6 @@ JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
*/
break;
case JSTRACE_ATOM:
js_TraceAtom(trc, (JSAtom *)thing);
break;
#if JS_HAS_XML_SUPPORT
case JSTRACE_NAMESPACE:
js_TraceXMLNamespace(trc, (JSXMLNamespace *)thing);
@ -1716,7 +1714,6 @@ JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
{
JSContext *cx;
JSRuntime *rt;
JSAtom *atom;
uint8 *flagp;
JS_ASSERT(thing);
@ -1733,36 +1730,6 @@ JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
JS_ASSERT(rt->gcMarkingTracer == trc);
JS_ASSERT(rt->gcLevel > 0);
if (kind == JSTRACE_ATOM) {
atom = (JSAtom *)thing;
/*
* Here we should workaround gcThingCallback deficiency of being able
* to handle only GC things, not atoms. Because of this we must call
* the callback on all GC things referenced by atoms. For unmarked
* atoms we call when tracing things reached directly from each such
* atom, but for already-marked atoms we have to call the callback
* explicitly.
*
* We do not do it currently for compatibility with XPCOM cycle
* collector which ignores JSString * and jsdouble * GC things that
* the atom can refer to.
*
* FIXME bug 386265 will remove the need to trace atoms and bug 379718
* may remove gcThingCallback altogether.
*/
if (!(atom->flags & ATOM_MARK)) {
atom->flags |= ATOM_MARK;
/*
* Call js_TraceAtom directly to avoid an extra dispatch in
* JS_TraceChildren.
*/
js_TraceAtom(trc, (JSAtom *)thing);
}
goto out;
}
flagp = js_GetGCThingFlags(thing);
JS_ASSERT(*flagp != GCF_FINAL);
JS_ASSERT(GCTypeToTraceKindMap[*flagp & GCF_TYPEMASK] == kind);
@ -2029,8 +1996,7 @@ TraceWeakRoots(JSTracer *trc, JSWeakRoots *wr)
gc_typenames[i]);
}
}
if (wr->lastAtom)
JS_CALL_TRACER(trc, wr->lastAtom, JSTRACE_ATOM, "lastAtom");
JS_CALL_VALUE_TRACER(trc, wr->lastAtom, "lastAtom");
JS_SET_TRACING_NAME(trc, "lastInternalResult");
js_CallValueTracerIfGCThing(trc, wr->lastInternalResult);
}
@ -2127,7 +2093,7 @@ js_TraceRuntime(JSTracer *trc, JSBool allAtoms)
JS_DHashTableEnumerate(&rt->gcRootsHash, gc_root_traversal, trc);
if (rt->gcLocksHash)
JS_DHashTableEnumerate(rt->gcLocksHash, gc_lock_traversal, trc);
js_TraceLockedAtoms(trc, allAtoms);
js_TraceAtomState(trc, allAtoms);
js_TraceWatchPoints(trc);
js_TraceNativeIteratorStates(trc);
@ -2397,12 +2363,22 @@ restart:
* so that any attempt to allocate a GC-thing from a finalizer will fail,
* rather than nest badly and leave the unmarked newborn to be swept.
*
* We first sweep atom state so we can use js_IsAboutToBeFinalized on
* JSString or jsdouble held in a hashtable to check if the hashtable
* entry can be freed. Note that even after the entry is freed, JSObject
* finalizers can continue to access the corresponding jsdouble* and
* JSString* assuming that they are unique. This works since the
* atomization API must not be called during GC.
*/
js_SweepAtomState(cx);
/*
* Here we need to ensure that JSObject instances are finalized before GC-
* allocated JSFunction instances so fun_finalize from jsfun.c can clear
* the weak pointer from the JSFunction back to the JSObject. For that we
* simply finalize the list containing JSObject first since the static
* assert at the beginning of the file guarantees that JSFunction instances
* are allocated from a different list.
* allocated JSString and jsdouble instances so object's finalizer can
* access them even if they will be freed. For that we simply finalize the
* list containing JSObject first since the static assert at the beginning
* of the file guarantees that JSString and jsdouble instances are
* allocated from a different list.
*/
for (i = 0; i < GC_NUM_FREELISTS; i++) {
arenaList = &rt->gcArenaList[i == 0
@ -2451,11 +2427,9 @@ restart:
/*
* Sweep the runtime's property tree after finalizing objects, in case any
* had watchpoints referencing tree nodes. Then sweep atoms, which may be
* referenced from dead property ids.
* had watchpoints referencing tree nodes.
*/
js_SweepScopeProperties(cx);
js_SweepAtomState(cx);
/*
* Sweep script filenames after sweeping functions in the generic loop

Просмотреть файл

@ -175,10 +175,9 @@ js_IsAboutToBeFinalized(JSContext *cx, void *thing);
JS_STATIC_ASSERT(JSTRACE_STRING == 2);
#define JSTRACE_FUNCTION 3
#define JSTRACE_ATOM 4
#define JSTRACE_NAMESPACE 5
#define JSTRACE_QNAME 6
#define JSTRACE_XML 7
#define JSTRACE_NAMESPACE 4
#define JSTRACE_QNAME 5
#define JSTRACE_XML 6
#if JS_HAS_XML_SUPPORT
# define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_XML)
@ -311,7 +310,7 @@ struct JSWeakRoots {
JSGCThing *newborn[GCX_NTYPES];
/* Atom root for the last-looked-up atom on this context. */
JSAtom *lastAtom;
jsval lastAtom;
/* Root for the result of the most recent js_InternalInvoke call. */
jsval lastInternalResult;

Просмотреть файл

@ -565,23 +565,10 @@ CallEnumeratorNext(JSContext *cx, JSObject *iterobj, uintN flags, jsval *rval)
}
} else {
/* Make rval a string for uniformity and compatibility. */
if (JSID_IS_ATOM(id)) {
*rval = ATOM_KEY(JSID_TO_ATOM(id));
}
#if JS_HAS_XML_SUPPORT
else if (JSID_IS_OBJECT(id)) {
str = js_ValueToString(cx, OBJECT_JSID_TO_JSVAL(id));
if (!str)
return JS_FALSE;
*rval = STRING_TO_JSVAL(str);
}
#endif
else {
str = js_NumberToString(cx, (jsdouble)JSID_TO_INT(id));
if (!str)
return JS_FALSE;
*rval = STRING_TO_JSVAL(str);
}
str = js_ValueToString(cx, ID_TO_VALUE(id));
if (!str)
return JS_FALSE;
*rval = STRING_TO_JSVAL(str);
}
return JS_TRUE;

Просмотреть файл

@ -724,7 +724,6 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp)
jsval *val;
JSString *gsopold[2];
JSString *gsop[2];
JSAtom *atom;
JSString *idstr, *valstr, *str;
int stackDummy;
@ -855,7 +854,6 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp)
* Convert id to a jsval and then to a string. Decide early whether we
* prefer get/set or old getter/setter syntax.
*/
atom = JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL;
idstr = js_ValueToString(cx, ID_TO_VALUE(id));
if (!idstr) {
ok = JS_FALSE;
@ -929,9 +927,9 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp)
* If id is a string that's not an identifier, then it needs to be
* quoted. Also, negative integer ids must be quoted.
*/
if (atom
if (JSID_IS_ATOM(id)
? !idIsLexicalIdentifier
: (JSID_IS_OBJECT(id) || JSID_TO_INT(id) < 0)) {
: (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) {
idstr = js_QuoteString(cx, idstr, (jschar)'\'');
if (!idstr) {
ok = JS_FALSE;
@ -2884,41 +2882,12 @@ CheckForStringIndex(jsid id, const jschar *cp, const jschar *end,
return id;
}
static JSBool
HidePropertyName(JSContext *cx, jsid *idp)
{
jsid id;
JSAtom *atom, *hidden;
id = *idp;
JS_ASSERT(JSID_IS_ATOM(id));
atom = JSID_TO_ATOM(id);
JS_ASSERT(!(atom->flags & ATOM_HIDDEN));
JS_ASSERT(ATOM_IS_STRING(atom));
hidden = js_AtomizeString(cx, ATOM_TO_STRING(atom), ATOM_HIDDEN);
if (!hidden)
return JS_FALSE;
/*
* Link hidden to unhidden atom to optimize call_enumerate -- this means
* the GC must mark a hidden atom's unhidden counterpart (see js_MarkAtom
* in jsgc.c). It uses the atom's entry.value member for this linkage.
*/
hidden->entry.value = atom;
*idp = ATOM_TO_JSID(hidden);
return JS_TRUE;
}
JSScopeProperty *
js_AddHiddenProperty(JSContext *cx, JSObject *obj, jsid id,
JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
uintN attrs, uintN flags, intN shortid)
{
if (!HidePropertyName(cx, &id))
return NULL;
id = JSID_HIDE_NAME(id);
flags |= SPROP_IS_HIDDEN;
return js_AddNativeProperty(cx, obj, id, getter, setter, slot, attrs,
flags, shortid);
@ -2928,8 +2897,8 @@ JSBool
js_LookupHiddenProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
JSProperty **propp)
{
return HidePropertyName(cx, &id) &&
js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_HIDDEN,
id = JSID_HIDE_NAME(id);
return js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_HIDDEN,
objp, propp);
}
@ -4461,7 +4430,7 @@ CheckCtorGetAccess(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
uintN attrs;
atom = cx->runtime->atomState.constructorAtom;
JS_ASSERT(id == ATOM_KEY(atom));
JS_ASSERT(id == ATOM_TO_JSID(atom));
return OBJ_CHECK_ACCESS(cx, obj, ATOM_TO_JSID(atom), JSACC_READ,
vp, &attrs);
}
@ -4473,7 +4442,7 @@ CheckCtorSetAccess(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
uintN attrs;
atom = cx->runtime->atomState.constructorAtom;
JS_ASSERT(id == ATOM_KEY(atom));
JS_ASSERT(id == ATOM_TO_JSID(atom));
return OBJ_CHECK_ACCESS(cx, obj, ATOM_TO_JSID(atom), JSACC_WRITE,
vp, &attrs);
}

Просмотреть файл

@ -1218,9 +1218,9 @@ GetSlotAtom(JSPrinter *jp, JSPropertyOp getter, uintN slot)
if (sprop->getter != getter)
continue;
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
JS_ASSERT(JSID_IS_ATOM(sprop->id));
JS_ASSERT(JSID_IS_HIDDEN(sprop->id));
if ((uintN) sprop->shortid == slot)
return JSID_TO_ATOM(sprop->id);
return JSID_TO_ATOM(JSID_UNHIDE_NAME(sprop->id));
}
obj = OBJ_GET_PROTO(jp->sprinter.context, obj);
}
@ -4776,8 +4776,9 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun)
continue;
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
JS_ASSERT((uint16) sprop->shortid < nargs);
JS_ASSERT(JSID_IS_ATOM(sprop->id));
params[(uint16) sprop->shortid] = JSID_TO_ATOM(sprop->id);
JS_ASSERT(JSID_IS_HIDDEN(sprop->id));
params[(uint16) sprop->shortid] =
JSID_TO_ATOM(JSID_UNHIDE_NAME(sprop->id));
}
pc = fun->u.i.script->main;

Просмотреть файл

@ -57,30 +57,37 @@
#include "jspubtd.h"
/* Internal identifier (jsid) macros. */
#define JSID_ATOM 0x0
#define JSID_INT 0x1
#define JSID_OBJECT 0x2
#define JSID_TAGMASK 0x3
#define JSID_TAG(id) ((id) & JSID_TAGMASK)
#define JSID_SETTAG(id,t) ((id) | (t))
#define JSID_CLRTAG(id) ((id) & ~(jsid)JSID_TAGMASK)
#define JSID_IS_ATOM(id) (JSID_TAG(id) == JSID_ATOM)
#define JSID_IS_ATOM(id) JSVAL_IS_STRING((jsval)(id))
#define JSID_TO_ATOM(id) ((JSAtom *)(id))
#define ATOM_TO_JSID(atom) ((jsid)(atom))
#define ATOM_JSID_TO_JSVAL(id) ATOM_KEY(JSID_TO_ATOM(id))
#define ATOM_TO_JSID(atom) (JS_ASSERT(ATOM_IS_STRING(atom)), \
(jsid)(atom))
#define JSID_IS_INT(id) ((id) & JSID_INT)
#define JSID_TO_INT(id) ((jsint)(id) >> 1)
#define INT_TO_JSID(i) (((jsint)(i) << 1) | JSID_INT)
#define INT_JSID_TO_JSVAL(id) (id)
#define INT_JSVAL_TO_JSID(v) (v)
#define JSID_IS_INT(id) JSVAL_IS_INT((jsval)(id))
#define JSID_TO_INT(id) JSVAL_TO_INT((jsval)(id))
#define INT_TO_JSID(i) ((jsid)INT_TO_JSVAL(i))
#define INT_JSVAL_TO_JSID(v) ((jsid)(v))
#define INT_JSID_TO_JSVAL(id) ((jsval)(id))
#define JSID_IS_OBJECT(id) (JSID_TAG(id) == JSID_OBJECT)
#define JSID_TO_OBJECT(id) ((JSObject *) JSID_CLRTAG(id))
#define OBJECT_TO_JSID(obj) ((jsid)(obj) | JSID_OBJECT)
#define OBJECT_JSID_TO_JSVAL(id) OBJECT_TO_JSVAL(JSID_CLRTAG(id))
#define OBJECT_JSVAL_TO_JSID(v) OBJECT_TO_JSID(JSVAL_TO_OBJECT(v))
#define JSID_IS_OBJECT(id) JSVAL_IS_OBJECT((jsval)(id))
#define JSID_TO_OBJECT(id) JSVAL_TO_OBJECT((jsval)(id))
#define OBJECT_TO_JSID(obj) ((jsid)OBJECT_TO_JSVAL(obj))
#define OBJECT_JSVAL_TO_JSID(v) ((jsid)v)
/*
* To put a property into the hidden subspace we re-tag JSString * behind
* property's atom as JSVAL_BOOLEAN to get a different id. js_TraceId must
* properly trace such pseudo-booleans to ensure GC safety.
*/
#define JSID_IS_HIDDEN(id) (JSVAL_TAG((jsval)(id)) == JSVAL_BOOLEAN)
#define JSID_HIDE_NAME(id) \
(JS_ASSERT(JSID_IS_ATOM(id)), \
(jsid)((jsval)(id) ^ (JSVAL_STRING ^ JSVAL_BOOLEAN)))
#define JSID_UNHIDE_NAME(id) \
(JS_ASSERT(JSID_IS_HIDDEN(id)), \
(jsid)((jsval)(id) ^ (JSVAL_BOOLEAN ^ JSVAL_STRING)))
/* Scalar typedefs. */
typedef uint8 jsbytecode;

Просмотреть файл

@ -1510,16 +1510,10 @@ js_ClearScope(JSContext *cx, JSScope *scope)
void
js_TraceId(JSTracer *trc, jsid id)
{
JSObject *obj;
jsval v;
if (JSID_IS_ATOM(id)) {
JS_CALL_TRACER(trc, JSID_TO_ATOM(id), JSTRACE_ATOM, "id");
} else if (!JSID_IS_INT(id)) {
JS_ASSERT(JSID_IS_OBJECT(id));
obj = JSID_TO_OBJECT(id);
if (obj)
JS_CALL_OBJECT_TRACER(trc, obj, "id");
}
v = ID_TO_VALUE(id);
JS_CALL_VALUE_TRACER(trc, v, "id");
}
#if defined DEBUG || defined DUMP_SCOPE_STATS
@ -1531,27 +1525,28 @@ static void
PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize)
{
JSScopeProperty *sprop;
jsid id;
size_t n;
const char *name;
const char *name, *prefix;
JS_ASSERT(trc->debugPrinter == PrintPropertyGetterOrSetter);
sprop = (JSScopeProperty *)trc->debugPrintArg;
id = sprop->id;
name = trc->debugPrintIndex ? js_setter_str : js_getter_str;
n = strlen(name);
if (JSID_IS_ATOM(sprop->id)) {
JSAtom *atom = JSID_TO_ATOM(sprop->id);
if (atom && ATOM_IS_STRING(atom)) {
n = js_PutEscapedString(buf, bufsize - 1,
ATOM_TO_STRING(atom), 0);
buf[n++] = ' ';
strncpy(buf + n, name, bufsize - n);
buf[bufsize - 1] = '\0';
if (JSID_IS_ATOM(id) || JSID_IS_HIDDEN(id)) {
if (JSID_IS_HIDDEN(id)) {
id = JSID_UNHIDE_NAME(id);
prefix = "hidden ";
} else {
JS_snprintf(buf, bufsize, "uknown %s", name);
prefix = "";
}
n = js_PutEscapedString(buf, bufsize - 1,
ATOM_TO_STRING(JSID_TO_ATOM(id)), 0);
if (n < bufsize - 1)
JS_snprintf(buf + n, bufsize - n, " %s%s", prefix, name);
} else if (JSID_IS_INT(sprop->id)) {
JS_snprintf(buf, bufsize, "%d %s", JSID_TO_INT(sprop->id), name);
JS_snprintf(buf, bufsize, "%d %s", JSID_TO_INT(id), name);
} else {
JS_snprintf(buf, bufsize, "<object> %s", name);
}
@ -1647,22 +1642,32 @@ js_MeterPropertyTree(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
static void
DumpSubtree(JSContext *cx, JSScopeProperty *sprop, int level, FILE *fp)
{
jsval v;
JSString *str;
JSScopeProperty *kids, *kid;
PropTreeKidsChunk *chunk;
uintN i;
fprintf(fp, "%*sid ", level, "");
if (JSID_IS_ATOM(sprop->id)) {
str = ATOM_TO_STRING(JSID_TO_ATOM(sprop->id));
} else if (JSID_IS_OBJECT(sprop->id)) {
str = js_ValueToString(cx, OBJECT_JSID_TO_JSVAL(sprop->id));
v = ID_TO_VALUE(sprop->id);
if (JSID_IS_INT(sprop->id)) {
fprintf(fp, "%d", JSVAL_TO_INT(v));
} else {
fprintf(fp, "%d", JSVAL_TO_INT(sprop->id));
str = NULL;
if (JSID_IS_ATOM(sprop->id)) {
str = JSVAL_TO_STRING(v);
} else if (JSID_IS_HIDDEN(sprop->id)) {
str = JSVAL_TO_STRING(v);
fputs("hidden ", fp);
} else {
JSASSERT(JSID_IS_OBJECT(sprop->id));
str = js_ValueToString(cx, v);
fputs("object ", fp);
}
if (!str)
fputs("<error>", fp);
else
js_FileEscapedString(fp, str, '"');
}
if (str)
js_FileEscapedString(fp, str, 0);
fprintf(fp, " g/s %p/%p slot %lu attrs %x flags %x shortid %d\n",
(void *) sprop->getter, (void *) sprop->setter,

Просмотреть файл

@ -348,9 +348,8 @@ js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
extern void
js_DestroyScope(JSContext *cx, JSScope *scope);
#define ID_TO_VALUE(id) (JSID_IS_ATOM(id) ? ATOM_JSID_TO_JSVAL(id) : \
JSID_IS_OBJECT(id) ? OBJECT_JSID_TO_JSVAL(id) : \
(jsval)(id))
#define ID_TO_VALUE(id) \
(JSID_IS_HIDDEN(id) ? (jsval)JSID_UNHIDE_NAME(id) : (jsval)(id))
extern JS_FRIEND_API(JSScopeProperty **)
js_SearchScope(JSScope *scope, jsid id, JSBool adding);

Просмотреть файл

@ -933,13 +933,6 @@ js_compare_strings(const void *k1, const void *k2)
return strcmp((const char *) k1, (const char *) k2) == 0;
}
/* Shared with jsatom.c to save code space. */
extern void * JS_DLL_CALLBACK
js_alloc_table_space(void *priv, size_t size);
extern void JS_DLL_CALLBACK
js_free_table_space(void *priv, void *item);
/* NB: This struct overlays JSHashEntry -- see jshash.h, do not reorganize. */
typedef struct ScriptFilenameEntry {
JSHashEntry *next; /* hash chain linkage */
@ -950,6 +943,18 @@ typedef struct ScriptFilenameEntry {
char filename[3]; /* two or more bytes, NUL-terminated */
} ScriptFilenameEntry;
JS_STATIC_DLL_CALLBACK(void *)
js_alloc_table_space(void *priv, size_t size)
{
return malloc(size);
}
JS_STATIC_DLL_CALLBACK(void)
js_free_table_space(void *priv, void *item)
{
free(item);
}
JS_STATIC_DLL_CALLBACK(JSHashEntry *)
js_alloc_sftbl_entry(void *priv, const void *key)
{
@ -1497,14 +1502,18 @@ js_TraceScript(JSTracer *trc, JSScript *script)
JSAtomMap *map;
uintN i, length;
JSAtom **vector;
jsval v;
JSObjectArray *objarray;
map = &script->atomMap;
length = map->length;
vector = map->vector;
for (i = 0; i < length; i++) {
JS_SET_TRACING_INDEX(trc, "atomMap", i);
JS_CallTracer(trc, vector[i], JSTRACE_ATOM);
v = ATOM_KEY(vector[i]);
if (JSVAL_IS_TRACEABLE(v)) {
JS_SET_TRACING_INDEX(trc, "atomMap", i);
JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
}
}
if (script->objectsOffset != 0) {

Просмотреть файл

@ -2760,10 +2760,13 @@ js_ValueToSource(JSContext *cx, jsval v)
return str;
}
JSHashNumber
/*
* str is not necessarily a GC thing here.
*/
uint32
js_HashString(JSString *str)
{
JSHashNumber h;
uint32 h;
const jschar *s;
size_t n;
@ -2773,31 +2776,9 @@ js_HashString(JSString *str)
return h;
}
intN
js_CompareStrings(JSString *str1, JSString *str2)
{
size_t l1, l2, n, i;
const jschar *s1, *s2;
intN cmp;
JS_ASSERT(str1);
JS_ASSERT(str2);
/* Fast case: pointer equality could be a quick win. */
if (str1 == str2)
return 0;
l1 = JSSTRING_LENGTH(str1), l2 = JSSTRING_LENGTH(str2);
s1 = JSSTRING_CHARS(str1), s2 = JSSTRING_CHARS(str2);
n = JS_MIN(l1, l2);
for (i = 0; i < n; i++) {
cmp = s1[i] - s2[i];
if (cmp != 0)
return cmp;
}
return (intN)(l1 - l2);
}
/*
* str is not necessarily a GC thing here.
*/
JSBool
js_EqualStrings(JSString *str1, JSString *str2)
{
@ -2828,6 +2809,31 @@ js_EqualStrings(JSString *str1, JSString *str2)
return JS_TRUE;
}
intN
js_CompareStrings(JSString *str1, JSString *str2)
{
size_t l1, l2, n, i;
const jschar *s1, *s2;
intN cmp;
JS_ASSERT(str1);
JS_ASSERT(str2);
/* Fast case: pointer equality could be a quick win. */
if (str1 == str2)
return 0;
l1 = JSSTRING_LENGTH(str1), l2 = JSSTRING_LENGTH(str2);
s1 = JSSTRING_CHARS(str1), s2 = JSSTRING_CHARS(str2);
n = JS_MIN(l1, l2);
for (i = 0; i < n; i++) {
cmp = s1[i] - s2[i];
if (cmp != 0)
return cmp;
}
return (intN)(l1 - l2);
}
size_t
js_strlen(const jschar *s)
{

Просмотреть файл

@ -51,7 +51,6 @@
#include <ctype.h>
#include "jspubtd.h"
#include "jsprvtd.h"
#include "jshash.h"
JS_BEGIN_EXTERN_C
@ -384,13 +383,19 @@ js_ValueToString(JSContext *cx, jsval v);
extern JS_FRIEND_API(JSString *)
js_ValueToSource(JSContext *cx, jsval v);
#ifdef HT_ENUMERATE_NEXT /* XXX don't require jshash.h */
/*
* Compute a hash function from str.
* Compute a hash function from str. The caller can call this function even if
* str is not a GC-allocated thing.
*/
extern JSHashNumber
extern uint32
js_HashString(JSString *str);
#endif
/*
* Test if strings are equal. The caller can call the function even if str1
* or str2 are not GC-allocated things.
*/
extern JSBool
js_EqualStrings(JSString *str1, JSString *str2);
/*
* Return less than, equal to, or greater than zero depending on whether
@ -399,12 +404,6 @@ js_HashString(JSString *str);
extern intN
js_CompareStrings(JSString *str1, JSString *str2);
/*
* Test if strings are equal.
*/
extern JSBool
js_EqualStrings(JSString *str1, JSString *str2);
/*
* Boyer-Moore-Horspool superlinear search for pat:patlen in text:textlen.
* The patlen argument must be positive and no greater than BMH_PATLEN_MAX.

Просмотреть файл

@ -611,7 +611,6 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **atomp)
jsval v;
uint32 type;
jsdouble d;
JSAtom *atom;
if (xdr->mode == JSXDR_ENCODE) {
v = ATOM_KEY(*atomp);
@ -630,17 +629,12 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **atomp)
if (type == JSVAL_DOUBLE) {
if (!XDRDoubleValue(xdr, &d))
return JS_FALSE;
atom = js_AtomizeDouble(xdr->cx, d);
} else {
if (!XDRValueBody(xdr, type, &v))
return JS_FALSE;
atom = js_AtomizePrimitiveValue(xdr->cx, v);
*atomp = js_AtomizeDouble(xdr->cx, d);
return *atomp != NULL;
}
if (!atom)
return JS_FALSE;
*atomp = atom;
return JS_TRUE;
return XDRValueBody(xdr, type, &v) &&
js_AtomizePrimitiveValue(xdr->cx, v, atomp);
}
extern JSBool

Просмотреть файл

@ -649,17 +649,6 @@ struct ContextCallbackItem : public JSTracer
void
NoteJSChild(JSTracer *trc, void *thing, uint32 kind)
{
if(kind == JSTRACE_ATOM)
{
JSAtom *atom = (JSAtom *)thing;
jsval v = ATOM_KEY(atom);
if(!JSVAL_IS_PRIMITIVE(v))
{
thing = JSVAL_TO_GCTHING(v);
kind = JSTRACE_OBJECT;
}
}
if(kind == JSTRACE_OBJECT || kind == JSTRACE_NAMESPACE ||
kind == JSTRACE_QNAME || kind == JSTRACE_XML)
{