Back out bug 654301 to run again on try.
authorChris Leary <cdleary@mozilla.com>
Mon, 16 May 2011 19:03:20 -0700
changeset 69901 c56c1dc32a542f515678dbd059c3696f2673d359
parent 69900 6d615d5101bbdb1b25d8766f80030e91a084a4fd
child 69902 0cf1acdb20b18120b939dd421e2c2fd8ef91f313
push idunknown
push userunknown
push dateunknown
bugs654301
milestone6.0a1
Back out bug 654301 to run again on try.
caps/src/nsScriptSecurityManager.cpp
content/events/src/nsEventListenerManager.cpp
content/html/document/src/nsHTMLDocument.cpp
dom/plugins/base/nsJSNPRuntime.cpp
dom/plugins/base/nsNPAPIPlugin.h
js/src/jsapi-tests/Makefile.in
js/src/jsapi-tests/testIntern.cpp
js/src/jsapi-tests/testStringBuffer.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarena.h
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsatom.h
js/src/jsatominlines.h
js/src/jsbuiltins.cpp
js/src/jsclone.cpp
js/src/jscntxt.h
js/src/jsemit.cpp
js/src/jsfun.h
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jsonparser.cpp
js/src/jsparse.cpp
js/src/jsreflect.cpp
js/src/jsscan.cpp
js/src/jsscope.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jsstr.h
js/src/jsstrinlines.h
js/src/jstracer.cpp
js/src/jsutil.h
js/src/jsxdrapi.cpp
js/src/jsxml.cpp
js/src/xpconnect/src/XPCDispInterface.cpp
js/src/xpconnect/src/xpcquickstubs.cpp
js/src/xpconnect/src/xpcwrappednativeinfo.cpp
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -3422,17 +3422,17 @@ nsresult nsScriptSecurityManager::Init()
     NS_ADDREF(sXPConnect = xpconnect);
     NS_ADDREF(sJSContextStack = xpconnect);
 
     JSContext* cx = GetSafeJSContext();
     if (!cx) return NS_ERROR_FAILURE;   // this can happen of xpt loading fails
     
     ::JS_BeginRequest(cx);
     if (sEnabledID == JSID_VOID)
-        sEnabledID = INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "enabled"));
+        sEnabledID = INTERNED_STRING_TO_JSID(::JS_InternString(cx, "enabled"));
     ::JS_EndRequest(cx);
 
     InitPrefs();
 
     nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIStringBundleService> bundleService =
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -903,17 +903,17 @@ nsEventListenerManager::RegisterScriptEv
   JSContext *cx;
   if (NS_FAILED(rv = stack->Peek(&cx)))
     return rv;
 
   if (cx) {
     if (sAddListenerID == JSID_VOID) {
       JSAutoRequest ar(cx);
       sAddListenerID =
-        INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "addEventListener"));
+        INTERNED_STRING_TO_JSID(::JS_InternString(cx, "addEventListener"));
     }
 
     if (aContext->GetScriptTypeID() == nsIProgrammingLanguage::JAVASCRIPT) {
         nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
         jsval v;
         rv = nsContentUtils::WrapNative(cx, (JSObject *)aScope, aObject, &v,
                                         getter_AddRefs(holder));
         NS_ENSURE_SUCCESS(rv, rv);
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -3317,25 +3317,25 @@ nsHTMLDocument::DoClipboardSecurityCheck
 
     NS_NAMED_LITERAL_CSTRING(classNameStr, "Clipboard");
 
     nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
 
     if (aPaste) {
       if (nsHTMLDocument::sPasteInternal_id == JSID_VOID) {
         nsHTMLDocument::sPasteInternal_id =
-          INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "paste"));
+          INTERNED_STRING_TO_JSID(::JS_InternString(cx, "paste"));
       }
       rv = secMan->CheckPropertyAccess(cx, nsnull, classNameStr.get(),
                                        nsHTMLDocument::sPasteInternal_id,
                                        nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
     } else {
       if (nsHTMLDocument::sCutCopyInternal_id == JSID_VOID) {
         nsHTMLDocument::sCutCopyInternal_id =
-          INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "cutcopy"));
+          INTERNED_STRING_TO_JSID(::JS_InternString(cx, "cutcopy"));
       }
       rv = secMan->CheckPropertyAccess(cx, nsnull, classNameStr.get(),
                                        nsHTMLDocument::sCutCopyInternal_id,
                                        nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
     }
   }
   return rv;
 }
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -980,17 +980,17 @@ nsJSObjWrapper::NP_Enumerate(NPObject *n
     if (JSVAL_IS_STRING(v)) {
       JSString *str = JS_InternJSString(cx, JSVAL_TO_STRING(v));
       if (!str) {
           ::JS_DestroyIdArray(cx, ida);
           PR_Free(*idarray);
 
           return PR_FALSE;
       }
-      id = StringToNPIdentifier(cx, str);
+      id = StringToNPIdentifier(str);
     } else {
       NS_ASSERTION(JSVAL_IS_INT(v),
                    "The element in ida must be either string or int!\n");
       id = IntToNPIdentifier(JSVAL_TO_INT(v));
     }
 
     (*idarray)[i] = id;
   }
