Bug 654301: Better interned string API. (r=Waldo)

This commit is contained in:
Chris Leary 2011-05-16 18:18:59 -07:00
parent c226d4cca1
commit 36481bff9a
39 changed files with 401 additions and 290 deletions

View File

@ -3427,7 +3427,7 @@ nsresult nsScriptSecurityManager::Init()
::JS_BeginRequest(cx);
if (sEnabledID == JSID_VOID)
sEnabledID = INTERNED_STRING_TO_JSID(::JS_InternString(cx, "enabled"));
sEnabledID = INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "enabled"));
::JS_EndRequest(cx);
InitPrefs();

View File

@ -908,7 +908,7 @@ nsEventListenerManager::RegisterScriptEventListener(nsIScriptContext *aContext,
if (sAddListenerID == JSID_VOID) {
JSAutoRequest ar(cx);
sAddListenerID =
INTERNED_STRING_TO_JSID(::JS_InternString(cx, "addEventListener"));
INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "addEventListener"));
}
if (aContext->GetScriptTypeID() == nsIProgrammingLanguage::JAVASCRIPT) {

View File

@ -3322,7 +3322,7 @@ nsHTMLDocument::DoClipboardSecurityCheck(PRBool aPaste)
if (aPaste) {
if (nsHTMLDocument::sPasteInternal_id == JSID_VOID) {
nsHTMLDocument::sPasteInternal_id =
INTERNED_STRING_TO_JSID(::JS_InternString(cx, "paste"));
INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "paste"));
}
rv = secMan->CheckPropertyAccess(cx, nsnull, classNameStr.get(),
nsHTMLDocument::sPasteInternal_id,
@ -3330,7 +3330,7 @@ nsHTMLDocument::DoClipboardSecurityCheck(PRBool aPaste)
} else {
if (nsHTMLDocument::sCutCopyInternal_id == JSID_VOID) {
nsHTMLDocument::sCutCopyInternal_id =
INTERNED_STRING_TO_JSID(::JS_InternString(cx, "cutcopy"));
INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "cutcopy"));
}
rv = secMan->CheckPropertyAccess(cx, nsnull, classNameStr.get(),
nsHTMLDocument::sCutCopyInternal_id,

View File

@ -985,7 +985,7 @@ nsJSObjWrapper::NP_Enumerate(NPObject *npobj, NPIdentifier **idarray,
return PR_FALSE;
}
id = StringToNPIdentifier(str);
id = StringToNPIdentifier(cx, str);
} else {
NS_ASSERTION(JSVAL_IS_INT(v),
"The element in ida must be either string or int!\n");
@ -1473,8 +1473,8 @@ CallNPMethodInternal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
if (npobj->_class->invoke) {
JSFunction *fun = (JSFunction *)::JS_GetPrivate(cx, funobj);
JSString *name = ::JS_GetFunctionId(fun);
NPIdentifier id = StringToNPIdentifier(name);
JSString *name = ::JS_InternJSString(cx, ::JS_GetFunctionId(fun));
NPIdentifier id = StringToNPIdentifier(cx, name);
ok = npobj->_class->invoke(npobj, id, npargs, argc, &v);
} else {

View File

@ -144,9 +144,9 @@ NPIdentifierToString(NPIdentifier id)
}
static inline NPIdentifier
StringToNPIdentifier(JSString *str)
StringToNPIdentifier(JSContext *cx, JSString *str)
{
return JSIdToNPIdentifier(INTERNED_STRING_TO_JSID(str));
return JSIdToNPIdentifier(INTERNED_STRING_TO_JSID(cx, str));
}
static inline bool

View File

@ -63,6 +63,7 @@ CPPSRCS = \
testGCChunkAlloc.cpp \
testGetPropertyDefault.cpp \
testIntString.cpp \
testIntern.cpp \
testLookup.cpp \
testLooselyEqual.cpp \
testNewObject.cpp \

View File

@ -0,0 +1,40 @@
#include "tests.h"
#include "jsatom.h"
BEGIN_TEST(testAtomizedIsNotInterned)
{
/* Try to pick a string that won't be interned by other tests in this runtime. */
static const char someChars[] = "blah blah blah? blah blah blah";
JSAtom *atom = js_Atomize(cx, someChars, JS_ARRAY_LENGTH(someChars));
CHECK(!JS_StringHasBeenInterned(cx, atom));
CHECK(JS_InternJSString(cx, atom));
CHECK(JS_StringHasBeenInterned(cx, atom));
return true;
}
END_TEST(testAtomizedIsNotInterned)
struct StringWrapper
{
JSString *str;
bool strOk;
} sw;
JSBool
GCCallback(JSContext *cx, JSGCStatus status)
{
if (status == JSGC_MARK_END)
sw.strOk = !JS_IsAboutToBeFinalized(cx, sw.str);
return true;
}
BEGIN_TEST(testInternAcrossGC)
{
sw.str = JS_InternString(cx, "wrapped chars that another test shouldn't be using");
sw.strOk = false;
CHECK(sw.str);
JS_SetGCCallback(cx, GCCallback);
JS_GC(cx);
CHECK(sw.strOk);
return true;
}
END_TEST(testInternAcrossGC)

View File

@ -14,7 +14,7 @@ BEGIN_TEST(testStringBuffer_finishString)
JSString *str = JS_NewStringCopyZ(cx, "foopy");
CHECK(str);
JSAtom *atom = js_AtomizeString(cx, str, 0);
JSAtom *atom = js_AtomizeString(cx, str);
CHECK(atom);
js::StringBuffer buffer(cx);

View File

@ -1574,7 +1574,7 @@ StdNameToAtom(JSContext *cx, JSStdName *stdn)
if (!atom) {
name = stdn->name;
if (name) {
atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
atom = js_Atomize(cx, name, strlen(name), InternAtom);
OFFSET_TO_ATOM(cx->runtime, offset) = atom;
}
}
@ -3236,14 +3236,14 @@ JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
JS_PUBLIC_API(JSBool)
JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
}
JS_PUBLIC_API(JSBool)
JS_LookupUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
{
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
}
@ -3266,7 +3266,7 @@ JS_PUBLIC_API(JSBool)
JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, uintN flags, jsval *vp)
{
JSObject *obj2;
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags, &obj2, vp);
}
@ -3290,14 +3290,14 @@ JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
JS_PUBLIC_API(JSBool)
JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
}
JS_PUBLIC_API(JSBool)
JS_HasUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, JSBool *foundp)
{
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
}
@ -3332,7 +3332,7 @@ JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, JSBool *found
JS_PUBLIC_API(JSBool)
JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
}
@ -3340,7 +3340,7 @@ JS_PUBLIC_API(JSBool)
JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
JSBool *foundp)
{
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
}
@ -3395,7 +3395,7 @@ DefineProperty(JSContext *cx, JSObject *obj, const char *name, const Value &valu
atom = NULL;
attrs &= ~JSPROP_INDEX;
} else {
atom = js_Atomize(cx, name, strlen(name), 0);
atom = js_Atomize(cx, name, strlen(name));
if (!atom)
return JS_FALSE;
id = ATOM_TO_JSID(atom);
@ -3424,7 +3424,7 @@ DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namele
const Value &value, PropertyOp getter, StrictPropertyOp setter, uintN attrs,
uintN flags, intN tinyid)
{
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
flags, tinyid);
}
@ -3522,7 +3522,7 @@ JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *ali
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
if (!atom)
return JS_FALSE;
if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
@ -3536,7 +3536,7 @@ JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *ali
alias, name, obj2->getClass()->name);
return JS_FALSE;
}
atom = js_Atomize(cx, alias, strlen(alias), 0);
atom = js_Atomize(cx, alias, strlen(alias));
if (!atom) {
ok = JS_FALSE;
} else {
@ -3560,7 +3560,7 @@ JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
if (!atom)
return JS_FALSE;
if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
@ -3665,7 +3665,7 @@ JS_PUBLIC_API(JSBool)
JS_GetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
uintN *attrsp, JSBool *foundp)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
attrsp, foundp, NULL, NULL);
}
@ -3674,7 +3674,7 @@ JS_PUBLIC_API(JSBool)
JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
uintN *attrsp, JSBool *foundp)
{
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
attrsp, foundp, NULL, NULL);
}
@ -3684,7 +3684,7 @@ JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, const char *nam
uintN *attrsp, JSBool *foundp,
JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
attrsp, foundp, getterp, setterp);
}
@ -3695,7 +3695,7 @@ JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
uintN *attrsp, JSBool *foundp,
JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
{
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
attrsp, foundp, getterp, setterp);
}
@ -3731,7 +3731,7 @@ JS_PUBLIC_API(JSBool)
JS_SetPropertyAttributes(JSContext *cx, JSObject *obj, const char *name,
uintN attrs, JSBool *foundp)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
}
@ -3739,7 +3739,7 @@ JS_PUBLIC_API(JSBool)
JS_SetUCPropertyAttributes(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
uintN attrs, JSBool *foundp)
{
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
}
@ -3767,21 +3767,21 @@ JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
JS_PUBLIC_API(JSBool)
JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
}
JS_PUBLIC_API(JSBool)
JS_GetPropertyDefault(JSContext *cx, JSObject *obj, const char *name, jsval def, jsval *vp)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && JS_GetPropertyByIdDefault(cx, obj, ATOM_TO_JSID(atom), def, vp);
}
JS_PUBLIC_API(JSBool)
JS_GetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
{
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
}
@ -3800,7 +3800,7 @@ JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *
JS_PUBLIC_API(JSBool)
JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp, jsval *vp)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp);
}
@ -3822,14 +3822,14 @@ JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
JS_PUBLIC_API(JSBool)
JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
}
JS_PUBLIC_API(JSBool)
JS_SetUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *vp)
{
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
}
@ -3851,14 +3851,14 @@ JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
JS_PUBLIC_API(JSBool)
JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, jsval *rval)
{
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
}
JS_PUBLIC_API(JSBool)
JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval *rval)
{
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
}
@ -4188,7 +4188,7 @@ JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
if (!name) {
atom = NULL;
} else {
atom = js_Atomize(cx, name, strlen(name), 0);
atom = js_Atomize(cx, name, strlen(name));
if (!atom)
return NULL;
}
@ -4397,7 +4397,7 @@ JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
if (!atom)
return NULL;
return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
@ -4411,7 +4411,7 @@ JS_DefineUCFunction(JSContext *cx, JSObject *obj,
JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
if (!atom)
return NULL;
return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
@ -4737,7 +4737,7 @@ CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj,
if (!name) {
funAtom = NULL;
} else {
funAtom = js_Atomize(cx, name, strlen(name), 0);
funAtom = js_Atomize(cx, name, strlen(name));
if (!funAtom) {
fun = NULL;
goto out2;
@ -4762,7 +4762,7 @@ CompileUCFunctionForPrincipalsCommon(JSContext *cx, JSObject *obj,
Bindings bindings(cx, emptyCallShape);
AutoBindingsRooter root(cx, bindings);
for (i = 0; i < nargs; i++) {
argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]));
if (!argAtom) {
fun = NULL;
goto out2;
@ -5059,7 +5059,7 @@ JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
assertSameCompartment(cx, obj, JSValueArray(argv, argc));
AutoValueRooter tvr(cx);
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
JSBool ok =
atom &&
js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
@ -5245,23 +5245,32 @@ JS_NewStringCopyZ(JSContext *cx, const char *s)
}
JS_PUBLIC_API(JSBool)
JS_StringHasBeenInterned(JSString *str)
JS_StringHasBeenInterned(JSContext *cx, JSString *str)
{
return str->isAtom();
CHECK_REQUEST(cx);
if (!str->isAtom())
return false;
return AtomIsInterned(cx, &str->asAtom());
}
JS_PUBLIC_API(JSString *)
JS_InternJSString(JSContext *cx, JSString *str)
{
CHECK_REQUEST(cx);
return js_AtomizeString(cx, str, 0);
JSAtom *atom = js_AtomizeString(cx, str, InternAtom);
JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
return atom;
}
JS_PUBLIC_API(JSString *)
JS_InternString(JSContext *cx, const char *s)
{
CHECK_REQUEST(cx);
return js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
JSAtom *atom = js_Atomize(cx, s, strlen(s), InternAtom);
JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
return atom;
}
JS_PUBLIC_API(JSString *)
@ -5291,7 +5300,9 @@ JS_PUBLIC_API(JSString *)
JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
{
CHECK_REQUEST(cx);
return js_AtomizeChars(cx, s, length, ATOM_INTERNED);
JSAtom *atom = js_AtomizeChars(cx, s, length, InternAtom);
JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
return atom;
}
JS_PUBLIC_API(JSString *)

View File

@ -333,16 +333,22 @@ JSID_IS_ZERO(jsid id)
}
JS_PUBLIC_API(JSBool)
JS_StringHasBeenInterned(JSString *str);
JS_StringHasBeenInterned(JSContext *cx, JSString *str);
/* A jsid may only hold an interned JSString. */
/*
* Only JSStrings that have been interned via the JSAPI can be turned into
* jsids by API clients.
*
* N.B. if a jsid is backed by a string which has not been interned, that
* string must be appropriately rooted to avoid being collected by the GC.
*/
static JS_ALWAYS_INLINE jsid
INTERNED_STRING_TO_JSID(JSString *str)
INTERNED_STRING_TO_JSID(JSContext *cx, JSString *str)
{
jsid id;
JS_ASSERT(str);
JS_ASSERT(JS_StringHasBeenInterned(str));
JS_ASSERT(((size_t)str & JSID_TYPE_MASK) == 0);
JS_ASSERT(JS_StringHasBeenInterned(cx, str));
JSID_BITS(id) = (size_t)str;
return id;
}

View File

@ -164,7 +164,6 @@ struct JSArenaPool {
(JS_UPTRDIFF(mark, (a)->base) <= JS_UPTRDIFF((a)->avail, (a)->base))
#ifdef DEBUG
#define JS_FREE_PATTERN 0xDA
#define JS_CLEAR_UNUSED(a) (JS_ASSERT((a)->avail <= (a)->limit), \
memset((void*)(a)->avail, JS_FREE_PATTERN, \
(a)->limit - (a)->avail))

View File

@ -278,7 +278,7 @@ BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom,
return JS_TRUE;
}
} else {
atom = js_AtomizeChars(cx, start, JS_ARRAY_END(buf) - start, 0);
atom = js_AtomizeChars(cx, start, JS_ARRAY_END(buf) - start);
if (!atom)
return JS_FALSE;
}

