Bug 789635 - Clean up JSAtomState so that all atom fields are macro-defined, and move the atoms set into JSRuntime directly. r=jorendorff
☠☠ backed out by 17497a3b1281 ☠ ☠
authorJeff Walden <jwalden@mit.edu>
Thu, 06 Sep 2012 13:48:40 -0700
changeset 107244 17d36418f4d6b6a863837418844b5f5012080722
parent 107243 b6855b09030771b0eb58f09994013f3e875c2cd2
child 107245 9eadf573bb384c43adf67e63ebffd17c6cb3906f
push id14930
push userjwalden@mit.edu
push dateMon, 17 Sep 2012 17:42:39 +0000
treeherdermozilla-inbound@d3d8807c6c59 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs789635
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 789635 - Clean up JSAtomState so that all atom fields are macro-defined, and move the atoms set into JSRuntime directly. r=jorendorff
js/src/builtin/MapObject.cpp
js/src/builtin/ParallelArray.cpp
js/src/builtin/RegExp.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/TokenStream.cpp
js/src/frontend/TokenStream.h
js/src/ion/CodeGenerator.cpp
js/src/ion/IonBuilder.cpp
js/src/ion/MIR.cpp
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsatom.h
js/src/jsatom.tbl
js/src/jsatominlines.h
js/src/jsbool.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsgc.cpp
js/src/jsinfer.cpp
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jsweakmap.cpp
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/StubCalls.cpp
js/src/vm/CommonPropertyNames.h
js/src/vm/GlobalObject.cpp
js/src/vm/StringBuffer.cpp
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -911,18 +911,17 @@ static JSObject *
 InitClass(JSContext *cx, Handle<GlobalObject*> global, Class *clasp, JSProtoKey key, Native construct,
           JSFunctionSpec *methods)
 {
     Rooted<JSObject*> proto(cx, global->createBlankPrototype(cx, clasp));
     if (!proto)
         return NULL;
     proto->setPrivate(NULL);
 
-    JSAtom *atom = cx->runtime->atomState.classAtoms[key];
-    Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, atom, 1));
+    Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, ClassName(key, cx), 1));
     if (!ctor ||
         !LinkConstructorAndPrototype(cx, ctor, proto) ||
         !DefinePropertiesAndBrand(cx, proto, NULL, methods) ||
         !DefineConstructorAndPrototype(cx, global, key, ctor, proto))
     {
         return NULL;
     }
     return proto;
--- a/js/src/builtin/ParallelArray.cpp
+++ b/js/src/builtin/ParallelArray.cpp
@@ -842,18 +842,18 @@ ParallelArrayObject::initClass(JSContext
 
     Rooted<GlobalObject *> global(cx, &obj->asGlobal());
 
     RootedObject proto(cx, global->createBlankPrototype(cx, &protoClass));
     if (!proto)
         return NULL;
 
     JSProtoKey key = JSProto_ParallelArray;
-    JSAtom *atom = CLASS_NAME(cx, ParallelArray);
-    RootedFunction ctor(cx, global->createConstructor(cx, construct, atom, 0));
+    Rooted<PropertyName*> name(cx, cx->runtime->atomState.ParallelArrayAtom);
+    RootedFunction ctor(cx, global->createConstructor(cx, construct, name, 0));
     if (!ctor ||
         !LinkConstructorAndPrototype(cx, ctor, proto) ||
         !DefinePropertiesAndBrand(cx, proto, NULL, methods) ||
         !DefineConstructorAndPrototype(cx, global, key, ctor, proto))
     {
         return NULL;
     }
 
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -497,17 +497,17 @@ js_InitRegExpClass(JSContext *cx, JSObje
     Rooted<JSAtom*> empty(cx, cx->runtime->emptyString);
     if (!builder.build(empty, RegExpFlag(0)))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, proto, NULL, regexp_methods))
         return NULL;
 
     RootedFunction ctor(cx);
-    ctor = global->createConstructor(cx, regexp_construct, CLASS_NAME(cx, RegExp), 2);
+    ctor = global->createConstructor(cx, regexp_construct, cx->runtime->atomState.RegExpAtom, 2);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return NULL;
 
     /* Add static properties to the RegExp constructor. */
     if (!JS_DefineProperties(cx, ctor, regexp_static_props))
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -398,26 +398,21 @@ NameNode::create(ParseNodeKind kind, JSA
     ParseNode *pn = ParseNode::create(kind, PN_NAME, parser);
     if (pn) {
         pn->pn_atom = atom;
         ((NameNode *)pn)->initCommon(pc);
     }
     return (NameNode *)pn;
 }
 
-const char js_argument_str[] = "argument";
-const char js_variable_str[] = "variable";
-const char js_unknown_str[]  = "unknown";
-
 const char *
 Definition::kindString(Kind kind)
 {
     static const char *table[] = {
-        js_var_str, js_const_str, js_let_str,
-        js_function_str, js_argument_str, js_unknown_str
+        js_var_str, js_const_str, js_let_str, js_function_str, "argument", "unknown"
     };
 
     JS_ASSERT(unsigned(kind) <= unsigned(ARG));
     return table[kind];
 }
 
 #if JS_HAS_DESTRUCTURING
 
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -40,21 +40,16 @@
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
 using namespace js;
 using namespace js::frontend;
 using namespace js::unicode;
 