@@ -1468,18 +1468,18 @@ CallNPMethodInternal(JSContext *cx, JSOb
       msg = "Attempt to construct object from class with no constructor.";
     }
   } else if (funobj != obj) {
     // A obj.function() style call is made, get the method name from
     // the function object.
 
     if (npobj->_class->invoke) {
       JSFunction *fun = (JSFunction *)::JS_GetPrivate(cx, funobj);
-      JSString *name = ::JS_InternJSString(cx, ::JS_GetFunctionId(fun));
-      NPIdentifier id = StringToNPIdentifier(cx, name);
+      JSString *name = ::JS_GetFunctionId(fun);
+      NPIdentifier id = StringToNPIdentifier(name);
 
       ok = npobj->_class->invoke(npobj, id, npargs, argc, &v);
     } else {
       ok = JS_FALSE;
 
       msg = "Attempt to call a method on object with no invoke method.";
     }
   } else {
--- a/dom/plugins/base/nsNPAPIPlugin.h
+++ b/dom/plugins/base/nsNPAPIPlugin.h
@@ -139,19 +139,19 @@ NPIdentifierIsString(NPIdentifier id)
 
 static inline JSString *
 NPIdentifierToString(NPIdentifier id)
 {
     return JSID_TO_STRING(NPIdentifierToJSId(id));
 }
 
 static inline NPIdentifier
-StringToNPIdentifier(JSContext *cx, JSString *str)
+StringToNPIdentifier(JSString *str)
 {
-    return JSIdToNPIdentifier(INTERNED_STRING_TO_JSID(cx, str));
+    return JSIdToNPIdentifier(INTERNED_STRING_TO_JSID(str));
 }
 
 static inline bool
 NPIdentifierIsInt(NPIdentifier id)
 {
     return JSID_IS_INT(NPIdentifierToJSId(id));
 }
 
--- a/js/src/jsapi-tests/Makefile.in
+++ b/js/src/jsapi-tests/Makefile.in
@@ -58,17 +58,16 @@ CPPSRCS = \
   testDeepFreeze.cpp \
   testDefineGetterSetterNonEnumerable.cpp \
   testDefineProperty.cpp \
   testExtendedEq.cpp \
   testFuncCallback.cpp \
   testGCChunkAlloc.cpp \
   testGetPropertyDefault.cpp \
   testIntString.cpp \
-  testIntern.cpp \
   testLookup.cpp \
   testLooselyEqual.cpp \
   testNewObject.cpp \
   testOps.cpp \
   testParseJSON.cpp \
   testPropCache.cpp \
   testResolveRecursion.cpp \
   testSameValue.cpp \
deleted file mode 100644
--- a/js/src/jsapi-tests/testIntern.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#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)
--- a/js/src/jsapi-tests/testStringBuffer.cpp
+++ b/js/src/jsapi-tests/testStringBuffer.cpp
@@ -9,17 +9,17 @@
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
 BEGIN_TEST(testStringBuffer_finishString)
 {
     JSString *str = JS_NewStringCopyZ(cx, "foopy");
     CHECK(str);
 
-    JSAtom *atom = js_AtomizeString(cx, str);
+    JSAtom *atom = js_AtomizeString(cx, str, 0);
     CHECK(atom);
 
     js::StringBuffer buffer(cx);
     CHECK(buffer.append("foopy"));
 
     JSAtom *finishedAtom = buffer.finishAtom();
     CHECK(finishedAtom);
     CHECK(atom == finishedAtom);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1569,17 +1569,17 @@ StdNameToAtom(JSContext *cx, JSStdName *
     JSAtom *atom;
     const char *name;
 
     offset = stdn->atomOffset;
     atom = OFFSET_TO_ATOM(cx->runtime, offset);
     if (!atom) {
         name = stdn->name;
         if (name) {
-            atom = js_Atomize(cx, name, strlen(name), InternAtom);
+            atom = js_Atomize(cx, name, strlen(name), ATOM_PINNED);
             OFFSET_TO_ATOM(cx->runtime, offset) = atom;
         }
     }
     return atom;
 }
 
 /*
  * Table of class initializers and their atom offsets in rt->atomState.
@@ -3231,24 +3231,24 @@ JS_PUBLIC_API(JSBool)
 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
 {
     return JS_LookupPropertyById(cx, obj, INT_TO_JSID(index), vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
 {
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     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));
+    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     return atom && JS_LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
                                JSObject **objp, jsval *vp)
 {
     JSBool ok;
@@ -3261,17 +3261,17 @@ JS_LookupPropertyWithFlagsById(JSContext
          : obj->lookupProperty(cx, id, objp, &prop);
     return ok && LookupResult(cx, obj, *objp, id, prop, Valueify(vp));
 }
 
 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));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     return atom && JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags, &obj2, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
 {
     JSObject *obj2;
     JSProperty *prop;
@@ -3285,24 +3285,24 @@ JS_PUBLIC_API(JSBool)
 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
 {
     return JS_HasPropertyById(cx, obj, INT_TO_JSID(index), foundp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_HasProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
 {
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     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));
+    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     return atom && JS_HasPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
@@ -3327,25 +3327,25 @@ JS_PUBLIC_API(JSBool)
 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
 {
     return JS_AlreadyHasOwnPropertyById(cx, obj, INT_TO_JSID(index), foundp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name, JSBool *foundp)
 {
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
 }
 
 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));
+    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     return atom && JS_AlreadyHasOwnPropertyById(cx, obj, ATOM_TO_JSID(atom), foundp);
 }
 
 static JSBool
 DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value,
                    PropertyOp getter, StrictPropertyOp setter, uintN attrs,
                    uintN flags, intN tinyid)
 {
@@ -3390,17 +3390,17 @@ DefineProperty(JSContext *cx, JSObject *
     jsid id;
     JSAtom *atom;
 
     if (attrs & JSPROP_INDEX) {
         id = INT_TO_JSID(intptr_t(name));
         atom = NULL;
         attrs &= ~JSPROP_INDEX;
     } else {
-        atom = js_Atomize(cx, name, strlen(name));
+        atom = js_Atomize(cx, name, strlen(name), 0);
         if (!atom)
             return JS_FALSE;
         id = ATOM_TO_JSID(atom);
     }
     return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, flags, tinyid);
 }
 
 JS_PUBLIC_API(JSBool)
@@ -3419,17 +3419,17 @@ JS_DefinePropertyWithTinyId(JSContext *c
                           Valueify(setter), attrs, Shape::HAS_SHORTID, tinyid);
 }
 
 static JSBool
 DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
                  const Value &value, PropertyOp getter, StrictPropertyOp setter, uintN attrs,
                  uintN flags, intN tinyid)
 {
-    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
+    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     return atom && DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
                                       flags, tinyid);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
                     jsval value, JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
 {
@@ -3517,31 +3517,31 @@ JS_AliasProperty(JSContext *cx, JSObject
     JSObject *obj2;
     JSProperty *prop;
     JSBool ok;
     Shape *shape;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     if (!atom)
         return JS_FALSE;
     if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
         return JS_FALSE;
     if (!prop) {
         js_ReportIsNotDefined(cx, name);
         return JS_FALSE;
     }
     if (obj2 != obj || !obj->isNative()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
                              alias, name, obj2->getClass()->name);
         return JS_FALSE;
     }
-    atom = js_Atomize(cx, alias, strlen(alias));
+    atom = js_Atomize(cx, alias, strlen(alias), 0);
     if (!atom) {
         ok = JS_FALSE;
     } else {
         shape = (Shape *)prop;
         ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
                                    shape->getter(), shape->setter(), shape->slot,
                                    shape->attributes(), shape->getFlags() | Shape::ALIAS,
                                    shape->shortid)
@@ -3555,17 +3555,17 @@ JS_AliasElement(JSContext *cx, JSObject 
 {
     JSObject *obj2;
     JSProperty *prop;
     Shape *shape;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     if (!atom)
         return JS_FALSE;
     if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
         return JS_FALSE;
     if (!prop) {
         js_ReportIsNotDefined(cx, name);
         return JS_FALSE;
     }
@@ -3660,47 +3660,47 @@ JS_GetPropertyAttrsGetterAndSetterById(J
         *setterp = Jsvalify(desc.setter);
     return true;
 }
 
 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));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
                                                           attrsp, foundp, NULL, NULL);
 }
 
 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));
+    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
                                                           attrsp, foundp, NULL, NULL);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj, const char *name,
                                    uintN *attrsp, JSBool *foundp,
                                    JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
 {
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
                                                           attrsp, foundp, getterp, setterp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetUCPropertyAttrsGetterAndSetter(JSContext *cx, JSObject *obj,
                                      const jschar *name, size_t namelen,
                                      uintN *attrsp, JSBool *foundp,
                                      JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
 {
-    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
+    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     return atom && JS_GetPropertyAttrsGetterAndSetterById(cx, obj, ATOM_TO_JSID(atom),
                                                           attrsp, foundp, getterp, setterp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     CHECK_REQUEST(cx);
@@ -3726,25 +3726,25 @@ SetPropertyAttributesById(JSContext *cx,
         *foundp = true;
     return ok;
 }
 
 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));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
 }
 
 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));
+    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     return atom && SetPropertyAttributesById(cx, obj, ATOM_TO_JSID(atom), attrs, foundp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
@@ -3762,31 +3762,31 @@ JS_PUBLIC_API(JSBool)
 JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
 {
     return JS_GetPropertyById(cx, obj, INT_TO_JSID(index), vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
 {
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     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));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     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));
+    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     return atom && JS_GetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval *vp)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
@@ -3795,17 +3795,17 @@ JS_GetMethodById(JSContext *cx, JSObject
     if (objp)
         *objp = obj;
     return JS_TRUE;
 }
 
 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));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     return atom && JS_GetMethodById(cx, obj, ATOM_TO_JSID(atom), objp, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
@@ -3817,24 +3817,24 @@ JS_PUBLIC_API(JSBool)
 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
 {
     return JS_SetPropertyById(cx, obj, INT_TO_JSID(index), vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
 {
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     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));
+    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     return atom && JS_SetPropertyById(cx, obj, ATOM_TO_JSID(atom), vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
@@ -3846,24 +3846,24 @@ JS_PUBLIC_API(JSBool)
 JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
 {
     return JS_DeletePropertyById2(cx, obj, INT_TO_JSID(index), rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeleteProperty2(JSContext *cx, JSObject *obj, const char *name, jsval *rval)
 {
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     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));
+    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     return atom && JS_DeletePropertyById2(cx, obj, ATOM_TO_JSID(atom), rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id)
 {
     jsval junk;
     return JS_DeletePropertyById2(cx, obj, id, &junk);
@@ -4183,17 +4183,17 @@ JS_NewFunction(JSContext *cx, JSNative n
     JSAtom *atom;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, parent);
 
     if (!name) {
         atom = NULL;
     } else {
-        atom = js_Atomize(cx, name, strlen(name));
+        atom = js_Atomize(cx, name, strlen(name), 0);
         if (!atom)
             return NULL;
     }
     return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, atom);
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_NewFunctionById(JSContext *cx, JSNative native, uintN nargs, uintN flags, JSObject *parent,
@@ -4392,31 +4392,31 @@ JS_DefineFunctions(JSContext *cx, JSObje
 
 JS_PUBLIC_API(JSFunction *)
 JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call,
                   uintN nargs, uintN attrs)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     if (!atom)
         return NULL;
     return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_DefineUCFunction(JSContext *cx, JSObject *obj,
                     const jschar *name, size_t namelen, JSNative call,
                     uintN nargs, uintN attrs)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
-    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
+    JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
     if (!atom)
         return NULL;
     return js_DefineFunction(cx, obj, ATOM_TO_JSID(atom), Valueify(call), nargs, attrs);
 }
 
 extern JS_PUBLIC_API(JSFunction *)
 JS_DefineFunctionById(JSContext *cx, JSObject *obj, jsid id, JSNative call,
                     uintN nargs, uintN attrs)
@@ -4732,17 +4732,17 @@ CompileUCFunctionForPrincipalsCommon(JSC
     JSAtom *funAtom, *argAtom;
     uintN i;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, principals);
     if (!name) {
         funAtom = NULL;
     } else {
-        funAtom = js_Atomize(cx, name, strlen(name));
+        funAtom = js_Atomize(cx, name, strlen(name), 0);
         if (!funAtom) {
             fun = NULL;
             goto out2;
         }
     }
 
     fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
     if (!fun)
@@ -4757,17 +4757,17 @@ CompileUCFunctionForPrincipalsCommon(JSC
         AutoShapeRooter shapeRoot(cx, emptyCallShape);
 
         AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
         MUST_FLOW_THROUGH("out");
 
         Bindings bindings(cx, emptyCallShape);
         AutoBindingsRooter root(cx, bindings);
         for (i = 0; i < nargs; i++) {
-            argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]));
+            argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
             if (!argAtom) {
                 fun = NULL;
                 goto out2;
             }
 
             uint16 dummy;
             if (!bindings.addArgument(cx, argAtom, &dummy)) {
                 fun = NULL;
@@ -5054,17 +5054,17 @@ JS_PUBLIC_API(JSBool)
 JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, jsval *argv,
                     jsval *rval)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, JSValueArray(argv, argc));
 
     AutoValueRooter tvr(cx);
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
+    JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     JSBool ok =
         atom &&
         js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) &&
         ExternalInvoke(cx, ObjectOrNullValue(obj), tvr.value(), argc, Valueify(argv),
                        Valueify(rval));
     LAST_FRAME_CHECKS(cx, ok);
     return ok;
 }
@@ -5240,42 +5240,33 @@ JS_NewStringCopyZ(JSContext *cx, const c
         return NULL;
     str = js_NewString(cx, js, n);
     if (!str)
         cx->free_(js);
     return str;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_StringHasBeenInterned(JSContext *cx, JSString *str)
-{
-    CHECK_REQUEST(cx);
-
-    if (!str->isAtom())
-        return false;
-
-    return AtomIsInterned(cx, &str->asAtom());
+JS_StringHasBeenInterned(JSString *str)
+{
+    return str->isAtom();
 }
 
 JS_PUBLIC_API(JSString *)
 JS_InternJSString(JSContext *cx, JSString *str)
 {
     CHECK_REQUEST(cx);
-    JSAtom *atom = js_AtomizeString(cx, str, InternAtom);
-    JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
-    return atom;
+    return js_AtomizeString(cx, str, 0);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_InternString(JSContext *cx, const char *s)
 {
     CHECK_REQUEST(cx);
-    JSAtom *atom = js_Atomize(cx, s, strlen(s), InternAtom);
-    JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
-    return atom;
+    return js_Atomize(cx, s, strlen(s), ATOM_INTERNED);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
 {
     CHECK_REQUEST(cx);
     return js_NewString(cx, chars, length);
 }
@@ -5295,19 +5286,17 @@ JS_NewUCStringCopyZ(JSContext *cx, const
         return cx->runtime->emptyString;
     return js_NewStringCopyZ(cx, s);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_InternUCStringN(JSContext *cx, const jschar *s, size_t length)
 {
     CHECK_REQUEST(cx);
-    JSAtom *atom = js_AtomizeChars(cx, s, length, InternAtom);
-    JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
-    return atom;
+    return js_AtomizeChars(cx, s, length, ATOM_INTERNED);
 }
 
 JS_PUBLIC_API(JSString *)
 JS_InternUCString(JSContext *cx, const jschar *s)
 {
     return JS_InternUCStringN(cx, s, js_strlen(s));
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -328,32 +328,26 @@ JSID_TO_STRING(jsid id)
 
 static JS_ALWAYS_INLINE JSBool
 JSID_IS_ZERO(jsid id)
 {
     return JSID_BITS(id) == 0;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_StringHasBeenInterned(JSContext *cx, JSString *str);
-
-/*
- * 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.
- */
+JS_StringHasBeenInterned(JSString *str);
+
+/* A jsid may only hold an interned JSString. */
 static JS_ALWAYS_INLINE jsid
-INTERNED_STRING_TO_JSID(JSContext *cx, JSString *str)
+INTERNED_STRING_TO_JSID(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;
 }
 
 static JS_ALWAYS_INLINE JSBool
 JSID_IS_INT(jsid id)
 {
     return !!(JSID_BITS(id) & JSID_TYPE_INT);
--- a/js/src/jsarena.h
+++ b/js/src/jsarena.h
@@ -159,16 +159,17 @@ struct JSArenaPool {
 
 /*
  * Check if the mark is inside arena's allocated area.
  */
 #define JS_ARENA_MARK_MATCH(a, mark)                                          \
     (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))
 #define JS_CLEAR_ARENA(a)       memset((void*)(a), JS_FREE_PATTERN,           \
                                        (a)->limit - (jsuword)(a))
 #else
 #define JS_CLEAR_UNUSED(a)      /* nothing */
 #define JS_CLEAR_ARENA(a)       /* nothing */
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -273,17 +273,17 @@ BigIndexToId(JSContext *cx, JSObject *ob
          obj->isArguments() ||
          clasp == &js_ObjectClass)) {
         atom = js_GetExistingStringAtom(cx, start, JS_ARRAY_END(buf) - start);
         if (!atom) {
             *idp = JSID_VOID;
             return JS_TRUE;
         }
     } else {
-        atom = js_AtomizeChars(cx, start, JS_ARRAY_END(buf) - start);
+        atom = js_AtomizeChars(cx, start, JS_ARRAY_END(buf) - start, 0);
         if (!atom)
             return JS_FALSE;
     }
 
     *idp = ATOM_TO_JSID(atom);
     return JS_TRUE;
 }
 
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -62,25 +62,38 @@
 
 #include "jsstrinlines.h"
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 
 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)
 {
     return js_ValueToPrintable(cx, StringValue(atom), bytes);
 }
 
 #define JS_PROTO(name,code,init) const char js_##name##_str[] = #name;
 #include "jsproto.tbl"
