mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Bug 386265: using double kashing for atoms. r=brendan
This commit is contained in:
parent
0e2dd9e951
commit
db0f3d53a2
51
js/src/js.c
51
js/src/js.c
@ -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;
|
||||
}
|
||||
|
680
js/src/jsatom.c
680
js/src/jsatom.c
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user