-#define JS_KEYWORD(keyword, type, op, version) \
-    const char js_##keyword##_str[] = #keyword;
-#include "jskeyword.tbl"
-#undef JS_KEYWORD
-
 static const KeywordInfo keywords[] = {
 #define JS_KEYWORD(keyword, type, op, version) \
     {js_##keyword##_str, type, op, version},
 #include "jskeyword.tbl"
 #undef JS_KEYWORD
 };
 
 const KeywordInfo *
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -16,21 +16,16 @@
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsopcode.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 
 #include "js/Vector.h"
 
-#define JS_KEYWORD(keyword, type, op, version) \
-    extern const char js_##keyword##_str[];
-#include "jskeyword.tbl"
-#undef JS_KEYWORD
-
 namespace js {
 namespace frontend {
 
 enum TokenKind {
     TOK_ERROR = -1,                /* well-known as the only code < EOF */
     TOK_EOF,                       /* end of file */
     TOK_EOL,                       /* end of line; only returned by peekTokenSameLine() */
     TOK_SEMI,                      /* semicolon */
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -3460,49 +3460,49 @@ CodeGenerator::visitTypeOfV(LTypeOfV *li
     const ValueOperand value = ToValue(lir, LTypeOfV::Input);
     Register output = ToRegister(lir->output());
     Register tag = masm.splitTagForTest(value);
 
     OutOfLineTypeOfV *ool = new OutOfLineTypeOfV(lir);
     if (!addOutOfLineCode(ool))
         return false;
 
-    PropertyName **typeAtoms = gen->compartment->rt->atomState.typeAtoms;
+    JSRuntime *rt = gen->compartment->rt;
 
     // Jump to the OOL path if the value is an object. Objects are complicated
     // since they may have a typeof hook.
     masm.branchTestObject(Assembler::Equal, tag, ool->entry());
 
     Label done;
 
     Label notNumber;
     masm.branchTestNumber(Assembler::NotEqual, tag, &notNumber);
-    masm.movePtr(ImmGCPtr(typeAtoms[JSTYPE_NUMBER]), output);
+    masm.movePtr(ImmGCPtr(rt->atomState.numberAtom), output);
     masm.jump(&done);
     masm.bind(&notNumber);
 
     Label notUndefined;
     masm.branchTestUndefined(Assembler::NotEqual, tag, &notUndefined);
-    masm.movePtr(ImmGCPtr(typeAtoms[JSTYPE_VOID]), output);
+    masm.movePtr(ImmGCPtr(rt->atomState.undefinedAtom), output);
     masm.jump(&done);
     masm.bind(&notUndefined);
 
     Label notNull;
     masm.branchTestNull(Assembler::NotEqual, tag, &notNull);
-    masm.movePtr(ImmGCPtr(typeAtoms[JSTYPE_OBJECT]), output);
+    masm.movePtr(ImmGCPtr(rt->atomState.objectAtom), output);
     masm.jump(&done);
     masm.bind(&notNull);
 
     Label notBoolean;
     masm.branchTestBoolean(Assembler::NotEqual, tag, &notBoolean);
-    masm.movePtr(ImmGCPtr(typeAtoms[JSTYPE_BOOLEAN]), output);
+    masm.movePtr(ImmGCPtr(rt->atomState.booleanAtom), output);
     masm.jump(&done);
     masm.bind(&notBoolean);
 
-    masm.movePtr(ImmGCPtr(typeAtoms[JSTYPE_STRING]), output);
+    masm.movePtr(ImmGCPtr(rt->atomState.stringAtom), output);
 
     masm.bind(&done);
     masm.bind(ool->rejoin());
     return true;
 }
 
 bool
 CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV *ool)
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -4607,17 +4607,17 @@ IonBuilder::monitorResult(MInstruction *
     MInstruction *monitor = MMonitorTypes::New(ins, types);
     current->add(monitor);
 }
 
 bool
 IonBuilder::jsop_getgname(HandlePropertyName name)
 {
     // Optimize undefined, NaN, and Infinity.
-    if (name == cx->runtime->atomState.typeAtoms[JSTYPE_VOID])
+    if (name == cx->runtime->atomState.undefinedAtom)
         return pushConstant(UndefinedValue());
     if (name == cx->runtime->atomState.NaNAtom)
         return pushConstant(cx->runtime->NaNValue);
     if (name == cx->runtime->atomState.InfinityAtom)
         return pushConstant(cx->runtime->positiveInfinityValue);
 
     RootedObject globalObj(cx, &script->global());
     JS_ASSERT(globalObj->isNative());
--- a/js/src/ion/MIR.cpp
+++ b/js/src/ion/MIR.cpp
@@ -7,16 +7,17 @@
 
 #include "IonBuilder.h"
 #include "LICM.h" // For LinearSum
 #include "MIR.h"
 #include "MIRGraph.h"
 #include "EdgeCaseAnalysis.h"
 #include "jsnum.h"
 #include "jsstr.h"
+#include "jsatominlines.h"
 #include "jstypedarrayinlines.h" // For ClampIntForUint8Array
 
 using namespace js;
 using namespace js::ion;
 
 void
 MDefinition::PrintOpcodeName(FILE *fp, MDefinition::Opcode op)
 {
@@ -1124,17 +1125,17 @@ MTypeOf::foldsTo(bool useValueNumbers)
       case MIRType_Boolean:
         type = JSTYPE_BOOLEAN;
         break;
       default:
         return this;
     }
 
     JSRuntime *rt = GetIonContext()->compartment->rt;
-    return MConstant::New(StringValue(rt->atomState.typeAtoms[type]));
+    return MConstant::New(StringValue(TypeName(type, rt)));
 }
 
 MBitAnd *
 MBitAnd::New(MDefinition *left, MDefinition *right)
 {
     return new MBitAnd(left, right);
 }
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -598,17 +598,17 @@ JS_TypeOfValue(JSContext *cx, jsval valu
     return TypeOfValue(cx, value);
 }
 
 JS_PUBLIC_API(const char *)
 JS_GetTypeName(JSContext *cx, JSType type)
 {
     if ((unsigned)type >= (unsigned)JSTYPE_LIMIT)
         return NULL;
-    return JS_TYPE_STR(type);
+    return TypeStrings[type];
 }
 
 JS_PUBLIC_API(JSBool)
 JS_StrictlyEqual(JSContext *cx, jsval value1Arg, jsval value2Arg, JSBool *equal)
 {
     RootedValue value1(cx, value1Arg);
     RootedValue value2(cx, value2Arg);
     AssertHeapIsIdle(cx);
@@ -905,17 +905,17 @@ JSRuntime::init(uint32_t maxbytes)
     {
         js_delete(atomsCompartment);
         return false;
     }
 
     atomsCompartment->isSystemCompartment = true;
     atomsCompartment->setGCLastBytes(8192, 8192, GC_NORMAL);
 
-    if (!InitAtomState(this))
+    if (!InitAtoms(this))
         return false;
 
     if (!InitRuntimeNumberState(this))
         return false;
 
     dtoaState = js_NewDtoaState();
     if (!dtoaState)
         return false;
@@ -983,17 +983,17 @@ JSRuntime::~JSRuntime()
         }
         fprintf(stderr,
 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
                 cxcount, (cxcount == 1) ? "" : "s");
     }
 #endif
 
     FinishRuntimeNumberState(this);
-    FinishAtomState(this);
+    FinishAtoms(this);
 
     if (dtoaState)
         js_DestroyDtoaState(dtoaState);
 
     js_FinishGC(this);
 #ifdef JS_THREADSAFE
     if (gcLock)
         PR_DestroyLock(gcLock);
@@ -1791,17 +1791,17 @@ JS_InitStandardClasses(JSContext *cx, JS
 
     Rooted<GlobalObject*> global(cx, &obj->global());
     return GlobalObject::initStandardClasses(cx, global);
 }
 
 #define CLASP(name)                 (&name##Class)
 #define TYPED_ARRAY_CLASP(type)     (&TypedArray::classes[TypedArray::type])
 #define EAGER_ATOM(name)            NAME_OFFSET(name)
-#define EAGER_CLASS_ATOM(name)      CLASS_NAME_OFFSET(name)
+#define EAGER_CLASS_ATOM(name)      NAME_OFFSET(name)
 #define EAGER_ATOM_AND_CLASP(name)  EAGER_CLASS_ATOM(name), CLASP(name)
 
 typedef struct JSStdName {
     JSClassInitializerOp init;
     size_t      atomOffset;     /* offset of atom pointer in JSAtomState */
     Class       *clasp;
 } JSStdName;
 
@@ -1950,17 +1950,17 @@ JS_ResolveStandardClass(JSContext *cx, J
 
     rt = cx->runtime;
     if (!rt->hasContexts() || !JSID_IS_ATOM(id))
         return true;
 
     idstr = JSID_TO_STRING(id);
 
     /* Check whether we're resolving 'undefined', and define it if so. */
-    atom = rt->atomState.typeAtoms[JSTYPE_VOID];
+    atom = rt->atomState.undefinedAtom;
     if (idstr == atom) {
         *resolved = true;
         RootedValue undefinedValue(cx, UndefinedValue());
         return JSObject::defineProperty(cx, obj, atom->asPropertyName(), undefinedValue,
                                         JS_PropertyStub, JS_StrictPropertyStub,
                                         JSPROP_PERMANENT | JSPROP_READONLY);
     }
 
@@ -2043,17 +2043,17 @@ JS_EnumerateStandardClasses(JSContext *c
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
     /*
      * Check whether we need to bind 'undefined' and define it if so.
      * Since ES5 15.1.1.3 undefined can't be deleted.
      */
-    RootedPropertyName undefinedName(cx, cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
+    RootedPropertyName undefinedName(cx, cx->runtime->atomState.undefinedAtom);
     RootedValue undefinedValue(cx, UndefinedValue());
     if (!obj->nativeContains(cx, undefinedName) &&
         !JSObject::defineProperty(cx, obj, undefinedName, undefinedValue,
                                   JS_PropertyStub, JS_StrictPropertyStub,
                                   JSPROP_PERMANENT | JSPROP_READONLY)) {
         return false;
     }
 
@@ -2152,17 +2152,17 @@ JS_EnumerateResolvedStandardClasses(JSCo
     } else {
         ida = NewIdArray(cx, 8);
         if (!ida)
             return NULL;
         i = 0;
     }
 
     /* Check whether 'undefined' has been resolved and enumerate it if so. */
-    Rooted<PropertyName*> name(cx, rt->atomState.typeAtoms[JSTYPE_VOID]);
+    Rooted<PropertyName*> name(cx, rt->atomState.undefinedAtom);
     ida = EnumerateIfResolved(cx, obj, name, ida, &i, &found);
     if (!ida)
         return NULL;
 
     /* Enumerate only classes that *have* been resolved. */
     for (j = 0; standard_class_atoms[j].init; j++) {
         name = OFFSET_TO_NAME(rt, standard_class_atoms[j].atomOffset);
         ida = EnumerateIfResolved(cx, obj, name, ida, &i, &found);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3546,17 +3546,18 @@ js_InitArrayClass(JSContext *cx, JSObjec
 
     Rooted<GlobalObject*> global(cx, &obj->asGlobal());
 
     RootedObject arrayProto(cx, global->createBlankPrototype(cx, &SlowArrayClass));
     if (!arrayProto || !AddLengthProperty(cx, arrayProto))
         return NULL;
     arrayProto->setArrayLength(cx, 0);
 
-    RootedFunction ctor(cx, global->createConstructor(cx, js_Array, CLASS_NAME(cx, Array), 1));
+    RootedFunction ctor(cx);
+    ctor = global->createConstructor(cx, js_Array, cx->runtime->atomState.ArrayAtom, 1);
     if (!ctor)
         return NULL;
 
     /*
      * The default 'new' type of Array.prototype is required by type inference
      * to have unknown properties, to simplify handling of e.g. heterogenous
      * arrays in JSON and script literals and allows setDenseArrayElement to
      * be used without updating the indexed type set for such default arrays.
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -23,214 +23,188 @@
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsstr.h"
 #include "jsversion.h"
 #include "jsxml.h"
 
 #include "frontend/Parser.h"
 #include "gc/Marking.h"
+#include "vm/Xdr.h"
 
 #include "jsstrinlines.h"
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/String-inl.h"
-#include "vm/Xdr.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 
-const size_t JSAtomState::commonAtomsOffset = offsetof(JSAtomState, emptyAtom);
-
 const char *
 js_AtomToPrintableString(JSContext *cx, JSAtom *atom, JSAutoByteString *bytes)
 {
     return js_ValueToPrintable(cx, StringValue(atom), bytes);
 }
 
+const char * js::TypeStrings[] = {
+    js_undefined_str,
+    js_object_str,
+    js_function_str,
+    js_string_str,
+    js_number_str,
+    js_boolean_str,
+    js_null_str,
+    js_xml_str,
+};
+
 #define DEFINE_PROTO_STRING(name,code,init) const char js_##name##_str[] = #name;
 JS_FOR_EACH_PROTOTYPE(DEFINE_PROTO_STRING)
 #undef DEFINE_PROTO_STRING
 
-/*
- * String constants for common atoms defined in JSAtomState starting from
- * JSAtomState.emptyAtom until JSAtomState.lazy.
- *
- * The elements of the array after the first empty string define strings
- * corresponding to the two boolean literals, false and true, followed by the
- * JSType enumerators from jspubtd.h starting with "undefined" for JSTYPE_VOID
- * (which is special-value 2) and continuing as initialized below. The static
- * asserts check these relations.
- */
-JS_STATIC_ASSERT(JSTYPE_LIMIT == 8);
-JS_STATIC_ASSERT(JSTYPE_VOID == 0);
-
-const char *const js_common_atom_names[] = {
-    "",                         /* emptyAtom                    */
-    js_false_str,               /* booleanAtoms[0]              */
-    js_true_str,                /* booleanAtoms[1]              */
-    js_undefined_str,           /* typeAtoms[JSTYPE_VOID]       */
-    js_object_str,              /* typeAtoms[JSTYPE_OBJECT]     */
-    js_function_str,            /* typeAtoms[JSTYPE_FUNCTION]   */
-    "string",                   /* typeAtoms[JSTYPE_STRING]     */
-    "number",                   /* typeAtoms[JSTYPE_NUMBER]     */
-    "boolean",                  /* typeAtoms[JSTYPE_BOOLEAN]    */
-    js_null_str,                /* typeAtoms[JSTYPE_NULL]       */
-    "xml",                      /* typeAtoms[JSTYPE_XML]        */
-    js_null_str                 /* nullAtom                     */
-
-#define PROTOTYPE_COMMON_ATOM(name,code,init) ,js_##name##_str
-JS_FOR_EACH_PROTOTYPE(PROTOTYPE_COMMON_ATOM)
-#undef PROTOTYPE_COMMON_ATOM
-
-#define DEFINE_ATOM(id, text)          ,js_##id##_str
-#define DEFINE_PROTOTYPE_ATOM(id)      ,js_##id##_str
-#define DEFINE_KEYWORD_ATOM(id)        ,js_##id##_str
-#include "jsatom.tbl"
-#undef DEFINE_ATOM
-#undef DEFINE_PROTOTYPE_ATOM
-#undef DEFINE_KEYWORD_ATOM
-};
+#define CONST_CHAR_STR(id, text)      const char js_##id##_str[] = text;
+FOR_EACH_COMMON_PROPERTYNAME(CONST_CHAR_STR)
+#undef CONST_CHAR_STR
 
-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);
-}
-
-/*
- * 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);
-
-const char js_undefined_str[]       = "undefined";
-const char js_object_str[]          = "object";
-
-#define DEFINE_ATOM(id, text)          const char js_##id##_str[] = text;
-#define DEFINE_PROTOTYPE_ATOM(id)
-#define DEFINE_KEYWORD_ATOM(id)
-#include "jsatom.tbl"
-#undef DEFINE_ATOM
-#undef DEFINE_PROTOTYPE_ATOM
-#undef DEFINE_KEYWORD_ATOM
-
+/* Constant strings that are not atomized. */
+const char js_break_str[]           = "break";
+const char js_case_str[]            = "case";
+const char js_catch_str[]           = "catch";
+const char js_class_str[]           = "class";
+const char js_const_str[]           = "const";
+const char js_continue_str[]        = "continue";
+const char js_debugger_str[]        = "debugger";
+const char js_default_str[]         = "default";
+const char js_do_str[]              = "do";
+const char js_else_str[]            = "else";
+const char js_enum_str[]            = "enum";
+const char js_export_str[]          = "export";
+const char js_extends_str[]         = "extends";
+const char js_finally_str[]         = "finally";
+const char js_for_str[]             = "for";
+const char js_getter_str[]          = "getter";
+const char js_if_str[]              = "if";
+const char js_implements_str[]      = "implements";
+const char js_import_str[]          = "import";
+const char js_in_str[]              = "in";
+const char js_instanceof_str[]      = "instanceof";
+const char js_interface_str[]       = "interface";
+const char js_let_str[]             = "let";
+const char js_new_str[]             = "new";
+const char js_package_str[]         = "package";
+const char js_private_str[]         = "private";
+const char js_protected_str[]       = "protected";
+const char js_public_str[]          = "public";
+const char js_setter_str[]          = "setter";
+const char js_static_str[]          = "static";
+const char js_super_str[]           = "super";
+const char js_switch_str[]          = "switch";
+const char js_this_str[]            = "this";
+const char js_try_str[]             = "try";
+const char js_typeof_str[]          = "typeof";
+const char js_void_str[]            = "void";
+const char js_while_str[]           = "while";
+const char js_with_str[]            = "with";
+const char js_yield_str[]           = "yield";
 #if JS_HAS_GENERATORS
 const char js_close_str[]           = "close";
 const char js_send_str[]            = "send";
 #endif
 
-/* Constant strings that are not atomized. */
-const char js_getter_str[]          = "getter";
-const char js_setter_str[]          = "setter";
-
 /*
  * 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
-js::InitAtomState(JSRuntime *rt)
+js::InitAtoms(JSRuntime *rt)
 {
-    JSAtomState *state = &rt->atomState;
-
-    JS_ASSERT(!state->atoms.initialized());
-    if (!state->atoms.init(JS_STRING_HASH_COUNT))
-        return false;
-
-    JS_ASSERT(state->atoms.initialized());
-    return true;
+    return rt->atoms.init(JS_STRING_HASH_COUNT);
 }
 
 void
-js::FinishAtomState(JSRuntime *rt)
+js::FinishAtoms(JSRuntime *rt)
 {
-    JSAtomState *state = &rt->atomState;
-
-    if (!state->atoms.initialized()) {
+    AtomSet &atoms = rt->atoms;
+    if (!atoms.initialized()) {
         /*
          * We are called with uninitialized state when JS_NewRuntime fails and
          * calls JS_DestroyRuntime on a partially initialized runtime.
          */
         return;
     }
 
     FreeOp fop(rt, false);
-    for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront())
+    for (AtomSet::Range r = atoms.all(); !r.empty(); r.popFront())
         r.front().asPtr()->finalize(&fop);
 }
 
+struct CommonNameInfo
+{
+    const char *str;
+    size_t length;
+};
+
 bool
-js::InitCommonAtoms(JSContext *cx)
+js::InitCommonNames(JSContext *cx)
 {
-    JSAtomState *state = &cx->runtime->atomState;
-    JSAtom **atoms = state->commonAtomsStart();
-    for (size_t i = 0; i < ArrayLength(js_common_atom_names); i++, atoms++) {
-        JSAtom *atom = Atomize(cx, js_common_atom_names[i], strlen(js_common_atom_names[i]),
-                               InternAtom);
+    static const CommonNameInfo cachedNames[] = {
+#define COMMON_NAME_INFO(id, text) { js_##id##_str, sizeof(text) - 1 },
+        FOR_EACH_COMMON_PROPERTYNAME(COMMON_NAME_INFO)
+#undef COMMON_NAME_INFO
+#define COMMON_NAME_INFO(name, code, init) { js_##name##_str, sizeof(#name) - 1 },
+        JS_FOR_EACH_PROTOTYPE(COMMON_NAME_INFO)
+#undef COMMON_NAME_INFO
+    };
+
+    PropertyName **names = &cx->runtime->firstCachedName;
+    for (size_t i = 0; i < ArrayLength(cachedNames); i++, names++) {
+        JSAtom *atom = Atomize(cx, cachedNames[i].str, cachedNames[i].length, InternAtom);
         if (!atom)
             return false;
-        *atoms = atom->asPropertyName();
+        *names = atom->asPropertyName();
     }
+    JS_ASSERT(uintptr_t(names) == uintptr_t(&cx->runtime->atomState + 1));
 
-    cx->runtime->emptyString = state->emptyAtom;
+    cx->runtime->emptyString = cx->runtime->atomState.emptyAtom;
     return true;
 }
 
 void
-js::FinishCommonAtoms(JSRuntime *rt)
+js::FinishCommonNames(JSRuntime *rt)
 {
     rt->emptyString = NULL;
-    rt->atomState.junkAtoms();
+#ifdef DEBUG
+    memset(&rt->atomState, JS_FREE_PATTERN, sizeof(JSAtomState));
+#endif
 }
 
 void
-js::MarkAtomState(JSTracer *trc)
+js::MarkAtoms(JSTracer *trc)
 {
     JSRuntime *rt = trc->runtime;
-    JSAtomState *state = &rt->atomState;
-
-    for (AtomSet::Range r = state->atoms.all(); !r.empty(); r.popFront()) {
+    for (AtomSet::Range r = rt->atoms.all(); !r.empty(); r.popFront()) {
         AtomStateEntry entry = r.front();
         if (!entry.isTagged())
             continue;
 
         JSAtom *tmp = entry.asPtr();
         MarkStringRoot(trc, &tmp, "interned_atom");
         JS_ASSERT(tmp == entry.asPtr());
     }
 }
 
 void
-js::SweepAtomState(JSRuntime *rt)
+js::SweepAtoms(JSRuntime *rt)
 {
-    JSAtomState *state = &rt->atomState;
-
-    for (AtomSet::Enum e(state->atoms); !e.empty(); e.popFront()) {
+    for (AtomSet::Enum e(rt->atoms); !e.empty(); e.popFront()) {
         AtomStateEntry entry = e.front();
         JSAtom *atom = entry.asPtr();
         bool isMarked = IsStringMarked(&atom);
 
         /* Pinned or interned key cannot be finalized. */
         JS_ASSERT_IF(entry.isTagged(), isMarked);
 
         if (!isMarked)
@@ -240,17 +214,17 @@ js::SweepAtomState(JSRuntime *rt)
 
 bool
 AtomIsInterned(JSContext *cx, JSAtom *atom)
 {
     /* We treat static strings as interned because they're never collected. */
     if (StaticStrings::isStatic(atom))
         return true;
 
-    AtomSet::Ptr p = cx->runtime->atomState.atoms.lookup(atom);
+    AtomSet::Ptr p = cx->runtime->atoms.lookup(atom);
     if (!p)
         return false;
 
     return p->isTagged();
 }
 
 enum OwnCharsBehavior
 {
@@ -268,17 +242,17 @@ static JSAtom *
 AtomizeInline(JSContext *cx, const jschar **pchars, size_t length,
               InternBehavior ib, OwnCharsBehavior ocb = CopyChars)
 {
     const jschar *chars = *pchars;
 
     if (JSAtom *s = cx->runtime->staticStrings.lookup(chars, length))
         return s;
 
-    AtomSet &atoms = cx->runtime->atomState.atoms;
+    AtomSet &atoms = cx->runtime->atoms;
     AtomSet::AddPtr p = atoms.lookupForAdd(AtomHasher::Lookup(chars, length));
 
     if (p) {
         JSAtom *atom = p->asPtr();
         p->setTagged(bool(ib));
         return atom;
     }
 
@@ -323,18 +297,17 @@ JSAtom *
 js::AtomizeString(JSContext *cx, JSString *str, InternBehavior ib)
 {
     if (str->isAtom()) {
         JSAtom &atom = str->asAtom();
         /* N.B. static atoms are effectively always interned. */
         if (ib != InternAtom || js::StaticStrings::isStatic(&atom))
             return &atom;
 
-        AtomSet &atoms = cx->runtime->atomState.atoms;
-        AtomSet::Ptr p = atoms.lookup(AtomHasher::Lookup(&atom));
+        AtomSet::Ptr p = cx->runtime->atoms.lookup(AtomHasher::Lookup(&atom));
         JS_ASSERT(p); /* Non-static atom must exist in atom state set. */
         JS_ASSERT(p->asPtr() == &atom);
         JS_ASSERT(ib == InternAtom);
         p->setTagged(bool(ib));
         return &atom;
     }
 
     size_t length = str->length();
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -2,29 +2,31 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jsatom_h___
 #define jsatom_h___
 
+#include "mozilla/HashFunctions.h"
+
 #include <stddef.h>
 #include "jsalloc.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jsprototypes.h"
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jslock.h"
 #include "jsversion.h"
 
 #include "gc/Barrier.h"
 #include "js/HashTable.h"
-#include "mozilla/HashFunctions.h"
+#include "vm/CommonPropertyNames.h"
 
 struct JSIdArray {
     int length;
     js::HeapId vector[1];    /* actually, length jsid words */
 };
 
 namespace js {
 
@@ -139,151 +141,106 @@ enum FlationCoding
     NormalEncoding,
     CESU8Encoding
 };
 
 class PropertyName;
 
 }  /* namespace js */
 
-struct JSAtomState
-{
-    js::AtomSet         atoms;
-
-    /*
-     * From this point until the end of struct definition the struct must
-     * contain only js::PropertyName fields. We use this to access the storage
-     * occupied by the common atoms in js_FinishCommonAtoms.
-     *
-     * js_common_atom_names defined in jsatom.cpp contains C strings for atoms
-     * in the order of atom fields here. Therefore you must update that array
-     * if you change member order here.
-     */
-
-    /* The rt->emptyString atom, see jsstr.c's js_InitRuntimeStringState. */
-    js::PropertyName    *emptyAtom;
-
-    /*
-     * Literal value and type names.
-     * NB: booleanAtoms must come right before typeAtoms!
-     */
-    js::PropertyName    *booleanAtoms[2];
-    js::PropertyName    *typeAtoms[JSTYPE_LIMIT];
-    js::PropertyName    *nullAtom;
-
-    /* Standard class constructor or prototype names. */
-    js::PropertyName    *classAtoms[JSProto_LIMIT];
-
-    /* Various built-in or commonly-used atoms, pinned on first context. */
-#define DEFINE_ATOM(id, text)          js::PropertyName *id##Atom;
-#define DEFINE_PROTOTYPE_ATOM(id)      js::PropertyName *id##Atom;
-#define DEFINE_KEYWORD_ATOM(id)        js::PropertyName *id##Atom;
-#include "jsatom.tbl"
-#undef DEFINE_ATOM
-#undef DEFINE_PROTOTYPE_ATOM
-#undef DEFINE_KEYWORD_ATOM
-
-    static const size_t commonAtomsOffset;
-
-    void junkAtoms() {
-#ifdef DEBUG
-        memset(commonAtomsStart(), JS_FREE_PATTERN, sizeof(*this) - commonAtomsOffset);
-#endif
-    }
-
-    JSAtom **commonAtomsStart() {
-        return reinterpret_cast<JSAtom **>(&emptyAtom);
-    }
-
-    void checkStaticInvariants();
-};
-
 extern bool
 AtomIsInterned(JSContext *cx, JSAtom *atom);
 
-#define ATOM(name) js::HandlePropertyName::fromMarkedLocation(&cx->runtime->atomState.name##Atom)
-
-#define COMMON_ATOM_INDEX(name)                                               \
-    ((offsetof(JSAtomState, name##Atom) - JSAtomState::commonAtomsOffset)     \
-     / sizeof(JSAtom*))
-#define COMMON_TYPE_ATOM_INDEX(type)                                          \
-    ((offsetof(JSAtomState, typeAtoms[type]) - JSAtomState::commonAtomsOffset)\
-     / sizeof(JSAtom*))
-
-#define NAME_OFFSET(name)       offsetof(JSAtomState, name##Atom)
-#define OFFSET_TO_NAME(rt,off)  (*(js::PropertyName **)((char*)&(rt)->atomState + (off)))
-#define CLASS_NAME_OFFSET(name) offsetof(JSAtomState, classAtoms[JSProto_##name])
-#define CLASS_NAME(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)])
-#define JS_TYPE_STR(type)    (js_common_atom_names[1 + 2 + (type)])
-
-/* Type names. */
-extern const char   js_object_str[];
-extern const char   js_undefined_str[];
-
 /* Well-known predefined C strings. */
 #define DECLARE_PROTO_STR(name,code,init) extern const char js_##name##_str[];
 JS_FOR_EACH_PROTOTYPE(DECLARE_PROTO_STR)
 #undef DECLARE_PROTO_STR
 
-#define DEFINE_ATOM(id, text)  extern const char js_##id##_str[];
-#define DEFINE_PROTOTYPE_ATOM(id)
-#define DEFINE_KEYWORD_ATOM(id)
-#include "jsatom.tbl"
-#undef DEFINE_ATOM
-#undef DEFINE_PROTOTYPE_ATOM
-#undef DEFINE_KEYWORD_ATOM
+#define DECLARE_CONST_CHAR_STR(id, text)  extern const char js_##id##_str[];
+FOR_EACH_COMMON_PROPERTYNAME(DECLARE_CONST_CHAR_STR)
+#undef DECLARE_CONST_CHAR_STR
 
+/* Constant strings that are not atomized. */
+extern const char js_break_str[];
+extern const char js_case_str[];
+extern const char js_catch_str[];
+extern const char js_class_str[];
+extern const char js_const_str[];
+extern const char js_continue_str[];
+extern const char js_debugger_str[];
+extern const char js_default_str[];
+extern const char js_do_str[];
+extern const char js_else_str[];
+extern const char js_enum_str[];
+extern const char js_export_str[];
+extern const char js_extends_str[];
+extern const char js_finally_str[];
+extern const char js_for_str[];
+extern const char js_getter_str[];
+extern const char js_if_str[];
+extern const char js_implements_str[];
+extern const char js_import_str[];
+extern const char js_in_str[];
+extern const char js_instanceof_str[];
+extern const char js_interface_str[];
+extern const char js_let_str[];
+extern const char js_new_str[];
+extern const char js_package_str[];
+extern const char js_private_str[];
+extern const char js_protected_str[];
+extern const char js_public_str[];
+extern const char js_setter_str[];
+extern const char js_static_str[];
+extern const char js_super_str[];
+extern const char js_switch_str[];
+extern const char js_this_str[];
+extern const char js_try_str[];
+extern const char js_typeof_str[];
+extern const char js_void_str[];
+extern const char js_while_str[];
+extern const char js_with_str[];
+extern const char js_yield_str[];
 #if JS_HAS_GENERATORS
 extern const char   js_close_str[];
 extern const char   js_send_str[];
 #endif
 
-/* Constant strings that are not atomized. */
-extern const char   js_getter_str[];
-extern const char   js_setter_str[];
+namespace js {
 
-namespace js {
+extern const char * TypeStrings[];
 
 /*
  * Initialize atom state. Return true on success, false on failure to allocate
  * memory. The caller must zero rt->atomState before calling this function and
  * only call it after js_InitGC successfully returns.
  */
 extern JSBool
-InitAtomState(JSRuntime *rt);
+InitAtoms(JSRuntime *rt);
 
 /*
  * Free and clear atom state including any interned string atoms. This
  * function must be called before js_FinishGC.
  */
 extern void
-FinishAtomState(JSRuntime *rt);
+FinishAtoms(JSRuntime *rt);
 
 /*
  * Atom tracing and garbage collection hooks.
  */
 extern void
-MarkAtomState(JSTracer *trc);
+MarkAtoms(JSTracer *trc);
 
 extern void
-SweepAtomState(JSRuntime *rt);
+SweepAtoms(JSRuntime *rt);
 
 extern bool
-InitCommonAtoms(JSContext *cx);
+InitCommonNames(JSContext *cx);
 
 extern void
-FinishCommonAtoms(JSRuntime *rt);
+FinishCommonNames(JSRuntime *rt);
 
 /* N.B. must correspond to boolean tagging behavior. */
 enum InternBehavior
 {
     DoNotInternAtom = false,
     InternAtom = true
 };
 
deleted file mode 100644
--- a/js/src/jsatom.tbl
+++ /dev/null
@@ -1,156 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* vim: set sw=4 ts=8 et tw=80 ft=c: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*
- * Declare pre-interned atoms for easy use by SpiderMonkey's C++ code.
- * These entries define two things, where <id> is the macros' first
- * argument:
- *
- *   - js::PropertyName *<id>Atom: a member of JSAtomState pointing to the
- *     atom itself. Usually accessed as cx->runtime->atomState.<id>Atom.
- *
- *   - const char js_<id>_str[]: a global within SpiderMonkey, holding the
- *     atom's name. Some macros skip this, because it's already defined
- *     elsewhere.
- *
- * DEFINE_ATOM(id, name)
- *   Define an atom whose JavaScript string's value is |name|.
- *
- * DEFINE_PROTOTYPE_ATOM(id)
- *   Define an atom whose name is the same as one of those defined in
- *   jsprototypes.h. The code that processes that has already declared and
- *   defined the js_<id>_str global, so this defines only the JSAtomState
- *   member.
- *
- * DEFINE_KEYWORD_ATOM(id)
- *   Define an atom whose name is the same as one of those defined in
- *   jskeyword.tbl. The code that processes that has already declared and
- *   defined the js_<id>_str global, so this defines only the JSAtomState
- *   member.
- */
-
-
-
-DEFINE_ATOM(anonymous, "anonymous")
-DEFINE_ATOM(apply, "apply")
-DEFINE_ATOM(arguments, "arguments")
-DEFINE_ATOM(arity, "arity")
-DEFINE_ATOM(BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT")
-DEFINE_ATOM(call, "call")
-DEFINE_ATOM(callee, "callee")
-DEFINE_ATOM(caller, "caller")
-DEFINE_ATOM(classPrototype, "prototype")
-DEFINE_ATOM(construct, "construct")
-DEFINE_ATOM(columnNumber, "columnNumber")
-DEFINE_ATOM(constructor, "constructor")
-DEFINE_ATOM(deleteProperty, "deleteProperty")
-DEFINE_ATOM(each, "each")
-DEFINE_ATOM(eval, "eval")
-DEFINE_ATOM(fileName, "fileName")
-DEFINE_ATOM(get, "get")
-DEFINE_ATOM(global, "global")
-DEFINE_ATOM(ignoreCase, "ignoreCase")
-DEFINE_ATOM(index, "index")
-DEFINE_ATOM(input, "input")
-DEFINE_ATOM(toISOString, "toISOString")
-DEFINE_ATOM(iterator, "iterator")
-DEFINE_ATOM(iteratorIntrinsic, "__iterator__")
-DEFINE_ATOM(join, "join")
-DEFINE_ATOM(lastIndex, "lastIndex")
-DEFINE_ATOM(length, "length")
-DEFINE_ATOM(lineNumber, "lineNumber")
-DEFINE_ATOM(message, "message")
-DEFINE_ATOM(multiline, "multiline")
-DEFINE_ATOM(name, "name")
-DEFINE_ATOM(next, "next")
-DEFINE_ATOM(noSuchMethod, "__noSuchMethod__")
-DEFINE_ATOM(objectNull, "[object Null]")
-DEFINE_ATOM(objectUndefined, "[object Undefined]")
-DEFINE_ATOM(of, "of")
-DEFINE_ATOM(proto, "__proto__")
-DEFINE_ATOM(set, "set")
-DEFINE_ATOM(source, "source")
-DEFINE_ATOM(stack, "stack")
-DEFINE_ATOM(sticky, "sticky")
-DEFINE_ATOM(toGMTString, "toGMTString")
-DEFINE_ATOM(toLocaleString, "toLocaleString")
-DEFINE_ATOM(toSource, "toSource")
-DEFINE_ATOM(toString, "toString")
-DEFINE_ATOM(toUTCString, "toUTCString")
-DEFINE_ATOM(valueOf, "valueOf")
-DEFINE_ATOM(toJSON, "toJSON")
-DEFINE_ATOM(void0, "(void 0)")
-DEFINE_ATOM(enumerable, "enumerable")
-DEFINE_ATOM(configurable, "configurable")
-DEFINE_ATOM(writable, "writable")
-DEFINE_ATOM(value, "value")
-DEFINE_ATOM(test, "test")
-DEFINE_ATOM(useStrict, "use strict")
-DEFINE_ATOM(loc, "loc")
-DEFINE_ATOM(line, "line")
-DEFINE_ATOM(Infinity, "Infinity")
-DEFINE_ATOM(NaN, "NaN")
-DEFINE_ATOM(builder, "builder")
-
-#if JS_HAS_XML_SUPPORT
-DEFINE_ATOM(etago, "</")
-DEFINE_ATOM(namespace, "namespace")
-DEFINE_ATOM(ptagc, "/>")
-DEFINE_ATOM(qualifier, "::")
-DEFINE_ATOM(space, " ")
-DEFINE_ATOM(stago, "<")
-DEFINE_ATOM(star, "*")
-DEFINE_ATOM(starQualifier, "*::")
-DEFINE_ATOM(tagc, ">")
-DEFINE_ATOM(xml, "xml")
-DEFINE_ATOM(functionNamespaceURI, "@mozilla.org/js/function")
-#endif
-
-DEFINE_PROTOTYPE_ATOM(Proxy)
-DEFINE_ATOM(getOwnPropertyDescriptor, "getOwnPropertyDescriptor")
-DEFINE_ATOM(getPropertyDescriptor, "getPropertyDescriptor")
-DEFINE_ATOM(defineProperty, "defineProperty")
-DEFINE_KEYWORD_ATOM(delete)
-DEFINE_ATOM(getOwnPropertyNames, "getOwnPropertyNames")
-DEFINE_ATOM(enumerate, "enumerate")
-DEFINE_ATOM(fix, "fix")
-DEFINE_ATOM(has, "has")
-DEFINE_ATOM(hasOwn, "hasOwn")
-DEFINE_ATOM(keys, "keys")
-DEFINE_ATOM(iterate, "iterate")
-DEFINE_PROTOTYPE_ATOM(WeakMap)
-DEFINE_ATOM(buffer, "buffer")
-DEFINE_ATOM(byteLength, "byteLength")
-DEFINE_ATOM(byteOffset, "byteOffset")
-DEFINE_ATOM(shape, "shape")
-DEFINE_KEYWORD_ATOM(return)
-DEFINE_KEYWORD_ATOM(throw)
-DEFINE_ATOM(url, "url")
-DEFINE_ATOM(innermost, "innermost")
-
-DEFINE_ATOM(XMLList, "XMLList")
-DEFINE_ATOM(decodeURI, "decodeURI")
-DEFINE_ATOM(decodeURIComponent, "decodeURIComponent")
-DEFINE_ATOM(defineGetter, "__defineGetter__")
-DEFINE_ATOM(defineSetter, "__defineSetter__")
-DEFINE_ATOM(encodeURI, "encodeURI")
-DEFINE_ATOM(encodeURIComponent, "encodeURIComponent")
-DEFINE_ATOM(escape, "escape")
-DEFINE_ATOM(hasOwnProperty, "hasOwnProperty")
-DEFINE_ATOM(isFinite, "isFinite")
-DEFINE_ATOM(isNaN, "isNaN")
-DEFINE_ATOM(isPrototypeOf, "isPrototypeOf")
-DEFINE_ATOM(isXMLName, "isXMLName")
-DEFINE_ATOM(lookupGetter, "__lookupGetter__")
-DEFINE_ATOM(lookupSetter, "__lookupSetter__")
-DEFINE_ATOM(parseFloat, "parseFloat")
-DEFINE_ATOM(parseInt, "parseInt")
-DEFINE_ATOM(propertyIsEnumerable, "propertyIsEnumerable")
-DEFINE_ATOM(unescape, "unescape")
-DEFINE_ATOM(uneval, "uneval")
-DEFINE_ATOM(unwatch, "unwatch")
-DEFINE_ATOM(watch, "watch")
-DEFINE_ATOM(_CallFunction, "_CallFunction")
--- a/js/src/jsatominlines.h
+++ b/js/src/jsatominlines.h
@@ -145,11 +145,38 @@ AtomHasher::match(const AtomStateEntry &
     JSAtom *key = entry.asPtr();
     if (lookup.atom)
         return lookup.atom == key;
     if (key->length() != lookup.length)
         return false;
     return PodEqual(key->chars(), lookup.chars, lookup.length);
 }
 
+inline PropertyName *
+TypeName(JSType type, JSRuntime *rt)
+{
+    JS_ASSERT(type < JSTYPE_LIMIT);
+    JS_STATIC_ASSERT(offsetof(JSAtomState, undefinedAtom) +
+                     JSTYPE_LIMIT * sizeof(PropertyName *) <=
+                     sizeof(JSAtomState));
+    JS_STATIC_ASSERT(JSTYPE_VOID == 0);
+    return (&rt->atomState.undefinedAtom)[type];
+}
+
+inline PropertyName *
+TypeName(JSType type, JSContext *cx)
+{
+    return TypeName(type, cx->runtime);
+}
+
+inline PropertyName *
+ClassName(JSProtoKey key, JSContext *cx)
+{
+    JS_ASSERT(key < JSProto_LIMIT);
+    JS_STATIC_ASSERT(offsetof(JSAtomState, NullAtom) + JSProto_LIMIT * sizeof(PropertyName *) <=
+                     sizeof(JSAtomState));
+    JS_STATIC_ASSERT(JSProto_Null == 0);
+    return (&cx->runtime->atomState.NullAtom)[key];
+}
+
 } // namespace js
 
 #endif /* jsatominlines_h___ */
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -82,17 +82,17 @@ bool_toSource(JSContext *cx, unsigned ar
 
 JS_ALWAYS_INLINE bool
 bool_toString_impl(JSContext *cx, CallArgs args)
 {
     const Value &thisv = args.thisv();
     JS_ASSERT(IsBoolean(thisv));
 
     bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().asBoolean().unbox();
-    args.rval().setString(cx->runtime->atomState.booleanAtoms[b ? 1 : 0]);
+    args.rval().setString(js_BooleanToString(cx, b));
     return true;
 }
 
 JSBool
 bool_toString(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsBoolean, bool_toString_impl>(cx, args);
@@ -149,17 +149,18 @@ js_InitBooleanClass(JSContext *cx, JSObj
 
     Rooted<GlobalObject*> global(cx, &obj->asGlobal());
 
     RootedObject booleanProto (cx, global->createBlankPrototype(cx, &BooleanClass));
     if (!booleanProto)
         return NULL;
     booleanProto->setFixedSlot(BooleanObject::PRIMITIVE_VALUE_SLOT, BooleanValue(false));
 
-    RootedFunction ctor(cx, global->createConstructor(cx, Boolean, CLASS_NAME(cx, Boolean), 1));
+    RootedFunction ctor(cx);
+    ctor = global->createConstructor(cx, Boolean, cx->runtime->atomState.BooleanAtom, 1);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, booleanProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, booleanProto, NULL, boolean_methods))
         return NULL;
@@ -182,17 +183,17 @@ js_InitBooleanClass(JSContext *cx, JSObj
         return NULL;
 
     return booleanProto;
 }
 
 JSString *
 js_BooleanToString(JSContext *cx, JSBool b)
 {
-    return cx->runtime->atomState.booleanAtoms[b ? 1 : 0];
+    return b ? cx->runtime->atomState.trueAtom : cx->runtime->atomState.falseAtom;
 }
 
 namespace js {
 
 JS_PUBLIC_API(bool)
 ToBooleanSlow(const Value &v)
 {
     JS_ASSERT(v.isString());
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -114,17 +114,17 @@ void CompartmentCallback(JSRuntime *rt, 
     data->n += data->mallocSizeOf(compartment);
 }
 
 void
 JSRuntime::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, RuntimeSizes *runtime)
 {
     runtime->object = mallocSizeOf(this);
 
-    runtime->atomsTable = atomState.atoms.sizeOfExcludingThis(mallocSizeOf);
+    runtime->atomsTable = atoms.sizeOfExcludingThis(mallocSizeOf);
 
     runtime->contexts = 0;
     for (ContextIter acx(this); !acx.done(); acx.next())
         runtime->contexts += acx->sizeOfIncludingThis(mallocSizeOf);
 
     runtime->dtoa = mallocSizeOf(dtoaState);
 
     runtime->temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
@@ -374,17 +374,17 @@ js::NewContext(JSRuntime *rt, size_t sta
      * cx will be "last" as well as "first".
      */
     if (first) {
 #ifdef JS_THREADSAFE
         JS_BeginRequest(cx);
 #endif
         bool ok = rt->staticStrings.init(cx);
         if (ok)
-            ok = InitCommonAtoms(cx);
+            ok = InitCommonNames(cx);
         if (ok)
             ok = rt->initSelfHosting(cx);
 
 #ifdef JS_THREADSAFE
         JS_EndRequest(cx);
 #endif
         if (!ok) {
             DestroyContext(cx, DCM_NEW_FAILED);
@@ -434,18 +434,18 @@ js::DestroyContext(JSContext *cx, Destro
          */
         for (CompartmentsIter c(rt); !c.done(); c.next())
             c->types.print(cx, false);
 
         /* Off thread ion compilations depend on atoms still existing. */
         for (CompartmentsIter c(rt); !c.done(); c.next())
             CancelOffThreadIonCompile(c, NULL);
 
-        /* Unpin all common atoms before final GC. */
-        FinishCommonAtoms(rt);
+        /* Unpin all common names before final GC. */
+        FinishCommonNames(rt);
 
         /* Clear debugging state to remove GC roots. */
         for (CompartmentsIter c(rt); !c.done(); c.next())
             c->clearTraps(rt->defaultFreeOp());
         JS_ClearAllWatchPoints(cx);
 
         PrepareForFullGC(rt);
         GC(rt, GC_NORMAL, gcreason::LAST_CONTEXT);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -17,16 +17,17 @@
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jsprvtd.h"
 #include "jsatom.h"
 #include "jsclist.h"
 #include "jsgc.h"
 #include "jspropertycache.h"
 #include "jspropertytree.h"
+#include "jsprototypes.h"
 #include "jsutil.h"
 #include "prmjtime.h"
 
 #include "ds/LifoAlloc.h"
 #include "gc/Statistics.h"
 #include "js/HashTable.h"
 #include "js/Vector.h"
 #include "vm/Stack.h"
@@ -373,16 +374,32 @@ class FreeOp : public JSFreeOp {
 };
 
 } /* namespace js */
 
 namespace JS {
 struct RuntimeSizes;
 }
 
+/* Various built-in or commonly-used names pinned on first context. */
+struct JSAtomState
+{
+#define PROPERTYNAME_FIELD(id, text)          js::PropertyName *id##Atom;
+    FOR_EACH_COMMON_PROPERTYNAME(PROPERTYNAME_FIELD)
+#undef PROPERTYNAME_FIELD
+#define PROPERTYNAME_FIELD(name, code, init)  js::PropertyName *name##Atom;
+    JS_FOR_EACH_PROTOTYPE(PROPERTYNAME_FIELD)
+#undef PROPERTYNAME_FIELD
+};
+
+#define ATOM(name) js::HandlePropertyName::fromMarkedLocation(&cx->runtime->atomState.name##Atom)
+
+#define NAME_OFFSET(name)       offsetof(JSAtomState, name##Atom)
+#define OFFSET_TO_NAME(rt,off)  (*(js::PropertyName **)((char*)&(rt)->atomState + (off)))
+
 struct JSRuntime : js::RuntimeFriendFields
 {
     /* Default compartment. */
     JSCompartment       *atomsCompartment;
 
     /* List of compartments (protected by the GC lock). */
     js::CompartmentVector compartments;
 
@@ -879,18 +896,28 @@ struct JSRuntime : js::RuntimeFriendFiel
     js::ConservativeGCData conservativeGC;
 
   private:
     JSPrincipals        *trustedPrincipals_;
   public:
     void setTrustedPrincipals(JSPrincipals *p) { trustedPrincipals_ = p; }
     JSPrincipals *trustedPrincipals() const { return trustedPrincipals_; }
 
-    /* Literal table maintained by jsatom.c functions. */
-    JSAtomState         atomState;
+    /* Set of all currently-living atoms. */
+    js::AtomSet         atoms;
+
+    union {
+        /*
+         * Cached pointers to various interned property names, initialized in
+         * order from first to last via the other union arm.
+         */
+        JSAtomState atomState;
+
+        js::PropertyName *firstCachedName;
+    };
 
     /* Tables of strings that are pre-allocated in the atomsCompartment. */
     js::StaticStrings   staticStrings;
 
     JSWrapObjectCallback                   wrapObjectCallback;
     JSSameCompartmentWrapObjectCallback    sameCompartmentWrapObjectCallback;
     JSPreWrapCallback                      preWrapObjectCallback;
     js::PreserveWrapperCallback            preserveWrapperCallback;
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -3155,17 +3155,18 @@ js_InitDateClass(JSContext *cx, JSObject
 
     Rooted<GlobalObject*> global(cx, &obj->asGlobal());
 
     RootedObject dateProto(cx, global->createBlankPrototype(cx, &DateClass));
     if (!dateProto)
         return NULL;
     SetDateToNaN(cx, dateProto);
 
-    RootedFunction ctor(cx, global->createConstructor(cx, js_Date, CLASS_NAME(cx, Date), MAXARGS));
+    RootedFunction ctor(cx);
+    ctor = global->createConstructor(cx, js_Date, cx->runtime->atomState.DateAtom, MAXARGS);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, dateProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, ctor, NULL, date_static_methods))
         return NULL;
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -630,17 +630,17 @@ exn_toString(JSContext *cx, unsigned arg
     /* Step 3. */
     RootedValue nameVal(cx);
     if (!JSObject::getProperty(cx, obj, obj, cx->runtime->atomState.nameAtom, &nameVal))
         return false;
 
     /* Step 4. */
     RootedString name(cx);
     if (nameVal.isUndefined()) {
-        name = CLASS_NAME(cx, Error);
+        name = cx->runtime->atomState.ErrorAtom;
     } else {
         name = ToString(cx, nameVal);
         if (!name)
             return false;
     }
 
     /* Step 5. */
     RootedValue msgVal(cx);
@@ -654,17 +654,17 @@ exn_toString(JSContext *cx, unsigned arg
     } else {
         message = ToString(cx, msgVal);
         if (!message)
             return false;
     }
 
     /* Step 7. */
     if (name->empty() && message->empty()) {
-        args.rval().setString(CLASS_NAME(cx, Error));
+        args.rval().setString(cx->runtime->atomState.ErrorAtom);
         return true;
     }
 
     /* Step 8. */
     if (name->empty()) {
         args.rval().setString(message);
         return true;
     }
@@ -784,17 +784,17 @@ JS_STATIC_ASSERT(JSProto_Error + JSEXN_R
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_SYNTAXERR    == JSProto_SyntaxError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_TYPEERR      == JSProto_TypeError);
 JS_STATIC_ASSERT(JSProto_Error + JSEXN_URIERR       == JSProto_URIError);
 
 static JSObject *
 InitErrorClass(JSContext *cx, Handle<GlobalObject*> global, int type, HandleObject proto)
 {
     JSProtoKey key = GetExceptionProtoKey(type);
-    RootedAtom name(cx, cx->runtime->atomState.classAtoms[key]);
+    RootedAtom name(cx, ClassName(key, cx));
     RootedObject errorProto(cx, global->createBlankPrototypeInheriting(cx, &ErrorClass, *proto));
     if (!errorProto)
         return NULL;
 
     RootedValue nameValue(cx, StringValue(name));
     RootedValue zeroValue(cx, Int32Value(0));
     RootedValue empty(cx, StringValue(cx->runtime->emptyString));
     RootedId nameId(cx, NameToId(cx->runtime->atomState.nameAtom));
@@ -889,17 +889,17 @@ GetErrorTypeName(JSContext* cx, int16_t 
      * is prepended before "uncaught exception: "
      */
     if (exnType <= JSEXN_NONE || exnType >= JSEXN_LIMIT ||
         exnType == JSEXN_INTERNALERR)
     {
         return NULL;
     }
     JSProtoKey key = GetExceptionProtoKey(exnType);
-    return cx->runtime->atomState.classAtoms[key]->chars();
+    return ClassName(key, cx)->chars();
 }
 
 } /* namespace js */
 
 #if defined ( DEBUG_mccabe ) && defined ( PRINTNAMES )
 /* For use below... get character strings for error name and exception name */
 static struct exnname { char *name; char *exception; } errortoexnname[] = {
 #define MSG_DEF(name, number, count, exception, format) \
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2561,17 +2561,17 @@ MarkRuntime(JSTracer *trc, bool useSaved
 
     if (rt->scriptAndCountsVector) {
         ScriptAndCountsVector &vec = *rt->scriptAndCountsVector;
         for (size_t i = 0; i < vec.length(); i++)
             MarkScriptRoot(trc, &vec[i].script, "scriptAndCountsVector");
     }
 
     if (!IS_GC_MARKING_TRACER(trc) || rt->atomsCompartment->isCollecting())
-        MarkAtomState(trc);
+        MarkAtoms(trc);
     rt->staticStrings.trace(trc);
 
     for (ContextIter acx(rt); !acx.done(); acx.next())
         acx->mark(trc);
 
     /* We can't use GCCompartmentsIter if we're called from TraceRuntime. */
     for (CompartmentsIter c(rt); !c.done(); c.next()) {
         if (IS_GC_MARKING_TRACER(trc) && !c->isCollecting())
@@ -3954,17 +3954,17 @@ SweepAtomsCompartment(JSRuntime *rt)
 
     JS_ASSERT(c->isGCMarking());
     c->setGCState(JSCompartment::Sweep);
 
     c->arenas.purge();
 
     {
         gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_ATOMS);
-        SweepAtomState(rt);
+        SweepAtoms(rt);
     }
 
     FreeOp fop(rt, rt->gcSweepOnBackgroundThread);
 
     c->arenas.queueStringsForSweep(&fop);
 }
 
 static void
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3730,19 +3730,20 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         jsid id = GetAtomId(cx, script, pc, 0);
 
         StackTypeSet *seen = bytecodeTypes(pc);
         seen->addSubset(cx, &pushed[0]);
 
         /*
          * Normally we rely on lazy standard class initialization to fill in
          * the types of global properties the script can access. In a few cases
-         * the method JIT will bypass this, and we need to add the types direclty.
+         * the method JIT will bypass this, and we need to add the types
+         * directly.
          */
-        if (id == NameToId(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]))
+        if (id == NameToId(cx->runtime->atomState.undefinedAtom))
             seen->addType(cx, Type::UndefinedType());
         if (id == NameToId(cx->runtime->atomState.NaNAtom))
             seen->addType(cx, Type::DoubleType());
         if (id == NameToId(cx->runtime->atomState.InfinityAtom))
             seen->addType(cx, Type::DoubleType());
 
         TypeObject *global = script->global().getType(cx);
 
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -14,16 +14,17 @@
 #include "jsinfer.h"
 #include "jsinterp.h"
 #include "jslibmath.h"
 #include "jsnum.h"
 #include "jsprobes.h"
 #include "jsstr.h"
 #include "methodjit/MethodJIT.h"
 
+#include "jsatominlines.h"
 #include "jsfuninlines.h"
 #include "jsinferinlines.h"
 #include "jsopcodeinlines.h"
 #include "jspropertycacheinlines.h"
 #include "jstypedarrayinlines.h"
 
 #include "vm/Stack-inl.h"
 
@@ -822,17 +823,17 @@ SetObjectElementOperation(JSContext *cx,
     RootedValue tmp(cx, value);
     return JSObject::setGeneric(cx, obj, obj, id, &tmp, strict);
 }
 
 static JS_ALWAYS_INLINE JSString *
 TypeOfOperation(JSContext *cx, HandleValue v)
 {
     JSType type = JS_TypeOfValue(cx, v);
-    return cx->runtime->atomState.typeAtoms[type];
+    return TypeName(type, cx);
 }
 
 #define RELATIONAL_OP(OP)                                                     \
     JS_BEGIN_MACRO                                                            \
         RootedValue lvalRoot(cx, lhs), rvalRoot(cx, rhs);                     \
         Value &lval = lvalRoot.get();                                         \
         Value &rval = rvalRoot.get();                                         \
         /* Optimize for two int-tagged operands (typical loop control). */    \
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -1772,18 +1772,18 @@ GlobalObject::initIteratorClasses(JSCont
         AutoIdVector blank(cx);
         NativeIterator *ni = NativeIterator::allocateIterator(cx, 0, blank);
         if (!ni)
             return false;
         ni->init(NULL, 0 /* flags */, 0, 0);
 
         iteratorProto->asPropertyIterator().setNativeIterator(ni);
 
-        Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, IteratorConstructor,
-                                                               CLASS_NAME(cx, Iterator), 2));
+        Rooted<JSFunction*> ctor(cx);
+        ctor = global->createConstructor(cx, IteratorConstructor, cx->runtime->atomState.IteratorAtom, 2);
         if (!ctor)
             return false;
         if (!LinkConstructorAndPrototype(cx, ctor, iteratorProto))
             return false;
         if (!DefinePropertiesAndBrand(cx, iteratorProto, NULL, iterator_methods))
             return false;
         if (!DefineConstructorAndPrototype(cx, global, JSProto_Iterator, ctor, iteratorProto))
             return false;
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -651,17 +651,17 @@ js::math_tan(JSContext *cx, unsigned arg
     vp->setDouble(z);
     return JS_TRUE;
 }
 
 #if JS_HAS_TOSOURCE
 static JSBool
 math_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
-    vp->setString(CLASS_NAME(cx, Math));
+    vp->setString(cx->runtime->atomState.MathAtom);
     return JS_TRUE;
 }
 #endif
 
 static JSFunctionSpec math_static_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,  math_toSource,        0, 0),
 #endif
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1131,17 +1131,18 @@ js_InitNumberClass(JSContext *cx, JSObje
 
     Rooted<GlobalObject*> global(cx, &obj->asGlobal());
 
     RootedObject numberProto(cx, global->createBlankPrototype(cx, &NumberClass));
     if (!numberProto)
         return NULL;
     numberProto->asNumber().setPrimitiveValue(0);
 
-    RootedFunction ctor(cx, global->createConstructor(cx, Number, CLASS_NAME(cx, Number), 1));
+    RootedFunction ctor(cx);
+    ctor = global->createConstructor(cx, Number, cx->runtime->atomState.NumberAtom, 1);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, numberProto))
         return NULL;
 
     /* Add numeric constants (MAX_VALUE, NaN, &c.) to the Number constructor. */
     if (!JS_DefineConstDoubles(cx, ctor, number_constants))
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2429,17 +2429,17 @@ Detecting(JSContext *cx, jsbytecode *pc)
 
     if (op == JSOP_GETGNAME || op == JSOP_NAME) {
         /*
          * Special case #2: handle (document.all == undefined).  Don't worry
          * about a local variable named |undefined| shadowing the immutable
          * global binding...because, really?
          */
         atom = script->getAtom(GET_UINT32_INDEX(pc));
-        if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&
+        if (atom == cx->runtime->atomState.undefinedAtom &&
             (pc += js_CodeSpec[op].length) < endpc) {
             op = JSOp(*pc);
             return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
         }
     }
 
     return false;
 }
@@ -3587,17 +3587,17 @@ js_GetClassObject(JSContext *cx, RawObje
     }
 
     Value v = global->getReservedSlot(key);
     if (v.isObject()) {
         objp.set(&v.toObject());
         return true;
     }
 
-    RootedId name(cx, NameToId(cx->runtime->atomState.classAtoms[key]));
+    RootedId name(cx, NameToId(ClassName(key, cx)));
     AutoResolving resolving(cx, global, name);
     if (resolving.alreadyStarted()) {
         /* Already caching id in global -- suppress recursion. */
         objp.set(NULL);
         return true;
     }
 
     JSObject *cobj = NULL;
@@ -3646,17 +3646,17 @@ js_FindClassObject(JSContext *cx, JSProt
         JS_ASSERT(protoKey < JSProto_LIMIT);
         RootedObject cobj(cx);
         if (!js_GetClassObject(cx, cx->global(), protoKey, &cobj))
             return false;
         if (cobj) {
             vp.set(ObjectValue(*cobj));
             return JS_TRUE;
         }
-        id = NameToId(cx->runtime->atomState.classAtoms[protoKey]);
+        id = NameToId(ClassName(protoKey, cx));
     } else {
         JSAtom *atom = Atomize(cx, clasp->name, strlen(clasp->name));
         if (!atom)
             return false;
         id = AtomToId(atom);
     }
 
     RootedObject pobj(cx);
@@ -4915,17 +4915,17 @@ DefaultValue(JSContext *cx, HandleObject
         if (!str)
             return false;
     } else {
         str = NULL;
     }
 
     RootedValue val(cx, ObjectValue(*obj));
     js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, JSDVG_SEARCH_STACK, val, str,
-                         (hint == JSTYPE_VOID) ? "primitive type" : JS_TYPE_STR(hint));
+                         (hint == JSTYPE_VOID) ? "primitive type" : TypeStrings[hint]);
     return false;
 }
 
 } /* namespace js */
 
 JS_FRIEND_API(JSBool)
 JS_EnumerateState(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op,
                   JSMutableHandleValue statep, JSMutableHandleId idp)
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1544,17 +1544,17 @@ PreallocateObjectDynamicSlots(JSContext 
 inline bool
 DefineConstructorAndPrototype(JSContext *cx, GlobalObject *global,
                               JSProtoKey key, JSObject *ctor, JSObject *proto)
 {
     JS_ASSERT(!global->nativeEmpty()); /* reserved slots already allocated */
     JS_ASSERT(ctor);
     JS_ASSERT(proto);
 
-    jsid id = NameToId(cx->runtime->atomState.classAtoms[key]);
+    jsid id = NameToId(ClassName(key, cx));
     JS_ASSERT(!global->nativeLookupNoAllocation(id));
 
     /* Set these first in case AddTypePropertyId looks for this class. */
     global->setSlot(key, ObjectValue(*ctor));
     global->setSlot(key + JSProto_LIMIT, ObjectValue(*proto));
     global->setSlot(key + JSProto_LIMIT * 2, ObjectValue(*ctor));
 
     types::AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -63,17 +63,17 @@ js_json_parse(JSContext *cx, unsigned ar
     if (argc >= 1) {
         JSString *str = ToString(cx, args[0]);
         if (!str)
             return false;
         linear = str->ensureLinear(cx);
         if (!linear)
             return false;
     } else {
-        linear = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
+        linear = cx->runtime->atomState.undefinedAtom;
     }
     JS::Anchor<JSString *> anchor(linear);
 
     RootedValue reviver(cx, (argc >= 2) ? args[1] : UndefinedValue());
 
     /* Steps 2-5. */
     return ParseJSONWithReviver(cx, linear->chars(), linear->length(), reviver, args.rval());
 }
@@ -882,17 +882,17 @@ ParseJSONWithReviver(JSContext *cx, cons
 }
 
 } /* namespace js */
 
 #if JS_HAS_TOSOURCE
 static JSBool
 json_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
-    vp->setString(CLASS_NAME(cx, JSON));
+    vp->setString(cx->runtime->atomState.JSONAtom);
     return JS_TRUE;
 }
 #endif
 
 static JSFunctionSpec json_static_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,  json_toSource,      0, 0),
 #endif
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -61,17 +61,17 @@ using namespace js;
 using namespace js::gc;
 using namespace js::types;
 using namespace js::unicode;
 
 static JSLinearString *
 ArgToRootedString(JSContext *cx, CallArgs &args, unsigned argno)
 {
     if (argno >= args.length())
-        return cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
+        return cx->runtime->atomState.undefinedAtom;
 
     Value &arg = args[argno];
     JSString *str = ToString(cx, arg);
     if (!str)
         return NULL;
 
     arg = StringValue(str);
     return str->ensureLinear(cx);
@@ -3232,17 +3232,18 @@ js_InitStringClass(JSContext *cx, JSObje
     Rooted<GlobalObject*> global(cx, &obj->asGlobal());
 
     Rooted<JSString*> empty(cx, cx->runtime->emptyString);
     RootedObject proto(cx, global->createBlankPrototype(cx, &StringClass));
     if (!proto || !proto->asString().init(cx, empty))
         return NULL;
 
     /* Now create the String function. */
-    RootedFunction ctor(cx, global->createConstructor(cx, js_String, CLASS_NAME(cx, String), 1));
+    RootedFunction ctor(cx);
+    ctor = global->createConstructor(cx, js_String, cx->runtime->atomState.StringAtom, 1);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, proto, NULL, string_methods) ||
         !DefinePropertiesAndBrand(cx, ctor, NULL, string_static_methods))
@@ -3419,17 +3420,17 @@ js::ToStringSlow(JSContext *cx, const Va
         str = Int32ToString(cx, v.toInt32());
     } else if (v.isDouble()) {
         str = js_NumberToString(cx, v.toDouble());
     } else if (v.isBoolean()) {
         str = js_BooleanToString(cx, v.toBoolean());
     } else if (v.isNull()) {
         str = cx->runtime->atomState.nullAtom;
     } else {
-        str = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
+        str = cx->runtime->atomState.undefinedAtom;
     }
     return str;
 }
 
 JS_FRIEND_API(JSString *)
 js_ValueToSource(JSContext *cx, const Value &v)
 {
     JS_CHECK_RECURSION(cx, return NULL);
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -3200,17 +3200,17 @@ InitTypedArrayClass(JSContext *cx)
 {
     Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
     RootedObject proto(cx, global->createBlankPrototype(cx, ArrayType::protoClass()));
     if (!proto)
         return NULL;
 
     RootedFunction ctor(cx);
     ctor = global->createConstructor(cx, ArrayType::class_constructor,
-                                     cx->runtime->atomState.classAtoms[ArrayType::key], 3);
+                                     ClassName(ArrayType::key, cx), 3);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return NULL;
 
     RootedValue bytesValue(cx, Int32Value(ArrayType::BYTES_PER_ELEMENT));
 
@@ -3286,17 +3286,17 @@ static JSObject *
 InitArrayBufferClass(JSContext *cx)
 {
     Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
     RootedObject arrayBufferProto(cx, global->createBlankPrototype(cx, &ArrayBufferObject::protoClass));
     if (!arrayBufferProto)
         return NULL;
 
     RootedFunction ctor(cx, global->createConstructor(cx, ArrayBufferObject::class_constructor,
-                                                      CLASS_NAME(cx, ArrayBuffer), 1));
+                                                      cx->runtime->atomState.ArrayBufferAtom, 1));
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto))
         return NULL;
 
     RootedId byteLengthId(cx, NameToId(cx->runtime->atomState.byteLengthAtom));
     unsigned flags = JSPROP_SHARED | JSPROP_GETTER | JSPROP_PERMANENT;
@@ -3415,17 +3415,17 @@ JSObject *
 DataViewObject::initClass(JSContext *cx)
 {
     Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
     RootedObject proto(cx, global->createBlankPrototype(cx, &DataViewObject::protoClass));
     if (!proto)
         return NULL;
 
     RootedFunction ctor(cx, global->createConstructor(cx, DataViewObject::class_constructor,
-                                                      CLASS_NAME(cx, DataView), 3));
+                                                      cx->runtime->atomState.DataViewAtom, 3));
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return NULL;
 
     if (!defineGetter<bufferValue>(cx, cx->runtime->atomState.bufferAtom, proto))
         return NULL;
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -368,17 +368,17 @@ js_InitWeakMapClass(JSContext *cx, JSObj
 
     Rooted<GlobalObject*> global(cx, &obj->asGlobal());
 
     RootedObject weakMapProto(cx, global->createBlankPrototype(cx, &WeakMapClass));
     if (!weakMapProto)
         return NULL;
 
     RootedFunction ctor(cx, global->createConstructor(cx, WeakMap_construct,
-                                                      CLASS_NAME(cx, WeakMap), 0));
+                                                      cx->runtime->atomState.WeakMapAtom, 0));
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, weakMapProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, weakMapProto, NULL, weak_map_methods))
         return NULL;
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -732,17 +732,17 @@ QNameHelper(JSContext *cx, int argc, jsv
 
         /* Namespace and qname were passed -- use the qname's localName. */
         nameval = qn->getQNameLocalNameVal();
     }
 
     if (argc == 0) {
         name = cx->runtime->emptyString;
     } else if (argc < 0) {
-        name = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
+        name = cx->runtime->atomState.undefinedAtom;
     } else {
         name = ToAtom(cx, nameval);
         if (!name)
             return false;
     }
 
     if (argc > 1 && !JSVAL_IS_VOID(argv[0])) {
         nsval = argv[0];
@@ -6545,17 +6545,17 @@ xml_replace(JSContext *cx, unsigned argc
     uint32_t index, i;
     JSObject *nameqn;
 
     NON_LIST_XML_METHOD_PROLOG;
     if (xml->xml_class != JSXML_CLASS_ELEMENT)
         goto done;
 
     if (argc <= 1) {
-        value = STRING_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
+        value = STRING_TO_JSVAL(cx->runtime->atomState.undefinedAtom);
     } else {
         value = vp[3];
         vxml = VALUE_IS_XML(value)
                ? (JSXML *) JSVAL_TO_OBJECT(value)->getPrivate()
                : NULL;
         if (!vxml) {
             if (!JS_ConvertValue(cx, value, JSTYPE_STRING, &vp[3]))
                 return JS_FALSE;
@@ -6637,17 +6637,17 @@ xml_setLocalName(JSContext *cx, unsigned
     NON_LIST_XML_METHOD_PROLOG;
     if (!JSXML_HAS_NAME(xml)) {
         vp[0] = JSVAL_VOID;
         return JS_TRUE;
     }
 
     JSAtom *namestr;
     if (argc == 0) {
-        namestr = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];
+        namestr = cx->runtime->atomState.undefinedAtom;
     } else {
         jsval name = vp[2];
         if (!JSVAL_IS_PRIMITIVE(name) && JSVAL_TO_OBJECT(name)->isQName()) {
             namestr = JSVAL_TO_OBJECT(name)->getQNameLocalName();
         } else {
             namestr = ToAtom(cx, name);
             if (!namestr)
                 return false;
@@ -6673,17 +6673,17 @@ xml_setName(JSContext *cx, unsigned argc
     uint32_t i, n;
     JSObject *ns;
 
     NON_LIST_XML_METHOD_PROLOG;
     if (!JSXML_HAS_NAME(xml))
         return JS_TRUE;
 
     if (argc == 0) {
-        name = STRING_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
+        name = STRING_TO_JSVAL(cx->runtime->atomState.undefinedAtom);
     } else {
         name = vp[2];
         if (!JSVAL_IS_PRIMITIVE(name) &&
             JSVAL_TO_OBJECT(name)->getClass() == &QNameClass &&
             !(nameqn = JSVAL_TO_OBJECT(name))->getNameURI()) {
             name = vp[2] = nameqn->getQNameLocalNameVal();
         }
     }
@@ -7334,18 +7334,19 @@ js_InitNamespaceClass(JSContext *cx, JSO
     JSObject *namespaceProto = global->createBlankPrototype(cx, &NamespaceClass);
     if (!namespaceProto)
         return NULL;
     JSFlatString *empty = cx->runtime->emptyString;
     namespaceProto->setNamePrefix(empty);
     namespaceProto->setNameURI(empty);
 
     const unsigned NAMESPACE_CTOR_LENGTH = 2;
-    RootedFunction ctor(cx, global->createConstructor(cx, Namespace, CLASS_NAME(cx, Namespace),
-                                                      NAMESPACE_CTOR_LENGTH));
+    RootedFunction ctor(cx);
+    ctor = global->createConstructor(cx, Namespace, cx->runtime->atomState.NamespaceAtom,
+                                     NAMESPACE_CTOR_LENGTH);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, namespaceProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, namespaceProto, namespace_props, namespace_methods))
         return NULL;
@@ -7367,17 +7368,17 @@ js_InitQNameClass(JSContext *cx, JSObjec
     RootedObject qnameProto(cx, global->createBlankPrototype(cx, &QNameClass));
     if (!qnameProto)
         return NULL;
     JSAtom *empty = cx->runtime->emptyString;
     if (!InitXMLQName(cx, qnameProto, empty, empty, empty))
         return NULL;
 
     const unsigned QNAME_CTOR_LENGTH = 2;
-    RootedFunction ctor(cx, global->createConstructor(cx, QName, CLASS_NAME(cx, QName),
+    RootedFunction ctor(cx, global->createConstructor(cx, QName, cx->runtime->atomState.QNameAtom,
                                                       QNAME_CTOR_LENGTH));
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, qnameProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, qnameProto, NULL, qname_methods))
@@ -7407,17 +7408,18 @@ js_InitXMLClass(JSContext *cx, JSObject 
 
     /* Don't count this as a real content-created XML object. */
     if (!cx->runningWithTrustedPrincipals()) {
         JS_ASSERT(sE4XObjectsCreated > 0);
         --sE4XObjectsCreated;
     }
 
     const unsigned XML_CTOR_LENGTH = 1;
-    RootedFunction ctor(cx, global->createConstructor(cx, XML, CLASS_NAME(cx, XML), XML_CTOR_LENGTH));
+    RootedFunction ctor(cx);
+    ctor = global->createConstructor(cx, XML, cx->runtime->atomState.XMLAtom, XML_CTOR_LENGTH);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, xmlProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, xmlProto, NULL, xml_methods) ||
         !DefinePropertiesAndBrand(cx, ctor, xml_static_props, xml_static_methods))
@@ -7463,17 +7465,17 @@ js_InitXMLClasses(JSContext *cx, JSObjec
 namespace js {
 
 bool
 GlobalObject::getFunctionNamespace(JSContext *cx, Value *vp)
 {
     Value v = getSlot(FUNCTION_NS);
     if (v.isUndefined()) {
         JSRuntime *rt = cx->runtime;
-        JSLinearString *prefix = rt->atomState.typeAtoms[JSTYPE_FUNCTION];
+        JSLinearString *prefix = rt->atomState.functionAtom;
         JSLinearString *uri = rt->atomState.functionNamespaceURIAtom;
         RootedObject obj(cx, NewXMLNamespace(cx, prefix, uri, JS_FALSE));
         if (!obj)
             return false;
 
         /*
          * Avoid entraining any in-scope Object.prototype.  The loss of
          * Namespace.prototype is not detectable, as there is no way to
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -6455,17 +6455,17 @@ mjit::Compiler::jsop_bindgname()
     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
 }
 
 bool
 mjit::Compiler::jsop_getgname(uint32_t index)
 {
     /* Optimize undefined, NaN and Infinity. */
     PropertyName *name = script->getName(index);
-    if (name == cx->runtime->atomState.typeAtoms[JSTYPE_VOID]) {
+    if (name == cx->runtime->atomState.undefinedAtom) {
         frame.push(UndefinedValue());
         return true;
     }
     if (name == cx->runtime->atomState.NaNAtom) {
         frame.push(cx->runtime->NaNValue);
         return true;
     }
     if (name == cx->runtime->atomState.InfinityAtom) {
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -687,32 +687,32 @@ mjit::Compiler::jsop_typeof()
     FrameEntry *fe = frame.peek(-1);
 
     if (fe->isTypeKnown()) {
         JSRuntime *rt = cx->runtime;
 
         JSAtom *atom = NULL;
         switch (fe->getKnownType()) {
           case JSVAL_TYPE_STRING:
-            atom = rt->atomState.typeAtoms[JSTYPE_STRING];
+            atom = rt->atomState.stringAtom;
             break;
           case JSVAL_TYPE_UNDEFINED:
-            atom = rt->atomState.typeAtoms[JSTYPE_VOID];
+            atom = rt->atomState.undefinedAtom;
             break;
           case JSVAL_TYPE_NULL:
-            atom = rt->atomState.typeAtoms[JSTYPE_OBJECT];
+            atom = rt->atomState.objectAtom;
             break;
           case JSVAL_TYPE_OBJECT:
             atom = NULL;
             break;
           case JSVAL_TYPE_BOOLEAN:
-            atom = rt->atomState.typeAtoms[JSTYPE_BOOLEAN];
+            atom = rt->atomState.booleanAtom;
             break;
           default:
-            atom = rt->atomState.typeAtoms[JSTYPE_NUMBER];
+            atom = rt->atomState.numberAtom;
             break;
         }
 
         if (atom) {
             frame.pop();
             frame.push(StringValue(atom));
             return;
         }
@@ -725,23 +725,23 @@ mjit::Compiler::jsop_typeof()
         if (op == JSOP_STRICTEQ || op == JSOP_EQ || op == JSOP_STRICTNE || op == JSOP_NE) {
             JSAtom *atom = script->getAtom(GET_UINT32_INDEX(PC + JSOP_TYPEOF_LENGTH));
             JSRuntime *rt = cx->runtime;
             JSValueType type = JSVAL_TYPE_UNKNOWN;
             Assembler::Condition cond = (op == JSOP_STRICTEQ || op == JSOP_EQ)
                                         ? Assembler::Equal
                                         : Assembler::NotEqual;
 
-            if (atom == rt->atomState.typeAtoms[JSTYPE_VOID]) {
+            if (atom == rt->atomState.undefinedAtom) {
                 type = JSVAL_TYPE_UNDEFINED;
-            } else if (atom == rt->atomState.typeAtoms[JSTYPE_STRING]) {
+            } else if (atom == rt->atomState.stringAtom) {
                 type = JSVAL_TYPE_STRING;
-            } else if (atom == rt->atomState.typeAtoms[JSTYPE_BOOLEAN]) {
+            } else if (atom == rt->atomState.booleanAtom) {
                 type = JSVAL_TYPE_BOOLEAN;
-            } else if (atom == rt->atomState.typeAtoms[JSTYPE_NUMBER]) {
+            } else if (atom == rt->atomState.numberAtom) {
                 type = JSVAL_TYPE_INT32;
 
                 /* JSVAL_TYPE_DOUBLE is 0x0 and JSVAL_TYPE_INT32 is 0x1, use <= or > to match both */
                 cond = (cond == Assembler::Equal) ? Assembler::BelowOrEqual : Assembler::Above;
             }
 
             jsbytecode *afterPC = PC + JSOP_STRING_LENGTH + JSOP_EQ_LENGTH;
 
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -1130,17 +1130,17 @@ stubs::EndIter(VMFrame &f)
         THROW();
 }
 
 JSString * JS_FASTCALL
 stubs::TypeOf(VMFrame &f)
 {
     const Value &ref = f.regs.sp[-1];
     JSType type = JS_TypeOfValue(f.cx, ref);
-    return f.cx->runtime->atomState.typeAtoms[type];
+    return TypeName(type, f.cx);
 }
 
 void JS_FASTCALL
 stubs::StrictEq(VMFrame &f)
 {
     const Value &rhs = f.regs.sp[-1];
     const Value &lhs = f.regs.sp[-2];
     bool equal;
new file mode 100644
--- /dev/null
+++ b/js/src/vm/CommonPropertyNames.h
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=4 sw=4 et tw=99 ft=cpp:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* A higher-order macro for enumerating all cached property names. */
+
+#ifndef CommonPropertyNames_h__
+#define CommonPropertyNames_h__
+
+#include "jsprototypes.h"
+#include "jsversion.h"
+
+#if JS_HAS_XML_SUPPORT
+#define FOR_EACH_XML_ONLY_NAME(macro) \
+    macro(etago, "</") \
+    macro(functionNamespaceURI, "@mozilla.org/js/function") \
+    macro(namespace, "namespace") \
+    macro(ptagc, "/>") \
+    macro(qualifier, "::") \
+    macro(space, " ") \
+    macro(stago, "<") \
+    macro(star, "*") \
+    macro(starQualifier, "*::") \
+    macro(tagc, ">") \
+    macro(XMLList, "XMLList")
+#else
+#define FOR_EACH_XML_ONLY_NAME(macro) /* nothing */
+#endif /* JS_HAS_XML_SUPPORT */
+
+#define FOR_EACH_COMMON_PROPERTYNAME(macro) \
+    macro(anonymous, "anonymous") \
+    macro(apply, "apply") \
+    macro(arguments, "arguments") \
+    macro(buffer, "buffer") \
+    macro(builder, "builder") \
+    macro(byteLength, "byteLength") \
+    macro(byteOffset, "byteOffset") \
+    macro(BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \
+    macro(call, "call") \
+    macro(callee, "callee") \
+    macro(caller, "caller") \
+    macro(_CallFunction, "_CallFunction") \
+    macro(classPrototype, "prototype") \
+    macro(columnNumber, "columnNumber") \
+    macro(configurable, "configurable") \
+    macro(construct, "construct") \
+    macro(constructor, "constructor") \
+    macro(decodeURI, "decodeURI") \
+    macro(decodeURIComponent, "decodeURIComponent") \
+    macro(defineProperty, "defineProperty") \
+    macro(defineGetter, "__defineGetter__") \
+    macro(defineSetter, "__defineSetter__") \
+    macro(delete, "delete") \
+    macro(deleteProperty, "deleteProperty") \
+    macro(each, "each") \
+    macro(empty, "") \
+    macro(encodeURI, "encodeURI") \
+    macro(encodeURIComponent, "encodeURIComponent") \
+    macro(enumerable, "enumerable") \
+    macro(enumerate, "enumerate") \
+    macro(escape, "escape") \
+    macro(eval, "eval") \
+    macro(false, "false") \
+    macro(fileName, "fileName") \
+    macro(fix, "fix") \
+    macro(get, "get") \
+    macro(getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \
+    macro(getOwnPropertyNames, "getOwnPropertyNames") \
+    macro(getPropertyDescriptor, "getPropertyDescriptor") \
+    macro(global, "global") \
+    macro(has, "has") \
+    macro(hasOwn, "hasOwn") \
+    macro(hasOwnProperty, "hasOwnProperty") \
+    macro(ignoreCase, "ignoreCase") \
+    macro(index, "index") \
+    macro(innermost, "innermost") \
+    macro(input, "input") \
+    macro(isFinite, "isFinite") \
+    macro(isNaN, "isNaN") \
+    macro(isPrototypeOf, "isPrototypeOf") \
+    macro(isXMLName, "isXMLName") \
+    macro(iterate, "iterate") \
+    macro(Infinity, "Infinity") \
+    macro(iterator, "iterator") \
+    macro(iteratorIntrinsic, "__iterator__") \
+    macro(join, "join") \
+    macro(keys, "keys") \
+    macro(lastIndex, "lastIndex") \
+    macro(length, "length") \
+    macro(line, "line") \
+    macro(lineNumber, "lineNumber") \
+    macro(loc, "loc") \
+    macro(lookupGetter, "__lookupGetter__") \
+    macro(lookupSetter, "__lookupSetter__") \
+    macro(message, "message") \
+    macro(multiline, "multiline") \
+    macro(name, "name") \
+    macro(NaN, "NaN") \
+    macro(next, "next") \
+    macro(noSuchMethod, "__noSuchMethod__") \
+    macro(objectNull, "[object Null]") \
+    macro(objectUndefined, "[object Undefined]") \
+    macro(of, "of") \
+    macro(parseFloat, "parseFloat") \
+    macro(parseInt, "parseInt") \
+    macro(propertyIsEnumerable, "propertyIsEnumerable") \
+    macro(proto, "__proto__") \
+    macro(return, "return") \
+    macro(set, "set") \
+    macro(shape, "shape") \
+    macro(source, "source") \
+    macro(stack, "stack") \
+    macro(sticky, "sticky") \
+    macro(test, "test") \
+    macro(throw, "throw") \
+    macro(toGMTString, "toGMTString") \
+    macro(toISOString, "toISOString") \
+    macro(toJSON, "toJSON") \
+    macro(toLocaleString, "toLocaleString") \
+    macro(toSource, "toSource") \
+    macro(toString, "toString") \
+    macro(toUTCString, "toUTCString") \
+    macro(true, "true") \
+    macro(unescape, "unescape") \
+    macro(uneval, "uneval") \
+    macro(unwatch, "unwatch") \
+    macro(url, "url") \
+    macro(useStrict, "use strict") \
+    macro(value, "value") \
+    macro(valueOf, "valueOf") \
+    macro(var, "var") \
+    macro(void0, "(void 0)") \
+    macro(watch, "watch") \
+    macro(writable, "writable") \
+    /* Type names must be contiguous and ordered; see js::TypeName. */ \
+    macro(undefined, "undefined") \
+    macro(object, "object") \
+    macro(function, "function") \
+    macro(string, "string") \
+    macro(number, "number") \
+    macro(boolean, "boolean") \
+    macro(null, "null") \
+    macro(xml, "xml") \
+    FOR_EACH_XML_ONLY_NAME(macro)
+
+#endif /* CommonPropertyNames_h__ */
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -343,17 +343,17 @@ GlobalObject::initFunctionAndObjectClass
 
     /* Create the Object function now that we have a [[Prototype]] for it. */
     RootedFunction objectCtor(cx);
     {
         JSObject *ctor = NewObjectWithGivenProto(cx, &FunctionClass, functionProto, self);
         if (!ctor)
             return NULL;
         objectCtor = js_NewFunction(cx, ctor, js_Object, 1, JSFUN_CONSTRUCTOR, self,
-                                    CLASS_NAME(cx, Object));
+                                    cx->runtime->atomState.ObjectAtom);
         if (!objectCtor)
             return NULL;
     }
 
     /*
      * Install |Object| and |Object.prototype| for the benefit of subsequent
      * code that looks for them.
      */
@@ -362,17 +362,17 @@ GlobalObject::initFunctionAndObjectClass
     /* Create |Function| so it and |Function.prototype| can be installed. */
     RootedFunction functionCtor(cx);
     {
         // Note that ctor is rooted purely for the JS_ASSERT at the end
         RootedObject ctor(cx, NewObjectWithGivenProto(cx, &FunctionClass, functionProto, self));
         if (!ctor)
             return NULL;
         functionCtor = js_NewFunction(cx, ctor, Function, 1, JSFUN_CONSTRUCTOR, self,
-                                      CLASS_NAME(cx, Function));
+                                      cx->runtime->atomState.FunctionAtom);
         if (!functionCtor)
             return NULL;
         JS_ASSERT(ctor == functionCtor);
     }
 
     /*
      * Install |Function| and |Function.prototype| so that we can freely create
      * functions and objects without special effort.
@@ -419,20 +419,20 @@ GlobalObject::initFunctionAndObjectClass
         !LinkConstructorAndPrototype(cx, functionCtor, functionProto) ||
         !DefinePropertiesAndBrand(cx, functionProto, NULL, function_methods) ||
         !DefinePropertiesAndBrand(cx, functionCtor, NULL, NULL))
     {
         return NULL;
     }
 
     /* Add the global Function and Object properties now. */
-    jsid objectId = NameToId(CLASS_NAME(cx, Object));
+    jsid objectId = NameToId(cx->runtime->atomState.ObjectAtom);
     if (!self->addDataProperty(cx, objectId, JSProto_Object + JSProto_LIMIT * 2, 0))
         return NULL;
-    jsid functionId = NameToId(CLASS_NAME(cx, Function));
+    jsid functionId = NameToId(cx->runtime->atomState.FunctionAtom);
     if (!self->addDataProperty(cx, functionId, JSProto_Function + JSProto_LIMIT * 2, 0))
         return NULL;
 
     /* Heavy lifting done, but lingering tasks remain. */
 
     /* ES5 15.1.2.1. */
     RootedId id(cx, NameToId(cx->runtime->atomState.evalAtom));
     JSObject *evalobj = js_DefineFunction(cx, self, id, IndirectEval, 1, JSFUN_STUB_GSOPS);
@@ -503,17 +503,17 @@ GlobalObject::create(JSContext *cx, Clas
 
 /* static */ bool
 GlobalObject::initStandardClasses(JSContext *cx, Handle<GlobalObject*> global)
 {
     JSAtomState &state = cx->runtime->atomState;
 
     /* Define a top-level property 'undefined' with the undefined value. */
     RootedValue undefinedValue(cx, UndefinedValue());
-    if (!JSObject::defineProperty(cx, global, state.typeAtoms[JSTYPE_VOID], undefinedValue,
+    if (!JSObject::defineProperty(cx, global, state.undefinedAtom, undefinedValue,
                                   JS_PropertyStub, JS_StrictPropertyStub, JSPROP_PERMANENT | JSPROP_READONLY))
     {
         return false;
     }
 
     if (!global->initFunctionAndObjectClasses(cx))
         return false;
 
--- a/js/src/vm/StringBuffer.cpp
+++ b/js/src/vm/StringBuffer.cpp
@@ -91,10 +91,10 @@ js::ValueToStringBufferSlow(JSContext *c
         return sb.append(v.toString());
     if (v.isNumber())
         return NumberValueToStringBuffer(cx, v, sb);
     if (v.isBoolean())
         return BooleanToStringBuffer(cx, v.toBoolean(), sb);
     if (v.isNull())
         return sb.append(cx->runtime->atomState.nullAtom);
     JS_ASSERT(v.isUndefined());
-    return sb.append(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
+    return sb.append(cx->runtime->atomState.undefinedAtom);
 }