@@ -199,38 +212,18 @@ const char *const js_common_atom_names[]
     "has",                      /* hasAtom                      */
     "hasOwn",                   /* hasOwnAtom                   */
     "keys",                     /* keysAtom                     */
     "iterate",                  /* iterateAtom                  */
 
     "WeakMap"                   /* WeakMapAtom                  */
 };
 
-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);
-}
+JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) * sizeof(JSAtom *) ==
+                 LAZY_ATOM_OFFSET_START - ATOM_OFFSET_START);
 
 /*
  * Interpreter macros called by the trace recorder assume common atom indexes
  * fit in one byte of immediate operand.
  */
 JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_common_atom_names) < 256);
 
 const size_t js_common_atom_count = JS_ARRAY_LENGTH(js_common_atom_names);
@@ -298,16 +291,50 @@ const char js_xml_str[]             = "x
 #endif
 
 #if JS_HAS_GENERATORS
 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
  * economical embeddings allocating too much memory initially we initialize
  * atomized strings with just 1K entries.
  */
 #define JS_STRING_HASH_COUNT   1024
 
 JSBool
@@ -335,224 +362,181 @@ js_FinishAtomState(JSRuntime *rt)
         /*
          * We are called with uninitialized state when JS_NewRuntime fails and
          * calls JS_DestroyRuntime on a partially initialized runtime.
          */
         return;
     }
 
     for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront())
-        r.front().toAtom()->finalize(rt);
+        AtomEntryToKey(r.front())->finalize(rt);
 
 #ifdef JS_THREADSAFE
     js_FinishLock(&state->lock);
 #endif
 }
 
-bool
+JSBool
 js_InitCommonAtoms(JSContext *cx)
 {
     JSAtomState *state = &cx->runtime->atomState;
-    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);
+    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);
         if (!*atoms)