View File

@ -67,28 +67,15 @@
using namespace js;
using namespace js::gc;
const size_t JSAtomState::commonAtomsOffset = offsetof(JSAtomState, emptyAtom);
const size_t JSAtomState::lazyAtomsOffset = offsetof(JSAtomState, lazy);
/*
* ATOM_HASH assumes that JSHashNumber is 32-bit even on 64-bit systems.
*/
JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4);
JS_STATIC_ASSERT(sizeof(JSAtom *) == JS_BYTES_PER_WORD);
/*
* Start and limit offsets for atom pointers in JSAtomState must be aligned
* on the word boundary.
*/
JS_STATIC_ASSERT(ATOM_OFFSET_START % sizeof(JSAtom *) == 0);
JS_STATIC_ASSERT(ATOM_OFFSET_LIMIT % sizeof(JSAtom *) == 0);
/*
* JS_BOOLEAN_STR and JS_TYPE_STR assume that boolean names starts from the
* index 1 and type name starts from the index 1+2 atoms in JSAtomState.
*/
JS_STATIC_ASSERT(1 * sizeof(JSAtom *) ==
offsetof(JSAtomState, booleanAtoms) - ATOM_OFFSET_START);
JS_STATIC_ASSERT((1 + 2) * sizeof(JSAtom *) ==
offsetof(JSAtomState, typeAtoms) - ATOM_OFFSET_START);
const char *
js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes)
{
@ -217,8 +204,28 @@ const char *const js_common_atom_names[] = {
"WeakMap" /* WeakMapAtom */
};
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) * sizeof(JSAtom *) ==
LAZY_ATOM_OFFSET_START - ATOM_OFFSET_START);
void
JSAtomState::checkStaticInvariants()
{
/*
* Start and limit offsets for atom pointers in JSAtomState must be aligned
* on the word boundary.
*/
JS_STATIC_ASSERT(commonAtomsOffset % sizeof(JSAtom *) == 0);
JS_STATIC_ASSERT(sizeof(*this) % sizeof(JSAtom *) == 0);
/*
* JS_BOOLEAN_STR and JS_TYPE_STR assume that boolean names starts from the
* index 1 and type name starts from the index 1+2 atoms in JSAtomState.
*/
JS_STATIC_ASSERT(1 * sizeof(JSAtom *) ==
offsetof(JSAtomState, booleanAtoms) - commonAtomsOffset);
JS_STATIC_ASSERT((1 + 2) * sizeof(JSAtom *) ==
offsetof(JSAtomState, typeAtoms) - commonAtomsOffset);
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) * sizeof(JSAtom *) ==
lazyAtomsOffset - commonAtomsOffset);
}
/*
* Interpreter macros called by the trace recorder assume common atom indexes
@ -295,40 +302,6 @@ const char js_close_str[] = "close";
const char js_send_str[] = "send";
#endif
/*
* Helper macros to access and modify JSAtomHashEntry.
*/
inline AtomEntryType
StringToInitialAtomEntry(JSString *str)
{
return (AtomEntryType) str;
}
inline uintN
AtomEntryFlags(AtomEntryType entry)
{
return (uintN) (entry & ATOM_ENTRY_FLAG_MASK);
}
/*
* Conceptually, we have compressed a HashMap<JSAtom *, uint> into a
* HashMap<size_t>. Here, we promise that we are only changing the "value" of
* the HashMap entry, so the const_cast is safe.
*/
inline void
AddAtomEntryFlags(const AtomEntryType &entry, uintN flags)
{
const_cast<AtomEntryType &>(entry) |= AtomEntryType(flags);
}
inline void
ClearAtomEntryFlags(const AtomEntryType &entry, uintN flags)
{
const_cast<AtomEntryType &>(entry) &= ~AtomEntryType(flags);
}
/*
* For a browser build from 2007-08-09 after the browser starts up there are
* just 55 double atoms, but over 15000 string atoms. Not to penalize more
@ -367,47 +340,35 @@ js_FinishAtomState(JSRuntime *rt)
}
for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront())
AtomEntryToKey(r.front())->finalize(rt);
r.front().toAtom()->finalize(rt);
#ifdef JS_THREADSAFE
js_FinishLock(&state->lock);
#endif
}
JSBool
bool
js_InitCommonAtoms(JSContext *cx)
{
JSAtomState *state = &cx->runtime->atomState;
uintN i;
JSAtom **atoms;
atoms = COMMON_ATOMS_START(state);
for (i = 0; i < JS_ARRAY_LENGTH(js_common_atom_names); i++, atoms++) {
*atoms = js_Atomize(cx, js_common_atom_names[i],
strlen(js_common_atom_names[i]), ATOM_PINNED);
JSAtom **atoms = state->commonAtomsStart();
for (size_t i = 0; i < JS_ARRAY_LENGTH(js_common_atom_names); i++, atoms++) {
*atoms = js_Atomize(cx, js_common_atom_names[i], strlen(js_common_atom_names[i]),
InternAtom);
if (!*atoms)
return JS_FALSE;
return false;
}
JS_ASSERT((uint8 *)atoms - (uint8 *)state == LAZY_ATOM_OFFSET_START);
memset(atoms, 0, ATOM_OFFSET_LIMIT - LAZY_ATOM_OFFSET_START);
state->clearLazyAtoms();
cx->runtime->emptyString = state->emptyAtom;
return JS_TRUE;
return true;
}
void
js_FinishCommonAtoms(JSContext *cx)
{
cx->runtime->emptyString = NULL;
JSAtomState *state = &cx->runtime->atomState;
for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront())
ClearAtomEntryFlags(r.front(), ATOM_PINNED);
#ifdef DEBUG
memset(COMMON_ATOMS_START(state), JS_FREE_PATTERN,
ATOM_OFFSET_LIMIT - ATOM_OFFSET_START);
#endif
cx->runtime->atomState.junkAtoms();
}
void
@ -423,20 +384,16 @@ js_TraceAtomState(JSTracer *trc)
if (rt->gcKeepAtoms) {
for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
JS_SET_TRACING_INDEX(trc, "locked_atom", number++);
MarkString(trc, AtomEntryToKey(r.front()));
MarkString(trc, r.front().toAtom());
}
} else {
for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
AtomEntryType entry = r.front();
uintN flags = AtomEntryFlags(entry);
if (flags & (ATOM_PINNED | ATOM_INTERNED)) {
JS_SET_TRACING_INDEX(trc,
flags & ATOM_PINNED
? "pinned_atom"
: "interned_atom",
number++);
MarkString(trc, AtomEntryToKey(entry));
}
AtomStateEntry entry = r.front();
if (!entry.isInterned())
continue;
JS_SET_TRACING_INDEX(trc, "interned_atom", number++);
MarkString(trc, entry.toAtom());
}
}
}
@ -447,26 +404,66 @@ js_SweepAtomState(JSContext *cx)
JSAtomState *state = &cx->runtime->atomState;
for (AtomSet::Enum e(state->atoms); !e.empty(); e.popFront()) {
AtomEntryType entry = e.front();
if (AtomEntryFlags(entry) & (ATOM_PINNED | ATOM_INTERNED)) {
AtomStateEntry entry = e.front();
if (entry.isInterned()) {
/* Pinned or interned key cannot be finalized. */
JS_ASSERT(!IsAboutToBeFinalized(cx, AtomEntryToKey(entry)));
} else if (IsAboutToBeFinalized(cx, AtomEntryToKey(entry))) {
e.removeFront();
JS_ASSERT(!IsAboutToBeFinalized(cx, entry.toAtom()));
continue;
}
if (IsAboutToBeFinalized(cx, entry.toAtom()))
e.removeFront();
}
}
bool
AtomIsInterned(JSContext *cx, JSAtom *atom)
{
if (atom->isStaticAtom())
return true;
AutoLockAtomsCompartment lock(cx);
AtomSet::Ptr p = cx->runtime->atomState.atoms.lookup(atom);
if (!p)
return false;
return p->isInterned();
}
/*
* Callers passing ATOM_NOCOPY have freshly allocated *pchars and thus this
* This call takes ownership of 'chars' if ATOM_NOCOPY is set.
* Non-branching code sequence to put the intern flag on |entryRef| if
* |intern| is true.
*
* Conceptually, we have compressed a HashMap<JSAtom *, uint> into a
* HashMap<size_t>. Here, we promise that we are only changing the "value" of
* the HashMap entry, so the const_cast is safe.
*/
static void
MakeInterned(const AutoLockAtomsCompartment &, const AtomStateEntry &entryRef, InternBehavior ib)
{
AtomStateEntry *entry = const_cast<AtomStateEntry *>(&entryRef);
AtomStateEntry::makeInterned(entry, ib);
JS_ASSERT(entryRef.isInterned() >= ib);
}
enum OwnCharsBehavior
{
CopyChars, /* in other words, do not take ownership */
TakeCharOwnership
};
/*
* Callers passing OwnChars have freshly allocated *pchars and thus this
* memory can be used as a new JSAtom's buffer without copying. When this flag
* is set, the contract is that callers will free *pchars iff *pchars == NULL.
*/
static JSAtom *
Atomize(JSContext *cx, const jschar **pchars, size_t length, uintN flags)
Atomize(JSContext *cx, const jschar **pchars, size_t length,
InternBehavior ib, OwnCharsBehavior ocb = CopyChars)
{
const jschar *chars = *pchars;
JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_NOCOPY)));
if (JSAtom *s = JSAtom::lookupStatic(chars, length))
return s;
@ -476,45 +473,65 @@ Atomize(JSContext *cx, const jschar **pchars, size_t length, uintN flags)
AtomSet &atoms = cx->runtime->atomState.atoms;
AtomSet::AddPtr p = atoms.lookupForAdd(AtomHasher::Lookup(chars, length));
JSAtom *atom;
if (p) {
atom = AtomEntryToKey(*p);
} else {
SwitchToCompartment sc(cx, cx->runtime->atomsCompartment);
JSFixedString *key;
if (flags & ATOM_NOCOPY) {
key = js_NewString(cx, const_cast<jschar *>(chars), length);
if (!key)
return NULL;
*pchars = NULL; /* Caller should not free *pchars. */
} else {
key = js_NewStringCopyN(cx, chars, length);
if (!key)
return NULL;
}
/*
* 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 */
return NULL;
}
atom = key->morphInternedStringIntoAtom();
JSAtom *atom = p->toAtom();
MakeInterned(lock, *p, ib);
return atom;
}
AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED));
return atom;
SwitchToCompartment sc(cx, cx->runtime->atomsCompartment);
JSFixedString *key;
if (ocb == TakeCharOwnership) {
key = js_NewString(cx, const_cast<jschar *>(chars), length);
if (!key)
return NULL;
*pchars = NULL; /* Called should not free *pchars. */
} else {
JS_ASSERT(ocb == CopyChars);
key = js_NewStringCopyN(cx, chars, length);
if (!key)
return NULL;
}
/*
* We have to relookup the key as the last ditch GC invoked from the
* string allocation or OOM handling may unlock the atomsCompartment.
*
* N.B. this avoids recomputing the hash but still has a potential
* (# collisions * # chars) comparison cost in the case of a hash
* collision!
*/
AtomHasher::Lookup lookup(chars, length);
if (!atoms.relookupOrAdd(p, lookup, AtomStateEntry(key, ib))) {
JS_ReportOutOfMemory(cx); /* SystemAllocPolicy does not report */
return NULL;
}
return key->morphAtomizedStringIntoAtom();
}
JSAtom *
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
js_AtomizeString(JSContext *cx, JSString *str, InternBehavior ib)
{
JS_ASSERT(!(flags & ATOM_NOCOPY));
if (str->isAtom()) {
JSAtom &atom = str->asAtom();
/* N.B. static atoms are effectively always interned. */
if (ib != InternAtom || atom.isStaticAtom())
return &atom;
/* Here we have to check whether the atom is already interned. */
AutoLockAtomsCompartment lock(cx);
AtomSet &atoms = cx->runtime->atomState.atoms;
AtomSet::Ptr p = atoms.lookup(AtomHasher::Lookup(&atom));
JS_ASSERT(p); /* Non-static atom must exist in atom state set. */
JS_ASSERT(p->toAtom() == &atom);
JS_ASSERT(ib == Intern);
MakeInterned(lock, *p, ib);
return &atom;
}
if (str->isAtom())
return &str->asAtom();
@ -525,13 +542,12 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
return NULL;
JS_ASSERT(length <= JSString::MAX_LENGTH);
return Atomize(cx, &chars, length, flags);
return Atomize(cx, &chars, length, ib);
}
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, InternBehavior ib, bool useCESU8)
{
JS_ASSERT(!(flags & ATOM_NOCOPY));
CHECK_REQUEST(cx);
if (!CheckStringLength(cx, length))
@ -549,6 +565,7 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags, bool us
size_t inflatedLength = ATOMIZE_BUF_MAX - 1;
const jschar *chars;
OwnCharsBehavior ocb = CopyChars;
if (length < ATOMIZE_BUF_MAX) {
if (useCESU8)
js_InflateUTF8StringToBuffer(cx, bytes, length, inflated, &inflatedLength, true);
@ -561,25 +578,24 @@ js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags, bool us
chars = js_InflateString(cx, bytes, &inflatedLength, useCESU8);
if (!chars)
return NULL;
flags |= ATOM_NOCOPY;
ocb = TakeCharOwnership;
}
JSAtom *atom = Atomize(cx, &chars, inflatedLength, flags);
if ((flags & ATOM_NOCOPY) && chars)
JSAtom *atom = Atomize(cx, &chars, inflatedLength, ib, ocb);
if (ocb == TakeCharOwnership && chars)
cx->free_((void *)chars);
return atom;
}
JSAtom *
js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, InternBehavior ib)
{
JS_ASSERT(!(flags & ATOM_NOCOPY));
CHECK_REQUEST(cx);
if (!CheckStringLength(cx, length))
return NULL;
return Atomize(cx, &chars, length, flags);
return Atomize(cx, &chars, length, ib);
}
JSAtom *
@ -589,7 +605,7 @@ js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
return atom;
AutoLockAtomsCompartment lock(cx);
AtomSet::Ptr p = cx->runtime->atomState.atoms.lookup(AtomHasher::Lookup(chars, length));
return p ? AtomEntryToKey(*p) : NULL;
return p ? p->toAtom() : NULL;
}
#ifdef DEBUG
@ -601,21 +617,12 @@ js_DumpAtoms(JSContext *cx, FILE *fp)
fprintf(fp, "atoms table contents:\n");
unsigned number = 0;
for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
AtomEntryType entry = r.front();
AtomStateEntry entry = r.front();
fprintf(fp, "%3u ", number++);
if (entry == 0) {
fputs("<uninitialized>", fp);
} else {
JSAtom *key = AtomEntryToKey(entry);
FileEscapedString(fp, key, '"');
uintN flags = AtomEntryFlags(entry);
if (flags != 0) {
fputs((flags & (ATOM_PINNED | ATOM_INTERNED))
? " pinned | interned"
: (flags & ATOM_PINNED) ? " pinned" : " interned",
fp);
}
}
JSAtom *key = entry.toAtom();
FileEscapeString(fp, key, '"');
if (entry.isInterned())
fputs(" interned", fp);
putc('\n', fp);
}
putc('\n', fp);

