Bug 613457 - clean up string interfaces (r=njn)

--HG--
extra : rebase_source : 3e77b67fa9fe2cc31312ad99951cf92258a98e64
This commit is contained in:
Luke Wagner 2011-03-14 13:59:53 -07:00
parent 7b695c0de6
commit 7c96945e3c
60 changed files with 1546 additions and 1428 deletions

View File

@ -50,9 +50,6 @@
#include "nsServiceManagerUtils.h" #include "nsServiceManagerUtils.h"
#include "nsDOMError.h" #include "nsDOMError.h"
#include "nsGlobalWindow.h" #include "nsGlobalWindow.h"
#include "jsobj.h"
#include "jsatom.h"
#include "jsfun.h"
#include "nsIContentSecurityPolicy.h" #include "nsIContentSecurityPolicy.h"
static const char kSetIntervalStr[] = "setInterval"; static const char kSetIntervalStr[] = "setInterval";
@ -134,10 +131,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler)
else if (tmp->mFunObj) { else if (tmp->mFunObj) {
JSFunction* fun = (JSFunction*)tmp->mFunObj->getPrivate(); JSFunction* fun = (JSFunction*)tmp->mFunObj->getPrivate();
if (fun->atom) { if (fun->atom) {
size_t size = 1 + JS_PutEscapedFlatString(NULL, 0, ATOM_TO_STRING(fun->atom), 0); JSFlatString *funId = JS_ASSERT_STRING_IS_FLAT(JS_GetFunctionId(fun));
size_t size = 1 + JS_PutEscapedFlatString(NULL, 0, funId, 0);
char *name = new char[size]; char *name = new char[size];
if (name) { if (name) {
JS_PutEscapedFlatString(name, size, ATOM_TO_STRING(fun->atom), 0); JS_PutEscapedFlatString(name, size, funId, 0);
foo.AppendLiteral(" ["); foo.AppendLiteral(" [");
foo.Append(name); foo.Append(name);
delete[] name; delete[] name;

View File

@ -71,7 +71,7 @@ void JSD_ASSERT_VALID_CONTEXT(JSDContext* jsdc)
static JSClass global_class = { static JSClass global_class = {
"JSDGlobal", JSCLASS_GLOBAL_FLAGS, "JSDGlobal", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS JSCLASS_NO_OPTIONAL_MEMBERS
}; };

View File

@ -11,28 +11,28 @@ BEGIN_TEST(testIntString_bug515273)
EVAL("'1';", v.addr()); EVAL("'1';", v.addr());
JSString *str = JSVAL_TO_STRING(v.value()); JSString *str = JSVAL_TO_STRING(v.value());
CHECK(JSString::isGCThingStatic(str) && str->isStaticAtom()); CHECK(str->isStaticAtom());
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "1")); CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "1"));
EVAL("'42';", v.addr()); EVAL("'42';", v.addr());
str = JSVAL_TO_STRING(v.value()); str = JSVAL_TO_STRING(v.value());
CHECK(JSString::isGCThingStatic(str) && str->isStaticAtom()); CHECK(str->isStaticAtom());
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "42")); CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "42"));
EVAL("'111';", v.addr()); EVAL("'111';", v.addr());
str = JSVAL_TO_STRING(v.value()); str = JSVAL_TO_STRING(v.value());
CHECK(JSString::isGCThingStatic(str) && str->isStaticAtom()); CHECK(str->isStaticAtom());
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "111")); CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "111"));
/* Test other types of static strings. */ /* Test other types of static strings. */
EVAL("'a';", v.addr()); EVAL("'a';", v.addr());
str = JSVAL_TO_STRING(v.value()); str = JSVAL_TO_STRING(v.value());
CHECK(JSString::isGCThingStatic(str) && str->isStaticAtom()); CHECK(str->isStaticAtom());
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "a")); CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "a"));
EVAL("'bc';", v.addr()); EVAL("'bc';", v.addr());
str = JSVAL_TO_STRING(v.value()); str = JSVAL_TO_STRING(v.value());
CHECK(JSString::isGCThingStatic(str) && str->isStaticAtom()); CHECK(str->isStaticAtom());
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "bc")); CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "bc"));
return true; return true;

View File

@ -328,10 +328,10 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format
return JS_FALSE; return JS_FALSE;
*sp = STRING_TO_JSVAL(str); *sp = STRING_TO_JSVAL(str);
if (c == 'W') { if (c == 'W') {
const jschar *chars = js_GetStringChars(cx, str); JSFixedString *fixed = str->ensureFixed(cx);
if (!chars) if (!fixed)
return JS_FALSE; return JS_FALSE;
*va_arg(ap, const jschar **) = chars; *va_arg(ap, const jschar **) = fixed->chars();
} else { } else {
*va_arg(ap, JSString **) = str; *va_arg(ap, JSString **) = str;
} }
@ -1769,7 +1769,7 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
/* Check whether we're resolving 'undefined', and define it if so. */ /* Check whether we're resolving 'undefined', and define it if so. */
atom = rt->atomState.typeAtoms[JSTYPE_VOID]; atom = rt->atomState.typeAtoms[JSTYPE_VOID];
if (idstr == ATOM_TO_STRING(atom)) { if (idstr == atom) {
*resolved = JS_TRUE; *resolved = JS_TRUE;
return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(), return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
PropertyStub, StrictPropertyStub, PropertyStub, StrictPropertyStub,
@ -1781,7 +1781,7 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
for (i = 0; standard_class_atoms[i].init; i++) { for (i = 0; standard_class_atoms[i].init; i++) {
JS_ASSERT(standard_class_atoms[i].clasp); JS_ASSERT(standard_class_atoms[i].clasp);
atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset); atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
if (idstr == ATOM_TO_STRING(atom)) { if (idstr == atom) {
stdnm = &standard_class_atoms[i]; stdnm = &standard_class_atoms[i];
break; break;
} }
@ -1794,7 +1794,7 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
atom = StdNameToAtom(cx, &standard_class_names[i]); atom = StdNameToAtom(cx, &standard_class_names[i]);
if (!atom) if (!atom)
return JS_FALSE; return JS_FALSE;
if (idstr == ATOM_TO_STRING(atom)) { if (idstr == atom) {
stdnm = &standard_class_names[i]; stdnm = &standard_class_names[i];
break; break;
} }
@ -1811,7 +1811,7 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved)
atom = StdNameToAtom(cx, &object_prototype_names[i]); atom = StdNameToAtom(cx, &object_prototype_names[i]);
if (!atom) if (!atom)
return JS_FALSE; return JS_FALSE;
if (idstr == ATOM_TO_STRING(atom)) { if (idstr == atom) {
stdnm = &object_prototype_names[i]; stdnm = &object_prototype_names[i];
break; break;
} }
@ -2321,7 +2321,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
JS_snprintf(buf, bufsize, "%p", fun); JS_snprintf(buf, bufsize, "%p", fun);
} else { } else {
if (fun->atom) if (fun->atom)
PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0); PutEscapedString(buf, bufsize, fun->atom, 0);
} }
} else if (clasp->flags & JSCLASS_HAS_PRIVATE) { } else if (clasp->flags & JSCLASS_HAS_PRIVATE) {
JS_snprintf(buf, bufsize, "%p", obj->getPrivate()); JS_snprintf(buf, bufsize, "%p", obj->getPrivate());
@ -2335,7 +2335,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
{ {
JSString *str = (JSString *)thing; JSString *str = (JSString *)thing;
if (str->isLinear()) if (str->isLinear())
PutEscapedString(buf, bufsize, str->assertIsLinear(), 0); PutEscapedString(buf, bufsize, &str->asLinear(), 0);
else else
JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length()); JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
break; break;
@ -2763,15 +2763,7 @@ JS_PUBLIC_API(JSString *)
JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type) JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
{ {
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
JS_ASSERT(uintN(type) < JSExternalString::TYPE_LIMIT); return JSExternalString::new_(cx, chars, length, type);
JSExternalString *str = js_NewGCExternalString(cx, uintN(type));
if (!str)
return NULL;
str->initFlat(chars, length);
str->externalStringType = type;
cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
return str;
} }
JS_PUBLIC_API(void) JS_PUBLIC_API(void)
@ -4322,7 +4314,7 @@ JS_GetFunctionObject(JSFunction *fun)
JS_PUBLIC_API(JSString *) JS_PUBLIC_API(JSString *)
JS_GetFunctionId(JSFunction *fun) JS_GetFunctionId(JSFunction *fun)
{ {
return fun->atom ? ATOM_TO_STRING(fun->atom) : NULL; return fun->atom;
} }
JS_PUBLIC_API(uintN) JS_PUBLIC_API(uintN)
@ -5291,22 +5283,14 @@ JS_PUBLIC_API(JSString *)
JS_InternJSString(JSContext *cx, JSString *str) JS_InternJSString(JSContext *cx, JSString *str)
{ {
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
JSAtom *atom = js_AtomizeString(cx, str, 0); return js_AtomizeString(cx, str, 0);
if (!atom)
return NULL;
return ATOM_TO_STRING(atom);
} }
JS_PUBLIC_API(JSString *) JS_PUBLIC_API(JSString *)
JS_InternString(JSContext *cx, const char *s) JS_InternString(JSContext *cx, const char *s)
{ {
JSAtom *atom;
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
atom = js_Atomize(cx, s, strlen(s), ATOM_INTERNED); return js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
if (!atom)
return NULL;
return ATOM_TO_STRING(atom);
} }
JS_PUBLIC_API(JSString *) JS_PUBLIC_API(JSString *)
@ -5335,13 +5319,8 @@ JS_NewUCStringCopyZ(JSContext *cx, const jschar *s)
JS_PUBLIC_API(JSString *) JS_PUBLIC_API(JSString *)
JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length) JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
{ {
JSAtom *atom;
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
atom = js_AtomizeChars(cx, s, length, ATOM_INTERNED); return js_AtomizeChars(cx, s, length, ATOM_INTERNED);
if (!atom)
return NULL;
return ATOM_TO_STRING(atom);
} }
JS_PUBLIC_API(JSString *) JS_PUBLIC_API(JSString *)
@ -5385,16 +5364,15 @@ JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
JS_PUBLIC_API(const jschar *) JS_PUBLIC_API(const jschar *)
JS_GetInternedStringChars(JSString *str) JS_GetInternedStringChars(JSString *str)
{ {
JS_ASSERT(str->isAtom()); return str->asAtom().chars();
return str->flatChars();
} }
JS_PUBLIC_API(const jschar *) JS_PUBLIC_API(const jschar *)
JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength) JS_GetInternedStringCharsAndLength(JSString *str, size_t *plength)
{ {
JS_ASSERT(str->isAtom()); JSAtom &atom = str->asAtom();
*plength = str->flatLength(); *plength = atom.length();
return str->flatChars(); return atom.chars();
} }
extern JS_PUBLIC_API(JSFlatString *) extern JS_PUBLIC_API(JSFlatString *)
@ -5487,7 +5465,7 @@ JS_PUBLIC_API(JSBool)
JS_MakeStringImmutable(JSContext *cx, JSString *str) JS_MakeStringImmutable(JSContext *cx, JSString *str)
{ {
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
return js_MakeStringImmutable(cx, str); return !!str->ensureFixed(cx);
} }
JS_PUBLIC_API(JSBool) JS_PUBLIC_API(JSBool)

View File

@ -108,6 +108,7 @@
#include "jscntxtinlines.h" #include "jscntxtinlines.h"
#include "jsinterpinlines.h" #include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsstrinlines.h"
using namespace js; using namespace js;
using namespace js::gc; using namespace js::gc;
@ -1250,7 +1251,7 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
genBefore = cx->busyArrays.generation(); genBefore = cx->busyArrays.generation();
} else { } else {
/* Cycle, so return empty string. */ /* Cycle, so return empty string. */
rval->setString(ATOM_TO_STRING(cx->runtime->atomState.emptyAtom)); rval->setString(cx->runtime->atomState.emptyAtom);
return true; return true;
} }
@ -3265,7 +3266,7 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
if (val.isString()) { if (val.isString()) {
// Strings must be made immutable before being copied to a clone. // Strings must be made immutable before being copied to a clone.
if (!js_MakeStringImmutable(cx, val.toString())) if (!val.toString()->ensureFixed(cx))
return JS_FALSE; return JS_FALSE;
} else if (val.isObject()) { } else if (val.isObject()) {
/* /*

View File

@ -109,35 +109,6 @@ js_IdIsIndex(jsid id, jsuint *indexp)
return js_StringIsIndex(JSID_TO_ATOM(id), indexp); return js_StringIsIndex(JSID_TO_ATOM(id), indexp);
} }
/* XML really wants to pretend jsvals are jsids. */
inline bool
js_IdValIsIndex(JSContext *cx, jsval id, jsuint *indexp, bool *isIndex)
{
if (JSVAL_IS_INT(id)) {
jsint i;
i = JSVAL_TO_INT(id);
if (i < 0) {
*isIndex = false;
return true;
}
*indexp = (jsuint)i;
*isIndex = true;
return true;
}
if (!JSVAL_IS_STRING(id)) {
*isIndex = false;
return true;
}
JSLinearString *str = JSVAL_TO_STRING(id)->ensureLinear(cx);
if (!str)
return false;
*isIndex = js_StringIsIndex(str, indexp);
return true;
}
extern js::Class js_ArrayClass, js_SlowArrayClass; extern js::Class js_ArrayClass, js_SlowArrayClass;
inline bool inline bool

View File

@ -91,7 +91,7 @@ JS_STATIC_ASSERT((1 + 2) * sizeof(JSAtom *) ==
const char * const char *
js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes) js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes)
{ {
return js_ValueToPrintable(cx, StringValue(ATOM_TO_STRING(atom)), bytes); return js_ValueToPrintable(cx, StringValue(atom), bytes);
} }
#define JS_PROTO(name,code,init) const char js_##name##_str[] = #name; #define JS_PROTO(name,code,init) const char js_##name##_str[] = #name;
@ -390,7 +390,7 @@ js_InitCommonAtoms(JSContext *cx)
JS_ASSERT((uint8 *)atoms - (uint8 *)state == LAZY_ATOM_OFFSET_START); JS_ASSERT((uint8 *)atoms - (uint8 *)state == LAZY_ATOM_OFFSET_START);
memset(atoms, 0, ATOM_OFFSET_LIMIT - LAZY_ATOM_OFFSET_START); memset(atoms, 0, ATOM_OFFSET_LIMIT - LAZY_ATOM_OFFSET_START);
cx->runtime->emptyString = ATOM_TO_STRING(state->emptyAtom); cx->runtime->emptyString = state->emptyAtom;
return JS_TRUE; return JS_TRUE;
} }
@ -456,79 +456,84 @@ js_SweepAtomState(JSContext *cx)
} }
} }
JSAtom * /*
js_AtomizeString(JSContext *cx, JSString *strArg, uintN flags) * This call takes ownership of 'chars' if ATOM_NOCOPY is set.
*/
static JSAtom *
Atomize(JSContext *cx, const jschar *chars, size_t length, uintN flags)
{ {
JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY))); JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_NOCOPY)));
JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR);
if (strArg->isAtom()) if (JSAtom *s = JSAtom::lookupStatic(chars, length))
return STRING_TO_ATOM(strArg); return s;
JSLinearString *str = strArg->ensureLinear(cx);
if (!str)
return NULL;
const jschar *chars = str->chars();
size_t length = str->length();
JSString *staticStr = JSString::lookupStaticString(chars, length);
if (staticStr)
return STRING_TO_ATOM(staticStr);
AutoLockAtomsCompartment lock(cx); AutoLockAtomsCompartment lock(cx);
AtomSet &atoms = cx->runtime->atomState.atoms; AtomSet &atoms = cx->runtime->atomState.atoms;
AtomSet::AddPtr p = atoms.lookupForAdd(str); AtomSet::AddPtr p = atoms.lookupForAdd(AtomHasher::Lookup(chars, length));
/* Hashing the string should have flattened it if it was a rope. */ JSAtom *atom;
JS_ASSERT(str->isFlat() || str->isDependent());
JSLinearString *key;
if (p) { if (p) {
key = AtomEntryToKey(*p); atom = AtomEntryToKey(*p);
} else { } else {
/*
* We have to relookup the key as the last ditch GC invoked from the
* string allocation or OOM handling may unlock the atomsCompartment.
*/
SwitchToCompartment sc(cx, cx->runtime->atomsCompartment); SwitchToCompartment sc(cx, cx->runtime->atomsCompartment);
if (flags & ATOM_NOCOPY) {
key = js_NewString(cx, const_cast<jschar *>(str->flatChars()), length);
if (!key)
return NULL;
/* Finish handing off chars to the GC'ed key string. */ JSFixedString *key;
JS_ASSERT(flags & ATOM_TMPSTR); if (flags & ATOM_NOCOPY) {
str->u.chars = NULL; key = js_NewString(cx, const_cast<jschar *>(chars), length);
if (!key) {
cx->free(const_cast<jschar *>(chars));
return NULL;
}
} else { } else {
key = js_NewStringCopyN(cx, chars, length); key = js_NewStringCopyN(cx, chars, length);
if (!key) if (!key)
return NULL; return NULL;
} }
if (!atoms.relookupOrAdd(p, key, StringToInitialAtomEntry(key))) { /*
* We have to relookup the key as the last ditch GC invoked from the
* string allocation or OOM handling may unlock the atomsCompartment.
*/
AtomHasher::Lookup lookup(chars, length);
if (!atoms.relookupOrAdd(p, lookup, StringToInitialAtomEntry(key))) {
JS_ReportOutOfMemory(cx); /* SystemAllocPolicy does not report */ JS_ReportOutOfMemory(cx); /* SystemAllocPolicy does not report */
return NULL; return NULL;
} }
key->flatSetAtomized();
atom = key->morphInternedStringIntoAtom();
} }
AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED)); AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED));
JSAtom *atom = STRING_TO_ATOM(key);
return atom; return atom;
} }
JSAtom *
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
{
JS_ASSERT(!(flags & ATOM_NOCOPY));
if (str->isAtom())
return &str->asAtom();
size_t length = str->length();
const jschar *chars = str->getChars(cx);
if (!chars)
return NULL;
JS_ASSERT(length <= JSString::MAX_LENGTH);
return Atomize(cx, chars, length, flags);
}
JSAtom * JSAtom *
js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags, bool useCESU8) js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags, bool useCESU8)
{ {
jschar *chars; JS_ASSERT(!(flags & ATOM_NOCOPY));
JSString str;
JSAtom *atom;
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
if (!CheckStringLength(cx, length))
return NULL;
/* /*
* Avoiding the malloc in js_InflateString on shorter strings saves us * Avoiding the malloc in js_InflateString on shorter strings saves us
* over 20,000 malloc calls on mozilla browser startup. This compares to * over 20,000 malloc calls on mozilla browser startup. This compares to
@ -536,10 +541,11 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags, bool us
* The vast majority of atomized strings are already in the hashtable. So * The vast majority of atomized strings are already in the hashtable. So
* js_AtomizeString rarely has to copy the temp string we make. * js_AtomizeString rarely has to copy the temp string we make.
*/ */
#define ATOMIZE_BUF_MAX 32 static const unsigned ATOMIZE_BUF_MAX = 32;
jschar inflated[ATOMIZE_BUF_MAX]; jschar inflated[ATOMIZE_BUF_MAX];
size_t inflatedLength = ATOMIZE_BUF_MAX - 1; size_t inflatedLength = ATOMIZE_BUF_MAX - 1;
const jschar *chars;
if (length < ATOMIZE_BUF_MAX) { if (length < ATOMIZE_BUF_MAX) {
if (useCESU8) if (useCESU8)
js_InflateUTF8StringToBuffer(cx, bytes, length, inflated, &inflatedLength, true); js_InflateUTF8StringToBuffer(cx, bytes, length, inflated, &inflatedLength, true);
@ -555,48 +561,29 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags, bool us
flags |= ATOM_NOCOPY; flags |= ATOM_NOCOPY;
} }
str.initFlat(chars, inflatedLength); return Atomize(cx, chars, inflatedLength, flags);
atom = js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
if (chars != inflated && str.flatChars())
cx->free(chars);
return atom;
} }
JSAtom * JSAtom *
js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags) js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
{ {
JSString str; JS_ASSERT(!(flags & ATOM_NOCOPY));
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
if (!CheckStringLength(cx, length)) if (!CheckStringLength(cx, length))
return NULL; return NULL;
str.initFlatNotTerminated((jschar *)chars, length); return Atomize(cx, chars, length, flags);
return js_AtomizeString(cx, &str, ATOM_TMPSTR | flags);
} }
JSAtom * JSAtom *
js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length) js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
{ {
JSString str, *str2; if (JSAtom *atom = JSAtom::lookupStatic(chars, length))
JSAtomState *state; return atom;
AutoLockAtomsCompartment lock(cx);
if (length == 1) { AtomSet::Ptr p = cx->runtime->atomState.atoms.lookup(AtomHasher::Lookup(chars, length));
jschar c = *chars; return p ? AtomEntryToKey(*p) : NULL;
if (c < UNIT_STRING_LIMIT)
return STRING_TO_ATOM(JSString::unitString(c));
}
str.initFlatNotTerminated((jschar *)chars, length);
state = &cx->runtime->atomState;
JS_LOCK(cx, &state->lock);
AtomSet::Ptr p = state->atoms.lookup(str.assertIsFlat());
str2 = p ? AtomEntryToKey(*p) : NULL;
JS_UNLOCK(cx, &state->lock);
return str2 ? STRING_TO_ATOM(str2) : NULL;
} }
#ifdef DEBUG #ifdef DEBUG