-            return false;
+            return JS_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 true;
+    return JS_TRUE;
 }
 
 void
 js_FinishCommonAtoms(JSContext *cx)
 {
     cx->runtime->emptyString = NULL;
-    cx->runtime->atomState.junkAtoms();
+    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
 }
 
 void
 js_TraceAtomState(JSTracer *trc)
 {
     JSRuntime *rt = trc->context->runtime;
     JSAtomState *state = &rt->atomState;
 
 #ifdef DEBUG
     size_t number = 0;
 #endif
 
     if (rt->gcKeepAtoms) {
         for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
             JS_SET_TRACING_INDEX(trc, "locked_atom", number++);
-            MarkString(trc, r.front().toAtom());
+            MarkString(trc, AtomEntryToKey(r.front()));
         }
     } else {
         for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
-            AtomStateEntry entry = r.front();
-            if (!entry.isInterned())
-                continue;
-
-            JS_SET_TRACING_INDEX(trc, "interned_atom", number++);
-            MarkString(trc, entry.toAtom());
+            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));
+            }
         }
     }
 }
 
 void
 js_SweepAtomState(JSContext *cx)
 {
     JSAtomState *state = &cx->runtime->atomState;
 
     for (AtomSet::Enum e(state->atoms); !e.empty(); e.popFront()) {
-        AtomStateEntry entry = e.front();
-
-        if (entry.isInterned()) {
+        AtomEntryType entry = e.front();
+        if (AtomEntryFlags(entry) & (ATOM_PINNED | ATOM_INTERNED)) {
             /* Pinned or interned key cannot be finalized. */
-            JS_ASSERT(!IsAboutToBeFinalized(cx, entry.toAtom()));
-            continue;
+            JS_ASSERT(!IsAboutToBeFinalized(cx, AtomEntryToKey(entry)));
+        } else if (IsAboutToBeFinalized(cx, AtomEntryToKey(entry))) {
+            e.removeFront();
         }
-        
-        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();
-}
-
 /*
- * 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
+ * Callers passing ATOM_NOCOPY 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,
-        InternBehavior ib, OwnCharsBehavior ocb = CopyChars)
+Atomize(JSContext *cx, const jschar **pchars, size_t length, uintN flags)
 {
     const jschar *chars = *pchars;
+    JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_NOCOPY)));
 
     if (JSAtom *s = JSAtom::lookupStatic(chars, length))
         return s;
 
     AutoLockAtomsCompartment lock(cx);
 
     AtomSet &atoms = cx->runtime->atomState.atoms;
     AtomSet::AddPtr p = atoms.lookupForAdd(AtomHasher::Lookup(chars, length));
 
+    JSAtom *atom;
     if (p) {
-        JSAtom *atom = p->toAtom();
-        MakeInterned(lock, *p, ib);
-        return atom;
+        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();
     }
 
-    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();
+    AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED));
+    return atom;
 }
 
 JSAtom *
-js_AtomizeString(JSContext *cx, JSString *str, InternBehavior ib)
+js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
 {
-    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 == InternAtom);
-        MakeInterned(lock, *p, ib);
-        return &atom;
-    }
+    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, ib);
+    return Atomize(cx, &chars, length, flags);
 }
 
 JSAtom *
-js_Atomize(JSContext *cx, const char *bytes, size_t length, InternBehavior ib, bool useCESU8)
+js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags, bool useCESU8)
 {
+    JS_ASSERT(!(flags & ATOM_NOCOPY));
     CHECK_REQUEST(cx);
 
     if (!CheckStringLength(cx, length))
         return NULL;
 
     /*
      * Avoiding the malloc in js_InflateString on shorter strings saves us
      * over 20,000 malloc calls on mozilla browser startup. This compares to
@@ -560,74 +544,83 @@ js_Atomize(JSContext *cx, const char *by
      * The vast majority of atomized strings are already in the hashtable. So
      * js_AtomizeString rarely has to copy the temp string we make.
      */
     static const unsigned ATOMIZE_BUF_MAX = 32;
     jschar inflated[ATOMIZE_BUF_MAX];
     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);
         else
             js_InflateStringToBuffer(cx, bytes, length, inflated, &inflatedLength);
         inflated[inflatedLength] = 0;
         chars = inflated;
     } else {
         inflatedLength = length;
         chars = js_InflateString(cx, bytes, &inflatedLength, useCESU8);
         if (!chars)
             return NULL;
-        ocb = TakeCharOwnership;
+        flags |= ATOM_NOCOPY;
     }
 
-    JSAtom *atom = Atomize(cx, &chars, inflatedLength, ib, ocb);
-    if (ocb == TakeCharOwnership && chars)
+    JSAtom *atom = Atomize(cx, &chars, inflatedLength, flags);
+    if ((flags & ATOM_NOCOPY) && chars)
         cx->free_((void *)chars);
     return atom;
 }
 
 JSAtom *