View File

@ -54,10 +54,6 @@
#include "jslock.h"
#include "jsvalue.h"
#define ATOM_PINNED 0x1 /* atom is pinned against GC */
#define ATOM_INTERNED 0x2 /* pinned variant for JS_Intern* API */
#define ATOM_NOCOPY 0x4 /* don't copy atom string bytes */
/* Engine-internal extensions of jsid */
static JS_ALWAYS_INLINE jsid
@ -278,42 +274,76 @@ struct JSAtomMap {
namespace js {
#define ATOM_ENTRY_FLAG_MASK ((size_t)(ATOM_PINNED | ATOM_INTERNED))
JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JS_GCTHING_ALIGN);
typedef uintptr_t AtomEntryType;
static JS_ALWAYS_INLINE JSAtom *
AtomEntryToKey(AtomEntryType entry)
enum InternBehavior
{
JS_ASSERT(entry != 0);
return (JSAtom *)(entry & ~ATOM_ENTRY_FLAG_MASK);
}
DoNotInternAtom = 0,
InternAtom = 1
};
/*
* Atom pointer with low bit stolen to indicate whether the atom is interned.
* Interned atoms are ignored by the GC, and thus live for the lifetime of the
* runtime.
*/
struct AtomStateEntry {
uintptr_t bits;
static const uintptr_t INTERNED_FLAG = 0x1;
AtomStateEntry() : bits(0) {}
AtomStateEntry(const AtomStateEntry &other) : bits(other.bits) {}
AtomStateEntry(JSFixedString *futureAtom, bool intern)
: bits(uintptr_t(futureAtom) | intern)
{}
bool isInterned() const {
return bits & INTERNED_FLAG;
}
/* In static form to avoid accidentally mutating a copy of a hash set value. */
static void makeInterned(AtomStateEntry *self, InternBehavior ib) {
JS_STATIC_ASSERT(DoNotInternAtom == 0 && InternAtom == 1);
JS_ASSERT(ib <= Intern);
self->bits |= uintptr_t(ib);
}
JS_ALWAYS_INLINE
JSAtom *toAtom() const {
JS_ASSERT(bits != 0); /* No NULL values should exist in the atom state. */
JS_ASSERT(((JSString *) (bits & ~INTERNED_FLAG))->isAtom());
return (JSAtom *) (bits & ~INTERNED_FLAG);
}
};
struct AtomHasher
{
struct Lookup
{
const jschar *chars;
size_t length;
Lookup(const jschar *chars, size_t length) : chars(chars), length(length) {}
const jschar *chars;
size_t length;
const JSAtom *atom; /* Optional. */
Lookup(const jschar *chars, size_t length) : chars(chars), length(length), atom(NULL) {}
Lookup(const JSAtom *atom) : chars(atom->chars()), length(atom->length()), atom(atom) {}
};
static HashNumber hash(const Lookup &l) {
return HashChars(l.chars, l.length);
}
static bool match(AtomEntryType entry, const Lookup &lookup) {
JS_ASSERT(entry);
JSAtom *key = AtomEntryToKey(entry);
static bool match(AtomStateEntry entry, const Lookup &lookup) {
JSAtom *key = entry.toAtom();
if (lookup.atom)
return lookup.atom == key;
if (key->length() != lookup.length)
return false;
return PodEqual(key->chars(), lookup.chars, lookup.length);
}
};
typedef HashSet<AtomEntryType, AtomHasher, SystemAllocPolicy> AtomSet;
typedef HashSet<AtomStateEntry, AtomHasher, SystemAllocPolicy> AtomSet;
} /* namespace js */
@ -463,29 +493,43 @@ struct JSAtomState
JSAtom *unwatchAtom;
JSAtom *watchAtom;
} lazy;
static const size_t commonAtomsOffset;
static const size_t lazyAtomsOffset;
void clearLazyAtoms() {
memset(&lazy, 0, sizeof(lazy));
}
void junkAtoms() {
#ifdef DEBUG
memset(commonAtomsStart(), JS_FREE_PATTERN, sizeof(*this) - commonAtomsOffset);
#endif
}
JSAtom **commonAtomsStart() {
return &emptyAtom;
}
void checkStaticInvariants();
};
extern bool
AtomIsInterned(JSContext *cx, JSAtom *atom);
#define ATOM(name) cx->runtime->atomState.name##Atom
#define ATOM_OFFSET_START offsetof(JSAtomState, emptyAtom)
#define LAZY_ATOM_OFFSET_START offsetof(JSAtomState, lazy)
#define ATOM_OFFSET_LIMIT (sizeof(JSAtomState))
#define COMMON_ATOMS_START(state) \
((JSAtom **)((uint8 *)(state) + ATOM_OFFSET_START))
#define COMMON_ATOM_INDEX(name) \
((offsetof(JSAtomState, name##Atom) - ATOM_OFFSET_START) \
((offsetof(JSAtomState, name##Atom) - JSAtomState::commonAtomsOffset) \
/ sizeof(JSAtom*))
#define COMMON_TYPE_ATOM_INDEX(type) \
((offsetof(JSAtomState, typeAtoms[type]) - ATOM_OFFSET_START) \
((offsetof(JSAtomState, typeAtoms[type]) - JSAtomState::commonAtomsOffset)\
/ sizeof(JSAtom*))
#define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom)
#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name])
#define CLASS_ATOM(cx,name) \
((cx)->runtime->atomState.classAtoms[JSProto_##name])
#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState, classAtoms[JSProto_##name])
#define CLASS_ATOM(cx,name) ((cx)->runtime->atomState.classAtoms[JSProto_##name])
extern const char *const js_common_atom_names[];
extern const size_t js_common_atom_count;
@ -588,7 +632,7 @@ js_TraceAtomState(JSTracer *trc);
extern void
js_SweepAtomState(JSContext *cx);
extern JSBool
extern bool
js_InitCommonAtoms(JSContext *cx);
extern void
@ -599,13 +643,15 @@ js_FinishCommonAtoms(JSContext *cx);
* memory.
*/
extern JSAtom *
js_AtomizeString(JSContext *cx, JSString *str, uintN flags);
js_AtomizeString(JSContext *cx, JSString *str, js::InternBehavior ib = js::DoNotInternAtom);
extern JSAtom *
js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags, bool useCESU8 = false);
js_Atomize(JSContext *cx, const char *bytes, size_t length,
js::InternBehavior ib = js::DoNotInternAtom, bool useCESU8 = false);
extern JSAtom *
js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags);
js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length,
js::InternBehavior ib = js::DoNotInternAtom);
/*
* Return an existing atom for the given char array or null if the char

View File

@ -51,7 +51,7 @@ js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp)
if (!str)
return false;
JS::Anchor<JSString *> anchor(str);
*atomp = js_AtomizeString(cx, str, 0);
*atomp = js_AtomizeString(cx, str);
return !!*atomp;
}
@ -61,7 +61,7 @@ js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp)
return true;
}
*atomp = js_AtomizeString(cx, str, 0);
*atomp = js_AtomizeString(cx, str);
return !!*atomp;
}
@ -144,7 +144,7 @@ IndexToId(JSContext *cx, uint32 index, jsid *idp)
if (!str)
return false;
JSAtom *atom = js_AtomizeString(cx, str, 0);
JSAtom *atom = js_AtomizeString(cx, str);
if (!atom)
return false;
*idp = ATOM_TO_JSID(atom);

View File

@ -260,7 +260,7 @@ HasProperty(JSContext* cx, JSObject* obj, jsid id)
JSBool FASTCALL
js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr)
{
JSAtom *atom = js_AtomizeString(cx, idstr, 0);
JSAtom *atom = js_AtomizeString(cx, idstr);
if (!atom)
return JS_NEITHER;

View File

@ -822,7 +822,7 @@ JSStructuredCloneReader::readId(jsid *idp)
JSString *str = readString(data);
if (!str)
return false;
JSAtom *atom = js_AtomizeString(context(), str, 0);
JSAtom *atom = js_AtomizeString(context(), str);
if (!atom)
return false;
*idp = ATOM_TO_JSID(atom);

View File

@ -1389,7 +1389,7 @@ static inline JSAtom **
FrameAtomBase(JSContext *cx, js::StackFrame *fp)
{
return fp->hasImacropc()
? COMMON_ATOMS_START(&cx->runtime->atomState)
? cx->runtime->atomState.commonAtomsStart()
: fp->script()->atomMap.vector;
}
@ -1875,7 +1875,7 @@ class AutoLockAtomsCompartment {
public:
AutoLockAtomsCompartment(JSContext *cx
JS_GUARD_OBJECT_NOTIFIER_PARAM)
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: cx(cx)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;

View File

@ -1323,8 +1323,8 @@ JSTreeContext::ensureSharpSlots()
JS_ASSERT(!(flags & TCF_HAS_SHARPS));
if (inFunction()) {
JSContext *cx = parser->context;
JSAtom *sharpArrayAtom = js_Atomize(cx, "#array", 6, 0);
JSAtom *sharpDepthAtom = js_Atomize(cx, "#depth", 6, 0);
JSAtom *sharpArrayAtom = js_Atomize(cx, "#array", 6);
JSAtom *sharpDepthAtom = js_Atomize(cx, "#depth", 6);
if (!sharpArrayAtom || !sharpDepthAtom)
return false;

View File

@ -404,9 +404,6 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj);
extern JSObject *
js_InitArgumentsClass(JSContext *cx, JSObject *obj);
extern void
js_TraceFunction(JSTracer *trc, JSFunction *fun);
extern void
js_FinalizeFunction(JSContext *cx, JSFunction *fun);

View File

@ -2259,7 +2259,7 @@ Interpret(JSContext *cx, StackFrame *entryFrame, uintN inlineCallCount, InterpMo
#define LOAD_ATOM(PCOFF, atom) \
JS_BEGIN_MACRO \
JS_ASSERT(regs.fp()->hasImacropc() \
? atoms == COMMON_ATOMS_START(&rt->atomState) && \
? atoms == rt->atomState.commonAtomsStart() && \
GET_INDEX(regs.pc + PCOFF) < js_common_atom_count \
: (size_t)(atoms - script->atomMap.vector) < \
(size_t)(script->atomMap.length - \
@ -2508,7 +2508,7 @@ Interpret(JSContext *cx, StackFrame *entryFrame, uintN inlineCallCount, InterpMo
}
if (regs.fp()->hasImacropc())
atoms = COMMON_ATOMS_START(&rt->atomState);
atoms = rt->atomState.commonAtomsStart();
#endif
/* Don't call the script prologue if executing between Method and Trace JIT. */
@ -2674,7 +2674,7 @@ Interpret(JSContext *cx, StackFrame *entryFrame, uintN inlineCallCount, InterpMo
break;
case ARECORD_IMACRO:
case ARECORD_IMACRO_ABORTED:
atoms = COMMON_ATOMS_START(&rt->atomState);
atoms = rt->atomState.commonAtomsStart();
op = JSOp(*regs.pc);
CLEAR_LEAVE_ON_TRACE_POINT();
if (status == ARECORD_IMACRO)

View File

@ -3995,7 +3995,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *protoProto,
JSPropertySpec *ps, JSFunctionSpec *fs,
JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
{
JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
if (!atom)
return NULL;
@ -4282,7 +4282,7 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
}
id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[protoKey]);
} else {
JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
if (!atom)
return false;
id = ATOM_TO_JSID(atom);
@ -6323,7 +6323,7 @@ js_XDRObject(JSXDRState *xdr, JSObject **objp)
if (protoKey != JSProto_Null) {
classDef |= (protoKey << 1);
} else {
atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
if (!atom)
return JS_FALSE;
}

View File

@ -87,7 +87,7 @@ JSONSourceParser::readString()
size_t length = current - start;
current++;
JSFlatString *str = (ST == JSONSourceParser::PropertyName)
? js_AtomizeChars(cx, start, length, 0)
? js_AtomizeChars(cx, start, length)
: js_NewStringCopyN(cx, start, length);
if (!str)
return token(OOM);

View File

@ -981,7 +981,7 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
* Save eval program source in script->atomMap.vector[0] for the
* eval cache (see EvalCacheLookup in jsobj.cpp).
*/
JSAtom *atom = js_AtomizeString(cx, source, 0);
JSAtom *atom = js_AtomizeString(cx, source);
if (!atom || !cg.atomList.add(&parser, atom))
goto out;
}
@ -8880,7 +8880,7 @@ FoldType(JSContext *cx, JSParseNode *pn, TokenKind type)
JSString *str = js_NumberToString(cx, pn->pn_dval);
if (!str)
return JS_FALSE;
pn->pn_atom = js_AtomizeString(cx, str, 0);
pn->pn_atom = js_AtomizeString(cx, str);
if (!pn->pn_atom)
return JS_FALSE;
pn->pn_type = TOK_STRING;
@ -9064,7 +9064,7 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
pn1->pn_type = TOK_XMLTEXT;
pn1->pn_op = JSOP_STRING;
pn1->pn_arity = PN_NULLARY;
pn1->pn_atom = js_AtomizeString(cx, accum, 0);
pn1->pn_atom = js_AtomizeString(cx, accum);
if (!pn1->pn_atom)
return JS_FALSE;
JS_ASSERT(pnp != &pn1->pn_next);
@ -9117,7 +9117,7 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
pn1->pn_type = TOK_XMLTEXT;
pn1->pn_op = JSOP_STRING;
pn1->pn_arity = PN_NULLARY;
pn1->pn_atom = js_AtomizeString(cx, accum, 0);
pn1->pn_atom = js_AtomizeString(cx, accum);
if (!pn1->pn_atom)
return JS_FALSE;
JS_ASSERT(pnp != &pn1->pn_next);
@ -9481,7 +9481,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
JS_ASSERT(*chars == 0);
/* Atomize the result string and mutate pn to refer to it. */
pn->pn_atom = js_AtomizeString(cx, str, 0);
pn->pn_atom = js_AtomizeString(cx, str);
if (!pn->pn_atom)
return JS_FALSE;
pn->pn_type = TOK_STRING;
@ -9506,7 +9506,7 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond)
str = js_ConcatStrings(cx, left, right);
if (!str)
return JS_FALSE;
pn->pn_atom = js_AtomizeString(cx, str, 0);
pn->pn_atom = js_AtomizeString(cx, str);
if (!pn->pn_atom)
return JS_FALSE;
pn->pn_type = TOK_STRING;

View File

@ -203,7 +203,7 @@ class NodeBuilder
Value funv;
const char *name = callbackNames[i];
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
if (!atom || !GetPropertyDefault(cx, userobj, ATOM_TO_JSID(atom), NullValue(), &funv))
return false;
@ -313,7 +313,7 @@ class NodeBuilder
/*
* Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
*/
JSAtom *atom = js_Atomize(cx, s, strlen(s), 0);
JSAtom *atom = js_Atomize(cx, s, strlen(s));
if (!atom)
return false;
@ -425,7 +425,7 @@ class NodeBuilder
/*
* Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
*/
JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
JSAtom *atom = js_Atomize(cx, name, strlen(name));
if (!atom)
return false;

View File

@ -1020,7 +1020,7 @@ TokenStream::getXMLMarkup(TokenKind *ttp, Token **tpp)
atom = cx->runtime->atomState.emptyAtom;
} else {
atom = js_AtomizeChars(cx, tokenbuf.begin() + contentIndex,
tokenbuf.length() - contentIndex, 0);
tokenbuf.length() - contentIndex);
if (!atom)
goto error;
}
@ -1184,7 +1184,7 @@ TokenStream::newToken(ptrdiff_t adjust)
JS_ALWAYS_INLINE JSAtom *
TokenStream::atomize(JSContext *cx, CharBuffer &cb)
{
return js_AtomizeChars(cx, cb.begin(), cb.length(), 0);
return js_AtomizeChars(cx, cb.begin(), cb.length());
}
#ifdef DEBUG
@ -1363,7 +1363,7 @@ TokenStream::getTokenInternal()
*/
JSAtom *atom;
if (!hadUnicodeEscape)
atom = js_AtomizeChars(cx, identStart, userbuf.addressOfNextRawChar() - identStart, 0);
atom = js_AtomizeChars(cx, identStart, userbuf.addressOfNextRawChar() - identStart);
else if (putIdentInTokenbuf(identStart))
atom = atomize(cx, tokenbuf);
else

View File

@ -610,6 +610,7 @@ struct Shape : public js::gc::Cell
void finalize(JSContext *cx);
void removeChild(js::Shape *child);
void removeChildSlowly(js::Shape *child);
};
struct EmptyShape : public js::Shape