View File

@ -56,12 +56,6 @@
#define ATOM_PINNED 0x1 /* atom is pinned against GC */ #define ATOM_PINNED 0x1 /* atom is pinned against GC */
#define ATOM_INTERNED 0x2 /* pinned variant for JS_Intern* API */ #define ATOM_INTERNED 0x2 /* pinned variant for JS_Intern* API */
#define ATOM_NOCOPY 0x4 /* don't copy atom string bytes */ #define ATOM_NOCOPY 0x4 /* don't copy atom string bytes */
#define ATOM_TMPSTR 0x8 /* internal, to avoid extra string */
#define STRING_TO_ATOM(str) (JS_ASSERT(str->isAtom()), \
(JSAtom *)str)
#define ATOM_TO_STRING(atom) (atom)
#define ATOM_TO_JSVAL(atom) STRING_TO_JSVAL(ATOM_TO_STRING(atom))
/* Engine-internal extensions of jsid */ /* Engine-internal extensions of jsid */
@ -274,14 +268,23 @@ AtomEntryToKey(AtomEntryType entry)
struct AtomHasher struct AtomHasher
{ {
typedef JSLinearString *Lookup; struct Lookup
{
const jschar *chars;
size_t length;
Lookup(const jschar *chars, size_t length) : chars(chars), length(length) {}
};
static HashNumber hash(JSLinearString *str) { static HashNumber hash(const Lookup &l) {
return js_HashString(str); return HashChars(l.chars, l.length);
} }
static bool match(AtomEntryType entry, JSLinearString *lookup) { static bool match(AtomEntryType entry, const Lookup &lookup) {
return entry ? EqualStrings(AtomEntryToKey(entry), lookup) : false; JS_ASSERT(entry);
JSAtom *key = AtomEntryToKey(entry);
if (key->length() != lookup.length)
return false;
return PodEqual(key->chars(), lookup.chars, lookup.length);
} }
}; };

View File

@ -43,40 +43,28 @@
#include "jsatom.h" #include "jsatom.h"
#include "jsnum.h" #include "jsnum.h"
/*
* Convert v to an atomized string and wrap it as an id.
*/
inline bool inline bool
js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp) js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp)
{ {
JSString *str; if (!v.isString()) {
JSAtom *atom; JSString *str = js_ValueToString(cx, v);
/*
* Optimize for the common case where v is an already-atomized string. The
* comment in jsstr.h before JSString::flatSetAtomized 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
* is least weakly rooted.
*/
if (v.isString()) {
str = v.toString();
if (str->isAtom()) {
*atomp = STRING_TO_ATOM(str);
return true;
}
} else {
str = js_ValueToString(cx, v);
if (!str) if (!str)
return false; return false;
JS::Anchor<JSString *> anchor(str);
*atomp = js_AtomizeString(cx, str, 0);
return !!*atomp;
} }
atom = js_AtomizeString(cx, str, 0);
if (!atom) JSString *str = v.toString();
return false; if (str->isAtom()) {
*atomp = atom; *atomp = &str->asAtom();
return true; return true;
} }
*atomp = js_AtomizeString(cx, str, 0);
return !!*atomp;
}
inline bool inline bool
js_ValueToStringId(JSContext *cx, const js::Value &v, jsid *idp) js_ValueToStringId(JSContext *cx, const js::Value &v, jsid *idp)
{ {
@ -121,7 +109,7 @@ js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval,
JSAtom *atom; JSAtom *atom;
if (js_ValueToAtom(cx, idval, &atom)) { if (js_ValueToAtom(cx, idval, &atom)) {
*idp = ATOM_TO_JSID(atom); *idp = ATOM_TO_JSID(atom);
vp->setString(ATOM_TO_STRING(atom)); vp->setString(atom);
return true; return true;
} }
return false; return false;

View File

@ -56,6 +56,7 @@
#include "jsinterpinlines.h" #include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsstrinlines.h"
using namespace js; using namespace js;
@ -100,7 +101,7 @@ bool_toString(JSContext *cx, uintN argc, Value *vp)
return false; return false;
JSAtom *atom = cx->runtime->atomState.booleanAtoms[b ? 1 : 0]; JSAtom *atom = cx->runtime->atomState.booleanAtoms[b ? 1 : 0];
JSString *str = ATOM_TO_STRING(atom); JSString *str = atom;
if (!str) if (!str)
return JS_FALSE; return JS_FALSE;
vp->setString(str); vp->setString(str);
@ -162,7 +163,7 @@ js_InitBooleanClass(JSContext *cx, JSObject *obj)
JSString * JSString *
js_BooleanToString(JSContext *cx, JSBool b) js_BooleanToString(JSContext *cx, JSBool b)
{ {
return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[b ? 1 : 0]); return cx->runtime->atomState.booleanAtoms[b ? 1 : 0];
} }
/* This function implements E-262-3 section 9.8, toString. */ /* This function implements E-262-3 section 9.8, toString. */

View File

@ -285,7 +285,7 @@ JSString* FASTCALL
js_TypeOfObject(JSContext* cx, JSObject* obj) js_TypeOfObject(JSContext* cx, JSObject* obj)
{ {
JS_ASSERT(obj); JS_ASSERT(obj);
return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[obj->typeOf(cx)]); return cx->runtime->atomState.typeAtoms[obj->typeOf(cx)];
} }
JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT, 1, ACCSET_NONE) JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT, 1, ACCSET_NONE)
@ -293,7 +293,7 @@ JSString* FASTCALL
js_BooleanIntToString(JSContext *cx, int32 unboxed) js_BooleanIntToString(JSContext *cx, int32 unboxed)
{ {
JS_ASSERT(uint32(unboxed) <= 1); JS_ASSERT(uint32(unboxed) <= 1);
return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[unboxed]); return cx->runtime->atomState.booleanAtoms[unboxed];
} }
JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanIntToString, CONTEXT, INT32, 1, ACCSET_NONE) JS_DEFINE_CALLINFO_2(extern, STRING, js_BooleanIntToString, CONTEXT, INT32, 1, ACCSET_NONE)

View File

@ -627,7 +627,7 @@ JS_DECLARE_CALLINFO(js_String_tn)
JS_DECLARE_CALLINFO(js_CompareStringsOnTrace) JS_DECLARE_CALLINFO(js_CompareStringsOnTrace)
JS_DECLARE_CALLINFO(js_ConcatStrings) JS_DECLARE_CALLINFO(js_ConcatStrings)
JS_DECLARE_CALLINFO(js_EqualStringsOnTrace) JS_DECLARE_CALLINFO(js_EqualStringsOnTrace)
JS_DECLARE_CALLINFO(js_Flatten) JS_DECLARE_CALLINFO(js_FlattenOnTrace)
/* Defined in jstypedarray.cpp. */ /* Defined in jstypedarray.cpp. */
JS_DECLARE_CALLINFO(js_TypedArray_uint8_clamp_double) JS_DECLARE_CALLINFO(js_TypedArray_uint8_clamp_double)

View File

@ -75,9 +75,6 @@ struct Cell {
inline JSCompartment *compartment() const; inline JSCompartment *compartment() const;
/* Needed for compatibility reasons because Cell can't be a base class of JSString */
JS_ALWAYS_INLINE js::gc::Cell *asCell() { return this; }
JS_ALWAYS_INLINE js::gc::FreeCell *asFreeCell() { JS_ALWAYS_INLINE js::gc::FreeCell *asFreeCell() {
return reinterpret_cast<FreeCell *>(this); return reinterpret_cast<FreeCell *>(this);
} }

View File

@ -1664,7 +1664,7 @@ js_ReportMissingArg(JSContext *cx, const Value &v, uintN arg)
if (IsFunctionObject(v)) { if (IsFunctionObject(v)) {
atom = GET_FUNCTION_PRIVATE(cx, &v.toObject())->atom; atom = GET_FUNCTION_PRIVATE(cx, &v.toObject())->atom;
bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
v, ATOM_TO_STRING(atom)); v, atom);
if (!bytes) if (!bytes)
return; return;
} }

View File

@ -556,7 +556,7 @@ class CompartmentChecker
void check(JSString *str) { void check(JSString *str) {
if (!str->isAtom()) if (!str->isAtom())
check(str->asCell()->compartment()); check(str->compartment());
} }
void check(const js::Value &v) { void check(const js::Value &v) {

View File

@ -205,12 +205,12 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
return true; return true;
/* If the string is already in this compartment, we are done. */ /* If the string is already in this compartment, we are done. */
if (str->asCell()->compartment() == this) if (str->compartment() == this)
return true; return true;
/* If the string is an atom, we don't have to copy. */ /* If the string is an atom, we don't have to copy. */
if (str->isAtom()) { if (str->isAtom()) {
JS_ASSERT(str->asCell()->compartment() == cx->runtime->atomsCompartment); JS_ASSERT(str->compartment() == cx->runtime->atomsCompartment);
return true; return true;
} }
} }

View File