-js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, InternBehavior ib)
+js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags)
 {
+    JS_ASSERT(!(flags & ATOM_NOCOPY));
     CHECK_REQUEST(cx);
 
     if (!CheckStringLength(cx, length))
         return NULL;
 
-    return Atomize(cx, &chars, length, ib);
+    return Atomize(cx, &chars, length, flags);
 }
 
 JSAtom *
 js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
 {
     if (JSAtom *atom = JSAtom::lookupStatic(chars, length))
         return atom;
     AutoLockAtomsCompartment lock(cx);
     AtomSet::Ptr p = cx->runtime->atomState.atoms.lookup(AtomHasher::Lookup(chars, length));
-    return p ? p->toAtom() : NULL;
+    return p ? AtomEntryToKey(*p) : NULL;
 }
 
 #ifdef DEBUG
 JS_FRIEND_API(void)
 js_DumpAtoms(JSContext *cx, FILE *fp)
 {
     JSAtomState *state = &cx->runtime->atomState;
 
     fprintf(fp, "atoms table contents:\n");
     unsigned number = 0;
     for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
-        AtomStateEntry entry = r.front();
+        AtomEntryType entry = r.front();
         fprintf(fp, "%3u ", number++);
-        JSAtom *key = entry.toAtom();
-        FileEscapedString(fp, key, '"');
-        if (entry.isInterned())
-            fputs(" interned", fp);
+        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);
+            }
+        }
         putc('\n', fp);
     }
     putc('\n', fp);
 }
 #endif
 
 static JSHashNumber
 js_hash_atom_ptr(const void *key)
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -49,16 +49,20 @@
 #include "jshash.h"
 #include "jshashtable.h"
 #include "jsnum.h"
 #include "jspubtd.h"
 #include "jsstr.h"
 #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
 JSID_FROM_BITS(size_t bits)
 {
     jsid id;
     JSID_BITS(id) = bits;
     return id;
@@ -269,86 +273,52 @@ class JSAtomListIterator {
 
 struct JSAtomMap {
     JSAtom              **vector;       /* array of ptrs to indexed atoms */
     jsatomid            length;         /* count of (to-be-)indexed atoms */
 };
 
 namespace js {
 
-enum InternBehavior
-{
-    DoNotInternAtom = 0,
-    InternAtom = 1
-};
+#define ATOM_ENTRY_FLAG_MASK            ((size_t)(ATOM_PINNED | ATOM_INTERNED))
 
-/*
- * 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;
+JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JS_GCTHING_ALIGN);
 
-    static const uintptr_t INTERNED_FLAG = 0x1;
-
-    AtomStateEntry() : bits(0) {}
-    AtomStateEntry(const AtomStateEntry &other) : bits(other.bits) {}
+typedef uintptr_t AtomEntryType;
 
-    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 <= InternAtom);
-        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);
-    }
-};
+static JS_ALWAYS_INLINE JSAtom *
+AtomEntryToKey(AtomEntryType entry)
+{
+    JS_ASSERT(entry != 0);
+    return (JSAtom *)(entry & ~ATOM_ENTRY_FLAG_MASK);
+}
 
 struct AtomHasher
 {
     struct Lookup
     {
-        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) {}
+        const jschar *chars;
+        size_t length;
+        Lookup(const jschar *chars, size_t length) : chars(chars), length(length) {}
     };
 
     static HashNumber hash(const Lookup &l) {
         return HashChars(l.chars, l.length);
     }
 
-    static bool match(AtomStateEntry entry, const Lookup &lookup) {
-        JSAtom *key = entry.toAtom();
-
-        if (lookup.atom)
-            return lookup.atom == key;
+    static bool match(AtomEntryType entry, const Lookup &lookup) {
+        JS_ASSERT(entry);
+        JSAtom *key = AtomEntryToKey(entry);
         if (key->length() != lookup.length)
             return false;
         return PodEqual(key->chars(), lookup.chars, lookup.length);
     }
 };
 
-typedef HashSet<AtomStateEntry, AtomHasher, SystemAllocPolicy> AtomSet;
+typedef HashSet<AtomEntryType, AtomHasher, SystemAllocPolicy> AtomSet;
 
 }  /* namespace js */
 
 struct JSAtomState
 {
     js::AtomSet         atoms;
 
 #ifdef JS_THREADSAFE
@@ -488,53 +458,39 @@ struct JSAtomState
         JSAtom          *parseFloatAtom;
         JSAtom          *parseIntAtom;
         JSAtom          *propertyIsEnumerableAtom;
         JSAtom          *unescapeAtom;
         JSAtom          *unevalAtom;
         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) - JSAtomState::commonAtomsOffset)     \
+    ((offsetof(JSAtomState, name##Atom) - ATOM_OFFSET_START)                  \
      / sizeof(JSAtom*))
 #define COMMON_TYPE_ATOM_INDEX(type)                                          \
-    ((offsetof(JSAtomState, typeAtoms[type]) - JSAtomState::commonAtomsOffset)\
+    ((offsetof(JSAtomState, typeAtoms[type]) - ATOM_OFFSET_START)             \
      / 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;
 
 /*
  * Macros to access C strings for JSType and boolean literals.
  */
 #define JS_BOOLEAN_STR(type) (js_common_atom_names[1 + (type)])
@@ -627,36 +583,34 @@ js_FinishAtomState(JSRuntime *rt);
  */
 
 extern void
 js_TraceAtomState(JSTracer *trc);
 
 extern void
 js_SweepAtomState(JSContext *cx);
 
-extern bool
+extern JSBool
 js_InitCommonAtoms(JSContext *cx);
 
 extern void
 js_FinishCommonAtoms(JSContext *cx);
 
 /*
  * Find or create the atom for a string. Return null on failure to allocate
  * memory.
  */
 extern JSAtom *
-js_AtomizeString(JSContext *cx, JSString *str, js::InternBehavior ib = js::DoNotInternAtom);
+js_AtomizeString(JSContext *cx, JSString *str, uintN flags);
 
 extern JSAtom *
-js_Atomize(JSContext *cx, const char *bytes, size_t length,
-           js::InternBehavior ib = js::DoNotInternAtom, bool useCESU8 = false);
+js_Atomize(JSContext *cx, const char *bytes, size_t length, uintN flags, bool useCESU8 = false);
 
 extern JSAtom *
-js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length,
-                js::InternBehavior ib = js::DoNotInternAtom);
+js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags);
 
 /*
  * Return an existing atom for the given char array or null if the char
  * sequence is currently not atomized.
  */
 extern JSAtom *
 js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length);
 
--- a/js/src/jsatominlines.h
+++ b/js/src/jsatominlines.h
@@ -46,27 +46,27 @@
 inline bool
 js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp)
 {
     if (!v.isString()) {
         JSString *str = js_ValueToString(cx, v);
         if (!str)
             return false;
         JS::Anchor<JSString *> anchor(str);
-        *atomp = js_AtomizeString(cx, str);
+        *atomp = js_AtomizeString(cx, str, 0);
         return !!*atomp;
     }
 
     JSString *str = v.toString();
     if (str->isAtom()) {
         *atomp = &str->asAtom();
         return true;
     }
 
-    *atomp = js_AtomizeString(cx, str);
+    *atomp = js_AtomizeString(cx, str, 0);
     return !!*atomp;
 }
 
 inline bool
 js_ValueToStringId(JSContext *cx, const js::Value &v, jsid *idp)
 {
     JSAtom *atom;
     if (js_ValueToAtom(cx, v, &atom)) {
@@ -139,17 +139,17 @@ IndexToId(JSContext *cx, uint32 index, j
         *idp = INT_TO_JSID(index);
         return true;
     }
 
     JSString *str = js_NumberToString(cx, index);
     if (!str)
         return false;
 
-    JSAtom *atom = js_AtomizeString(cx, str);
+    JSAtom *atom = js_AtomizeString(cx, str, 0);
     if (!atom)
         return false;
     *idp = ATOM_TO_JSID(atom);
     return true;
 }
 
 } // namespace js
 
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -255,17 +255,17 @@ HasProperty(JSContext* cx, JSObject* obj
     if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
         return JS_NEITHER;
     return prop != NULL;
 }
 
 JSBool FASTCALL
 js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr)
 {
-    JSAtom *atom = js_AtomizeString(cx, idstr);
+    JSAtom *atom = js_AtomizeString(cx, idstr, 0);
     if (!atom)
         return JS_NEITHER;
 
     return HasProperty(cx, obj, ATOM_TO_JSID(atom));
 }
 JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedProperty, CONTEXT, OBJECT, STRING,
                      0, ACCSET_STORE_ANY)
 
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -817,17 +817,17 @@ JSStructuredCloneReader::readId(jsid *id
     if (tag == SCTAG_INDEX) {
         *idp = INT_TO_JSID(int32_t(data));
         return true;
     }
     if (tag == SCTAG_STRING) {
         JSString *str = readString(data);
         if (!str)
             return false;
-        JSAtom *atom = js_AtomizeString(context(), str);
+        JSAtom *atom = js_AtomizeString(context(), str, 0);
         if (!atom)
             return false;
         *idp = ATOM_TO_JSID(atom);
         return true;
     }
     if (tag == SCTAG_NULL) {
         *idp = JSID_VOID;
         return true;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1384,17 +1384,17 @@ FramePCOffset(JSContext *cx, js::StackFr
     jsbytecode *pc = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx);
     return uintN(pc - fp->script()->code);
 }
 
 static inline JSAtom **
 FrameAtomBase(JSContext *cx, js::StackFrame *fp)
 {
     return fp->hasImacropc()
-           ? cx->runtime->atomState.commonAtomsStart()
+           ? COMMON_ATOMS_START(&cx->runtime->atomState)
            : fp->script()->atomMap.vector;
 }
 
 struct AutoResolving {
   public:
     enum Kind {
         LOOKUP,
         WATCH
@@ -1870,17 +1870,17 @@ class AutoUnlockGC {
 
 class AutoLockAtomsCompartment {
   private:
     JSContext *cx;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 
   public:
     AutoLockAtomsCompartment(JSContext *cx
-                             JS_GUARD_OBJECT_NOTIFIER_PARAM)
+                               JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : cx(cx)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
         JS_LOCK(cx, &cx->runtime->atomState.lock);
 #ifdef JS_THREADSAFE
         cx->runtime->atomsCompartmentIsLocked = true;
 #endif
     }
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -1318,18 +1318,18 @@ JSTreeContext::ensureSharpSlots()
     if (sharpSlotBase >= 0) {
         JS_ASSERT(flags & TCF_HAS_SHARPS);
         return true;
     }
 
     JS_ASSERT(!(flags & TCF_HAS_SHARPS));
     if (inFunction()) {
         JSContext *cx = parser->context;
-        JSAtom *sharpArrayAtom = js_Atomize(cx, "#array", 6);
-        JSAtom *sharpDepthAtom = js_Atomize(cx, "#depth", 6);
+        JSAtom *sharpArrayAtom = js_Atomize(cx, "#array", 6, 0);
+        JSAtom *sharpDepthAtom = js_Atomize(cx, "#depth", 6, 0);
         if (!sharpArrayAtom || !sharpDepthAtom)
             return false;
 
         sharpSlotBase = bindings.countVars();
         if (!bindings.addVariable(cx, sharpArrayAtom))
             return false;
         if (!bindings.addVariable(cx, sharpDepthAtom))
             return false;
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -400,16 +400,19 @@ js_NewFunction(JSContext *cx, JSObject *
 
 extern JSObject *
 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);
 
 extern JSObject * JS_FASTCALL
 js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
                        JSObject *proto);
 
 inline JSObject *
 CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent)
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -2254,17 +2254,17 @@ Interpret(JSContext *cx, StackFrame *ent
 # define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP)
 # define END_EMPTY_CASES    goto advance_pc_by_one;
 
 #endif /* !JS_THREADED_INTERP */
 
 #define LOAD_ATOM(PCOFF, atom)                                                \
     JS_BEGIN_MACRO                                                            \
         JS_ASSERT(regs.fp()->hasImacropc()                                    \
-                  ? atoms == rt->atomState.commonAtomsStart() &&              \
+                  ? atoms == COMMON_ATOMS_START(&rt->atomState) &&            \
                     GET_INDEX(regs.pc + PCOFF) < js_common_atom_count         \
                   : (size_t)(atoms - script->atomMap.vector) <                \
                     (size_t)(script->atomMap.length -                         \
                              GET_INDEX(regs.pc + PCOFF)));                    \
         atom = atoms[GET_INDEX(regs.pc + PCOFF)];                             \
     JS_END_MACRO
 
 #define GET_FULL_INDEX(PCOFF)                                                 \
@@ -2503,17 +2503,17 @@ Interpret(JSContext *cx, StackFrame *ent
         ENABLE_INTERRUPTS();
     } else if (interpMode == JSINTERP_PROFILE) {
         ENABLE_INTERRUPTS();
     } else if (TRACE_RECORDER(cx)) {
         AbortRecording(cx, "attempt to reenter interpreter while recording");
     }
 
     if (regs.fp()->hasImacropc())
-        atoms = rt->atomState.commonAtomsStart();
+        atoms = COMMON_ATOMS_START(&rt->atomState);
 #endif
 
     /* Don't call the script prologue if executing between Method and Trace JIT. */
     if (interpMode == JSINTERP_NORMAL) {
         JS_ASSERT_IF(!regs.fp()->isGeneratorFrame(), regs.pc == script->code);
         if (!ScriptPrologueOrGeneratorResume(cx, regs.fp()))
             goto error;
     }
@@ -2669,17 +2669,17 @@ Interpret(JSContext *cx, StackFrame *ent
             }
 
             switch (status) {
               case ARECORD_CONTINUE:
                 moreInterrupts = true;
                 break;
               case ARECORD_IMACRO:
               case ARECORD_IMACRO_ABORTED:
-                atoms = rt->atomState.commonAtomsStart();
+                atoms = COMMON_ATOMS_START(&rt->atomState);
                 op = JSOp(*regs.pc);
                 CLEAR_LEAVE_ON_TRACE_POINT();
                 if (status == ARECORD_IMACRO)
                     DO_OP();    /* keep interrupting for op. */
                 break;
               case ARECORD_ERROR:
                 // The code at 'error:' aborts the recording.
                 goto error;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3990,17 +3990,17 @@ MarkStandardClassInitializedNoProto(JSOb
 }
 
 JSObject *
 js_InitClass(JSContext *cx, JSObject *obj, JSObject *protoProto,
              Class *clasp, Native constructor, uintN nargs,
              JSPropertySpec *ps, JSFunctionSpec *fs,
              JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
 {
-    JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
+    JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
     if (!atom)
         return NULL;
 
     /*
      * All instances of the class will inherit properties from the prototype
      * object we are about to create (in DefineConstructorAndPrototype), which
      * in turn will inherit from protoProto.
      *
@@ -4277,17 +4277,17 @@ js_FindClassObject(JSContext *cx, JSObje
         if (!js_GetClassObject(cx, obj, protoKey, &cobj))
             return false;
         if (cobj) {
             vp->setObject(*cobj);
             return JS_TRUE;
         }
         id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[protoKey]);
     } else {
-        JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
+        JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
         if (!atom)
             return false;
         id = ATOM_TO_JSID(atom);
     }
 
     JS_ASSERT(obj->isNative());
     if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME, &pobj, &prop))
         return false;
@@ -6318,17 +6318,17 @@ js_XDRObject(JSXDRState *xdr, JSObject *
         classDef = !classId;
         if (classDef) {
             if (!JS_XDRRegisterClass(xdr, Jsvalify(clasp), &classId))
                 return JS_FALSE;
             protoKey = JSCLASS_CACHED_PROTO_KEY(clasp);
             if (protoKey != JSProto_Null) {
                 classDef |= (protoKey << 1);
             } else {
-                atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
+                atom = js_Atomize(cx, clasp->name, strlen(clasp->name), 0);
                 if (!atom)
                     return JS_FALSE;
             }
         }
     } else {
         clasp = NULL;           /* quell GCC overwarning */
         classDef = 0;
     }
--- a/js/src/jsonparser.cpp
+++ b/js/src/jsonparser.cpp
@@ -82,17 +82,17 @@ JSONSourceParser::readString()
      * string directly from the source text.
      */
     RangeCheckedPointer<const jschar> start = current;
     for (; current < end; current++) {
         if (*current == '"') {
             size_t length = current - start;
             current++;
             JSFlatString *str = (ST == JSONSourceParser::PropertyName)
-                                ? js_AtomizeChars(cx, start, length)
+                                ? js_AtomizeChars(cx, start, length, 0)
                                 : js_NewStringCopyN(cx, start, length);
             if (!str)
                 return token(OOM);
             return stringToken(str);
         }
 
         if (*current == '\\')
             break;
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -976,17 +976,17 @@ Compiler::compileScript(JSContext *cx, J
     funbox = NULL;
 
     if (tcflags & TCF_COMPILE_N_GO) {
         if (source) {
             /*
              * Save eval program source in script->atomMap.vector[0] for the
              * eval cache (see EvalCacheLookup in jsobj.cpp).
              */
-            JSAtom *atom = js_AtomizeString(cx, source);
+            JSAtom *atom = js_AtomizeString(cx, source, 0);
             if (!atom || !cg.atomList.add(&parser, atom))
                 goto out;
         }
 
         if (callerFrame && callerFrame->isFunctionFrame()) {
             /*
              * An eval script in a caller frame needs to have its enclosing
              * function captured in case it refers to an upvar, and someone
@@ -8875,17 +8875,17 @@ FoldType(JSContext *cx, JSParseNode *pn,
             }
             break;
 
           case TOK_STRING:
             if (pn->pn_type == TOK_NUMBER) {
                 JSString *str = js_NumberToString(cx, pn->pn_dval);
                 if (!str)
                     return JS_FALSE;
-                pn->pn_atom = js_AtomizeString(cx, str);
+                pn->pn_atom = js_AtomizeString(cx, str, 0);
                 if (!pn->pn_atom)
                     return JS_FALSE;
                 pn->pn_type = TOK_STRING;
                 pn->pn_op = JSOP_STRING;
             }
             break;
 
           default:;
@@ -9059,17 +9059,17 @@ FoldXMLConstants(JSContext *cx, JSParseN
             } else if (accum && pn1 != pn2) {
                 while (pn1->pn_next != pn2) {
                     pn1 = RecycleTree(pn1, tc);
                     --pn->pn_count;
                 }
                 pn1->pn_type = TOK_XMLTEXT;
                 pn1->pn_op = JSOP_STRING;
                 pn1->pn_arity = PN_NULLARY;
-                pn1->pn_atom = js_AtomizeString(cx, accum);
+                pn1->pn_atom = js_AtomizeString(cx, accum, 0);
                 if (!pn1->pn_atom)
                     return JS_FALSE;
                 JS_ASSERT(pnp != &pn1->pn_next);
                 *pnp = pn1;
             }
             pnp = &pn2->pn_next;
             pn1 = *pnp;
             accum = NULL;
@@ -9112,17 +9112,17 @@ FoldXMLConstants(JSContext *cx, JSParseN
         JS_ASSERT(*pnp == pn1);
         while (pn1->pn_next) {
             pn1 = RecycleTree(pn1, tc);
             --pn->pn_count;
         }
         pn1->pn_type = TOK_XMLTEXT;
         pn1->pn_op = JSOP_STRING;
         pn1->pn_arity = PN_NULLARY;
-        pn1->pn_atom = js_AtomizeString(cx, accum);
+        pn1->pn_atom = js_AtomizeString(cx, accum, 0);
         if (!pn1->pn_atom)
             return JS_FALSE;
         JS_ASSERT(pnp != &pn1->pn_next);
         *pnp = pn1;
     }
 
     if (pn1 && pn->pn_count == 1) {
         /*
@@ -9476,17 +9476,17 @@ js_FoldConstants(JSContext *cx, JSParseN
                 JSAtom *atom = pn2->pn_atom;
                 size_t length2 = atom->length();
                 js_strncpy(chars, atom->chars(), length2);
                 chars += length2;
             }
             JS_ASSERT(*chars == 0);
 
             /* Atomize the result string and mutate pn to refer to it. */
-            pn->pn_atom = js_AtomizeString(cx, str);
+            pn->pn_atom = js_AtomizeString(cx, str, 0);
             if (!pn->pn_atom)
                 return JS_FALSE;
             pn->pn_type = TOK_STRING;
             pn->pn_op = JSOP_STRING;
             pn->pn_arity = PN_NULLARY;
             break;
         }
 
@@ -9501,17 +9501,17 @@ js_FoldConstants(JSContext *cx, JSParseN
             }
             if (pn1->pn_type != TOK_STRING || pn2->pn_type != TOK_STRING)
                 return JS_TRUE;
             left = pn1->pn_atom;
             right = pn2->pn_atom;
             str = js_ConcatStrings(cx, left, right);
             if (!str)
                 return JS_FALSE;
-            pn->pn_atom = js_AtomizeString(cx, str);
+            pn->pn_atom = js_AtomizeString(cx, str, 0);
             if (!pn->pn_atom)
                 return JS_FALSE;
             pn->pn_type = TOK_STRING;
             pn->pn_op = JSOP_STRING;
             pn->pn_arity = PN_NULLARY;
             RecycleTree(pn1, tc);
             RecycleTree(pn2, tc);
             break;
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -198,17 +198,17 @@ class NodeBuilder
         }
 
         userv.setObject(*userobj);
 
         for (uintN i = 0; i < AST_LIMIT; i++) {
             Value funv;
 
             const char *name = callbackNames[i];
-            JSAtom *atom = js_Atomize(cx, name, strlen(name));
+            JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
             if (!atom || !GetPropertyDefault(cx, userobj, ATOM_TO_JSID(atom), NullValue(), &funv))
                 return false;
 
             if (funv.isNullOrUndefined()) {
                 callbacks[i].setNull();
                 continue;
             }
 
@@ -308,17 +308,17 @@ class NodeBuilder
         JS_ASSERT_IF(v.isMagic(), v.whyMagic() == JS_SERIALIZE_NO_NODE);
         return v.isMagic(JS_SERIALIZE_NO_NODE) ? UndefinedValue() : v;
     }
 
     bool atomValue(const char *s, Value *dst) {
         /*
          * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
          */
-        JSAtom *atom = js_Atomize(cx, s, strlen(s));
+        JSAtom *atom = js_Atomize(cx, s, strlen(s), 0);
         if (!atom)
             return false;
 
         dst->setString(atom);
         return true;
     }
 
     bool newObject(JSObject **dst) {
@@ -420,17 +420,17 @@ class NodeBuilder
 
         /* Represent "no node" as null and ensure users are not exposed to magic values. */
         if (val.isMagic(JS_SERIALIZE_NO_NODE))
             val.setNull();
 
         /*
          * Bug 575416: instead of js_Atomize, lookup constant atoms in tbl file
          */
-        JSAtom *atom = js_Atomize(cx, name, strlen(name));
+        JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
         if (!atom)
             return false;
 
         return obj->defineProperty(cx, ATOM_TO_JSID(atom), val);
     }
 
     bool newNodeLoc(TokenPos *pos, Value *dst);
 
--- a/js/src/jsscan.cpp
+++ b/js/src/jsscan.cpp
@@ -1015,17 +1015,17 @@ TokenStream::getXMLMarkup(TokenKind *ttp
                 goto error;
         }
         if (targetLength == 0)
             goto bad_xml_markup;
         if (contentIndex < 0) {
             atom = cx->runtime->atomState.emptyAtom;
         } else {
             atom = js_AtomizeChars(cx, tokenbuf.begin() + contentIndex,
-                                   tokenbuf.length() - contentIndex);
+                                   tokenbuf.length() - contentIndex, 0);
             if (!atom)
                 goto error;
         }
         tokenbuf.shrinkBy(tokenbuf.length() - targetLength);
         tp->t_atom2 = atom;
         tt = TOK_XMLPI;
 
   finish_xml_markup:
@@ -1179,17 +1179,17 @@ TokenStream::newToken(ptrdiff_t adjust)
     tp->pos.begin.index = tp->ptr - linebase;
     tp->pos.begin.lineno = tp->pos.end.lineno = lineno;
     return tp;
 }
 
 JS_ALWAYS_INLINE JSAtom *
 TokenStream::atomize(JSContext *cx, CharBuffer &cb)
 {
-    return js_AtomizeChars(cx, cb.begin(), cb.length());
+    return js_AtomizeChars(cx, cb.begin(), cb.length(), 0);
 }
 
 #ifdef DEBUG
 bool
 IsTokenSane(Token *tp)
 {
     /*
      * Nb: TOK_EOL should never be used in an actual Token;  it should only be
@@ -1358,17 +1358,17 @@ TokenStream::getTokenInternal()
 
         /* 
          * Identifiers containing no Unicode escapes can be atomized directly
          * from userbuf.  The rest must have the escapes converted via
          * tokenbuf before atomizing.
          */
         JSAtom *atom;
         if (!hadUnicodeEscape)
-            atom = js_AtomizeChars(cx, identStart, userbuf.addressOfNextRawChar() - identStart);
+            atom = js_AtomizeChars(cx, identStart, userbuf.addressOfNextRawChar() - identStart, 0);
         else if (putIdentInTokenbuf(identStart))
             atom = atomize(cx, tokenbuf);
         else
             atom = NULL;
         if (!atom)
             goto error;
         tp->t_op = JSOP_NAME;
         tp->t_atom = atom;
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -605,17 +605,16 @@ struct Shape : public js::gc::Cell
 
 #ifdef DEBUG
     void dump(JSContext *cx, FILE *fp) const;
     void dumpSubtree(JSContext *cx, int level, FILE *fp) const;
 #endif
 
     void finalize(JSContext *cx);
     void removeChild(js::Shape *child);
-    void removeChildSlowly(js::Shape *child);
 };
 
 struct EmptyShape : public js::Shape
 {
     EmptyShape(JSCompartment *comp, js::Class *aclasp);
 
     js::Class *getClass() const { return clasp; };
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -257,17 +257,17 @@ Bindings::lastUpvar() const
     return lastBinding;
 }
 
 int
 Bindings::sharpSlotBase(JSContext *cx)
 {
     JS_ASSERT(lastBinding);
 #if JS_HAS_SHARP_VARS
-    if (JSAtom *name = js_Atomize(cx, "#array", 6)) {
+    if (JSAtom *name = js_Atomize(cx, "#array", 6, 0)) {
         uintN index = uintN(-1);
         DebugOnly<BindingKind> kind = lookup(cx, name, &index);
         JS_ASSERT(kind == VARIABLE);
         return int(index);
     }
 #endif
     return -1;
 }
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -644,17 +644,17 @@ StackDepth(JSScript *script)
  * imacro body, so we use cx->runtime common atoms instead of script_'s atoms.
  * This macro uses cx from its callers' environments in the pc-in-imacro case.
  */
 #define JS_GET_SCRIPT_ATOM(script_, pc_, index, atom)                         \
     JS_BEGIN_MACRO                                                            \
         if ((pc_) < (script_)->code ||                                        \
             (script_)->code + (script_)->length <= (pc_)) {                   \
             JS_ASSERT((size_t)(index) < js_common_atom_count);                \
-            (atom) = cx->runtime->atomState.commonAtomsStart()[index];        \
+            (atom) = COMMON_ATOMS_START(&cx->runtime->atomState)[index];      \
         } else {                                                              \
             (atom) = script_->getAtom(index);                                 \
         }                                                                     \
     JS_END_MACRO
 
 extern JS_FRIEND_DATA(js::Class) js_ScriptClass;
 
 extern JSObject *
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2063,17 +2063,17 @@ FindReplaceLength(JSContext *cx, RegExpS
         if (!res->createLastMatch(cx, &match))
             return false;
         JSString *str = match.toString();
 
         JSAtom *atom;
         if (str->isAtom()) {
             atom = &str->asAtom();
         } else {
-            atom = js_AtomizeString(cx, str);
+            atom = js_AtomizeString(cx, str, 0);
             if (!atom)
                 return false;
         }
         jsid id = ATOM_TO_JSID(atom);
 
         JSObject *holder;
         JSProperty *prop = NULL;
         if (!LookupPropertyWithFlags(cx, base, id, JSRESOLVE_QUALIFIED, &holder, &prop))
@@ -3716,17 +3716,17 @@ JSAtom *
 StringBuffer::finishAtom()
 {
     JSContext *cx = context();
 
     size_t length = cb.length();
     if (length == 0)
         return cx->runtime->atomState.emptyAtom;
 
-    JSAtom *atom = js_AtomizeChars(cx, cb.begin(), length);
+    JSAtom *atom = js_AtomizeChars(cx, cb.begin(), length, 0);
     cb.clear();
     return atom;
 }
 
 JSLinearString *
 js_NewDependentString(JSContext *cx, JSString *baseArg, size_t start, size_t length)
 {
     if (length == 0)
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -481,21 +481,20 @@ JS_STATIC_ASSERT(sizeof(JSExtensibleStri
 class JSFixedString : public JSFlatString
 {
     void init(const jschar *chars, size_t length);
 
   public:
     static inline JSFixedString *new_(JSContext *cx, const jschar *chars, size_t length);
 
     /*
-     * 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.
+     * Once a JSFixedString has been added to the atom table, this operation
+     * changes the type (in place) of the JSFixedString into a JSAtom.
      */
-    inline JSAtom *morphAtomizedStringIntoAtom();
+    inline JSAtom *morphInternedStringIntoAtom();
 };
 
 JS_STATIC_ASSERT(sizeof(JSFixedString) == sizeof(JSString));
 
 class JSInlineString : public JSFixedString
 {
     static const size_t MAX_INLINE_LENGTH = NUM_INLINE_CHARS - 1;
 
--- a/js/src/jsstrinlines.h
+++ b/js/src/jsstrinlines.h
@@ -339,17 +339,17 @@ JSFixedString::new_(JSContext *cx, const
     JS_LOCK_RUNTIME_VOID(rt,
         (rt->lengthSum += (double)length,
          rt->lengthSquaredSum += (double)length * (double)length));
 #endif
     return str;
 }
 
 JS_ALWAYS_INLINE JSAtom *
-JSFixedString::morphAtomizedStringIntoAtom()
+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 JSInlineString *
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -12465,21 +12465,21 @@ TraceRecorder::finishGetProp(LIns* obj_i
     pendingUnboxSlot = outp;
 }
 
 static inline bool
 RootedStringToId(JSContext* cx, JSString** namep, jsid* idp)
 {
     JSString* name = *namep;
     if (name->isAtom()) {
-        *idp = ATOM_TO_JSID(&name->asAtom());
+        *idp = INTERNED_STRING_TO_JSID(name);
         return true;
     }
 
-    JSAtom* atom = js_AtomizeString(cx, name);
+    JSAtom* atom = js_AtomizeString(cx, name, 0);
     if (!atom)
         return false;
     *namep = atom; /* write back to GC root */
     *idp = ATOM_TO_JSID(atom);
     return true;
 }
 
 static const size_t PIC_TABLE_ENTRY_COUNT = 32;
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -82,18 +82,16 @@ JS_Assert(const char *s, const char *fil
 #define JS_ALWAYS_FALSE(expr) JS_ASSERT(!(expr))
 
 # ifdef JS_THREADSAFE
 # define JS_THREADSAFE_ASSERT(expr) JS_ASSERT(expr) 
 # else
 # define JS_THREADSAFE_ASSERT(expr) ((void) 0)
 # endif
 
-#define JS_FREE_PATTERN 0xDA
-
 #else
 
 #define JS_ASSERT(expr)         ((void) 0)
 #define JS_ASSERT_IF(cond,expr) ((void) 0)
 #define JS_NOT_REACHED(reason)
 #define JS_ALWAYS_TRUE(expr)    ((void) (expr))
 #define JS_ALWAYS_FALSE(expr)    ((void) (expr))
 #define JS_THREADSAFE_ASSERT(expr) ((void) 0)
--- a/js/src/jsxdrapi.cpp
+++ b/js/src/jsxdrapi.cpp
@@ -653,17 +653,17 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **ato
                 return false;
 
             JS_ASSERT(xdr->ops == &xdrmem_ops);
             uint32 paddedLen = (len + JSXDR_MASK) & ~JSXDR_MASK;
             char *buf = (char *)mem_raw(xdr, paddedLen);
             if (!buf)
                 return false;
 
-            JSAtom *atom = js_Atomize(xdr->cx, buf, len, DoNotInternAtom, true);
+            JSAtom *atom = js_Atomize(xdr->cx, buf, len, 0, true);
             if (!atom)
                 return false;
 
             if (!XDRPutAtomIndex(xdr, atom))
                 return false;
 
             *atomp = atom;
         }
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -2867,17 +2867,17 @@ ToXMLName(JSContext *cx, jsval v, jsid *
             name = cx->runtime->atomState.starAtom;
             goto construct;
         }
         name = js_ValueToString(cx, Valueify(v));
         if (!name)
             return NULL;
     }
 
-    atomizedName = js_AtomizeString(cx, name);
+    atomizedName = js_AtomizeString(cx, name, 0);
     if (!atomizedName)
         return NULL;
 
     /*
      * ECMA-357 10.6.1 step 1 seems to be incorrect.  The spec says:
      *
      * 1. If ToString(ToNumber(P)) == ToString(P), throw a TypeError exception
      *
@@ -5339,17 +5339,17 @@ ValueToId(JSContext *cx, jsval v, AutoId
 {
     if (JSVAL_IS_INT(v)) {
         jsint i = JSVAL_TO_INT(v);
         if (INT_FITS_IN_JSID(i))
             *idr->addr() = INT_TO_JSID(i);
         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));
+        JSAtom *atom = js_AtomizeString(cx, JSVAL_TO_STRING(v), 0);
         if (!atom)
             return JS_FALSE;
         *idr->addr() = ATOM_TO_JSID(atom);
     } else if (!JSVAL_IS_PRIMITIVE(v)) {
         *idr->addr() = OBJECT_TO_JSID(JSVAL_TO_OBJECT(v));
     } else {
         ReportBadXMLName(cx, Valueify(v));
         return JS_FALSE;
--- a/js/src/xpconnect/src/XPCDispInterface.cpp
+++ b/js/src/xpconnect/src/XPCDispInterface.cpp
@@ -185,17 +185,17 @@ PRBool InitializeMember(JSContext * cx, 
                                        ::SysStringLen(name));
     ::SysFreeString(name);
     if(!str)
         return PR_FALSE;
     // Initialize
     pInfo = new (pInfo) XPCDispInterface::Member;
     if(!pInfo)
         return PR_FALSE;
-    pInfo->SetName(INTERNED_STRING_TO_JSID(cx, str));
+    pInfo->SetName(INTERNED_STRING_TO_JSID(str));
     pInfo->ResetType();
     ConvertInvokeKind(pFuncDesc->invkind, *pInfo);
     pInfo->SetTypeInfo(pFuncDesc->memid, pTypeInfo, pFuncDesc);
     return PR_TRUE;
 }
 
 static
 XPCDispInterface::Member * FindExistingMember(XPCDispInterface::Member * first,
--- a/js/src/xpconnect/src/xpcquickstubs.cpp
+++ b/js/src/xpconnect/src/xpcquickstubs.cpp
@@ -543,17 +543,17 @@ GetMemberInfo(JSObject *obj, jsid member
 
 static void
 GetMethodInfo(JSContext *cx, jsval *vp, const char **ifaceNamep, jsid *memberIdp)
 {
     JSObject *funobj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
     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(cx, str) : JSID_VOID;
+    jsid methodId = str ? INTERNED_STRING_TO_JSID(str) : JSID_VOID;
     GetMemberInfo(JSVAL_TO_OBJECT(vp[1]), methodId, ifaceNamep);
     *memberIdp = methodId;
 }
 
 static JSBool
 ThrowCallFailed(JSContext *cx, nsresult rv,
                 const char *ifaceName, jsid memberId, const char *memberName)
 {
--- a/js/src/xpconnect/src/xpcwrappednativeinfo.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativeinfo.cpp
@@ -377,17 +377,17 @@ XPCNativeInterface::NewInstance(XPCCallC
 
         str = JS_InternString(ccx, info->GetName());
         if(!str)
         {
             NS_ERROR("bad method name");
             failed = JS_TRUE;
             break;
         }
-        name = INTERNED_STRING_TO_JSID(ccx, str);
+        name = INTERNED_STRING_TO_JSID(str);
 
         if(info->IsSetter())
         {
             NS_ASSERTION(realTotalCount,"bad setter");
             // Note: ASSUMES Getter/Setter pairs are next to each other
             // This is a rule of the typelib spec.
             cur = &members[realTotalCount-1];
             NS_ASSERTION(cur->GetName() == name,"bad setter");
@@ -421,17 +421,17 @@ XPCNativeInterface::NewInstance(XPCCallC
 
             str = JS_InternString(ccx, constant->GetName());
             if(!str)
             {
                 NS_ERROR("bad constant name");
                 failed = JS_TRUE;
                 break;
             }
-            name = INTERNED_STRING_TO_JSID(ccx, str);
+            name = INTERNED_STRING_TO_JSID(str);
 
             // XXX need better way to find dups
             //NS_ASSERTION(!LookupMemberByID(name),"duplicate method/constant name");
 
             cur = &members[realTotalCount++];
             cur->SetName(name);
             cur->SetConstant(i);
         }
@@ -440,17 +440,17 @@ XPCNativeInterface::NewInstance(XPCCallC
     if(!failed)
     {
         const char* bytes;
         if(NS_FAILED(aInfo->GetNameShared(&bytes)) || !bytes ||
            nsnull == (str = JS_InternString(ccx, bytes)))
         {
             failed = JS_TRUE;
         }
-        interfaceName = INTERNED_STRING_TO_JSID(ccx, str);
+        interfaceName = INTERNED_STRING_TO_JSID(str);
     }
 
     if(!failed)
     {
         // Use placement new to create an object with the right amount of space
         // to hold the members array
         int size = sizeof(XPCNativeInterface);
         if(realTotalCount > 1)