mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 391290: mutability flag for strings is stored inside strings. r=brendan
This commit is contained in:
parent
a96dc350c6
commit
4773ca1cae
@ -2515,8 +2515,7 @@ JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
|
||||
str = (JSString *) js_NewGCThing(cx, (uintN) type, sizeof(JSString));
|
||||
if (!str)
|
||||
return NULL;
|
||||
str->length = length;
|
||||
str->chars = chars;
|
||||
JSSTRING_INIT(str, chars, length);
|
||||
return str;
|
||||
}
|
||||
|
||||
@ -2527,7 +2526,7 @@ JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
|
||||
|
||||
if (type >= GCX_EXTERNAL_STRING)
|
||||
return (intN)type;
|
||||
JS_ASSERT(type == GCX_STRING || type == GCX_MUTABLE_STRING);
|
||||
JS_ASSERT(type == GCX_STRING);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -5028,7 +5027,7 @@ JS_NewString(JSContext *cx, char *bytes, size_t nbytes)
|
||||
return NULL;
|
||||
|
||||
/* Free chars (but not bytes, which caller frees on error) if we fail. */
|
||||
str = js_NewString(cx, chars, length, 0);
|
||||
str = js_NewString(cx, chars, length);
|
||||
if (!str) {
|
||||
JS_free(cx, chars);
|
||||
return NULL;
|
||||
@ -5050,7 +5049,7 @@ JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
|
||||
js = js_InflateString(cx, s, &n);
|
||||
if (!js)
|
||||
return NULL;
|
||||
str = js_NewString(cx, js, n, 0);
|
||||
str = js_NewString(cx, js, n);
|
||||
if (!str)
|
||||
JS_free(cx, js);
|
||||
return str;
|
||||
@ -5070,7 +5069,7 @@ JS_NewStringCopyZ(JSContext *cx, const char *s)
|
||||
js = js_InflateString(cx, s, &n);
|
||||
if (!js)
|
||||
return NULL;
|
||||
str = js_NewString(cx, js, n, 0);
|
||||
str = js_NewString(cx, js, n);
|
||||
if (!str)
|
||||
JS_free(cx, js);
|
||||
return str;
|
||||
@ -5092,7 +5091,7 @@ JS_PUBLIC_API(JSString *)
|
||||
JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
return js_NewString(cx, chars, length, 0);
|
||||
return js_NewString(cx, chars, length);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSString *)
|
||||
@ -5162,15 +5161,17 @@ JS_GetStringChars(JSString *str)
|
||||
size = (n + 1) * sizeof(jschar);
|
||||
s = (jschar *) malloc(size);
|
||||
if (s) {
|
||||
js_strncpy(s, JSSTRDEP_CHARS(str), n);
|
||||
memcpy(s, JSSTRDEP_CHARS(str), n * sizeof *s);
|
||||
s[n] = 0;
|
||||
str->length = n;
|
||||
str->chars = s;
|
||||
JSSTRING_INIT(str, s, n);
|
||||
} else {
|
||||
s = JSSTRDEP_CHARS(str);
|
||||
}
|
||||
} else {
|
||||
JSSTRING_CLEAR_MUTABLE(str);
|
||||
s = str->u.chars;
|
||||
}
|
||||
|
||||
*js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
|
||||
return JSSTRING_CHARS(str);
|
||||
return s;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(size_t)
|
||||
@ -5188,8 +5189,14 @@ JS_CompareStrings(JSString *str1, JSString *str2)
|
||||
JS_PUBLIC_API(JSString *)
|
||||
JS_NewGrowableString(JSContext *cx, jschar *chars, size_t length)
|
||||
{
|
||||
JSString *str;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
return js_NewString(cx, chars, length, GCF_MUTABLE);
|
||||
str = js_NewString(cx, chars, length);
|
||||
if (!str)
|
||||
return str;
|
||||
JSSTRING_SET_MUTABLE(str);
|
||||
return str;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSString *)
|
||||
@ -5218,11 +5225,7 @@ JS_PUBLIC_API(JSBool)
|
||||
JS_MakeStringImmutable(JSContext *cx, JSString *str)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
if (!js_UndependString(cx, str))
|
||||
return JS_FALSE;
|
||||
|
||||
*js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
|
||||
return JS_TRUE;
|
||||
return js_MakeStringImmutable(cx, str);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
|
@ -602,8 +602,7 @@ array_join_sub(JSContext *cx, JSObject *obj, enum ArrayToStringOp op,
|
||||
MAKE_BUSY(he);
|
||||
|
||||
if (sep) {
|
||||
sepstr = JSSTRING_CHARS(sep);
|
||||
seplen = JSSTRING_LENGTH(sep);
|
||||
JSSTRING_CHARS_AND_LENGTH(sep, sepstr, seplen);
|
||||
} else {
|
||||
sepstr = NULL; /* indicates to use "," as separator */
|
||||
seplen = 1;
|
||||
@ -715,7 +714,7 @@ array_join_sub(JSContext *cx, JSObject *obj, enum ArrayToStringOp op,
|
||||
}
|
||||
chars[nchars] = 0;
|
||||
JS_ASSERT(growth == (size_t)-1 || (nchars + 1) * sizeof(jschar) == growth);
|
||||
str = js_NewString(cx, chars, nchars, 0);
|
||||
str = js_NewString(cx, chars, nchars);
|
||||
if (!str) {
|
||||
free(chars);
|
||||
return JS_FALSE;
|
||||
|
@ -632,14 +632,14 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
|
||||
|
||||
if (flags & ATOM_TMPSTR) {
|
||||
if (flags & ATOM_NOCOPY) {
|
||||
key = js_NewString(cx, str->chars, str->length, 0);
|
||||
key = js_NewString(cx, str->u.chars, str->length);
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
/* Transfer ownership of str->chars to GC-controlled string. */
|
||||
str->chars = NULL;
|
||||
str->u.chars = NULL;
|
||||
} else {
|
||||
key = js_NewStringCopyN(cx, str->chars, str->length);
|
||||
key = js_NewStringCopyN(cx, str->u.chars, str->length);
|
||||
if (!key)
|
||||
return NULL;
|
||||
}
|
||||
@ -708,10 +708,9 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags)
|
||||
flags |= ATOM_NOCOPY;
|
||||
}
|
||||
|
||||
str.chars = chars;
|
||||
str.length = inflatedLength;
|
||||
JSSTRING_INIT(&str, (jschar *)chars, inflatedLength);
|
||||
atom = js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
|
||||
if (chars != inflated && str.chars)
|
||||
if (chars != inflated && str.u.chars)
|
||||
JS_free(cx, chars);
|
||||
return atom;
|
||||
}
|
||||
@ -721,8 +720,7 @@ js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
|
||||
{
|
||||
JSString str;
|
||||
|
||||
str.chars = (jschar *)chars;
|
||||
str.length = length;
|
||||
JSSTRING_INIT(&str, (jschar *)chars, length);
|
||||
return js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
|
||||
}
|
||||
|
||||
@ -733,8 +731,7 @@ js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
|
||||
JSAtomState *state;
|
||||
JSDHashEntryHdr *hdr;
|
||||
|
||||
str.chars = (jschar *)chars;
|
||||
str.length = length;
|
||||
JSSTRING_INIT(&str, (jschar *)chars, length);
|
||||
state = &cx->runtime->atomState;
|
||||
|
||||
JS_LOCK(&state->lock, cx);
|
||||
|
@ -622,8 +622,8 @@ date_parseString(JSString *str, jsdouble *result)
|
||||
{
|
||||
jsdouble msec;
|
||||
|
||||
const jschar *s = JSSTRING_CHARS(str);
|
||||
size_t limit = JSSTRING_LENGTH(str);
|
||||
const jschar *s;
|
||||
size_t limit;
|
||||
size_t i = 0;
|
||||
int year = -1;
|
||||
int mon = -1;
|
||||
@ -639,6 +639,7 @@ date_parseString(JSString *str, jsdouble *result)
|
||||
int temp;
|
||||
JSBool seenmonthname = JS_FALSE;
|
||||
|
||||
JSSTRING_CHARS_AND_LENGTH(str, s, limit);
|
||||
if (limit == 0)
|
||||
goto syntax;
|
||||
while (i < limit) {
|
||||
|
@ -636,7 +636,10 @@ StackTraceToString(JSContext *cx, JSExnPrivate *priv)
|
||||
#define APPEND_STRING_TO_STACK(str) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSString *str_ = str; \
|
||||
size_t length_ = JSSTRING_LENGTH(str_); \
|
||||
jschar *chars_; \
|
||||
size_t length_; \
|
||||
\
|
||||
JSSTRING_CHARS_AND_LENGTH(str_, chars_, length_); \
|
||||
if (length_ > stackmax - stacklen) { \
|
||||
void *ptr_; \
|
||||
if (stackmax >= STACK_LENGTH_LIMIT || \
|
||||
@ -649,7 +652,7 @@ StackTraceToString(JSContext *cx, JSExnPrivate *priv)
|
||||
goto bad; \
|
||||
stackbuf = (jschar *) ptr_; \
|
||||
} \
|
||||
js_strncpy(stackbuf + stacklen, JSSTRING_CHARS(str_), length_); \
|
||||
js_strncpy(stackbuf + stacklen, chars_, length_); \
|
||||
stacklen += length_; \
|
||||
JS_END_MACRO
|
||||
|
||||
@ -701,7 +704,7 @@ StackTraceToString(JSContext *cx, JSExnPrivate *priv)
|
||||
}
|
||||
|
||||
stackbuf[stacklen] = 0;
|
||||
str = js_NewString(cx, stackbuf, stacklen, 0);
|
||||
str = js_NewString(cx, stackbuf, stacklen);
|
||||
if (str)
|
||||
return str;
|
||||
|
||||
@ -847,7 +850,7 @@ exn_toString(JSContext *cx, uintN argc, jsval *vp)
|
||||
cp += message_length;
|
||||
*cp = 0;
|
||||
|
||||
result = js_NewString(cx, chars, length, 0);
|
||||
result = js_NewString(cx, chars, length);
|
||||
if (!result) {
|
||||
JS_free(cx, chars);
|
||||
return JS_FALSE;
|
||||
@ -973,7 +976,7 @@ exn_toSource(JSContext *cx, uintN argc, jsval *vp)
|
||||
|
||||
*cp++ = ')'; *cp++ = ')'; *cp = 0;
|
||||
|
||||
result = js_NewString(cx, chars, length, 0);
|
||||
result = js_NewString(cx, chars, length);
|
||||
if (!result) {
|
||||
JS_free(cx, chars);
|
||||
return JS_FALSE;
|
||||
|
@ -247,11 +247,11 @@ static uint8 GCTypeToTraceKindMap[GCX_NTYPES] = {
|
||||
JSTRACE_OBJECT, /* GCX_OBJECT */
|
||||
JSTRACE_STRING, /* GCX_STRING */
|
||||
JSTRACE_DOUBLE, /* GCX_DOUBLE */
|
||||
JSTRACE_STRING, /* GCX_MUTABLE_STRING */
|
||||
JSTRACE_FUNCTION, /* GCX_FUNCTION */
|
||||
JSTRACE_NAMESPACE, /* GCX_NAMESPACE */
|
||||
JSTRACE_QNAME, /* GCX_QNAME */
|
||||
JSTRACE_XML, /* GCX_XML */
|
||||
(uint8)-1, /* unused */
|
||||
JSTRACE_STRING, /* GCX_EXTERNAL_STRING + 0 */
|
||||
JSTRACE_STRING, /* GCX_EXTERNAL_STRING + 1 */
|
||||
JSTRACE_STRING, /* GCX_EXTERNAL_STRING + 2 */
|
||||
@ -561,11 +561,11 @@ static GCFinalizeOp gc_finalizers[GCX_NTYPES] = {
|
||||
(GCFinalizeOp) js_FinalizeObject, /* GCX_OBJECT */
|
||||
(GCFinalizeOp) js_FinalizeString, /* GCX_STRING */
|
||||
(GCFinalizeOp) js_FinalizeDouble, /* GCX_DOUBLE */
|
||||
(GCFinalizeOp) js_FinalizeString, /* GCX_MUTABLE_STRING */
|
||||
(GCFinalizeOp) js_FinalizeFunction, /* GCX_FUNCTION */
|
||||
(GCFinalizeOp) js_FinalizeXMLNamespace, /* GCX_NAMESPACE */
|
||||
(GCFinalizeOp) js_FinalizeXMLQName, /* GCX_QNAME */
|
||||
(GCFinalizeOp) js_FinalizeXML, /* GCX_XML */
|
||||
NULL, /* unused */
|
||||
NULL, /* GCX_EXTERNAL_STRING */
|
||||
NULL,
|
||||
NULL,
|
||||
|
@ -53,12 +53,10 @@ JS_BEGIN_EXTERN_C
|
||||
#define GCX_OBJECT 0 /* JSObject */
|
||||
#define GCX_STRING 1 /* JSString */
|
||||
#define GCX_DOUBLE 2 /* jsdouble */
|
||||
#define GCX_MUTABLE_STRING 3 /* JSString that's mutable --
|
||||
single-threaded only! */
|
||||
#define GCX_FUNCTION 4 /* JSFunction */
|
||||
#define GCX_NAMESPACE 5 /* JSXMLNamespace */
|
||||
#define GCX_QNAME 6 /* JSXMLQName */
|
||||
#define GCX_XML 7 /* JSXML */
|
||||
#define GCX_FUNCTION 3 /* JSFunction */
|
||||
#define GCX_NAMESPACE 4 /* JSXMLNamespace */
|
||||
#define GCX_QNAME 5 /* JSXMLQName */
|
||||
#define GCX_XML 6 /* JSXML */
|
||||
#define GCX_EXTERNAL_STRING 8 /* JSString w/ external chars */
|
||||
|
||||
#define GCX_NTYPES_LOG2 4 /* type index bits */
|
||||
@ -72,13 +70,6 @@ JS_BEGIN_EXTERN_C
|
||||
#define GCF_LOCKSHIFT (GCX_NTYPES_LOG2 + 3) /* lock bit shift */
|
||||
#define GCF_LOCK JS_BIT(GCF_LOCKSHIFT) /* lock request bit in API */
|
||||
|
||||
/* Pseudo-flag that modifies GCX_STRING to make GCX_MUTABLE_STRING. */
|
||||
#define GCF_MUTABLE 2
|
||||
|
||||
#if (GCX_STRING | GCF_MUTABLE) != GCX_MUTABLE_STRING
|
||||
# error "mutable string type index botch!"
|
||||
#endif
|
||||
|
||||
extern JS_FRIEND_API(uint8 *)
|
||||
js_GetGCThingFlags(void *thing);
|
||||
|
||||
|
@ -375,22 +375,6 @@ ShareScope(JSContext *cx, JSScope *scope)
|
||||
* updates rt->sharedScopes.
|
||||
*/
|
||||
|
||||
static JSBool
|
||||
MakeStringImmutable(JSContext *cx, JSString *str)
|
||||
{
|
||||
uint8 *flagp;
|
||||
|
||||
flagp = js_GetGCThingFlags(str);
|
||||
if (*flagp & GCF_MUTABLE) {
|
||||
if (JSSTRING_IS_DEPENDENT(str) && !js_UndependString(cx, str)) {
|
||||
JS_RUNTIME_METER(cx->runtime, badUndependStrings);
|
||||
return JS_FALSE;
|
||||
}
|
||||
*flagp &= ~GCF_MUTABLE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
js_FinishSharingScope(JSContext *cx, JSScope *scope)
|
||||
{
|
||||
@ -403,7 +387,7 @@ js_FinishSharingScope(JSContext *cx, JSScope *scope)
|
||||
for (i = 0; i != nslots; ++i) {
|
||||
v = STOBJ_GET_SLOT(obj, i);
|
||||
if (JSVAL_IS_STRING(v) &&
|
||||
!MakeStringImmutable(cx, JSVAL_TO_STRING(v))) {
|
||||
!js_MakeStringImmutable(cx, JSVAL_TO_STRING(v))) {
|
||||
/*
|
||||
* FIXME bug 363059: The following error recovery changes the
|
||||
* execution semantic arbitrary and silently ignores any errors
|
||||
@ -677,7 +661,7 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
|
||||
|
||||
/* Any string stored in a thread-safe object must be immutable. */
|
||||
if (JSVAL_IS_STRING(v) &&
|
||||
!MakeStringImmutable(cx, JSVAL_TO_STRING(v))) {
|
||||
!js_MakeStringImmutable(cx, JSVAL_TO_STRING(v))) {
|
||||
/* FIXME bug 363059: See comments in js_FinishSharingScope. */
|
||||
v = JSVAL_NULL;
|
||||
}
|
||||
|
@ -92,13 +92,13 @@ num_parseFloat(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
JSString *str;
|
||||
jsdouble d;
|
||||
const jschar *bp, *ep;
|
||||
const jschar *bp, *end, *ep;
|
||||
|
||||
str = js_ValueToString(cx, vp[2]);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
bp = JSSTRING_CHARS(str);
|
||||
if (!js_strtod(cx, bp, bp + JSSTRING_LENGTH(str), &ep, &d))
|
||||
JSSTRING_CHARS_AND_END(str, bp, end);
|
||||
if (!js_strtod(cx, bp, end, &ep, &d))
|
||||
return JS_FALSE;
|
||||
if (ep == bp) {
|
||||
*vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
|
||||
@ -114,7 +114,7 @@ num_parseInt(JSContext *cx, uintN argc, jsval *vp)
|
||||
jsint radix;
|
||||
JSString *str;
|
||||
jsdouble d;
|
||||
const jschar *bp, *ep;
|
||||
const jschar *bp, *end, *ep;
|
||||
|
||||
if (argc > 1) {
|
||||
if (!js_ValueToECMAInt32(cx, vp[3], &radix))
|
||||
@ -130,8 +130,8 @@ num_parseInt(JSContext *cx, uintN argc, jsval *vp)
|
||||
str = js_ValueToString(cx, vp[2]);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
bp = JSSTRING_CHARS(str);
|
||||
if (!js_strtointeger(cx, bp, bp + JSSTRING_LENGTH(str), &ep, radix, &d))
|
||||
JSSTRING_CHARS_AND_END(str, bp, end);
|
||||
if (!js_strtointeger(cx, bp, end, &ep, radix, &d))
|
||||
return JS_FALSE;
|
||||
if (ep == bp) {
|
||||
*vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
|
||||
@ -724,8 +724,7 @@ js_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
|
||||
* interpreted as decimal by js_strtod and will never get passed to
|
||||
* js_strtointeger (which would interpret them as octal).
|
||||
*/
|
||||
bp = JSSTRING_CHARS(str);
|
||||
end = bp + JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_END(str, bp, end);
|
||||
if ((!js_strtod(cx, bp, end, &ep, dp) ||
|
||||
js_SkipWhiteSpace(ep, end) != end) &&
|
||||
(!js_strtointeger(cx, bp, end, &ep, 0, dp) ||
|
||||
|
@ -937,8 +937,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp)
|
||||
}
|
||||
*vp = STRING_TO_JSVAL(idstr); /* local root */
|
||||
}
|
||||
idstrchars = JSSTRING_CHARS(idstr);
|
||||
idstrlength = JSSTRING_LENGTH(idstr);
|
||||
JSSTRING_CHARS_AND_LENGTH(idstr, idstrchars, idstrlength);
|
||||
|
||||
for (j = 0; j < valcnt; j++) {
|
||||
/* Convert val[j] to its canonical source form. */
|
||||
@ -948,8 +947,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp)
|
||||
goto error;
|
||||
}
|
||||
vp[2 + j] = STRING_TO_JSVAL(valstr); /* local root */
|
||||
vchars = JSSTRING_CHARS(valstr);
|
||||
vlength = JSSTRING_LENGTH(valstr);
|
||||
JSSTRING_CHARS_AND_LENGTH(valstr, vchars, vlength);
|
||||
|
||||
if (vchars[0] == '#')
|
||||
needOldStyleGetterSetter = JS_TRUE;
|
||||
@ -1131,7 +1129,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp)
|
||||
return JS_FALSE;
|
||||
}
|
||||
make_string:
|
||||
str = js_NewString(cx, chars, nchars, 0);
|
||||
str = js_NewString(cx, chars, nchars);
|
||||
if (!str) {
|
||||
free(chars);
|
||||
return JS_FALSE;
|
||||
@ -1170,7 +1168,7 @@ obj_toString(JSContext *cx, uintN argc, jsval *vp)
|
||||
chars[nchars++] = ']';
|
||||
chars[nchars] = 0;
|
||||
|
||||
str = js_NewString(cx, chars, nchars, 0);
|
||||
str = js_NewString(cx, chars, nchars);
|
||||
if (!str) {
|
||||
JS_free(cx, chars);
|
||||
return JS_FALSE;
|
||||
@ -2844,7 +2842,7 @@ 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_->chars; \
|
||||
const jschar *cp_ = str_->u.chars; \
|
||||
JSBool negative_ = (*cp_ == '-'); \
|
||||
if (negative_) cp_++; \
|
||||
if (JS7_ISDEC(*cp_)) { \
|
||||
@ -4965,8 +4963,8 @@ void printString(JSString *str) {
|
||||
size_t i, n;
|
||||
jschar *s;
|
||||
fprintf(stderr, "string (%p) \"", (void *)str);
|
||||
s = JSSTRING_CHARS(str);
|
||||
for (i=0, n=JSSTRING_LENGTH(str); i < n; i++)
|
||||
JSSTRING_CHARS_AND_LENGTH(str, s, n);
|
||||
for (i=0; i < n; i++)
|
||||
fputc(s[i], stderr);
|
||||
fputc('"', stderr);
|
||||
fputc('\n', stderr);
|
||||
|
@ -467,8 +467,7 @@ SprintString(Sprinter *sp, JSString *str)
|
||||
size_t length, size;
|
||||
ptrdiff_t offset;
|
||||
|
||||
chars = JSSTRING_CHARS(str);
|
||||
length = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, chars, length);
|
||||
if (length == 0)
|
||||
return sp->offset;
|
||||
|
||||
@ -537,8 +536,7 @@ QuoteString(Sprinter *sp, JSString *str, uint32 quote)
|
||||
return NULL;
|
||||
|
||||
/* Loop control variables: z points at end of string sentinel. */
|
||||
s = JSSTRING_CHARS(str);
|
||||
z = s + JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_END(str, s, z);
|
||||
for (t = s; t < z; s = ++t) {
|
||||
/* Move t forward from s past un-quote-worthy characters. */
|
||||
c = *t;
|
||||
|
@ -6653,7 +6653,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
|
||||
chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
|
||||
if (!chars)
|
||||
return JS_FALSE;
|
||||
str = js_NewString(cx, chars, length, 0);
|
||||
str = js_NewString(cx, chars, length);
|
||||
if (!str) {
|
||||
JS_free(cx, chars);
|
||||
return JS_FALSE;
|
||||
@ -6663,7 +6663,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
|
||||
for (pn2 = pn1; pn2; pn2 = RecycleTree(pn2, tc)) {
|
||||
str2 = ATOM_TO_STRING(pn2->pn_atom);
|
||||
length2 = str2->length;
|
||||
js_strncpy(chars, str2->chars, length2);
|
||||
js_strncpy(chars, str2->u.chars, length2);
|
||||
chars += length2;
|
||||
}
|
||||
*chars = 0;
|
||||
|
@ -97,7 +97,6 @@ typedef uint32 jsatomid;
|
||||
/* Struct typedefs. */
|
||||
typedef struct JSArgumentFormatMap JSArgumentFormatMap;
|
||||
typedef struct JSCodeGenerator JSCodeGenerator;
|
||||
typedef struct JSDependentString JSDependentString;
|
||||
typedef struct JSGCThing JSGCThing;
|
||||
typedef struct JSGenerator JSGenerator;
|
||||
typedef struct JSParseContext JSParseContext;
|
||||
|
@ -2032,8 +2032,8 @@ js_NewRegExpOpt(JSContext *cx, JSTokenStream *ts,
|
||||
|
||||
flags = 0;
|
||||
if (opt) {
|
||||
s = JSSTRING_CHARS(opt);
|
||||
for (i = 0, n = JSSTRING_LENGTH(opt); i < n; i++) {
|
||||
JSSTRING_CHARS_AND_LENGTH(opt, s, n);
|
||||
for (i = 0; i < n; i++) {
|
||||
switch (s[i]) {
|
||||
case 'g':
|
||||
flags |= JSREG_GLOB;
|
||||
@ -3373,10 +3373,9 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
|
||||
* and we never let cp get beyond cpend.
|
||||
*/
|
||||
start = *indexp;
|
||||
length = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, cp, length);
|
||||
if (start > length)
|
||||
start = length;
|
||||
cp = JSSTRING_CHARS(str);
|
||||
gData.cpbegin = cp;
|
||||
gData.cpend = cp + length;
|
||||
cp += start;
|
||||
@ -3914,8 +3913,7 @@ js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
source = JSSTRING_CHARS(re->source);
|
||||
length = JSSTRING_LENGTH(re->source);
|
||||
JSSTRING_CHARS_AND_LENGTH(re->source, source, length);
|
||||
if (length == 0) {
|
||||
source = empty_regexp_ucstr;
|
||||
length = sizeof(empty_regexp_ucstr) / sizeof(jschar) - 1;
|
||||
@ -3946,7 +3944,7 @@ js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp)
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
chars[length] = 0;
|
||||
|
||||
str = js_NewString(cx, chars, length, 0);
|
||||
str = js_NewString(cx, chars, length);
|
||||
if (!str) {
|
||||
JS_free(cx, chars);
|
||||
return JS_FALSE;
|
||||
@ -4021,8 +4019,7 @@ regexp_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
}
|
||||
|
||||
/* Escape any naked slashes in the regexp source. */
|
||||
length = JSSTRING_LENGTH(str);
|
||||
start = JSSTRING_CHARS(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, start, length);
|
||||
end = start + length;
|
||||
nstart = ncp = NULL;
|
||||
for (cp = start; cp < end; cp++) {
|
||||
@ -4053,7 +4050,7 @@ regexp_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
/* Don't forget to store the backstop after the new string. */
|
||||
JS_ASSERT((size_t)(ncp - nstart) == length);
|
||||
*ncp = 0;
|
||||
str = js_NewString(cx, nstart, length, 0);
|
||||
str = js_NewString(cx, nstart, length);
|
||||
if (!str) {
|
||||
JS_free(cx, nstart);
|
||||
return JS_FALSE;
|
||||
|
@ -157,10 +157,9 @@ js_IsIdentifier(JSString *str)
|
||||
size_t length;
|
||||
jschar c, *chars, *end;
|
||||
|
||||
length = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, chars, length);
|
||||
if (length == 0)
|
||||
return JS_FALSE;
|
||||
chars = JSSTRING_CHARS(str);
|
||||
c = *chars;
|
||||
if (!JS_ISIDSTART(c))
|
||||
return JS_FALSE;
|
||||
|
@ -129,8 +129,7 @@ script_toSource(JSContext *cx, uintN argc, jsval *vp)
|
||||
str = js_QuoteString(cx, str, '\'');
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
s = JSSTRING_CHARS(str);
|
||||
k = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, s, k);
|
||||
n += k;
|
||||
}
|
||||
|
||||
@ -725,8 +724,7 @@ script_thaw(JSContext *cx, uintN argc, jsval *vp)
|
||||
if (!xdr)
|
||||
return JS_FALSE;
|
||||
|
||||
buf = JSSTRING_CHARS(str);
|
||||
len = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, buf, len);
|
||||
#if IS_BIG_ENDIAN
|
||||
{
|
||||
jschar *from, *to;
|
||||
|
316
js/src/jsstr.c
316
js/src/jsstr.c
@ -91,12 +91,11 @@ js_MinimizeDependentStrings(JSString *str, int level, JSString **basep)
|
||||
} while (JSSTRING_IS_DEPENDENT(base));
|
||||
}
|
||||
if (start == 0) {
|
||||
JS_ASSERT(JSSTRING_IS_PREFIX(str));
|
||||
JS_ASSERT(JSSTRDEP_IS_PREFIX(str));
|
||||
JSPREFIX_SET_BASE(str, base);
|
||||
} else if (start <= JSSTRDEP_START_MASK) {
|
||||
length = JSSTRDEP_LENGTH(str);
|
||||
JSSTRDEP_SET_START_AND_LENGTH(str, start, length);
|
||||
JSSTRDEP_SET_BASE(str, base);
|
||||
JSSTRDEP_INIT(str, base, start, length);
|
||||
}
|
||||
}
|
||||
*basep = base;
|
||||
@ -111,18 +110,17 @@ js_GetDependentStringChars(JSString *str)
|
||||
|
||||
start = js_MinimizeDependentStrings(str, 0, &base);
|
||||
JS_ASSERT(!JSSTRING_IS_DEPENDENT(base));
|
||||
JS_ASSERT(start < base->length);
|
||||
return base->chars + start;
|
||||
JS_ASSERT(start < (base->length & ~JSSTRFLAG_MUTABLE));
|
||||
return base->u.chars + start;
|
||||
}
|
||||
|
||||
const jschar *
|
||||
js_GetStringChars(JSContext *cx, JSString *str)
|
||||
{
|
||||
if (JSSTRING_IS_DEPENDENT(str) && !js_UndependString(cx, str))
|
||||
if (!js_MakeStringImmutable(cx, str))
|
||||
return NULL;
|
||||
|
||||
*js_GetGCThingFlags(str) &= ~GCF_MUTABLE;
|
||||
return str->chars;
|
||||
JS_ASSERT(!JSSTRING_IS_DEPENDENT(str));
|
||||
return str->u.chars;
|
||||
}
|
||||
|
||||
JSString *
|
||||
@ -130,26 +128,19 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
|
||||
{
|
||||
size_t rn, ln, lrdist, n;
|
||||
jschar *rs, *ls, *s;
|
||||
JSDependentString *ldep; /* non-null if left should become dependent */
|
||||
JSString *ldep; /* non-null if left should become dependent */
|
||||
JSString *str;
|
||||
|
||||
if (JSSTRING_IS_DEPENDENT(right)) {
|
||||
rn = JSSTRDEP_LENGTH(right);
|
||||
rs = JSSTRDEP_CHARS(right);
|
||||
} else {
|
||||
rn = right->length;
|
||||
rs = right->chars;
|
||||
}
|
||||
JSSTRING_CHARS_AND_LENGTH(right, rs, rn);
|
||||
if (rn == 0)
|
||||
return left;
|
||||
|
||||
if (JSSTRING_IS_DEPENDENT(left) ||
|
||||
!(*js_GetGCThingFlags(left) & GCF_MUTABLE)) {
|
||||
JSSTRING_CHARS_AND_LENGTH(left, ls, ln);
|
||||
if (ln == 0)
|
||||
return right;
|
||||
|
||||
if (!JSSTRING_IS_MUTABLE(left)) {
|
||||
/* We must copy if left does not own a buffer to realloc. */
|
||||
ln = JSSTRING_LENGTH(left);
|
||||
if (ln == 0)
|
||||
return right;
|
||||
ls = JSSTRING_CHARS(left);
|
||||
s = (jschar *) JS_malloc(cx, (ln + rn + 1) * sizeof(jschar));
|
||||
if (!s)
|
||||
return NULL;
|
||||
@ -157,10 +148,7 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
|
||||
ldep = NULL;
|
||||
} else {
|
||||
/* We can realloc left's space and make it depend on our result. */
|
||||
ln = left->length;
|
||||
if (ln == 0)
|
||||
return right;
|
||||
ls = left->chars;
|
||||
JS_ASSERT(!JSSTRING_IS_DEPENDENT(left));
|
||||
s = (jschar *) JS_realloc(cx, ls, (ln + rn + 1) * sizeof(jschar));
|
||||
if (!s)
|
||||
return NULL;
|
||||
@ -169,14 +157,14 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
|
||||
lrdist = (size_t)(rs - ls);
|
||||
if (lrdist < ln)
|
||||
rs = s + lrdist;
|
||||
left->chars = ls = s;
|
||||
ldep = JSSTRDEP(left);
|
||||
left->u.chars = ls = s;
|
||||
ldep = left;
|
||||
}
|
||||
|
||||
js_strncpy(s + ln, rs, rn);
|
||||
n = ln + rn;
|
||||
s[n] = 0;
|
||||
str = js_NewString(cx, s, n, GCF_MUTABLE);
|
||||
str = js_NewString(cx, s, n);
|
||||
if (!str) {
|
||||
/* Out of memory: clean up any space we (re-)allocated. */
|
||||
if (!ldep) {
|
||||
@ -184,13 +172,14 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right)
|
||||
} else {
|
||||
s = (jschar *) JS_realloc(cx, ls, (ln + 1) * sizeof(jschar));
|
||||
if (s)
|
||||
left->chars = s;
|
||||
left->u.chars = s;
|
||||
}
|
||||
} else {
|
||||
JSSTRING_SET_MUTABLE(str);
|
||||
|
||||
/* Morph left into a dependent prefix if we realloc'd its buffer. */
|
||||
if (ldep) {
|
||||
JSPREFIX_SET_LENGTH(ldep, ln);
|
||||
JSPREFIX_SET_BASE(ldep, str);
|
||||
JSPREFIX_INIT(ldep, str, ln);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
@ -222,8 +211,7 @@ js_UndependString(JSContext *cx, JSString *str)
|
||||
|
||||
js_strncpy(s, JSSTRDEP_CHARS(str), n);
|
||||
s[n] = 0;
|
||||
str->length = n;
|
||||
str->chars = s;
|
||||
JSSTRING_INIT(str, s, n);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
@ -237,7 +225,18 @@ js_UndependString(JSContext *cx, JSString *str)
|
||||
#endif
|
||||
}
|
||||
|
||||
return str->chars;
|
||||
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;
|
||||
}
|
||||
JSSTRING_CLEAR_MUTABLE(str);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -332,8 +331,8 @@ js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval
|
||||
return JS_FALSE;
|
||||
argv[0] = STRING_TO_JSVAL(str);
|
||||
|
||||
chars = JSSTRING_CHARS(str);
|
||||
length = newlength = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, chars, length);
|
||||
newlength = length;
|
||||
|
||||
/* Take a first pass and see how big the result string will need to be. */
|
||||
for (i = 0; i < length; i++) {
|
||||
@ -388,7 +387,7 @@ js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval
|
||||
JS_ASSERT(ni == newlength);
|
||||
newchars[newlength] = 0;
|
||||
|
||||
str = js_NewString(cx, newchars, newlength, 0);
|
||||
str = js_NewString(cx, newchars, newlength);
|
||||
if (!str) {
|
||||
JS_free(cx, newchars);
|
||||
return JS_FALSE;
|
||||
@ -419,8 +418,7 @@ str_unescape(JSContext *cx, uintN argc, jsval *vp)
|
||||
return JS_FALSE;
|
||||
vp[2] = STRING_TO_JSVAL(str);
|
||||
|
||||
chars = JSSTRING_CHARS(str);
|
||||
length = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, chars, length);
|
||||
|
||||
/* Don't bother allocating less space for the new string. */
|
||||
newchars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));
|
||||
@ -450,7 +448,7 @@ str_unescape(JSContext *cx, uintN argc, jsval *vp)
|
||||
}
|
||||
newchars[ni] = 0;
|
||||
|
||||
str = js_NewString(cx, newchars, ni, 0);
|
||||
str = js_NewString(cx, newchars, ni);
|
||||
if (!str) {
|
||||
JS_free(cx, newchars);
|
||||
return JS_FALSE;
|
||||
@ -644,8 +642,7 @@ str_toSource(JSContext *cx, uintN argc, jsval *vp)
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
j = JS_snprintf(buf, sizeof buf, "(new %s(", js_StringClass.name);
|
||||
s = JSSTRING_CHARS(str);
|
||||
k = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, s, k);
|
||||
n = j + k + 2;
|
||||
t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
|
||||
if (!t)
|
||||
@ -657,7 +654,7 @@ str_toSource(JSContext *cx, uintN argc, jsval *vp)
|
||||
t[i++] = ')';
|
||||
t[i++] = ')';
|
||||
t[i] = 0;
|
||||
str = js_NewString(cx, t, n, 0);
|
||||
str = js_NewString(cx, t, n);
|
||||
if (!str) {
|
||||
JS_free(cx, t);
|
||||
return JS_FALSE;
|
||||
@ -738,15 +735,14 @@ str_toLowerCase(JSContext *cx, uintN argc, jsval *vp)
|
||||
return JS_FALSE;
|
||||
vp[1] = STRING_TO_JSVAL(str);
|
||||
|
||||
n = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, s, n);
|
||||
news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
|
||||
if (!news)
|
||||
return JS_FALSE;
|
||||
s = JSSTRING_CHARS(str);
|
||||
for (i = 0; i < n; i++)
|
||||
news[i] = JS_TOLOWER(s[i]);
|
||||
news[n] = 0;
|
||||
str = js_NewString(cx, news, n, 0);
|
||||
str = js_NewString(cx, news, n);
|
||||
if (!str) {
|
||||
JS_free(cx, news);
|
||||
return JS_FALSE;
|
||||
@ -786,15 +782,14 @@ str_toUpperCase(JSContext *cx, uintN argc, jsval *vp)
|
||||
return JS_FALSE;
|
||||
vp[1] = STRING_TO_JSVAL(str);
|
||||
|
||||
n = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, s, n);
|
||||
news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
|
||||
if (!news)
|
||||
return JS_FALSE;
|
||||
s = JSSTRING_CHARS(str);
|
||||
for (i = 0; i < n; i++)
|
||||
news[i] = JS_TOUPPER(s[i]);
|
||||
news[n] = 0;
|
||||
str = js_NewString(cx, news, n, 0);
|
||||
str = js_NewString(cx, news, n);
|
||||
if (!str) {
|
||||
JS_free(cx, news);
|
||||
return JS_FALSE;
|
||||
@ -1673,7 +1668,7 @@ str_replace(JSContext *cx, uintN argc, jsval *vp)
|
||||
rightlen);
|
||||
chars[length] = 0;
|
||||
|
||||
str = js_NewString(cx, chars, length, 0);
|
||||
str = js_NewString(cx, chars, length);
|
||||
if (!str) {
|
||||
JS_free(cx, chars);
|
||||
ok = JS_FALSE;
|
||||
@ -1844,8 +1839,7 @@ str_split(JSContext *cx, uintN argc, jsval *vp)
|
||||
* Point sep at a local copy of str2's header because find_split
|
||||
* will modify sep->length.
|
||||
*/
|
||||
tmp.length = JSSTRING_LENGTH(str2);
|
||||
tmp.chars = JSSTRING_CHARS(str2);
|
||||
JSSTRING_CHARS_AND_LENGTH(str2, tmp.chars, tmp.length);
|
||||
sep = &tmp;
|
||||
re = NULL;
|
||||
}
|
||||
@ -2134,7 +2128,7 @@ tagify(JSContext *cx, const char *begin, JSString *param, const char *end,
|
||||
JS_ASSERT(j == taglen);
|
||||
tagbuf[j] = 0;
|
||||
|
||||
str = js_NewString(cx, tagbuf, taglen, 0);
|
||||
str = js_NewString(cx, tagbuf, taglen);
|
||||
if (!str) {
|
||||
free((char *)tagbuf);
|
||||
return JS_FALSE;
|
||||
@ -2334,7 +2328,7 @@ str_fromCharCode(JSContext *cx, uintN argc, jsval *vp)
|
||||
chars[i] = (jschar)code;
|
||||
}
|
||||
chars[i] = 0;
|
||||
str = js_NewString(cx, chars, argc, 0);
|
||||
str = js_NewString(cx, chars, argc);
|
||||
if (!str) {
|
||||
JS_free(cx, chars);
|
||||
return JS_FALSE;
|
||||
@ -2409,8 +2403,8 @@ js_GetUnitString(JSContext *cx, jschar c)
|
||||
}
|
||||
if (!rt->unitStrings[c]) {
|
||||
cp = UNIT_STRING_SPACE_RT(rt);
|
||||
str = js_NewString(cx, cp + 2 * c, 1, GCF_LOCK);
|
||||
if (!str)
|
||||
str = js_NewString(cx, cp + 2 * c, 1);
|
||||
if (!str || !js_LockGCThing(cx, str))
|
||||
return NULL;
|
||||
JS_LOCK_GC(rt);
|
||||
if (!rt->unitStrings[c]) {
|
||||
@ -2479,7 +2473,7 @@ js_InitStringClass(JSContext *cx, JSObject *obj)
|
||||
}
|
||||
|
||||
JSString *
|
||||
js_NewString(JSContext *cx, jschar *chars, size_t length, uintN gcflag)
|
||||
js_NewString(JSContext *cx, jschar *chars, size_t length)
|
||||
{
|
||||
JSString *str;
|
||||
|
||||
@ -2488,11 +2482,10 @@ js_NewString(JSContext *cx, jschar *chars, size_t length, uintN gcflag)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
str = (JSString *) js_NewGCThing(cx, gcflag | GCX_STRING, sizeof(JSString));
|
||||
str = (JSString *) js_NewGCThing(cx, GCX_STRING, sizeof(JSString));
|
||||
if (!str)
|
||||
return NULL;
|
||||
str->length = length;
|
||||
str->chars = chars;
|
||||
JSSTRING_INIT(str, chars, length);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
@ -2510,7 +2503,7 @@ JSString *
|
||||
js_NewDependentString(JSContext *cx, JSString *base, size_t start,
|
||||
size_t length)
|
||||
{
|
||||
JSDependentString *ds;
|
||||
JSString *ds;
|
||||
|
||||
if (length == 0)
|
||||
return cx->runtime->emptyString;
|
||||
@ -2523,17 +2516,13 @@ js_NewDependentString(JSContext *cx, JSString *base, size_t start,
|
||||
return js_NewStringCopyN(cx, JSSTRING_CHARS(base) + start, length);
|
||||
}
|
||||
|
||||
ds = (JSDependentString *)
|
||||
js_NewGCThing(cx, GCX_MUTABLE_STRING, sizeof(JSString));
|
||||
ds = (JSString *)js_NewGCThing(cx, GCX_STRING, sizeof(JSString));
|
||||
if (!ds)
|
||||
return NULL;
|
||||
if (start == 0) {
|
||||
JSPREFIX_SET_LENGTH(ds, length);
|
||||
JSPREFIX_SET_BASE(ds, base);
|
||||
} else {
|
||||
JSSTRDEP_SET_START_AND_LENGTH(ds, start, length);
|
||||
JSSTRDEP_SET_BASE(ds, base);
|
||||
}
|
||||
if (start == 0)
|
||||
JSPREFIX_INIT(ds, base, length);
|
||||
else
|
||||
JSSTRDEP_INIT(ds, base, start, length);
|
||||
#ifdef DEBUG
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
@ -2549,7 +2538,7 @@ js_NewDependentString(JSContext *cx, JSString *base, size_t start,
|
||||
rt->lengthSquaredSum += (double)length * (double)length));
|
||||
}
|
||||
#endif
|
||||
return (JSString *)ds;
|
||||
return ds;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -2602,7 +2591,7 @@ js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n)
|
||||
return NULL;
|
||||
js_strncpy(news, s, n);
|
||||
news[n] = 0;
|
||||
str = js_NewString(cx, news, n, 0);
|
||||
str = js_NewString(cx, news, n);
|
||||
if (!str)
|
||||
JS_free(cx, news);
|
||||
return str;
|
||||
@ -2621,7 +2610,7 @@ js_NewStringCopyZ(JSContext *cx, const jschar *s)
|
||||
if (!news)
|
||||
return NULL;
|
||||
memcpy(news, s, m);
|
||||
str = js_NewString(cx, news, n, 0);
|
||||
str = js_NewString(cx, news, n);
|
||||
if (!str)
|
||||
JS_free(cx, news);
|
||||
return str;
|
||||
@ -2675,15 +2664,15 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str)
|
||||
valid = JS_TRUE;
|
||||
} else {
|
||||
/* A stillborn string has null chars, so is not valid. */
|
||||
valid = (str->chars != NULL);
|
||||
if (valid && !IN_UNIT_STRING_SPACE_RT(rt, str->chars))
|
||||
free(str->chars);
|
||||
valid = (str->u.chars != NULL);
|
||||
if (valid && !IN_UNIT_STRING_SPACE_RT(rt, str->u.chars))
|
||||
free(str->u.chars);
|
||||
}
|
||||
if (valid) {
|
||||
if (valid)
|
||||
js_PurgeDeflatedStringCache(rt, str);
|
||||
str->chars = NULL;
|
||||
}
|
||||
str->length = 0;
|
||||
#ifdef DEBUG
|
||||
memset(str, JS_FREE_PATTERN, sizeof *str);
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_FRIEND_API(const char *)
|
||||
@ -2766,12 +2755,12 @@ js_ValueToSource(JSContext *cx, jsval v)
|
||||
uint32
|
||||
js_HashString(JSString *str)
|
||||
{
|
||||
uint32 h;
|
||||
const jschar *s;
|
||||
size_t n;
|
||||
uint32 h;
|
||||
|
||||
h = 0;
|
||||
for (s = JSSTRING_CHARS(str), n = JSSTRING_LENGTH(str); n; s++, n--)
|
||||
JSSTRING_CHARS_AND_LENGTH(str, s, n);
|
||||
for (h = 0; n; s++, n--)
|
||||
h = (h >> (JS_HASH_BITS - 4)) ^ (h << 4) ^ *s;
|
||||
return h;
|
||||
}
|
||||
@ -2823,8 +2812,8 @@ js_CompareStrings(JSString *str1, JSString *str2)
|
||||
if (str1 == str2)
|
||||
return 0;
|
||||
|
||||
l1 = JSSTRING_LENGTH(str1), l2 = JSSTRING_LENGTH(str2);
|
||||
s1 = JSSTRING_CHARS(str1), s2 = JSSTRING_CHARS(str2);
|
||||
JSSTRING_CHARS_AND_LENGTH(str1, s1, l1);
|
||||
JSSTRING_CHARS_AND_LENGTH(str2, s2, l2);
|
||||
n = JS_MIN(l1, l2);
|
||||
for (i = 0; i < n; i++) {
|
||||
cmp = s1[i] - s2[i];
|
||||
@ -4608,27 +4597,55 @@ const jschar js_uriUnescaped_ucstr[] =
|
||||
|
||||
#define URI_CHUNK 64U
|
||||
|
||||
/* Concatenate jschars onto an unshared/newborn JSString. */
|
||||
/* Concatenate jschars onto the buffer */
|
||||
static JSBool
|
||||
AddCharsToURI(JSContext *cx, JSString *str, const jschar *chars, size_t length)
|
||||
AddCharsToURI(JSContext *cx, JSCharBuffer *buf,
|
||||
const jschar *chars, size_t length)
|
||||
{
|
||||
size_t total;
|
||||
jschar *newchars;
|
||||
|
||||
JS_ASSERT(!JSSTRING_IS_DEPENDENT(str));
|
||||
total = str->length + length + 1;
|
||||
if (!str->chars ||
|
||||
JS_HOWMANY(total, URI_CHUNK) > JS_HOWMANY(str->length + 1, URI_CHUNK)) {
|
||||
total = buf->length + length + 1;
|
||||
if (!buf->chars ||
|
||||
JS_HOWMANY(total, URI_CHUNK) > JS_HOWMANY(buf->length + 1, URI_CHUNK)) {
|
||||
total = JS_ROUNDUP(total, URI_CHUNK);
|
||||
newchars = (jschar *) JS_realloc(cx, str->chars,
|
||||
newchars = (jschar *) JS_realloc(cx, buf->chars,
|
||||
total * sizeof(jschar));
|
||||
if (!newchars)
|
||||
return JS_FALSE;
|
||||
str->chars = newchars;
|
||||
buf->chars = newchars;
|
||||
}
|
||||
js_strncpy(str->chars + str->length, chars, length);
|
||||
str->length += length;
|
||||
str->chars[str->length] = 0;
|
||||
js_strncpy(buf->chars + buf->length, chars, length);
|
||||
buf->length += length;
|
||||
buf->chars[buf->length] = 0;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
TransferBufferToString(JSContext *cx, JSCharBuffer *cb, jsval *rval)
|
||||
{
|
||||
jschar *chars;
|
||||
size_t n;
|
||||
JSString *str;
|
||||
|
||||
/*
|
||||
* Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
|
||||
* don't worry about that case here.
|
||||
*/
|
||||
n = cb->length;
|
||||
chars = (jschar *) JS_realloc(cx, cb->chars, (n + 1) * sizeof(jschar));
|
||||
if (!chars)
|
||||
chars = cb->chars;
|
||||
str = js_NewString(cx, chars, n);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Successful allocation transfer ownership of cb->chars to the string. */
|
||||
#ifdef DEBUG
|
||||
memset(cb, JS_FREE_PATTERN, sizeof *cb);
|
||||
#endif
|
||||
|
||||
*rval = STRING_TO_JSVAL(str);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@ -4644,37 +4661,36 @@ Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
|
||||
const jschar *unescapedSet2, jsval *rval)
|
||||
{
|
||||
size_t length, j, k, L;
|
||||
JSCharBuffer cb;
|
||||
jschar *chars, c, c2;
|
||||
uint32 v;
|
||||
uint8 utf8buf[6];
|
||||
jschar hexBuf[4];
|
||||
static const char HexDigits[] = "0123456789ABCDEF"; /* NB: uppercase */
|
||||
JSString *R;
|
||||
|
||||
length = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, chars, length);
|
||||
if (length == 0) {
|
||||
*rval = STRING_TO_JSVAL(cx->runtime->emptyString);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
R = js_NewString(cx, NULL, 0, 0);
|
||||
if (!R)
|
||||
return JS_FALSE;
|
||||
cb.length = 0;
|
||||
cb.chars = NULL;
|
||||
|
||||
/* From this point the control must goto bad on failures. */
|
||||
hexBuf[0] = '%';
|
||||
hexBuf[3] = 0;
|
||||
chars = JSSTRING_CHARS(str);
|
||||
for (k = 0; k < length; k++) {
|
||||
c = chars[k];
|
||||
if (js_strchr(unescapedSet, c) ||
|
||||
(unescapedSet2 && js_strchr(unescapedSet2, c))) {
|
||||
if (!AddCharsToURI(cx, R, &c, 1))
|
||||
return JS_FALSE;
|
||||
if (!AddCharsToURI(cx, &cb, &c, 1))
|
||||
goto bad;
|
||||
} else {
|
||||
if ((c >= 0xDC00) && (c <= 0xDFFF)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_URI, NULL);
|
||||
return JS_FALSE;
|
||||
goto bad;
|
||||
}
|
||||
if (c < 0xD800 || c > 0xDBFF) {
|
||||
v = c;
|
||||
@ -4683,13 +4699,13 @@ Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
|
||||
if (k == length) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_URI, NULL);
|
||||
return JS_FALSE;
|
||||
goto bad;
|
||||
}
|
||||
c2 = chars[k];
|
||||
if ((c2 < 0xDC00) || (c2 > 0xDFFF)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_URI, NULL);
|
||||
return JS_FALSE;
|
||||
goto bad;
|
||||
}
|
||||
v = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
|
||||
}
|
||||
@ -4697,54 +4713,51 @@ Encode(JSContext *cx, JSString *str, const jschar *unescapedSet,
|
||||
for (j = 0; j < L; j++) {
|
||||
hexBuf[1] = HexDigits[utf8buf[j] >> 4];
|
||||
hexBuf[2] = HexDigits[utf8buf[j] & 0xf];
|
||||
if (!AddCharsToURI(cx, R, hexBuf, 3))
|
||||
return JS_FALSE;
|
||||
if (!AddCharsToURI(cx, &cb, hexBuf, 3))
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
|
||||
* don't worry about that case here. Worst case, R hangs onto URI_CHUNK-1
|
||||
* more jschars than it needs.
|
||||
*/
|
||||
chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
|
||||
if (chars)
|
||||
R->chars = chars;
|
||||
*rval = STRING_TO_JSVAL(R);
|
||||
if (!TransferBufferToString(cx, &cb, rval))
|
||||
goto bad;
|
||||
|
||||
return JS_TRUE;
|
||||
|
||||
bad:
|
||||
JS_free(cx, cb.chars);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
|
||||
{
|
||||
size_t length, start, k;
|
||||
JSCharBuffer cb;
|
||||
jschar *chars, c, H;
|
||||
uint32 v;
|
||||
jsuint B;
|
||||
uint8 octets[6];
|
||||
JSString *R;
|
||||
intN j, n;
|
||||
|
||||
length = JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, chars, length);
|
||||
if (length == 0) {
|
||||
*rval = STRING_TO_JSVAL(cx->runtime->emptyString);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
R = js_NewString(cx, NULL, 0, 0);
|
||||
if (!R)
|
||||
return JS_FALSE;
|
||||
cb.length = 0;
|
||||
cb.chars = NULL;
|
||||
|
||||
chars = JSSTRING_CHARS(str);
|
||||
/* From this point the control must goto bad on failures. */
|
||||
for (k = 0; k < length; k++) {
|
||||
c = chars[k];
|
||||
if (c == '%') {
|
||||
start = k;
|
||||
if ((k + 2) >= length)
|
||||
goto bad;
|
||||
goto report_bad_uri;
|
||||
if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
|
||||
goto bad;
|
||||
goto report_bad_uri;
|
||||
B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
|
||||
k += 2;
|
||||
if (!(B & 0x80)) {
|
||||
@ -4754,19 +4767,19 @@ Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
|
||||
while (B & (0x80 >> n))
|
||||
n++;
|
||||
if (n == 1 || n > 6)
|
||||
goto bad;
|
||||
goto report_bad_uri;
|
||||
octets[0] = (uint8)B;
|
||||
if (k + 3 * (n - 1) >= length)
|
||||
goto bad;
|
||||
goto report_bad_uri;
|
||||
for (j = 1; j < n; j++) {
|
||||
k++;
|
||||
if (chars[k] != '%')
|
||||
goto bad;
|
||||
goto report_bad_uri;
|
||||
if (!JS7_ISHEX(chars[k+1]) || !JS7_ISHEX(chars[k+2]))
|
||||
goto bad;
|
||||
goto report_bad_uri;
|
||||
B = JS7_UNHEX(chars[k+1]) * 16 + JS7_UNHEX(chars[k+2]);
|
||||
if ((B & 0xC0) != 0x80)
|
||||
goto bad;
|
||||
goto report_bad_uri;
|
||||
k += 2;
|
||||
octets[j] = (char)B;
|
||||
}
|
||||
@ -4774,41 +4787,39 @@ Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval)
|
||||
if (v >= 0x10000) {
|
||||
v -= 0x10000;
|
||||
if (v > 0xFFFFF)
|
||||
goto bad;
|
||||
goto report_bad_uri;
|
||||
c = (jschar)((v & 0x3FF) + 0xDC00);
|
||||
H = (jschar)((v >> 10) + 0xD800);
|
||||
if (!AddCharsToURI(cx, R, &H, 1))
|
||||
return JS_FALSE;
|
||||
if (!AddCharsToURI(cx, &cb, &H, 1))
|
||||
goto bad;
|
||||
} else {
|
||||
c = (jschar)v;
|
||||
}
|
||||
}
|
||||
if (js_strchr(reservedSet, c)) {
|
||||
if (!AddCharsToURI(cx, R, &chars[start], (k - start + 1)))
|
||||
return JS_FALSE;
|
||||
if (!AddCharsToURI(cx, &cb, &chars[start], (k - start + 1)))
|
||||
goto bad;
|
||||
} else {
|
||||
if (!AddCharsToURI(cx, R, &c, 1))
|
||||
return JS_FALSE;
|
||||
if (!AddCharsToURI(cx, &cb, &c, 1))
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
if (!AddCharsToURI(cx, R, &c, 1))
|
||||
if (!AddCharsToURI(cx, &cb, &c, 1))
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Shrinking realloc can fail (e.g., with a BSD-style allocator), but we
|
||||
* don't worry about that case here. Worst case, R hangs onto URI_CHUNK-1
|
||||
* more jschars than it needs.
|
||||
*/
|
||||
chars = (jschar *) JS_realloc(cx, R->chars, (R->length+1) * sizeof(jschar));
|
||||
if (chars)
|
||||
R->chars = chars;
|
||||
*rval = STRING_TO_JSVAL(R);
|
||||
if (!TransferBufferToString(cx, &cb, rval))
|
||||
goto bad;
|
||||
|
||||
return JS_TRUE;
|
||||
|
||||
bad:
|
||||
report_bad_uri:
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_URI);
|
||||
/* FALL THROUGH */
|
||||
|
||||
bad:
|
||||
JS_free(cx, cb.chars);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
@ -4949,8 +4960,7 @@ js_PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp,
|
||||
JS_ASSERT_IF(!buffer, bufferSize == 0);
|
||||
JS_ASSERT_IF(fp, !buffer);
|
||||
|
||||
chars = JSSTRING_CHARS(str);
|
||||
charsEnd = chars + JSSTRING_LENGTH(str);
|
||||
JSSTRING_CHARS_AND_END(str, chars, charsEnd);
|
||||
n = 0;
|
||||
--bufferSize;
|
||||
state = FIRST_QUOTE;
|
||||
|
140
js/src/jsstr.h
140
js/src/jsstr.h
@ -55,90 +55,140 @@
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* The original GC-thing "string" type, a flat character string owned by its
|
||||
* GC-thing descriptor. The chars member points to a vector having byte size
|
||||
* (length + 1) * sizeof(jschar), terminated at index length by a zero jschar.
|
||||
* The terminator is purely a backstop, in case the chars pointer flows out to
|
||||
* native code that requires \u0000 termination.
|
||||
* The GC-thing "string" type.
|
||||
*
|
||||
* NB: Always use the JSSTRING_LENGTH and JSSTRING_CHARS accessor macros,
|
||||
* unless you guard str->member uses with !JSSTRING_IS_DEPENDENT(str).
|
||||
* When the JSSTRFLAG_DEPENDENT bit of the length field is unset, the u.chars
|
||||
* field points to a flat character array owned by its GC-thing descriptor.
|
||||
* The array is terminated at index length by a zero character and the size of
|
||||
* the array in bytes is (length + 1) * sizeof(jschar). The terminator is
|
||||
* purely a backstop, in case the chars pointer flows out to native code that
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* JSSTRDEP_START_MASK and JSSTRDEP_LENGTH_MASK macros below for details.
|
||||
*
|
||||
* When JSSTRFLAG_PREFIX is set, the dependent string is a prefix of the base
|
||||
* string. The number of characters in the prefix is encoded using all
|
||||
* non-flag bits of the length field and spans the same 0 .. SIZE_T_MAX/4
|
||||
* range as the length of the flat string.
|
||||
*
|
||||
* NB: Always use the JSSTRING_LENGTH and JSSTRING_CHARS accessor macros.
|
||||
*/
|
||||
struct JSString {
|
||||
size_t length;
|
||||
jschar *chars;
|
||||
union {
|
||||
jschar *chars;
|
||||
JSString *base;
|
||||
} u;
|
||||
};
|
||||
|
||||
/*
|
||||
* Overlay structure for a string that depends on another string's characters.
|
||||
* Distinguished by the JSSTRFLAG_DEPENDENT bit being set in length. The base
|
||||
* member may point to another dependent string if JSSTRING_CHARS has not been
|
||||
* called yet. The length chars in a dependent string are stored starting at
|
||||
* base->chars + start, and are not necessarily zero-terminated. If start is
|
||||
* 0, it is not stored, length is a full size_t (minus the JSSTRFLAG_* bits in
|
||||
* the high two positions), and the JSSTRFLAG_PREFIX flag is set.
|
||||
* 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.
|
||||
*/
|
||||
struct JSDependentString {
|
||||
size_t length;
|
||||
JSString *base;
|
||||
};
|
||||
|
||||
/* Definitions for flags stored in the high order bits of JSString.length. */
|
||||
#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_PREFIX(str) JSSTRING_HAS_FLAG(str, JSSTRFLAG_PREFIX)
|
||||
#define JSSTRING_IS_MUTABLE(str) (((str)->length & JSSTRFLAG_MASK) == \
|
||||
JSSTRFLAG_MUTABLE)
|
||||
|
||||
#define JSSTRING_CHARS(str) (JSSTRING_IS_DEPENDENT(str) \
|
||||
? JSSTRDEP_CHARS(str) \
|
||||
: (str)->chars)
|
||||
: (str)->u.chars)
|
||||
#define JSSTRING_LENGTH(str) (JSSTRING_IS_DEPENDENT(str) \
|
||||
? JSSTRDEP_LENGTH(str) \
|
||||
: (str)->length)
|
||||
: ((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_) = (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)) \
|
||||
: ((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)
|
||||
|
||||
/* Specific JSDependentString shift/mask accessor and mutator macros. */
|
||||
#define JSSTRING_INIT(str, chars_, length_) \
|
||||
((void)(JS_ASSERT(((length_) & JSSTRFLAG_MASK) == 0), \
|
||||
(str)->length = (length_), (str)->u.chars = (chars_)))
|
||||
|
||||
/* 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)), \
|
||||
(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)
|
||||
|
||||
#define JSSTRDEP(str) ((JSDependentString *)(str))
|
||||
#define JSSTRDEP_START(str) (JSSTRING_IS_PREFIX(str) ? 0 \
|
||||
: ((JSSTRDEP(str)->length \
|
||||
#define JSSTRDEP_IS_PREFIX(str) JSSTRING_HAS_FLAG(str, JSSTRFLAG_PREFIX)
|
||||
|
||||
#define JSSTRDEP_START(str) (JSSTRDEP_IS_PREFIX(str) ? 0 \
|
||||
: (((str)->length \
|
||||
>> JSSTRDEP_START_SHIFT) \
|
||||
& JSSTRDEP_START_MASK))
|
||||
#define JSSTRDEP_LENGTH(str) (JSSTRDEP(str)->length \
|
||||
& (JSSTRING_IS_PREFIX(str) \
|
||||
#define JSSTRDEP_LENGTH(str) ((str)->length \
|
||||
& (JSSTRDEP_IS_PREFIX(str) \
|
||||
? JSSTRING_LENGTH_MASK \
|
||||
: JSSTRDEP_LENGTH_MASK))
|
||||
|
||||
#define JSSTRDEP_SET_START_AND_LENGTH(str,off,len) \
|
||||
(JSSTRDEP(str)->length = JSSTRFLAG_DEPENDENT \
|
||||
| ((off) << JSSTRDEP_START_SHIFT) \
|
||||
| (len))
|
||||
#define JSPREFIX_SET_LENGTH(str,len) \
|
||||
(JSSTRDEP(str)->length = JSSTRFLAG_DEPENDENT | JSSTRFLAG_PREFIX | (len))
|
||||
#define JSSTRDEP_INIT(str,bstr,off,len) \
|
||||
((str)->length = JSSTRFLAG_DEPENDENT \
|
||||
| ((off) << JSSTRDEP_START_SHIFT) \
|
||||
| (len), \
|
||||
(str)->u.base = (bstr))
|
||||
|
||||
#define JSSTRDEP_BASE(str) (JSSTRDEP(str)->base)
|
||||
#define JSSTRDEP_SET_BASE(str,bstr) (JSSTRDEP(str)->base = (bstr))
|
||||
#define JSPREFIX_INIT(str,bstr,len) \
|
||||
((str)->length = JSSTRFLAG_DEPENDENT | JSSTRFLAG_PREFIX | (len), \
|
||||
(str)->u.base = (bstr))
|
||||
|
||||
#define JSSTRDEP_BASE(str) ((str)->u.base)
|
||||
#define JSPREFIX_BASE(str) JSSTRDEP_BASE(str)
|
||||
#define JSPREFIX_SET_BASE(str,bstr) JSSTRDEP_SET_BASE(str,bstr)
|
||||
#define JSPREFIX_SET_BASE(str,bstr) ((str)->u.base = (bstr))
|
||||
|
||||
#define JSSTRDEP_CHARS(str) \
|
||||
(JSSTRING_IS_DEPENDENT(JSSTRDEP_BASE(str)) \
|
||||
? js_GetDependentStringChars(str) \
|
||||
: JSSTRDEP_BASE(str)->chars + JSSTRDEP_START(str))
|
||||
: JSSTRDEP_BASE(str)->u.chars + JSSTRDEP_START(str))
|
||||
|
||||
extern size_t
|
||||
js_MinimizeDependentStrings(JSString *str, int level, JSString **basep);
|
||||
@ -155,6 +205,14 @@ js_ConcatStrings(JSContext *cx, JSString *left, JSString *right);
|
||||
extern const jschar *
|
||||
js_UndependString(JSContext *cx, JSString *str);
|
||||
|
||||
extern JSBool
|
||||
js_MakeStringImmutable(JSContext *cx, JSString *str);
|
||||
|
||||
typedef struct JSCharBuffer {
|
||||
size_t length;
|
||||
jschar *chars;
|
||||
} JSCharBuffer;
|
||||
|
||||
struct JSSubString {
|
||||
size_t length;
|
||||
const jschar *chars;
|
||||
@ -334,7 +392,7 @@ extern const char js_encodeURIComponent_str[];
|
||||
|
||||
/* GC-allocate a string descriptor for the given malloc-allocated chars. */
|
||||
extern JSString *
|
||||
js_NewString(JSContext *cx, jschar *chars, size_t length, uintN gcflag);
|
||||
js_NewString(JSContext *cx, jschar *chars, size_t length);
|
||||
|
||||
extern JSString *
|
||||
js_NewDependentString(JSContext *cx, JSString *base, size_t start,
|
||||
|
@ -534,7 +534,7 @@ qname_toString(JSContext *cx, uintN argc, jsval *vp)
|
||||
*chars = '@';
|
||||
js_strncpy(chars + 1, JSSTRING_CHARS(str), length);
|
||||
chars[++length] = 0;
|
||||
str = js_NewString(cx, chars, length, 0);
|
||||
str = js_NewString(cx, chars, length);
|
||||
if (!str) {
|
||||
JS_free(cx, chars);
|
||||
return JS_FALSE;
|
||||
@ -1402,8 +1402,7 @@ ParseNodeToQName(JSContext *cx, JSParseNode *pn, JSXMLArray *inScopeNSes,
|
||||
|
||||
JS_ASSERT(pn->pn_arity == PN_NULLARY);
|
||||
str = ATOM_TO_STRING(pn->pn_atom);
|
||||
length = JSSTRING_LENGTH(str);
|
||||
start = JSSTRING_CHARS(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, start, length);
|
||||
JS_ASSERT(length != 0 && *start != '@');
|
||||
JS_ASSERT(length != 1 || *start != '*');
|
||||
|
||||
@ -1489,8 +1488,8 @@ ChompXMLWhitespace(JSContext *cx, JSString *str)
|
||||
const jschar *cp, *start, *end;
|
||||
jschar c;
|
||||
|
||||
length = JSSTRING_LENGTH(str);
|
||||
for (cp = start = JSSTRING_CHARS(str), end = cp + length; cp < end; cp++) {
|
||||
JSSTRING_CHARS_AND_LENGTH(str, start, length);
|
||||
for (cp = start, end = cp + length; cp < end; cp++) {
|
||||
c = *cp;
|
||||
if (!JS_ISXMLSPACE(c))
|
||||
break;
|
||||
@ -1676,8 +1675,7 @@ ParseNodeToXML(JSContext *cx, JSParseNode *pn, JSXMLArray *inScopeNSes,
|
||||
if (pn2->pn_type != TOK_XMLATTR)
|
||||
goto syntax;
|
||||
|
||||
length = JSSTRING_LENGTH(str);
|
||||
chars = JSSTRING_CHARS(str);
|
||||
JSSTRING_CHARS_AND_LENGTH(str, chars, length);
|
||||
if (length >= 5 &&
|
||||
IS_XMLNS_CHARS(chars) &&
|
||||
(length == 5 || chars[5] == ':')) {
|
||||
@ -2289,7 +2287,7 @@ MakeXMLSpecialString(JSContext *cx, JSStringBuffer *sb,
|
||||
js_strncpy(bp, suffix, suffixlength);
|
||||
bp[suffixlength] = 0;
|
||||
|
||||
str = js_NewString(cx, base, newlength, 0);
|
||||
str = js_NewString(cx, base, newlength);
|
||||
if (!str)
|
||||
free(base);
|
||||
return str;
|
||||
@ -2364,8 +2362,9 @@ EscapeElementValue(JSContext *cx, JSStringBuffer *sb, JSString *str)
|
||||
const jschar *cp, *start, *end;
|
||||
jschar c;
|
||||
|
||||
length = newlength = JSSTRING_LENGTH(str);
|
||||
for (cp = start = JSSTRING_CHARS(str), end = cp + length; cp < end; cp++) {
|
||||
JSSTRING_CHARS_AND_LENGTH(str, start, length);
|
||||
newlength = length;
|
||||
for (cp = start, end = cp + length; cp < end; cp++) {
|
||||
c = *cp;
|
||||
if (c == '<' || c == '>')
|
||||
newlength += 3;
|
||||
@ -2399,7 +2398,7 @@ EscapeElementValue(JSContext *cx, JSStringBuffer *sb, JSString *str)
|
||||
js_AppendChar(sb, c);
|
||||
}
|
||||
JS_ASSERT(STRING_BUFFER_OK(sb));
|
||||
str = js_NewString(cx, sb->base, STRING_BUFFER_OFFSET(sb), 0);
|
||||
str = js_NewString(cx, sb->base, STRING_BUFFER_OFFSET(sb));
|
||||
if (!str)
|
||||
js_FinishStringBuffer(sb);
|
||||
}
|
||||
@ -2417,8 +2416,9 @@ EscapeAttributeValue(JSContext *cx, JSStringBuffer *sb, JSString *str)
|
||||
const jschar *cp, *start, *end;
|
||||
jschar c;
|
||||
|
||||
length = newlength = JSSTRING_LENGTH(str);
|
||||
for (cp = start = JSSTRING_CHARS(str), end = cp + length; cp < end; cp++) {
|
||||
JSSTRING_CHARS_AND_LENGTH(str, start, length);
|
||||
newlength = length;
|
||||
for (cp = start, end = cp + length; cp < end; cp++) {
|
||||
c = *cp;
|
||||
if (c == '"')
|
||||
newlength += 5;
|
||||
@ -2460,7 +2460,7 @@ EscapeAttributeValue(JSContext *cx, JSStringBuffer *sb, JSString *str)
|
||||
js_AppendChar(sb, c);
|
||||
}
|
||||
JS_ASSERT(STRING_BUFFER_OK(sb));
|
||||
str = js_NewString(cx, sb->base, STRING_BUFFER_OFFSET(sb), 0);
|
||||
str = js_NewString(cx, sb->base, STRING_BUFFER_OFFSET(sb));
|
||||
if (!str)
|
||||
js_FinishStringBuffer(sb);
|
||||
}
|
||||
@ -2579,8 +2579,8 @@ GeneratePrefix(JSContext *cx, JSString *uri, JSXMLArray *decls)
|
||||
* ".../there.is.only.xul", "xbl" given ".../xbl", and "xbl2" given any
|
||||
* likely URI of the form ".../xbl2/2005".
|
||||
*/
|
||||
start = JSSTRING_CHARS(uri);
|
||||
cp = end = start + JSSTRING_LENGTH(uri);
|
||||
JSSTRING_CHARS_AND_END(uri, start, end);
|
||||
cp = end;
|
||||
while (--cp > start) {
|
||||
if (*cp == '.' || *cp == '/' || *cp == ':') {
|
||||
++cp;
|
||||
@ -2654,7 +2654,7 @@ GeneratePrefix(JSContext *cx, JSString *uri, JSXMLArray *decls)
|
||||
offset = PTRDIFF(cp, start, jschar);
|
||||
prefix = js_NewDependentString(cx, uri, offset, length);
|
||||
} else {
|
||||
prefix = js_NewString(cx, bp, newlength, 0);
|
||||
prefix = js_NewString(cx, bp, newlength);
|
||||
if (!prefix)
|
||||
JS_free(cx, bp);
|
||||
}
|
||||
@ -2752,7 +2752,7 @@ XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
str = js_NewString(cx, sb.base, STRING_BUFFER_OFFSET(&sb), 0);
|
||||
str = js_NewString(cx, sb.base, STRING_BUFFER_OFFSET(&sb));
|
||||
list_out:
|
||||
if (!str && STRING_BUFFER_OK(&sb))
|
||||
js_FinishStringBuffer(&sb);
|
||||
@ -3025,7 +3025,7 @@ XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes,
|
||||
goto out;
|
||||
}
|
||||
|
||||
str = js_NewString(cx, sb.base, STRING_BUFFER_OFFSET(&sb), 0);
|
||||
str = js_NewString(cx, sb.base, STRING_BUFFER_OFFSET(&sb));
|
||||
out:
|
||||
js_LeaveLocalRootScopeWithResult(cx, STRING_TO_JSVAL(str));
|
||||
if (!str && STRING_BUFFER_OK(&sb))
|
||||
@ -7875,39 +7875,38 @@ JSString *
|
||||
js_AddAttributePart(JSContext *cx, JSBool isName, JSString *str, JSString *str2)
|
||||
{
|
||||
size_t len, len2, newlen;
|
||||
jschar *chars;
|
||||
jschar *chars, *chars2;
|
||||
|
||||
if (JSSTRING_IS_DEPENDENT(str) ||
|
||||
!(*js_GetGCThingFlags(str) & GCF_MUTABLE)) {
|
||||
str = js_NewStringCopyN(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
|
||||
JSSTRING_CHARS_AND_LENGTH(str, chars, len);
|
||||
if (!JSSTRING_IS_MUTABLE(str)) {
|
||||
str = js_NewStringCopyN(cx, chars, len);
|
||||
if (!str)
|
||||
return NULL;
|
||||
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);
|
||||
}
|
||||
|
||||
len = str->length;
|
||||
len2 = JSSTRING_LENGTH(str2);
|
||||
JSSTRING_CHARS_AND_LENGTH(str2, chars2, len2);
|
||||
newlen = (isName) ? len + 1 + len2 : len + 2 + len2 + 1;
|
||||
chars = (jschar *) JS_realloc(cx, str->chars, (newlen+1) * sizeof(jschar));
|
||||
chars = (jschar *) JS_realloc(cx, chars, (newlen+1) * sizeof(jschar));
|
||||
if (!chars)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Reallocating str (because we know it has no other references) requires
|
||||
* purging any deflated string cached for it.
|
||||
*/
|
||||
js_PurgeDeflatedStringCache(cx->runtime, str);
|
||||
|
||||
str->chars = chars;
|
||||
str->length = newlen;
|
||||
JSSTRING_INIT(str, chars, newlen);
|
||||
chars += len;
|
||||
if (isName) {
|
||||
*chars++ = ' ';
|
||||
js_strncpy(chars, JSSTRING_CHARS(str2), len2);
|
||||
js_strncpy(chars, chars2, len2);
|
||||
chars += len2;
|
||||
} else {
|
||||
*chars++ = '=';
|
||||
*chars++ = '"';
|
||||
js_strncpy(chars, JSSTRING_CHARS(str2), len2);
|
||||
js_strncpy(chars, chars2, len2);
|
||||
chars += len2;
|
||||
*chars++ = '"';
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user