@ -350,16 +350,16 @@ class NativeIterCache {
class DtoaCache { class DtoaCache {
double d; double d;
jsint base; jsint base;
JSString *s; // if s==NULL, d and base are not valid JSFixedString *s; // if s==NULL, d and base are not valid
public: public:
DtoaCache() : s(NULL) {} DtoaCache() : s(NULL) {}
void purge() { s = NULL; } void purge() { s = NULL; }
JSString *lookup(jsint base, double d) { JSFixedString *lookup(jsint base, double d) {
return this->s && base == this->base && d == this->d ? this->s : NULL; return this->s && base == this->base && d == this->d ? this->s : NULL;
} }
void cache(jsint base, double d, JSString *s) { void cache(jsint base, double d, JSFixedString *s) {
this->base = base; this->base = base;
this->d = d; this->d = d;
this->s = s; this->s = s;

View File

@ -1287,7 +1287,7 @@ JS_LocalNameToAtom(jsuword w)
extern JS_PUBLIC_API(JSString *) extern JS_PUBLIC_API(JSString *)
JS_AtomKey(JSAtom *atom) JS_AtomKey(JSAtom *atom)
{ {
return ATOM_TO_STRING(atom); return atom;
} }
extern JS_PUBLIC_API(void) extern JS_PUBLIC_API(void)
@ -1871,7 +1871,7 @@ GetAtomTotalSize(JSContext *cx, JSAtom *atom)
nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub); nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub);
nbytes += sizeof(JSString); nbytes += sizeof(JSString);
nbytes += (ATOM_TO_STRING(atom)->flatLength() + 1) * sizeof(jschar); nbytes += (atom->length() + 1) * sizeof(jschar);
return nbytes; return nbytes;
} }

View File

@ -2979,7 +2979,7 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
} }
right = &rtmp; right = &rtmp;
right->pn_type = TOK_STRING; right->pn_type = TOK_STRING;
right->pn_op = js_IsIdentifier(ATOM_TO_STRING(pn->pn_atom)) right->pn_op = js_IsIdentifier(pn->pn_atom)
? JSOP_QNAMEPART ? JSOP_QNAMEPART
: JSOP_STRING; : JSOP_STRING;
right->pn_arity = PN_NULLARY; right->pn_arity = PN_NULLARY;
@ -3211,7 +3211,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
constVal.setNumber(pn4->pn_dval); constVal.setNumber(pn4->pn_dval);
break; break;
case TOK_STRING: case TOK_STRING:
constVal.setString(ATOM_TO_STRING(pn4->pn_atom)); constVal.setString(pn4->pn_atom);
break; break;
case TOK_NAME: case TOK_NAME:
if (!pn4->maybeExpr()) { if (!pn4->maybeExpr()) {
@ -4426,7 +4426,7 @@ JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp)
vp->setNumber(pn_dval); vp->setNumber(pn_dval);
return true; return true;
case TOK_STRING: case TOK_STRING:
vp->setString(ATOM_TO_STRING(pn_atom)); vp->setString(pn_atom);
return true; return true;
case TOK_PRIMARY: case TOK_PRIMARY:
switch (pn_op) { switch (pn_op) {

View File

@ -341,7 +341,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
elem->argc = 0; elem->argc = 0;
} else { } else {
elem->funName = fp->fun()->atom elem->funName = fp->fun()->atom
? ATOM_TO_STRING(fp->fun()->atom) ? fp->fun()->atom
: cx->runtime->emptyString; : cx->runtime->emptyString;
elem->argc = fp->numActualArgs(); elem->argc = fp->numActualArgs();
fp->forEachCanonicalActualArg(CopyTo(Valueify(values))); fp->forEachCanonicalActualArg(CopyTo(Valueify(values)));
@ -471,7 +471,7 @@ exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
str = JSID_TO_STRING(id); str = JSID_TO_STRING(id);
atom = cx->runtime->atomState.messageAtom; atom = cx->runtime->atomState.messageAtom;
if (str == ATOM_TO_STRING(atom)) { if (str == atom) {
prop = js_message_str; prop = js_message_str;
/* /*
@ -487,21 +487,21 @@ exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
} }
atom = cx->runtime->atomState.fileNameAtom; atom = cx->runtime->atomState.fileNameAtom;
if (str == ATOM_TO_STRING(atom)) { if (str == atom) {
prop = js_fileName_str; prop = js_fileName_str;
v = STRING_TO_JSVAL(priv->filename); v = STRING_TO_JSVAL(priv->filename);
goto define; goto define;
} }
atom = cx->runtime->atomState.lineNumberAtom; atom = cx->runtime->atomState.lineNumberAtom;
if (str == ATOM_TO_STRING(atom)) { if (str == atom) {
prop = js_lineNumber_str; prop = js_lineNumber_str;
v = INT_TO_JSVAL(priv->lineno); v = INT_TO_JSVAL(priv->lineno);
goto define; goto define;
} }
atom = cx->runtime->atomState.stackAtom; atom = cx->runtime->atomState.stackAtom;
if (str == ATOM_TO_STRING(atom)) { if (str == atom) {
stack = StackTraceToString(cx, priv); stack = StackTraceToString(cx, priv);
if (!stack) if (!stack)
return false; return false;
@ -1284,9 +1284,10 @@ js_ReportUncaughtException(JSContext *cx)
report.filename = filename.ptr(); report.filename = filename.ptr();
report.lineno = (uintN) lineno; report.lineno = (uintN) lineno;
if (JSVAL_IS_STRING(roots[2])) { if (JSVAL_IS_STRING(roots[2])) {
report.ucmessage = js_GetStringChars(cx, JSVAL_TO_STRING(roots[2])); JSFixedString *fixed = JSVAL_TO_STRING(roots[2])->ensureFixed(cx);
if (!report.ucmessage) if (!fixed)
return false; return false;
report.ucmessage = fixed->chars();
} }
} }

View File

@ -44,5 +44,5 @@ JS_FRIEND_API(JSString *)
JS_GetAnonymousString(JSRuntime *rt) JS_GetAnonymousString(JSRuntime *rt)
{ {
JS_ASSERT(rt->state == JSRTS_UP); JS_ASSERT(rt->state == JSRTS_UP);
return ATOM_TO_STRING(rt->atomState.anonymousAtom); return rt->atomState.anonymousAtom;
} }

View File

@ -1617,7 +1617,7 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
break; break;
case FUN_NAME: case FUN_NAME:
vp->setString(fun->atom ? ATOM_TO_STRING(fun->atom) vp->setString(fun->atom ? fun->atom
: cx->runtime->emptyString); : cx->runtime->emptyString);
break; break;
@ -1977,7 +1977,7 @@ fun_trace(JSTracer *trc, JSObject *obj)
} }
if (fun->atom) if (fun->atom)
MarkString(trc, ATOM_TO_STRING(fun->atom), "atom"); MarkString(trc, fun->atom, "atom");
if (fun->isInterpreted() && fun->script()) if (fun->isInterpreted() && fun->script())
js_TraceScript(trc, fun->script()); js_TraceScript(trc, fun->script());

View File

@ -206,13 +206,13 @@ struct JSFunction : public JSObject_Slots2
*/ */
JSAtom *methodAtom() const { JSAtom *methodAtom() const {
return (joinable() && getSlot(METHOD_ATOM_SLOT).isString()) return (joinable() && getSlot(METHOD_ATOM_SLOT).isString())
? STRING_TO_ATOM(getSlot(METHOD_ATOM_SLOT).toString()) ? &getSlot(METHOD_ATOM_SLOT).toString()->asAtom()
: NULL; : NULL;
} }
void setMethodAtom(JSAtom *atom) { void setMethodAtom(JSAtom *atom) {
JS_ASSERT(joinable()); JS_ASSERT(joinable());
getSlotRef(METHOD_ATOM_SLOT).setString(ATOM_TO_STRING(atom)); getSlotRef(METHOD_ATOM_SLOT).setString(atom);
} }
js::Native maybeNative() const { js::Native maybeNative() const {
@ -425,7 +425,7 @@ inline const char *
GetFunctionNameBytes(JSContext *cx, JSFunction *fun, JSAutoByteString *bytes) GetFunctionNameBytes(JSContext *cx, JSFunction *fun, JSAutoByteString *bytes)
{ {
if (fun->atom) if (fun->atom)
return bytes->encode(cx, ATOM_TO_STRING(fun->atom)); return bytes->encode(cx, fun->atom);
return js_anonymous_str; return js_anonymous_str;
} }

View File

@ -496,7 +496,7 @@ AllocateArena(JSContext *cx, unsigned thingKind)
JS_FRIEND_API(bool) JS_FRIEND_API(bool)
IsAboutToBeFinalized(JSContext *cx, void *thing) IsAboutToBeFinalized(JSContext *cx, void *thing)
{ {
if (JSString::isGCThingStatic(thing)) if (JSAtom::isStatic(thing))
return false; return false;
JS_ASSERT(cx); JS_ASSERT(cx);
@ -1068,8 +1068,6 @@ FreeLists::purge()
*p = NULL; *p = NULL;
} }
class JSShortString;
ArenaList * ArenaList *
GetFinalizableArenaList(JSCompartment *c, unsigned thingKind) { GetFinalizableArenaList(JSCompartment *c, unsigned thingKind) {
JS_ASSERT(thingKind < FINALIZE_LIMIT); JS_ASSERT(thingKind < FINALIZE_LIMIT);
@ -1210,7 +1208,8 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
} }
uint32 uint32
js_GetGCThingTraceKind(void *thing) { js_GetGCThingTraceKind(void *thing)
{
return GetGCThingTraceKind(thing); return GetGCThingTraceKind(thing);
} }
@ -1351,7 +1350,7 @@ Arena<T>::markDelayedChildren(JSTracer *trc)
T *thingsEnd = &t.things[ThingsPerArena-1].t; T *thingsEnd = &t.things[ThingsPerArena-1].t;
JS_ASSERT(thing == getAlignedThing(thing)); JS_ASSERT(thing == getAlignedThing(thing));
while (thing <= thingsEnd) { while (thing <= thingsEnd) {
if (thing->asCell()->isMarked()) if (thing->isMarked())
js::gc::MarkChildren(trc, thing); js::gc::MarkChildren(trc, thing);
thing++; thing++;
@ -1436,7 +1435,7 @@ gc_root_traversal(JSTracer *trc, const RootEntry &entry)
} }
if (ptr) { if (ptr) {
if (!JSString::isGCThingStatic(ptr)) { if (!JSAtom::isStatic(ptr)) {
bool root_points_to_gcArenaList = false; bool root_points_to_gcArenaList = false;
JSCompartment **c = trc->context->runtime->compartments.begin(); JSCompartment **c = trc->context->runtime->compartments.begin();
for (; c != trc->context->runtime->compartments.end(); ++c) { for (; c != trc->context->runtime->compartments.end(); ++c) {
@ -1854,23 +1853,19 @@ void
js_FinalizeStringRT(JSRuntime *rt, JSString *str) js_FinalizeStringRT(JSRuntime *rt, JSString *str)
{ {
JS_RUNTIME_UNMETER(rt, liveStrings); JS_RUNTIME_UNMETER(rt, liveStrings);
JS_ASSERT(!str->isStaticAtom()); JS_ASSERT(str->isLinear() && !str->isStaticAtom());
JS_ASSERT(!str->isRope());
if (str->isDependent()) { if (str->isDependent()) {
/* A dependent string can not be external and must be valid. */ /* A dependent string can not be external and must be valid. */
JS_ASSERT(str->asCell()->arena()->header()->thingKind == FINALIZE_STRING); JS_ASSERT(str->arena()->header()->thingKind == FINALIZE_STRING);
JS_ASSERT(str->dependentBase()); JS_ASSERT(str->asDependent().base());
JS_RUNTIME_UNMETER(rt, liveDependentStrings); JS_RUNTIME_UNMETER(rt, liveDependentStrings);
} else { } else {
unsigned thingKind = str->asCell()->arena()->header()->thingKind; unsigned thingKind = str->arena()->header()->thingKind;
JS_ASSERT(unsigned(FINALIZE_SHORT_STRING) <= thingKind && JS_ASSERT(unsigned(FINALIZE_SHORT_STRING) <= thingKind &&
thingKind <= unsigned(FINALIZE_EXTERNAL_STRING)); thingKind <= unsigned(FINALIZE_EXTERNAL_STRING));
/* A stillborn string has null chars, so is not valid. */ jschar *chars = const_cast<jschar *>(str->asFlat().chars());
jschar *chars = const_cast<jschar *>(str->flatChars());
if (!chars)
return;
if (thingKind == FINALIZE_STRING) { if (thingKind == FINALIZE_STRING) {
rt->stringMemoryUsed -= str->length() * 2; rt->stringMemoryUsed -= str->length() * 2;
rt->free(chars); rt->free(chars);
@ -1915,22 +1910,22 @@ FinalizeArenaList(JSCompartment *comp, JSContext *cx, unsigned thingKind)
if (!nextFree) { if (!nextFree) {
nextFree = thingsEnd->asFreeCell(); nextFree = thingsEnd->asFreeCell();
} else { } else {
JS_ASSERT(thing->asCell() <= nextFree); JS_ASSERT(thing->asFreeCell() <= nextFree);
JS_ASSERT(nextFree < thingsEnd->asCell()); JS_ASSERT(nextFree < thingsEnd->asFreeCell());
} }
for (;; thing++) { for (;; thing++) {
if (thing->asCell() == nextFree) { if (thing->asFreeCell() == nextFree) {
if (thing == thingsEnd) if (thing == thingsEnd)
break; break;
nextFree = nextFree->link; nextFree = nextFree->link;
if (!nextFree) { if (!nextFree) {
nextFree = thingsEnd->asFreeCell(); nextFree = thingsEnd->asFreeCell();
} else { } else {
JS_ASSERT(thing->asCell() < nextFree); JS_ASSERT(thing->asFreeCell() < nextFree);
JS_ASSERT(nextFree < thingsEnd->asFreeCell()); JS_ASSERT(nextFree < thingsEnd->asFreeCell());
} }
} else if (thing->asCell()->isMarked()) { } else if (thing->isMarked()) {
allClear = false; allClear = false;
METER(nthings++); METER(nthings++);
continue; continue;

View File

@ -532,15 +532,8 @@ GetFinalizableTraceKind(size_t thingKind)
return map[thingKind]; return map[thingKind];
} }
static inline uint32 inline uint32
GetGCThingTraceKind(void *thing) GetGCThingTraceKind(void *thing);
{
JS_ASSERT(thing);
if (JSString::isGCThingStatic(thing))
return JSTRACE_STRING;
Cell *cell = reinterpret_cast<Cell *>(thing);
return GetFinalizableTraceKind(cell->arena()->header()->thingKind);
}
static inline JSRuntime * static inline JSRuntime *
GetGCThingRuntime(void *thing) GetGCThingRuntime(void *thing)

View File

@ -43,6 +43,7 @@
#include "jsgc.h" #include "jsgc.h"
#include "jscntxt.h" #include "jscntxt.h"
#include "jscompartment.h" #include "jscompartment.h"
#include "jsscope.h"
#include "jslock.h" #include "jslock.h"
#include "jstl.h" #include "jstl.h"
@ -55,9 +56,64 @@
# define METER_IF(condition, x) ((void) 0) # define METER_IF(condition, x) ((void) 0)
#endif #endif
inline bool
JSAtom::isUnitString(void *ptr)
{
jsuword delta = reinterpret_cast<jsuword>(ptr) -
reinterpret_cast<jsuword>(unitStaticTable);
if (delta >= UNIT_STATIC_LIMIT * sizeof(JSString))
return false;
/* If ptr points inside the static array, it must be well-aligned. */
JS_ASSERT(delta % sizeof(JSString) == 0);
return true;
}
inline bool
JSAtom::isLength2String(void *ptr)
{
jsuword delta = reinterpret_cast<jsuword>(ptr) -
reinterpret_cast<jsuword>(length2StaticTable);
if (delta >= NUM_SMALL_CHARS * NUM_SMALL_CHARS * sizeof(JSString))
return false;
/* If ptr points inside the static array, it must be well-aligned. */
JS_ASSERT(delta % sizeof(JSString) == 0);
return true;
}
inline bool
JSAtom::isHundredString(void *ptr)
{
jsuword delta = reinterpret_cast<jsuword>(ptr) -
reinterpret_cast<jsuword>(hundredStaticTable);
if (delta >= NUM_HUNDRED_STATICS * sizeof(JSString))
return false;
/* If ptr points inside the static array, it must be well-aligned. */
JS_ASSERT(delta % sizeof(JSString) == 0);
return true;
}
inline bool
JSAtom::isStatic(void *ptr)
{
return isUnitString(ptr) || isLength2String(ptr) || isHundredString(ptr);
}
namespace js { namespace js {
namespace gc { namespace gc {
inline uint32
GetGCThingTraceKind(void *thing)
{
JS_ASSERT(thing);
if (JSAtom::isStatic(thing))
return JSTRACE_STRING;
Cell *cell = reinterpret_cast<Cell *>(thing);
return GetFinalizableTraceKind(cell->arena()->header()->thingKind);
}
/* Capacity for slotsToThingKind */ /* Capacity for slotsToThingKind */
const size_t SLOTS_TO_THING_KIND_LIMIT = 17; const size_t SLOTS_TO_THING_KIND_LIMIT = 17;
@ -194,7 +250,7 @@ TypedMarker(JSTracer *trc, JSFunction *thing);
static JS_ALWAYS_INLINE void static JS_ALWAYS_INLINE void
TypedMarker(JSTracer *trc, JSShortString *thing); TypedMarker(JSTracer *trc, JSShortString *thing);
static JS_ALWAYS_INLINE void extern void
TypedMarker(JSTracer *trc, JSString *thing); TypedMarker(JSTracer *trc, JSString *thing);
template<typename T> template<typename T>
@ -210,7 +266,7 @@ Mark(JSTracer *trc, T *thing)
JSRuntime *rt = trc->context->runtime; JSRuntime *rt = trc->context->runtime;
/* Don't mark things outside a compartment if we are in a per-compartment GC */ /* Don't mark things outside a compartment if we are in a per-compartment GC */
if (rt->gcCurrentCompartment && thing->asCell()->compartment() != rt->gcCurrentCompartment) if (rt->gcCurrentCompartment && thing->compartment() != rt->gcCurrentCompartment)
goto out; goto out;
if (!IS_GC_MARKING_TRACER(trc)) { if (!IS_GC_MARKING_TRACER(trc)) {
@ -307,10 +363,11 @@ static inline void
MarkChildren(JSTracer *trc, JSString *str) MarkChildren(JSTracer *trc, JSString *str)
{ {
if (str->isDependent()) if (str->isDependent())
MarkString(trc, str->dependentBase(), "base"); MarkString(trc, str->asDependent().base(), "base");
else if (str->isRope()) { else if (str->isRope()) {
MarkString(trc, str->ropeLeft(), "left child"); JSRope &rope = str->asRope();
MarkString(trc, str->ropeRight(), "right child"); MarkString(trc, rope.leftChild(), "left child");
MarkString(trc, rope.rightChild(), "right child");
} }
} }
@ -349,7 +406,7 @@ static JS_ALWAYS_INLINE void
TypedMarker(JSTracer *trc, JSObject *thing) TypedMarker(JSTracer *trc, JSObject *thing)
{ {
JS_ASSERT(thing); JS_ASSERT(thing);
JS_ASSERT(JSTRACE_OBJECT == GetFinalizableTraceKind(thing->asCell()->arena()->header()->thingKind)); JS_ASSERT(JSTRACE_OBJECT == GetFinalizableTraceKind(thing->arena()->header()->thingKind));
GCMarker *gcmarker = static_cast<GCMarker *>(trc); GCMarker *gcmarker = static_cast<GCMarker *>(trc);
if (!thing->markIfUnmarked(gcmarker->getMarkColor())) if (!thing->markIfUnmarked(gcmarker->getMarkColor()))
@ -366,7 +423,7 @@ static JS_ALWAYS_INLINE void
TypedMarker(JSTracer *trc, JSFunction *thing) TypedMarker(JSTracer *trc, JSFunction *thing)
{ {
JS_ASSERT(thing); JS_ASSERT(thing);
JS_ASSERT(JSTRACE_OBJECT == GetFinalizableTraceKind(thing->asCell()->arena()->header()->thingKind)); JS_ASSERT(JSTRACE_OBJECT == GetFinalizableTraceKind(thing->arena()->header()->thingKind));
GCMarker *gcmarker = static_cast<GCMarker *>(trc); GCMarker *gcmarker = static_cast<GCMarker *>(trc);
if (!thing->markIfUnmarked(gcmarker->getMarkColor())) if (!thing->markIfUnmarked(gcmarker->getMarkColor()))
@ -387,111 +444,7 @@ TypedMarker(JSTracer *trc, JSShortString *thing)
* anything to mark if the string was unmarked and ignore the * anything to mark if the string was unmarked and ignore the
* markIfUnmarked result. * markIfUnmarked result.
*/ */
(void) thing->asCell()->markIfUnmarked(); (void) thing->markIfUnmarked();
}
} /* namespace gc */
namespace detail {
static JS_ALWAYS_INLINE JSString *
Tag(JSString *str)
{
JS_ASSERT(!(size_t(str) & 1));
return (JSString *)(size_t(str) | 1);
}
static JS_ALWAYS_INLINE bool
Tagged(JSString *str)
{
return (size_t(str) & 1) != 0;
}
static JS_ALWAYS_INLINE JSString *
Untag(JSString *str)
{
JS_ASSERT((size_t(str) & 1) == 1);
return (JSString *)(size_t(str) & ~size_t(1));
}
static JS_ALWAYS_INLINE void
NonRopeTypedMarker(JSString *str)
{
/* N.B. The base of a dependent string is not necessarily flat. */
JS_ASSERT(!str->isRope());
while (!str->isStaticAtom() &&
str->asCell()->markIfUnmarked() &&
str->isDependent()) {
str = str->dependentBase();
}
}
} /* namespace detail */
namespace gc {
static JS_ALWAYS_INLINE void
TypedMarker(JSTracer *trc, JSString *str)
{
using namespace detail;
JS_ASSERT(!str->isStaticAtom());
if (!str->isRope()) {
NonRopeTypedMarker(str);
return;
}
/*
* This function must not fail, so a simple stack-based traversal must not
* be used (since it may oom if the stack grows large). Instead, strings
* are temporarily mutated to embed parent pointers as they are traversed.
* This algorithm is homomorphic to JSString::flatten.
*/
JSString *parent = NULL;
first_visit_node: {
JS_ASSERT(!str->isStaticAtom());
if (!str->asCell()->markIfUnmarked())
goto finish_node;
JSString *left = str->ropeLeft();
if (left->isRope()) {
JS_ASSERT(!Tagged(str->u.left) && !Tagged(str->s.right));
str->u.left = Tag(parent);
parent = str;
str = left;
goto first_visit_node;
}
NonRopeTypedMarker(left);
}
visit_right_child: {
JSString *right = str->ropeRight();
if (right->isRope()) {
JS_ASSERT(!Tagged(str->u.left) && !Tagged(str->s.right));
str->s.right = Tag(parent);
parent = str;
str = right;
goto first_visit_node;
}
NonRopeTypedMarker(right);
}
finish_node: {
if (!parent)
return;
if (Tagged(parent->u.left)) {
JS_ASSERT(!Tagged(parent->s.right));
JSString *nextParent = Untag(parent->u.left);
parent->u.left = str;
str = parent;
parent = nextParent;
goto visit_right_child;
}
JS_ASSERT(Tagged(parent->s.right));
JSString *nextParent = Untag(parent->s.right);
parent->s.right = str;
str = parent;
parent = nextParent;
goto finish_node;
}
} }
static inline void static inline void
@ -500,9 +453,8 @@ MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name)
for (uint32 i = 0; i < len; i++) { for (uint32 i = 0; i < len; i++) {
if (JSAtom *atom = vec[i]) { if (JSAtom *atom = vec[i]) {
JS_SET_TRACING_INDEX(trc, name, i); JS_SET_TRACING_INDEX(trc, name, i);
JSString *str = ATOM_TO_STRING(atom); if (!atom->isStaticAtom())
if (!str->isStaticAtom()) Mark(trc, atom);
Mark(trc, str);
} }
} }
} }

View File

@ -364,7 +364,7 @@ GCMarker::dumpConservativeRoots()
JSString *str = (JSString *) i->thing; JSString *str = (JSString *) i->thing;
if (str->isLinear()) { if (str->isLinear()) {
char buf[50]; char buf[50];
PutEscapedString(buf, sizeof buf, str->assertIsLinear(), '"'); PutEscapedString(buf, sizeof buf, &str->asLinear(), '"');
fprintf(fp, "string %s", buf); fprintf(fp, "string %s", buf);
} else { } else {
fprintf(fp, "rope: length %d", (int)str->length()); fprintf(fp, "rope: length %d", (int)str->length());

View File

@ -3906,7 +3906,7 @@ BEGIN_CASE(JSOP_TYPEOF)
const Value &ref = regs.sp[-1]; const Value &ref = regs.sp[-1];
JSType type = JS_TypeOfValue(cx, Jsvalify(ref)); JSType type = JS_TypeOfValue(cx, Jsvalify(ref));
JSAtom *atom = rt->atomState.typeAtoms[type]; JSAtom *atom = rt->atomState.typeAtoms[type];
regs.sp[-1].setString(ATOM_TO_STRING(atom)); regs.sp[-1].setString(atom);
} }
END_CASE(JSOP_TYPEOF) END_CASE(JSOP_TYPEOF)
@ -4325,7 +4325,7 @@ BEGIN_CASE(JSOP_CALLPROP)
#if JS_HAS_NO_SUCH_METHOD #if JS_HAS_NO_SUCH_METHOD
if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) { if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) {
LOAD_ATOM(0, atom); LOAD_ATOM(0, atom);
regs.sp[-2].setString(ATOM_TO_STRING(atom)); regs.sp[-2].setString(atom);
if (!js_OnUnknownMethod(cx, regs.sp - 2)) if (!js_OnUnknownMethod(cx, regs.sp - 2))
goto error; goto error;
} }
@ -4502,7 +4502,7 @@ BEGIN_CASE(JSOP_GETELEM)
JSString *str = lref.toString(); JSString *str = lref.toString();
int32_t i = rref.toInt32(); int32_t i = rref.toInt32();
if (size_t(i) < str->length()) { if (size_t(i) < str->length()) {
str = JSString::getUnitString(cx, str, size_t(i)); str = JSAtom::getUnitStringForElement(cx, str, size_t(i));
if (!str) if (!str)
goto error; goto error;
regs.sp--; regs.sp--;
@ -4945,7 +4945,7 @@ BEGIN_CASE(JSOP_STRING)
{ {
JSAtom *atom; JSAtom *atom;
LOAD_ATOM(0, atom); LOAD_ATOM(0, atom);
PUSH_STRING(ATOM_TO_STRING(atom)); PUSH_STRING(atom);
} }
END_CASE(JSOP_STRING) END_CASE(JSOP_STRING)
@ -5128,7 +5128,7 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
JSLinearString *str2; JSLinearString *str2;
SEARCH_PAIRS( SEARCH_PAIRS(
match = (rval.isString() && match = (rval.isString() &&
((str2 = rval.toString()->assertIsLinear()) == str || ((str2 = &rval.toString()->asLinear()) == str ||
EqualStrings(str2, str))); EqualStrings(str2, str)));
) )
} else if (lval.isNumber()) { } else if (lval.isNumber()) {
@ -6290,7 +6290,7 @@ BEGIN_CASE(JSOP_QNAMEPART)
{ {
JSAtom *atom; JSAtom *atom;
LOAD_ATOM(0, atom); LOAD_ATOM(0, atom);
PUSH_STRING(ATOM_TO_STRING(atom)); PUSH_STRING(atom);
} }
END_CASE(JSOP_QNAMEPART) END_CASE(JSOP_QNAMEPART)
@ -6298,7 +6298,7 @@ BEGIN_CASE(JSOP_QNAMECONST)
{ {
JSAtom *atom; JSAtom *atom;
LOAD_ATOM(0, atom); LOAD_ATOM(0, atom);
Value rval = StringValue(ATOM_TO_STRING(atom)); Value rval = StringValue(atom);
Value lval = regs.sp[-1]; Value lval = regs.sp[-1];
JSObject *obj = js_ConstructXMLQNameObject(cx, lval, rval); JSObject *obj = js_ConstructXMLQNameObject(cx, lval, rval);
if (!obj) if (!obj)
@ -6511,7 +6511,7 @@ BEGIN_CASE(JSOP_XMLCDATA)
{ {
JSAtom *atom; JSAtom *atom;
LOAD_ATOM(0, atom); LOAD_ATOM(0, atom);
JSString *str = ATOM_TO_STRING(atom); JSString *str = atom;
JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str); JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str);
if (!obj) if (!obj)
goto error; goto error;
@ -6523,7 +6523,7 @@ BEGIN_CASE(JSOP_XMLCOMMENT)
{ {
JSAtom *atom; JSAtom *atom;
LOAD_ATOM(0, atom); LOAD_ATOM(0, atom);
JSString *str = ATOM_TO_STRING(atom); JSString *str = atom;
JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str); JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str);
if (!obj) if (!obj)
goto error; goto error;
@ -6535,7 +6535,7 @@ BEGIN_CASE(JSOP_XMLPI)
{ {
JSAtom *atom; JSAtom *atom;
LOAD_ATOM(0, atom); LOAD_ATOM(0, atom);
JSString *str = ATOM_TO_STRING(atom); JSString *str = atom;
Value rval = regs.sp[-1]; Value rval = regs.sp[-1];
JSString *str2 = rval.toString(); JSString *str2 = rval.toString();
JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_PROCESSING_INSTRUCTION, str, str2); JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_PROCESSING_INSTRUCTION, str, str2);

View File

@ -1006,8 +1006,8 @@ js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
JSString *str; JSString *str;
jsint i; jsint i;
if (rval->isInt32() && (jsuint(i = rval->toInt32()) < INT_STRING_LIMIT)) { if (rval->isInt32() && JSAtom::hasIntStatic(i = rval->toInt32())) {
str = JSString::intString(i); str = &JSAtom::intStatic(i);
} else { } else {
str = js_ValueToString(cx, *rval); str = js_ValueToString(cx, *rval);
if (!str) if (!str)

View File

@ -663,7 +663,7 @@ math_tan(JSContext *cx, uintN argc, Value *vp)
static JSBool static JSBool
math_toSource(JSContext *cx, uintN argc, Value *vp) math_toSource(JSContext *cx, uintN argc, Value *vp)
{ {
vp->setString(ATOM_TO_STRING(CLASS_ATOM(cx, Math))); vp->setString(CLASS_ATOM(cx, Math));
return JS_TRUE; return JS_TRUE;
} }
#endif #endif

View File

@ -605,8 +605,8 @@ js_IntToString(JSContext *cx, int32 si)
{ {
uint32 ui; uint32 ui;
if (si >= 0) { if (si >= 0) {
if (si < INT_STRING_LIMIT) if (JSAtom::hasIntStatic(si))
return JSString::intString(si); return &JSAtom::intStatic(si);
ui = si; ui = si;
} else { } else {
ui = uint32(-si); ui = uint32(-si);
@ -621,10 +621,10 @@ js_IntToString(JSContext *cx, int32 si)
if (!str) if (!str)
return NULL; return NULL;
/* +1, since MAX_SHORT_STRING_LENGTH does not count the null char. */ /* +1, since MAX_LENGTH does not count the null char. */
JS_STATIC_ASSERT(JSShortString::MAX_SHORT_STRING_LENGTH + 1 >= sizeof("-2147483648")); JS_STATIC_ASSERT(JSShortString::MAX_LENGTH + 1 >= sizeof("-2147483648"));
jschar *end = str->getInlineStorageBeforeInit() + JSShortString::MAX_SHORT_STRING_LENGTH; jschar *end = str->inlineStorageBeforeInit() + JSShortString::MAX_SHORT_LENGTH;
jschar *cp = end; jschar *cp = end;
*cp = 0; *cp = 0;
@ -639,9 +639,8 @@ js_IntToString(JSContext *cx, int32 si)
str->initAtOffsetInBuffer(cp, end - cp); str->initAtOffsetInBuffer(cp, end - cp);
JSString *ret = str->header(); c->dtoaCache.cache(10, si, str);
c->dtoaCache.cache(10, si, ret); return str;
return ret;
} }
/* Returns a non-NULL pointer to inside cbuf. */ /* Returns a non-NULL pointer to inside cbuf. */
@ -1154,7 +1153,6 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
{ {
ToCStringBuf cbuf; ToCStringBuf cbuf;
char *numStr; char *numStr;
JSString *s;
/* /*
* Caller is responsible for error reporting. When called from trace, * Caller is responsible for error reporting. When called from trace,
@ -1168,21 +1166,23 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
int32_t i; int32_t i;
if (JSDOUBLE_IS_INT32(d, &i)) { if (JSDOUBLE_IS_INT32(d, &i)) {
if (base == 10 && jsuint(i) < INT_STRING_LIMIT) if (base == 10 && JSAtom::hasIntStatic(i))
return JSString::intString(i); return &JSAtom::intStatic(i);
if (jsuint(i) < jsuint(base)) { if (jsuint(i) < jsuint(base)) {
if (i < 10) if (i < 10)
return JSString::intString(i); return &JSAtom::intStatic(i);
return JSString::unitString(jschar('a' + i - 10)); jschar c = 'a' + i - 10;
JS_ASSERT(JSAtom::hasUnitStatic(c));
return &JSAtom::unitStatic(c);
} }
if (JSString *str = c->dtoaCache.lookup(base, d)) if (JSFlatString *str = c->dtoaCache.lookup(base, d))
return str; return str;
numStr = IntToCString(&cbuf, i, base); numStr = IntToCString(&cbuf, i, base);
JS_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize); JS_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize);
} else { } else {
if (JSString *str = c->dtoaCache.lookup(base, d)) if (JSFlatString *str = c->dtoaCache.lookup(base, d))
return str; return str;
numStr = FracNumberToCString(cx, &cbuf, d, base); numStr = FracNumberToCString(cx, &cbuf, d, base);
@ -1196,8 +1196,7 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
cbuf.dbuf && cbuf.dbuf == numStr); cbuf.dbuf && cbuf.dbuf == numStr);
} }
s = js_NewStringCopyZ(cx, numStr); JSFixedString *s = js_NewStringCopyZ(cx, numStr);
c->dtoaCache.cache(base, d, s); c->dtoaCache.cache(base, d, s);
return s; return s;
} }
@ -1210,11 +1209,11 @@ js_NumberToString(JSContext *cx, jsdouble d)
namespace js { namespace js {
JSFlatString * JSFixedString *
NumberToString(JSContext *cx, jsdouble d) NumberToString(JSContext *cx, jsdouble d)
{ {
if (JSString *str = js_NumberToStringWithBase(cx, d, 10)) if (JSString *str = js_NumberToStringWithBase(cx, d, 10))
return str->assertIsFlat(); return &str->asFixed();
return NULL; return NULL;
} }

View File

@ -207,7 +207,7 @@ extern bool JS_FASTCALL
NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb); NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb);
/* Same as js_NumberToString, different signature. */ /* Same as js_NumberToString, different signature. */
extern JSFlatString * extern JSFixedString *
NumberToString(JSContext *cx, jsdouble d); NumberToString(JSContext *cx, jsdouble d);
/* /*

View File

@ -590,13 +590,13 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
if (attrs & JSPROP_GETTER) { if (attrs & JSPROP_GETTER) {
doGet = false; doGet = false;
val[valcnt] = shape->getterValue(); val[valcnt] = shape->getterValue();
gsop[valcnt] = ATOM_TO_STRING(cx->runtime->atomState.getAtom); gsop[valcnt] = cx->runtime->atomState.getAtom;
valcnt++; valcnt++;
} }
if (attrs & JSPROP_SETTER) { if (attrs & JSPROP_SETTER) {
doGet = false; doGet = false;
val[valcnt] = shape->setterValue(); val[valcnt] = shape->setterValue();
gsop[valcnt] = ATOM_TO_STRING(cx->runtime->atomState.setAtom); gsop[valcnt] = cx->runtime->atomState.setAtom;
valcnt++; valcnt++;
} }
} }
@ -855,13 +855,13 @@ obj_toString(JSContext *cx, uintN argc, Value *vp)
/* Step 1. */ /* Step 1. */
if (thisv.isUndefined()) { if (thisv.isUndefined()) {
vp->setString(ATOM_TO_STRING(cx->runtime->atomState.objectUndefinedAtom)); vp->setString(cx->runtime->atomState.objectUndefinedAtom);
return true; return true;
} }
/* Step 2. */ /* Step 2. */
if (thisv.isNull()) { if (thisv.isNull()) {
vp->setString(ATOM_TO_STRING(cx->runtime->atomState.objectNullAtom)); vp->setString(cx->runtime->atomState.objectNullAtom);
return true; return true;
} }
@ -4420,8 +4420,7 @@ js_CheckForStringIndex(jsid id)
return id; return id;
JSAtom *atom = JSID_TO_ATOM(id); JSAtom *atom = JSID_TO_ATOM(id);
JSString *str = ATOM_TO_STRING(atom); const jschar *s = atom->chars();
const jschar *s = str->flatChars();
jschar ch = *s; jschar ch = *s;
JSBool negative = (ch == '-'); JSBool negative = (ch == '-');
@ -4431,7 +4430,7 @@ js_CheckForStringIndex(jsid id)
if (!JS7_ISDEC(ch)) if (!JS7_ISDEC(ch))
return id; return id;
size_t n = str->flatLength() - negative; size_t n = atom->length() - negative;
if (n > sizeof(JSBOXEDWORD_INT_MAX_STRING) - 1) if (n > sizeof(JSBOXEDWORD_INT_MAX_STRING) - 1)
return id; return id;
@ -6246,7 +6245,7 @@ js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, Value *rval)
{ {
Value argv[1]; Value argv[1];
argv[0].setString(ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type])); argv[0].setString(cx->runtime->atomState.typeAtoms[type]);
return js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom, return js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom,
1, argv, rval); 1, argv, rval);
} }
@ -6589,7 +6588,7 @@ JS_FRIEND_API(void)
js_DumpAtom(JSAtom *atom) js_DumpAtom(JSAtom *atom)
{ {
fprintf(stderr, "JSAtom* (%p) = ", (void *) atom); fprintf(stderr, "JSAtom* (%p) = ", (void *) atom);
js_DumpString(ATOM_TO_STRING(atom)); js_DumpString(atom);
} }
void void
@ -6610,7 +6609,7 @@ dumpValue(const Value &v)
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
if (fun->atom) { if (fun->atom) {
fputs("<function ", stderr); fputs("<function ", stderr);
FileEscapedString(stderr, ATOM_TO_STRING(fun->atom), 0); FileEscapedString(stderr, fun->atom, 0);
} else { } else {
fputs("<unnamed function", stderr); fputs("<unnamed function", stderr);
} }

View File

@ -58,13 +58,13 @@
#include "jsbool.h" #include "jsbool.h"
#include "jscntxt.h" #include "jscntxt.h"
#include "jsnum.h" #include "jsnum.h"
#include "jsscopeinlines.h"
#include "jsscriptinlines.h" #include "jsscriptinlines.h"
#include "jsstr.h" #include "jsstr.h"
#include "jsfuninlines.h" #include "jsfuninlines.h"
#include "jsgcinlines.h" #include "jsgcinlines.h"
#include "jsprobes.h" #include "jsprobes.h"
#include "jsscopeinlines.h"
inline bool inline bool
JSObject::preventExtensions(JSContext *cx, js::AutoIdVector *props) JSObject::preventExtensions(JSContext *cx, js::AutoIdVector *props)
@ -125,6 +125,39 @@ JSObject::syncSpecialEquality()
flags |= JSObject::HAS_EQUALITY; flags |= JSObject::HAS_EQUALITY;
} }
inline void
JSObject::trace(JSTracer *trc)
{
if (!isNative())
return;
JSContext *cx = trc->context;
js::Shape *shape = lastProp;
if (IS_GC_MARKING_TRACER(trc) && cx->runtime->gcRegenShapes) {
/*
* Either this object has its own shape, which must be regenerated, or
* it must have the same shape as lastProp.
*/
if (!shape->hasRegenFlag()) {
shape->shape = js_RegenerateShapeForGC(cx->runtime);
shape->setRegenFlag();
}
uint32 newShape = shape->shape;
if (hasOwnShape()) {
newShape = js_RegenerateShapeForGC(cx->runtime);
JS_ASSERT(newShape != shape->shape);
}
objShape = newShape;
}
/* Trace our property tree or dictionary ancestor line. */
do {
shape->trace(trc);
} while ((shape = shape->parent) != NULL && !shape->marked());
}
inline void inline void
JSObject::finalize(JSContext *cx) JSObject::finalize(JSContext *cx)
{ {
@ -670,7 +703,7 @@ JSObject::getNamePrefix() const
{ {
JS_ASSERT(isNamespace() || isQName()); JS_ASSERT(isNamespace() || isQName());
const js::Value &v = getSlot(JSSLOT_NAME_PREFIX); const js::Value &v = getSlot(JSSLOT_NAME_PREFIX);
return !v.isUndefined() ? v.toString()->assertIsLinear() : NULL; return !v.isUndefined() ? &v.toString()->asLinear() : NULL;
} }
inline jsval inline jsval
@ -699,7 +732,7 @@ JSObject::getNameURI() const
{ {
JS_ASSERT(isNamespace() || isQName()); JS_ASSERT(isNamespace() || isQName());
const js::Value &v = getSlot(JSSLOT_NAME_URI); const js::Value &v = getSlot(JSSLOT_NAME_URI);
return !v.isUndefined() ? v.toString()->assertIsLinear() : NULL; return !v.isUndefined() ? &v.toString()->asLinear() : NULL;
} }
inline jsval inline jsval
@ -735,7 +768,7 @@ JSObject::getQNameLocalName() const
{ {
JS_ASSERT(isQName()); JS_ASSERT(isQName());
const js::Value &v = getSlot(JSSLOT_QNAME_LOCAL_NAME); const js::Value &v = getSlot(JSSLOT_QNAME_LOCAL_NAME);
return !v.isUndefined() ? v.toString()->assertIsLinear() : NULL; return !v.isUndefined() ? &v.toString()->asLinear() : NULL;
} }
inline jsval inline jsval

View File

@ -64,6 +64,7 @@
#include "jsatominlines.h" #include "jsatominlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsstrinlines.h"
using namespace js; using namespace js;
using namespace js::gc; using namespace js::gc;
@ -1262,7 +1263,7 @@ js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len
static JSBool static JSBool
json_toSource(JSContext *cx, uintN argc, Value *vp) json_toSource(JSContext *cx, uintN argc, Value *vp)
{ {
vp->setString(ATOM_TO_STRING(CLASS_ATOM(cx, JSON))); vp->setString(CLASS_ATOM(cx, JSON));
return JS_TRUE; return JS_TRUE;
} }
#endif #endif

View File

@ -421,7 +421,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
v = Jsvalify(script->getConst(index)); v = Jsvalify(script->getConst(index));
} else { } else {
JS_GET_SCRIPT_ATOM(script, pc, index, atom); JS_GET_SCRIPT_ATOM(script, pc, index, atom);
v = ATOM_TO_JSVAL(atom); v = STRING_TO_JSVAL(atom);
} }
} else { } else {
if (type == JOF_OBJECT) if (type == JOF_OBJECT)
@ -440,7 +440,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
case JOF_GLOBAL: case JOF_GLOBAL:
atom = script->getGlobalAtom(GET_SLOTNO(pc)); atom = script->getGlobalAtom(GET_SLOTNO(pc));
v = ATOM_TO_JSVAL(atom); v = STRING_TO_JSVAL(atom);
{ {
JSAutoByteString bytes; JSAutoByteString bytes;
if (!ToDisassemblySource(cx, v, &bytes)) if (!ToDisassemblySource(cx, v, &bytes))
@ -528,7 +528,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
index = js_GetIndexFromBytecode(cx, script, pc, SLOTNO_LEN); index = js_GetIndexFromBytecode(cx, script, pc, SLOTNO_LEN);
if (type == JOF_SLOTATOM) { if (type == JOF_SLOTATOM) {
JS_GET_SCRIPT_ATOM(script, pc, index, atom); JS_GET_SCRIPT_ATOM(script, pc, index, atom);
v = ATOM_TO_JSVAL(atom); v = STRING_TO_JSVAL(atom);
} else { } else {
obj = script->getObject(index); obj = script->getObject(index);
v = OBJECT_TO_JSVAL(obj); v = OBJECT_TO_JSVAL(obj);
@ -1263,7 +1263,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
*/ */
todo = -1; todo = -1;
if (table[i].label) { if (table[i].label) {
str = ATOM_TO_STRING(table[i].label); str = table[i].label;
key = JSVAL_VOID; key = JSVAL_VOID;
} else if (JSVAL_IS_DOUBLE(key)) { } else if (JSVAL_IS_DOUBLE(key)) {
JSOp junk; JSOp junk;
@ -1385,7 +1385,7 @@ GetLocal(SprintStack *ss, jsint i)
LOCAL_ASSERT(JSID_IS_ATOM(shape.id)); LOCAL_ASSERT(JSID_IS_ATOM(shape.id));
JSAtom *atom = JSID_TO_ATOM(shape.id); JSAtom *atom = JSID_TO_ATOM(shape.id);
const char *rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); const char *rval = QuoteString(&ss->sprinter, atom, 0);
if (!rval) if (!rval)
return NULL; return NULL;
@ -1925,7 +1925,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
quote_ = 0; \ quote_ = 0; \
fmt = ufmt; \ fmt = ufmt; \
} \ } \
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), quote_); \ rval = QuoteString(&ss->sprinter, atom, quote_); \
if (!rval) \ if (!rval) \
return NULL; \ return NULL; \
JS_END_MACRO JS_END_MACRO
@ -2285,7 +2285,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case SRC_LABEL: case SRC_LABEL:
GET_SOURCE_NOTE_ATOM(sn, atom); GET_SOURCE_NOTE_ATOM(sn, atom);
jp->indent -= 4; jp->indent -= 4;
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); rval = QuoteString(&ss->sprinter, atom, 0);
if (!rval) if (!rval)
return NULL; return NULL;
RETRACT(&ss->sprinter, rval); RETRACT(&ss->sprinter, rval);
@ -2295,7 +2295,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case SRC_LABELBRACE: case SRC_LABELBRACE:
GET_SOURCE_NOTE_ATOM(sn, atom); GET_SOURCE_NOTE_ATOM(sn, atom);
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); rval = QuoteString(&ss->sprinter, atom, 0);
if (!rval) if (!rval)
return NULL; return NULL;
RETRACT(&ss->sprinter, rval); RETRACT(&ss->sprinter, rval);
@ -2707,7 +2707,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
ok = JS_TRUE; ok = JS_TRUE;
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
atom = atomv[i]; atom = atomv[i];
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); rval = QuoteString(&ss->sprinter, atom, 0);
if (!rval || if (!rval ||
!PushOff(ss, STR2OFF(&ss->sprinter, rval), op)) { !PushOff(ss, STR2OFF(&ss->sprinter, rval), op)) {
ok = JS_FALSE; ok = JS_FALSE;
@ -2781,7 +2781,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
i = GET_SLOTNO(pc) - jp->script->nfixed; i = GET_SLOTNO(pc) - jp->script->nfixed;
pc += JSOP_SETLOCALPOP_LENGTH; pc += JSOP_SETLOCALPOP_LENGTH;
atom = atomv[i - OBJ_BLOCK_DEPTH(cx, obj)]; atom = atomv[i - OBJ_BLOCK_DEPTH(cx, obj)];
str = ATOM_TO_STRING(atom); str = atom;
if (!QuoteString(&jp->sprinter, str, 0)) { if (!QuoteString(&jp->sprinter, str, 0)) {
ok = JS_FALSE; ok = JS_FALSE;
goto enterblock_out; goto enterblock_out;
@ -3243,7 +3243,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case SRC_CONT2LABEL: case SRC_CONT2LABEL:
GET_SOURCE_NOTE_ATOM(sn, atom); GET_SOURCE_NOTE_ATOM(sn, atom);
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); rval = QuoteString(&ss->sprinter, atom, 0);
if (!rval) if (!rval)
return NULL; return NULL;
RETRACT(&ss->sprinter, rval); RETRACT(&ss->sprinter, rval);
@ -3256,7 +3256,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case SRC_BREAK2LABEL: case SRC_BREAK2LABEL:
GET_SOURCE_NOTE_ATOM(sn, atom); GET_SOURCE_NOTE_ATOM(sn, atom);
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); rval = QuoteString(&ss->sprinter, atom, 0);
if (!rval) if (!rval)
return NULL; return NULL;
RETRACT(&ss->sprinter, rval); RETRACT(&ss->sprinter, rval);
@ -3434,7 +3434,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
atom = GetArgOrVarAtom(jp, i); atom = GetArgOrVarAtom(jp, i);
LOCAL_ASSERT(atom); LOCAL_ASSERT(atom);
todo = SprintCString(&ss->sprinter, VarPrefix(sn)); todo = SprintCString(&ss->sprinter, VarPrefix(sn));
if (todo < 0 || !QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) if (todo < 0 || !QuoteString(&ss->sprinter, atom, 0))
return NULL; return NULL;
break; break;
@ -3444,7 +3444,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
sn = js_GetSrcNote(jp->script, pc); sn = js_GetSrcNote(jp->script, pc);
todo = SprintCString(&ss->sprinter, VarPrefix(sn)); todo = SprintCString(&ss->sprinter, VarPrefix(sn));
if (todo < 0 || !QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) if (todo < 0 || !QuoteString(&ss->sprinter, atom, 0))
return NULL; return NULL;
break; break;
@ -3452,7 +3452,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
xval = NULL; xval = NULL;
LOAD_ATOM(0); LOAD_ATOM(0);
if (!ATOM_IS_IDENTIFIER(atom)) { if (!ATOM_IS_IDENTIFIER(atom)) {
xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), xval = QuoteString(&ss->sprinter, atom,
(jschar)'\''); (jschar)'\'');
if (!xval) if (!xval)
return NULL; return NULL;
@ -3465,7 +3465,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
todo = Sprint(&ss->sprinter, ss_format, lval, *lval ? "." : ""); todo = Sprint(&ss->sprinter, ss_format, lval, *lval ? "." : "");
if (todo < 0) if (todo < 0)
return NULL; return NULL;
if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0)) if (!QuoteString(&ss->sprinter, atom, 0))
return NULL; return NULL;
} }
break; break;
@ -3560,7 +3560,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
LOAD_ATOM(0); LOAD_ATOM(0);
do_setname: do_setname:
lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); lval = QuoteString(&ss->sprinter, atom, 0);
if (!lval) if (!lval)
return NULL; return NULL;
rval = POP_STR(); rval = POP_STR();
@ -3671,7 +3671,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_DELNAME: case JSOP_DELNAME:
LOAD_ATOM(0); LOAD_ATOM(0);
lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); lval = QuoteString(&ss->sprinter, atom, 0);
if (!lval) if (!lval)
return NULL; return NULL;
RETRACT(&ss->sprinter, lval); RETRACT(&ss->sprinter, lval);
@ -3731,7 +3731,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_DECGNAME: case JSOP_DECGNAME:
LOAD_ATOM(0); LOAD_ATOM(0);
do_incatom: do_incatom:
lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); lval = QuoteString(&ss->sprinter, atom, 0);
if (!lval) if (!lval)
return NULL; return NULL;
RETRACT(&ss->sprinter, lval); RETRACT(&ss->sprinter, lval);
@ -3787,7 +3787,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_GNAMEDEC: case JSOP_GNAMEDEC:
LOAD_ATOM(0); LOAD_ATOM(0);
do_atominc: do_atominc:
lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); lval = QuoteString(&ss->sprinter, atom, 0);
if (!lval) if (!lval)
return NULL; return NULL;
RETRACT(&ss->sprinter, lval); RETRACT(&ss->sprinter, lval);
@ -3866,7 +3866,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
do_getarg_prop: do_getarg_prop:
atom = GetArgOrVarAtom(ss->printer, i); atom = GetArgOrVarAtom(ss->printer, i);
LOCAL_ASSERT(atom); LOCAL_ASSERT(atom);
lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); lval = QuoteString(&ss->sprinter, atom, 0);
if (!lval || !PushOff(ss, STR2OFF(&ss->sprinter, lval), op)) if (!lval || !PushOff(ss, STR2OFF(&ss->sprinter, lval), op))
return NULL; return NULL;
@ -4002,8 +4002,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
do_qname: do_qname:
#endif #endif
sn = js_GetSrcNote(jp->script, pc); sn = js_GetSrcNote(jp->script, pc);
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), rval = QuoteString(&ss->sprinter, atom, inXML ? DONT_ESCAPE : 0);
inXML ? DONT_ESCAPE : 0);
if (!rval) if (!rval)
return NULL; return NULL;
RETRACT(&ss->sprinter, rval); RETRACT(&ss->sprinter, rval);
@ -4040,8 +4039,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_STRING: case JSOP_STRING:
LOAD_ATOM(0); LOAD_ATOM(0);
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), rval = QuoteString(&ss->sprinter, atom, inXML ? DONT_ESCAPE : '"');
inXML ? DONT_ESCAPE : '"');
if (!rval) if (!rval)
return NULL; return NULL;
todo = STR2OFF(&ss->sprinter, rval); todo = STR2OFF(&ss->sprinter, rval);
@ -4214,7 +4212,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_CALLEE: case JSOP_CALLEE:
JS_ASSERT(jp->fun && jp->fun->atom); JS_ASSERT(jp->fun && jp->fun->atom);
todo = SprintString(&ss->sprinter, ATOM_TO_STRING(jp->fun->atom)); todo = SprintString(&ss->sprinter, jp->fun->atom);
break; break;
case JSOP_OBJECT: case JSOP_OBJECT:
@ -4556,7 +4554,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_INITPROP: case JSOP_INITPROP:
case JSOP_INITMETHOD: case JSOP_INITMETHOD:
LOAD_ATOM(0); LOAD_ATOM(0);
xval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), xval = QuoteString(&ss->sprinter, atom,
jschar(ATOM_IS_IDENTIFIER(atom) ? 0 : '\'')); jschar(ATOM_IS_IDENTIFIER(atom) ? 0 : '\''));
if (!xval) if (!xval)
return NULL; return NULL;
@ -4644,7 +4642,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_QNAMECONST: case JSOP_QNAMECONST:
LOAD_ATOM(0); LOAD_ATOM(0);
rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); rval = QuoteString(&ss->sprinter, atom, 0);
if (!rval) if (!rval)
return NULL; return NULL;
RETRACT(&ss->sprinter, rval); RETRACT(&ss->sprinter, rval);
@ -4737,8 +4735,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_XMLCDATA: case JSOP_XMLCDATA:
LOAD_ATOM(0); LOAD_ATOM(0);
todo = SprintPut(&ss->sprinter, "<![CDATA[", 9); todo = SprintPut(&ss->sprinter, "<![CDATA[", 9);
if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), if (!QuoteString(&ss->sprinter, atom, DONT_ESCAPE))
DONT_ESCAPE))
return NULL; return NULL;
SprintPut(&ss->sprinter, "]]>", 3); SprintPut(&ss->sprinter, "]]>", 3);
break; break;
@ -4746,8 +4743,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_XMLCOMMENT: case JSOP_XMLCOMMENT:
LOAD_ATOM(0); LOAD_ATOM(0);
todo = SprintPut(&ss->sprinter, "<!--", 4); todo = SprintPut(&ss->sprinter, "<!--", 4);
if (!QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), if (!QuoteString(&ss->sprinter, atom, DONT_ESCAPE))
DONT_ESCAPE))
return NULL; return NULL;
SprintPut(&ss->sprinter, "-->", 3); SprintPut(&ss->sprinter, "-->", 3);
break; break;
@ -4758,7 +4754,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
if (!rval) if (!rval)
return NULL; return NULL;
todo = SprintPut(&ss->sprinter, "<?", 2); todo = SprintPut(&ss->sprinter, "<?", 2);
ok = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0) && ok = QuoteString(&ss->sprinter, atom, 0) &&
(*rval == '\0' || (*rval == '\0' ||
(SprintPut(&ss->sprinter, " ", 1) >= 0 && (SprintPut(&ss->sprinter, " ", 1) >= 0 &&
SprintCString(&ss->sprinter, rval))); SprintCString(&ss->sprinter, rval)));
@ -4972,7 +4968,7 @@ js_DecompileFunction(JSPrinter *jp)
} }
js_printf(jp, "%s ", js_function_str); js_printf(jp, "%s ", js_function_str);
if (fun->atom && !QuoteString(&jp->sprinter, ATOM_TO_STRING(fun->atom), 0)) if (fun->atom && !QuoteString(&jp->sprinter, fun->atom, 0))
return JS_FALSE; return JS_FALSE;
js_puts(jp, "("); js_puts(jp, "(");
@ -5041,7 +5037,7 @@ js_DecompileFunction(JSPrinter *jp)
#undef LOCAL_ASSERT #undef LOCAL_ASSERT
#endif #endif
if (!QuoteString(&jp->sprinter, ATOM_TO_STRING(param), 0)) { if (!QuoteString(&jp->sprinter, param, 0)) {
ok = JS_FALSE; ok = JS_FALSE;
break; break;
} }

View File

@ -9136,7 +9136,7 @@ FoldType(JSContext *cx, JSParseNode *pn, TokenKind type)
case TOK_NUMBER: case TOK_NUMBER:
if (pn->pn_type == TOK_STRING) { if (pn->pn_type == TOK_STRING) {
jsdouble d; jsdouble d;
if (!ValueToNumber(cx, StringValue(ATOM_TO_STRING(pn->pn_atom)), &d)) if (!ValueToNumber(cx, StringValue(pn->pn_atom), &d))
return JS_FALSE; return JS_FALSE;
pn->pn_dval = d; pn->pn_dval = d;
pn->pn_type = TOK_NUMBER; pn->pn_type = TOK_NUMBER;
@ -9265,9 +9265,9 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
str = NULL; str = NULL;
if ((pn->pn_xflags & PNX_CANTFOLD) == 0) { if ((pn->pn_xflags & PNX_CANTFOLD) == 0) {
if (tt == TOK_XMLETAGO) if (tt == TOK_XMLETAGO)
accum = ATOM_TO_STRING(cx->runtime->atomState.etagoAtom); accum = cx->runtime->atomState.etagoAtom;
else if (tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) else if (tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC)
accum = ATOM_TO_STRING(cx->runtime->atomState.stagoAtom); accum = cx->runtime->atomState.stagoAtom;
} }
/* /*
@ -9291,24 +9291,23 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
case TOK_STRING: case TOK_STRING:
if (pn2->pn_arity == PN_LIST) if (pn2->pn_arity == PN_LIST)
goto cantfold; goto cantfold;
str = ATOM_TO_STRING(pn2->pn_atom); str = pn2->pn_atom;
break; break;
case TOK_XMLCDATA: case TOK_XMLCDATA:
str = js_MakeXMLCDATAString(cx, ATOM_TO_STRING(pn2->pn_atom)); str = js_MakeXMLCDATAString(cx, pn2->pn_atom);
if (!str) if (!str)
return JS_FALSE; return JS_FALSE;
break; break;
case TOK_XMLCOMMENT: case TOK_XMLCOMMENT:
str = js_MakeXMLCommentString(cx, ATOM_TO_STRING(pn2->pn_atom)); str = js_MakeXMLCommentString(cx, pn2->pn_atom);
if (!str) if (!str)
return JS_FALSE; return JS_FALSE;
break; break;
case TOK_XMLPI: case TOK_XMLPI:
str = js_MakeXMLPIString(cx, ATOM_TO_STRING(pn2->pn_atom), str = js_MakeXMLPIString(cx, pn2->pn_atom, pn2->pn_atom2);
ATOM_TO_STRING(pn2->pn_atom2));
if (!str) if (!str)
return JS_FALSE; return JS_FALSE;
break; break;
@ -9369,9 +9368,9 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
str = NULL; str = NULL;
if ((pn->pn_xflags & PNX_CANTFOLD) == 0) { if ((pn->pn_xflags & PNX_CANTFOLD) == 0) {
if (tt == TOK_XMLPTAGC) if (tt == TOK_XMLPTAGC)
str = ATOM_TO_STRING(cx->runtime->atomState.ptagcAtom); str = cx->runtime->atomState.ptagcAtom;
else if (tt == TOK_XMLSTAGO || tt == TOK_XMLETAGO) else if (tt == TOK_XMLSTAGO || tt == TOK_XMLETAGO)
str = ATOM_TO_STRING(cx->runtime->atomState.tagcAtom); str = cx->runtime->atomState.tagcAtom;
} }
if (str) { if (str) {
accum = js_ConcatStrings(cx, accum, str); accum = js_ConcatStrings(cx, accum, str);
@ -9422,7 +9421,7 @@ Boolish(JSParseNode *pn)
return pn->pn_dval != 0 && !JSDOUBLE_IS_NaN(pn->pn_dval); return pn->pn_dval != 0 && !JSDOUBLE_IS_NaN(pn->pn_dval);
case JSOP_STRING: case JSOP_STRING:
return ATOM_TO_STRING(pn->pn_atom)->length() != 0; return pn->pn_atom->length() != 0;
#if JS_HAS_GENERATOR_EXPRS #if JS_HAS_GENERATOR_EXPRS
case JSOP_CALL: case JSOP_CALL:
@ -9596,7 +9595,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
pn2 = pn3; pn2 = pn3;
break; break;
case TOK_STRING: case TOK_STRING:
if (ATOM_TO_STRING(pn1->pn_atom)->length() == 0) if (pn1->pn_atom->length() == 0)
pn2 = pn3; pn2 = pn3;
break; break;
case TOK_PRIMARY: case TOK_PRIMARY:
@ -9708,10 +9707,6 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
case TOK_PLUS: case TOK_PLUS:
if (pn->pn_arity == PN_LIST) { if (pn->pn_arity == PN_LIST) {
size_t length, length2;
jschar *chars;
JSString *str, *str2;
/* /*
* Any string literal term with all others number or string means * Any string literal term with all others number or string means
* this is a concatenation. If any term is not a string or number * this is a concatenation. If any term is not a string or number
@ -9724,22 +9719,22 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
goto do_binary_op; goto do_binary_op;
/* Ok, we're concatenating: convert non-string constant operands. */ /* Ok, we're concatenating: convert non-string constant operands. */
length = 0; size_t length = 0;
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) { for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
if (!FoldType(cx, pn2, TOK_STRING)) if (!FoldType(cx, pn2, TOK_STRING))
return JS_FALSE; return JS_FALSE;
/* XXX fold only if all operands convert to string */ /* XXX fold only if all operands convert to string */
if (pn2->pn_type != TOK_STRING) if (pn2->pn_type != TOK_STRING)
return JS_TRUE; return JS_TRUE;
length += ATOM_TO_STRING(pn2->pn_atom)->flatLength(); length += pn2->pn_atom->length();
} }
/* Allocate a new buffer and string descriptor for the result. */ /* Allocate a new buffer and string descriptor for the result. */
chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar)); jschar *chars = (jschar *) cx->malloc((length + 1) * sizeof(jschar));
if (!chars) if (!chars)
return JS_FALSE; return JS_FALSE;
chars[length] = 0; chars[length] = 0;
str = js_NewString(cx, chars, length); JSString *str = js_NewString(cx, chars, length);
if (!str) { if (!str) {
cx->free(chars); cx->free(chars);
return JS_FALSE; return JS_FALSE;
@ -9747,9 +9742,9 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
/* Fill the buffer, advancing chars and recycling kids as we go. */ /* Fill the buffer, advancing chars and recycling kids as we go. */
for (pn2 = pn1; pn2; pn2 = RecycleTree(pn2, tc)) { for (pn2 = pn1; pn2; pn2 = RecycleTree(pn2, tc)) {
str2 = ATOM_TO_STRING(pn2->pn_atom); JSAtom *atom = pn2->pn_atom;
length2 = str2->flatLength(); size_t length2 = atom->length();
js_strncpy(chars, str2->flatChars(), length2); js_strncpy(chars, atom->chars(), length2);
chars += length2; chars += length2;
} }
JS_ASSERT(*chars == 0); JS_ASSERT(*chars == 0);
@ -9775,8 +9770,8 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
} }
if (pn1->pn_type != TOK_STRING || pn2->pn_type != TOK_STRING) if (pn1->pn_type != TOK_STRING || pn2->pn_type != TOK_STRING)
return JS_TRUE; return JS_TRUE;
left = ATOM_TO_STRING(pn1->pn_atom); left = pn1->pn_atom;
right = ATOM_TO_STRING(pn2->pn_atom); right = pn2->pn_atom;
str = js_ConcatStrings(cx, left, right); str = js_ConcatStrings(cx, left, right);
if (!str) if (!str)
return JS_FALSE; return JS_FALSE;
@ -9898,7 +9893,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
if (pn1->pn_type == TOK_XMLNAME) { if (pn1->pn_type == TOK_XMLNAME) {
JSObjectBox *xmlbox; JSObjectBox *xmlbox;
Value v = StringValue(ATOM_TO_STRING(pn1->pn_atom)); Value v = StringValue(pn1->pn_atom);
if (!js_ToAttributeName(cx, &v)) if (!js_ToAttributeName(cx, &v))
return JS_FALSE; return JS_FALSE;
JS_ASSERT(v.isObject()); JS_ASSERT(v.isObject());

View File

@ -601,7 +601,7 @@ public:
*/ */
bool isEscapeFreeStringLiteral() const { bool isEscapeFreeStringLiteral() const {
JS_ASSERT(pn_type == js::TOK_STRING && !pn_parens); JS_ASSERT(pn_type == js::TOK_STRING && !pn_parens);
JSString *str = ATOM_TO_STRING(pn_atom); JSString *str = pn_atom;
/* /*
* If the string's length in the source code is its length as a value, * If the string's length in the source code is its length as a value,

View File

@ -140,7 +140,7 @@ Probes::FunctionName(JSContext *cx, const JSFunction *fun, JSAutoByteString *byt
return nullName; return nullName;
} }
return bytes->encode(cx, ATOM_TO_STRING(atom)) ? bytes->ptr() : nullName; return bytes->encode(cx, atom) ? bytes->ptr() : nullName;
} }
#ifdef INCLUDE_MOZILLA_DTRACE #ifdef INCLUDE_MOZILLA_DTRACE

View File

@ -93,8 +93,6 @@ typedef struct JSTreeContext JSTreeContext;
typedef struct JSTryNote JSTryNote; typedef struct JSTryNote JSTryNote;
/* Friend "Advanced API" typedefs. */ /* Friend "Advanced API" typedefs. */
typedef struct JSLinearString JSLinearString;
typedef struct JSAtom JSAtom;
typedef struct JSAtomList JSAtomList; typedef struct JSAtomList JSAtomList;
typedef struct JSAtomListElement JSAtomListElement; typedef struct JSAtomListElement JSAtomListElement;
typedef struct JSAtomMap JSAtomMap; typedef struct JSAtomMap JSAtomMap;
@ -118,8 +116,17 @@ typedef struct JSXMLArrayCursor JSXMLArrayCursor;
* templates. * templates.
*/ */
#ifdef __cplusplus #ifdef __cplusplus
extern "C++" { extern "C++" {
class JSDependentString;
class JSExtensibleString;
class JSLinearString;
class JSFixedString;
class JSStaticAtom;
class JSRope;
class JSAtom;
namespace js { namespace js {
struct ArgumentsData; struct ArgumentsData;
@ -177,6 +184,11 @@ class Bindings;
} /* namespace js */ } /* namespace js */
} /* export "C++" */ } /* export "C++" */
#else
typedef struct JSAtom JSAtom;
#endif /* __cplusplus */ #endif /* __cplusplus */
/* "Friend" types used by jscntxt.h and jsdbgapi.h. */ /* "Friend" types used by jscntxt.h and jsdbgapi.h. */

View File

@ -317,7 +317,7 @@ class NodeBuilder
if (!atom) if (!atom)
return false; return false;
*dst = Valueify(ATOM_TO_JSVAL(atom)); dst->setString(atom);
return true; return true;
} }
@ -1613,7 +1613,7 @@ class ASTSerializer
uint32 lineno; uint32 lineno;
Value atomContents(JSAtom *atom) { Value atomContents(JSAtom *atom) {
return Valueify(ATOM_TO_JSVAL(atom ? atom : cx->runtime->atomState.emptyAtom)); return StringValue(atom ? atom : cx->runtime->atomState.emptyAtom);
} }
BinaryOperator binop(TokenKind tk, JSOp op); BinaryOperator binop(TokenKind tk, JSOp op);
@ -2886,7 +2886,7 @@ ASTSerializer::literal(JSParseNode *pn, Value *dst)
Value val; Value val;
switch (PN_TYPE(pn)) { switch (PN_TYPE(pn)) {
case TOK_STRING: case TOK_STRING:
val = Valueify(ATOM_TO_JSVAL(pn->pn_atom)); val.setString(pn->pn_atom);
break; break;
case TOK_REGEXP: case TOK_REGEXP:

View File

@ -42,7 +42,10 @@
#include "jsregexp.h" #include "jsregexp.h"
#include "jscntxt.h" #include "jscntxt.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsstrinlines.h"
#include "assembler/wtf/Platform.h" #include "assembler/wtf/Platform.h"
#if ENABLE_YARR_JIT #if ENABLE_YARR_JIT

View File

@ -57,7 +57,6 @@
#include "jsprvtd.h" #include "jsprvtd.h"
#include "jspubtd.h" #include "jspubtd.h"
#include "jspropertytree.h" #include "jspropertytree.h"
#include "jsstrinlines.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)

View File

@ -132,39 +132,6 @@ JSObject::extend(JSContext *cx, const js::Shape *shape, bool isDefinitelyAtom)
updateShape(cx); updateShape(cx);
} }
inline void
JSObject::trace(JSTracer *trc)
{
if (!isNative())
return;
JSContext *cx = trc->context;
js::Shape *shape = lastProp;
if (IS_GC_MARKING_TRACER(trc) && cx->runtime->gcRegenShapes) {
/*
* Either this object has its own shape, which must be regenerated, or
* it must have the same shape as lastProp.
*/
if (!shape->hasRegenFlag()) {
shape->shape = js_RegenerateShapeForGC(cx->runtime);
shape->setRegenFlag();
}
uint32 newShape = shape->shape;
if (hasOwnShape()) {
newShape = js_RegenerateShapeForGC(cx->runtime);
JS_ASSERT(newShape != shape->shape);
}
objShape = newShape;
}
/* Trace our property tree or dictionary ancestor line. */
do {
shape->trace(trc);
} while ((shape = shape->parent) != NULL && !shape->marked());
}
namespace js { namespace js {
inline inline

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -41,7 +41,9 @@
#define jsstrinlines_h___ #define jsstrinlines_h___
#include "jsstr.h" #include "jsstr.h"
#include "jscntxtinlines.h" #include "jscntxtinlines.h"
#include "jsgcinlines.h"
namespace js { namespace js {
@ -49,6 +51,16 @@ static inline bool
CheckStringLength(JSContext *cx, size_t length) CheckStringLength(JSContext *cx, size_t length)
{ {
if (JS_UNLIKELY(length > JSString::MAX_LENGTH)) { if (JS_UNLIKELY(length > JSString::MAX_LENGTH)) {
if (JS_ON_TRACE(cx)) {
/*
* If we can't leave the trace, signal OOM condition, otherwise
* exit from trace before throwing.
*/
if (!CanLeaveTrace(cx))
return NULL;
LeaveTrace(cx);
}
js_ReportAllocationOverflow(cx); js_ReportAllocationOverflow(cx);
return false; return false;
} }
@ -116,7 +128,7 @@ class StringBuffer
* This method takes responsibility for adding the terminating '\0' * This method takes responsibility for adding the terminating '\0'
* required by js_NewString. * required by js_NewString.
*/ */
JSFlatString *finishString(); JSFixedString *finishString();
template <size_t ArrayLength> template <size_t ArrayLength>
bool append(const char (&array)[ArrayLength]) { bool append(const char (&array)[ArrayLength]) {
@ -227,73 +239,206 @@ StringBuffer::checkLength(size_t length)
} /* namespace js */ } /* namespace js */
inline JSFlatString * JS_ALWAYS_INLINE void
JSString::unitString(jschar c) JSRope::init(JSString *left, JSString *right, size_t length)
{ {
JS_ASSERT(c < UNIT_STRING_LIMIT); d.lengthAndFlags = buildLengthAndFlags(length, ROPE_BIT);
return const_cast<JSString *>(&unitStringTable[c])->assertIsFlat(); d.u1.left = left;
d.s.u2.right = right;
}
JS_ALWAYS_INLINE JSRope *
JSRope::new_(JSContext *cx, JSString *left, JSString *right, size_t length)
{
JSRope *str = (JSRope *)js_NewGCString(cx);
if (!str)
return NULL;
str->init(left, right, length);
return str;
}
JS_ALWAYS_INLINE void
JSDependentString::init(JSLinearString *base, const jschar *chars, size_t length)
{
d.lengthAndFlags = buildLengthAndFlags(length, DEPENDENT_BIT);
d.u1.chars = chars;
d.s.u2.base = base;
}
JS_ALWAYS_INLINE JSDependentString *
JSDependentString::new_(JSContext *cx, JSLinearString *base, const jschar *chars, size_t length)
{
/* Try to avoid long chains of dependent strings. */
while (base->isDependent())
base = base->asDependent().base();
JS_ASSERT(base->isFlat());
JS_ASSERT(chars >= base->chars() && chars < base->chars() + base->length());
JS_ASSERT(length <= base->length() - (chars - base->chars()));
JSDependentString *str = (JSDependentString *)js_NewGCString(cx);
if (!str)
return NULL;
str->init(base, chars, length);
#ifdef DEBUG
JSRuntime *rt = cx->runtime;
JS_RUNTIME_METER(rt, liveDependentStrings);
JS_RUNTIME_METER(rt, totalDependentStrings);
JS_RUNTIME_METER(rt, liveStrings);
JS_RUNTIME_METER(rt, totalStrings);
JS_LOCK_RUNTIME_VOID(rt,
(rt->strdepLengthSum += (double)length,
rt->strdepLengthSquaredSum += (double)length * (double)length));
JS_LOCK_RUNTIME_VOID(rt,
(rt->lengthSum += (double)length,
rt->lengthSquaredSum += (double)length * (double)length));
#endif
return str;
}
JS_ALWAYS_INLINE void
JSFixedString::init(const jschar *chars, size_t length)
{
d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
d.u1.chars = chars;
}
JS_ALWAYS_INLINE JSFixedString *
JSFixedString::new_(JSContext *cx, const jschar *chars, size_t length)
{
JS_ASSERT(length <= MAX_LENGTH);
JS_ASSERT(chars[length] == jschar(0));
JSFixedString *str = (JSFixedString *)js_NewGCString(cx);
if (!str)
return NULL;
str->init(chars, length);
cx->runtime->stringMemoryUsed += length * 2;
#ifdef DEBUG
JSRuntime *rt = cx->runtime;
JS_RUNTIME_METER(rt, liveStrings);
JS_RUNTIME_METER(rt, totalStrings);
JS_LOCK_RUNTIME_VOID(rt,
(rt->lengthSum += (double)length,
rt->lengthSquaredSum += (double)length * (double)length));
#endif
return str;
}
JS_ALWAYS_INLINE JSAtom *
JSFixedString::morphInternedStringIntoAtom()
{
JS_ASSERT((d.lengthAndFlags & FLAGS_MASK) == JS_BIT(2));
JS_STATIC_ASSERT(NON_STATIC_ATOM == JS_BIT(3));
d.lengthAndFlags ^= (JS_BIT(2) | JS_BIT(3));
return &asAtom();
}
JS_ALWAYS_INLINE void
JSExternalString::init(const jschar *chars, size_t length, intN type)
{
d.lengthAndFlags = buildLengthAndFlags(length, FIXED_FLAGS);
d.u1.chars = chars;
d.s.u2.externalStringType = type;
}
JS_ALWAYS_INLINE JSExternalString *
JSExternalString::new_(JSContext *cx, const jschar *chars, size_t length, intN type)
{
JS_ASSERT(uintN(type) < JSExternalString::TYPE_LIMIT);
JS_ASSERT(chars[length] == 0);
JSExternalString *str = (JSExternalString *)js_NewGCExternalString(cx, type);
if (!str)
return NULL;
str->init(chars, length, type);
cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
return str;
}
inline bool
JSAtom::fitsInSmallChar(jschar c)
{
return c < SMALL_CHAR_LIMIT && toSmallChar[c] != INVALID_SMALL_CHAR;
}
inline bool
JSAtom::hasUnitStatic(jschar c)
{
return c < UNIT_STATIC_LIMIT;
}
inline JSStaticAtom &
JSAtom::unitStatic(jschar c)
{
JS_ASSERT(hasUnitStatic(c));
return (JSStaticAtom &)unitStaticTable[c];
}
inline bool
JSAtom::hasIntStatic(int32 i)
{
return uint32(i) < INT_STATIC_LIMIT;
}
inline JSStaticAtom &
JSAtom::intStatic(jsint i)
{
JS_ASSERT(hasIntStatic(i));
return (JSStaticAtom &)*intStaticTable[i];
} }
inline JSLinearString * inline JSLinearString *
JSString::getUnitString(JSContext *cx, JSString *str, size_t index) JSAtom::getUnitStringForElement(JSContext *cx, JSString *str, size_t index)
{ {
JS_ASSERT(index < str->length()); JS_ASSERT(index < str->length());
const jschar *chars = str->getChars(cx); const jschar *chars = str->getChars(cx);
if (!chars) if (!chars)
return NULL; return NULL;
jschar c = chars[index]; jschar c = chars[index];
if (c < UNIT_STRING_LIMIT) if (c < UNIT_STATIC_LIMIT)
return unitString(c); return &unitStatic(c);
return js_NewDependentString(cx, str, index, 1); return js_NewDependentString(cx, str, index, 1);
} }
inline JSFlatString * inline JSStaticAtom &
JSString::length2String(jschar c1, jschar c2) JSAtom::length2Static(jschar c1, jschar c2)
{ {
JS_ASSERT(fitsInSmallChar(c1)); JS_ASSERT(fitsInSmallChar(c1));
JS_ASSERT(fitsInSmallChar(c2)); JS_ASSERT(fitsInSmallChar(c2));
return const_cast<JSString *> ( size_t index = (((size_t)toSmallChar[c1]) << 6) + toSmallChar[c2];
&length2StringTable[(((size_t)toSmallChar[c1]) << 6) + toSmallChar[c2]] return (JSStaticAtom &)length2StaticTable[index];
)->assertIsFlat();
} }
inline JSFlatString * inline JSStaticAtom &
JSString::length2String(uint32 i) JSAtom::length2Static(uint32 i)
{ {
JS_ASSERT(i < 100); JS_ASSERT(i < 100);
return length2String('0' + i / 10, '0' + i % 10); return length2Static('0' + i / 10, '0' + i % 10);
}
inline JSFlatString *
JSString::intString(jsint i)
{
jsuint u = jsuint(i);
JS_ASSERT(u < INT_STRING_LIMIT);
return const_cast<JSString *>(JSString::intStringTable[u])->assertIsFlat();
} }
/* Get a static atomized string for chars if possible. */ /* Get a static atomized string for chars if possible. */
inline JSFlatString * inline JSStaticAtom *
JSString::lookupStaticString(const jschar *chars, size_t length) JSAtom::lookupStatic(const jschar *chars, size_t length)
{ {
if (length == 1) { switch (length) {
if (chars[0] < UNIT_STRING_LIMIT) case 1:
return unitString(chars[0]); if (chars[0] < UNIT_STATIC_LIMIT)
} return &unitStatic(chars[0]);
return NULL;
if (length == 2) { case 2:
if (fitsInSmallChar(chars[0]) && fitsInSmallChar(chars[1])) if (fitsInSmallChar(chars[0]) && fitsInSmallChar(chars[1]))
return length2String(chars[0], chars[1]); return &length2Static(chars[0], chars[1]);
} return NULL;
case 3:
/* /*
* Here we know that JSString::intStringTable covers only 256 (or at least * Here we know that JSString::intStringTable covers only 256 (or at least
* not 1000 or more) chars. We rely on order here to resolve the unit vs. * not 1000 or more) chars. We rely on order here to resolve the unit vs.
* int string/length-2 string atom identity issue by giving priority to unit * int string/length-2 string atom identity issue by giving priority to unit
* strings for "0" through "9" and length-2 strings for "10" through "99". * strings for "0" through "9" and length-2 strings for "10" through "99".
*/ */
JS_STATIC_ASSERT(INT_STRING_LIMIT <= 999); JS_STATIC_ASSERT(INT_STATIC_LIMIT <= 999);
if (length == 3) {
if ('1' <= chars[0] && chars[0] <= '9' && if ('1' <= chars[0] && chars[0] <= '9' &&
'0' <= chars[1] && chars[1] <= '9' && '0' <= chars[1] && chars[1] <= '9' &&
'0' <= chars[2] && chars[2] <= '9') { '0' <= chars[2] && chars[2] <= '9') {
@ -301,60 +446,51 @@ JSString::lookupStaticString(const jschar *chars, size_t length)
(chars[1] - '0') * 10 + (chars[1] - '0') * 10 +
(chars[2] - '0'); (chars[2] - '0');
if (jsuint(i) < INT_STRING_LIMIT) if (jsuint(i) < INT_STATIC_LIMIT)
return intString(i); return &intStatic(i);
} }
return NULL;
} }
return NULL; return NULL;
} }
inline void JS_ALWAYS_INLINE void
JSString::finalize(JSContext *cx) { JSString::finalize(JSContext *cx)
JS_ASSERT(!isStaticAtom()); {
JS_ASSERT(!isStaticAtom() && !isShort());
JS_RUNTIME_UNMETER(cx->runtime, liveStrings); JS_RUNTIME_UNMETER(cx->runtime, liveStrings);
if (isDependent()) { if (isDependent()) {
JS_RUNTIME_UNMETER(cx->runtime, liveDependentStrings); JS_RUNTIME_UNMETER(cx->runtime, liveDependentStrings);
} else if (isFlat()) { } else if (isFlat()) {
/*
* flatChars for stillborn string is null, but cx->free checks
* for a null pointer on its own.
*/
cx->runtime->stringMemoryUsed -= length() * 2; cx->runtime->stringMemoryUsed -= length() * 2;
cx->free(const_cast<jschar *>(flatChars())); cx->free(const_cast<jschar *>(asFlat().chars()));
} else {
JS_ASSERT(isRope());
} }
} }
inline void inline void
JSShortString::finalize(JSContext *cx) JSShortString::finalize(JSContext *cx)
{ {
JS_ASSERT(!mHeader.isStaticAtom()); JS_ASSERT(isShort());
JS_ASSERT(mHeader.isFlat());
JS_RUNTIME_UNMETER(cx->runtime, liveStrings); JS_RUNTIME_UNMETER(cx->runtime, liveStrings);
} }
inline void inline void
JSExternalString::finalize(JSContext *cx) JSExternalString::finalize(JSContext *cx)
{ {
JS_ASSERT(unsigned(externalStringType) < JS_ARRAY_LENGTH(str_finalizers));
JS_ASSERT(!isStaticAtom());
JS_ASSERT(isFlat());
JS_RUNTIME_UNMETER(cx->runtime, liveStrings); JS_RUNTIME_UNMETER(cx->runtime, liveStrings);
if (JSStringFinalizeOp finalizer = str_finalizers[externalStringType()])
/* A stillborn string has null chars. */
jschar *chars = const_cast<jschar *>(flatChars());
if (!chars)
return;
JSStringFinalizeOp finalizer = str_finalizers[externalStringType];
if (finalizer)
finalizer(cx, this); finalizer(cx, this);
} }
inline void inline void
JSExternalString::finalize() JSExternalString::finalize()
{ {
JS_ASSERT(unsigned(externalStringType) < JS_ARRAY_LENGTH(str_finalizers)); JSStringFinalizeOp finalizer = str_finalizers[externalStringType()];
JSStringFinalizeOp finalizer = str_finalizers[externalStringType];
if (finalizer) { if (finalizer) {
/* /*
* Assume that the finalizer for the permanently interned * Assume that the finalizer for the permanently interned
@ -392,15 +528,16 @@ class StringSegmentRange
* StackAllocPolicy which stashes a reusable freed-at-gc buffer in the cx. * StackAllocPolicy which stashes a reusable freed-at-gc buffer in the cx.
*/ */
Vector<JSString *, 32> stack; Vector<JSString *, 32> stack;
JSString *cur; JSLinearString *cur;
bool settle(JSString *str) { bool settle(JSString *str) {
while (str->isRope()) { while (str->isRope()) {
if (!stack.append(str->ropeRight())) JSRope &rope = str->asRope();
if (!stack.append(rope.rightChild()))
return false; return false;
str = str->ropeLeft(); str = rope.leftChild();
} }
cur = str; cur = &str->asLinear();
return true; return true;
} }
@ -418,7 +555,7 @@ class StringSegmentRange
return cur == NULL; return cur == NULL;
} }
JSString *front() const { JSLinearString *front() const {
JS_ASSERT(!cur->isRope()); JS_ASSERT(!cur->isRope());
return cur; return cur;
} }

View File

@ -902,7 +902,7 @@ FragProfiling_showResults(TraceMonitor* tm)
/* ----------------------------------------------------------------- */ /* ----------------------------------------------------------------- */
#ifdef DEBUG #ifdef DEBUG
static JSBool FASTCALL JSBool FASTCALL
PrintOnTrace(char* format, uint32 argc, double *argv) PrintOnTrace(char* format, uint32 argc, double *argv)
{ {
union { union {
@ -974,7 +974,10 @@ PrintOnTrace(char* format, uint32 argc, double *argv)
fprintf(out, "<rope>"); fprintf(out, "<rope>");
break; break;
} }
const jschar *chars = u.s->nonRopeChars(); if (u.s->isRope()) {
fprintf(out, "<rope: length %d>", (int)u.s->asRope().length());
} else {
const jschar *chars = u.s->asLinear().chars();
for (unsigned i = 0; i < length; ++i) { for (unsigned i = 0; i < length; ++i) {
jschar co = chars[i]; jschar co = chars[i];
if (co < 128) if (co < 128)
@ -985,6 +988,7 @@ PrintOnTrace(char* format, uint32 argc, double *argv)
fprintf(out, "\\u%04x", co); fprintf(out, "\\u%04x", co);
} }
} }
}
break; break;
case 'S': case 'S':
GET_ARG(); GET_ARG();
@ -2750,7 +2754,7 @@ ValueToNative(const Value &v, JSValueType type, double* slot)
if (LogController.lcbits & LC_TMTracer) { if (LogController.lcbits & LC_TMTracer) {
char funName[40]; char funName[40];
if (fun->atom) if (fun->atom)
JS_PutEscapedFlatString(funName, sizeof funName, ATOM_TO_STRING(fun->atom), 0); JS_PutEscapedFlatString(funName, sizeof funName, fun->atom, 0);
else else
strcpy(funName, "unnamed"); strcpy(funName, "unnamed");
LogController.printf("function<%p:%s> ", (void*)*(JSObject **)slot, funName); LogController.printf("function<%p:%s> ", (void*)*(JSObject **)slot, funName);
@ -2979,7 +2983,7 @@ NativeToValue(JSContext* cx, Value& v, JSValueType type, double* slot)
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &v.toObject()); JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &v.toObject());
char funName[40]; char funName[40];
if (fun->atom) if (fun->atom)
JS_PutEscapedFlatString(funName, sizeof funName, ATOM_TO_STRING(fun->atom), 0); JS_PutEscapedFlatString(funName, sizeof funName, fun->atom, 0);
else else
strcpy(funName, "unnamed"); strcpy(funName, "unnamed");
LogController.printf("function<%p:%s> ", (void*) &v.toObject(), funName); LogController.printf("function<%p:%s> ", (void*) &v.toObject(), funName);
@ -11601,7 +11605,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
#ifdef DEBUG #ifdef DEBUG
ci->_name = js_anonymous_str; ci->_name = js_anonymous_str;
if (fun->atom) { if (fun->atom) {
JSAutoByteString bytes(cx, ATOM_TO_STRING(fun->atom)); JSAutoByteString bytes(cx, fun->atom);
if (!!bytes) { if (!!bytes) {
size_t n = strlen(bytes.ptr()) + 1; size_t n = strlen(bytes.ptr()) + 1;
char *buffer = new (traceAlloc()) char[n]; char *buffer = new (traceAlloc()) char[n];
@ -12523,7 +12527,7 @@ RootedStringToId(JSContext* cx, JSString** namep, jsid* idp)
JSAtom* atom = js_AtomizeString(cx, name, 0); JSAtom* atom = js_AtomizeString(cx, name, 0);
if (!atom) if (!atom)
return false; return false;
*namep = ATOM_TO_STRING(atom); /* write back to GC root */ *namep = atom; /* write back to GC root */
*idp = ATOM_TO_JSID(atom); *idp = ATOM_TO_JSID(atom);
return true; return true;
} }
@ -12850,7 +12854,7 @@ TraceRecorder::getCharCodeAt(JSString *str, LIns* str_ins, LIns* idx_ins, LIns**
if (MaybeBranch mbr = w.jt(w.eqp0(w.andp(lengthAndFlags_ins, w.nameImmw(JSString::ROPE_BIT))))) if (MaybeBranch mbr = w.jt(w.eqp0(w.andp(lengthAndFlags_ins, w.nameImmw(JSString::ROPE_BIT)))))
{ {
LIns *args[] = { str_ins, cx_ins }; LIns *args[] = { str_ins, cx_ins };
LIns *ok_ins = w.call(&js_Flatten_ci, args); LIns *ok_ins = w.call(&js_FlattenOnTrace_ci, args);
guard(false, w.eqi0(ok_ins), OOM_EXIT); guard(false, w.eqi0(ok_ins), OOM_EXIT);
w.label(mbr); w.label(mbr);
} }
@ -12869,8 +12873,9 @@ JS_REQUIRES_STACK LIns*
TraceRecorder::getUnitString(LIns* str_ins, LIns* idx_ins) TraceRecorder::getUnitString(LIns* str_ins, LIns* idx_ins)
{ {
LIns *ch_ins = w.getStringChar(str_ins, idx_ins); LIns *ch_ins = w.getStringChar(str_ins, idx_ins);
guard(true, w.ltuiN(ch_ins, UNIT_STRING_LIMIT), MISMATCH_EXIT); guard(true, w.ltuiN(ch_ins, JSAtom::UNIT_STATIC_LIMIT), MISMATCH_EXIT);
return w.addp(w.nameImmpNonGC(JSString::unitStringTable), JS_STATIC_ASSERT(sizeof(JSString) == 16 || sizeof(JSString) == 32);
return w.addp(w.nameImmpNonGC(JSAtom::unitStaticTable),
w.lshpN(w.ui2p(ch_ins), (sizeof(JSString) == 16) ? 4 : 5)); w.lshpN(w.ui2p(ch_ins), (sizeof(JSString) == 16) ? 4 : 5));
} }
@ -12884,7 +12889,7 @@ TraceRecorder::getCharAt(JSString *str, LIns* str_ins, LIns* idx_ins, JSOp mode,
w.nameImmw(JSString::ROPE_BIT))))) w.nameImmw(JSString::ROPE_BIT)))))
{ {
LIns *args[] = { str_ins, cx_ins }; LIns *args[] = { str_ins, cx_ins };
LIns *ok_ins = w.call(&js_Flatten_ci, args); LIns *ok_ins = w.call(&js_FlattenOnTrace_ci, args);
guard(false, w.eqi0(ok_ins), OOM_EXIT); guard(false, w.eqi0(ok_ins), OOM_EXIT);
w.label(mbr); w.label(mbr);
} }

View File

@ -1138,7 +1138,7 @@ class TraceRecorder
#define immpObjGC(obj) name(w_immpObjGC(obj), #obj) #define immpObjGC(obj) name(w_immpObjGC(obj), #obj)
#define immpFunGC(fun) name(w_immpFunGC(fun), #fun) #define immpFunGC(fun) name(w_immpFunGC(fun), #fun)
#define immpStrGC(str) name(w_immpStrGC(str), #str) #define immpStrGC(str) name(w_immpStrGC(str), #str)
#define immpAtomGC(atom) name(w_immpStrGC(ATOM_TO_STRING(atom)), "ATOM_TO_STRING(" #atom ")") #define immpAtomGC(atom) name(w_immpStrGC(atom), "ATOM(" #atom ")")
#define immpShapeGC(shape) name(w_immpShapeGC(shape), #shape) #define immpShapeGC(shape) name(w_immpShapeGC(shape), #shape)
#define immpIdGC(id) name(w_immpIdGC(id), #id) #define immpIdGC(id) name(w_immpIdGC(id), #id)

View File

@ -488,6 +488,22 @@ PodCopy(T *dst, const T *src, size_t nelem)
} }
} }
template <class T>
JS_ALWAYS_INLINE static bool
PodEqual(T *one, T *two, size_t len)
{
if (len < 128) {
T *p1end = one + len;
for (T *p1 = one, *p2 = two; p1 != p1end; ++p1, ++p2) {
if (*p1 != *p2)
return false;
}
return true;
}
return !memcmp(one, two, len * sizeof(T));
}
} /* namespace js */ } /* namespace js */
#endif /* defined(__cplusplus) */ #endif /* defined(__cplusplus) */

View File

@ -267,8 +267,13 @@ typedef enum JSWhyMagic
JS_GENERIC_MAGIC /* for local use */ JS_GENERIC_MAGIC /* for local use */
} JSWhyMagic; } JSWhyMagic;
#ifdef __cplusplus
class JSString;
class JSFlatString;
#else
typedef struct JSString JSString; typedef struct JSString JSString;
typedef struct JSFlatString JSFlatString; typedef struct JSFlatString JSFlatString;
#endif
typedef struct JSObject JSObject; typedef struct JSObject JSObject;
#if defined(IS_LITTLE_ENDIAN) #if defined(IS_LITTLE_ENDIAN)

