--- a/js/src/js.c
+++ b/js/src/js.c
@@ -1689,41 +1689,42 @@ DumpHeap(JSContext *cx, uintN argc, jsva
}
#endif /* DEBUG */
#ifdef TEST_EXPORT
static JSBool
DoExport(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
- jsid id;
+ JSAtom *atom;
JSObject *obj2;
JSProperty *prop;
JSBool ok;
uintN attrs;
if (argc != 2) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_DOEXP_USAGE);
return JS_FALSE;
}
if (!JS_ValueToObject(cx, argv[0], &obj))
return JS_FALSE;
argv[0] = OBJECT_TO_JSVAL(obj);
- if (!js_ValueToStringId(cx, argv[1], &id))
+ atom = js_ValueToStringAtom(cx, argv[1]);
+ if (!atom)
return JS_FALSE;
- if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
return JS_FALSE;
if (!prop) {
ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL,
JSPROP_EXPORTED, NULL);
} else {
- ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
+ ok = OBJ_GET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
if (ok) {
attrs |= JSPROP_EXPORTED;
- ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, &attrs);
+ ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
}
OBJ_DROP_PROPERTY(cx, obj2, prop);
}
return ok;
}
#endif
#ifdef TEST_CVTARGS
--- a/js/src/jsapi.c
+++ b/js/src/jsapi.c
@@ -2560,25 +2560,33 @@ JS_PUBLIC_API(void)
JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
{
JS_free(cx, ida);
}
JS_PUBLIC_API(JSBool)
JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
{
+ JSAtom *atom;
+
CHECK_REQUEST(cx);
- if (JSVAL_IS_INT(v))
+ if (JSVAL_IS_INT(v)) {
*idp = INT_JSVAL_TO_JSID(v);
+ } else {
#if JS_HAS_XML_SUPPORT
- else if (!JSVAL_IS_PRIMITIVE(v))
- *idp = OBJECT_JSVAL_TO_JSID(v);
+ if (JSVAL_IS_OBJECT(v)) {
+ *idp = OBJECT_JSVAL_TO_JSID(v);
+ return JS_TRUE;
+ }
#endif
- else
- return js_ValueToStringId(cx, v, idp);
+ atom = js_ValueToStringAtom(cx, v);
+ if (!atom)
+ return JS_FALSE;
+ *idp = ATOM_TO_JSID(atom);
+ }
return JS_TRUE;
}
JS_PUBLIC_API(JSBool)
JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
{
CHECK_REQUEST(cx);
*vp = ID_TO_VALUE(id);
@@ -5227,17 +5235,17 @@ JS_GetStringChars(JSString *str)
memcpy(s, JSSTRDEP_CHARS(str), n * sizeof *s);
s[n] = 0;
JSSTRING_INIT(str, s, n);
} else {
s = JSSTRDEP_CHARS(str);
}
} else {
JSSTRING_CLEAR_MUTABLE(str);
- s = JSFLATSTR_CHARS(str);
+ s = str->u.chars;
}
return s;
}
JS_PUBLIC_API(size_t)
JS_GetStringLength(JSString *str)
{
return JSSTRING_LENGTH(str);
--- a/js/src/jsatom.c
+++ b/js/src/jsatom.c
@@ -616,94 +616,76 @@ js_AtomizeDouble(JSContext *cx, jsdouble
JS_UNLOCK(&state->lock,cx);
JS_ReportOutOfMemory(cx);
return NULL;
}
JSAtom *
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
{
- jsval v;
JSAtomState *state;
JSDHashTable *table;
JSAtomHashEntry *entry;
JSString *key;
uint32 gen;
+ jsval v;
- JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY)));
- JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR);
-
+ JS_ASSERT((flags &
+ ~(ATOM_PINNED | ATOM_INTERNED | ATOM_TMPSTR | ATOM_NOCOPY))
+ == 0);
state = &cx->runtime->atomState;
table = &state->stringAtoms;
JS_LOCK(&state->lock, cx);
entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, str, JS_DHASH_ADD));
if (!entry)
goto failed_hash_add;
- if (entry->keyAndFlags != 0) {
- key = (JSString *)ATOM_ENTRY_KEY(entry);
- } else {
- /*
- * We created a new hashtable entry. Unless str is already allocated
- * from the GC heap and flat, we have to release state->lock as
- * string construction is a complex operation. For example, it can
- * trigger GC which may rehash the table and make the entry invalid.
- */
+ if (entry->keyAndFlags == 0) {
++state->tablegen;
+ gen = state->tablegen;
+ JS_UNLOCK(&state->lock, cx);
- if (!(flags & ATOM_TMPSTR) && !JSSTRING_IS_DEPENDENT(str)) {
- JSSTRING_CLEAR_MUTABLE(str);
- key = str;
- } else {
- gen = state->tablegen;
- JS_UNLOCK(&state->lock, cx);
-
- if (flags & ATOM_TMPSTR) {
- if (flags & ATOM_NOCOPY) {
- key = js_NewString(cx, JSFLATSTR_CHARS(str),
- JSFLATSTR_LENGTH(str));
- if (!key)
- return NULL;
+ if (flags & ATOM_TMPSTR) {
+ if (flags & ATOM_NOCOPY) {
+ key = js_NewString(cx, str->u.chars, str->length);
+ if (!key)
+ return NULL;
- /* Finish handing off chars to the GC'ed key string. */
- str->u.chars = NULL;
- } else {
- key = js_NewStringCopyN(cx, JSFLATSTR_CHARS(str),
- JSFLATSTR_LENGTH(str));
- if (!key)
- return NULL;
- }
+ /* Transfer ownership of str->chars to GC-controlled string. */
+ str->u.chars = NULL;
} else {
- JS_ASSERT(JSSTRING_IS_DEPENDENT(str));
- if (!js_UndependString(cx, str))
+ key = js_NewStringCopyN(cx, str->u.chars, str->length);
+ if (!key)
return NULL;
- key = str;
}
+ } 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) {
- 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;
- }
+ JS_LOCK(&state->lock, cx);
+ 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;
}
INIT_ATOM_ENTRY(entry, key);
- JSSTRING_SET_ATOMIZED(key);
}
finish:
ADD_ATOM_ENTRY_FLAGS(entry, flags & (ATOM_PINNED | ATOM_INTERNED));
- JS_ASSERT(JSSTRING_IS_ATOMIZED(key));
- v = STRING_TO_JSVAL(key);
+ v = STRING_TO_JSVAL((JSString *)ATOM_ENTRY_KEY(entry));
cx->weakRoots.lastAtom = v;
JS_UNLOCK(&state->lock, cx);
return (JSAtom *)v;
failed_hash_add:
JS_UNLOCK(&state->lock,cx);
JS_ReportOutOfMemory(cx);
return NULL;
@@ -792,46 +774,25 @@ js_AtomizePrimitiveValue(JSContext *cx,
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;
}
-JSBool
-js_ValueToStringId(JSContext *cx, jsval v, jsid *idp)
+JSAtom *
+js_ValueToStringAtom(JSContext *cx, jsval v)
{
JSString *str;
- JSAtom *atom;
- /*
- * Optimize for the common case where v is an already-atomized string. The
- * comment in jsstr.h before the JSSTRING_SET_ATOMIZED macro's definition
- * explains why this is thread-safe. The extra rooting via lastAtom (which
- * would otherwise be done in js_js_AtomizeString) ensures the caller that
- * the resulting id at least weakly rooted.
- */
- if (JSVAL_IS_STRING(v)) {
- str = JSVAL_TO_STRING(v);
- if (JSSTRING_IS_ATOMIZED(str)) {
- cx->weakRoots.lastAtom = v;
- *idp = ATOM_TO_JSID((JSAtom *) v);
- return JS_TRUE;
- }
- } else {
- str = js_ValueToString(cx, v);
- if (!str)
- return JS_FALSE;
- }
- atom = js_AtomizeString(cx, str, 0);
- if (!atom)
- return JS_FALSE;
- *idp = ATOM_TO_JSID(atom);
- return JS_TRUE;
+ str = js_ValueToString(cx, v);
+ if (!str)
+ return NULL;
+ return js_AtomizeString(cx, str, 0);
}
#ifdef DEBUG
JS_STATIC_DLL_CALLBACK(JSDHashOperator)
atom_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr,
uint32 number, void *arg)
{
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -411,20 +411,20 @@ js_GetExistingStringAtom(JSContext *cx,
/*
* This variant handles all primitive values.
*/
JSBool
js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp);
/*
- * Convert v to an atomized string and wrap it as an id.
+ * Convert v to an atomized string.
*/
-extern JSBool
-js_ValueToStringId(JSContext *cx, jsval v, jsid *idp);
+extern JSAtom *
+js_ValueToStringAtom(JSContext *cx, jsval v);
#ifdef DEBUG
extern JS_FRIEND_API(void)
js_DumpAtoms(JSContext *cx, FILE *fp);
#endif
--- a/js/src/jsdbgapi.c
+++ b/js/src/jsdbgapi.c
@@ -670,53 +670,59 @@ js_WrapWatchedSetter(JSContext *cx, jsid
JSFunction *wrapper;
if (!(attrs & JSPROP_SETTER))
return &js_watch_set; /* & to silence schoolmarmish MSVC */
if (JSID_IS_ATOM(id)) {
atom = JSID_TO_ATOM(id);
} else if (JSID_IS_INT(id)) {
- if (!js_ValueToStringId(cx, INT_JSID_TO_JSVAL(id), &id))
+ atom = js_ValueToStringAtom(cx, INT_JSID_TO_JSVAL(id));
+ if (!atom)
return NULL;
- atom = JSID_TO_ATOM(id);
} else {
atom = NULL;
}
wrapper = js_NewFunction(cx, NULL, js_watch_set_wrapper, 1, 0,
OBJ_GET_PARENT(cx, (JSObject *)setter),
atom);
if (!wrapper)
return NULL;
return (JSPropertyOp) wrapper->object;
}
JS_PUBLIC_API(JSBool)
-JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval,
+JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
JSWatchPointHandler handler, void *closure)
{
+ JSAtom *atom;
jsid propid;
JSObject *pobj;
JSProperty *prop;
JSScopeProperty *sprop;
JSRuntime *rt;
JSBool ok;
JSWatchPoint *wp;
JSPropertyOp watcher;
if (!OBJ_IS_NATIVE(obj)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
OBJ_GET_CLASS(cx, obj)->name);
return JS_FALSE;
}
- if (JSVAL_IS_INT(idval))
- propid = INT_JSVAL_TO_JSID(idval);
- else if (!js_ValueToStringId(cx, idval, &propid))
- return JS_FALSE;
+ if (JSVAL_IS_INT(id)) {
+ propid = INT_JSVAL_TO_JSID(id);
+ atom = NULL;
+ } else {
+ atom = js_ValueToStringAtom(cx, id);
+ if (!atom)
+ return JS_FALSE;
+ propid = ATOM_TO_JSID(atom);
+ }
if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
return JS_FALSE;
sprop = (JSScopeProperty *) prop;
rt = cx->runtime;
if (!sprop) {
/* Check for a deleted symbol watchpoint, which holds its property. */
sprop = js_FindWatchPoint(rt, OBJ_SCOPE(obj), propid);
@@ -741,18 +747,18 @@ JS_SetWatchPoint(JSContext *cx, JSObject
? LOCKED_OBJ_GET_SLOT(pobj, sprop->slot)
: JSVAL_VOID;
getter = sprop->getter;
setter = sprop->setter;
attrs = sprop->attrs;
flags = sprop->flags;
shortid = sprop->shortid;
} else {
- if (!OBJ_GET_PROPERTY(cx, pobj, propid, &value) ||
- !OBJ_GET_ATTRIBUTES(cx, pobj, propid, prop, &attrs)) {
+ if (!OBJ_GET_PROPERTY(cx, pobj, id, &value) ||
+ !OBJ_GET_ATTRIBUTES(cx, pobj, id, prop, &attrs)) {
OBJ_DROP_PROPERTY(cx, pobj, prop);
return JS_FALSE;
}
getter = setter = NULL;
flags = 0;
shortid = 0;
}
OBJ_DROP_PROPERTY(cx, pobj, prop);
@@ -1511,18 +1517,17 @@ JS_GetObjectTotalSize(JSContext *cx, JSO
static size_t
GetAtomTotalSize(JSContext *cx, JSAtom *atom)
{
size_t nbytes;
nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub);
if (ATOM_IS_STRING(atom)) {
nbytes += sizeof(JSString);
- nbytes += (JSFLATSTR_LENGTH(ATOM_TO_STRING(atom)) + 1)
- * sizeof(jschar);
+ nbytes += (ATOM_TO_STRING(atom)->length + 1) * sizeof(jschar);
} else if (ATOM_IS_DOUBLE(atom)) {
nbytes += sizeof(jsdouble);
}
return nbytes;
}
JS_PUBLIC_API(size_t)
JS_GetFunctionTotalSize(JSContext *cx, JSFunction *fun)
--- a/js/src/jsfun.c
+++ b/js/src/jsfun.c
@@ -802,39 +802,42 @@ call_enumerate(JSContext *cx, JSObject *
}
out:
JS_ARENA_RELEASE(&cx->tempPool, mark);
return names != NULL;
}
static JSBool
-call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
+call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSObject **objp)
{
JSStackFrame *fp;
- jsid id;
+ JSString *str;
+ JSAtom *atom;
JSLocalKind localKind;
JSPropertyOp getter, setter;
uintN slot, attrs;
jsval *vp;
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (!fp)
return JS_TRUE;
JS_ASSERT(fp->fun);
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee) == fp->fun);
- if (!JSVAL_IS_STRING(idval))
+ if (!JSVAL_IS_STRING(id))
return JS_TRUE;
- if (!js_ValueToStringId(cx, idval, &id))
+ str = JSVAL_TO_STRING(id);
+ atom = js_AtomizeString(cx, str, 0);
+ if (!atom)
return JS_FALSE;
- localKind = js_LookupLocal(cx, fp->fun, JSID_TO_ATOM(id), &slot);
+ localKind = js_LookupLocal(cx, fp->fun, atom, &slot);
if (localKind != JSLOCAL_NONE) {
if (localKind == JSLOCAL_ARG) {
JS_ASSERT(slot < fp->fun->nargs);
vp = fp->argv;
getter = setter = NULL;
attrs = JSPROP_PERMANENT;
} else {
JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
@@ -842,31 +845,33 @@ call_resolve(JSContext *cx, JSObject *ob
JS_ASSERT(slot < fp->nvars);
vp = fp->vars;
getter = js_GetCallVariable;
setter = js_SetCallVariable;
attrs = (localKind == JSLOCAL_CONST)
? JSPROP_PERMANENT | JSPROP_READONLY
: JSPROP_PERMANENT;
}
- if (!js_DefineNativeProperty(cx, obj, id, vp[slot], getter, setter,
- attrs, SPROP_HAS_SHORTID, (int) slot,
- NULL)) {
+ if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), vp[slot],
+ getter, setter, attrs,
+ SPROP_HAS_SHORTID, (int) slot, NULL)) {
return JS_FALSE;
}
*objp = obj;
return JS_TRUE;
}
/*
* Resolve arguments so that we never store a particular Call object's
* arguments object reference in a Call prototype's |arguments| slot.
*/
- if (id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
- if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID,
+ atom = cx->runtime->atomState.argumentsAtom;
+ if (id == ATOM_KEY(atom)) {
+ if (!js_DefineNativeProperty(cx, obj,
+ ATOM_TO_JSID(atom), JSVAL_VOID,
NULL, NULL, JSPROP_PERMANENT,
SPROP_HAS_SHORTID, CALL_ARGUMENTS,
NULL)) {
return JS_FALSE;
}
*objp = obj;
return JS_TRUE;
}
--- a/js/src/jsinterp.c
+++ b/js/src/jsinterp.c
@@ -1627,32 +1627,38 @@ js_InvokeConstructor(JSContext *cx, jsva
JS_RUNTIME_METER(cx->runtime, constructs);
return JS_TRUE;
}
static JSBool
InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp)
{
+ JSAtom *atom;
+
JS_ASSERT(!JSVAL_IS_INT(idval));
#if JS_HAS_XML_SUPPORT
if (!JSVAL_IS_PRIMITIVE(idval)) {
if (OBJECT_IS_XML(cx, obj)) {
*idp = OBJECT_JSVAL_TO_JSID(idval);
return JS_TRUE;
}
if (!js_IsFunctionQName(cx, JSVAL_TO_OBJECT(idval), idp))
return JS_FALSE;
if (*idp != 0)
return JS_TRUE;
}
#endif
- return js_ValueToStringId(cx, idval, idp);
+ atom = js_ValueToStringAtom(cx, idval);
+ if (!atom)
+ return JS_FALSE;
+ *idp = ATOM_TO_JSID(atom);
+ return JS_TRUE;
}
/*
* Threaded interpretation via computed goto appears to be well-supported by
* GCC 3 and higher. IBM's C compiler when run with the right options (e.g.,
* -qlanglvl=extended) also supports threading. Ditto the SunPro C compiler.
* Currently it's broken for JS_VERSION < 160, though this isn't worth fixing.
* Add your compiler support macros here.
--- a/js/src/jsobj.c
+++ b/js/src/jsobj.c
@@ -2932,21 +2932,21 @@ js_FreeSlot(JSContext *cx, JSObject *obj
/* JSVAL_INT_MAX as a string */
#define JSVAL_INT_MAX_STRING "1073741823"
#define CHECK_FOR_STRING_INDEX(id) \
JS_BEGIN_MACRO \
if (JSID_IS_ATOM(id)) { \
JSAtom *atom_ = JSID_TO_ATOM(id); \
JSString *str_ = ATOM_TO_STRING(atom_); \
- const jschar *cp_ = JSFLATSTR_CHARS(str_); \
+ const jschar *cp_ = str_->u.chars; \
JSBool negative_ = (*cp_ == '-'); \
if (negative_) cp_++; \
if (JS7_ISDEC(*cp_)) { \
- size_t n_ = JSFLATSTR_LENGTH(str_) - negative_; \
+ size_t n_ = str_->length - negative_; \
if (n_ <= sizeof(JSVAL_INT_MAX_STRING) - 1) \
id = CheckForStringIndex(id, cp_, cp_ + n_, negative_); \
} \
} \
JS_END_MACRO
static jsid
CheckForStringIndex(jsid id, const jschar *cp, const jschar *end,
--- a/js/src/jsparse.c
+++ b/js/src/jsparse.c
@@ -6401,34 +6401,34 @@ js_FoldConstants(JSContext *cx, JSParseN
/* Ok, we're concatenating: convert non-string constant operands. */
length = 0;
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
if (!FoldType(cx, pn2, TOK_STRING))
return JS_FALSE;
/* XXX fold only if all operands convert to string */
if (pn2->pn_type != TOK_STRING)
return JS_TRUE;
- length += JSFLATSTR_LENGTH(ATOM_TO_STRING(pn2->pn_atom));
+ length += ATOM_TO_STRING(pn2->pn_atom)->length;
}
/* Allocate a new buffer and string descriptor for the result. */
chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
if (!chars)
return JS_FALSE;
str = js_NewString(cx, chars, length);
if (!str) {
JS_free(cx, chars);
return JS_FALSE;
}
/* Fill the buffer, advancing chars and recycling kids as we go. */
for (pn2 = pn1; pn2; pn2 = RecycleTree(pn2, tc)) {
str2 = ATOM_TO_STRING(pn2->pn_atom);
- length2 = JSFLATSTR_LENGTH(str2);
- js_strncpy(chars, JSFLATSTR_CHARS(str2), length2);
+ length2 = str2->length;
+ js_strncpy(chars, str2->u.chars, length2);
chars += length2;
}
*chars = 0;
/* Atomize the result string and mutate pn to refer to it. */
pn->pn_atom = js_AtomizeString(cx, str, 0);
if (!pn->pn_atom)
return JS_FALSE;
--- a/js/src/jsstr.c
+++ b/js/src/jsstr.c
@@ -105,27 +105,27 @@ js_MinimizeDependentStrings(JSString *st
jschar *
js_GetDependentStringChars(JSString *str)
{
size_t start;
JSString *base;
start = js_MinimizeDependentStrings(str, 0, &base);
JS_ASSERT(!JSSTRING_IS_DEPENDENT(base));
- JS_ASSERT(start < JSFLATSTR_LENGTH(base));
- return JSFLATSTR_CHARS(base) + start;
+ JS_ASSERT(start < (base->length & ~JSSTRFLAG_MUTABLE));
+ return base->u.chars + start;
}
const jschar *
js_GetStringChars(JSContext *cx, JSString *str)
{
if (!js_MakeStringImmutable(cx, str))
return NULL;
JS_ASSERT(!JSSTRING_IS_DEPENDENT(str));
- return JSFLATSTR_CHARS(str);
+ return str->u.chars;
}
JSString *
js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
{
size_t rn, ln, lrdist, n;
jschar *rs, *ls, *s;
JSString *ldep; /* non-null if left should become dependent */
@@ -220,17 +220,17 @@ js_UndependString(JSContext *cx, JSStrin
JS_RUNTIME_UNMETER(rt, totalDependentStrings);
JS_LOCK_RUNTIME_VOID(rt,
(rt->strdepLengthSum -= (double)n,
rt->strdepLengthSquaredSum -= (double)n * (double)n));
}
#endif
}
- return JSFLATSTR_CHARS(str);
+ return str->u.chars;
}
JSBool
js_MakeStringImmutable(JSContext *cx, JSString *str)
{
if (JSSTRING_IS_DEPENDENT(str) && !js_UndependString(cx, str)) {
JS_RUNTIME_METER(cx->runtime, badUndependStrings);
return JS_FALSE;
@@ -2640,38 +2640,36 @@ js_ChangeExternalStringFinalizer(JSStrin
/*
* cx is NULL when we are called from js_FinishAtomState to force the
* finalization of the permanently interned strings.
*/
void
js_FinalizeStringRT(JSRuntime *rt, JSString *str, intN type, JSContext *cx)
{
- jschar *chars;
JSBool valid;
JSStringFinalizeOp finalizer;
JS_RUNTIME_UNMETER(rt, liveStrings);
if (JSSTRING_IS_DEPENDENT(str)) {
/* A dependent string can not be external and must be valid. */
JS_ASSERT(type < 0);
JS_ASSERT(JSSTRDEP_BASE(str));
JS_RUNTIME_UNMETER(rt, liveDependentStrings);
valid = JS_TRUE;
} else {
/* A stillborn string has null chars, so is not valid. */
- chars = JSFLATSTR_CHARS(str);
- valid = (chars != NULL);
+ valid = (str->u.chars != NULL);
if (valid) {
- if (IN_UNIT_STRING_SPACE_RT(rt, chars)) {
- JS_ASSERT(rt->unitStrings[*chars] == str);
+ if (IN_UNIT_STRING_SPACE_RT(rt, str->u.chars)) {
+ JS_ASSERT(rt->unitStrings[*str->u.chars] == str);
JS_ASSERT(type < 0);
- rt->unitStrings[*chars] = NULL;
+ rt->unitStrings[*str->u.chars] = NULL;
} else if (type < 0) {
- free(chars);
+ free(str->u.chars);
} else {
JS_ASSERT((uintN) type < JS_ARRAY_LENGTH(str_finalizers));
finalizer = str_finalizers[type];
if (finalizer) {
/*
* Assume that the finalizer for the permanently interned
* string knows how to deal with null context.
*/
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -65,20 +65,16 @@ JS_BEGIN_EXTERN_C
* requires \u0000 termination.
*
* A flat string with JSSTRFLAG_MUTABLE set means the string is accessible
* only from one thread and it is possible to turn it into a dependent string
* of the same length to optimize js_ConcatStrings. It also possible to grow
* such string but extreme care must be taken to ensure that no other code
* relies on the original length of the string.
*
- * A flat string with JSSTRFLAG_ATOMIZED set means that the string is hashed
- * as an atom. This flag is used to avoid re-hashing of the already-atomized
- * string.
- *
* When JSSTRFLAG_DEPENDENT is set, the string depends on characters of
* another string strongly referenced by the u.base field. The base member may
* point to another dependent string if JSSTRING_CHARS has not been called
* yet.
*
* JSSTRFLAG_PREFIX determines the kind of the dependent string. When the flag
* is unset, the length field encodes both starting position relative to the
* base string and the number of characters in the dependent string, see
@@ -98,112 +94,69 @@ struct JSString {
JSString *base;
} u;
};
/*
* Definitions for flags stored in the high order bits of JSString.length.
* JSSTRFLAG_PREFIX and JSSTRFLAG_MUTABLE are two aliases for the same value.
* JSSTRFLAG_PREFIX should be used only if JSSTRFLAG_DEPENDENT is set and
- * JSSTRFLAG_MUTABLE should be used only if the string is flat and
- * JSSTRFLAG_DEPENDENT is unset. JSSTRFLAG_ATOMIZED is used only with the
- * flat immutable strings.
+ * JSSTRFLAG_MUTABLE should be used only if JSSTRFLAG_DEPENDENT is unset.
*/
-#define JSSTRFLAG_DEPENDENT JSSTRING_BIT(JS_BITS_PER_WORD - 1)
-#define JSSTRFLAG_PREFIX JSSTRING_BIT(JS_BITS_PER_WORD - 2)
-#define JSSTRFLAG_MUTABLE JSSTRFLAG_PREFIX
-#define JSSTRFLAG_ATOMIZED JSSTRING_BIT(JS_BITS_PER_WORD - 3)
-
-#define JSSTRING_LENGTH_BITS (JS_BITS_PER_WORD - 3)
-#define JSSTRING_LENGTH_MASK JSSTRING_BITMASK(JSSTRING_LENGTH_BITS)
+#define JSSTRFLAG_BITS 2
+#define JSSTRFLAG_SHIFT(flg) ((size_t)(flg) << JSSTRING_LENGTH_BITS)
+#define JSSTRFLAG_MASK JSSTRFLAG_SHIFT(JS_BITMASK(JSSTRFLAG_BITS))
+#define JSSTRFLAG_DEPENDENT JSSTRFLAG_SHIFT(1)
+#define JSSTRFLAG_PREFIX JSSTRFLAG_SHIFT(2)
+#define JSSTRFLAG_MUTABLE JSSTRFLAG_SHIFT(2)
/* Universal JSString type inquiry and accessor macros. */
#define JSSTRING_BIT(n) ((size_t)1 << (n))
#define JSSTRING_BITMASK(n) (JSSTRING_BIT(n) - 1)
#define JSSTRING_HAS_FLAG(str,flg) ((str)->length & (flg))
#define JSSTRING_IS_DEPENDENT(str) JSSTRING_HAS_FLAG(str, JSSTRFLAG_DEPENDENT)
-#define JSSTRING_IS_MUTABLE(str) (((str)->length & (JSSTRFLAG_DEPENDENT | \
- JSSTRFLAG_MUTABLE)) == \
+#define JSSTRING_IS_MUTABLE(str) (((str)->length & JSSTRFLAG_MASK) == \
JSSTRFLAG_MUTABLE)
-#define JSSTRING_IS_ATOMIZED(str) (((str)->length & (JSSTRFLAG_DEPENDENT | \
- JSSTRFLAG_ATOMIZED)) ==\
- JSSTRFLAG_ATOMIZED)
#define JSSTRING_CHARS(str) (JSSTRING_IS_DEPENDENT(str) \
? JSSTRDEP_CHARS(str) \
- : JSFLATSTR_CHARS(str))
+ : (str)->u.chars)
#define JSSTRING_LENGTH(str) (JSSTRING_IS_DEPENDENT(str) \
? JSSTRDEP_LENGTH(str) \
- : JSFLATSTR_LENGTH(str))
+ : ((str)->length & ~JSSTRFLAG_MUTABLE))
#define JSSTRING_CHARS_AND_LENGTH(str, chars_, length_) \
((void)(JSSTRING_IS_DEPENDENT(str) \
? ((length_) = JSSTRDEP_LENGTH(str), \
(chars_) = JSSTRDEP_CHARS(str)) \
- : ((length_) = JSFLATSTR_LENGTH(str), \
- (chars_) = JSFLATSTR_CHARS(str))))
+ : ((length_) = (str)->length & ~JSSTRFLAG_MUTABLE, \
+ (chars_) = (str)->u.chars)))
#define JSSTRING_CHARS_AND_END(str, chars_, end) \
((void)((end) = JSSTRING_IS_DEPENDENT(str) \
? JSSTRDEP_LENGTH(str) + ((chars_) = JSSTRDEP_CHARS(str)) \
- : JSFLATSTR_LENGTH(str) + ((chars_) = JSFLATSTR_CHARS(str))))
+ : ((str)->length & ~JSSTRFLAG_MUTABLE) + \
+ ((chars_) = (str)->u.chars)))
+
+#define JSSTRING_LENGTH_BITS (sizeof(size_t) * JS_BITS_PER_BYTE \
+ - JSSTRFLAG_BITS)
+#define JSSTRING_LENGTH_MASK JSSTRING_BITMASK(JSSTRING_LENGTH_BITS)
#define JSSTRING_INIT(str, chars_, length_) \
- ((void)(JS_ASSERT(((length_) & ~JSSTRING_LENGTH_MASK) == 0), \
+ ((void)(JS_ASSERT(((length_) & JSSTRFLAG_MASK) == 0), \
(str)->length = (length_), (str)->u.chars = (chars_)))
-/*
- * Specific macro to get the length and characters of a flat string.
- */
-#define JSFLATSTR_LENGTH(str) \
- (JS_ASSERT(!JSSTRING_IS_DEPENDENT(str)), \
- (str)->length & JSSTRING_LENGTH_MASK)
-
-#define JSFLATSTR_CHARS(str) \
- (JS_ASSERT(!JSSTRING_IS_DEPENDENT(str)), (str)->u.chars)
-
-/*
- * Specific macros to manipulate atomized and mutable flags. It is safe to use
- * these without extra locking due to the following properties:
- *
- * * We do not have a macro like JSSTRING_CLEAR_ATOMIZED as a string remains
- * atomized until the GC collects it.
- *
- * * A thread may call JSSTRING_SET_MUTABLE only when it is the only thread
- * accessing the string until a later call to JSSTRING_CLEAR_MUTABLE.
- *
- * * Multiple threads can call JSSTRING_CLEAR_MUTABLE but the macro actually
- * clears the mutable flag only when the flag is set -- in which case only
- * one thread can access the string (see previous property).
- *
- * Thus, when multiple threads access the string, JSSTRING_SET_ATOMIZED is
- * the only macro that can update the length field of the string by changing
- * the mutable bit from 0 to 1. We call the macro only after the string has
- * been hashed. When some threads in js_ValueToStringId see that the flag is
- * set, it knows that the string was atomized.
- *
- * On the other hand, if the thread sees that the flag is unset, it could be
- * seeing a stale value when another thread has just atomized the string and
- * set the flag. But this can lead only to an extra call to js_AtomizeString.
- * This function would find that the string was already hashed and return it
- * with the atomized bit set.
- */
-#define JSSTRING_SET_ATOMIZED(str) \
- ((void)(JS_ASSERT(!JSSTRING_IS_DEPENDENT(str)), \
- JS_ASSERT(!JSSTRING_IS_MUTABLE(str)), \
- (str)->length |= JSSTRFLAG_ATOMIZED))
-
+/* Specific mutable string manipulation macros. */
#define JSSTRING_SET_MUTABLE(str) \
((void)(JS_ASSERT(!JSSTRING_IS_DEPENDENT(str)), \
(str)->length |= JSSTRFLAG_MUTABLE))
#define JSSTRING_CLEAR_MUTABLE(str) \
((void)(JS_ASSERT(!JSSTRING_IS_DEPENDENT(str)), \
- JSSTRING_HAS_FLAG(str, JSSTRFLAG_MUTABLE) && \
- ((str)->length &= ~JSSTRFLAG_MUTABLE)))
+ (str)->length &= ~JSSTRFLAG_MUTABLE))
/* Specific dependent string shift/mask accessor and mutator macros. */
#define JSSTRDEP_START_BITS (JSSTRING_LENGTH_BITS-JSSTRDEP_LENGTH_BITS)
#define JSSTRDEP_START_SHIFT JSSTRDEP_LENGTH_BITS
#define JSSTRDEP_START_MASK JSSTRING_BITMASK(JSSTRDEP_START_BITS)
#define JSSTRDEP_LENGTH_BITS (JSSTRING_LENGTH_BITS / 2)
#define JSSTRDEP_LENGTH_MASK JSSTRING_BITMASK(JSSTRDEP_LENGTH_BITS)
@@ -230,17 +183,17 @@ struct JSString {
#define JSSTRDEP_BASE(str) ((str)->u.base)
#define JSPREFIX_BASE(str) JSSTRDEP_BASE(str)
#define JSPREFIX_SET_BASE(str,bstr) ((str)->u.base = (bstr))
#define JSSTRDEP_CHARS(str) \
(JSSTRING_IS_DEPENDENT(JSSTRDEP_BASE(str)) \
? js_GetDependentStringChars(str) \
- : JSFLATSTR_CHARS(JSSTRDEP_BASE(str)) + JSSTRDEP_START(str))
+ : JSSTRDEP_BASE(str)->u.chars + JSSTRDEP_START(str))
extern size_t
js_MinimizeDependentStrings(JSString *str, int level, JSString **basep);
extern jschar *
js_GetDependentStringChars(JSString *str);
extern const jschar *
--- a/js/src/jsxml.c
+++ b/js/src/jsxml.c
@@ -7891,17 +7891,17 @@ js_AddAttributePart(JSContext *cx, JSBoo
size_t len, len2, newlen;
jschar *chars, *chars2;
JSSTRING_CHARS_AND_LENGTH(str, chars, len);
if (!JSSTRING_IS_MUTABLE(str)) {
str = js_NewStringCopyN(cx, chars, len);
if (!str)
return NULL;
- chars = JSFLATSTR_CHARS(str);
+ chars = str->u.chars;
} else {
/*
* Reallocating str (because we know it has no other references)
* requires purging any deflated string cached for it.
*/
js_PurgeDeflatedStringCache(cx->runtime, str);
}