mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 412340: JString stores a flag to indicate that it was atomized. r=brendan a=blocking1.9+
This commit is contained in:
parent
d312d51d70
commit
d4e057f519
11
js/src/js.c
11
js/src/js.c
@ -1694,7 +1694,7 @@ DumpHeap(JSContext *cx, uintN argc, jsval *vp)
|
||||
static JSBool
|
||||
DoExport(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSAtom *atom;
|
||||
jsid id;
|
||||
JSObject *obj2;
|
||||
JSProperty *prop;
|
||||
JSBool ok;
|
||||
@ -1707,19 +1707,18 @@ DoExport(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
if (!JS_ValueToObject(cx, argv[0], &obj))
|
||||
return JS_FALSE;
|
||||
argv[0] = OBJECT_TO_JSVAL(obj);
|
||||
atom = js_ValueToStringAtom(cx, argv[1]);
|
||||
if (!atom)
|
||||
if (!js_ValueToStringId(cx, argv[1], &id))
|
||||
return JS_FALSE;
|
||||
if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop))
|
||||
if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &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, ATOM_TO_JSID(atom), prop, &attrs);
|
||||
ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
|
||||
if (ok) {
|
||||
attrs |= JSPROP_EXPORTED;
|
||||
ok = OBJ_SET_ATTRIBUTES(cx, obj, ATOM_TO_JSID(atom), prop, &attrs);
|
||||
ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, &attrs);
|
||||
}
|
||||
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
||||
}
|
||||
|
@ -2565,23 +2565,15 @@ JS_DestroyIdArray(JSContext *cx, JSIdArray *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
|
||||
if (JSVAL_IS_OBJECT(v)) {
|
||||
*idp = OBJECT_JSVAL_TO_JSID(v);
|
||||
return JS_TRUE;
|
||||
}
|
||||
else if (!JSVAL_IS_PRIMITIVE(v))
|
||||
*idp = OBJECT_JSVAL_TO_JSID(v);
|
||||
#endif
|
||||
atom = js_ValueToStringAtom(cx, v);
|
||||
if (!atom)
|
||||
return JS_FALSE;
|
||||
*idp = ATOM_TO_JSID(atom);
|
||||
}
|
||||
else
|
||||
return js_ValueToStringId(cx, v, idp);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@ -5240,7 +5232,7 @@ JS_GetStringChars(JSString *str)
|
||||
}
|
||||
} else {
|
||||
JSSTRING_CLEAR_MUTABLE(str);
|
||||
s = str->u.chars;
|
||||
s = JSFLATSTR_CHARS(str);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
125
js/src/jsatom.c
125
js/src/jsatom.c
@ -621,16 +621,16 @@ js_AtomizeDouble(JSContext *cx, jsdouble d)
|
||||
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))
|
||||
== 0);
|
||||
JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY)));
|
||||
JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR);
|
||||
|
||||
state = &cx->runtime->atomState;
|
||||
table = &state->stringAtoms;
|
||||
|
||||
@ -638,49 +638,67 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
||||
entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, str, JS_DHASH_ADD));
|
||||
if (!entry)
|
||||
goto failed_hash_add;
|
||||
if (entry->keyAndFlags == 0) {
|
||||
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.
|
||||
*/
|
||||
++state->tablegen;
|
||||
gen = state->tablegen;
|
||||
JS_UNLOCK(&state->lock, cx);
|
||||
|
||||
if (flags & ATOM_TMPSTR) {
|
||||
if (flags & ATOM_NOCOPY) {
|
||||
key = js_NewString(cx, str->u.chars, str->length);
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
/* Transfer ownership of str->chars to GC-controlled string. */
|
||||
str->u.chars = NULL;
|
||||
} else {
|
||||
key = js_NewStringCopyN(cx, str->u.chars, str->length);
|
||||
if (!key)
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT((flags & ATOM_NOCOPY) == 0);
|
||||
if (!JS_MakeStringImmutable(cx, str))
|
||||
return NULL;
|
||||
if (!(flags & ATOM_TMPSTR) && !JSSTRING_IS_DEPENDENT(str)) {
|
||||
JSSTRING_CLEAR_MUTABLE(str);
|
||||
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;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(JSSTRING_IS_DEPENDENT(str));
|
||||
if (!js_UndependString(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;
|
||||
}
|
||||
}
|
||||
INIT_ATOM_ENTRY(entry, key);
|
||||
JSSTRING_SET_ATOMIZED(key);
|
||||
}
|
||||
|
||||
finish:
|
||||
ADD_ATOM_ENTRY_FLAGS(entry, flags & (ATOM_PINNED | ATOM_INTERNED));
|
||||
v = STRING_TO_JSVAL((JSString *)ATOM_ENTRY_KEY(entry));
|
||||
JS_ASSERT(JSSTRING_IS_ATOMIZED(key));
|
||||
v = STRING_TO_JSVAL(key);
|
||||
cx->weakRoots.lastAtom = v;
|
||||
JS_UNLOCK(&state->lock, cx);
|
||||
return (JSAtom *)v;
|
||||
@ -779,15 +797,36 @@ js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSAtom *
|
||||
js_ValueToStringAtom(JSContext *cx, jsval v)
|
||||
JSBool
|
||||
js_ValueToStringId(JSContext *cx, jsval v, jsid *idp)
|
||||
{
|
||||
JSString *str;
|
||||
JSAtom *atom;
|
||||
|
||||
str = js_ValueToString(cx, v);
|
||||
if (!str)
|
||||
return NULL;
|
||||
return js_AtomizeString(cx, str, 0);
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -416,10 +416,10 @@ JSBool
|
||||
js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp);
|
||||
|
||||
/*
|
||||
* Convert v to an atomized string.
|
||||
* Convert v to an atomized string and wrap it as an id.
|
||||
*/
|
||||
extern JSAtom *
|
||||
js_ValueToStringAtom(JSContext *cx, jsval v);
|
||||
extern JSBool
|
||||
js_ValueToStringId(JSContext *cx, jsval v, jsid *idp);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
|
@ -675,9 +675,9 @@ js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
|
||||
if (JSID_IS_ATOM(id)) {
|
||||
atom = JSID_TO_ATOM(id);
|
||||
} else if (JSID_IS_INT(id)) {
|
||||
atom = js_ValueToStringAtom(cx, INT_JSID_TO_JSVAL(id));
|
||||
if (!atom)
|
||||
if (!js_ValueToStringId(cx, INT_JSID_TO_JSVAL(id), &id))
|
||||
return NULL;
|
||||
atom = JSID_TO_ATOM(id);
|
||||
} else {
|
||||
atom = NULL;
|
||||
}
|
||||
@ -690,10 +690,9 @@ js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter)
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
|
||||
JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval,
|
||||
JSWatchPointHandler handler, void *closure)
|
||||
{
|
||||
JSAtom *atom;
|
||||
jsid propid;
|
||||
JSObject *pobj;
|
||||
JSProperty *prop;
|
||||
@ -709,15 +708,10 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
|
||||
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 (JSVAL_IS_INT(idval))
|
||||
propid = INT_JSVAL_TO_JSID(idval);
|
||||
else if (!js_ValueToStringId(cx, idval, &propid))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
|
||||
return JS_FALSE;
|
||||
@ -752,8 +746,8 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id,
|
||||
flags = sprop->flags;
|
||||
shortid = sprop->shortid;
|
||||
} else {
|
||||
if (!OBJ_GET_PROPERTY(cx, pobj, id, &value) ||
|
||||
!OBJ_GET_ATTRIBUTES(cx, pobj, id, prop, &attrs)) {
|
||||
if (!OBJ_GET_PROPERTY(cx, pobj, propid, &value) ||
|
||||
!OBJ_GET_ATTRIBUTES(cx, pobj, propid, prop, &attrs)) {
|
||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||
return JS_FALSE;
|
||||
}
|
||||
@ -1522,7 +1516,8 @@ GetAtomTotalSize(JSContext *cx, JSAtom *atom)
|
||||
nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub);
|
||||
if (ATOM_IS_STRING(atom)) {
|
||||
nbytes += sizeof(JSString);
|
||||
nbytes += (ATOM_TO_STRING(atom)->length + 1) * sizeof(jschar);
|
||||
nbytes += (JSFLATSTR_LENGTH(ATOM_TO_STRING(atom)) + 1)
|
||||
* sizeof(jschar);
|
||||
} else if (ATOM_IS_DOUBLE(atom)) {
|
||||
nbytes += sizeof(jsdouble);
|
||||
}
|
||||
|
@ -807,12 +807,11 @@ call_enumerate(JSContext *cx, JSObject *obj)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
||||
call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
|
||||
JSObject **objp)
|
||||
{
|
||||
JSStackFrame *fp;
|
||||
JSString *str;
|
||||
JSAtom *atom;
|
||||
jsid id;
|
||||
JSLocalKind localKind;
|
||||
JSPropertyOp getter, setter;
|
||||
uintN slot, attrs;
|
||||
@ -824,15 +823,13 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
||||
JS_ASSERT(fp->fun);
|
||||
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee) == fp->fun);
|
||||
|
||||
if (!JSVAL_IS_STRING(id))
|
||||
if (!JSVAL_IS_STRING(idval))
|
||||
return JS_TRUE;
|
||||
|
||||
str = JSVAL_TO_STRING(id);
|
||||
atom = js_AtomizeString(cx, str, 0);
|
||||
if (!atom)
|
||||
if (!js_ValueToStringId(cx, idval, &id))
|
||||
return JS_FALSE;
|
||||
|
||||
localKind = js_LookupLocal(cx, fp->fun, atom, &slot);
|
||||
localKind = js_LookupLocal(cx, fp->fun, JSID_TO_ATOM(id), &slot);
|
||||
if (localKind != JSLOCAL_NONE) {
|
||||
if (localKind == JSLOCAL_ARG) {
|
||||
JS_ASSERT(slot < fp->fun->nargs);
|
||||
@ -850,9 +847,9 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
||||
? JSPROP_PERMANENT | JSPROP_READONLY
|
||||
: JSPROP_PERMANENT;
|
||||
}
|
||||
if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), vp[slot],
|
||||
getter, setter, attrs,
|
||||
SPROP_HAS_SHORTID, (int) slot, NULL)) {
|
||||
if (!js_DefineNativeProperty(cx, obj, id, vp[slot], getter, setter,
|
||||
attrs, SPROP_HAS_SHORTID, (int) slot,
|
||||
NULL)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
*objp = obj;
|
||||
@ -863,10 +860,8 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
||||
* Resolve arguments so that we never store a particular Call object's
|
||||
* arguments object reference in a Call prototype's |arguments| slot.
|
||||
*/
|
||||
atom = cx->runtime->atomState.argumentsAtom;
|
||||
if (id == ATOM_KEY(atom)) {
|
||||
if (!js_DefineNativeProperty(cx, obj,
|
||||
ATOM_TO_JSID(atom), JSVAL_VOID,
|
||||
if (id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
|
||||
if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID,
|
||||
NULL, NULL, JSPROP_PERMANENT,
|
||||
SPROP_HAS_SHORTID, CALL_ARGUMENTS,
|
||||
NULL)) {
|
||||
|
@ -1632,8 +1632,6 @@ js_InvokeConstructor(JSContext *cx, jsval *vp, uintN argc)
|
||||
static JSBool
|
||||
InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp)
|
||||
{
|
||||
JSAtom *atom;
|
||||
|
||||
JS_ASSERT(!JSVAL_IS_INT(idval));
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
@ -1649,11 +1647,7 @@ InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp)
|
||||
}
|
||||
#endif
|
||||
|
||||
atom = js_ValueToStringAtom(cx, idval);
|
||||
if (!atom)
|
||||
return JS_FALSE;
|
||||
*idp = ATOM_TO_JSID(atom);
|
||||
return JS_TRUE;
|
||||
return js_ValueToStringId(cx, idval, idp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2937,11 +2937,11 @@ js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
|
||||
if (JSID_IS_ATOM(id)) { \
|
||||
JSAtom *atom_ = JSID_TO_ATOM(id); \
|
||||
JSString *str_ = ATOM_TO_STRING(atom_); \
|
||||
const jschar *cp_ = str_->u.chars; \
|
||||
const jschar *cp_ = JSFLATSTR_CHARS(str_); \
|
||||
JSBool negative_ = (*cp_ == '-'); \
|
||||
if (negative_) cp_++; \
|
||||
if (JS7_ISDEC(*cp_)) { \
|
||||
size_t n_ = str_->length - negative_; \
|
||||
size_t n_ = JSFLATSTR_LENGTH(str_) - negative_; \
|
||||
if (n_ <= sizeof(JSVAL_INT_MAX_STRING) - 1) \
|
||||
id = CheckForStringIndex(id, cp_, cp_ + n_, negative_); \
|
||||
} \
|
||||
|
@ -6406,7 +6406,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
|
||||
/* XXX fold only if all operands convert to string */
|
||||
if (pn2->pn_type != TOK_STRING)
|
||||
return JS_TRUE;
|
||||
length += ATOM_TO_STRING(pn2->pn_atom)->length;
|
||||
length += JSFLATSTR_LENGTH(ATOM_TO_STRING(pn2->pn_atom));
|
||||
}
|
||||
|
||||
/* Allocate a new buffer and string descriptor for the result. */
|
||||
@ -6422,8 +6422,8 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
|
||||
/* 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 = str2->length;
|
||||
js_strncpy(chars, str2->u.chars, length2);
|
||||
length2 = JSFLATSTR_LENGTH(str2);
|
||||
js_strncpy(chars, JSFLATSTR_CHARS(str2), length2);
|
||||
chars += length2;
|
||||
}
|
||||
*chars = 0;
|
||||
|
@ -110,8 +110,8 @@ js_GetDependentStringChars(JSString *str)
|
||||
|
||||
start = js_MinimizeDependentStrings(str, 0, &base);
|
||||
JS_ASSERT(!JSSTRING_IS_DEPENDENT(base));
|
||||
JS_ASSERT(start < (base->length & ~JSSTRFLAG_MUTABLE));
|
||||
return base->u.chars + start;
|
||||
JS_ASSERT(start < JSFLATSTR_LENGTH(base));
|
||||
return JSFLATSTR_CHARS(base) + start;
|
||||
}
|
||||
|
||||
const jschar *
|
||||
@ -120,7 +120,7 @@ js_GetStringChars(JSContext *cx, JSString *str)
|
||||
if (!js_MakeStringImmutable(cx, str))
|
||||
return NULL;
|
||||
JS_ASSERT(!JSSTRING_IS_DEPENDENT(str));
|
||||
return str->u.chars;
|
||||
return JSFLATSTR_CHARS(str);
|
||||
}
|
||||
|
||||
JSString *
|
||||
@ -225,7 +225,7 @@ js_UndependString(JSContext *cx, JSString *str)
|
||||
#endif
|
||||
}
|
||||
|
||||
return str->u.chars;
|
||||
return JSFLATSTR_CHARS(str);
|
||||
}
|
||||
|
||||
JSBool
|
||||
@ -2645,6 +2645,7 @@ js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop,
|
||||
void
|
||||
js_FinalizeStringRT(JSRuntime *rt, JSString *str, intN type, JSContext *cx)
|
||||
{
|
||||
jschar *chars;
|
||||
JSBool valid;
|
||||
JSStringFinalizeOp finalizer;
|
||||
|
||||
@ -2657,14 +2658,15 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str, intN type, JSContext *cx)
|
||||
valid = JS_TRUE;
|
||||
} else {
|
||||
/* A stillborn string has null chars, so is not valid. */
|
||||
valid = (str->u.chars != NULL);
|
||||
chars = JSFLATSTR_CHARS(str);
|
||||
valid = (chars != NULL);
|
||||
if (valid) {
|
||||
if (IN_UNIT_STRING_SPACE_RT(rt, str->u.chars)) {
|
||||
JS_ASSERT(rt->unitStrings[*str->u.chars] == str);
|
||||
if (IN_UNIT_STRING_SPACE_RT(rt, chars)) {
|
||||
JS_ASSERT(rt->unitStrings[*chars] == str);
|
||||
JS_ASSERT(type < 0);
|
||||
rt->unitStrings[*str->u.chars] = NULL;
|
||||
rt->unitStrings[*chars] = NULL;
|
||||
} else if (type < 0) {
|
||||
free(str->u.chars);
|
||||
free(chars);
|
||||
} else {
|
||||
JS_ASSERT((uintN) type < JS_ARRAY_LENGTH(str_finalizers));
|
||||
finalizer = str_finalizers[type];
|
||||
|
@ -70,6 +70,10 @@ JS_BEGIN_EXTERN_C
|
||||
* 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
|
||||
@ -99,59 +103,102 @@ struct JSString {
|
||||
* 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 JSSTRFLAG_DEPENDENT is unset.
|
||||
* 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.
|
||||
*/
|
||||
#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)
|
||||
#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)
|
||||
|
||||
/* 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_MASK) == \
|
||||
#define JSSTRING_IS_MUTABLE(str) (((str)->length & (JSSTRFLAG_DEPENDENT | \
|
||||
JSSTRFLAG_MUTABLE)) == \
|
||||
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) \
|
||||
: (str)->u.chars)
|
||||
: JSFLATSTR_CHARS(str))
|
||||
#define JSSTRING_LENGTH(str) (JSSTRING_IS_DEPENDENT(str) \
|
||||
? JSSTRDEP_LENGTH(str) \
|
||||
: ((str)->length & ~JSSTRFLAG_MUTABLE))
|
||||
: JSFLATSTR_LENGTH(str))
|
||||
|
||||
#define JSSTRING_CHARS_AND_LENGTH(str, chars_, length_) \
|
||||
((void)(JSSTRING_IS_DEPENDENT(str) \
|
||||
? ((length_) = JSSTRDEP_LENGTH(str), \
|
||||
(chars_) = JSSTRDEP_CHARS(str)) \
|
||||
: ((length_) = (str)->length & ~JSSTRFLAG_MUTABLE, \
|
||||
(chars_) = (str)->u.chars)))
|
||||
: ((length_) = JSFLATSTR_LENGTH(str), \
|
||||
(chars_) = JSFLATSTR_CHARS(str))))
|
||||
|
||||
#define JSSTRING_CHARS_AND_END(str, chars_, end) \
|
||||
((void)((end) = JSSTRING_IS_DEPENDENT(str) \
|
||||
? JSSTRDEP_LENGTH(str) + ((chars_) = JSSTRDEP_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)
|
||||
: JSFLATSTR_LENGTH(str) + ((chars_) = JSFLATSTR_CHARS(str))))
|
||||
|
||||
#define JSSTRING_INIT(str, chars_, length_) \
|
||||
((void)(JS_ASSERT(((length_) & JSSTRFLAG_MASK) == 0), \
|
||||
((void)(JS_ASSERT(((length_) & ~JSSTRING_LENGTH_MASK) == 0), \
|
||||
(str)->length = (length_), (str)->u.chars = (chars_)))
|
||||
|
||||
/* Specific mutable string manipulation macros. */
|
||||
/*
|
||||
* 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))
|
||||
|
||||
#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)), \
|
||||
(str)->length &= ~JSSTRFLAG_MUTABLE))
|
||||
JSSTRING_HAS_FLAG(str, 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)
|
||||
@ -188,7 +235,7 @@ struct JSString {
|
||||
#define JSSTRDEP_CHARS(str) \
|
||||
(JSSTRING_IS_DEPENDENT(JSSTRDEP_BASE(str)) \
|
||||
? js_GetDependentStringChars(str) \
|
||||
: JSSTRDEP_BASE(str)->u.chars + JSSTRDEP_START(str))
|
||||
: JSFLATSTR_CHARS(JSSTRDEP_BASE(str)) + JSSTRDEP_START(str))
|
||||
|
||||
extern size_t
|
||||
js_MinimizeDependentStrings(JSString *str, int level, JSString **basep);
|
||||
|
@ -7896,7 +7896,7 @@ js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, JSString *str2)
|
||||
str = js_NewStringCopyN(cx, chars, len);
|
||||
if (!str)
|
||||
return NULL;
|
||||
chars = str->u.chars;
|
||||
chars = JSFLATSTR_CHARS(str);
|
||||
} else {
|
||||
/*
|
||||
* Reallocating str (because we know it has no other references)
|
||||
|
Loading…
Reference in New Issue
Block a user