View File

@ -670,7 +670,7 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **atomp)
} }
} else { } else {
if (idx == uint32(-1)) { if (idx == uint32(-1)) {
JSString *str = ATOM_TO_STRING(*atomp); JSString *str = *atomp;
return JS_XDRString(xdr, &str); return JS_XDRString(xdr, &str);
} }
} }

View File

@ -412,12 +412,12 @@ ConvertQNameToString(JSContext *cx, JSObject *obj)
JSString *str; JSString *str;
if (!uri) { if (!uri) {
/* No uri means wildcard qualifier. */ /* No uri means wildcard qualifier. */
str = ATOM_TO_STRING(cx->runtime->atomState.starQualifierAtom); str = cx->runtime->atomState.starQualifierAtom;
} else if (uri->empty()) { } else if (uri->empty()) {
/* Empty string for uri means localName is in no namespace. */ /* Empty string for uri means localName is in no namespace. */
str = cx->runtime->emptyString; str = cx->runtime->emptyString;
} else { } else {
JSString *qualstr = ATOM_TO_STRING(cx->runtime->atomState.qualifierAtom); JSString *qualstr = cx->runtime->atomState.qualifierAtom;
str = js_ConcatStrings(cx, uri, qualstr); str = js_ConcatStrings(cx, uri, qualstr);
if (!str) if (!str)
return NULL; return NULL;
@ -758,7 +758,7 @@ QNameHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, jsval *rval)
if (argc == 0) { if (argc == 0) {
name = cx->runtime->emptyString; name = cx->runtime->emptyString;
} else if (argc < 0) { } else if (argc < 0) {
name = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); name = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
} else { } else {
JSString *str = js_ValueToString(cx, Valueify(nameval)); JSString *str = js_ValueToString(cx, Valueify(nameval));
if (!str) if (!str)
@ -1430,7 +1430,7 @@ ParseNodeToXML(Parser *parser, JSParseNode *pn,
/* Enforce "Well-formedness constraint: Unique Att Spec". */ /* Enforce "Well-formedness constraint: Unique Att Spec". */
for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) { for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) {
if (pn3->pn_atom == pn2->pn_atom) { if (pn3->pn_atom == pn2->pn_atom) {
Value v = StringValue(ATOM_TO_STRING(pn2->pn_atom)); Value v = StringValue(pn2->pn_atom);
JSAutoByteString bytes; JSAutoByteString bytes;
if (js_ValueToPrintable(cx, v, &bytes)) { if (js_ValueToPrintable(cx, v, &bytes)) {
ReportCompileErrorNumber(cx, &parser->tokenStream, pn2, ReportCompileErrorNumber(cx, &parser->tokenStream, pn2,
@ -1454,7 +1454,7 @@ ParseNodeToXML(Parser *parser, JSParseNode *pn,
(length == 5 || chars[5] == ':')) { (length == 5 || chars[5] == ':')) {
JSLinearString *uri, *prefix; JSLinearString *uri, *prefix;
uri = ATOM_TO_STRING(pn2->pn_atom); uri = pn2->pn_atom;
if (length == 5) { if (length == 5) {
/* 10.3.2.1. Step 6(h)(i)(1)(a). */ /* 10.3.2.1. Step 6(h)(i)(1)(a). */
prefix = cx->runtime->emptyString; prefix = cx->runtime->emptyString;
@ -1528,7 +1528,7 @@ ParseNodeToXML(Parser *parser, JSParseNode *pn,
attrjqn = attrj->name; attrjqn = attrj->name;
if (EqualStrings(attrjqn->getNameURI(), qn->getNameURI()) && if (EqualStrings(attrjqn->getNameURI(), qn->getNameURI()) &&
EqualStrings(attrjqn->getQNameLocalName(), qn->getQNameLocalName())) { EqualStrings(attrjqn->getQNameLocalName(), qn->getQNameLocalName())) {
Value v = StringValue(ATOM_TO_STRING(pn2->pn_atom)); Value v = StringValue(pn2->pn_atom);
JSAutoByteString bytes; JSAutoByteString bytes;
if (js_ValueToPrintable(cx, v, &bytes)) { if (js_ValueToPrintable(cx, v, &bytes)) {
ReportCompileErrorNumber(cx, &parser->tokenStream, pn2, ReportCompileErrorNumber(cx, &parser->tokenStream, pn2,
@ -1550,7 +1550,7 @@ ParseNodeToXML(Parser *parser, JSParseNode *pn,
XMLARRAY_SET_MEMBER(&xml->xml_attrs, i, attr); XMLARRAY_SET_MEMBER(&xml->xml_attrs, i, attr);
attr->parent = xml; attr->parent = xml;
attr->name = qn; attr->name = qn;
attr->xml_value = ATOM_TO_STRING(pn2->pn_atom); attr->xml_value = pn2->pn_atom;
} }
/* Point tag closes its own namespace scope. */ /* Point tag closes its own namespace scope. */
@ -1563,7 +1563,7 @@ ParseNodeToXML(Parser *parser, JSParseNode *pn,
case TOK_XMLCDATA: case TOK_XMLCDATA:
case TOK_XMLCOMMENT: case TOK_XMLCOMMENT:
case TOK_XMLPI: case TOK_XMLPI:
str = ATOM_TO_STRING(pn->pn_atom); str = pn->pn_atom;
qn = NULL; qn = NULL;
if (pn->pn_type == TOK_XMLCOMMENT) { if (pn->pn_type == TOK_XMLCOMMENT) {
if (flags & XSF_IGNORE_COMMENTS) if (flags & XSF_IGNORE_COMMENTS)
@ -1587,9 +1587,7 @@ ParseNodeToXML(Parser *parser, JSParseNode *pn,
if (!qn) if (!qn)
goto fail; goto fail;
str = pn->pn_atom2 str = pn->pn_atom2 ? pn->pn_atom2 : cx->runtime->emptyString;
? ATOM_TO_STRING(pn->pn_atom2)
: cx->runtime->emptyString;
xml_class = JSXML_CLASS_PROCESSING_INSTRUCTION; xml_class = JSXML_CLASS_PROCESSING_INSTRUCTION;
} else { } else {
/* CDATA section content, or element text. */ /* CDATA section content, or element text. */
@ -2792,7 +2790,7 @@ ToAttributeName(JSContext *cx, jsval v)
name = qn->getQNameLocalName(); name = qn->getQNameLocalName();
} else { } else {
if (clasp == &js_AnyNameClass) { if (clasp == &js_AnyNameClass) {
name = ATOM_TO_STRING(cx->runtime->atomState.starAtom); name = cx->runtime->atomState.starAtom;
} else { } else {
JSString *str = js_ValueToString(cx, Valueify(v)); JSString *str = js_ValueToString(cx, Valueify(v));
if (!str) if (!str)
@ -2825,11 +2823,8 @@ IsFunctionQName(JSContext *cx, JSObject *qn, jsid *funidp)
atom = cx->runtime->atomState.functionNamespaceURIAtom; atom = cx->runtime->atomState.functionNamespaceURIAtom;
uri = qn->getNameURI(); uri = qn->getNameURI();
if (uri && if (uri && (uri == atom || EqualStrings(uri, atom)))
(uri == ATOM_TO_STRING(atom) ||
EqualStrings(uri, ATOM_TO_STRING(atom)))) {
return JS_ValueToId(cx, STRING_TO_JSVAL(qn->getQNameLocalName()), funidp); return JS_ValueToId(cx, STRING_TO_JSVAL(qn->getQNameLocalName()), funidp);
}
*funidp = JSID_VOID; *funidp = JSID_VOID;
return JS_TRUE; return JS_TRUE;
} }
@ -2865,7 +2860,7 @@ ToXMLName(JSContext *cx, jsval v, jsid *funidp)
if (clasp == &js_AttributeNameClass || clasp == &js_QNameClass) if (clasp == &js_AttributeNameClass || clasp == &js_QNameClass)
goto out; goto out;
if (clasp == &js_AnyNameClass) { if (clasp == &js_AnyNameClass) {
name = ATOM_TO_STRING(cx->runtime->atomState.starAtom); name = cx->runtime->atomState.starAtom;
goto construct; goto construct;
} }
name = js_ValueToString(cx, Valueify(v)); name = js_ValueToString(cx, Valueify(v));
@ -4622,6 +4617,34 @@ HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found)
return true; return true;
} }
static bool
IdValIsIndex(JSContext *cx, jsval id, jsuint *indexp, bool *isIndex)
{
if (JSVAL_IS_INT(id)) {
jsint i;
i = JSVAL_TO_INT(id);
if (i < 0) {
*isIndex = false;
return true;
}
*indexp = (jsuint)i;
*isIndex = true;
return true;
}
if (!JSVAL_IS_STRING(id)) {
*isIndex = false;
return true;
}
JSLinearString *str = JSVAL_TO_STRING(id)->ensureLinear(cx);
if (!str)
return false;
*isIndex = js_StringIsIndex(str, indexp);
return true;
}
/* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */ /* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */
static JSBool static JSBool
HasProperty(JSContext *cx, JSObject *obj, jsval id, JSBool *found) HasProperty(JSContext *cx, JSObject *obj, jsval id, JSBool *found)
@ -4633,7 +4656,7 @@ HasProperty(JSContext *cx, JSObject *obj, jsval id, JSBool *found)
jsid funid; jsid funid;
xml = (JSXML *) obj->getPrivate(); xml = (JSXML *) obj->getPrivate();
if (!js_IdValIsIndex(cx, id, &i, &isIndex)) if (!IdValIsIndex(cx, id, &i, &isIndex))
return JS_FALSE; return JS_FALSE;
if (isIndex) { if (isIndex) {
@ -5291,7 +5314,7 @@ xml_attribute(JSContext *cx, uintN argc, jsval *vp)
static JSBool static JSBool
xml_attributes(JSContext *cx, uintN argc, jsval *vp) xml_attributes(JSContext *cx, uintN argc, jsval *vp)
{ {
jsval name = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom); jsval name = STRING_TO_JSVAL(cx->runtime->atomState.starAtom);
JSObject *qn = ToAttributeName(cx, name); JSObject *qn = ToAttributeName(cx, name);
if (!qn) if (!qn)
return JS_FALSE; return JS_FALSE;
@ -5355,7 +5378,7 @@ xml_child_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval name,
/* ECMA-357 13.4.4.6 */ /* ECMA-357 13.4.4.6 */
JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST);
if (!js_IdValIsIndex(cx, name, &index, &isIndex)) if (!IdValIsIndex(cx, name, &index, &isIndex))
return JS_FALSE; return JS_FALSE;
if (isIndex) { if (isIndex) {
@ -5577,7 +5600,7 @@ xml_descendants(JSContext *cx, uintN argc, jsval *vp)
JSXML *list; JSXML *list;
XML_METHOD_PROLOG; XML_METHOD_PROLOG;
name = argc == 0 ? ATOM_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2]; name = argc == 0 ? STRING_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2];
list = Descendants(cx, xml, name); list = Descendants(cx, xml, name);
if (!list) if (!list)
return JS_FALSE; return JS_FALSE;
@ -5653,7 +5676,7 @@ xml_elements(JSContext *cx, uintN argc, jsval *vp)
XML_METHOD_PROLOG; XML_METHOD_PROLOG;
name = (argc == 0) ? ATOM_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2]; name = (argc == 0) ? STRING_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2];
nameqn = ToXMLName(cx, name, &funid); nameqn = ToXMLName(cx, name, &funid);
if (!nameqn) if (!nameqn)
return JS_FALSE; return JS_FALSE;
@ -6201,7 +6224,7 @@ xml_processingInstructions(JSContext *cx, uintN argc, jsval *vp)
XML_METHOD_PROLOG; XML_METHOD_PROLOG;
name = (argc == 0) ? ATOM_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2]; name = (argc == 0) ? STRING_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2];
nameqn = ToXMLName(cx, name, &funid); nameqn = ToXMLName(cx, name, &funid);
if (!nameqn) if (!nameqn)
return JS_FALSE; return JS_FALSE;
@ -6234,7 +6257,7 @@ xml_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp)
XML_METHOD_PROLOG; XML_METHOD_PROLOG;
*vp = JSVAL_FALSE; *vp = JSVAL_FALSE;
if (argc != 0) { if (argc != 0) {
if (!js_IdValIsIndex(cx, vp[2], &index, &isIndex)) if (!IdValIsIndex(cx, vp[2], &index, &isIndex))
return JS_FALSE; return JS_FALSE;
if (isIndex) { if (isIndex) {
@ -6340,7 +6363,7 @@ xml_replace(JSContext *cx, uintN argc, jsval *vp)
goto done; goto done;
if (argc <= 1) { if (argc <= 1) {
value = ATOM_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); value = STRING_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
} else { } else {
value = vp[3]; value = vp[3];
vxml = VALUE_IS_XML(value) vxml = VALUE_IS_XML(value)
@ -6366,7 +6389,7 @@ xml_replace(JSContext *cx, uintN argc, jsval *vp)
if (argc == 0) { if (argc == 0) {
haveIndex = false; haveIndex = false;
} else { } else {
if (!js_IdValIsIndex(cx, vp[2], &index, &haveIndex)) if (!IdValIsIndex(cx, vp[2], &index, &haveIndex))
return JS_FALSE; return JS_FALSE;
} }
@ -6432,7 +6455,7 @@ xml_setLocalName(JSContext *cx, uintN argc, jsval *vp)
return JS_TRUE; return JS_TRUE;
if (argc == 0) { if (argc == 0) {
namestr = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); namestr = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
} else { } else {
name = vp[2]; name = vp[2];
if (!JSVAL_IS_PRIMITIVE(name) && if (!JSVAL_IS_PRIMITIVE(name) &&
@ -6472,7 +6495,7 @@ xml_setName(JSContext *cx, uintN argc, jsval *vp)
return JS_TRUE; return JS_TRUE;
if (argc == 0) { if (argc == 0) {
name = ATOM_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); name = STRING_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
} else { } else {
name = vp[2]; name = vp[2];
if (!JSVAL_IS_PRIMITIVE(name) && if (!JSVAL_IS_PRIMITIVE(name) &&
@ -7358,8 +7381,7 @@ js_GetAnyName(JSContext *cx, jsid *idp)
JS_ASSERT(!obj->getProto()); JS_ASSERT(!obj->getProto());
JSRuntime *rt = cx->runtime; JSRuntime *rt = cx->runtime;
InitXMLQName(obj, rt->emptyString, rt->emptyString, InitXMLQName(obj, rt->emptyString, rt->emptyString, rt->atomState.starAtom);
ATOM_TO_STRING(rt->atomState.starAtom));
METER(xml_stats.qname); METER(xml_stats.qname);
v.setObject(*obj); v.setObject(*obj);
@ -7385,7 +7407,7 @@ js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *i
JS_ASSERT(nameval.isObject()); JS_ASSERT(nameval.isObject());
nameobj = &nameval.toObject(); nameobj = &nameval.toObject();
if (nameobj->getClass() == &js_AnyNameClass) { if (nameobj->getClass() == &js_AnyNameClass) {
v = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom); v = STRING_TO_JSVAL(cx->runtime->atomState.starAtom);
nameobj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, nameobj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1,
Valueify(&v)); Valueify(&v));
if (!nameobj) if (!nameobj)

View File

@ -1412,11 +1412,7 @@ mjit::Compiler::generateMethod()
END_CASE(JSOP_DOUBLE) END_CASE(JSOP_DOUBLE)
BEGIN_CASE(JSOP_STRING) BEGIN_CASE(JSOP_STRING)
{ frame.push(StringValue(script->getAtom(fullAtomIndex(PC))));
JSAtom *atom = script->getAtom(fullAtomIndex(PC));
JSString *str = ATOM_TO_STRING(atom);
frame.push(Value(StringValue(str)));
}
END_CASE(JSOP_STRING) END_CASE(JSOP_STRING)
BEGIN_CASE(JSOP_ZERO) BEGIN_CASE(JSOP_ZERO)

View File

@ -851,7 +851,7 @@ mjit::Compiler::jsop_typeof()
if (atom) { if (atom) {
frame.pop(); frame.pop();
frame.push(StringValue(ATOM_TO_STRING(atom))); frame.push(StringValue(atom));
return; return;
} }
} }

View File

@ -1851,7 +1851,7 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic)
#if JS_HAS_NO_SUCH_METHOD #if JS_HAS_NO_SUCH_METHOD
if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) { if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) {
regs.sp[-2].setString(ATOM_TO_STRING(pic->atom)); regs.sp[-2].setString(pic->atom);
if (!js_OnUnknownMethod(cx, regs.sp - 2)) if (!js_OnUnknownMethod(cx, regs.sp - 2))
THROW(); THROW();
} }
@ -2131,7 +2131,7 @@ GetElementIC::attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid i
CodeLocationLabel cs = buffer.finalize(); CodeLocationLabel cs = buffer.finalize();
#if DEBUG #if DEBUG
char *chars = js_DeflateString(cx, v.toString()->nonRopeChars(), v.toString()->length()); char *chars = js_DeflateString(cx, v.toString()->getChars(cx), v.toString()->length());
JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom 0x%x (\"%s\") shape 0x%x (%s: %d)\n", JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom 0x%x (\"%s\") shape 0x%x (%s: %d)\n",
js_CodeName[op], cs.executableAddress(), id, chars, holder->shape(), js_CodeName[op], cs.executableAddress(), id, chars, holder->shape(),
cx->fp()->script()->filename, js_FramePCToLineNumber(cx, cx->fp())); cx->fp()->script()->filename, js_FramePCToLineNumber(cx, cx->fp()));

View File

@ -419,7 +419,7 @@ stubs::GetElem(VMFrame &f)
JSString *str = lref.toString(); JSString *str = lref.toString();
int32_t i = rref.toInt32(); int32_t i = rref.toInt32();
if ((size_t)i < str->length()) { if ((size_t)i < str->length()) {
str = JSString::getUnitString(cx, str, (size_t)i); str = JSAtom::getUnitStringForElement(cx, str, (size_t)i);
if (!str) if (!str)
THROW(); THROW();
f.regs.sp[-2].setString(str); f.regs.sp[-2].setString(str);
@ -2002,7 +2002,7 @@ stubs::CallProp(VMFrame &f, JSAtom *origAtom)
} }
#if JS_HAS_NO_SUCH_METHOD #if JS_HAS_NO_SUCH_METHOD
if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) { if (JS_UNLIKELY(rval.isUndefined()) && regs.sp[-1].isObject()) {
regs.sp[-2].setString(ATOM_TO_STRING(origAtom)); regs.sp[-2].setString(origAtom);
if (!js_OnUnknownMethod(cx, regs.sp - 2)) if (!js_OnUnknownMethod(cx, regs.sp - 2))
THROW(); THROW();
} }
@ -2173,7 +2173,7 @@ stubs::TypeOf(VMFrame &f)
const Value &ref = f.regs.sp[-1]; const Value &ref = f.regs.sp[-1];
JSType type = JS_TypeOfValue(f.cx, Jsvalify(ref)); JSType type = JS_TypeOfValue(f.cx, Jsvalify(ref));
JSAtom *atom = f.cx->runtime->atomState.typeAtoms[type]; JSAtom *atom = f.cx->runtime->atomState.typeAtoms[type];
return ATOM_TO_STRING(atom); return atom;
} }
void JS_FASTCALL void JS_FASTCALL
@ -2376,7 +2376,7 @@ stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
Value rval = script->getConst(GET_INDEX(pc)); Value rval = script->getConst(GET_INDEX(pc));
pc += INDEX_LEN; pc += INDEX_LEN;
if (rval.isString()) { if (rval.isString()) {
JSLinearString *rhs = rval.toString()->assertIsLinear(); JSLinearString *rhs = &rval.toString()->asLinear();
if (rhs == str || EqualStrings(str, rhs)) { if (rhs == str || EqualStrings(str, rhs)) {
void* native = script->nativeCodeForPC(ctor, void* native = script->nativeCodeForPC(ctor,
jpc + GET_JUMP_OFFSET(pc)); jpc + GET_JUMP_OFFSET(pc));

View File

@ -2058,9 +2058,8 @@ SrcNotes(JSContext *cx, JSScript *script)
case SRC_CONT2LABEL: case SRC_CONT2LABEL:
index = js_GetSrcNoteOffset(sn, 0); index = js_GetSrcNoteOffset(sn, 0);
JS_GET_SCRIPT_ATOM(script, NULL, index, atom); JS_GET_SCRIPT_ATOM(script, NULL, index, atom);
str = ATOM_TO_STRING(atom);
fprintf(gOutFile, " atom %u (", index); fprintf(gOutFile, " atom %u (", index);
JS_FileEscapedString(gOutFile, str, 0); JS_FileEscapedString(gOutFile, atom, 0);
putc(')', gOutFile); putc(')', gOutFile);
break; break;
case SRC_FUNCDEF: { case SRC_FUNCDEF: {
@ -4815,7 +4814,7 @@ Help(JSContext *cx, uintN argc, jsval *vp)
type = JS_TypeOfValue(cx, argv[i]); type = JS_TypeOfValue(cx, argv[i]);
if (type == JSTYPE_FUNCTION) { if (type == JSTYPE_FUNCTION) {
fun = JS_ValueToFunction(cx, argv[i]); fun = JS_ValueToFunction(cx, argv[i]);
str = fun->atom ? ATOM_TO_STRING(fun->atom) : NULL; str = fun->atom;
} else if (type == JSTYPE_STRING) { } else if (type == JSTYPE_STRING) {
str = JSVAL_TO_STRING(argv[i]); str = JSVAL_TO_STRING(argv[i]);
} else { } else {
@ -5314,7 +5313,7 @@ Exec(JSContext *cx, uintN argc, jsval *vp)
nargv[0] = name; nargv[0] = name;
jsval *argv = JS_ARGV(cx, vp); jsval *argv = JS_ARGV(cx, vp);
for (i = 0; i < nargc; i++) { for (i = 0; i < nargc; i++) {
str = (i == 0) ? ATOM_TO_STRING(fun->atom) : JS_ValueToString(cx, argv[i-1]); str = (i == 0) ? fun->atom : JS_ValueToString(cx, argv[i-1]);
if (!str) { if (!str) {
ok = false; ok = false;
goto done; goto done;

View File

@ -248,9 +248,9 @@ couldBeObjectOrString(LIns *ins)
#endif #endif
} else if (ins->isop(LIR_addp) && } else if (ins->isop(LIR_addp) &&
((ins->oprnd1()->isImmP() && ((ins->oprnd1()->isImmP() &&
(void *)ins->oprnd1()->immP() == JSString::unitStringTable) || (void *)ins->oprnd1()->immP() == JSAtom::unitStaticTable) ||
(ins->oprnd2()->isImmP() && (ins->oprnd2()->isImmP() &&
(void *)ins->oprnd2()->immP() == JSString::unitStringTable))) (void *)ins->oprnd2()->immP() == JSAtom::unitStaticTable)))
{ {
// (String only) // (String only)
// ins = addp ..., JSString::unitStringTable // ins = addp ..., JSString::unitStringTable

View File

@ -90,7 +90,7 @@ XPCStringConvert::ReadableToJSVal(JSContext *cx,
JSAtom *atom; JSAtom *atom;
if (length == 0 && (atom = cx->runtime->atomState.emptyAtom)) if (length == 0 && (atom = cx->runtime->atomState.emptyAtom))
{ {
return ATOM_TO_JSVAL(atom); return STRING_TO_JSVAL(atom);
} }
nsStringBuffer *buf = nsStringBuffer::FromString(readable); nsStringBuffer *buf = nsStringBuffer::FromString(readable);