View File

@ -262,7 +262,7 @@ Bindings::sharpSlotBase(JSContext *cx)
{
JS_ASSERT(lastBinding);
#if JS_HAS_SHARP_VARS
if (JSAtom *name = js_Atomize(cx, "#array", 6, 0)) {
if (JSAtom *name = js_Atomize(cx, "#array", 6)) {
uintN index = uintN(-1);
DebugOnly<BindingKind> kind = lookup(cx, name, &index);
JS_ASSERT(kind == VARIABLE);

View File

@ -649,7 +649,7 @@ StackDepth(JSScript *script)
if ((pc_) < (script_)->code || \
(script_)->code + (script_)->length <= (pc_)) { \
JS_ASSERT((size_t)(index) < js_common_atom_count); \
(atom) = COMMON_ATOMS_START(&cx->runtime->atomState)[index]; \
(atom) = cx->runtime->atomState.commonAtomsStart()[index]; \
} else { \
(atom) = script_->getAtom(index); \
} \

View File

@ -2068,7 +2068,7 @@ FindReplaceLength(JSContext *cx, RegExpStatics *res, ReplaceData &rdata, size_t
if (str->isAtom()) {
atom = &str->asAtom();
} else {
atom = js_AtomizeString(cx, str, 0);
atom = js_AtomizeString(cx, str);
if (!atom)
return false;
}
@ -3721,7 +3721,7 @@ StringBuffer::finishAtom()
if (length == 0)
return cx->runtime->atomState.emptyAtom;
JSAtom *atom = js_AtomizeChars(cx, cb.begin(), length, 0);
JSAtom *atom = js_AtomizeChars(cx, cb.begin(), length);
cb.clear();
return atom;
}

View File

@ -486,10 +486,11 @@ class JSFixedString : public JSFlatString
static inline JSFixedString *new_(JSContext *cx, const jschar *chars, size_t length);
/*
* Once a JSFixedString has been added to the atom table, this operation
* changes the type (in place) of the JSFixedString into a JSAtom.
* Once a JSFixedString has been added to the atom state, this operation
* changes the type (in place, as reflected by the flag bits) of the
* JSFixedString into a JSAtom.
*/
inline JSAtom *morphInternedStringIntoAtom();
inline JSAtom *morphAtomizedStringIntoAtom();
};
JS_STATIC_ASSERT(sizeof(JSFixedString) == sizeof(JSString));

View File

@ -344,7 +344,7 @@ JSFixedString::new_(JSContext *cx, const jschar *chars, size_t length)
}
JS_ALWAYS_INLINE JSAtom *
JSFixedString::morphInternedStringIntoAtom()
JSFixedString::morphAtomizedStringIntoAtom()
{
JS_ASSERT((d.lengthAndFlags & FLAGS_MASK) == JS_BIT(2));
JS_STATIC_ASSERT(NON_STATIC_ATOM == JS_BIT(3));

View File

@ -12470,11 +12470,11 @@ RootedStringToId(JSContext* cx, JSString** namep, jsid* idp)
{
JSString* name = *namep;
if (name->isAtom()) {
*idp = INTERNED_STRING_TO_JSID(name);
*idp = ATOM_TO_JSID(&name->asAtom());
return true;
}
JSAtom* atom = js_AtomizeString(cx, name, 0);
JSAtom* atom = js_AtomizeString(cx, name);
if (!atom)
return false;
*namep = atom; /* write back to GC root */

View File

@ -87,6 +87,8 @@ JS_Assert(const char *s, const char *file, JSIntn ln);
# define JS_THREADSAFE_ASSERT(expr) ((void) 0)
# endif
#define JS_FREE_PATTERN 0xDA
#else
#define JS_ASSERT(expr) ((void) 0)

View File

@ -658,7 +658,7 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **atomp)
if (!buf)
return false;
JSAtom *atom = js_Atomize(xdr->cx, buf, len, 0, true);
JSAtom *atom = js_Atomize(xdr->cx, buf, len, DoNotInternAtom, true);
if (!atom)
return false;

View File

@ -2872,7 +2872,7 @@ ToXMLName(JSContext *cx, jsval v, jsid *funidp)
return NULL;
}
atomizedName = js_AtomizeString(cx, name, 0);
atomizedName = js_AtomizeString(cx, name);
if (!atomizedName)
return NULL;
@ -5344,7 +5344,7 @@ ValueToId(JSContext *cx, jsval v, AutoIdRooter *idr)
else if (!js_ValueToStringId(cx, Valueify(v), idr->addr()))
return JS_FALSE;
} else if (JSVAL_IS_STRING(v)) {
JSAtom *atom = js_AtomizeString(cx, JSVAL_TO_STRING(v), 0);
JSAtom *atom = js_AtomizeString(cx, JSVAL_TO_STRING(v));
if (!atom)
return JS_FALSE;
*idr->addr() = ATOM_TO_JSID(atom);

View File

@ -190,7 +190,7 @@ PRBool InitializeMember(JSContext * cx, ITypeInfo * pTypeInfo,
pInfo = new (pInfo) XPCDispInterface::Member;
if(!pInfo)
return PR_FALSE;
pInfo->SetName(INTERNED_STRING_TO_JSID(str));
pInfo->SetName(INTERNED_STRING_TO_JSID(cx, str));
pInfo->ResetType();
ConvertInvokeKind(pFuncDesc->invkind, *pInfo);
pInfo->SetTypeInfo(pFuncDesc->memid, pTypeInfo, pFuncDesc);

View File

@ -548,7 +548,7 @@ GetMethodInfo(JSContext *cx, jsval *vp, const char **ifaceNamep, jsid *memberIdp
NS_ASSERTION(JS_ObjectIsFunction(cx, funobj),
"JSNative callee should be Function object");
JSString *str = JS_GetFunctionId((JSFunction *) JS_GetPrivate(cx, funobj));
jsid methodId = str ? INTERNED_STRING_TO_JSID(str) : JSID_VOID;
jsid methodId = str ? INTERNED_STRING_TO_JSID(cx, str) : JSID_VOID;
GetMemberInfo(JSVAL_TO_OBJECT(vp[1]), methodId, ifaceNamep);
*memberIdp = methodId;
}

View File

@ -382,7 +382,7 @@ XPCNativeInterface::NewInstance(XPCCallContext& ccx,
failed = JS_TRUE;
break;
}
name = INTERNED_STRING_TO_JSID(str);
name = INTERNED_STRING_TO_JSID(ccx, str);
if(info->IsSetter())
{
@ -426,7 +426,7 @@ XPCNativeInterface::NewInstance(XPCCallContext& ccx,
failed = JS_TRUE;
break;
}
name = INTERNED_STRING_TO_JSID(str);
name = INTERNED_STRING_TO_JSID(ccx, str);
// XXX need better way to find dups
//NS_ASSERTION(!LookupMemberByID(name),"duplicate method/constant name");
@ -445,7 +445,7 @@ XPCNativeInterface::NewInstance(XPCCallContext& ccx,
{
failed = JS_TRUE;
}
interfaceName = INTERNED_STRING_TO_JSID(str);
interfaceName = INTERNED_STRING_TO_JSID(ccx, str);
}
if(!failed)