Backout bug 684110 (08b6eaf6aad0, cf8b35fa1010, 25ee45edabe1, 659f5c7d2cc9, 870f6dd82586 & e1ad65d6a7fd) and bug 684344 (cd1957f6628d) on a CLOSED TREE; a=bustage-fairies
authorEd Morley <bmo@edmorley.co.uk>
Sat, 03 Sep 2011 03:21:25 +0100
changeset 76505 38a81587cccef98bb32e4d6c40a6c4b5964eb64d
parent 76504 cd1957f6628df6914117a1771dc432e35e879454
child 76506 ecdad0ca5b0092e6206fc424404d693982715744
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersbustage-fairies
bugs684110, 684344
milestone9.0a1
Backout bug 684110 (08b6eaf6aad0, cf8b35fa1010, 25ee45edabe1, 659f5c7d2cc9, 870f6dd82586 & e1ad65d6a7fd) and bug 684344 (cd1957f6628d) on a CLOSED TREE; a=bustage-fairies
caps/src/nsScriptSecurityManager.cpp
js/src/jsapi-tests/testConservativeGC.cpp
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsbool.cpp
js/src/jsbool.h
js/src/jsbuiltins.cpp
js/src/jsbuiltins.h
js/src/jsclone.cpp
js/src/jscntxtinlines.h
js/src/jscompartment.cpp
js/src/jsdate.cpp
js/src/jsdate.h
js/src/jsemit.cpp
js/src/jsexn.cpp
js/src/jsexn.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsgcmark.cpp
js/src/jsinfer.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsiter.h
js/src/jsmath.cpp
js/src/jsmath.h
js/src/jsnum.cpp
js/src/jsnum.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/json.h
js/src/jsonparser.cpp
js/src/jsopcode.cpp
js/src/jsprobes.h
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jsreflect.cpp
js/src/jsregexp.cpp
js/src/jsregexp.h
js/src/jsregexpinlines.h
js/src/jsscopeinlines.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsstr.cpp
js/src/jsstr.h
js/src/jstracer.cpp
js/src/jstypedarray.cpp
js/src/jsweakmap.cpp
js/src/jsweakmap.h
js/src/jswrapper.cpp
js/src/jsxml.cpp
js/src/jsxml.h
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/shell/jsheaptools.cpp
js/src/tracejit/Writer.h
js/src/vm/ArgumentsObject.h
js/src/vm/Debugger.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/StringObject-inl.h
js/src/xpconnect/src/nsXPConnect.cpp
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2418,25 +2418,25 @@ nsScriptSecurityManager::doGetObjectPrin
 
     // A common case seen in this code is that we enter this function
     // with aObj being a Function object, whose parent is a Call
     // object. Neither of those have object principals, so we can skip
     // those objects here before we enter the below loop. That way we
     // avoid wasting time checking properties of their classes etc in
     // the loop.
 
-    if (jsClass == &js::FunctionClass) {
+    if (jsClass == &js_FunctionClass) {
         aObj = aObj->getParent();
 
         if (!aObj)
             return nsnull;
 
         jsClass = aObj->getClass();
 
-        if (jsClass == &js::CallClass) {
+        if (jsClass == &js_CallClass) {
             aObj = aObj->getParent();
 
             if (!aObj)
                 return nsnull;
 
             jsClass = aObj->getClass();
         }
     }
--- a/js/src/jsapi-tests/testConservativeGC.cpp
+++ b/js/src/jsapi-tests/testConservativeGC.cpp
@@ -44,17 +44,17 @@ BEGIN_TEST(testConservativeGC)
 
     return true;
 }
 
 bool checkObjectFields(JSObject *savedCopy, JSObject *obj)
 {
     /* Ignore fields which are unstable across GCs. */
     CHECK(savedCopy->lastProp == obj->lastProp);
-    CHECK(savedCopy->getClass() == obj->getClass());
+    CHECK(savedCopy->clasp == obj->clasp);
     CHECK(savedCopy->flags == obj->flags);
     CHECK(savedCopy->newType == obj->newType);
     CHECK(savedCopy->getProto() == obj->getProto());
     CHECK(savedCopy->parent == obj->parent);
     CHECK(savedCopy->privateData == obj->privateData);
     return true;
 }
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1538,17 +1538,17 @@ JS_InitStandardClasses(JSContext *cx, JS
     if (!cx->globalObject)
         JS_SetGlobalObject(cx, obj);
 
     assertSameCompartment(cx, obj);
 
     return obj->asGlobal()->initStandardClasses(cx);
 }
 
-#define CLASP(name)                 (&name##Class)
+#define CLASP(name)                 (&js_##name##Class)
 #define TYPED_ARRAY_CLASP(type)     (&TypedArray::fastClasses[TypedArray::type])
 #define EAGER_ATOM(name)            ATOM_OFFSET(name), NULL
 #define EAGER_CLASS_ATOM(name)      CLASS_ATOM_OFFSET(name), NULL
 #define EAGER_ATOM_AND_CLASP(name)  EAGER_CLASS_ATOM(name), CLASP(name)
 #define LAZY_ATOM(name)             ATOM_OFFSET(lazy.name), js_##name##_str
 
 typedef struct JSStdName {
     JSObjectOp  init;
@@ -1648,17 +1648,17 @@ static JSStdName standard_class_names[] 
 #endif
 
 #if JS_HAS_GENERATORS
     {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Iterator)},
     {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Generator)},
 #endif
 
     /* Typed Arrays */
-    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(ArrayBuffer),  &ArrayBufferClass},
+    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(ArrayBuffer), &js_ArrayBufferClass},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int8Array),    TYPED_ARRAY_CLASP(TYPE_INT8)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8Array),   TYPED_ARRAY_CLASP(TYPE_UINT8)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int16Array),   TYPED_ARRAY_CLASP(TYPE_INT16)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint16Array),  TYPED_ARRAY_CLASP(TYPE_UINT16)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int32Array),   TYPED_ARRAY_CLASP(TYPE_INT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint32Array),  TYPED_ARRAY_CLASP(TYPE_UINT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
@@ -2270,17 +2270,17 @@ JS_PrintTraceThingInfo(char *buf, size_t
         *buf++ = ' ';
         bufsize--;
 
         switch (kind) {
           case JSTRACE_OBJECT:
           {
             JSObject  *obj = (JSObject *)thing;
             Class *clasp = obj->getClass();
-            if (clasp == &FunctionClass) {
+            if (clasp == &js_FunctionClass) {
                 JSFunction *fun = obj->getFunctionPrivate();
                 if (!fun) {
                     JS_snprintf(buf, bufsize, "<newborn>");
                 } else if (fun != obj) {
                     JS_snprintf(buf, bufsize, "%p", fun);
                 } else {
                     if (fun->atom)
                         PutEscapedString(buf, bufsize, fun->atom, 0);
@@ -3059,19 +3059,19 @@ JS_PUBLIC_API(JSObject *)
 JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
-        clasp = &ObjectClass;    /* default class is Object */
-
-    JS_ASSERT(clasp != &FunctionClass);
+        clasp = &js_ObjectClass;    /* default class is Object */
+
+    JS_ASSERT(clasp != &js_FunctionClass);
     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
     if (proto)
         proto->getNewType(cx, NULL, /* markUnknown = */ true);
 
     JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
     if (obj) {
         if (clasp->ext.equality)
@@ -3088,19 +3088,19 @@ JS_PUBLIC_API(JSObject *)
 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
-        clasp = &ObjectClass;    /* default class is Object */
-
-    JS_ASSERT(clasp != &FunctionClass);
+        clasp = &js_ObjectClass;    /* default class is Object */
+
+    JS_ASSERT(clasp != &js_FunctionClass);
     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
     JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
     if (obj) {
         obj->syncSpecialEquality();
         MarkTypeObjectUnknownProperties(cx, obj->type());
     }
     return obj;
@@ -3163,29 +3163,29 @@ JS_DeepFreezeObject(JSContext *cx, JSObj
 
 JS_PUBLIC_API(JSObject *)
 JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent);
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
-        clasp = &ObjectClass;    /* default class is Object */
+        clasp = &js_ObjectClass;    /* default class is Object */
     return js_ConstructObject(cx, clasp, proto, parent, 0, NULL);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto,
                                 JSObject *parent, uintN argc, jsval *argv)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc));
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
-        clasp = &ObjectClass;    /* default class is Object */
+        clasp = &js_ObjectClass;    /* default class is Object */
     return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv));
 }
 
 static JSBool
 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
                    JSObject **objp, JSProperty **propp)
 {
     CHECK_REQUEST(cx);
@@ -3515,17 +3515,17 @@ JS_PUBLIC_API(JSObject *)
 JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp,
                 JSObject *proto, uintN attrs)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, proto);
 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
-        clasp = &ObjectClass;    /* default class is Object */
+        clasp = &js_ObjectClass;    /* default class is Object */
 
     JSObject *nobj = NewObject<WithProto::Class>(cx, clasp, proto, obj);
     if (!nobj)
         return NULL;
 
     nobj->syncSpecialEquality();
 
     if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
@@ -4210,17 +4210,17 @@ JS_CloneFunctionObject(JSContext *cx, JS
     if (!parent) {
         if (cx->hasfp())
             parent = GetScopeChain(cx, cx->fp());
         if (!parent)
             parent = cx->globalObject;
         JS_ASSERT(parent);
     }
 
-    if (!funobj->isFunction()) {
+    if (funobj->getClass() != &js_FunctionClass) {
         /*
          * We cannot clone this object, so fail (we used to return funobj, bad
          * idea, but we changed incompatibly to teach any abusers a lesson!).
          */
         Value v = ObjectValue(*funobj);
         js_ReportIsNotFunction(cx, &v, 0);
         return NULL;
     }
@@ -4301,17 +4301,17 @@ JS_PUBLIC_API(uint16)
 JS_GetFunctionArity(JSFunction *fun)
 {
     return fun->nargs;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ObjectIsFunction(JSContext *cx, JSObject *obj)
 {
-    return obj->isFunction();
+    return obj->getClass() == &js_FunctionClass;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ObjectIsCallable(JSContext *cx, JSObject *obj)
 {
     return obj->isCallable();
 }
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -39,17 +39,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JS array class.
  *
  * Array objects begin as "dense" arrays, optimized for index-only property
  * access over a vector of slots with high load factor.  Array methods
  * optimize for denseness by testing that the object's class is
- * &ArrayClass, and can then directly manipulate the slots for efficiency.
+ * &js_ArrayClass, and can then directly manipulate the slots for efficiency.
  *
  * We track these pieces of metadata for arrays in dense mode:
  *  - The array's length property as a uint32, accessible with
  *    getArrayLength(), setArrayLength().
  *  - The number of element slots (capacity), gettable with
  *    getDenseArrayCapacity().
  *  - The array's initialized length, accessible with
  *    getDenseArrayInitializedLength().
@@ -76,29 +76,29 @@
  * initialized length must hold, e.g. if an array has length 5, capacity 10,
  * completely empty, it is valid for the initialized length to be any value
  * between zero and 5, as long as the in memory values below the initialized
  * length have been initialized with a hole value. However, in such cases we
  * want to keep the initialized length as small as possible: if the array is
  * known to have no hole values below its initialized length, then it is a
  * "packed" array and can be accessed much faster by JIT code.
  *
- * Arrays are converted to use SlowArrayClass when any of these conditions
+ * Arrays are converted to use js_SlowArrayClass when any of these conditions
  * are met:
  *  - there are more than MIN_SPARSE_INDEX slots total and the load factor
  *    (COUNT / capacity) is less than 0.25
  *  - a property is set that is not indexed (and not "length")
  *  - a property is defined that has non-default property attributes.
  *
  * Dense arrays do not track property creation order, so unlike other native
  * objects and slow arrays, enumerating an array does not necessarily visit the
  * properties in the order they were created.  We could instead maintain the
  * scope to track property enumeration order, but still use the fast slot
  * access.  That would have the same memory cost as just using a
- * SlowArrayClass, but have the same performance characteristics as a dense
+ * js_SlowArrayClass, but have the same performance characteristics as a dense
  * array for slot accesses, at some cost in code complexity.
  */
 #include <stdlib.h>
 #include <string.h>
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsutil.h"
 
@@ -141,16 +141,23 @@
 
 #include "vm/ArgumentsObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
+static inline bool
+ENSURE_SLOW_ARRAY(JSContext *cx, JSObject *obj)
+{
+    return obj->getClass() == &js_SlowArrayClass ||
+           obj->makeDenseArraySlow(cx);
+}
+
 JSBool
 js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
 {
     if (obj->isArray()) {
         *lengthp = obj->getArrayLength();
         return true;
     }
 
@@ -234,36 +241,42 @@ StringIsArrayIndex(JSLinearString *str, 
 }
 
 }
 
 static JSBool
 BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom,
              jsid *idp)
 {
+    jschar buf[10], *start;
+    Class *clasp;
+    JSAtom *atom;
     JS_STATIC_ASSERT((jsuint)-1 == 4294967295U);
+
     JS_ASSERT(index > JSID_INT_MAX);
 
-    jschar buf[10];
-    jschar *start = JS_ARRAY_END(buf);
+    start = JS_ARRAY_END(buf);
     do {
         --start;
         *start = (jschar)('0' + index % 10);
         index /= 10;
     } while (index != 0);
 
     /*
      * Skip the atomization if the class is known to store atoms corresponding
      * to big indexes together with elements. In such case we know that the
      * array does not have an element at the given index if its atom does not
-     * exist.  Dense arrays don't use atoms for any indexes, though it would be
-     * rare to see them have a big index in any case.
+     * exist.  Fast arrays (clasp == &js_ArrayClass) don't use atoms for
+     * any indexes, though it would be rare to see them have a big index
+     * in any case.
      */
-    JSAtom *atom;
-    if (!createAtom && (obj->isSlowArray() || obj->isArguments() || obj->isObject())) {
+    if (!createAtom &&
+        ((clasp = obj->getClass()) == &js_SlowArrayClass ||
+         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);
         if (!atom)
@@ -483,23 +496,23 @@ SetArrayElement(JSContext *cx, JSObject 
     return obj->setProperty(cx, idr.id(), &tmp, true);
 }
 
 #ifdef JS_TRACER
 JSBool JS_FASTCALL
 js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i)
 {
 #ifdef DEBUG
-    Class *origObjClasp = obj->getClass();
+    Class *origObjClasp = obj->clasp;
 #endif
     jsuint u = jsuint(i);
     JSBool ret = (obj->ensureDenseArrayElements(cx, u, 1) == JSObject::ED_OK);
 
     /* Partially check the CallInfo's storeAccSet is correct. */
-    JS_ASSERT(obj->getClass() == origObjClasp);
+    JS_ASSERT(obj->clasp == origObjClasp);
     return ret;
 }
 /* This function and its callees do not touch any object's .clasp field. */
 JS_DEFINE_CALLINFO_3(extern, BOOL, js_EnsureDenseArrayCapacity, CONTEXT, OBJECT, INT32,
                      0, nanojit::ACCSET_STORE_ANY & ~tjit::ACCSET_OBJ_CLASP)
 #endif
 
 /*
@@ -971,17 +984,17 @@ array_fix(JSContext *cx, JSObject *obj, 
     if (!obj->makeDenseArraySlow(cx) ||
         !GetPropertyNames(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, props))
         return false;
 
     *success = true;
     return true;
 }
 
-Class js::ArrayClass = {
+Class js_ArrayClass = {
     "Array",
     Class::NON_NATIVE | JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
@@ -1006,17 +1019,17 @@ Class js::ArrayClass = {
         NULL,       /* enumerate      */
         array_typeOf,
         array_fix,
         NULL,       /* thisObject     */
         NULL,       /* clear          */
     }
 };
 
-Class js::SlowArrayClass = {
+Class js_SlowArrayClass = {
     "Array",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
     slowarray_addProperty,
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -1051,17 +1064,17 @@ JSObject::makeDenseArraySlow(JSContext *
      * Save old map now, before calling InitScopeForObject. We'll have to undo
      * on error. This is gross, but a better way is not obvious. Note: the
      * exact contents of the array are not preserved on error.
      */
     js::Shape *oldMap = lastProp;
 
     /* Create a native scope. */
     gc::AllocKind kind = getAllocKind();
-    if (!InitScopeForObject(cx, this, &SlowArrayClass, getProto()->getNewType(cx), kind))
+    if (!InitScopeForObject(cx, this, &js_SlowArrayClass, getProto()->getNewType(cx), kind))
         return false;
 
     backfillDenseArrayHoles(cx);
 
     uint32 arrayCapacity = getDenseArrayCapacity();
     uint32 arrayInitialized = getDenseArrayInitializedLength();
 
     /*
@@ -1072,17 +1085,17 @@ JSObject::makeDenseArraySlow(JSContext *
     if (denseArrayHasInlineSlots()) {
         if (!allocSlots(cx, numSlots())) {
             setMap(oldMap);
             return false;
         }
         JS_ASSERT(!denseArrayHasInlineSlots());
     }
     capacity = numFixedSlots() + arrayCapacity;
-    clasp = &SlowArrayClass;
+    clasp = &js_SlowArrayClass;
 
     /*
      * Root all values in the array during conversion, as SlowArrayClass only
      * protects up to its slot span.
      */
     AutoValueArray autoArray(cx, slots, arrayInitialized);
 
     /* The initialized length is used iff this is a dense array. */
@@ -1092,17 +1105,17 @@ JSObject::makeDenseArraySlow(JSContext *
     /*
      * Begin with the length property to share more of the property tree.
      * The getter/setter here will directly access the object's private value.
      */
     if (!AddLengthProperty(cx, this)) {
         setMap(oldMap);
         capacity = arrayCapacity;
         initializedLength = arrayInitialized;
-        clasp = &ArrayClass;
+        clasp = &js_ArrayClass;
         return false;
     }
 
     /*
      * Create new properties pointing to existing elements. Pack the array to
      * remove holes, so that shapes use successive slots (as for other objects).
      */
     uint32 next = 0;
@@ -1115,28 +1128,28 @@ JSObject::makeDenseArraySlow(JSContext *
             continue;
 
         setSlot(next, slots[i]);
 
         if (!addDataProperty(cx, id, next, JSPROP_ENUMERATE)) {
             setMap(oldMap);
             capacity = arrayCapacity;
             initializedLength = arrayInitialized;
-            clasp = &ArrayClass;
+            clasp = &js_ArrayClass;
             return false;
         }
 
         next++;
     }
 
     clearSlotRange(next, capacity - next);
 
     /*
      * Finally, update class. If |this| is Array.prototype, then js_InitClass
-     * will create an emptyShape whose class is &SlowArrayClass, to ensure
+     * will create an emptyShape whose class is &js_SlowArrayClass, to ensure
      * that delegating instances can share shapes in the tree rooted at the
      * proto's empty shape.
      */
     return true;
 }
 
 #if JS_HAS_TOSOURCE
 class ArraySharpDetector
@@ -1193,17 +1206,17 @@ static JSBool
 array_toSource(JSContext *cx, uintN argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
     if (!obj->isArray()) {
-        ReportIncompatibleMethod(cx, vp, &ArrayClass);
+        ReportIncompatibleMethod(cx, vp, &js_ArrayClass);
         return false;
     }
 
     ArraySharpDetector detector(cx);
     if (!detector.init(obj))
         return false;
 
     StringBuffer sb(cx);
@@ -1522,17 +1535,17 @@ InitArrayElements(JSContext *cx, JSObjec
             return JS_FALSE;
         }
     }
 
     if (vector == end)
         return JS_TRUE;
 
     /* Finish out any remaining elements past the max array index. */
-    if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx))
+    if (obj->isDenseArray() && !ENSURE_SLOW_ARRAY(cx, obj))
         return JS_FALSE;
 
     JS_ASSERT(start == MAX_ARRAY_INDEX + 1);
     AutoValueRooter tvr(cx);
     AutoIdRooter idr(cx);
     Value idval = DoubleValue(MAX_ARRAY_INDEX + 1);
     do {
         *tvr.addr() = *vector++;
@@ -3199,22 +3212,22 @@ js_Array(JSContext *cx, uintN argc, Valu
 
 JSObject *
 js_InitArrayClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     GlobalObject *global = obj->asGlobal();
 
-    JSObject *arrayProto = global->createBlankPrototype(cx, &SlowArrayClass);
+    JSObject *arrayProto = global->createBlankPrototype(cx, &js_SlowArrayClass);
     if (!arrayProto || !AddLengthProperty(cx, arrayProto))
         return NULL;
     arrayProto->setArrayLength(cx, 0);
 
-    JSFunction *ctor = global->createConstructor(cx, js_Array, &ArrayClass,
+    JSFunction *ctor = global->createConstructor(cx, js_Array, &js_ArrayClass,
                                                  CLASS_ATOM(cx, Array), 1);
     if (!ctor)
         return NULL;
 
     /* The default 'new' object for Array.prototype has unknown properties. */
     arrayProto->getNewType(cx, NULL, /* markUnknown = */ true);
 
     if (!LinkConstructorAndPrototype(cx, ctor, arrayProto))
@@ -3239,17 +3252,17 @@ namespace js {
 
 template<bool allocateCapacity>
 static JS_ALWAYS_INLINE JSObject *
 NewArray(JSContext *cx, jsuint length, JSObject *proto)
 {
     JS_ASSERT_IF(proto, proto->isArray());
 
     gc::AllocKind kind = GuessObjectGCKind(length, true);
-    JSObject *obj = detail::NewObject<WithProto::Class, false>(cx, &ArrayClass, proto, NULL, kind);
+    JSObject *obj = detail::NewObject<WithProto::Class, false>(cx, &js_ArrayClass, proto, NULL, kind);
     if (!obj)
         return NULL;
 
     obj->setArrayLength(cx, length);
 
     if (!cx->typeInferenceEnabled()) {
         obj->markDenseArrayNotPacked(cx);
         obj->backfillDenseArrayHoles(cx);
@@ -3328,17 +3341,17 @@ JS_DEFINE_CALLINFO_3(extern, OBJECT, New
                      nanojit::ACCSET_STORE_ANY)
 #endif
 
 
 
 JSObject *
 NewSlowEmptyArray(JSContext *cx)
 {
-    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &SlowArrayClass, NULL, NULL);
+    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_SlowArrayClass, NULL, NULL);
     if (!obj || !AddLengthProperty(cx, obj))
         return NULL;
 
     obj->setArrayLength(cx, 0);
     return obj;
 }
 
 }
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -58,17 +58,17 @@
 #include "jsinferinlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
 using namespace js;
 using namespace js::types;
 
-Class js::BooleanClass = {
+Class js_BooleanClass = {
     "Boolean",
     JSCLASS_HAS_RESERVED_SLOTS(1) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -133,31 +133,31 @@ static JSFunctionSpec boolean_methods[] 
 
 static JSBool
 Boolean(JSContext *cx, uintN argc, Value *vp)
 {
     Value *argv = vp + 2;
     bool b = argc != 0 ? js_ValueToBoolean(argv[0]) : false;
 
     if (IsConstructing(vp)) {
-        JSObject *obj = NewBuiltinClassInstance(cx, &BooleanClass);
+        JSObject *obj = NewBuiltinClassInstance(cx, &js_BooleanClass);
         if (!obj)
             return false;
         obj->setPrimitiveThis(BooleanValue(b));
         vp->setObject(*obj);
     } else {
         vp->setBoolean(b);
     }
     return true;
 }
 
 JSObject *
 js_InitBooleanClass(JSContext *cx, JSObject *obj)
 {
-    JSObject *proto = js_InitClass(cx, obj, NULL, &BooleanClass, Boolean, 1,
+    JSObject *proto = js_InitClass(cx, obj, NULL, &js_BooleanClass, Boolean, 1,
                                    NULL, boolean_methods, NULL, NULL);
     if (!proto)
         return NULL;
     proto->setPrimitiveThis(BooleanValue(false));
     return proto;
 }
 
 JSString *
--- a/js/src/jsbool.h
+++ b/js/src/jsbool.h
@@ -41,16 +41,24 @@
 #define jsbool_h___
 /*
  * JS boolean interface.
  */
 
 #include "jsapi.h"
 #include "jsobj.h"
 
+extern js::Class js_BooleanClass;
+
+inline bool
+JSObject::isBoolean() const
+{
+    return getClass() == &js_BooleanClass;
+}
+
 extern JSObject *
 js_InitBooleanClass(JSContext *cx, JSObject *obj);
 
 extern JSString *
 js_BooleanToString(JSContext *cx, JSBool b);
 
 namespace js {
 
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -246,17 +246,17 @@ JS_DEFINE_CALLINFO_3(extern, BOOL, js_Ad
 static JSBool
 HasProperty(JSContext* cx, JSObject* obj, jsid id)
 {
     // Check that we know how the lookup op will behave.
     for (JSObject* pobj = obj; pobj; pobj = pobj->getProto()) {
         if (pobj->getOps()->lookupProperty)
             return JS_NEITHER;
         Class* clasp = pobj->getClass();
-        if (clasp->resolve != JS_ResolveStub && clasp != &StringClass)
+        if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass)
             return JS_NEITHER;
     }
 
     JSObject* obj2;
     JSProperty* prop;
     if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
         return JS_NEITHER;
     return prop != NULL;
@@ -315,17 +315,17 @@ js_NewNullClosure(JSContext* cx, JSObjec
     types::TypeObject *type = proto->getNewType(cx);
     if (!type)
         return NULL;
 
     JSObject* closure = js_NewGCObject(cx, gc::FINALIZE_OBJECT2);
     if (!closure)
         return NULL;
 
-    if (!closure->initSharingEmptyShape(cx, &FunctionClass, type, parent,
+    if (!closure->initSharingEmptyShape(cx, &js_FunctionClass, type, parent,
                                         fun, gc::FINALIZE_OBJECT2)) {
         return NULL;
     }
     return closure;
 }
 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT,
                      0, ACCSET_STORE_ANY)
 
--- a/js/src/jsbuiltins.h
+++ b/js/src/jsbuiltins.h
@@ -79,18 +79,18 @@ enum {
  * reverse order (so TC means JSContext* as the first arg, and the
  * JSObject* for |this| as the second arg).
  *
  * |argtypes| can contain the following characters:
  * 'd': a number (double) argument
  * 'i': an integer argument
  * 's': a JSString* argument
  * 'o': a JSObject* argument
- * 'r': a JSObject* argument that is of class RegExpClass
- * 'f': a JSObject* argument that is of class FunctionClass
+ * 'r': a JSObject* argument that is of class js_RegExpClass
+ * 'f': a JSObject* argument that is of class js_FunctionClass
  * 'v': a value argument: on 32-bit, a Value*, on 64-bit, a jsval
  */
 struct JSSpecializedNative {
     const nanojit::CallInfo *builtin;
     const char              *prefix;
     const char              *argtypes;
     uintN                   flags;  /* JSTNErrType | JSTN_UNBOX_AFTER | JSTN_MORE |
                                        JSTN_CONSTRUCTOR */
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -777,17 +777,17 @@ JSStructuredCloneReader::startRead(Value
         vp->setObject(*obj);
         break;
       }
 
       case SCTAG_ARRAY_OBJECT:
       case SCTAG_OBJECT_OBJECT: {
         JSObject *obj = (tag == SCTAG_ARRAY_OBJECT)
                         ? NewDenseEmptyArray(context())
-                        : NewBuiltinClassInstance(context(), &ObjectClass);
+                        : NewBuiltinClassInstance(context(), &js_ObjectClass);
         if (!obj || !objs.append(ObjectValue(*obj)) ||
             !allObjs.append(ObjectValue(*obj)))
             return false;
         vp->setObject(*obj);
         break;
       }
 
       case SCTAG_BACK_REFERENCE_OBJECT: {
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -329,20 +329,22 @@ CallJSNativeConstructor(JSContext *cx, j
      * Proxies are exceptions to both rules: they can return primitives and
      * they allow content to return the callee.
      *
      * CallOrConstructBoundFunction is an exception as well because we
      * might have used bind on a proxy function.
      *
      * (new Object(Object)) returns the callee.
      */
-    JS_ASSERT_IF(native != FunctionProxyClass.construct &&
-                 native != CallableObjectClass.construct &&
+    extern JSBool proxy_Construct(JSContext *, uintN, Value *);
+    extern JSBool callable_Construct(JSContext *, uintN, Value *);
+    JS_ASSERT_IF(native != proxy_Construct &&
+                 native != callable_Construct &&
                  native != js::CallOrConstructBoundFunction &&
-                 (!callee.isFunction() || callee.getFunctionPrivate()->u.n.clasp != &ObjectClass),
+                 (!callee.isFunction() || callee.getFunctionPrivate()->u.n.clasp != &js_ObjectClass),
                  !args.rval().isPrimitive() && callee != args.rval().toObject());
 
     return true;
 }
 
 JS_ALWAYS_INLINE bool
 CallJSPropertyOp(JSContext *cx, js::PropertyOp op, JSObject *receiver, jsid id, js::Value *vp)
 {
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -242,17 +242,17 @@ JSCompartment::wrap(JSContext *cx, Value
     if (vp->isObject()) {
         JSObject *obj = &vp->toObject();
 
         /* If the object is already in this compartment, we are done. */
         if (obj->compartment() == this)
             return true;
 
         /* Translate StopIteration singleton. */
-        if (obj->isStopIteration())
+        if (obj->getClass() == &js_StopIterationClass)
             return js_FindClassObject(cx, NULL, JSProto_StopIteration, vp);
 
         /* Don't unwrap an outer window proxy. */
         if (!obj->getClass()->ext.innerObject) {
             obj = vp->toObject().unwrap(&flags);
             vp->setObject(*obj);
             if (obj->getCompartment() == this)
                 return true;
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -498,17 +498,17 @@ date_convert(JSContext *cx, JSObject *ob
 
     return DefaultValue(cx, obj, (hint == JSTYPE_VOID) ? JSTYPE_STRING : hint, vp);
 }
 
 /*
  * Other Support routines and definitions
  */
 
-Class js::DateClass = {
+Class js_DateClass = {
     js_Date_str,
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_CLASS_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -1221,17 +1221,17 @@ date_now_tn(JSContext*)
  * Get UTC time from the date object. Returns false if the object is not
  * Date type.
  */
 static JSBool
 GetUTCTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp)
 {
     if (!obj->isDate()) {
         if (vp)
-            ReportIncompatibleMethod(cx, vp, &DateClass);
+            ReportIncompatibleMethod(cx, vp, &js_DateClass);
         return false;
     }
     *dp = obj->getDateUTCTime().toNumber();
     return true;
 }
 
 /*
  * Set UTC time to a given time and invalidate cached local time.
@@ -1403,17 +1403,17 @@ FillLocalTimes(JSContext *cx, JSObject *
 /* Cache the local times in obj, if necessary. */
 static inline JSBool
 GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *time = NULL)
 {
     if (!obj)
         return false;
     if (!obj->isDate()) {
         if (vp)
-            ReportIncompatibleMethod(cx, vp, &DateClass);
+            ReportIncompatibleMethod(cx, vp, &js_DateClass);
         return false;
     }
 
     /* If the local time is undefined, we need to fill in the cached values. */
     if (obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined()) {
         if (!FillLocalTimes(cx, obj))
             return false;
     }
@@ -1696,17 +1696,17 @@ date_getTimezoneOffset(JSContext *cx, ui
 static JSBool
 date_setTime(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     if (!obj->isDate()) {
-        ReportIncompatibleMethod(cx, vp, &DateClass);
+        ReportIncompatibleMethod(cx, vp, &js_DateClass);
         return false;
     }
 
     if (argc == 0) {
         SetDateToNaN(cx, obj, vp);
         return true;
     }
 
@@ -2602,17 +2602,17 @@ js_Date(JSContext *cx, uintN argc, Value
     return true;
 }
 
 JSObject *
 js_InitDateClass(JSContext *cx, JSObject *obj)
 {
     /* set static LocalTZA */
     LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
-    JSObject *proto = js_InitClass(cx, obj, NULL, &DateClass, js_Date, MAXARGS,
+    JSObject *proto = js_InitClass(cx, obj, NULL, &js_DateClass, js_Date, MAXARGS,
                                    NULL, date_methods, NULL, date_static_methods);
     if (!proto)
         return NULL;
 
     AutoObjectRooter tvr(cx, proto);
 
     SetDateToNaN(cx, proto);
 
@@ -2633,17 +2633,17 @@ js_InitDateClass(JSContext *cx, JSObject
     }
 
     return proto;
 }
 
 JS_FRIEND_API(JSObject *)
 js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
 {
-    JSObject *obj = NewBuiltinClassInstance(cx, &DateClass);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_DateClass);
     if (!obj || !obj->ensureSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS))
         return NULL;
     if (!SetUTCTime(cx, obj, msec_time))
         return NULL;
     return obj;
 }
 
 JS_FRIEND_API(JSObject *)
--- a/js/src/jsdate.h
+++ b/js/src/jsdate.h
@@ -41,16 +41,24 @@
  * JS Date class interface.
  */
 
 #ifndef jsdate_h___
 #define jsdate_h___
 
 #include "jsobj.h"
 
+extern js::Class js_DateClass;
+
+inline bool
+JSObject::isDate() const
+{
+    return getClass() == &js_DateClass;
+}
+
 #define HalfTimeDomain  8.64e15
 
 #define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \
                       && !((d < 0 ? -d : d) > HalfTimeDomain)) \
                      ? js_DoubleToInteger(d + (+0.)) : js_NaN)
 
 extern JSObject *
 js_InitDateClass(JSContext *cx, JSObject *obj);
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -1995,17 +1995,17 @@ EmitEnterBlock(JSContext *cx, JSParseNod
     if (!EmitObjectOp(cx, pn->pn_objbox, JSOP_ENTERBLOCK, cg))
         return false;
 
     JSObject *blockObj = pn->pn_objbox->object;
     jsint depth = AdjustBlockSlot(cx, cg, OBJ_BLOCK_DEPTH(cx, blockObj));
     if (depth < 0)
         return false;
 
-    uintN base = JSSLOT_FREE(&BlockClass);
+    uintN base = JSSLOT_FREE(&js_BlockClass);
     for (uintN slot = base, limit = base + OBJ_BLOCK_COUNT(cx, blockObj); slot < limit; slot++) {
         const Value &v = blockObj->getSlot(slot);
 
         /* Beware the empty destructuring dummy. */
         if (v.isUndefined()) {
             JS_ASSERT(slot + 1 <= limit);
             continue;
         }
@@ -4893,17 +4893,17 @@ JSParseNode::getConstantValue(JSContext 
         types::FixArrayType(cx, obj);
         vp->setObject(*obj);
         return true;
       }
       case TOK_RC: {
         JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
 
         gc::AllocKind kind = GuessObjectGCKind(pn_count, false);
-        JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
+        JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
         if (!obj)
             return false;
 
         for (JSParseNode *pn = pn_head; pn; pn = pn->pn_next) {
             Value value;
             if (!pn->pn_right->getConstantValue(cx, strictChecks, &value))
                 return false;
 
@@ -7087,17 +7087,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 
         /*
          * Try to construct the shape of the object as we go, so we can emit a
          * JSOP_NEWOBJECT with the final shape instead.
          */
         JSObject *obj = NULL;
         if (!cg->hasSharps() && cg->compileAndGo()) {
             gc::AllocKind kind = GuessObjectGCKind(pn->pn_count, false);
-            obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
+            obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
             if (!obj)
                 return JS_FALSE;
         }
 
         uintN methodInits = 0, slowMethodInits = 0;
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
             pn3 = pn2->pn_left;
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -70,31 +70,31 @@
 #include "jsobjinlines.h"
 
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
-/* Forward declarations for ErrorClass's initializer. */
+/* Forward declarations for js_ErrorClass's initializer. */
 static JSBool
 Exception(JSContext *cx, uintN argc, Value *vp);
 
 static void
 exn_trace(JSTracer *trc, JSObject *obj);
 
 static void
 exn_finalize(JSContext *cx, JSObject *obj);
 
 static JSBool
 exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
             JSObject **objp);
 
-Class js::ErrorClass = {
+Class js_ErrorClass = {
     js_Error_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Error),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -258,141 +258,139 @@ GetStackTraceValueBuffer(JSExnPrivate *p
      * assert allows us to assume that no gap after stackElems is necessary to
      * align the buffer properly.
      */
     JS_STATIC_ASSERT(sizeof(JSStackTraceElem) % sizeof(jsval) == 0);
 
     return (jsval *)(priv->stackElems + priv->stackDepth);
 }
 
-struct SuppressErrorsGuard
-{
-    JSContext *cx;
-    JSErrorReporter prevReporter;
-    JSExceptionState *prevState;
-
-    SuppressErrorsGuard(JSContext *cx)
-      : cx(cx),
-        prevReporter(JS_SetErrorReporter(cx, NULL)),
-        prevState(JS_SaveExceptionState(cx))
-    {}
-
-    ~SuppressErrorsGuard()
-    {
-        JS_RestoreExceptionState(cx, prevState);
-        JS_SetErrorReporter(cx, prevReporter);
-    }
-};
-
-struct AppendArg {
-    Vector<Value> &values;
-    AppendArg(Vector<Value> &values) : values(values) {}
-    bool operator()(uintN, Value *vp) {
-        return values.append(*vp);
-    }
-};
-
-static bool
+static JSBool
 InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
                JSString *filename, uintN lineno, JSErrorReport *report, intN exnType)
 {
-    JS_ASSERT(exnObject->isError());
-    JS_ASSERT(!exnObject->getPrivate());
+    JSSecurityCallbacks *callbacks;
+    CheckAccessOp checkAccess;
+    JSErrorReporter older;
+    JSExceptionState *state;
+    jsid callerid;
+    size_t stackDepth, valueCount, size;
+    JSBool overflow;
+    JSExnPrivate *priv;
+    JSStackTraceElem *elem;
+    jsval *values;
 
-    JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx);
-    CheckAccessOp checkAccess = callbacks
-                                ? Valueify(callbacks->checkObjectAccess)
-                                : NULL;
+    JS_ASSERT(exnObject->getClass() == &js_ErrorClass);
 
-    Vector<JSStackTraceElem> frames(cx);
-    Vector<Value> values(cx);
-    {
-        SuppressErrorsGuard seg(cx);
-        for (FrameRegsIter i(cx); !i.done(); ++i) {
-            /*
-             * An exception object stores stack values from 'fp' which may be
-             * in a different compartment from 'exnObject'. Engine compartment
-             * invariants require such values to be wrapped. A simpler solution
-             * is to just cut off the backtrace at compartment boundaries.
-             * Also, avoid exposing values from different security principals.
-             */
-            StackFrame *fp = i.fp();
-            if (fp->compartment() != cx->compartment)
+    /*
+     * Prepare stack trace data.
+     *
+     * Set aside any error reporter for cx and save its exception state
+     * so we can suppress any checkAccess failures.  Such failures should stop
+     * the backtrace procedure, not result in a failure of this constructor.
+     */
+    callbacks = JS_GetSecurityCallbacks(cx);
+    checkAccess = callbacks
+                  ? Valueify(callbacks->checkObjectAccess)
+                  : NULL;
+    older = JS_SetErrorReporter(cx, NULL);
+    state = JS_SaveExceptionState(cx);
+
+    callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom);
+    stackDepth = 0;
+    valueCount = 0;
+    FrameRegsIter firstPass(cx);
+    for (; !firstPass.done(); ++firstPass) {
+        StackFrame *fp = firstPass.fp();
+        if (fp->compartment() != cx->compartment)
+            break;
+        if (fp->isNonEvalFunctionFrame()) {
+            Value v = NullValue();
+            if (checkAccess &&
+                !checkAccess(cx, &fp->callee(), callerid, JSACC_READ, &v)) {
                 break;
-            if (checkAccess && fp->isNonEvalFunctionFrame()) {
-                Value v = NullValue();
-                jsid callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom);
-                if (!checkAccess(cx, &fp->callee(), callerid, JSACC_READ, &v))
-                    break;
             }
+            valueCount += fp->numActualArgs();
+        }
+        ++stackDepth;
+    }
+    JS_RestoreExceptionState(cx, state);
+    JS_SetErrorReporter(cx, older);
 
-            if (!frames.growBy(1))
-                return false;
-            JSStackTraceElem &frame = frames.back();
-            if (fp->isNonEvalFunctionFrame()) {
-                frame.funName = fp->fun()->atom ? fp->fun()->atom : cx->runtime->emptyString;
-                frame.argc = fp->numActualArgs();
-                if (!fp->forEachCanonicalActualArg(AppendArg(values)))
-                    return false;
-            } else {
-                frame.funName = NULL;
-                frame.argc = 0;
-            }
-            if (fp->isScriptFrame()) {
-                frame.filename = fp->script()->filename;
-                frame.ulineno = js_FramePCToLineNumber(cx, fp, i.pc());
-            } else {
-                frame.ulineno = 0;
-                frame.filename = NULL;
-            }
+    size = offsetof(JSExnPrivate, stackElems);
+    overflow = (stackDepth > ((size_t)-1 - size) / sizeof(JSStackTraceElem));
+    size += stackDepth * sizeof(JSStackTraceElem);
+    overflow |= (valueCount > ((size_t)-1 - size) / sizeof(jsval));
+    size += valueCount * sizeof(jsval);
+    if (overflow) {
+        js_ReportAllocationOverflow(cx);
+        return JS_FALSE;
+    }
+    priv = (JSExnPrivate *)cx->malloc_(size);
+    if (!priv)
+        return JS_FALSE;
+
+    /*
+     * We initialize errorReport with a copy of report after setting the
+     * private slot, to prevent GC accessing a junk value we clear the field
+     * here.
+     */
+    priv->errorReport = NULL;
+    priv->message = message;
+    priv->filename = filename;
+    priv->lineno = lineno;
+    priv->stackDepth = stackDepth;
+    priv->exnType = exnType;
+
+    values = GetStackTraceValueBuffer(priv);
+    elem = priv->stackElems;
+
+    for (FrameRegsIter iter(cx); iter != firstPass; ++iter) {
+        StackFrame *fp = iter.fp();
+        if (fp->compartment() != cx->compartment)
+            break;
+        if (!fp->isNonEvalFunctionFrame()) {
+            elem->funName = NULL;
+            elem->argc = 0;
+        } else {
+            elem->funName = fp->fun()->atom
+                            ? fp->fun()->atom
+                            : cx->runtime->emptyString;
+            elem->argc = fp->numActualArgs();
+            fp->forEachCanonicalActualArg(CopyTo(Valueify(values)));
+            values += elem->argc;
         }
+        elem->ulineno = 0;
+        elem->filename = NULL;
+        if (fp->isScriptFrame()) {
+            elem->filename = fp->script()->filename;
+            elem->ulineno = js_FramePCToLineNumber(cx, fp, iter.pc());
+        }
+        ++elem;
     }
-
-    /* Do not need overflow check: the vm stack is already bigger. */
-    JS_STATIC_ASSERT(sizeof(JSStackTraceElem) <= sizeof(StackFrame));
+    JS_ASSERT(priv->stackElems + stackDepth == elem);
+    JS_ASSERT(GetStackTraceValueBuffer(priv) + valueCount == values);
 
-    size_t nbytes = offsetof(JSExnPrivate, stackElems) +
-                    frames.length() * sizeof(JSStackTraceElem) +
-                    values.length() * sizeof(Value);
-
-    JSExnPrivate *priv = (JSExnPrivate *)cx->malloc_(nbytes);
-    if (!priv)
-        return false;
+    exnObject->setPrivate(priv);
 
     if (report) {
         /*
          * Construct a new copy of the error report struct. We can't use the
          * error report struct that was passed in, because it's allocated on
          * the stack, and also because it may point to transient data in the
          * TokenStream.
          */
         priv->errorReport = CopyErrorReport(cx, report);
         if (!priv->errorReport) {
-            cx->free_(priv);
-            return false;
+            /* The finalizer realeases priv since it is in the private slot. */
+            return JS_FALSE;
         }
-    } else {
-        priv->errorReport = NULL;
     }
 
-    priv->message = message;
-    priv->filename = filename;
-    priv->lineno = lineno;
-    priv->stackDepth = frames.length();
-    priv->exnType = exnType;
-
-    JSStackTraceElem *framesDest = priv->stackElems;
-    Value *valuesDest = reinterpret_cast<Value *>(framesDest + frames.length());
-    JS_ASSERT(valuesDest == Valueify(GetStackTraceValueBuffer(priv)));
-
-    PodCopy(framesDest, frames.begin(), frames.length());
-    PodCopy(valuesDest, values.begin(), values.length());
-
-    exnObject->setPrivate(priv);
-    return true;
+    return JS_TRUE;
 }
 
 static inline JSExnPrivate *
 GetExnPrivate(JSObject *obj)
 {
     JS_ASSERT(obj->isError());
     return (JSExnPrivate *) obj->getPrivate();
 }
@@ -426,19 +424,22 @@ exn_trace(JSTracer *trc, JSObject *obj)
             JS_CALL_VALUE_TRACER(trc, v, "stack trace argument");
         }
     }
 }
 
 static void
 exn_finalize(JSContext *cx, JSObject *obj)
 {
-    if (JSExnPrivate *priv = GetExnPrivate(obj)) {
-        if (JSErrorReport *report = priv->errorReport)
-            cx->free_(report);
+    JSExnPrivate *priv;
+
+    priv = GetExnPrivate(obj);
+    if (priv) {
+        if (priv->errorReport)
+            cx->free_(priv->errorReport);
         cx->free_(priv);
     }
 }
 
 static JSBool
 exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
             JSObject **objp)
 {
@@ -515,17 +516,17 @@ JSErrorReport *
 js_ErrorFromException(JSContext *cx, jsval exn)
 {
     JSObject *obj;
     JSExnPrivate *priv;
 
     if (JSVAL_IS_PRIMITIVE(exn))
         return NULL;
     obj = JSVAL_TO_OBJECT(exn);
-    if (!obj->isError())
+    if (obj->getClass() != &js_ErrorClass)
         return NULL;
     priv = GetExnPrivate(obj);
     if (!priv)
         return NULL;
     return priv->errorReport;
 }
 
 static JSString *
@@ -698,88 +699,96 @@ FilenameToString(JSContext *cx, const ch
 
 enum {
     JSSLOT_ERROR_EXNTYPE = 0
 };
 
 static JSBool
 Exception(JSContext *cx, uintN argc, Value *vp)
 {
-    CallArgs args = CallArgsFromVp(argc, vp);
-
     /*
      * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when
      * called as functions, without operator new.  But as we do not give
      * each constructor a distinct JSClass, whose .name member is used by
      * NewNativeClassInstance to find the class prototype, we must get the
      * class prototype ourselves.
      */
+    JSObject &callee = vp[0].toObject();
     Value protov;
-    jsid protoAtom = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
-    if (!args.callee().getProperty(cx, protoAtom, &protov))
-        return false;
+    if (!callee.getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &protov))
+        return JS_FALSE;
 
     if (!protov.isObject()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, "Error");
-        return false;
+        return JS_FALSE;
     }
 
     JSObject *errProto = &protov.toObject();
-    JSObject *obj = NewNativeClassInstance(cx, &ErrorClass, errProto, errProto->getParent());
+    JSObject *obj = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent());
     if (!obj)
-        return false;
+        return JS_FALSE;
+
+    /*
+     * If it's a new object of class Exception, then null out the private
+     * data so that the finalizer doesn't attempt to free it.
+     */
+    if (obj->getClass() == &js_ErrorClass)
+        obj->setPrivate(NULL);
 
     /* Set the 'message' property. */
+    Value *argv = vp + 2;
     JSString *message;
-    if (args.argc() != 0 && !args[0].isUndefined()) {
-        message = js_ValueToString(cx, args[0]);
+    if (argc != 0 && !argv[0].isUndefined()) {
+        message = js_ValueToString(cx, argv[0]);
         if (!message)
-            return false;
-        args[0].setString(message);
+            return JS_FALSE;
+        argv[0].setString(message);
     } else {
         message = NULL;
     }
 
     /* Find the scripted caller. */
     FrameRegsIter iter(cx);
     while (!iter.done() && !iter.fp()->isScriptFrame())
         ++iter;
 
     /* Set the 'fileName' property. */
     JSString *filename;
-    if (args.argc() > 1) {
-        filename = js_ValueToString(cx, args[1]);
+    if (argc > 1) {
+        filename = js_ValueToString(cx, argv[1]);
         if (!filename)
-            return false;
-        args[1].setString(filename);
+            return JS_FALSE;
+        argv[1].setString(filename);
     } else {
         if (!iter.done()) {
             filename = FilenameToString(cx, iter.fp()->script()->filename);
             if (!filename)
-                return false;
+                return JS_FALSE;
         } else {
             filename = cx->runtime->emptyString;
         }
     }
 
     /* Set the 'lineNumber' property. */
     uint32_t lineno;
-    if (args.argc() > 2) {
-        if (!ValueToECMAUint32(cx, args[2], &lineno))
-            return false;
+    if (argc > 2) {
+        if (!ValueToECMAUint32(cx, argv[2], &lineno))
+            return JS_FALSE;
     } else {
         lineno = iter.done() ? 0 : js_FramePCToLineNumber(cx, iter.fp(), iter.pc());
     }
 
-    intN exnType = args.callee().getReservedSlot(JSSLOT_ERROR_EXNTYPE).toInt32();
-    if (!InitExnPrivate(cx, obj, message, filename, lineno, NULL, exnType))
-        return false;
+    intN exnType = callee.getReservedSlot(JSSLOT_ERROR_EXNTYPE).toInt32();
+    if (obj->getClass() == &js_ErrorClass &&
+        !InitExnPrivate(cx, obj, message, filename, lineno, NULL, exnType)) {
+        return JS_FALSE;
+    }
 
-    args.rval().setObject(*obj);
-    return true;
+    vp->setObject(*obj);
+    return JS_TRUE;
 }
 
 /*
  * Convert to string.
  *
  * This method only uses JavaScript-modifiable properties name, message.  It
  * is left to the host to check for private data and report filename and line
  * number information along with this message.
@@ -1005,17 +1014,17 @@ GetExceptionProtoKey(intN exn)
     return JSProtoKey(JSProto_Error + exn);
 }
 
 static JSObject *
 InitErrorClass(JSContext *cx, GlobalObject *global, intN type, JSObject &proto)
 {
     JSProtoKey key = GetExceptionProtoKey(type);
     JSAtom *name = cx->runtime->atomState.classAtoms[key];
-    JSObject *errorProto = global->createBlankPrototypeInheriting(cx, &ErrorClass, proto);
+    JSObject *errorProto = global->createBlankPrototypeInheriting(cx, &js_ErrorClass, proto);
     if (!errorProto)
         return NULL;
 
     Value empty = StringValue(cx->runtime->emptyString);
     jsid nameId = ATOM_TO_JSID(cx->runtime->atomState.nameAtom);
     jsid messageId = ATOM_TO_JSID(cx->runtime->atomState.messageAtom);
     jsid fileNameId = ATOM_TO_JSID(cx->runtime->atomState.fileNameAtom);
     jsid lineNumberId = ATOM_TO_JSID(cx->runtime->atomState.lineNumberAtom);
@@ -1027,17 +1036,17 @@ InitErrorClass(JSContext *cx, GlobalObje
                               PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE, 0, 0) ||
         !DefineNativeProperty(cx, errorProto, lineNumberId, Int32Value(0),
                               PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE, 0, 0))
     {
         return NULL;
     }
 
     /* Create the corresponding constructor. */
-    JSFunction *ctor = global->createConstructor(cx, Exception, &ErrorClass, name, 1);
+    JSFunction *ctor = global->createConstructor(cx, Exception, &js_ErrorClass, name, 1);
     if (!ctor)
         return NULL;
     ctor->setReservedSlot(JSSLOT_ERROR_EXNTYPE, Int32Value(int32(type)));
 
     if (!LinkConstructorAndPrototype(cx, ctor, errorProto))
         return NULL;
 
     if (!DefineConstructorAndPrototype(cx, global, key, ctor, errorProto))
@@ -1166,17 +1175,17 @@ js_ErrorToException(JSContext *cx, const
      * exception constructor name in the scope chain of the current context's
      * top stack frame, or in the global object if no frame is active.
      */
     ok = js_GetClassPrototype(cx, NULL, GetExceptionProtoKey(exn), &errProto);
     if (!ok)
         goto out;
     tv[0] = OBJECT_TO_JSVAL(errProto);
 
-    errObject = NewNativeClassInstance(cx, &ErrorClass, errProto, errProto->getParent());
+    errObject = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent());
     if (!errObject) {
         ok = JS_FALSE;
         goto out;
     }
     tv[1] = OBJECT_TO_JSVAL(errObject);
 
     messageStr = JS_NewStringCopyZ(cx, message);
     if (!messageStr) {
@@ -1250,17 +1259,17 @@ js_ReportUncaughtException(JSContext *cx
     } else {
         roots[1] = STRING_TO_JSVAL(str);
         if (!bytesStorage.encode(cx, str))
             return false;
         bytes = bytesStorage.ptr();
     }
 
     JSAutoByteString filename;
-    if (!reportp && exnObject && exnObject->isError()) {
+    if (!reportp && exnObject && exnObject->getClass() == &js_ErrorClass) {
         if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2]))
             return false;
         if (JSVAL_IS_STRING(roots[2])) {
             bytesStorage.clear();
             if (!bytesStorage.encode(cx, str))
                 return false;
             bytes = bytesStorage.ptr();
         }
@@ -1354,13 +1363,13 @@ js_CopyErrorObject(JSContext *cx, JSObje
     copy->lineno = priv->lineno;
     copy->stackDepth = 0;
     copy->exnType = priv->exnType;
 
     // Create the Error object.
     JSObject *proto;
     if (!js_GetClassPrototype(cx, scope->getGlobal(), GetExceptionProtoKey(copy->exnType), &proto))
         return NULL;
-    JSObject *copyobj = NewNativeClassInstance(cx, &ErrorClass, proto, proto->getParent());
+    JSObject *copyobj = NewNativeClassInstance(cx, &js_ErrorClass, proto, proto->getParent());
     copyobj->setPrivate(copy);
     autoFree.p = NULL;
     return copyobj;
 }
--- a/js/src/jsexn.h
+++ b/js/src/jsexn.h
@@ -41,16 +41,24 @@
  * JS runtime exception classes.
  */
 
 #ifndef jsexn_h___
 #define jsexn_h___
 
 #include "jsobj.h"
 
+extern js::Class js_ErrorClass;
+
+inline bool
+JSObject::isError() const
+{
+    return clasp == &js_ErrorClass;
+}
+
 /*
  * Initialize the exception constructor/prototype hierarchy.
  */
 extern JSObject *
 js_InitExceptionClasses(JSContext *cx, JSObject *obj);
 
 /*
  * Given a JSErrorReport, check to see if there is an exception associated with
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -211,18 +211,18 @@ ArgumentsObject::create(JSContext *cx, u
     ArgumentsData *data = (ArgumentsData *)
         cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
     if (!data)
         return NULL;
     SetValueRangeToUndefined(data->slots, argc);
 
     /* Can't fail from here on, so initialize everything in argsobj. */
     obj->init(cx, callee.getFunctionPrivate()->inStrictMode()
-              ? &StrictArgumentsObjectClass
-              : &NormalArgumentsObjectClass,
+              ? &StrictArgumentsObject::jsClass
+              : &NormalArgumentsObject::jsClass,
               type, proto->getParent(), NULL, false);
     obj->setMap(emptyArgumentsShape);
 
     ArgumentsObject *argsobj = obj->asArguments();
 
     JS_ASSERT(UINT32_MAX > (uint64(argc) << PACKED_BITS_COUNT));
     argsobj->setInitialLength(argc);
 
@@ -681,26 +681,28 @@ args_trace(JSTracer *trc, JSObject *obj)
     ArgumentsData *data = argsobj->data();
     if (data->callee.isObject())
         MarkObject(trc, data->callee.toObject(), js_callee_str);
     MarkValueRange(trc, argsobj->initialLength(), data->slots, js_arguments_str);
 
     MaybeMarkGenerator(trc, argsobj);
 }
 
+namespace js {
+
 /*
  * The classes below collaborate to lazily reflect and synchronize actual
  * argument values, argument count, and callee function object stored in a
  * StackFrame with their corresponding property values in the frame's
  * arguments object.
  */
-Class js::NormalArgumentsObjectClass = {
+Class NormalArgumentsObject::jsClass = {
     "Arguments",
     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
-    JSCLASS_HAS_RESERVED_SLOTS(NormalArgumentsObject::RESERVED_SLOTS) |
+    JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     PropertyStub,         /* addProperty */
     args_delProperty,
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     args_enumerate,
     reinterpret_cast<JSResolveOp>(args_resolve),
     ConvertStub,
@@ -714,20 +716,20 @@ Class js::NormalArgumentsObjectClass = {
     args_trace
 };
 
 /*
  * Strict mode arguments is significantly less magical than non-strict mode
  * arguments, so it is represented by a different class while sharing some
  * functionality.
  */
-Class js::StrictArgumentsObjectClass = {
+Class StrictArgumentsObject::jsClass = {
     "Arguments",
     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
-    JSCLASS_HAS_RESERVED_SLOTS(StrictArgumentsObject::RESERVED_SLOTS) |
+    JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     PropertyStub,         /* addProperty */
     args_delProperty,
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     strictargs_enumerate,
     reinterpret_cast<JSResolveOp>(strictargs_resolve),
     ConvertStub,
@@ -736,21 +738,23 @@ Class js::StrictArgumentsObjectClass = {
     NULL,                 /* checkAccess */
     NULL,                 /* call        */
     NULL,                 /* construct   */
     NULL,                 /* xdrObject   */
     NULL,                 /* hasInstance */
     args_trace
 };
 
+}
+
 /*
  * A Declarative Environment object stores its active StackFrame pointer in
  * its private slot, just as Call and Arguments objects do.
  */
-Class js::DeclEnvClass = {
+Class js_DeclEnvClass = {
     js_Object_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
@@ -802,17 +806,17 @@ NewDeclEnvObject(JSContext *cx, StackFra
 {
     JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!envobj)
         return NULL;
 
     EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx);
     if (!emptyDeclEnvShape)
         return NULL;
-    envobj->init(cx, &DeclEnvClass, &emptyTypeObject, &fp->scopeChain(), fp, false);
+    envobj->init(cx, &js_DeclEnvClass, &emptyTypeObject, &fp->scopeChain(), fp, false);
     envobj->setMap(emptyDeclEnvShape);
 
     return envobj;
 }
 
 namespace js {
 
 JSObject *
@@ -943,21 +947,21 @@ js_PutCallObject(StackFrame *fp)
                 nclosed = script->nClosedVars;
                 for (uint32 i = 0; i < nclosed; i++) {
                     uint32 e = script->getClosedVar(i);
                     callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + nargs + e, fp->slots()[e]);
                 }
             }
         }
 
-        /* Clear private pointers to fp, which is about to go away. */
+        /* Clear private pointers to fp, which is about to go away (js_Invoke). */
         if (js_IsNamedLambda(fun)) {
             JSObject *env = callobj.getParent();
 
-            JS_ASSERT(env->isDeclEnv());
+            JS_ASSERT(env->getClass() == &js_DeclEnvClass);
             JS_ASSERT(env->getPrivate() == fp);
             env->setPrivate(NULL);
         }
     }
 
     callobj.setPrivate(NULL);
 }
 
@@ -1167,17 +1171,17 @@ call_resolve(JSContext *cx, JSObject *ob
 static void
 call_trace(JSTracer *trc, JSObject *obj)
 {
     JS_ASSERT(obj->isCall());
 
     MaybeMarkGenerator(trc, obj);
 }
 
-JS_PUBLIC_DATA(Class) js::CallClass = {
+JS_PUBLIC_DATA(Class) js_CallClass = {
     "Call",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS) |
     JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
@@ -1457,17 +1461,17 @@ ResolveInterpretedFunctionPrototype(JSCo
     /*
      * Make the prototype object an instance of Object with the same parent
      * as the function object itself.
      */
     JSObject *parent = obj->getParent();
     JSObject *objProto;
     if (!js_GetClassPrototype(cx, parent, JSProto_Object, &objProto))
         return NULL;
-    JSObject *proto = NewNativeClassInstance(cx, &ObjectClass, objProto, parent);
+    JSObject *proto = NewNativeClassInstance(cx, &js_ObjectClass, objProto, parent);
     if (!proto || !proto->setSingletonType(cx))
         return NULL;
 
     /*
      * Per ES5 15.3.5.2 a user-defined function's .prototype property is
      * initially non-configurable, non-enumerable, and writable.  Per ES5 13.2
      * the prototype's .constructor property is configurable, non-enumerable,
      * and writable.
@@ -1709,17 +1713,17 @@ fun_finalize(JSContext *cx, JSObject *ob
     obj->finalizeUpvarsIfFlatClosure();
 }
 
 /*
  * Reserve two slots in all function objects for XPConnect.  Note that this
  * does not bloat every instance, only those on which reserved slots are set,
  * and those on which ad-hoc properties are defined.
  */
-JS_PUBLIC_DATA(Class) js::FunctionClass = {
+JS_PUBLIC_DATA(Class) js_FunctionClass = {
     js_Function_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_RESERVED_SLOTS(JSFunction::CLASS_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Function) |
     JSCLASS_CONCURRENT_FINALIZER,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
@@ -1822,17 +1826,17 @@ fun_toSource(JSContext *cx, uintN argc, 
 
 JSBool
 js_fun_call(JSContext *cx, uintN argc, Value *vp)
 {
     LeaveTrace(cx);
     Value fval = vp[1];
 
     if (!js_IsCallable(fval)) {
-        ReportIncompatibleMethod(cx, vp, &FunctionClass);
+        ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
         return false;
     }
 
     Value *argv = vp + 2;
     Value thisv;
     if (argc == 0) {
         thisv.setUndefined();
     } else {
@@ -1859,17 +1863,17 @@ js_fun_call(JSContext *cx, uintN argc, V
 
 /* ES5 15.3.4.3 */
 JSBool
 js_fun_apply(JSContext *cx, uintN argc, Value *vp)
 {
     /* Step 1. */
     Value fval = vp[1];
     if (!js_IsCallable(fval)) {
-        ReportIncompatibleMethod(cx, vp, &FunctionClass);
+        ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
         return false;
     }
 
     /* Step 2. */
     if (argc < 2 || vp[3].isNullOrUndefined())
         return js_fun_call(cx, (argc > 0) ? 1 : 0, vp);
 
     /* N.B. Changes need to be propagated to stubs::SplatApplyArgs. */
@@ -2068,17 +2072,17 @@ fun_isGenerator(JSContext *cx, uintN arg
 static JSBool
 fun_bind(JSContext *cx, uintN argc, Value *vp)
 {
     /* Step 1. */
     Value &thisv = vp[1];
 
     /* Step 2. */
     if (!js_IsCallable(thisv)) {
-        ReportIncompatibleMethod(cx, vp, &FunctionClass);
+        ReportIncompatibleMethod(cx, vp, &js_FunctionClass);
         return false;
     }
 
     JSObject *target = &thisv.toObject();
 
     /* Step 3. */
     Value *args = NULL;
     uintN argslen = 0;
@@ -2361,17 +2365,17 @@ ThrowTypeError(JSContext *cx, uintN argc
     JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
                                  JSMSG_THROW_TYPE_ERROR);
     return false;
 }
 
 JSObject *
 js_InitFunctionClass(JSContext *cx, JSObject *obj)
 {
-    JSObject *proto = js_InitClass(cx, obj, NULL, &FunctionClass, Function, 1,
+    JSObject *proto = js_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
                                    NULL, function_methods, NULL, NULL);
     if (!proto)
         return NULL;
 
     /*
      * The default 'new' object for Function.prototype has unknown properties.
      * This will be used for generic scripted functions, e.g. from non-compileAndGo code.
      */
@@ -2468,17 +2472,17 @@ js_CloneFunctionObject(JSContext *cx, JS
     JS_ASSERT(proto);
 
     JSObject *clone;
     if (cx->compartment == fun->compartment()) {
         /*
          * The cloned function object does not need the extra JSFunction members
          * beyond JSObject as it points to fun via the private slot.
          */
-        clone = NewNativeClassInstance(cx, &FunctionClass, proto, parent);
+        clone = NewNativeClassInstance(cx, &js_FunctionClass, proto, parent);
         if (!clone)
             return NULL;
 
         /*
          * We can use the same type as the original function provided that (a)
          * its prototype is correct, and (b) its type is not a singleton. The
          * first case will hold in all compileAndGo code, and the second case
          * will have been caught by CloneFunctionObject coming from function
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -165,17 +165,17 @@ struct JSFunction : public JSObject_Slot
     }
 
     JSObject &compiledFunObj() {
         return *this;
     }
 
   private:
     /*
-     * FunctionClass reserves two slots, which are free in JSObject::fslots
+     * js_FunctionClass reserves two slots, which are free in JSObject::fslots
      * without requiring dslots allocation. Null closures that can be joined to
      * a compiler-created function object use the first one to hold a mutable
      * methodAtom() state variable, needed for correct foo.caller handling.
      */
     enum {
         METHOD_ATOM_SLOT  = JSSLOT_FUN_METHOD_ATOM
     };
 
@@ -250,16 +250,32 @@ struct JSFunction : public JSObject_Slot
 # define JS_TN(name,fastcall,nargs,flags,trcinfo)                             \
     JS_FN(name, JS_DATA_TO_FUNC_PTR(Native, trcinfo), nargs,                  \
           (flags) | JSFUN_STUB_GSOPS | JSFUN_TRCINFO)
 #else
 # define JS_TN(name,fastcall,nargs,flags,trcinfo)                             \
     JS_FN(name, fastcall, nargs, flags)
 #endif
 
+extern JS_PUBLIC_DATA(js::Class) js_CallClass;
+extern JS_PUBLIC_DATA(js::Class) js_FunctionClass;
+extern JS_FRIEND_DATA(js::Class) js_DeclEnvClass;
+
+inline bool
+JSObject::isCall() const
+{
+    return getClass() == &js_CallClass;
+}
+
+inline bool
+JSObject::isFunction() const
+{
+    return getClass() == &js_FunctionClass;
+}
+
 inline JSFunction *
 JSObject::getFunctionPrivate() const
 {
     JS_ASSERT(isFunction());
     return reinterpret_cast<JSFunction *>(getPrivate());
 }
 
 namespace js {
@@ -310,17 +326,17 @@ IsNativeFunction(const js::Value &v, Nat
 {
     JSFunction *fun;
     return IsFunctionObject(v, &fun) && fun->maybeNative() == native;
 }
 
 /*
  * When we have an object of a builtin class, we don't quite know what its
  * valueOf/toString methods are, since these methods may have been overwritten
- * or shadowed. However, we can still do better than the general case by
+ * or shadowed. However, we can still do better than js_TryMethod by
  * hard-coding the necessary properties for us to find the native we expect.
  *
  * TODO: a per-thread shape-based cache would be faster and simpler.
  */
 static JS_ALWAYS_INLINE bool
 ClassMethodIsNative(JSContext *cx, JSObject *obj, Class *clasp, jsid methodid, Native native)
 {
     JS_ASSERT(obj->getClass() == clasp);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1567,18 +1567,19 @@ GCMarker::GCMarker(JSContext *cx)
 GCMarker::~GCMarker()
 {
 #ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
     dumpConservativeRoots();
 #endif
 }
 
 void
-GCMarker::delayMarkingChildren(const Cell *cell)
+GCMarker::delayMarkingChildren(const void *thing)
 {
+    const Cell *cell = reinterpret_cast<const Cell *>(thing);
     ArenaHeader *aheader = cell->arenaHeader();
     if (aheader->getMarkingDelay()->link) {
         /* Arena already scheduled to be marked later */
         return;
     }
     aheader->getMarkingDelay()->link = unmarkedArenaStackTop;
     unmarkedArenaStackTop = aheader;
 #ifdef DEBUG
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -53,20 +53,22 @@
 #include "jsgcchunk.h"
 #include "jsutil.h"
 #include "jsvector.h"
 #include "jsversion.h"
 #include "jsobj.h"
 #include "jsfun.h"
 #include "jsgcstats.h"
 #include "jscell.h"
-#include "jsxml.h"
 
 struct JSCompartment;
 
+extern "C" void
+js_TraceXML(JSTracer *trc, JSXML* thing);
+
 #if JS_STACK_GROWTH_DIRECTION > 0
 # define JS_CHECK_STACK_SIZE(limit, lval)  ((jsuword)(lval) < limit)
 #else
 # define JS_CHECK_STACK_SIZE(limit, lval)  ((jsuword)(lval) > limit)
 #endif
 
 namespace js {
 
@@ -1506,17 +1508,17 @@ struct GCMarker : public JSTracer {
     }
 
     void setMarkColor(uint32 newColor) {
         /* We must process the mark stack here, otherwise we confuse colors. */
         drainMarkStack();
         color = newColor;
     }
 
-    void delayMarkingChildren(const js::gc::Cell *cell);
+    void delayMarkingChildren(const void *thing);
 
     void markDelayedChildren();
 
     bool isMarkStackEmpty() {
         return objStack.isEmpty() &&
                ropeStack.isEmpty() &&
                typeStack.isEmpty() &&
                xmlStack.isEmpty() &&
--- a/js/src/jsgcmark.cpp
+++ b/js/src/jsgcmark.cpp
@@ -61,17 +61,17 @@
  * or strings) it eagerly marks the object rather than pushing it. Popping is
  * done by the drainMarkStack method. For each thing it pops, drainMarkStack
  * calls ScanObject (or a related function).
  *
  * Most of the marking code outside jsgcmark uses functions like MarkObject,
  * MarkString, etc. These functions check if an object is in the compartment
  * currently being GCed. If it is, they call PushMarkStack. Roots are pushed
  * this way as well as pointers traversed inside trace hooks (for things like
- * IteratorClass). It it always valid to call a MarkX function instead of
+ * js_IteratorClass). It it always valid to call a MarkX function instead of
  * PushMarkStack, although it may be slower.
  *
  * The MarkX functions also handle non-GC object traversal. In this case, they
  * call a callback for each object visited. This is a recursive process; the
  * mark stacks are not involved. These callbacks may ask for the outgoing
  * pointers to be visited. Eventually, this leads to the MarkChildren functions
  * being called. These functions duplicate much of the functionality of
  * ScanObject, but they don't push onto an explicit stack.
@@ -703,17 +703,17 @@ ScanObject(GCMarker *gcmarker, JSObject 
         PushMarkStack(gcmarker, parent);
 
     /*
      * Call the trace hook if necessary, and check for a newType on objects
      * which are not dense arrays (dense arrays have trace hooks).
      */
     Class *clasp = obj->getClass();
     if (clasp->trace) {
-        if (clasp == &ArrayClass) {
+        if (clasp == &js_ArrayClass) {
             if (obj->getDenseArrayInitializedLength() > LARGE_OBJECT_CHUNK_SIZE) {
                 if (!gcmarker->largeStack.push(LargeMarkItem(obj)))
                     clasp->trace(gcmarker, obj);
             } else {
                 clasp->trace(gcmarker, obj);
             }
         } else {
             if (obj->newType)
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -4380,17 +4380,17 @@ AnalyzeNewScriptProperties(JSContext *cx
  */
 static void
 CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script)
 {
     if (type->unknownProperties())
         return;
 
     /* Strawman object to add properties to and watch for duplicates. */
-    JSObject *baseobj = NewBuiltinClassInstance(cx, &ObjectClass, gc::FINALIZE_OBJECT16);
+    JSObject *baseobj = NewBuiltinClassInstance(cx, &js_ObjectClass, gc::FINALIZE_OBJECT16);
     if (!baseobj) {
         if (type->newScript)
             type->clearNewScript(cx);
         return;
     }
 
     Vector<TypeNewScript::Initializer> initializerList(cx);
     AnalyzeNewScriptProperties(cx, type, script, &baseobj, &initializerList);
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -295,17 +295,17 @@ GetScopeChainFull(JSContext *cx, StackFr
     } else {
         /*
          * scopeChain includes all blocks whose static scope we're within that
          * have already been cloned.  Find the innermost such block.  Its
          * prototype should appear on blockChain; we'll clone blockChain up
          * to, but not including, that prototype.
          */
         limitClone = &fp->scopeChain();
-        while (limitClone->isWith())
+        while (limitClone->getClass() == &js_WithClass)
             limitClone = limitClone->getParent();
         JS_ASSERT(limitClone);
 
         /*
          * It may seem like we don't know enough about limitClone to be able
          * to just grab its prototype as we do here, but it's actually okay.
          *
          * If limitClone is a block object belonging to this frame, then its
@@ -397,30 +397,32 @@ CallThisObjectHook(JSContext *cx, JSObje
 {
     JSObject *thisp = obj->thisObject(cx);
     if (!thisp)
         return NULL;
     argv[-1].setObject(*thisp);
     return thisp;
 }
 
+namespace js {
+
 void
-js::ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp)
+ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp)
 {
     Value &thisv = vp[1];
 
 #ifdef DEBUG
     if (thisv.isObject()) {
         JS_ASSERT(thisv.toObject().getClass() != clasp);
     } else if (thisv.isString()) {
-        JS_ASSERT(clasp != &StringClass);
+        JS_ASSERT(clasp != &js_StringClass);
     } else if (thisv.isNumber()) {
-        JS_ASSERT(clasp != &NumberClass);
+        JS_ASSERT(clasp != &js_NumberClass);
     } else if (thisv.isBoolean()) {
-        JS_ASSERT(clasp != &BooleanClass);
+        JS_ASSERT(clasp != &js_BooleanClass);
     } else {
         JS_ASSERT(thisv.isUndefined() || thisv.isNull());
     }
 #endif
 
     if (JSFunction *fun = js_ValueToFunction(cx, &vp[0], 0)) {
         JSAutoByteString funNameBytes;
         if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
@@ -441,17 +443,17 @@ js::ReportIncompatibleMethod(JSContext *
  *
  *   // in window w2
  *   var h = w1.g()
  *   alert(h() == w1)
  *
  * The alert should display "true".
  */
 bool
-js::BoxNonStrictThis(JSContext *cx, const CallReceiver &call)
+BoxNonStrictThis(JSContext *cx, const CallReceiver &call)
 {
     /*
      * Check for SynthesizeFrame poisoning and fast constructors which
      * didn't check their callee properly.
      */
     Value &thisv = call.thisv();
     JS_ASSERT(!thisv.isMagic());
 
@@ -469,16 +471,18 @@ js::BoxNonStrictThis(JSContext *cx, cons
     }
 
     if (!thisv.isObject())
         return !!js_PrimitiveToObject(cx, &thisv);
 
     return true;
 }
 
+}
+
 #if JS_HAS_NO_SUCH_METHOD
 
 const uint32 JSSLOT_FOUND_FUNCTION  = 0;
 const uint32 JSSLOT_SAVED_ID        = 1;
 
 static void
 no_such_method_trace(JSTracer *trc, JSObject *obj)
 {
@@ -515,18 +519,18 @@ Class js_NoSuchMethodClass = {
  * NoSuchMethod that invokes the method like:
  *
  *   this.__noSuchMethod__(id, args)
  *
  * where id is the name of the method that this invocation attempted to
  * call by name, and args is an Array containing this invocation's actual
  * parameters.
  */
-bool
-js::OnUnknownMethod(JSContext *cx, Value *vp)
+JSBool
+js_OnUnknownMethod(JSContext *cx, Value *vp)
 {
     JS_ASSERT(!vp[1].isPrimitive());
 
     JSObject *obj = &vp[1].toObject();
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
     AutoValueRooter tvr(cx);
     if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr()))
         return false;
@@ -577,18 +581,20 @@ NoSuchMethod(JSContext *cx, uintN argc, 
     args[1].setObject(*argsobj);
     JSBool ok = Invoke(cx, args);
     vp[0] = args.rval();
     return ok;
 }
 
 #endif /* JS_HAS_NO_SUCH_METHOD */
 
+namespace js {
+
 JS_REQUIRES_STACK bool
-js::RunScript(JSContext *cx, JSScript *script, StackFrame *fp)
+RunScript(JSContext *cx, JSScript *script, StackFrame *fp)
 {
     JS_ASSERT(script);
     JS_ASSERT(fp == cx->fp());
     JS_ASSERT(fp->script() == script);
 #ifdef JS_METHODJIT_SPEW
     JMCheckLogging();
 #endif
 
@@ -615,18 +621,18 @@ js::RunScript(JSContext *cx, JSScript *s
 }
 
 /*
  * Find a function reference and its 'this' value implicit first parameter
  * under argc arguments on cx's stack, and call the function.  Push missing
  * required arguments, allocate declared local variables, and pop everything
  * when done.  Then push the return value.
  */
-bool
-js::InvokeKernel(JSContext *cx, const CallArgs &argsRef, MaybeConstruct construct)
+JS_REQUIRES_STACK bool
+InvokeKernel(JSContext *cx, const CallArgs &argsRef, MaybeConstruct construct)
 {
     /* N.B. Must be kept in sync with InvokeSessionGuard::start/invoke */
 
     CallArgs args = argsRef;
     JS_ASSERT(args.argc() <= StackSpace::ARGS_LENGTH_MAX);
 
     JS_ASSERT(!cx->compartment->activeAnalysis);
 
@@ -637,17 +643,17 @@ js::InvokeKernel(JSContext *cx, const Ca
         js_ReportIsNotFunction(cx, &args.calleev(), ToReportFlags(initial));
         return false;
     }
 
     JSObject &callee = args.callee();
     Class *clasp = callee.getClass();
 
     /* Invoke non-functions. */
-    if (JS_UNLIKELY(clasp != &FunctionClass)) {
+    if (JS_UNLIKELY(clasp != &js_FunctionClass)) {
 #if JS_HAS_NO_SUCH_METHOD
         if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass))
             return NoSuchMethod(cx, args.argc(), args.base());
 #endif
         JS_ASSERT_IF(construct, !clasp->construct);
         if (!clasp->call) {
             js_ReportIsNotFunction(cx, &args.calleev(), ToReportFlags(initial));
             return false;
@@ -656,33 +662,49 @@ js::InvokeKernel(JSContext *cx, const Ca
     }
 
     /* Invoke native functions. */
     JSFunction *fun = callee.getFunctionPrivate();
     JS_ASSERT_IF(construct, !fun->isConstructor());
     if (fun->isNative())
         return CallJSNative(cx, fun->u.n.native, args);
 
+    /* Handle the empty-script special case. */
+    JSScript *script = fun->script();
+    if (JS_UNLIKELY(script->isEmpty())) {
+        if (construct) {
+            bool newType = cx->typeInferenceEnabled() && cx->fp()->isScriptFrame() &&
+                UseNewType(cx, cx->fp()->script(), cx->regs().pc);
+            JSObject *obj = js_CreateThisForFunction(cx, &callee, newType);
+            if (!obj)
+                return false;
+            args.rval().setObject(*obj);
+        } else {
+            args.rval().setUndefined();
+        }
+        return true;
+    }
+
     TypeMonitorCall(cx, args, construct);
 
     /* Get pointer to new frame/slots, prepare arguments. */
     InvokeFrameGuard ifg;
     if (!cx->stack.pushInvokeFrame(cx, args, initial, &ifg))
         return false;
 
     /* Now that the new frame is rooted, maybe create a call object. */
     StackFrame *fp = ifg.fp();
     if (fun->isHeavyweight() && !CreateFunCallObject(cx, fp))
         return false;
 
     /* Run function until JSOP_STOP, JSOP_RETURN or error. */
     JSBool ok;
     {
         AutoPreserveEnumerators preserve(cx);
-        ok = RunScript(cx, fun->script(), fp);
+        ok = RunScript(cx, script, fp);
     }
 
     args.rval() = fp->returnValue();
     JS_ASSERT_IF(ok && construct, !args.rval().isPrimitive());
     return ok;
 }
 
 bool
@@ -706,23 +728,23 @@ InvokeSessionGuard::start(JSContext *cx,
     /* If anyone (through jsdbgapi) finds this frame, make it safe. */
     MakeRangeGCSafe(args_.argv(), args_.argc());
 
     do {
         /* Hoist dynamic checks from scripted Invoke. */
         if (!calleev.isObject())
             break;
         JSObject &callee = calleev.toObject();
-        if (callee.getClass() != &FunctionClass)
+        if (callee.getClass() != &js_FunctionClass)
             break;
         JSFunction *fun = callee.getFunctionPrivate();
         if (fun->isNative())
             break;
         script_ = fun->script();
-        if (fun->isHeavyweight())
+        if (fun->isHeavyweight() || script_->isEmpty())
             break;
 
         /*
          * The frame will remain pushed even when the callee isn't active which
          * will affect the observable current global, so avoid any change.
          */
         if (callee.getGlobal() != GetGlobalForScopeChain(cx))
             break;
@@ -779,18 +801,18 @@ InvokeSessionGuard::start(JSContext *cx,
     if (ifg_.pushed())
         ifg_.pop();
     formals_ = actuals_ = args_.argv();
     nformals_ = (unsigned)-1;
     return true;
 }
 
 bool
-js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, uintN argc, Value *argv,
-           Value *rval)
+Invoke(JSContext *cx, const Value &thisv, const Value &fval, uintN argc, Value *argv,
+       Value *rval)
 {
     LeaveTrace(cx);
 
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return false;
 
     args.calleev() = fval;
@@ -812,17 +834,17 @@ js::Invoke(JSContext *cx, const Value &t
     if (!Invoke(cx, args))
         return false;
 
     *rval = args.rval();
     return true;
 }
 
 bool
-js::InvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *argv, Value *rval)
+InvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *argv, Value *rval)
 {
     LeaveTrace(cx);
 
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return false;
 
     args.calleev() = fval;
@@ -832,18 +854,18 @@ js::InvokeConstructor(JSContext *cx, con
     if (!InvokeConstructor(cx, args))
         return false;
 
     *rval = args.rval();
     return true;
 }
 
 bool
-js::InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, uintN argc, Value *argv,
-                         Value *rval)
+InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, uintN argc, Value *argv,
+                     Value *rval)
 {
     LeaveTrace(cx);
 
     /*
      * Invoke could result in another try to get or set the same id again, see
      * bug 355497.
      */
     JS_CHECK_RECURSION(cx, return false);
@@ -875,18 +897,18 @@ InitSharpSlots(JSContext *cx, StackFrame
         sharps[0].setUndefined();
         sharps[1].setUndefined();
     }
     return true;
 }
 #endif
 
 bool
-js::ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value &thisv,
-                  ExecuteType type, StackFrame *evalInFrame, Value *result)
+ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value &thisv,
+              ExecuteType type, StackFrame *evalInFrame, Value *result)
 {
     JS_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG);
 
     if (script->isEmpty()) {
         if (result)
             result->setUndefined();
         return true;
     }
@@ -917,17 +939,17 @@ js::ExecuteKernel(JSContext *cx, JSScrip
         *result = fp->returnValue();
 
     Probes::stopExecution(cx, script);
 
     return !!ok;
 }
 
 bool
-js::Execute(JSContext *cx, JSScript *script, JSObject &scopeChainArg, Value *rval)
+Execute(JSContext *cx, JSScript *script, JSObject &scopeChainArg, Value *rval)
 {
     /* The scope chain could be anything, so innerize just in case. */
     JSObject *scopeChain = &scopeChainArg;
     OBJ_TO_INNER_OBJECT(cx, scopeChain);
     if (!scopeChain)
         return false;
 
     /* If we were handed a non-native object, complain bitterly. */
@@ -947,17 +969,17 @@ js::Execute(JSContext *cx, JSScript *scr
         return false;
     Value thisv = ObjectValue(*thisObj);
 
     return ExecuteKernel(cx, script, *scopeChain, thisv, EXECUTE_GLOBAL,
                          NULL /* evalInFrame */, rval);
 }
 
 bool
-js::CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs)
+CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs)
 {
     JSObject *obj2;
     JSProperty *prop;
     uintN oldAttrs;
     bool isFunction;
     const char *type, *name;
 
     if (!obj->lookupProperty(cx, id, &obj2, &prop))
@@ -1018,28 +1040,28 @@ js::CheckRedeclaration(JSContext *cx, JS
     if (!name)
         return false;
     JS_ALWAYS_FALSE(JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
                                                  JSMSG_REDECLARED_VAR, type, name));
     return false;
 }
 
 JSBool
-js::HasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
+HasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
 {
     Class *clasp = obj->getClass();
     if (clasp->hasInstance)
         return clasp->hasInstance(cx, obj, v, bp);
     js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
                         JSDVG_SEARCH_STACK, ObjectValue(*obj), NULL);
     return JS_FALSE;
 }
 
 bool
-js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *result)
+LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *result)
 {
 #if JS_HAS_XML_SUPPORT
     if (JS_UNLIKELY(lval.isObject() && lval.toObject().isXML()) ||
                     (rval.isObject() && rval.toObject().isXML())) {
         return js_TestXMLEquality(cx, lval, rval, result);
     }
 #endif
 
@@ -1100,17 +1122,17 @@ js::LooselyEqual(JSContext *cx, const Va
     double l, r;
     if (!ToNumber(cx, lvalue, &l) || !ToNumber(cx, rvalue, &r))
         return false;
     *result = JSDOUBLE_COMPARE(l, ==, r, false);
     return true;
 }
 
 bool
-js::StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, JSBool *equal)
+StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, JSBool *equal)
 {
     Value lval = lref, rval = rref;
     if (SameType(lval, rval)) {
         if (lval.isString())
             return EqualStrings(cx, lval.toString(), rval.toString(), equal);
         if (lval.isDouble()) {
             *equal = JSDOUBLE_COMPARE(lval.toDouble(), ==, rval.toDouble(), JS_FALSE);
             return true;
@@ -1152,17 +1174,17 @@ IsNegativeZero(const Value &v)
 
 static inline bool
 IsNaN(const Value &v)
 {
     return v.isDouble() && JSDOUBLE_IS_NaN(v.toDouble());
 }
 
 bool
-js::SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same)
+SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same)
 {
     if (IsNegativeZero(v1)) {
         *same = IsNegativeZero(v2);
         return true;
     }
     if (IsNegativeZero(v2)) {
         *same = false;
         return true;
@@ -1170,43 +1192,43 @@ js::SameValue(JSContext *cx, const Value
     if (IsNaN(v1) && IsNaN(v2)) {
         *same = true;
         return true;
     }
     return StrictlyEqual(cx, v1, v2, same);
 }
 
 JSType
-js::TypeOfValue(JSContext *cx, const Value &vref)
+TypeOfValue(JSContext *cx, const Value &vref)
 {
     Value v = vref;
     if (v.isNumber())
         return JSTYPE_NUMBER;
     if (v.isString())
         return JSTYPE_STRING;
     if (v.isNull())
         return JSTYPE_OBJECT;
     if (v.isUndefined())
         return JSTYPE_VOID;
     if (v.isObject())
         return v.toObject().typeOf(cx);
     JS_ASSERT(v.isBoolean());
     return JSTYPE_BOOLEAN;
 }
 
-bool
-js::InvokeConstructorKernel(JSContext *cx, const CallArgs &argsRef)
-{
-    JS_ASSERT(!FunctionClass.construct);
+JS_REQUIRES_STACK bool
+InvokeConstructorKernel(JSContext *cx, const CallArgs &argsRef)
+{
+    JS_ASSERT(!js_FunctionClass.construct);
     CallArgs args = argsRef;
 
     if (args.calleev().isObject()) {
         JSObject *callee = &args.callee();
         Class *clasp = callee->getClass();
-        if (clasp == &FunctionClass) {
+        if (clasp == &js_FunctionClass) {
             JSFunction *fun = callee->getFunctionPrivate();
 
             if (fun->isConstructor()) {
                 args.thisv().setMagicWithObjectOrNullPayload(NULL);
             Probes::calloutBegin(cx, fun);
             bool ok = CallJSNativeConstructor(cx, fun->u.n.native, args);
             Probes::calloutEnd(cx, fun);
             return ok;
@@ -1228,35 +1250,35 @@ js::InvokeConstructorKernel(JSContext *c
     }
 
 error:
     js_ReportIsNotFunction(cx, &args.calleev(), JSV2F_CONSTRUCT);
     return false;
 }
 
 bool
-js::InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fval,
-                                   uintN argc, Value *argv, Value *rval)
+InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fval,
+                               uintN argc, Value *argv, Value *rval)
 {
     LeaveTrace(cx);
 
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return JS_FALSE;
 
     args.calleev() = fval;
     /* Initialize args.thisv on all paths below. */
     memcpy(args.argv(), argv, argc * sizeof(Value));
 
     /* Handle the fast-constructor cases before calling the general case. */
     JSObject &callee = fval.toObject();
     Class *clasp = callee.getClass();
     JSFunction *fun;
     bool ok;
-    if (clasp == &FunctionClass && (fun = callee.getFunctionPrivate())->isConstructor()) {
+    if (clasp == &js_FunctionClass && (fun = callee.getFunctionPrivate())->isConstructor()) {
         args.thisv().setMagicWithObjectOrNullPayload(thisobj);
         Probes::calloutBegin(cx, fun);
         ok = CallJSNativeConstructor(cx, fun->u.n.native, args);
         Probes::calloutEnd(cx, fun);
     } else if (clasp->construct) {
         args.thisv().setMagicWithObjectOrNullPayload(thisobj);
         ok = CallJSNativeConstructor(cx, clasp->construct, args);
     } else {
@@ -1264,17 +1286,17 @@ js::InvokeConstructorWithGivenThis(JSCon
         ok = Invoke(cx, args, CONSTRUCT);
     }
 
     *rval = args.rval();
     return ok;
 }
 
 bool
-js::ValueToId(JSContext *cx, const Value &v, jsid *idp)
+ValueToId(JSContext *cx, const Value &v, jsid *idp)
 {
     int32_t i;
     if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) {
         *idp = INT_TO_JSID(i);
         return true;
     }
 
 #if JS_HAS_XML_SUPPORT
@@ -1285,22 +1307,24 @@ js::ValueToId(JSContext *cx, const Value
             return JS_TRUE;
         }
     }
 #endif
 
     return js_ValueToStringId(cx, v, idp);
 }
 
+} /* namespace js */
+
 /*
  * Enter the new with scope using an object at sp[-1] and associate the depth
  * of the with block with sp + stackIndex.
  */
-static bool
-EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen)
+JS_REQUIRES_STACK JSBool
+js_EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen)
 {
     StackFrame *fp = cx->fp();
     Value *sp = cx->regs().sp;
     JS_ASSERT(stackIndex < 0);
     JS_ASSERT(fp->base() <= sp + stackIndex);
 
     JSObject *obj;
     if (sp[-1].isObject()) {
@@ -1324,72 +1348,74 @@ EnterWith(JSContext *cx, jsint stackInde
                                          sp + stackIndex - fp->base());
     if (!withobj)
         return JS_FALSE;
 
     fp->setScopeChainNoCallObj(*withobj);
     return JS_TRUE;
 }
 
-static void
-LeaveWith(JSContext *cx)
+JS_REQUIRES_STACK void
+js_LeaveWith(JSContext *cx)
 {
     JSObject *withobj;
 
     withobj = &cx->fp()->scopeChain();
-    JS_ASSERT(withobj->getClass() == &WithClass);
+    JS_ASSERT(withobj->getClass() == &js_WithClass);
     JS_ASSERT(withobj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()));
     JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0);
     withobj->setPrivate(NULL);
     cx->fp()->setScopeChainNoCallObj(*withobj->getParent());
 }
 
-bool
-js::IsActiveWithOrBlock(JSContext *cx, JSObject &obj, int stackDepth)
-{
-    return (obj.isWith() || obj.isBlock()) &&
-           obj.getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()) &&
-           OBJ_BLOCK_DEPTH(cx, &obj) >= stackDepth;
+JS_REQUIRES_STACK Class *
+js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth)
+{
+    Class *clasp;
+
+    clasp = obj->getClass();
+    if ((clasp == &js_WithClass || clasp == &js_BlockClass) &&
+        obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()) &&
+        OBJ_BLOCK_DEPTH(cx, obj) >= stackDepth) {
+        return clasp;
+    }
+    return NULL;
 }
 
 /*
  * Unwind block and scope chains to match the given depth. The function sets
  * fp->sp on return to stackDepth.
  */
-bool
-js::UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind)
-{
+JS_REQUIRES_STACK JSBool
+js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind)
+{
+    Class *clasp;
+
     JS_ASSERT(stackDepth >= 0);
     JS_ASSERT(cx->fp()->base() + stackDepth <= cx->regs().sp);
 
     StackFrame *fp = cx->fp();
     for (;;) {
-        JSObject &scopeChain = fp->scopeChain();
-        if (!IsActiveWithOrBlock(cx, scopeChain, stackDepth))
+        clasp = js_IsActiveWithOrBlock(cx, &fp->scopeChain(), stackDepth);
+        if (!clasp)
             break;
-        if (scopeChain.isBlock()) {
+        if (clasp == &js_BlockClass) {
             /* Don't fail until after we've updated all stacks. */
             normalUnwind &= js_PutBlockObject(cx, normalUnwind);
         } else {
-            LeaveWith(cx);
+            js_LeaveWith(cx);
         }
     }
 
     cx->regs().sp = fp->base() + stackDepth;
     return normalUnwind;
 }
 
-/*
- * Find the results of incrementing or decrementing *vp. For pre-increments,
- * both *vp and *vp2 will contain the result on return. For post-increments,
- * vp will contain the original value converted to a number and vp2 will get
- * the result. Both vp and vp2 must be roots.
- */
-static bool
-DoIncDec(JSContext *cx, const JSCodeSpec *cs, Value *vp, Value *vp2)
+JSBool
+js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, Value *vp, Value *vp2)
 {
     if (cs->format & JOF_POST) {
         double d;
         if (!ToNumber(cx, *vp, &d))
             return JS_FALSE;
         vp->setNumber(d);
         (cs->format & JOF_INC) ? ++d : --d;
         vp2->setNumber(d);
@@ -1654,33 +1680,33 @@ JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == 
 
 /*
  * Inline fast paths for iteration. js_IteratorMore and js_IteratorNext handle
  * all cases, but we inline the most frequently taken paths here.
  */
 static inline bool
 IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, Value *rval)
 {
-    if (iterobj->isIterator()) {
+    if (iterobj->getClass() == &js_IteratorClass) {
         NativeIterator *ni = iterobj->getNativeIterator();
         if (ni->isKeyIter()) {
             *cond = (ni->props_cursor < ni->props_end);
             return true;
         }
     }
     if (!js_IteratorMore(cx, iterobj, rval))
         return false;
     *cond = rval->isTrue();
     return true;
 }
 
 static inline bool
 IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
 {
-    if (iterobj->isIterator()) {
+    if (iterobj->getClass() == &js_IteratorClass) {
         NativeIterator *ni = iterobj->getNativeIterator();
         if (ni->isKeyIter()) {
             JS_ASSERT(ni->props_cursor < ni->props_end);
             jsid id = *ni->current();
             if (JSID_IS_ATOM(id)) {
                 rval->setString(JSID_TO_STRING(id));
                 ni->incCursor();
                 return true;
@@ -1702,18 +1728,20 @@ TypeCheckNextBytecode(JSContext *cx, JSS
     if (cx->typeInferenceEnabled() &&
         *regs.pc != JSOP_TRAP &&
         n == analyze::GetBytecodeLength(regs.pc)) {
         TypeScript::CheckBytecode(cx, script, regs.pc, regs.sp);
     }
 #endif
 }
 
-JS_NEVER_INLINE bool
-js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
+namespace js {
+
+JS_REQUIRES_STACK JS_NEVER_INLINE bool
+Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
 {
 #ifdef MOZ_TRACEVIS
     TraceVisStateObj tvso(cx, S_INTERP);
 #endif
     JSAutoResolveFlags rf(cx, RESOLVE_INFER);
 
     JS_ASSERT(!cx->compartment->activeAnalysis);
 
@@ -2338,35 +2366,38 @@ BEGIN_CASE(JSOP_POPN)
     regs.sp -= GET_UINT16(regs.pc);
 #ifdef DEBUG
     JS_ASSERT(regs.fp()->base() <= regs.sp);
     JSObject *obj = GetBlockChain(cx, regs.fp());
     JS_ASSERT_IF(obj,
                  OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj)
                  <= (size_t) (regs.sp - regs.fp()->base()));
     for (obj = &regs.fp()->scopeChain(); obj; obj = obj->getParent()) {
-        if (!obj->isBlock() || !obj->isWith())
+        Class *clasp = obj->getClass();
+        if (clasp != &js_BlockClass && clasp != &js_WithClass)
             continue;
         if (obj->getPrivate() != js_FloatingFrameIfGenerator(cx, regs.fp()))
             break;
         JS_ASSERT(regs.fp()->base() + OBJ_BLOCK_DEPTH(cx, obj)
-                  + (obj->isBlock() ? OBJ_BLOCK_COUNT(cx, obj) : 1)
+                             + ((clasp == &js_BlockClass)
+                                ? OBJ_BLOCK_COUNT(cx, obj)
+                                : 1)
                   <= regs.sp);
     }
 #endif
 }
 END_CASE(JSOP_POPN)
 
 BEGIN_CASE(JSOP_SETRVAL)
 BEGIN_CASE(JSOP_POPV)
     POP_RETURN_VALUE();
 END_CASE(JSOP_POPV)
 
 BEGIN_CASE(JSOP_ENTERWITH)
-    if (!EnterWith(cx, -1, JSOP_ENTERWITH, JSOP_ENTERWITH_LENGTH))
+    if (!js_EnterWith(cx, -1, JSOP_ENTERWITH, JSOP_ENTERWITH_LENGTH))
         goto error;
 
     /*
      * We must ensure that different "with" blocks have different stack depth
      * associated with them. This allows the try handler search to properly
      * recover the scope chain. Thus we must keep the stack at least at the
      * current level.
      *
@@ -2374,17 +2405,17 @@ BEGIN_CASE(JSOP_ENTERWITH)
      * enter/leave balance in [leavewith].
      */
     regs.sp[-1].setObject(regs.fp()->scopeChain());
 END_CASE(JSOP_ENTERWITH)
 
 BEGIN_CASE(JSOP_LEAVEWITH)
     JS_ASSERT(regs.sp[-1].toObject() == regs.fp()->scopeChain());
     regs.sp--;
-    LeaveWith(cx);
+    js_LeaveWith(cx);
 END_CASE(JSOP_LEAVEWITH)
 
 BEGIN_CASE(JSOP_RETURN)
     POP_RETURN_VALUE();
     /* FALL THROUGH */
 
 BEGIN_CASE(JSOP_RETRVAL)    /* fp return value already set */
 BEGIN_CASE(JSOP_STOP)
@@ -2415,17 +2446,17 @@ BEGIN_CASE(JSOP_STOP)
     }
 #endif
 
     interpReturnOK = true;
     if (entryFrame != regs.fp())
   inline_return:
     {
         JS_ASSERT(!regs.fp()->hasImacropc());
-        JS_ASSERT(!IsActiveWithOrBlock(cx, regs.fp()->scopeChain(), 0));
+        JS_ASSERT(!js_IsActiveWithOrBlock(cx, &regs.fp()->scopeChain(), 0));
         interpReturnOK = ScriptEpilogue(cx, regs.fp(), interpReturnOK);
 
         /* The JIT inlines ScriptEpilogue. */
 #ifdef JS_METHODJIT
   jit_return:
 #endif
 
         /* The results of lowered call/apply frames need to be shifted. */
@@ -3494,17 +3525,17 @@ do_incop:
         /*
          * We must set regs.sp[-1] to tmp for both post and pre increments
          * as the setter overwrites regs.sp[-1].
          */
         ref.setInt32(tmp);
     } else {
         /* We need an extra root for the result. */
         PUSH_NULL();
-        if (!DoIncDec(cx, cs, &regs.sp[-2], &regs.sp[-1]))
+        if (!js_DoIncDec(cx, cs, &regs.sp[-2], &regs.sp[-1]))
             goto error;
 
         {
             JSAutoResolveFlags rf(cx, setPropFlags);
             if (!obj->setProperty(cx, id, &regs.sp[-1], script->strictModeCode))
                 goto error;
         }
 
@@ -3566,17 +3597,17 @@ BEGIN_CASE(JSOP_LOCALINC)
     int32_t tmp;
     if (JS_LIKELY(vp->isInt32() && CanIncDecWithoutOverflow(tmp = vp->toInt32()))) {
         vp->getInt32Ref() = tmp + incr;
         JS_ASSERT(JSOP_INCARG_LENGTH == js_CodeSpec[op].length);
         SKIP_POP_AFTER_SET(JSOP_INCARG_LENGTH, 0);
         PUSH_INT32(tmp + incr2);
     } else {
         PUSH_COPY(*vp);
-        if (!DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-1], vp))
+        if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-1], vp))
             goto error;
         TypeScript::MonitorOverflow(cx, script, regs.pc);
     }
     len = JSOP_INCARG_LENGTH;
     JS_ASSERT(len == js_CodeSpec[op].length);
     DO_NEXT_OP(len);
 }
 
@@ -3772,17 +3803,17 @@ BEGIN_CASE(JSOP_CALLPROP)
             regs.sp[-2] = rval;
             assertSameCompartment(cx, regs.sp[-1], regs.sp[-2]);
         }
     }
 #if JS_HAS_NO_SUCH_METHOD
     if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) {
         LOAD_ATOM(0, atom);
         regs.sp[-2].setString(atom);
-        if (!OnUnknownMethod(cx, regs.sp - 2))
+        if (!js_OnUnknownMethod(cx, regs.sp - 2))
             goto error;
     }
 #endif
     TypeScript::Monitor(cx, script, regs.pc, rval);
 }
 END_CASE(JSOP_CALLPROP)
 
 BEGIN_CASE(JSOP_UNBRAND)
@@ -4048,20 +4079,20 @@ BEGIN_CASE(JSOP_CALLELEM)
     FETCH_ELEMENT_ID(thisObj, -1, id);
 
     /* Get the method. */
     if (!js_GetMethod(cx, thisObj, id, JSGET_NO_METHOD_BARRIER, &regs.sp[-2]))
         goto error;
 
 #if JS_HAS_NO_SUCH_METHOD
     if (JS_UNLIKELY(regs.sp[-2].isPrimitive()) && thisv.isObject()) {
-        /* For OnUnknownMethod, sp[-2] is the index, and sp[-1] is the object missing it. */
+        /* For js_OnUnknownMethod, sp[-2] is the index, and sp[-1] is the object missing it. */
         regs.sp[-2] = regs.sp[-1];
         regs.sp[-1].setObject(*thisObj);
-        if (!OnUnknownMethod(cx, regs.sp - 2))
+        if (!js_OnUnknownMethod(cx, regs.sp - 2))
             goto error;
     } else
 #endif
     {
         regs.sp[-1] = thisv;
     }
 
     if (!JSID_IS_INT(id))
@@ -4287,17 +4318,17 @@ BEGIN_CASE(JSOP_CALLNAME)
 
     /* Take the slow path if prop was not found in a native object. */
     if (!obj->isNative() || !obj2->isNative()) {
         if (!obj->getProperty(cx, id, &rval))
             goto error;
     } else {
         shape = (Shape *)prop;
         JSObject *normalized = obj;
-        if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter())
+        if (normalized->getClass() == &js_WithClass && !shape->hasDefaultGetter())
             normalized = js_UnwrapWithObject(cx, normalized);
         NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval);
     }
 
     PUSH_COPY(rval);
     TypeScript::Monitor(cx, script, regs.pc, rval);
 
     /* obj must be on the scope chain, thus not a function. */
@@ -4985,17 +5016,17 @@ BEGIN_CASE(JSOP_LAMBDA)
                  * match the optimization cases in the following code that
                  * break from the outer do-while(0).
                  */
                 if (op2 == JSOP_INITMETHOD) {
 #ifdef DEBUG
                     const Value &lref = regs.sp[-1];
                     JS_ASSERT(lref.isObject());
                     JSObject *obj2 = &lref.toObject();
-                    JS_ASSERT(obj2->isObject());
+                    JS_ASSERT(obj2->getClass() == &js_ObjectClass);
 #endif
 
                     fun->setMethodAtom(script->getAtom(GET_FULL_INDEX(pc2 - regs.pc)));
                     break;
                 }
 
                 if (op2 == JSOP_SETMETHOD) {
 #ifdef DEBUG
@@ -5202,17 +5233,17 @@ BEGIN_CASE(JSOP_NEWINIT)
 
     JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
     JSObject *obj;
 
     if (i == JSProto_Array) {
         obj = NewDenseEmptyArray(cx);
     } else {
         gc::AllocKind kind = GuessObjectGCKind(0, false);
-        obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
+        obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
     }
 
     if (!obj)
         goto error;
 
     TypeObject *type = TypeScript::InitObject(cx, script, regs.pc, (JSProtoKey) i);
     if (!type)
         goto error;
@@ -5788,27 +5819,27 @@ BEGIN_CASE(JSOP_FILTER)
 END_VARLEN_CASE
 }
 
 BEGIN_CASE(JSOP_ENDFILTER)
 {
     bool cond = !regs.sp[-1].isMagic();
     if (cond) {
         /* Exit the "with" block left from the previous iteration. */
-        LeaveWith(cx);
+        js_LeaveWith(cx);
     }
     if (!js_StepXMLListFilter(cx, cond))
         goto error;
     if (!regs.sp[-1].isNull()) {
         /*
          * Decrease sp after EnterWith returns as we use sp[-1] there to root
          * temporaries.
          */
         JS_ASSERT(IsXML(regs.sp[-1]));
-        if (!EnterWith(cx, -2, JSOP_ENDFILTER, JSOP_ENDFILTER_LENGTH))
+        if (!js_EnterWith(cx, -2, JSOP_ENDFILTER, JSOP_ENDFILTER_LENGTH))
             goto error;
         regs.sp--;
         len = GET_JUMP_OFFSET(regs.pc);
         JS_ASSERT(len < 0);
         BRANCH(len);
     }
     regs.sp--;
 }
@@ -5925,19 +5956,20 @@ BEGIN_CASE(JSOP_ENTERBLOCK)
     /*
      * The young end of fp->scopeChain may omit blocks if we haven't closed
      * over them, but if there are any closure blocks on fp->scopeChain, they'd
      * better be (clones of) ancestors of the block we're entering now;
      * anything else we should have popped off fp->scopeChain when we left its
      * static scope.
      */
     JSObject *obj2 = &regs.fp()->scopeChain();
-    while (obj2->isWith())
+    Class *clasp;
+    while ((clasp = obj2->getClass()) == &js_WithClass)
         obj2 = obj2->getParent();
-    if (obj2->isBlock() &&
+    if (clasp == &js_BlockClass &&
         obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, regs.fp())) {
         JSObject *youngestProto = obj2->getProto();
         JS_ASSERT(youngestProto->isStaticBlock());
         JSObject *parent = obj;
         while ((parent = parent->getParent()) != youngestProto)
             JS_ASSERT(parent);
     }
 #endif
@@ -6192,17 +6224,17 @@ END_CASE(JSOP_ARRAYPUSH)
 
             /*
              * Set pc to the first bytecode after the the try note to point
              * to the beginning of catch or finally or to [enditer] closing
              * the for-in loop.
              */
             regs.pc = (script)->main() + tn->start + tn->length;
 
-            JSBool ok = UnwindScope(cx, tn->stackDepth, JS_TRUE);
+            JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE);
             JS_ASSERT(regs.sp == regs.fp()->base() + tn->stackDepth);
             if (!ok) {
                 /*
                  * Restart the handler search with updated pc and stack depth
                  * to properly notify the debugger.
                  */
                 goto error;
             }
@@ -6262,22 +6294,22 @@ END_CASE(JSOP_ARRAYPUSH)
             regs.fp()->clearReturnValue();
         }
 #endif
     }
 
   forced_return:
     /*
      * Unwind the scope making sure that interpReturnOK stays false even when
-     * UnwindScope returns true.
+     * js_UnwindScope returns true.
      *
      * When a trap handler returns JSTRAP_RETURN, we jump here with
      * interpReturnOK set to true bypassing any finally blocks.
      */
-    interpReturnOK &= UnwindScope(cx, 0, interpReturnOK || cx->isExceptionPending());
+    interpReturnOK &= js_UnwindScope(cx, 0, interpReturnOK || cx->isExceptionPending());
     JS_ASSERT(regs.sp == regs.fp()->base());
 
     if (entryFrame != regs.fp())
         goto inline_return;
 
   exit:
     interpReturnOK = ScriptEpilogueOrGeneratorYield(cx, regs.fp(), interpReturnOK);
     regs.fp()->setFinishedInInterpreter();
@@ -6301,17 +6333,17 @@ END_CASE(JSOP_ARRAYPUSH)
         AbortRecording(cx, "recording out of Interpret");
 # ifdef JS_METHODJIT
     if (TRACE_PROFILER(cx))
         AbortProfiling(cx);
 # endif
 #endif
 
     JS_ASSERT_IF(!regs.fp()->isGeneratorFrame(),
-                 !IsActiveWithOrBlock(cx, regs.fp()->scopeChain(), 0));
+                 !js_IsActiveWithOrBlock(cx, &regs.fp()->scopeChain(), 0));
 
 #ifdef JS_METHODJIT
     /*
      * This path is used when it's guaranteed the method can be finished
      * inside the JIT.
      */
   leave_on_safe_point:
 #endif
@@ -6321,8 +6353,10 @@ END_CASE(JSOP_ARRAYPUSH)
   atom_not_defined:
     {
         JSAutoByteString printable;
         if (js_AtomToPrintableString(cx, atomNotDefined, &printable))
             js_ReportIsNotDefined(cx, printable.ptr());
     }
     goto error;
 }
+
+} /* namespace js */
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -355,24 +355,39 @@ class InterpreterFrames {
     InterpreterFrames *older;
 
   private:
     JSContext *context;
     FrameRegs *regs;
     const InterruptEnablerBase &enabler;
 };
 
+} /* namespace js */
+
+extern JS_REQUIRES_STACK JSBool
+js_EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen);
+
+extern JS_REQUIRES_STACK void
+js_LeaveWith(JSContext *cx);
+
+/*
+ * Find the results of incrementing or decrementing *vp. For pre-increments,
+ * both *vp and *vp2 will contain the result on return. For post-increments,
+ * vp will contain the original value converted to a number and vp2 will get
+ * the result. Both vp and vp2 must be roots.
+ */
+extern JSBool
+js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, js::Value *vp, js::Value *vp2);
+
 /*
  * Unwind block and scope chains to match the given depth. The function sets
  * fp->sp on return to stackDepth.
  */
-extern bool
-UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind);
+extern JS_REQUIRES_STACK JSBool
+js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind);
 
-extern bool
-OnUnknownMethod(JSContext *cx, js::Value *vp);
+extern JSBool
+js_OnUnknownMethod(JSContext *cx, js::Value *vp);
 
-extern bool
-IsActiveWithOrBlock(JSContext *cx, JSObject &obj, int stackDepth);
-
-}  /* namespace js */
+extern JS_REQUIRES_STACK js::Class *
+js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth);
 
 #endif /* jsinterp_h___ */
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -177,33 +177,33 @@ namespace detail {
 
 template<typename T> class PrimitiveBehavior { };
 
 template<>
 class PrimitiveBehavior<JSString *> {
   public:
     static inline bool isType(const Value &v) { return v.isString(); }
     static inline JSString *extract(const Value &v) { return v.toString(); }
-    static inline Class *getClass() { return &StringClass; }
+    static inline Class *getClass() { return &js_StringClass; }
 };
 
 template<>
 class PrimitiveBehavior<bool> {
   public:
     static inline bool isType(const Value &v) { return v.isBoolean(); }
     static inline bool extract(const Value &v) { return v.toBoolean(); }
-    static inline Class *getClass() { return &BooleanClass; }
+    static inline Class *getClass() { return &js_BooleanClass; }
 };
 
 template<>
 class PrimitiveBehavior<double> {
   public:
     static inline bool isType(const Value &v) { return v.isNumber(); }
     static inline double extract(const Value &v) { return v.toNumber(); }
-    static inline Class *getClass() { return &NumberClass; }
+    static inline Class *getClass() { return &js_NumberClass; }
 };
 
 } // namespace detail
 
 template <typename T>
 inline bool
 GetPrimitiveThis(JSContext *cx, Value *vp, T *v)
 {
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -85,17 +85,17 @@
 
 using namespace js;
 using namespace js::gc;
 
 static void iterator_finalize(JSContext *cx, JSObject *obj);
 static void iterator_trace(JSTracer *trc, JSObject *obj);
 static JSObject *iterator_iterator(JSContext *cx, JSObject *obj, JSBool keysonly);
 
-Class js::IteratorClass = {
+Class js_IteratorClass = {
     "Iterator",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_CONCURRENT_FINALIZER |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
@@ -125,17 +125,17 @@ NativeIterator::mark(JSTracer *trc)
     MarkIdRange(trc, begin(), end(), "props");
     if (obj)
         MarkObject(trc, *obj, "obj");
 }
 
 static void
 iterator_finalize(JSContext *cx, JSObject *obj)
 {
-    JS_ASSERT(obj->isIterator());
+    JS_ASSERT(obj->getClass() == &js_IteratorClass);
 
     NativeIterator *ni = obj->getNativeIterator();
     if (ni) {
         cx->free_(ni);
         obj->setNativeIterator(NULL);
     }
 }
 
@@ -413,22 +413,22 @@ NewIteratorObject(JSContext *cx, uintN f
          */
         JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT0);
         if (!obj)
             return NULL;
 
         EmptyShape *emptyEnumeratorShape = EmptyShape::getEmptyEnumeratorShape(cx);
         if (!emptyEnumeratorShape)
             return NULL;
-        obj->init(cx, &IteratorClass, &types::emptyTypeObject, NULL, NULL, false);
+        obj->init(cx, &js_IteratorClass, &types::emptyTypeObject, NULL, NULL, false);
         obj->setMap(emptyEnumeratorShape);
         return obj;
     }
 
-    return NewBuiltinClassInstance(cx, &IteratorClass);
+    return NewBuiltinClassInstance(cx, &js_IteratorClass);
 }
 
 NativeIterator *
 NativeIterator::allocateIterator(JSContext *cx, uint32 slength, const AutoIdVector &props)
 {
     size_t plength = props.length();
     NativeIterator *ni = (NativeIterator *)
         cx->malloc_(sizeof(NativeIterator) + plength * sizeof(jsid) + slength * sizeof(uint32));
@@ -566,17 +566,17 @@ GetIterator(JSContext *cx, JSObject *obj
     Vector<uint32, 8> shapes(cx);
     uint32 key = 0;
 
     bool keysOnly = (flags == JSITER_ENUMERATE);
 
     if (obj) {
         /* Enumerate Iterator.prototype directly. */
         JSIteratorOp op = obj->getClass()->ext.iteratorObject;
-        if (op && (obj->getClass() != &IteratorClass || obj->getNativeIterator())) {
+        if (op && (obj->getClass() != &js_IteratorClass || obj->getNativeIterator())) {
             JSObject *iterobj = op(cx, obj, !(flags & JSITER_FOREACH));
             if (!iterobj)
                 return false;
             vp->setObject(*iterobj);
             types::MarkIteratorUnknown(cx);
             return true;
         }
 
@@ -713,18 +713,18 @@ js_ThrowStopIteration(JSContext *cx)
 }
 
 static JSBool
 iterator_next(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
-    if (!obj->isIterator()) {
-        ReportIncompatibleMethod(cx, vp, &IteratorClass);
+    if (obj->getClass() != &js_IteratorClass) {
+        ReportIncompatibleMethod(cx, vp, &js_IteratorClass);
         return false;
     }
 
     if (!js_IteratorMore(cx, obj, vp))
         return false;
     if (!vp->toBoolean()) {
         js_ThrowStopIteration(cx);
         return false;
@@ -787,17 +787,18 @@ static JS_REQUIRES_STACK JSBool
 CloseGenerator(JSContext *cx, JSObject *genobj);
 #endif
 
 JS_FRIEND_API(JSBool)
 js_CloseIterator(JSContext *cx, JSObject *obj)
 {
     cx->iterValue.setMagic(JS_NO_ITER_VALUE);
 
-    if (obj->isIterator()) {
+    Class *clasp = obj->getClass();
+    if (clasp == &js_IteratorClass) {
         /* Remove enumerators from the active list, which is a stack. */
         NativeIterator *ni = obj->getNativeIterator();
 
         if (ni->flags & JSITER_ENUMERATE) {
             JS_ASSERT(cx->enumerators == obj);
             cx->enumerators = ni->next;
 
             JS_ASSERT(ni->flags & JSITER_ACTIVE);
@@ -806,17 +807,17 @@ js_CloseIterator(JSContext *cx, JSObject
             /*
              * Reset the enumerator; it may still be in the cached iterators
              * for this thread, and can be reused.
              */
             ni->props_cursor = ni->props_array;
         }
     }
 #if JS_HAS_GENERATORS
-    else if (obj->isGenerator()) {
+    else if (clasp == &js_GeneratorClass) {
         return CloseGenerator(cx, obj);
     }
 #endif
     return JS_TRUE;
 }
 
 /*
  * Suppress enumeration of deleted properties. This function must be called
@@ -937,17 +938,17 @@ js_SuppressDeletedIndexProperties(JSCont
     return SuppressDeletedPropertyHelper(cx, obj, IndexRangePredicate(begin, end));
 }
 
 JSBool
 js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
 {
     /* Fast path for native iterators */
     NativeIterator *ni = NULL;
-    if (iterobj->isIterator()) {
+    if (iterobj->getClass() == &js_IteratorClass) {
         /* Key iterators are handled by fast-paths. */
         ni = iterobj->getNativeIterator();
         if (ni) {
             bool more = ni->props_cursor < ni->props_end;
             if (ni->isKeyIter() || !more) {
                 rval->setBoolean(more);
                 return true;
             }
@@ -965,17 +966,17 @@ js_IteratorMore(JSContext *cx, JSObject 
 
     /* Fetch and cache the next value from the iterator. */
     if (!ni) {
         jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom);
         if (!js_GetMethod(cx, iterobj, id, JSGET_METHOD_BARRIER, rval))
             return false;
         if (!Invoke(cx, ObjectValue(*iterobj), *rval, 0, NULL, rval)) {
             /* Check for StopIteration. */
-            if (!cx->isExceptionPending() || !IsStopIteration(cx->getPendingException()))
+            if (!cx->isExceptionPending() || !js_ValueIsStopIteration(cx->getPendingException()))
                 return false;
 
             cx->clearPendingException();
             cx->iterValue.setMagic(JS_NO_ITER_VALUE);
             rval->setBoolean(false);
             return true;
         }
     } else {
@@ -994,17 +995,17 @@ js_IteratorMore(JSContext *cx, JSObject 
     rval->setBoolean(true);
     return true;
 }
 
 JSBool
 js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
 {
     /* Fast path for native iterators */
-    if (iterobj->isIterator()) {
+    if (iterobj->getClass() == &js_IteratorClass) {
         /*
          * Implement next directly as all the methods of the native iterator are
          * read-only and permanent.
          */
         NativeIterator *ni = iterobj->getNativeIterator();
         if (ni && ni->isKeyIter()) {
             JS_ASSERT(ni->props_cursor < ni->props_end);
             *rval = IdToValue(*ni->current());
@@ -1033,21 +1034,21 @@ js_IteratorNext(JSContext *cx, JSObject 
     cx->iterValue.setMagic(JS_NO_ITER_VALUE);
 
     return true;
 }
 
 static JSBool
 stopiter_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
 {
-    *bp = IsStopIteration(*v);
+    *bp = js_ValueIsStopIteration(*v);
     return JS_TRUE;
 }
 
-Class js::StopIterationClass = {
+Class js_StopIterationClass = {
     js_StopIteration_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration) |
     JSCLASS_FREEZE_PROTO,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -1105,17 +1106,17 @@ generator_trace(JSTracer *trc, JSObject 
      * plan is to eventually mjit generators, it makes sense to future-proof
      * this code and save someone an hour later.
      */
     MarkStackRangeConservatively(trc, gen->floatingStack, fp->formalArgsEnd());
     js_TraceStackFrame(trc, fp);
     MarkStackRangeConservatively(trc, fp->slots(), gen->regs.sp);
 }
 
-Class js::GeneratorClass = {
+Class js_GeneratorClass = {
     js_Generator_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator) |
     JSCLASS_IS_ANONYMOUS,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -1144,17 +1145,17 @@ Class js::GeneratorClass = {
  * JSGenerator object, which contains its own StackFrame that we populate
  * from *fp.  We know that upon return, the JSOP_GENERATOR opcode will return
  * from the activation in fp, so we can steal away fp->callobj and fp->argsobj
  * if they are non-null.
  */
 JS_REQUIRES_STACK JSObject *
 js_NewGenerator(JSContext *cx)
 {
-    JSObject *obj = NewBuiltinClassInstance(cx, &GeneratorClass);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_GeneratorClass);
     if (!obj)
         return NULL;
 
     FrameRegs &stackRegs = cx->regs();
     StackFrame *stackfp = stackRegs.fp();
     JS_ASSERT(stackfp->base() == cx->regs().sp);
     JS_ASSERT(stackfp->actualArgs() <= stackfp->formalArgs());
 
@@ -1303,17 +1304,17 @@ SendToGenerator(JSContext *cx, JSGenerat
      * Propagate the condition to the caller.
      */
     return JS_FALSE;
 }
 
 static JS_REQUIRES_STACK JSBool
 CloseGenerator(JSContext *cx, JSObject *obj)
 {
-    JS_ASSERT(obj->isGenerator());
+    JS_ASSERT(obj->getClass() == &js_GeneratorClass);
 
     JSGenerator *gen = (JSGenerator *) obj->getPrivate();
     if (!gen) {
         /* Generator prototype object. */
         return JS_TRUE;
     }
 
     if (gen->state == JSGEN_CLOSED)
@@ -1328,18 +1329,18 @@ CloseGenerator(JSContext *cx, JSObject *
 static JSBool
 generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
 {
     LeaveTrace(cx);
 
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return JS_FALSE;
-    if (!obj->isGenerator()) {
-        ReportIncompatibleMethod(cx, vp, &GeneratorClass);
+    if (obj->getClass() != &js_GeneratorClass) {
+        ReportIncompatibleMethod(cx, vp, &js_GeneratorClass);
         return JS_FALSE;
     }
 
     JSGenerator *gen = (JSGenerator *) obj->getPrivate();
     if (!gen) {
         /* This happens when obj is the generator prototype. See bug 352885. */
         goto closed_generator;
     }
@@ -1420,21 +1421,21 @@ static JSFunctionSpec generator_methods[
     JS_FS_END
 };
 
 #endif /* JS_HAS_GENERATORS */
 
 static bool
 InitIteratorClass(JSContext *cx, GlobalObject *global)
 {
-    JSObject *iteratorProto = global->createBlankPrototype(cx, &IteratorClass);
+    JSObject *iteratorProto = global->createBlankPrototype(cx, &js_IteratorClass);
     if (!iteratorProto)
         return false;
 
-    JSFunction *ctor = global->createConstructor(cx, Iterator, &IteratorClass,
+    JSFunction *ctor = global->createConstructor(cx, Iterator, &js_IteratorClass,
                                                  CLASS_ATOM(cx, Iterator), 2);
     if (!ctor)
         return false;
 
     if (!LinkConstructorAndPrototype(cx, ctor, iteratorProto))
         return false;
 
     if (!DefinePropertiesAndBrand(cx, iteratorProto, NULL, iterator_methods))
@@ -1442,42 +1443,42 @@ InitIteratorClass(JSContext *cx, GlobalO
 
     return DefineConstructorAndPrototype(cx, global, JSProto_Iterator, ctor, iteratorProto);
 }
 
 static bool
 InitGeneratorClass(JSContext *cx, GlobalObject *global)
 {
 #if JS_HAS_GENERATORS
-    JSObject *proto = global->createBlankPrototype(cx, &GeneratorClass);
+    JSObject *proto = global->createBlankPrototype(cx, &js_GeneratorClass);
     if (!proto)
         return false;
 
     if (!DefinePropertiesAndBrand(cx, proto, NULL, generator_methods))
         return false;
 
     /* This should use a non-JSProtoKey'd slot, but this is easier for now. */
     return DefineConstructorAndPrototype(cx, global, JSProto_Generator, proto, proto);
 #else
     return true;
 #endif
 }
 
 static JSObject *
 InitStopIterationClass(JSContext *cx, GlobalObject *global)
 {
-    JSObject *proto = global->createBlankPrototype(cx, &StopIterationClass);
+    JSObject *proto = global->createBlankPrototype(cx, &js_StopIterationClass);
     if (!proto || !proto->freeze(cx))
         return NULL;
 
     /* This should use a non-JSProtoKey'd slot, but this is easier for now. */
     if (!DefineConstructorAndPrototype(cx, global, JSProto_StopIteration, proto, proto))
         return NULL;
 
-    MarkStandardClassInitializedNoProto(global, &StopIterationClass);
+    MarkStandardClassInitializedNoProto(global, &js_StopIterationClass);
 
     return proto;
 }
 
 JSObject *
 js_InitIteratorClasses(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -226,22 +226,22 @@ js_FloatingFrameToGenerator(js::StackFra
 inline js::StackFrame *
 js_LiveFrameIfGenerator(js::StackFrame *fp)
 {
     return fp->isGeneratorFrame() ? js_FloatingFrameToGenerator(fp)->liveFrame() : fp;
 }
 
 #endif
 
-namespace js {
+extern js::Class js_GeneratorClass;
+extern js::Class js_IteratorClass;
+extern js::Class js_StopIterationClass;
 
 static inline bool
-IsStopIteration(const js::Value &v)
+js_ValueIsStopIteration(const js::Value &v)
 {
-    return v.isObject() && v.toObject().isStopIteration();
+    return v.isObject() && v.toObject().getClass() == &js_StopIterationClass;
 }
 
-}  /* namespace js */
-
 extern JSObject *
 js_InitIteratorClasses(JSContext *cx, JSObject *obj);
 
 #endif /* jsiter_h___ */
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -101,17 +101,17 @@ MathCache::MathCache() {
     memset(table, 0, sizeof(table));
 
     /* See comments in lookup(). */
     JS_ASSERT(JSDOUBLE_IS_NEGZERO(-0.0));
     JS_ASSERT(!JSDOUBLE_IS_NEGZERO(+0.0));
     JS_ASSERT(hash(-0.0) != hash(+0.0));
 }
 
-Class js::MathClass = {
+Class js_MathClass = {
     js_Math_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Math),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
@@ -860,26 +860,26 @@ js_IsMathFunction(JSNative native)
             return true;
     }
     return false;
 }
 
 JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj)
 {
-    JSObject *Math = NewNonFunction<WithProto::Class>(cx, &MathClass, NULL, obj);
+    JSObject *Math = NewNonFunction<WithProto::Class>(cx, &js_MathClass, NULL, obj);
     if (!Math || !Math->setSingletonType(cx))
         return NULL;
 
     if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),
                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
         return NULL;
     }
 
     if (!JS_DefineFunctions(cx, Math, math_static_methods))
         return NULL;
     if (!JS_DefineConstDoubles(cx, Math, math_constants))
         return NULL;
 
-    MarkStandardClassInitializedNoProto(obj, &MathClass);
+    MarkStandardClassInitializedNoProto(obj, &js_MathClass);
 
     return Math;
 }
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -77,16 +77,18 @@ class MathCache
 };
 
 } /* namespace js */
 
 /*
  * JS math functions.
  */
 
+extern js::Class js_MathClass;
+
 extern JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj);
 
 extern bool
 js_IsMathFunction(JSNative native);
 
 extern void
 js_InitRandom(JSContext *cx);
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -554,17 +554,17 @@ JS_DEFINE_TRCINFO_1(num_parseFloat,
 static JSFunctionSpec number_functions[] = {
     JS_FN(js_isNaN_str,         num_isNaN,           1,0),
     JS_FN(js_isFinite_str,      num_isFinite,        1,0),
     JS_TN(js_parseFloat_str,    num_parseFloat,      1,0, &num_parseFloat_trcinfo),
     JS_TN(js_parseInt_str,      num_parseInt,        2,0, &num_parseInt_trcinfo),
     JS_FS_END
 };
 
-Class js::NumberClass = {
+Class js_NumberClass = {
     js_Number_str,
     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
@@ -583,17 +583,17 @@ Number(JSContext *cx, uintN argc, Value 
         vp[0] = vp[2];
     } else {
         vp[0].setInt32(0);
     }
 
     if (!isConstructing)
         return true;
 
-    JSObject *obj = NewBuiltinClassInstance(cx, &NumberClass);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_NumberClass);
     if (!obj)
         return false;
     obj->setPrimitiveThis(vp[0]);
     vp->setObject(*obj);
     return true;
 }
 
 #if JS_HAS_TOSOURCE
@@ -607,17 +607,17 @@ num_toSource(JSContext *cx, uintN argc, 
     ToCStringBuf cbuf;
     char *numStr = NumberToCString(cx, &cbuf, d);
     if (!numStr) {
         JS_ReportOutOfMemory(cx);
         return false;
     }
 
     char buf[64];
-    JS_snprintf(buf, sizeof buf, "(new %s(%s))", NumberClass.name, numStr);
+    JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr);
     JSString *str = js_NewStringCopyZ(cx, buf);
     if (!str)
         return false;
     vp->setString(str);
     return true;
 }
 #endif
 
@@ -1101,17 +1101,17 @@ JSObject *
 js_InitNumberClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto, *ctor;
     JSRuntime *rt;
 
     /* XXX must do at least once per new thread, so do it per JSContext... */
     FIX_FPU();
 
-    proto = js_InitClass(cx, obj, NULL, &NumberClass, Number, 1,
+    proto = js_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1,
                          NULL, number_methods, NULL, NULL);
     if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
         return NULL;
     proto->setPrimitiveThis(Int32Value(0));
 
     if (!JS_DefineFunctions(cx, obj, number_functions))
         return NULL;
 
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -155,16 +155,24 @@ extern bool
 InitRuntimeNumberState(JSRuntime *rt);
 
 extern void
 FinishRuntimeNumberState(JSRuntime *rt);
 
 } /* namespace js */
 
 /* Initialize the Number class, returning its prototype object. */
+extern js::Class js_NumberClass;
+
+inline bool
+JSObject::isNumber() const
+{
+    return getClass() == &js_NumberClass;
+}
+
 extern JSObject *
 js_InitNumberClass(JSContext *cx, JSObject *obj);
 
 /*
  * String constants for global function names, used in jsapi.c and jsnum.c.
  */
 extern const char js_Infinity_str[];
 extern const char js_NaN_str[];
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -110,17 +110,17 @@
 #include "jsautooplen.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 JS_FRIEND_DATA(js::Shape) Shape::sharedNonNative(SHAPELESS);
 
-Class js::ObjectClass = {
+Class js_ObjectClass = {
     js_Object_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
@@ -1795,17 +1795,17 @@ PropDesc::initFromPropertyDescriptor(con
     }
     hasEnumerable = true;
     hasConfigurable = true;
 }
 
 bool
 PropDesc::makeObject(JSContext *cx)
 {
-    JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
     if (!obj)
         return false;
 
     const JSAtomState &atomState = cx->runtime->atomState;
     if ((hasConfigurable &&
          !obj->defineProperty(cx, ATOM_TO_JSID(atomState.configurableAtom),
                               BooleanValue((attrs & JSPROP_PERMANENT) == 0),
                               PropertyStub, StrictPropertyStub, JSPROP_ENUMERATE)) ||
@@ -2625,17 +2625,17 @@ obj_create(JSContext *cx, uintN argc, Va
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XML_PROTO_FORBIDDEN);
         return false;
     }
 
     /*
      * Use the callee's global as the parent of the new object to avoid dynamic
      * scoping (i.e., using the caller's global).
      */
-    JSObject *obj = NewNonFunction<WithProto::Given>(cx, &ObjectClass, proto,
+    JSObject *obj = NewNonFunction<WithProto::Given>(cx, &js_ObjectClass, proto,
                                                      vp->toObject().getGlobal());
     if (!obj)
         return JS_FALSE;
     vp->setObject(*obj); /* Root and prepare for eventual return. */
 
     /* Don't track types or array-ness for objects created here. */
     MarkTypeObjectUnknownProperties(cx, obj->type());
 
@@ -2908,18 +2908,18 @@ js_Object(JSContext *cx, uintN argc, Val
     } else {
         /* If argv[0] is null or undefined, obj comes back null. */
         if (!js_ValueToObjectOrNull(cx, vp[2], &obj))
             return JS_FALSE;
     }
     if (!obj) {
         /* Make an object whether this was called with 'new' or not. */
         JS_ASSERT(!argc || vp[2].isNull() || vp[2].isUndefined());
-        gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
-        obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
+        gc::AllocKind kind = NewObjectGCKind(cx, &js_ObjectClass);
+        obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
         if (!obj)
             return JS_FALSE;
         TypeObject *type = GetTypeCallerInitObject(cx, JSProto_Object);
         if (!type)
             return JS_FALSE;
         obj->setType(type);
     }
     vp->setObject(*obj);
@@ -2961,18 +2961,18 @@ js::NewReshapedObject(JSContext *cx, Typ
     return res;
 }
 
 JSObject*
 js_CreateThis(JSContext *cx, JSObject *callee)
 {
     Class *clasp = callee->getClass();
 
-    Class *newclasp = &ObjectClass;
-    if (clasp == &FunctionClass) {
+    Class *newclasp = &js_ObjectClass;
+    if (clasp == &js_FunctionClass) {
         JSFunction *fun = callee->getFunctionPrivate();
         if (fun->isNative() && fun->u.n.clasp)
             newclasp = fun->u.n.clasp;
     }
 
     Value protov;
     if (!callee->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &protov))
         return NULL;
@@ -2997,34 +2997,34 @@ CreateThisForFunctionWithType(JSContext 
          */
         gc::AllocKind kind = type->newScript->allocKind;
         JSObject *res = NewObjectWithType(cx, type, parent, kind);
         if (res)
             res->setMap((Shape *) type->newScript->shape);
         return res;
     }
 
-    gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
+    gc::AllocKind kind = NewObjectGCKind(cx, &js_ObjectClass);
     return NewObjectWithType(cx, type, parent, kind);
 }
 
 JSObject *
 js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto)
 {
     JSScript *calleeScript = callee->getFunctionPrivate()->script();
     JSObject *res;
 
     if (proto) {
         types::TypeObject *type = proto->getNewType(cx, calleeScript);
         if (!type)
             return NULL;
         res = CreateThisForFunctionWithType(cx, type, callee->getParent());
     } else {
-        gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
-        res = NewNonFunction<WithProto::Class>(cx, &ObjectClass, proto, callee->getParent(), kind);
+        gc::AllocKind kind = NewObjectGCKind(cx, &js_ObjectClass);
+        res = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, callee->getParent(), kind);
     }
 
     if (res && cx->typeInferenceEnabled())
         TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(res));
 
     return res;
 }
 
@@ -3060,30 +3060,30 @@ js_CreateThisForFunction(JSContext *cx, 
     return obj;
 }
 
 #ifdef JS_TRACER
 
 JSObject* FASTCALL
 js_Object_tn(JSContext* cx, JSObject* proto)
 {
-    JS_ASSERT(!(ObjectClass.flags & JSCLASS_HAS_PRIVATE));
-    return NewObjectWithClassProto(cx, &ObjectClass, proto, FINALIZE_OBJECT8);
+    JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
+    return NewObjectWithClassProto(cx, &js_ObjectClass, proto, FINALIZE_OBJECT8);
 }
 
 JS_DEFINE_TRCINFO_1(js_Object,
     (2, (extern, CONSTRUCTOR_RETRY, js_Object_tn, CONTEXT, CALLEE_PROTOTYPE, 0,
          nanojit::ACCSET_STORE_ANY)))
 
 JSObject* FASTCALL
 js_InitializerObject(JSContext* cx, JSObject *proto, JSObject *baseobj)
 {
     if (!baseobj) {
         gc::AllocKind kind = GuessObjectGCKind(0, false);
-        return NewObjectWithClassProto(cx, &ObjectClass, proto, kind);
+        return NewObjectWithClassProto(cx, &js_ObjectClass, proto, kind);
     }
 
     /* :FIXME: bug 637856 new Objects do not have the right type when created on trace. */
     TypeObject *type = proto->getNewType(cx);
     if (!type)
         return NULL;
 
     return CopyInitializerObject(cx, baseobj, type);
@@ -3124,18 +3124,18 @@ js_CreateThisFromTrace(JSContext *cx, JS
         /*
          * GetInterpretedFunctionPrototype found that ctor.prototype is
          * primitive. Use Object.prototype for proto, per ES5 13.2.2 step 7.
          */
         if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
             return NULL;
     }
 
-    gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
-    return NewNativeClassInstance(cx, &ObjectClass, proto, parent, kind);
+    gc::AllocKind kind = NewObjectGCKind(cx, &js_ObjectClass);
+    return NewNativeClassInstance(cx, &js_ObjectClass, proto, parent, kind);
 }
 JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, OBJECT, UINTN, 0,
                      nanojit::ACCSET_STORE_ANY)
 
 #else  /* !JS_TRACER */
 
 # define js_Object_trcinfo NULL
 
@@ -3304,17 +3304,17 @@ with_TypeOf(JSContext *cx, JSObject *obj
 }
 
 static JSObject *
 with_ThisObject(JSContext *cx, JSObject *obj)
 {
     return obj->getWithThis();
 }
 
-Class js::WithClass = {
+Class js_WithClass = {
     "With",
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
@@ -3354,17 +3354,17 @@ js_NewWithObject(JSContext *cx, JSObject
         return NULL;
 
     obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!obj)
         return NULL;
 
     StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
 
-    obj->init(cx, &WithClass, type, parent, priv, false);
+    obj->init(cx, &js_WithClass, type, parent, priv, false);
 
     EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx);
     if (!emptyWithShape)
         return NULL;
 
     obj->setMap(emptyWithShape);
     OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
 
@@ -3388,17 +3388,17 @@ js_NewBlockObject(JSContext *cx)
      */
     JSObject *blockObj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!blockObj)
         return NULL;
 
     EmptyShape *emptyBlockShape = EmptyShape::getEmptyBlockShape(cx);
     if (!emptyBlockShape)
         return NULL;
-    blockObj->init(cx, &BlockClass, &emptyTypeObject, NULL, NULL, false);
+    blockObj->init(cx, &js_BlockClass, &emptyTypeObject, NULL, NULL, false);
     blockObj->setMap(emptyBlockShape);
 
     return blockObj;
 }
 
 JSObject *
 js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp)
 {
@@ -3478,17 +3478,17 @@ block_getProperty(JSContext *cx, JSObjec
         fp = js_LiveFrameIfGenerator(fp);
         index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
         JS_ASSERT(index < fp->numSlots());
         *vp = fp->slots()[index];
         return true;
     }
 
     /* Values are in slots immediately following the class-reserved ones. */
-    JS_ASSERT(obj->getSlot(JSSLOT_FREE(&BlockClass) + index) == *vp);
+    JS_ASSERT(obj->getSlot(JSSLOT_FREE(&js_BlockClass) + index) == *vp);
     return true;
 }
 
 static JSBool
 block_setProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
     JS_ASSERT(obj->isClonedBlock());
     uintN index = (uintN) JSID_TO_INT(id);
@@ -3511,17 +3511,17 @@ block_setProperty(JSContext *cx, JSObjec
 }
 
 const Shape *
 JSObject::defineBlockVariable(JSContext *cx, jsid id, intN index)
 {
     JS_ASSERT(isStaticBlock());
 
     /* Use JSPROP_ENUMERATE to aid the disassembler. */
-    uint32 slot = JSSLOT_FREE(&BlockClass) + index;
+    uint32 slot = JSSLOT_FREE(&js_BlockClass) + index;
     const Shape *shape = addProperty(cx, id,
                                      block_getProperty, block_setProperty,
                                      slot, JSPROP_ENUMERATE | JSPROP_PERMANENT,
                                      Shape::HAS_SHORTID, index);
     if (!shape)
         return NULL;
     if (slot >= numSlots() && !growSlots(cx, slot + 1))
         return NULL;
@@ -3980,32 +3980,32 @@ js_XDRBlockObject(JSXDRState *xdr, JSObj
                 return false;
         }
     }
     return true;
 }
 
 #endif
 
-Class js::BlockClass = {
+Class js_BlockClass = {
     "Block",
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub
 };
 
 JSObject *
 js_InitObjectClass(JSContext *cx, JSObject *obj)
 {
-    JSObject *proto = js_InitClass(cx, obj, NULL, &ObjectClass, js_Object, 1,
+    JSObject *proto = js_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1,
                                    object_props, object_methods, NULL, object_static_methods);
     if (!proto)
         return NULL;
 
     /* The default 'new' object for Object.prototype has unknown properties. */
     proto->getNewType(cx, NULL, /* markUnknown = */ true);
 
     /* ECMA (15.1.2.1) says 'eval' is a property of the global object. */
@@ -4097,20 +4097,20 @@ DefineConstructorAndPrototype(JSContext 
      * 1. NewObject attempting to compute a default prototype object when
      *    passed null for proto; and
      *
      * 2. NewObject tolerating no default prototype (null proto slot value)
      *    due to this js_InitClass call coming from js_InitFunctionClass on an
      *    otherwise-uninitialized global.
      *
      * 3. NewObject allocating a JSFunction-sized GC-thing when clasp is
-     *    &FunctionClass, not a JSObject-sized (smaller) GC-thing.
+     *    &js_FunctionClass, not a JSObject-sized (smaller) GC-thing.
      *
      * The JS_NewObjectForGivenProto and JS_NewObject APIs also allow clasp to
-     * be &FunctionClass (we could break compatibility easily). But fixing
+     * be &js_FunctionClass (we could break compatibility easily). But fixing
      * (3) is not enough without addressing the bootstrapping dependency on (1)
      * and (2).
      */
 
     /*
      * Create the prototype object.  (GlobalObject::createBlankPrototype isn't
      * used because it parents the prototype object to the global and because
      * it uses WithProto::Given.  FIXME: Undo dependencies on this parentage
@@ -4119,17 +4119,17 @@ DefineConstructorAndPrototype(JSContext 
      */
     JSObject *proto = NewObject<WithProto::Class>(cx, clasp, protoProto, obj);
     if (!proto)
         return NULL;
 
     if (!proto->setSingletonType(cx))
         return NULL;
 
-    if (clasp == &ArrayClass && !proto->makeDenseArraySlow(cx))
+    if (clasp == &js_ArrayClass && !proto->makeDenseArraySlow(cx))
         return NULL;
 
     TypeObject *type = proto->getNewType(cx);
     if (!type || !type->getEmptyShape(cx, proto->getClass(), FINALIZE_OBJECT0))
         return NULL;
 
     proto->syncSpecialEquality();
 
@@ -5093,17 +5093,17 @@ DefineNativeProperty(JSContext *cx, JSOb
      * value to define, and just so addProperty can mutate its inout parameter.
      */
     Value valueCopy = value;
     bool adding = false;
 
     if (!shape) {
         /* Add a new property, or replace an existing one of the same id. */
         if (defineHow & DNP_SET_METHOD) {
-            JS_ASSERT(clasp == &ObjectClass);
+            JS_ASSERT(clasp == &js_ObjectClass);
             JS_ASSERT(IsFunctionObject(value));
             JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
             JS_ASSERT(!getter && !setter);
 
             JSObject *funobj = &value.toObject();
             if (funobj->getFunctionPrivate() == funobj) {
                 flags |= Shape::METHOD;
                 getter = CastAsPropertyOp(funobj);
@@ -5395,19 +5395,20 @@ js_FindPropertyHelper(JSContext *cx, jsi
          : !obj->getOps()->lookupProperty;
          ++scopeIndex) {
         if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
             return NULL;
 
         if (prop) {
 #ifdef DEBUG
             if (parent) {
+                Class *clasp = obj->getClass();
                 JS_ASSERT(pobj->isNative());
-                JS_ASSERT(pobj->getClass() == obj->getClass());
-                if (obj->isBlock()) {
+                JS_ASSERT(pobj->getClass() == clasp);
+                if (clasp == &js_BlockClass) {
                     /*
                      * A block instance on the scope chain is immutable and
                      * shares its shape with the compile-time prototype. Thus
                      * we cannot find any property on the prototype.
                      */
                     JS_ASSERT(pobj->isClonedBlock());
                 } else {
                     /* Call and DeclEnvClass objects have no prototypes. */
@@ -6290,19 +6291,19 @@ JSBool
 DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
 {
     JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
     JS_ASSERT(!obj->isXML());
 
     Class *clasp = obj->getClass();
     if (hint == JSTYPE_STRING) {
         /* Optimize (new String(...)).toString(). */
-        if (clasp == &StringClass &&
+        if (clasp == &js_StringClass &&
             ClassMethodIsNative(cx, obj,
-                                 &StringClass,
+                                 &js_StringClass,
                                  ATOM_TO_JSID(cx->runtime->atomState.toStringAtom),
                                  js_str_toString)) {
             *vp = obj->getPrimitiveThis();
             return true;
         }
 
         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), vp))
             return false;
@@ -6310,22 +6311,22 @@ DefaultValue(JSContext *cx, JSObject *ob
             return true;
 
         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom), vp))
             return false;
         if (vp->isPrimitive())
             return true;
     } else {
         /* Optimize (new String(...)).valueOf(). */
-        if ((clasp == &StringClass &&
-             ClassMethodIsNative(cx, obj, &StringClass,
+        if ((clasp == &js_StringClass &&
+             ClassMethodIsNative(cx, obj, &js_StringClass,
                                  ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom),
                                  js_str_toString)) ||
-            (clasp == &NumberClass &&
-             ClassMethodIsNative(cx, obj, &NumberClass,
+            (clasp == &js_NumberClass &&
+             ClassMethodIsNative(cx, obj, &js_NumberClass,
                                  ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom),
                                  js_num_valueOf))) {
             *vp = obj->getPrimitiveThis();
             return true;
         }
 
         if (!MaybeCallMethod(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom), vp))
             return false;
@@ -6384,17 +6385,17 @@ CheckAccess(JSContext *cx, JSObject *obj
     JSBool writing;
     JSObject *pobj;
     JSProperty *prop;
     Class *clasp;
     const Shape *shape;
     JSSecurityCallbacks *callbacks;
     CheckAccessOp check;
 
-    while (JS_UNLIKELY(obj->isWith()))
+    while (JS_UNLIKELY(obj->getClass() == &js_WithClass))
         obj = obj->getProto();
 
     writing = (mode & JSACC_WRITE) != 0;
     switch (mode & JSACC_TYPEMASK) {
       case JSACC_PROTO:
         pobj = obj;
         if (!writing)
             vp->setObjectOrNull(obj->getProto());
@@ -6536,17 +6537,17 @@ js_GetClassPrototype(JSContext *cx, JSOb
 
 JSObject *
 PrimitiveToObject(JSContext *cx, const Value &v)
 {
     if (v.isString())
         return StringObject::create(cx, v.toString());
 
     JS_ASSERT(v.isNumber() || v.isBoolean());
-    Class *clasp = v.isNumber() ? &NumberClass : &BooleanClass;
+    Class *clasp = v.isNumber() ? &js_NumberClass : &js_BooleanClass;
     JSObject *obj = NewBuiltinClassInstance(cx, clasp);
     if (!obj)
         return NULL;
 
     obj->setPrimitiveThis(v);
     return obj;
 }
 
@@ -6934,17 +6935,17 @@ dumpValue(const Value &v)
                     script->filename ? script->filename : "", script->lineno);
         }
         fprintf(stderr, " at %p (JSFunction at %p)>", (void *) funobj, (void *) fun);
     } else if (v.isObject()) {
         JSObject *obj = &v.toObject();
         Class *clasp = obj->getClass();
         fprintf(stderr, "<%s%s at %p>",
                 clasp->name,
-                (clasp == &ObjectClass) ? "" : " object",
+                (clasp == &js_ObjectClass) ? "" : " object",
                 (void *) obj);
     } else if (v.isBoolean()) {
         if (v.toBoolean())
             fprintf(stderr, "true");
         else
             fprintf(stderr, "false");
     } else if (v.isMagic()) {
         fprintf(stderr, "<invalid");
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -54,25 +54,21 @@
 #include "jshash.h"
 #include "jspubtd.h"
 #include "jsprvtd.h"
 #include "jslock.h"
 #include "jsvalue.h"
 #include "jsvector.h"
 #include "jscell.h"
 
-namespace nanojit { class ValidateWriter; }
-
 namespace js {
 
+class JSProxyHandler;
 class AutoPropDescArrayRooter;
-class JSProxyHandler;
-class RegExp;
 struct GCMarker;
-struct NativeIterator;
 
 namespace mjit { class Compiler; }
 
 static inline PropertyOp
 CastAsPropertyOp(JSObject *object)
 {
     return JS_DATA_TO_FUNC_PTR(PropertyOp, object);
 }
@@ -283,64 +279,36 @@ extern JS_FRIEND_API(JSBool)
 js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
              js::Value *statep, jsid *idp);
 
 extern JSType
 js_TypeOf(JSContext *cx, JSObject *obj);
 
 namespace js {
 
+struct NativeIterator;
+class RegExp;
+
+class GlobalObject;
+class ArgumentsObject;
+class NormalArgumentsObject;
+class StrictArgumentsObject;
+class StringObject;
+
 /* ES5 8.12.8. */
 extern JSBool
 DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp);
 
-extern JS_FRIEND_DATA(Class) AnyNameClass;
-extern JS_FRIEND_DATA(Class) AttributeNameClass;
-extern JS_FRIEND_DATA(Class) CallClass;
-extern JS_FRIEND_DATA(Class) DeclEnvClass;
-extern JS_FRIEND_DATA(Class) FunctionClass;
-extern JS_FRIEND_DATA(Class) FunctionProxyClass;
-extern JS_FRIEND_DATA(Class) NamespaceClass;
-extern JS_FRIEND_DATA(Class) OuterWindowProxyClass;
-extern JS_FRIEND_DATA(Class) ObjectProxyClass;
-extern JS_FRIEND_DATA(Class) QNameClass;
-extern JS_FRIEND_DATA(Class) ScriptClass;
-extern JS_FRIEND_DATA(Class) XMLClass;
+}
+
+struct JSFunction;
 
-extern Class ArrayClass;
-extern Class ArrayBufferClass;
-extern Class BlockClass;
-extern Class BooleanClass;
-extern Class CallableObjectClass;
-extern Class DateClass;
-extern Class ErrorClass;
-extern Class GeneratorClass;
-extern Class IteratorClass;
-extern Class JSONClass;
-extern Class MathClass;
-extern Class NumberClass;
-extern Class NormalArgumentsObjectClass;
-extern Class ObjectClass;
-extern Class ProxyClass;
-extern Class RegExpClass;
-extern Class SlowArrayClass;
-extern Class StopIterationClass;
-extern Class StringClass;
-extern Class StrictArgumentsObjectClass;
-extern Class WeakMapClass;
-extern Class WithClass;
-extern Class XMLFilterClass;
-
-class ArgumentsObject;
-class GlobalObject;
-class NormalArgumentsObject;
-class StrictArgumentsObject;
-class StringObject;
-
-}  /* namespace js */
+namespace nanojit {
+class ValidateWriter;
+}
 
 /*
  * JSObject struct, with members sized to fit in 32 bytes on 32-bit targets,
  * 64 bytes on 64-bit systems. The JSFunction struct is an extension of this
  * struct allocated from a larger GC size-class.
  *
  * The clasp member stores the js::Class pointer for this object.
  *
@@ -403,19 +371,19 @@ struct JSObject : js::gc::Cell {
     friend class nanojit::ValidateWriter;
 
     /*
      * Private pointer to the last added property and methods to manipulate the
      * list it links among properties in this scope.
      */
     js::Shape           *lastProp;
 
-  private:
     js::Class           *clasp;
 
+  private:
     inline void setLastProperty(const js::Shape *shape);
     inline void removeLastProperty();
 
     /* For setLastProperty() only. */
     friend class js::StringObject;
 
 #ifdef DEBUG
     void checkShapeConsistency();
@@ -497,17 +465,16 @@ struct JSObject : js::gc::Cell {
     /* Make the type object to use for LAZY_TYPE objects. */
     void makeLazyType(JSContext *cx);
 
   public:
 
     inline bool isNative() const;
     inline bool isNewborn() const;
 
-    void setClass(js::Class *c) { clasp = c; }
     js::Class *getClass() const { return clasp; }
     JSClass *getJSClass() const { return Jsvalify(clasp); }
 
     bool hasClass(const js::Class *c) const {
         return c == clasp;
     }
 
     const js::ObjectOps *getOps() const {
@@ -1226,20 +1193,20 @@ struct JSObject : js::gc::Cell {
     inline JSScript *getScript() const;
 
     /*
      * XML-related getters and setters.
      */
 
     /*
      * Slots for XML-related classes are as follows:
-     * - NamespaceClass.base reserves the *_NAME_* and *_NAMESPACE_* slots.
-     * - QNameClass.base, AttributeNameClass, AnyNameClass reserve
+     * - js_NamespaceClass.base reserves the *_NAME_* and *_NAMESPACE_* slots.
+     * - js_QNameClass.base, js_AttributeNameClass, js_AnyNameClass reserve
      *   the *_NAME_* and *_QNAME_* slots.
-     * - Others (XMLClass, js_XMLFilterClass) don't reserve any slots.
+     * - Others (js_XMLClass, js_XMLFilterClass) don't reserve any slots.
      */
   private:
     static const uint32 JSSLOT_NAME_PREFIX          = 0;   // shared
     static const uint32 JSSLOT_NAME_URI             = 1;   // shared
 
     static const uint32 JSSLOT_NAMESPACE_DECLARED   = 2;
 
     static const uint32 JSSLOT_QNAME_LOCAL_NAME     = 2;
@@ -1459,67 +1426,53 @@ struct JSObject : js::gc::Cell {
     JS_FRIEND_API(JSObject *) clone(JSContext *cx, JSObject *proto, JSObject *parent);
     JS_FRIEND_API(bool) copyPropertiesFrom(JSContext *cx, JSObject *obj);
     bool swap(JSContext *cx, JSObject *other);
 
     const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index);
 
     inline bool canHaveMethodBarrier() const;
 
-    inline bool isArguments() const { return isNormalArguments() || isStrictArguments(); }
-    inline bool isArrayBuffer() const { return clasp == &js::ArrayBufferClass; }
-    inline bool isNormalArguments() const { return clasp == &js::NormalArgumentsObjectClass; }
-    inline bool isStrictArguments() const { return clasp == &js::StrictArgumentsObjectClass; }
-    inline bool isArray() const { return isSlowArray() || isDenseArray(); }
-    inline bool isDenseArray() const { return clasp == &js::ArrayClass; }
-    inline bool isSlowArray() const { return clasp == &js::SlowArrayClass; }
-    inline bool isNumber() const { return clasp == &js::NumberClass; }
-    inline bool isBoolean() const { return clasp == &js::BooleanClass; }
-    inline bool isString() const { return clasp == &js::StringClass; }
-    inline bool isPrimitive() const { return isNumber() || isString() || isBoolean(); }
-    inline bool isDate() const { return clasp == &js::DateClass; }
-    inline bool isFunction() const { return clasp == &js::FunctionClass; }
-    inline bool isObject() const { return clasp == &js::ObjectClass; }
-    inline bool isWith() const { return clasp == &js::WithClass; }
-    inline bool isBlock() const { return clasp == &js::BlockClass; }
-    inline bool isStaticBlock() const { return isBlock() && !getProto(); }
-    inline bool isClonedBlock() const { return isBlock() && !!getProto(); }
-    inline bool isCall() const { return clasp == &js::CallClass; }
-    inline bool isDeclEnv() const { return clasp == &js::DeclEnvClass; }
-    inline bool isRegExp() const { return clasp == &js::RegExpClass; }
-    inline bool isScript() const { return clasp == &js::ScriptClass; }
-    inline bool isGenerator() const { return clasp == &js::GeneratorClass; }
-    inline bool isIterator() const { return clasp == &js::IteratorClass; }
-    inline bool isStopIteration() const { return clasp == &js::StopIterationClass; }
-    inline bool isError() const { return clasp == &js::ErrorClass; }
-    inline bool isXML() const { return clasp == &js::XMLClass; }
-    inline bool isNamespace() const { return clasp == &js::NamespaceClass; }
-    inline bool isWeakMap() const { return clasp == &js::WeakMapClass; }
-    inline bool isFunctionProxy() const { return clasp == &js::FunctionProxyClass; }
-    inline bool isProxy() const { return isObjectProxy() || isFunctionProxy(); }
+    inline bool isArguments() const;
+    inline bool isNormalArguments() const;
+    inline bool isStrictArguments() const;
+    inline bool isArray() const;
+    inline bool isDenseArray() const;
+    inline bool isSlowArray() const;
+    inline bool isNumber() const;
+    inline bool isBoolean() const;
+    inline bool isString() const;
+    inline bool isPrimitive() const;
+    inline bool isDate() const;
+    inline bool isFunction() const;
+    inline bool isObject() const;
+    inline bool isWith() const;
+    inline bool isBlock() const;
+    inline bool isStaticBlock() const;
+    inline bool isClonedBlock() const;
+    inline bool isCall() const;
+    inline bool isRegExp() const;
+    inline bool isScript() const;
+    inline bool isError() const;
+    inline bool isXML() const;
+    inline bool isXMLId() const;
+    inline bool isNamespace() const;
+    inline bool isQName() const;
+    inline bool isWeakMap() const;
 
-    inline bool isXMLId() const {
-        return clasp == &js::QNameClass || clasp == &js::AttributeNameClass || clasp == &js::AnyNameClass;
-    }
-    inline bool isQName() const {
-        return clasp == &js::QNameClass || clasp == &js::AttributeNameClass || clasp == &js::AnyNameClass;
-    }
-    inline bool isObjectProxy() const {
-        return clasp == &js::ObjectProxyClass || clasp == &js::OuterWindowProxyClass;
-    }
+    inline bool isProxy() const;
+    inline bool isObjectProxy() const;
+    inline bool isFunctionProxy() const;
+    inline bool isArrayBuffer() const;
 
     JS_FRIEND_API(bool) isWrapper() const;
     bool isCrossCompartmentWrapper() const;
     JS_FRIEND_API(JSObject *) unwrap(uintN *flagsp = NULL);
 
     inline void initArrayClass();
-
-    /*** For jit compiler: ***/
-
-    static size_t offsetOfClassPointer() { return offsetof(JSObject, clasp); }
 };
 
 /* Check alignment for any fixed slots allocated after the object. */
 JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(js::Value) == 0);
 
 /*
  * The only sensible way to compare JSObject with == is by identity. We use
  * const& instead of * as a syntactic way to assert non-null. This leads to an
@@ -1608,18 +1561,52 @@ class JSValueArray {
 class ValueArray {
   public:
     js::Value *array;
     size_t length;
 
     ValueArray(js::Value *v, size_t c) : array(v), length(c) {}
 };
 
+extern js::Class js_ArrayClass, js_SlowArrayClass, js_ArrayBufferClass;
+
+inline bool
+JSObject::isDenseArray() const
+{
+    return getClass() == &js_ArrayClass;
+}
+
+inline bool
+JSObject::isSlowArray() const
+{
+    return getClass() == &js_SlowArrayClass;
+}
+
+inline bool
+JSObject::isArray() const
+{
+    return isDenseArray() || isSlowArray();
+}
+
+inline bool
+JSObject::isArrayBuffer() const
+{
+    return getClass() == &js_ArrayBufferClass;
+}
+
+extern js::Class js_ObjectClass;
+extern js::Class js_WithClass;
+extern js::Class js_BlockClass;
+
+inline bool JSObject::isObject() const { return getClass() == &js_ObjectClass; }
+inline bool JSObject::isWith() const   { return getClass() == &js_WithClass; }
+inline bool JSObject::isBlock() const  { return getClass() == &js_BlockClass; }
+
 /*
- * Block scope object macros.  The slots reserved by BlockClass are:
+ * Block scope object macros.  The slots reserved by js_BlockClass are:
  *
  *   private              StackFrame *      active frame pointer or null
  *   JSSLOT_BLOCK_DEPTH   int               depth of block slots in frame
  *
  * After JSSLOT_BLOCK_DEPTH come one or more slots for the block locals.
  *
  * A With object is like a Block object, in that both have one reserved slot
  * telling the stack depth of the relevant slots (the slot whose value is the
@@ -1833,16 +1820,19 @@ extern const js::Shape *
 js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
                              const js::Shape *shape, uintN attrs, uintN mask,
                              js::PropertyOp getter, js::StrictPropertyOp setter);
 
 extern JSBool
 js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id,
                      const js::Value &descriptor, JSBool *bp);
 
+extern JS_FRIEND_DATA(js::Class) js_CallClass;
+extern JS_FRIEND_DATA(js::Class) js_DeclEnvClass;
+
 namespace js {
 
 /*
  * Flags for the defineHow parameter of js_DefineNativeProperty.
  */
 const uintN DNP_CACHE_RESULT = 1;   /* an interpreter call from JSOP_INITPROP */
 const uintN DNP_DONT_PURGE   = 2;   /* suppress js_PurgeScopeChain */
 const uintN DNP_SET_METHOD   = 4;   /* DefineNativeProperty,js_SetPropertyHelper
@@ -1901,19 +1891,19 @@ static const uintN RESOLVE_INFER = 0xfff
  * see bug 462734 and bug 487039.
  */
 static inline bool
 IsCacheableNonGlobalScope(JSObject *obj)
 {
     JS_ASSERT(obj->getParent());
 
     js::Class *clasp = obj->getClass();
-    bool cacheable = (clasp == &CallClass ||
-                      clasp == &BlockClass ||
-                      clasp == &DeclEnvClass);
+    bool cacheable = (clasp == &js_CallClass ||
+                      clasp == &js_BlockClass ||
+                      clasp == &js_DeclEnvClass);
 
     JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
     return cacheable;
 }
 
 }
 
 /*
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -193,17 +193,17 @@ JSObject::finalize(JSContext *cx)
 
 /* 
  * Initializer for Call objects for functions and eval frames. Set class,
  * parent, map, and shape, and allocate slots.
  */
 inline void
 JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent)
 {
-    init(cx, &js::CallClass, &js::types::emptyTypeObject, parent, NULL, false);
+    init(cx, &js_CallClass, &js::types::emptyTypeObject, parent, NULL, false);
     lastProp = bindings.lastShape();
 
     /*
      * If |bindings| is for a function that has extensible parents, that means
      * its Call should have its own shape; see js::Bindings::extensibleParents.
      */
     if (bindings.extensibleParents())
         setOwnShape(js_GenerateShape(cx));
@@ -213,17 +213,17 @@ JSObject::initCall(JSContext *cx, const 
 
 /*
  * Initializer for cloned block objects. Set class, prototype, frame, map, and
  * shape.
  */
 inline void
 JSObject::initClonedBlock(JSContext *cx, js::types::TypeObject *type, js::StackFrame *frame)
 {
-    init(cx, &js::BlockClass, type, NULL, frame, false);
+    init(cx, &js_BlockClass, type, NULL, frame, false);
 
     /* Cloned blocks copy their prototype's map; it had better be shareable. */
     JS_ASSERT(!getProto()->inDictionaryMode() || getProto()->lastProp->frozen());
     lastProp = getProto()->lastProp;
 
     /*
      * If the prototype has its own shape, that means the clone should, too; see
      * js::Bindings::extensibleParents.
@@ -377,16 +377,22 @@ JSObject::setReservedSlot(uintN index, c
 }
 
 inline bool
 JSObject::canHaveMethodBarrier() const
 {
     return isObject() || isFunction() || isPrimitive() || isDate();
 }
 
+inline bool
+JSObject::isPrimitive() const
+{
+    return isNumber() || isString() || isBoolean();
+}
+
 inline const js::Value &
 JSObject::getPrimitiveThis() const
 {
     JS_ASSERT(isPrimitive());
     return getFixedSlot(JSSLOT_PRIMITIVE_THIS);
 }
 
 inline void
@@ -900,17 +906,17 @@ JSObject::setType(js::types::TypeObject 
 
 inline void
 JSObject::init(JSContext *cx, js::Class *aclasp, js::types::TypeObject *type,
                JSObject *parent, void *priv, bool denseArray)
 {
     clasp = aclasp;
     flags = capacity << FIXED_SLOTS_SHIFT;
 
-    JS_ASSERT(denseArray == (aclasp == &js::ArrayClass));
+    JS_ASSERT(denseArray == (aclasp == &js_ArrayClass));
 
 #ifdef DEBUG
     /*
      * NB: objShape must not be set here; rather, the caller must call setMap
      * or setSharedNonNativeMap after calling init. To defend this requirement
      * we set objShape to a value that obj->shape() is asserted never to return.
      */
     objShape = INVALID_SHAPE;
@@ -1157,20 +1163,32 @@ JSObject::setSharedNonNativeMap()
 }
 
 static inline bool
 js_IsCallable(const js::Value &v)
 {
     return v.isObject() && v.toObject().isCallable();
 }
 
+inline bool
+JSObject::isStaticBlock() const
+{
+    return isBlock() && !getProto();
+}
+
+inline bool
+JSObject::isClonedBlock() const
+{
+    return isBlock() && !!getProto();
+}
+
 inline JSObject *
 js_UnwrapWithObject(JSContext *cx, JSObject *withobj)
 {
-    JS_ASSERT(withobj->isWith());
+    JS_ASSERT(withobj->getClass() == &js_WithClass);
     return withobj->getProto();
 }
 
 namespace js {
 
 class AutoPropDescArrayRooter : private AutoGCRooter
 {
   public:
@@ -1296,17 +1314,17 @@ NewNativeClassInstance(JSContext *cx, Cl
 
     JSObject* obj = js_NewGCObject(cx, kind);
 
     if (obj) {
         /*
          * Default parent to the parent of the prototype, which was set from
          * the parent of the prototype's constructor.
          */
-        bool denseArray = (clasp == &ArrayClass);
+        bool denseArray = (clasp == &js_ArrayClass);
         obj->init(cx, clasp, type, parent, NULL, denseArray);
 
         JS_ASSERT(type->canProvideEmptyShape(clasp));
         js::EmptyShape *empty = type->getEmptyShape(cx, clasp, kind);
 
         if (empty)
             obj->setMap(empty);
         else
@@ -1464,17 +1482,17 @@ NewObject(JSContext *cx, js::Class *clas
     JS_ASSERT_IF(isFunction, kind == gc::FINALIZE_OBJECT2);
 
     /*
      * Default parent to the parent of the prototype, which was set from
      * the parent of the prototype's constructor.
      */
     obj->init(cx, clasp, type,
               (!parent && proto) ? proto->getParent() : parent,
-              NULL, clasp == &ArrayClass);
+              NULL, clasp == &js_ArrayClass);
 
     if (clasp->isNative()) {
         if (!InitScopeForObject(cx, obj, clasp, type, kind)) {
             obj = NULL;
             goto out;
         }
     } else {
         obj->setSharedNonNativeMap();
@@ -1487,24 +1505,24 @@ out:
 } /* namespace detail */
 
 static JS_ALWAYS_INLINE JSObject *
 NewFunction(JSContext *cx, js::GlobalObject &global)
 {
     JSObject *proto;
     if (!js_GetClassPrototype(cx, &global, JSProto_Function, &proto))
         return NULL;
-    return detail::NewObject<WithProto::Given, true>(cx, &FunctionClass, proto, &global,
+    return detail::NewObject<WithProto::Given, true>(cx, &js_FunctionClass, proto, &global,
                                                      gc::FINALIZE_OBJECT2);
 }
 
 static JS_ALWAYS_INLINE JSObject *
 NewFunction(JSContext *cx, JSObject *parent)
 {
-    return detail::NewObject<WithProto::Class, true>(cx, &FunctionClass, NULL, parent,
+    return detail::NewObject<WithProto::Class, true>(cx, &js_FunctionClass, NULL, parent,
                                                      gc::FINALIZE_OBJECT2);
 }
 
 template <WithProto::e withProto>
 static JS_ALWAYS_INLINE JSObject *
 NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
                gc::AllocKind kind)
 {
@@ -1519,17 +1537,17 @@ NewNonFunction(JSContext *cx, js::Class 
     return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
 }
 
 template <WithProto::e withProto>
 static JS_ALWAYS_INLINE JSObject *
 NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
           gc::AllocKind kind)
 {
-    if (clasp == &FunctionClass)
+    if (clasp == &js_FunctionClass)
         return detail::NewObject<withProto, true>(cx, clasp, proto, parent, kind);
     return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
 }
 
 template <WithProto::e withProto>
 static JS_ALWAYS_INLINE JSObject *
 NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
 {
@@ -1541,32 +1559,32 @@ NewObject(JSContext *cx, js::Class *clas
  * Create a plain object with the specified type. This bypasses getNewType to
  * avoid losing creation site information for objects made by scripted 'new'.
  */
 static JS_ALWAYS_INLINE JSObject *
 NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::AllocKind kind)
 {
     JS_ASSERT(type == type->proto->newType);
 
-    if (CanBeFinalizedInBackground(kind, &ObjectClass))
+    if (CanBeFinalizedInBackground(kind, &js_ObjectClass))
         kind = GetBackgroundAllocKind(kind);
 
     JSObject* obj = js_NewGCObject(cx, kind);
     if (!obj)
         goto out;
 
     /*
      * Default parent to the parent of the prototype, which was set from
      * the parent of the prototype's constructor.
      */
-    obj->init(cx, &ObjectClass, type,
+    obj->init(cx, &js_ObjectClass, type,
               (!parent && type->proto) ? type->proto->getParent() : parent,
               NULL, false);
 
-    if (!InitScopeForObject(cx, obj, &ObjectClass, type, kind)) {
+    if (!InitScopeForObject(cx, obj, &js_ObjectClass, type, kind)) {
         obj = NULL;
         goto out;
     }
 
 out:
     Probes::createObject(cx, obj);
     return obj;
 }
@@ -1590,19 +1608,19 @@ GuessObjectGCKind(size_t numSlots, bool 
 
 /*
  * Get the GC kind to use for scripted 'new' on the given class.
  * FIXME bug 547327: estimate the size from the allocation site.
  */
 static inline gc::AllocKind
 NewObjectGCKind(JSContext *cx, js::Class *clasp)
 {
-    if (clasp == &ArrayClass || clasp == &SlowArrayClass)
+    if (clasp == &js_ArrayClass || clasp == &js_SlowArrayClass)
         return gc::FINALIZE_OBJECT8;
-    if (clasp == &FunctionClass)
+    if (clasp == &js_FunctionClass)
         return gc::FINALIZE_OBJECT2;
     return gc::FINALIZE_OBJECT4;
 }
 
 static JS_ALWAYS_INLINE JSObject*
 NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto,
                         gc::AllocKind kind)
 {
@@ -1623,20 +1641,20 @@ NewObjectWithClassProto(JSContext *cx, C
         return NULL;
     return obj;
 }
 
 /* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
 static inline JSObject *
 CopyInitializerObject(JSContext *cx, JSObject *baseobj, types::TypeObject *type)
 {
-    JS_ASSERT(baseobj->getClass() == &ObjectClass);
+    JS_ASSERT(baseobj->getClass() == &js_ObjectClass);
     JS_ASSERT(!baseobj->inDictionaryMode());
 
-    JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, baseobj->getAllocKind());
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, baseobj->getAllocKind());
 
     if (!obj || !obj->ensureSlots(cx, baseobj->numSlots()))
         return NULL;
 
     obj->setType(type);
     obj->flags = baseobj->flags;
     obj->lastProp = baseobj->lastProp;
     obj->objShape = baseobj->objShape;
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -69,17 +69,17 @@
 #include "jsstrinlines.h"
 
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
-Class js::JSONClass = {
+Class js_JSONClass = {
     js_JSON_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_JSON),
     PropertyStub,        /* addProperty */
     PropertyStub,        /* delProperty */
     PropertyStub,        /* getProperty */
     StrictPropertyStub,  /* setProperty */
     EnumerateStub,
     ResolveStub,
@@ -339,27 +339,27 @@ PreprocessValue(JSContext *cx, JSObject 
             return false;
         *vp = args.rval();
     }
 
     /* Step 4. */
     if (vp->isObject()) {
         JSObject *obj = &vp->toObject();
         Class *clasp = obj->getClass();
-        if (clasp == &NumberClass) {
+        if (clasp == &js_NumberClass) {
             double d;
             if (!ToNumber(cx, *vp, &d))
                 return false;
             vp->setNumber(d);
-        } else if (clasp == &StringClass) {
+        } else if (clasp == &js_StringClass) {
             JSString *str = js_ValueToString(cx, *vp);
             if (!str)
                 return false;
             vp->setString(str);
-        } else if (clasp == &BooleanClass) {
+        } else if (clasp == &js_BooleanClass) {
             *vp = obj->getPrimitiveThis();
             JS_ASSERT(vp->isBoolean());
         }
     }
 
     return true;
 }
 
@@ -720,17 +720,17 @@ js_Stringify(JSContext *cx, Value *vp, J
         if (!gap.append(str->chars(), len))
             return false;
     } else {
         /* Step 8. */
         JS_ASSERT(gap.empty());
     }
 
     /* Step 9. */
-    JSObject *wrapper = NewBuiltinClassInstance(cx, &ObjectClass);
+    JSObject *wrapper = NewBuiltinClassInstance(cx, &js_ObjectClass);
     if (!wrapper)
         return false;
 
     /* Step 10. */
     jsid emptyId = ATOM_TO_JSID(cx->runtime->atomState.emptyAtom);
     if (!DefineNativeProperty(cx, wrapper, emptyId, *vp, PropertyStub, StrictPropertyStub,
                               JSPROP_ENUMERATE, 0, 0))
     {
@@ -851,17 +851,17 @@ Walk(JSContext *cx, JSObject *holder, js
     *vp = args.rval();
     return true;
 }
 
 static bool
 Revive(JSContext *cx, const Value &reviver, Value *vp)
 {
 
-    JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
     if (!obj)
         return false;
 
     AutoObjectRooter tvr(cx, obj);
     if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom),
                              *vp, NULL, NULL, JSPROP_ENUMERATE)) {
         return false;
     }
@@ -905,23 +905,23 @@ static JSFunctionSpec json_static_method
     JS_FN("parse",          js_json_parse,      2, 0),
     JS_FN("stringify",      js_json_stringify,  3, 0),
     JS_FS_END
 };
 
 JSObject *
 js_InitJSONClass(JSContext *cx, JSObject *obj)
 {
-    JSObject *JSON = NewNonFunction<WithProto::Class>(cx, &JSONClass, NULL, obj);
+    JSObject *JSON = NewNonFunction<WithProto::Class>(cx, &js_JSONClass, NULL, obj);
     if (!JSON || !JSON->setSingletonType(cx))
         return NULL;
 
     if (!JS_DefineProperty(cx, obj, js_JSON_str, OBJECT_TO_JSVAL(JSON),
                            JS_PropertyStub, JS_StrictPropertyStub, 0))
         return NULL;
 
     if (!JS_DefineFunctions(cx, JSON, json_static_methods))
         return NULL;
 
-    MarkStandardClassInitializedNoProto(obj, &JSONClass);
+    MarkStandardClassInitializedNoProto(obj, &js_JSONClass);
 
     return JSON;
 }
--- a/js/src/json.h
+++ b/js/src/json.h
@@ -41,16 +41,18 @@
 #include "jsprvtd.h"
 #include "jspubtd.h"
 #include "jsvalue.h"
 #include "jsvector.h"
 
 #define JSON_MAX_DEPTH  2048
 #define JSON_PARSER_BUFSIZE 1024
 
+extern js::Class js_JSONClass;
+
 extern JSObject *
 js_InitJSONClass(JSContext *cx, JSObject *obj);
 
 extern JSBool
 js_Stringify(JSContext *cx, js::Value *vp, JSObject *replacer, js::Value space,
              js::StringBuffer &sb);
 
 /*
--- a/js/src/jsonparser.cpp
+++ b/js/src/jsonparser.cpp
@@ -629,17 +629,17 @@ JSONParser::parse(Value *vp)
                 if (token == ArrayClose)
                     break;
                 if (!stateStack.append(FinishArrayElement))
                     return false;
                 goto JSONValueSwitch;
               }
 
               case ObjectOpen: {
-                JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
+                JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
                 if (!obj || !valueStack.append(ObjectValue(*obj)))
                     return false;
                 token = advanceAfterObjectOpen();
                 if (token == ObjectClose)
                     break;
                 goto JSONMember;
               }
 
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -361,17 +361,17 @@ js_DumpScript(JSContext *cx, JSScript *s
 
 static bool
 ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes)
 {
     if (!JSVAL_IS_PRIMITIVE(v)) {
         JSObject *obj = JSVAL_TO_OBJECT(v);
         Class *clasp = obj->getClass();
 
-        if (clasp == &BlockClass) {
+        if (clasp == &js_BlockClass) {
             char *source = JS_sprintf_append(NULL, "depth %d {", OBJ_BLOCK_DEPTH(cx, obj));
             if (!source)
                 return false;
 
             Shape::Range r = obj->lastProperty()->all();
             while (!r.empty()) {
                 const Shape &shape = r.front();
                 JSAutoByteString bytes;
@@ -388,25 +388,25 @@ ToDisassemblySource(JSContext *cx, jsval
 
             source = JS_sprintf_append(source, "}");
             if (!source)
                 return false;
             bytes->initBytes(source);
             return true;
         }
 
-        if (clasp == &FunctionClass) {
+        if (clasp == &js_FunctionClass) {
             JSFunction *fun = obj->getFunctionPrivate();
             JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT);
             if (!str)
                 return false;
             return bytes->encode(cx, str);
         }
 
-        if (clasp == &RegExpClass) {
+        if (clasp == &js_RegExpClass) {
             AutoValueRooter tvr(cx);
             if (!js_regexp_toString(cx, obj, tvr.addr()))
                 return false;
             return bytes->encode(cx, JSVAL_TO_STRING(Jsvalify(tvr.value())));
         }
     }
 
     return !!js_ValueToPrintable(cx, Valueify(v), bytes, true);
--- a/js/src/jsprobes.h
+++ b/js/src/jsprobes.h
@@ -349,23 +349,23 @@ Probes::resizeHeap(JSCompartment *compar
         ok = false;
 #endif
 
     return ok;
 }
 
 #ifdef INCLUDE_MOZILLA_DTRACE
 static const char *ObjectClassname(JSObject *obj) {
-    if (!obj)
+    if (! obj)
         return "(null object)";
     Class *clasp = obj->getClass();
-    if (!clasp)
+    if (! clasp)
         return "(null)";
     const char *class_name = clasp->name;
-    if (!class_name)
+    if (! class_name)
         return "(null class name)";
     return class_name;
 }
 #endif
 
 inline bool
 Probes::createObject(JSContext *cx, JSObject *obj)
 {
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -52,16 +52,18 @@
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
+namespace js {
+
 static inline const Value &
 GetCall(JSObject *proxy) {
     JS_ASSERT(proxy->isFunctionProxy());
     return proxy->getSlot(JSSLOT_PROXY_CALL);
 }
 
 static inline Value
 GetConstruct(JSObject *proxy) {
@@ -406,17 +408,17 @@ IndicatePropertyNotFound(JSContext *cx, 
 
 static bool
 ValueToBool(JSContext *cx, const Value &v, bool *bp)
 {
     *bp = !!js_ValueToBoolean(v);
     return true;
 }
 
-static bool
+bool
 ArrayToIdVector(JSContext *cx, const Value &array, AutoIdVector &props)
 {
     JS_ASSERT(props.length() == 0);
 
     if (array.isPrimitive())
         return true;
 
     JSObject *obj = &array.toObject();
@@ -1020,17 +1022,17 @@ proxy_HasInstance(JSContext *cx, JSObjec
 
 static JSType
 proxy_TypeOf(JSContext *cx, JSObject *proxy)
 {
     JS_ASSERT(proxy->isProxy());
     return JSProxy::typeOf(cx, proxy);
 }
 
-JS_FRIEND_DATA(Class) js::ObjectProxyClass = {
+JS_FRIEND_API(Class) ObjectProxyClass = {
     "Proxy",
     Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(3),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
@@ -1055,17 +1057,17 @@ JS_FRIEND_DATA(Class) js::ObjectProxyCla
         NULL,             /* enumerate       */
         proxy_TypeOf,
         proxy_Fix,        /* fix             */
         NULL,             /* thisObject      */
         NULL,             /* clear           */
     }
 };
 
-JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = {
+JS_FRIEND_API(Class) OuterWindowProxyClass = {
     "Proxy",
     Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(3),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
@@ -1095,50 +1097,50 @@ JS_FRIEND_DATA(Class) js::OuterWindowPro
         NULL,             /* enumerate       */
         NULL,             /* typeof          */
         NULL,             /* fix             */
         NULL,             /* thisObject      */
         NULL,             /* clear           */
     }
 };
 
-static JSBool
+JSBool
 proxy_Call(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
     JS_ASSERT(proxy->isProxy());
     return JSProxy::call(cx, proxy, argc, vp);
 }
 
-static JSBool
+JSBool
 proxy_Construct(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
     JS_ASSERT(proxy->isProxy());
     bool ok = JSProxy::construct(cx, proxy, argc, JS_ARGV(cx, vp), vp);
     return ok;
 }
 
-JS_FRIEND_DATA(Class) js::FunctionProxyClass = {
+JS_FRIEND_API(Class) FunctionProxyClass = {
     "Proxy",
     Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(5),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub,
     NULL,                 /* finalize */
     NULL,                 /* reserved0   */
     NULL,                 /* checkAccess */
     proxy_Call,
     proxy_Construct,
     NULL,                 /* xdrObject   */
-    FunctionClass.hasInstance,
+    js_FunctionClass.hasInstance,
     proxy_TraceFunction,  /* trace       */
     JS_NULL_CLASS_EXT,
     {
         proxy_LookupProperty,
         proxy_DefineProperty,
         proxy_GetProperty,
         proxy_SetProperty,
         proxy_GetAttributes,
@@ -1148,17 +1150,17 @@ JS_FRIEND_DATA(Class) js::FunctionProxyC
         proxy_TypeOf,
         NULL,             /* fix             */
         NULL,             /* thisObject      */
         NULL,             /* clear           */
     }
 };
 
 JS_FRIEND_API(JSObject *)
-js::NewProxyObject(JSContext *cx, JSProxyHandler *handler, const Value &priv, JSObject *proto,
+NewProxyObject(JSContext *cx, JSProxyHandler *handler, const Value &priv, JSObject *proto,
                JSObject *parent, JSObject *call, JSObject *construct)
 {
     JS_ASSERT_IF(proto, cx->compartment == proto->compartment());
     JS_ASSERT_IF(parent, cx->compartment == parent->compartment());
     bool fun = call || construct;
     Class *clasp;
     if (fun)
         clasp = &FunctionProxyClass;
@@ -1304,16 +1306,18 @@ static JSFunctionSpec static_methods[] =
     JS_FN("createFunction", proxy_createFunction,  3, 0),
 #ifdef DEBUG
     JS_FN("isTrapping",     proxy_isTrapping,      1, 0),
     JS_FN("fix",            proxy_fix,             1, 0),
 #endif
     JS_FS_END
 };
 
+extern Class CallableObjectClass;
+
 static const uint32 JSSLOT_CALLABLE_CALL = 0;
 static const uint32 JSSLOT_CALLABLE_CONSTRUCT = 1;
 
 static JSBool
 callable_Call(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *callable = &JS_CALLEE(cx, vp).toObject();
     JS_ASSERT(callable->getClass() == &CallableObjectClass);
@@ -1346,17 +1350,17 @@ callable_Construct(JSContext *cx, uintN 
         JSObject *proto;
         if (protov.isObject()) {
             proto = &protov.toObject();
         } else {
             if (!js_GetClassPrototype(cx, NULL, JSProto_Object, &proto))
                 return false;
         }
 
-        JSObject *newobj = NewNativeClassInstance(cx, &ObjectClass, proto, proto->getParent());
+        JSObject *newobj = NewNativeClassInstance(cx, &js_ObjectClass, proto, proto->getParent());
         if (!newobj)
             return false;
 
         /* If the call returns an object, return that, otherwise the original newobj. */
         Value rval;
         if (!Invoke(cx, ObjectValue(*newobj), callable->getSlot(JSSLOT_CALLABLE_CALL),
                     argc, vp + 2, &rval)) {
             return false;
@@ -1367,17 +1371,17 @@ callable_Construct(JSContext *cx, uintN 
             *vp = rval;
         return true;
     }
 
     bool ok = Invoke(cx, ObjectValue(*thisobj), fval, argc, vp + 2, vp);
     return ok;
 }
 
-Class js::CallableObjectClass = {
+Class CallableObjectClass = {
     "Function",
     JSCLASS_HAS_RESERVED_SLOTS(2),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
@@ -1385,17 +1389,17 @@ Class js::CallableObjectClass = {
     NULL,                 /* finalize    */
     NULL,                 /* reserved0   */
     NULL,                 /* checkAccess */
     callable_Call,
     callable_Construct,
 };
 
 JS_FRIEND_API(JSBool)
-js::FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
+FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
 {
     if (OperationInProgress(cx, proxy)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROXY_FIX);
         return false;
     }
 
     AutoValueRooter tvr(cx);
     if (!JSProxy::fix(cx, proxy, tvr.addr()))
@@ -1406,17 +1410,17 @@ js::FixProxy(JSContext *cx, JSObject *pr
     }
 
     JSObject *props = NonNullObject(cx, tvr.value());
     if (!props)
         return false;
 
     JSObject *proto = proxy->getProto();
     JSObject *parent = proxy->getParent();
-    Class *clasp = proxy->isFunctionProxy() ? &CallableObjectClass : &ObjectClass;
+    Class *clasp = proxy->isFunctionProxy() ? &CallableObjectClass : &js_ObjectClass;
 
     /*
      * Make a blank object from the recipe fix provided to us.  This must have
      * number of fixed slots as the proxy so that we can swap their contents.
      */
     gc::AllocKind kind = proxy->getAllocKind();
     JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
     if (!newborn)
@@ -1439,38 +1443,40 @@ js::FixProxy(JSContext *cx, JSObject *pr
         return false;
 
     /* The GC will dispose of the proxy object. */
 
     *bp = true;
     return true;
 }
 
-Class js::ProxyClass = {
+}
+
+Class js_ProxyClass = {
     "Proxy",
     JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub
 };
 
 JS_FRIEND_API(JSObject *)
 js_InitProxyClass(JSContext *cx, JSObject *obj)
 {
-    JSObject *module = NewNonFunction<WithProto::Class>(cx, &ProxyClass, NULL, obj);
+    JSObject *module = NewNonFunction<WithProto::Class>(cx, &js_ProxyClass, NULL, obj);
     if (!module || !module->setSingletonType(cx))
         return NULL;
 
     if (!JS_DefineProperty(cx, obj, "Proxy", OBJECT_TO_JSVAL(module),
                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
         return NULL;
     }
     if (!JS_DefineFunctions(cx, module, static_methods))
         return NULL;
 
-    MarkStandardClassInitializedNoProto(obj, &ProxyClass);
+    MarkStandardClassInitializedNoProto(obj, &js_ProxyClass);
 
     return module;
 }
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -137,16 +137,40 @@ class JSProxy {
 /* Shared between object and function proxies. */
 const uint32 JSSLOT_PROXY_HANDLER = 0;
 const uint32 JSSLOT_PROXY_PRIVATE = 1;
 const uint32 JSSLOT_PROXY_EXTRA   = 2;
 /* Function proxies only. */
 const uint32 JSSLOT_PROXY_CALL = 3;
 const uint32 JSSLOT_PROXY_CONSTRUCT = 4;
 
+extern JS_FRIEND_API(js::Class) ObjectProxyClass;
+extern JS_FRIEND_API(js::Class) FunctionProxyClass;
+extern JS_FRIEND_API(js::Class) OuterWindowProxyClass;
+extern js::Class CallableObjectClass;
+
+}
+
+inline bool
+JSObject::isObjectProxy() const
+{
+    return getClass() == &js::ObjectProxyClass ||
+           getClass() == &js::OuterWindowProxyClass;
+}
+
+inline bool
+JSObject::isFunctionProxy() const
+{
+    return getClass() == &js::FunctionProxyClass;
+}
+
+inline bool
+JSObject::isProxy() const
+{
+    return isObjectProxy() || isFunctionProxy();
 }
 
 inline js::JSProxyHandler *
 JSObject::getProxyHandler() const
 {
     JS_ASSERT(isProxy());
     return (js::JSProxyHandler *) getSlot(js::JSSLOT_PROXY_HANDLER).toPrivate();
 }
@@ -188,14 +212,16 @@ NewProxyObject(JSContext *cx, JSProxyHan
 
 JS_FRIEND_API(JSBool)
 FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp);
 
 }
 
 JS_BEGIN_EXTERN_C
 
+extern js::Class js_ProxyClass;
+
 extern JS_FRIEND_API(JSObject *)
 js_InitProxyClass(JSContext *cx, JSObject *obj);
 
 JS_END_EXTERN_C
 
 #endif
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -318,17 +318,17 @@ class NodeBuilder
         if (!atom)
             return false;
 
         dst->setString(atom);
         return true;
     }
 
     bool newObject(JSObject **dst) {
-        JSObject *nobj = NewNonFunction<WithProto::Class>(cx, &ObjectClass, NULL, NULL);
+        JSObject *nobj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL);
         if (!nobj)
             return false;
 
         *dst = nobj;
         return true;
     }
 
     bool newArray(NodeVector &elts, Value *dst);
@@ -628,17 +628,17 @@ class NodeBuilder
 
 bool
 NodeBuilder::newNode(ASTType type, TokenPos *pos, JSObject **dst)
 {
     JS_ASSERT(type > AST_ERROR && type < AST_LIMIT);
 
     Value tv;
 
-    JSObject *node = NewNonFunction<WithProto::Class>(cx, &ObjectClass, NULL, NULL);
+    JSObject *node = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, NULL);
     if (!node ||
         !setNodeLoc(node, pos) ||
         !atomValue(nodeTypeNames[type], &tv) ||
         !setProperty(node, "type", tv)) {
         return false;
     }
 
     *dst = node;
@@ -3233,17 +3233,17 @@ static JSFunctionSpec static_methods[] =
 };
 
 
 JS_BEGIN_EXTERN_C
 
 JS_PUBLIC_API(JSObject *)
 JS_InitReflect(JSContext *cx, JSObject *obj)
 {
-    JSObject *Reflect = NewNonFunction<WithProto::Class>(cx, &ObjectClass, NULL, obj);
+    JSObject *Reflect = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, NULL, obj);
     if (!Reflect || !Reflect->setSingletonType(cx))
         return NULL;
 
     if (!JS_DefineProperty(cx, obj, "Reflect", OBJECT_TO_JSVAL(Reflect),
                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
         return NULL;
     }
 
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -136,20 +136,21 @@ SwapObjectRegExp(JSContext *cx, JSObject
     JS_ALWAYS_TRUE(obj->initRegExp(cx, newRegExp.get()));
     if (oldRegExp)
         oldRegExp->decref(cx);
 }
 
 JSObject * JS_FASTCALL
 js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto)
 {
-    JS_ASSERT(obj->isRegExp());
-    JS_ASSERT(proto->isRegExp());
+    JS_ASSERT(obj->getClass() == &js_RegExpClass);
+    JS_ASSERT(proto);
+    JS_ASSERT(proto->getClass() == &js_RegExpClass);
 
-    JSObject *clone = NewNativeClassInstance(cx, &RegExpClass, proto, proto->getParent());
+    JSObject *clone = NewNativeClassInstance(cx, &js_RegExpClass, proto, proto->getParent());
     if (!clone)
         return NULL;
 
     /*
      * This clone functionality does not duplicate the JITted code blob, which is necessary for
      * cross-compartment cloning functionality.
      */
     assertSameCompartment(cx, obj, clone);
@@ -426,17 +427,17 @@ js_XDRRegExpObject(JSXDRState *xdr, JSOb
         if (!re)
             return false;
         source = re->getSource();
         flagsword = re->getFlags();
     }
     if (!JS_XDRString(xdr, &source) || !JS_XDRUint32(xdr, &flagsword))
         return false;
     if (xdr->mode == JSXDR_DECODE) {
-        JSObject *obj = NewBuiltinClassInstance(xdr->cx, &RegExpClass);
+        JSObject *obj = NewBuiltinClassInstance(xdr->cx, &js_RegExpClass);
         if (!obj)
             return false;
         obj->clearParent();
         obj->clearType();
 
         /*
          * initRegExp can GC before storing re in the private field of the
          * object. At that point the only reference to the source string could
@@ -454,17 +455,17 @@ js_XDRRegExpObject(JSXDRState *xdr, JSOb
 }
 
 #else  /* !JS_HAS_XDR */
 
 #define js_XDRRegExpObject NULL
 
 #endif /* !JS_HAS_XDR */
 
-Class js::RegExpClass = {
+js::Class js_RegExpClass = {
     js_RegExp_str,
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::REGEXP_CLASS_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
@@ -484,17 +485,17 @@ Class js::RegExpClass = {
 /*
  * RegExp instance methods.
  */
 
 JSBool
 js_regexp_toString(JSContext *cx, JSObject *obj, Value *vp)
 {
     if (!obj->isRegExp()) {
-        ReportIncompatibleMethod(cx, vp, &RegExpClass);
+        ReportIncompatibleMethod(cx, vp, &js_RegExpClass);
         return false;
     }
 
     RegExp *re = RegExp::extractFrom(obj);
     if (!re) {
         *vp = StringValue(cx->runtime->emptyString);
         return true;
     }
@@ -603,17 +604,17 @@ enum ExecType { RegExpExec, RegExpTest }
 static JSBool
 ExecuteRegExp(JSContext *cx, ExecType execType, uintN argc, Value *vp)
 {
     /* Step 1. */
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
     if (!obj->isRegExp()) {
-        ReportIncompatibleMethod(cx, vp, &RegExpClass);
+        ReportIncompatibleMethod(cx, vp, &js_RegExpClass);
         return false;
     }
 
     RegExp *re = RegExp::extractFrom(obj);
     if (!re)
         return true;
 
     /*
@@ -697,17 +698,17 @@ js_regexp_test(JSContext *cx, uintN argc
  */
 static bool
 CompileRegExpAndSwap(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
 {
     if (argc == 0)
         return SwapRegExpInternals(cx, obj, rval, cx->runtime->emptyString);
 
     Value sourceValue = argv[0];
-    if (sourceValue.isObject() && sourceValue.toObject().isRegExp()) {
+    if (sourceValue.isObject() && sourceValue.toObject().getClass() == &js_RegExpClass) {
         /*
          * If we get passed in a RegExp object we return a new object with the
          * same RegExp (internal matcher program) guts.
          * Note: the regexp static flags are not taken into consideration here.
          */
         JSObject &sourceObj = sourceValue.toObject();
         if (argc >= 2 && !argv[1].isUndefined()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED);
@@ -753,17 +754,17 @@ CompileRegExpAndSwap(JSContext *cx, JSOb
 
 static JSBool
 regexp_compile(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
     if (!obj->isRegExp()) {
-        ReportIncompatibleMethod(cx, vp, &RegExpClass);
+        ReportIncompatibleMethod(cx, vp, &js_RegExpClass);
         return false;
     }
 
     return CompileRegExpAndSwap(cx, obj, argc, JS_ARGV(cx, vp), &JS_RVAL(cx, vp));
 }
 
 static JSBool
 regexp_construct(JSContext *cx, uintN argc, Value *vp)
@@ -778,17 +779,17 @@ regexp_construct(JSContext *cx, uintN ar
          */
         if (argc >= 1 && argv[0].isObject() && argv[0].toObject().isRegExp() &&
             (argc == 1 || argv[1].isUndefined())) {
             *vp = argv[0];
             return true;
         }
     }
 
-    JSObject *obj = NewBuiltinClassInstance(cx, &RegExpClass);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_RegExpClass);
     if (!obj)
         return false;
 
     return CompileRegExpAndSwap(cx, obj, argc, argv, &JS_RVAL(cx, vp));
 }
 
 static JSFunctionSpec regexp_methods[] = {
 #if JS_HAS_TOSOURCE
@@ -803,17 +804,17 @@ static JSFunctionSpec regexp_methods[] =
 
 JSObject *
 js_InitRegExpClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     GlobalObject *global = obj->asGlobal();
 
-    JSObject *proto = global->createBlankPrototype(cx, &RegExpClass);
+    JSObject *proto = global->createBlankPrototype(cx, &js_RegExpClass);
     if (!proto)
         return NULL;
 
     AlreadyIncRefed<RegExp> re = RegExp::create(cx, cx->runtime->emptyString, 0, NULL);
     if (!re)
         return NULL;
 
     /*
@@ -825,17 +826,17 @@ js_InitRegExpClass(JSContext *cx, JSObje
     assertSameCompartment(cx, proto, re->compartment);
 #endif
     if (!proto->initRegExp(cx, re.get()))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, proto, NULL, regexp_methods))
         return NULL;
 
-    JSFunction *ctor = global->createConstructor(cx, regexp_construct, &RegExpClass,
+    JSFunction *ctor = global->createConstructor(cx, regexp_construct, &js_RegExpClass,
                                                  CLASS_ATOM(cx, RegExp), 2);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return NULL;
 
     /* Add static properties to the RegExp constructor. */
--- a/js/src/jsregexp.h
+++ b/js/src/jsregexp.h
@@ -47,16 +47,18 @@
 #include "jsstr.h"
 #include "jscntxt.h"
 #include "jsvector.h"
 
 #ifdef JS_THREADSAFE
 #include "jsdhash.h"
 #endif
 
+extern js::Class js_RegExpClass;
+
 namespace js {
 
 class RegExpStatics
 {
     typedef Vector<int, 20, SystemAllocPolicy> MatchPairs;
     MatchPairs      matchPairs;
     /* The input that was used to produce matchPairs. */
     JSLinearString  *matchPairsInput;
@@ -381,16 +383,22 @@ JSObject::setRegExpMultiline(bool multil
 inline void
 JSObject::setRegExpSticky(bool sticky)
 {
     setSlot(JSSLOT_REGEXP_STICKY, js::BooleanValue(sticky));
 }
 
 namespace js { class AutoStringRooter; }
 
+inline bool
+JSObject::isRegExp() const
+{
+    return getClass() == &js_RegExpClass;
+}
+
 extern JS_FRIEND_API(JSBool)
 js_ObjectIsRegExp(JSObject *obj);
 
 extern JSObject *
 js_InitRegExpClass(JSContext *cx, JSObject *obj);
 
 /*
  * Export js_regexp_toString to the decompiler.
--- a/js/src/jsregexpinlines.h
+++ b/js/src/jsregexpinlines.h
@@ -443,17 +443,17 @@ RegExp::createObjectNoStatics(JSContext 
      * NewBuiltinClassInstance can GC before we store re in the private field
      * of the object. At that point the only reference to the source string
      * could be from the malloc-allocated GC-invisible re. So we must anchor.
      */
     JS::Anchor<JSString *> anchor(str);
     AlreadyIncRefed<RegExp> re = RegExp::create(cx, str, flags, ts);
     if (!re)
         return NULL;
-    JSObject *obj = NewBuiltinClassInstance(cx, &RegExpClass);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_RegExpClass);
     if (!obj || !obj->initRegExp(cx, re.get())) {
         re->decref(cx);
         return NULL;
     }
     return obj;
 }
 
 /*
--- a/js/src/jsscopeinlines.h
+++ b/js/src/jsscopeinlines.h
@@ -283,17 +283,17 @@ Shape::get(JSContext* cx, JSObject *rece
         vp->setObject(methodObject());
         return pobj->methodReadBarrier(cx, *this, vp);
     }
 
     /*
      * |with (it) color;| ends up here, as do XML filter-expressions.
      * Avoid exposing the With object to native getters.
      */
-    if (obj->isWith())
+    if (obj->getClass() == &js_WithClass)
         obj = js_UnwrapWithObject(cx, obj);
     return js::CallJSPropertyOp(cx, getterOp(), receiver, SHAPE_USERID(this), vp);
 }
 
 inline bool
 Shape::set(JSContext* cx, JSObject* obj, bool strict, js::Value* vp) const
 {
     JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
@@ -302,17 +302,17 @@ Shape::set(JSContext* cx, JSObject* obj,
         js::Value fval = setterValue();
         return js::InvokeGetterOrSetter(cx, obj, fval, 1, vp, vp);
     }
 
     if (attrs & JSPROP_GETTER)
         return js_ReportGetterOnlyAssignment(cx);
 
     /* See the comment in js::Shape::get as to why we check for With. */
-    if (obj->isWith())
+    if (obj->getClass() == &js_WithClass)
         obj = js_UnwrapWithObject(cx, obj);
     return js::CallJSPropertyOpSetter(cx, setterOp(), obj, SHAPE_USERID(this), strict, vp);
 }
 
 inline void
 Shape::removeFromDictionary(JSObject *obj) const
 {
     JS_ASSERT(!frozen());
@@ -359,44 +359,44 @@ Shape::insertIntoDictionary(js::Shape **
 inline
 EmptyShape::EmptyShape(JSCompartment *comp, js::Class *aclasp)
   : js::Shape(comp, aclasp)
 {}
 
 /* static */ inline EmptyShape *
 EmptyShape::getEmptyArgumentsShape(JSContext *cx)
 {
-    return ensure(cx, &NormalArgumentsObjectClass, &cx->compartment->emptyArgumentsShape);
+    return ensure(cx, &NormalArgumentsObject::jsClass, &cx->compartment->emptyArgumentsShape);
 }
 
 /* static */ inline EmptyShape *
 EmptyShape::getEmptyBlockShape(JSContext *cx)
 {
-    return ensure(cx, &BlockClass, &cx->compartment->emptyBlockShape);
+    return ensure(cx, &js_BlockClass, &cx->compartment->emptyBlockShape);
 }
 
 /* static */ inline EmptyShape *
 EmptyShape::getEmptyCallShape(JSContext *cx)
 {
-    return ensure(cx, &CallClass, &cx->compartment->emptyCallShape);
+    return ensure(cx, &js_CallClass, &cx->compartment->emptyCallShape);
 }
 
 /* static */ inline EmptyShape *
 EmptyShape::getEmptyDeclEnvShape(JSContext *cx)
 {
-    return ensure(cx, &DeclEnvClass, &cx->compartment->emptyDeclEnvShape);
+    return ensure(cx, &js_DeclEnvClass, &cx->compartment->emptyDeclEnvShape);
 }
 
 /* static */ inline EmptyShape *
 EmptyShape::getEmptyEnumeratorShape(JSContext *cx)
 {
-    return ensure(cx, &IteratorClass, &cx->compartment->emptyEnumeratorShape);
+    return ensure(cx, &js_IteratorClass, &cx->compartment->emptyEnumeratorShape);
 }
 
 /* static */ inline EmptyShape *
 EmptyShape::getEmptyWithShape(JSContext *cx)
 {
-    return ensure(cx, &WithClass, &cx->compartment->emptyWithShape);
+    return ensure(cx, &js_WithClass, &cx->compartment->emptyWithShape);
 }
 
 } /* namespace js */
 
 #endif /* jsscopeinlines_h___ */
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -663,19 +663,19 @@ js_XDRScript(JSXDRState *xdr, JSScript *
      * restored in the outer-to-inner order. js_XDRBlockObject relies on this
      * to restore the parent chain.
      */
     for (i = 0; i != nobjects; ++i) {
         JSObject **objp = &script->objects()->vector[i];
         uint32 isBlock;
         if (xdr->mode == JSXDR_ENCODE) {
             Class *clasp = (*objp)->getClass();
-            JS_ASSERT(clasp == &FunctionClass ||
-                      clasp == &BlockClass);
-            isBlock = (clasp == &BlockClass) ? 1 : 0;
+            JS_ASSERT(clasp == &js_FunctionClass ||
+                      clasp == &js_BlockClass);
+            isBlock = (clasp == &js_BlockClass) ? 1 : 0;
         }
         if (!JS_XDRUint32(xdr, &isBlock))
             goto error;
         if (isBlock == 0) {
             if (!js_XDRFunctionObject(xdr, objp))
                 goto error;
         } else {
             JS_ASSERT(isBlock == 1);
@@ -773,17 +773,17 @@ script_trace(JSTracer *trc, JSObject *ob
 {
     JSScript *script = (JSScript *) obj->getPrivate();
     if (script) {
         CheckScriptOwner(script, obj);
         MarkScript(trc, script, "script");
     }
 }
 
-Class js::ScriptClass = {
+Class js_ScriptClass = {
     "Script",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -1382,17 +1382,17 @@ JSScript::finalize(JSContext *cx)
     }
 }
 
 JSObject *
 js_NewScriptObject(JSContext *cx, JSScript *script)
 {
     JS_ASSERT(!script->u.object);
 
-    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &ScriptClass, NULL, NULL);
+    JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
     if (!obj)
         return NULL;
     obj->setPrivate(script);
     script->u.object = obj;
     script->setOwnerObject(obj);
 
     /*
      * Clear the object's type/proto, to avoid entraining stuff. Once we no longer use the parent
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -547,17 +547,17 @@ struct JSScript : public js::gc::Cell {
   public:
     js::Bindings    bindings;   /* names of top-level variables in this script
                                    (and arguments if this is a function script) */
     JSPrincipals    *principals;/* principals for this script */
     jschar          *sourceMap; /* source map file or null */
 
     union {
         /*
-         * A script object of class ScriptClass, to ensure the script is GC'd.
+         * A script object of class js_ScriptClass, to ensure the script is GC'd.
          * - All scripts returned by JSAPI functions (JS_CompileScript,
          *   JS_CompileFile, etc.) have these objects.
          * - Function scripts never have script objects; such scripts are owned
          *   by their function objects.
          * - Temporary scripts created by obj_eval, JS_EvaluateScript, and
          *   similar functions never have these objects; such scripts are
          *   explicitly destroyed by the code that created them.
          */
@@ -838,16 +838,17 @@ StackDepth(JSScript *script)
             (script_)->code + (script_)->length <= (pc_)) {                   \
             JS_ASSERT((size_t)(index) < js_common_atom_count);                \
             (atom) = cx->runtime->atomState.commonAtomsStart()[index];        \
         } else {                                                              \
             (atom) = script_->getAtom(index);                                 \
         }                                                                     \
     JS_END_MACRO
 
+extern JS_FRIEND_DATA(js::Class) js_ScriptClass;
 
 extern JSObject *
 js_InitScriptClass(JSContext *cx, JSObject *obj);
 
 extern void
 js_MarkScriptFilename(const char *filename);
 
 extern void
@@ -960,16 +961,22 @@ js_CloneScript(JSContext *cx, JSScript *
 /*
  * NB: after a successful JSXDR_DECODE, js_XDRScript callers must do any
  * required subsequent set-up of owning function or script object and then call
  * js_CallNewScriptHook.
  */
 extern JSBool
 js_XDRScript(JSXDRState *xdr, JSScript **scriptp);
 
+inline bool
+JSObject::isScript() const
+{
+    return getClass() == &js_ScriptClass;
+}
+
 inline JSScript *
 JSObject::getScript() const
 {
     JS_ASSERT(isScript());
     return static_cast<JSScript *>(getPrivate());
 }
 
 #endif /* jsscript_h___ */
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -148,17 +148,17 @@ JSScript::getCallerFunction()
 }
 
 inline JSObject *
 JSScript::getRegExp(size_t index)
 {
     JSObjectArray *arr = regexps();
     JS_ASSERT((uint32) index < arr->length);
     JSObject *obj = arr->vector[index];
-    JS_ASSERT(obj->isRegExp());
+    JS_ASSERT(obj->getClass() == &js_RegExpClass);
     return obj;
 }
 
 inline bool
 JSScript::isEmpty() const
 {
     if (length > 3)
         return false;
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -379,48 +379,48 @@ str_resolve(JSContext *cx, JSObject *obj
                                  STRING_ELEMENT_ATTRS)) {
             return JS_FALSE;
         }
         *objp = obj;
     }
     return JS_TRUE;
 }
 
-Class js::StringClass = {
+Class js_StringClass = {
     js_String_str,
     JSCLASS_HAS_RESERVED_SLOTS(StringObject::RESERVED_SLOTS) |
     JSCLASS_NEW_RESOLVE | JSCLASS_HAS_CACHED_PROTO(JSProto_String),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     str_enumerate,
     (JSResolveOp)str_resolve,
     ConvertStub
 };
 
 /*
  * Returns a JSString * for the |this| value associated with vp, or throws a
  * TypeError if |this| is null or undefined.  This algorithm is the same as
  * calling CheckObjectCoercible(this), then returning ToString(this), as all
- * String.prototype.* methods do (other than toString and valueOf).
+ * String.prototype.* methods do.
  */
 static JS_ALWAYS_INLINE JSString *
 ThisToStringForStringProto(JSContext *cx, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return NULL);
 
     if (vp[1].isString())
         return vp[1].toString();
 
     if (vp[1].isObject()) {
         JSObject *obj = &vp[1].toObject();
-        if (obj->isString() &&
+        if (obj->getClass() == &js_StringClass &&
             ClassMethodIsNative(cx, obj,
-                                &StringClass,
+                                &js_StringClass,
                                 ATOM_TO_JSID(cx->runtime->atomState.toStringAtom),
                                 js_str_toString))
         {
             vp[1] = obj->getPrimitiveThis();
             return vp[1].toString();
         }
     } else if (vp[1].isNullOrUndefined()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
@@ -3186,22 +3186,22 @@ StringObject::assignInitialShape(JSConte
 
 JSObject *
 js_InitStringClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     GlobalObject *global = obj->asGlobal();
 
-    JSObject *proto = global->createBlankPrototype(cx, &StringClass);
+    JSObject *proto = global->createBlankPrototype(cx, &js_StringClass);
     if (!proto || !proto->asString()->init(cx, cx->runtime->emptyString))
         return NULL;
 
     /* Now create the String function. */
-    JSFunction *ctor = global->createConstructor(cx, js_String, &StringClass,
+    JSFunction *ctor = global->createConstructor(cx, js_String, &js_StringClass,
                                                  CLASS_ATOM(cx, String), 1);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, proto, NULL, string_methods) ||
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -96,16 +96,24 @@ extern JSSubString js_EmptySubString;
  */
 #define JS7_ISDEC(c)    ((((unsigned)(c)) - '0') <= 9)
 #define JS7_UNDEC(c)    ((c) - '0')
 #define JS7_ISHEX(c)    ((c) < 128 && isxdigit(c))
 #define JS7_UNHEX(c)    (uintN)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a')
 #define JS7_ISLET(c)    ((c) < 128 && isalpha(c))
 
 /* Initialize the String class, returning its prototype object. */
+extern js::Class js_StringClass;
+
+inline bool
+JSObject::isString() const
+{
+    return getClass() == &js_StringClass;
+}
+
 extern JSObject *
 js_InitStringClass(JSContext *cx, JSObject *obj);
 
 extern const char js_escape_str[];
 extern const char js_unescape_str[];
 extern const char js_uneval_str[];
 extern const char js_decodeURI_str[];
 extern const char js_encodeURI_str[];
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -9827,19 +9827,19 @@ TraceRecorder::unbox_non_double_object(A
 
 LIns*
 TraceRecorder::unbox_object(Address addr, LIns* tag_ins, JSValueType type, VMSideExit* exit)
 {
     JS_ASSERT(type == JSVAL_TYPE_FUNOBJ || type == JSVAL_TYPE_NONFUNOBJ);
     guard(true, w.name(w.eqi(tag_ins, w.nameImmui(JSVAL_TAG_OBJECT)), "isObj"), exit);
     LIns *payload_ins = w.ldiValuePayload(addr);
     if (type == JSVAL_TYPE_FUNOBJ)
-        guardClass(payload_ins, &FunctionClass, exit, LOAD_NORMAL);
+        guardClass(payload_ins, &js_FunctionClass, exit, LOAD_NORMAL);
     else
-        guardNotClass(payload_ins, &FunctionClass, exit, LOAD_NORMAL);
+        guardNotClass(payload_ins, &js_FunctionClass, exit, LOAD_NORMAL);
     return payload_ins;
 }
 
 LIns*
 TraceRecorder::unbox_value(const Value &v, Address addr, VMSideExit *exit, bool force_double)
 {
     LIns *tag_ins = w.ldiValueTag(addr);
 
@@ -9980,19 +9980,19 @@ TraceRecorder::unbox_object(LIns* v_ins,
 {
     JS_STATIC_ASSERT(JSVAL_TYPE_OBJECT == JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET);
     JS_ASSERT(type == JSVAL_TYPE_FUNOBJ || type == JSVAL_TYPE_NONFUNOBJ);
     guard(true,
           w.geuq(v_ins, w.nameImmq(JSVAL_SHIFTED_TAG_OBJECT)),
           exit);
     v_ins = unpack_ptr(v_ins);
     if (type == JSVAL_TYPE_FUNOBJ)
-        guardClass(v_ins, &FunctionClass, exit, LOAD_NORMAL);
+        guardClass(v_ins, &js_FunctionClass, exit, LOAD_NORMAL);
     else
-        guardNotClass(v_ins, &FunctionClass, exit, LOAD_NORMAL);
+        guardNotClass(v_ins, &js_FunctionClass, exit, LOAD_NORMAL);
     return v_ins;
 }
 
 LIns*
 TraceRecorder::unbox_value(const Value &v, Address addr, VMSideExit *exit, bool force_double)
 {
     LIns *v_ins = w.ldq(addr);
 
@@ -10189,23 +10189,23 @@ JS_REQUIRES_STACK void
 TraceRecorder::guardNotClass(LIns* obj_ins, Class* clasp, VMSideExit* exit, LoadQual loadQual)
 {
     guardClassHelper(false, obj_ins, clasp, exit, loadQual);
 }
 
 JS_REQUIRES_STACK void
 TraceRecorder::guardDenseArray(LIns* obj_ins, ExitType exitType)
 {
-    guardClass(obj_ins, &ArrayClass, snapshot(exitType), LOAD_NORMAL);
+    guardClass(obj_ins, &js_ArrayClass, snapshot(exitType), LOAD_NORMAL);
 }
 
 JS_REQUIRES_STACK void
 TraceRecorder::guardDenseArray(LIns* obj_ins, VMSideExit* exit)
 {
-    guardClass(obj_ins, &ArrayClass, exit, LOAD_NORMAL);
+    guardClass(obj_ins, &js_ArrayClass, exit, LOAD_NORMAL);
 }
 
 JS_REQUIRES_STACK bool
 TraceRecorder::guardHasPrototype(JSObject* obj, LIns* obj_ins,
                                  JSObject** pobj, LIns** pobj_ins,
                                  VMSideExit* exit)
 {
     *pobj = obj->getProto();
@@ -11060,17 +11060,17 @@ TraceRecorder::getClassPrototype(JSObjec
     JS_ASSERT((~attrs & (JSPROP_READONLY | JSPROP_PERMANENT)) == 0);
 #endif
 
     // Since ctor was built by js_InitClass, we can assert (rather than check)
     // that pval is usable.
     JS_ASSERT(!pval.isPrimitive());
     JSObject *proto = &pval.toObject();
     JS_ASSERT(!proto->isDenseArray());
-    JS_ASSERT_IF(clasp != &ArrayClass, proto->getNewType(cx)->emptyShapes[0]->getClass() == clasp);
+    JS_ASSERT_IF(clasp != &js_ArrayClass, proto->getNewType(cx)->emptyShapes[0]->getClass() == clasp);
 
     proto_ins = w.immpObjGC(proto);
     return RECORD_CONTINUE;
 }
 
 RecordingStatus
 TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins)
 {
@@ -11603,25 +11603,25 @@ TraceRecorder::callNative(uintN argc, JS
 
     // vp[0] is the callee.
     box_value_into(vp[0], w.immpObjGC(funobj), AllocSlotsAddress(invokevp_ins));
 
     // Calculate |this|.
     LIns* this_ins;
     if (mode == JSOP_NEW) {
         Class* clasp = fun->u.n.clasp;
-        JS_ASSERT(clasp != &SlowArrayClass);
+        JS_ASSERT(clasp != &js_SlowArrayClass);
         if (!clasp)
-            clasp = &ObjectClass;
+            clasp = &js_ObjectClass;
         JS_ASSERT(((jsuword) clasp & 3) == 0);
 
         // Abort on |new Function|. (FIXME: This restriction might not
         // unnecessary now that the constructor creates the new function object
         // itself.)
-        if (clasp == &FunctionClass)
+        if (clasp == &js_FunctionClass)
             RETURN_STOP("new Function");
 
         if (!IsFastTypedArrayClass(clasp) && !clasp->isNative())
             RETURN_STOP("new with non-native ops");
 
         // Don't trace |new Math.sin(0)|.
         if (!fun->isConstructor())
             RETURN_STOP("new with non-constructor native function");
@@ -12489,17 +12489,17 @@ TraceRecorder::record_JSOP_SETNAME()
 }
 
 JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::recordInitPropertyOp(jsbytecode op)
 {
     Value& l = stackval(-2);
     JSObject* obj = &l.toObject();
     LIns* obj_ins = get(&l);
-    JS_ASSERT(obj->getClass() == &ObjectClass);
+    JS_ASSERT(obj->getClass() == &js_ObjectClass);
 
     Value& v = stackval(-1);
     LIns* v_ins = get(&v);
 
     JSAtom* atom = atoms[GET_INDEX(cx->regs().pc)];
     jsid id = js_CheckForStringIndex(ATOM_TO_JSID(atom));
 
     // If obj already has this property (because JSOP_NEWOBJECT already set its
@@ -12764,17 +12764,17 @@ GetPropertyWithNativeGetter(JSContext* c
     JSObject* pobj;
     JS_ASSERT(obj->lookupProperty(cx, shape->propid, &pobj, &prop));
     JS_ASSERT(prop == (JSProperty*) shape);
 #endif
 
     // Shape::get contains a special case for With objects. We can elide it
     // here because With objects are, we claim, never on the operand stack
     // while recording.
-    JS_ASSERT(obj->getClass() != &WithClass);
+    JS_ASSERT(obj->getClass() != &js_WithClass);
 
     vp->setUndefined();
     if (!shape->getterOp()(cx, obj, SHAPE_USERID(shape), vp)) {
         SetBuiltinError(tm);
         return JS_FALSE;
     }
     return WasBuiltinSuccessful(tm);
 }
@@ -14818,31 +14818,31 @@ TraceRecorder::record_JSOP_MOREITER()
     LIns* cond_ins;
 
     /*
      * JSOP_ITERNEXT already guards on this, but in certain rare cases we might
      * record misformed loop traces. Note that it's not necessary to guard on
      * ni->flags (nor do we in unboxNextValue), because the different iteration
      * type will guarantee a different entry typemap.
      */
-    if (iterobj->hasClass(&IteratorClass)) {
-        guardClass(iterobj_ins, &IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
+    if (iterobj->hasClass(&js_IteratorClass)) {
+        guardClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
 
         NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
         if (ni->isKeyIter()) {
             LIns *ni_ins = w.ldpObjPrivate(iterobj_ins);
             LIns *cursor_ins = w.ldpIterCursor(ni_ins);
             LIns *end_ins = w.ldpIterEnd(ni_ins);
 
             cond_ins = w.ltp(cursor_ins, end_ins);
             stack(0, cond_ins);
             return ARECORD_CONTINUE;
         }
     } else {
-        guardNotClass(iterobj_ins, &IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
+        guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
     }
 
     enterDeepBailCall();
 
     LIns* vp_ins = w.allocp(sizeof(Value));
     LIns* args[] = { vp_ins, iterobj_ins, cx_ins };
     pendingGuardCondition = w.call(&IteratorMore_ci, args);
 
@@ -14917,18 +14917,18 @@ TraceRecorder::storeMagic(JSWhyMagic why
 #endif
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::unboxNextValue(Value &iterobj_val, LIns* &v_ins)
 {
     JSObject *iterobj = &iterobj_val.toObject();
     LIns* iterobj_ins = get(&iterobj_val);
 
-    if (iterobj->hasClass(&IteratorClass)) {
-        guardClass(iterobj_ins, &IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
+    if (iterobj->hasClass(&js_IteratorClass)) {
+        guardClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
         NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
 
         LIns *ni_ins = w.ldpObjPrivate(iterobj_ins);
         LIns *cursor_ins = w.ldpIterCursor(ni_ins);
 
         /* Emit code to stringify the id if necessary. */
         Address cursorAddr = IterPropsAddress(cursor_ins);
         if (ni->isKeyIter()) {
@@ -14961,17 +14961,17 @@ TraceRecorder::unboxNextValue(Value &ite
             }
 
             /* Increment the cursor by one jsid and store it back. */
             cursor_ins = w.addp(cursor_ins, w.nameImmw(sizeof(jsid)));
             w.stpIterCursor(cursor_ins, ni_ins);
             return ARECORD_CONTINUE;
         }
     } else {
-        guardNotClass(iterobj_ins, &IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
+        guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
     }
 
 
     Address iterValueAddr = CxAddress(iterValue);
     v_ins = unbox_value(cx->iterValue, iterValueAddr, snapshot(BRANCH_EXIT));
     storeMagic(JS_NO_ITER_VALUE, iterValueAddr);
 
     return ARECORD_CONTINUE;
@@ -16335,17 +16335,17 @@ TraceRecorder::record_JSOP_LENGTH()
     }
 
     LIns* v_ins;
     if (obj->isArray()) {
         if (obj->isDenseArray()) {
             guardDenseArray(obj_ins, BRANCH_EXIT);
         } else {
             JS_ASSERT(obj->isSlowArray());
-            guardClass(obj_ins, &SlowArrayClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
+            guardClass(obj_ins, &js_SlowArrayClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
         }
         v_ins = w.lduiObjPrivate(obj_ins);
         if (obj->getArrayLength() <= JSVAL_INT_MAX) {
             guard(true, w.leui(v_ins, w.immi(JSVAL_INT_MAX)), BRANCH_EXIT);
             v_ins = w.i2d(v_ins);
         } else {
             v_ins = w.ui2d(v_ins);
         }
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -181,17 +181,17 @@ JSObject::allocateArrayBufferSlots(JSCon
     *((uint32*)slots) = size;
     return true;
 }
 
 static JSObject *
 DelegateObject(JSContext *cx, JSObject *obj)
 {
     if (!obj->getPrivate()) {
-        JSObject *delegate = NewNonFunction<WithProto::Given>(cx, &ObjectClass, obj->getProto(), NULL);
+        JSObject *delegate = NewNonFunction<WithProto::Given>(cx, &js_ObjectClass, obj->getProto(), NULL);
         obj->setPrivate(delegate);
         return delegate;
     }
     return static_cast<JSObject*>(obj->getPrivate());
 }
 
 JSObject *
 ArrayBuffer::create(JSContext *cx, int32 nbytes)
@@ -207,17 +207,17 @@ ArrayBuffer::create(JSContext *cx, int32
          * can fix.
          */
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
         return NULL;
     }
 
     JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass);
     obj->setSharedNonNativeMap();
-    obj->setClass(&ArrayBufferClass);
+    obj->clasp = &js_ArrayBufferClass;
 
     /*
      * The first 8 bytes hold the length.
      * The rest of it is a flat data store for the array buffer.
      */
     if (!obj->allocateArrayBufferSlots(cx, nbytes))
         return NULL;
 
@@ -975,17 +975,17 @@ class TypedArrayTemplate
         DebugOnly<uint32> bufferByteLength = getBuffer(obj)->arrayBufferByteLength();
         JS_ASSERT(bufferByteLength - getByteOffset(obj) >= getByteLength(obj));
         JS_ASSERT(getByteOffset(obj) <= bufferByteLength);
         JS_ASSERT(getBuffer(obj)->arrayBufferDataOffset() <= getDataOffset(obj));
         JS_ASSERT(getDataOffset(obj) <= offsetData(obj, bufferByteLength));
 
         JS_ASSERT(obj->getClass() == slowClass());
         obj->setSharedNonNativeMap();
-        obj->setClass(fastClass());
+        obj->clasp = fastClass();
 
         // FIXME Bug 599008: make it ok to call preventExtensions here.
         obj->flags |= JSObject::NOT_EXTENSIBLE;
 
         return obj;
     }
 
     /*
@@ -1689,17 +1689,17 @@ Class ArrayBuffer::slowClass = {
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub,
     FinalizeStub
 };
 
-Class js::ArrayBufferClass = {
+Class js_ArrayBufferClass = {
     "ArrayBuffer",
     JSCLASS_HAS_PRIVATE |
     Class::NON_NATIVE |
     JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
@@ -1897,17 +1897,17 @@ Class TypedArray::slowClasses[TYPE_MAX] 
 static JSObject *
 InitArrayBufferClass(JSContext *cx, GlobalObject *global)
 {
     JSObject *arrayBufferProto = global->createBlankPrototype(cx, &ArrayBuffer::slowClass);
     if (!arrayBufferProto)
         return NULL;
 
     JSFunction *ctor =
-        global->createConstructor(cx, ArrayBuffer::class_constructor, &ArrayBufferClass,
+        global->createConstructor(cx, ArrayBuffer::class_constructor, &js_ArrayBufferClass,
                                   CLASS_ATOM(cx, ArrayBuffer), 1);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, arrayBufferProto, ArrayBuffer::jsprops, NULL))
@@ -1948,17 +1948,17 @@ js_InitTypedArrayClasses(JSContext *cx, 
 
     return InitArrayBufferClass(cx, global);
 }
 
 JS_FRIEND_API(JSBool)
 js_IsArrayBuffer(JSObject *obj)
 {
     JS_ASSERT(obj);
-    return obj->isArrayBuffer();
+    return obj->getClass() == &js_ArrayBufferClass;
 }
 
 namespace js {
 
 bool
 IsFastTypedArrayClass(const Class *clasp)
 {
     return &TypedArray::fastClasses[0] <= clasp &&
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -73,16 +73,22 @@ WeakMapBase::sweepAll(JSTracer *tracer)
 {
     JSRuntime *rt = tracer->context->runtime;
     for (WeakMapBase *m = rt->gcWeakMapList; m; m = m->next)
         m->sweep(tracer);
 }
 
 } /* namespace js */
 
+bool
+JSObject::isWeakMap() const
+{
+    return getClass() == &WeakMapClass;
+}
+
 typedef WeakMap<JSObject *, Value> ObjectValueMap;
 
 static ObjectValueMap *
 GetObjectMap(JSObject *obj)
 {
     JS_ASSERT(obj->isWeakMap());
     return (ObjectValueMap *)obj->getPrivate();
 }
@@ -253,17 +259,19 @@ WeakMap_construct(JSContext *cx, uintN a
         return false;
 
     obj->setPrivate(NULL);
 
     vp->setObject(*obj);
     return true;
 }
 
-Class js::WeakMapClass = {
+namespace js {
+
+Class WeakMapClass = {
     "WeakMap",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_WeakMap),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -274,16 +282,18 @@ Class js::WeakMapClass = {
     NULL,                 /* checkAccess */
     NULL,                 /* call        */
     NULL,                 /* construct   */
     NULL,                 /* xdrObject   */
     NULL,                 /* hasInstance */
     WeakMap_mark
 };
 
+}
+
 static JSFunctionSpec weak_map_methods[] = {
     JS_FN("has",    WeakMap_has, 1, 0),
     JS_FN("get",    WeakMap_get, 2, 0),
     JS_FN("delete", WeakMap_delete, 1, 0),
     JS_FN("set",    WeakMap_set, 2, 0),
     JS_FS_END
 };
 
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -312,14 +312,17 @@ class DefaultMarkPolicy<JSObject *, JSOb
 // compartments within a runtime.
 //
 // With the current GC, the implementation turns out to be identical to the
 // default mark policy. We give it a distinct name anyway, in case this ever
 // changes.
 //
 typedef DefaultMarkPolicy<JSObject *, JSObject *> CrossCompartmentMarkPolicy;
 
+// The class of JavaScript WeakMap objects.
+extern Class WeakMapClass;
+
 }
 
 extern JSObject *
 js_InitWeakMapClass(JSContext *cx, JSObject *obj);
 
 #endif
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -627,17 +627,17 @@ JSCrossCompartmentWrapper::keys(JSContex
  * We can reify non-escaping iterator objects instead of having to wrap them. This
  * allows fast iteration over objects across a compartment boundary.
  */
 static bool
 CanReify(Value *vp)
 {
     JSObject *obj;
     return vp->isObject() &&
-           (obj = &vp->toObject())->getClass() == &IteratorClass &&
+           (obj = &vp->toObject())->getClass() == &js_IteratorClass &&
            (obj->getNativeIterator()->flags & JSITER_ENUMERATE);
 }
 
 struct AutoCloseIterator
 {
     AutoCloseIterator(JSContext *cx, JSObject *obj) : cx(cx), obj(obj) {}
 
     ~AutoCloseIterator() { if (obj) js_CloseIterator(cx, obj); }
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -148,17 +148,17 @@ const char js_leftcurly_entity_str[]   =
 static JSBool
 GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
 
 static JSBool
 IsDeclared(const JSObject *obj)
 {
     jsval v;
 
-    JS_ASSERT(obj->getClass() == &NamespaceClass);
+    JS_ASSERT(obj->getClass() == &js_NamespaceClass);
     v = obj->getNamespaceDeclared();
     JS_ASSERT(JSVAL_IS_VOID(v) || v == JSVAL_TRUE);
     return v == JSVAL_TRUE;
 }
 
 static JSBool
 xml_isXMLName(JSContext *cx, uintN argc, jsval *vp)
 {
@@ -192,34 +192,34 @@ NewBuiltinClassInstanceXML(JSContext *cx
         code;                                                                  \
         return true;                                                           \
     }
 
 /*
  * Namespace class and library functions.
  */
 DEFINE_GETTER(NamePrefix_getter,
-              if (obj->getClass() == &NamespaceClass) *vp = obj->getNamePrefixVal())
+              if (obj->getClass() == &js_NamespaceClass) *vp = obj->getNamePrefixVal())
 DEFINE_GETTER(NameURI_getter,
-              if (obj->getClass() == &NamespaceClass) *vp = obj->getNameURIVal())
+              if (obj->getClass() == &js_NamespaceClass) *vp = obj->getNameURIVal())
 
 static JSBool
 namespace_equality(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
 {
     JSObject *obj2;
 
     JS_ASSERT(v->isObjectOrNull());
     obj2 = v->toObjectOrNull();
-    *bp = (!obj2 || obj2->getClass() != &NamespaceClass)
+    *bp = (!obj2 || obj2->getClass() != &js_NamespaceClass)
           ? JS_FALSE
           : EqualStrings(obj->getNameURI(), obj2->getNameURI());
     return JS_TRUE;
 }
 
-JS_FRIEND_DATA(Class) js::NamespaceClass = {
+JS_FRIEND_DATA(Class) js_NamespaceClass = {
     "Namespace",
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::NAMESPACE_CLASS_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Namespace),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -253,34 +253,34 @@ static JSPropertySpec namespace_props[] 
 
 static JSBool
 namespace_toString(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return JS_FALSE;
     if (!obj->isNamespace()) {
-        ReportIncompatibleMethod(cx, vp, &NamespaceClass);
+        ReportIncompatibleMethod(cx, vp, &js_NamespaceClass);
         return JS_FALSE;
     }
     *vp = Valueify(obj->getNameURIVal());
     return JS_TRUE;
 }
 
 static JSFunctionSpec namespace_methods[] = {
     JS_FN(js_toString_str,  namespace_toString,        0,0),
     JS_FS_END
 };
 
 static JSObject *
 NewXMLNamespace(JSContext *cx, JSLinearString *prefix, JSLinearString *uri, JSBool declared)
 {
     JSObject *obj;
 
-    obj = NewBuiltinClassInstanceXML(cx, &NamespaceClass);
+    obj = NewBuiltinClassInstanceXML(cx, &js_NamespaceClass);
     if (!obj)
         return NULL;
     JS_ASSERT(JSVAL_IS_VOID(obj->getNamePrefixVal()));
     JS_ASSERT(JSVAL_IS_VOID(obj->getNameURIVal()));
     JS_ASSERT(JSVAL_IS_VOID(obj->getNamespaceDeclared()));
 
     /* Per ECMA-357, 13.2.5, these properties must be "own". */
     if (!JS_DefineProperties(cx, obj, namespace_props))
@@ -294,20 +294,20 @@ NewXMLNamespace(JSContext *cx, JSLinearS
         obj->setNamespaceDeclared(JSVAL_TRUE);
     return obj;
 }
 
 /*
  * QName class and library functions.
  */
 DEFINE_GETTER(QNameNameURI_getter,
-              if (obj->getClass() == &QNameClass)
+              if (obj->getClass() == &js_QNameClass)
                   *vp = JSVAL_IS_VOID(obj->getNameURIVal()) ? JSVAL_NULL : obj->getNameURIVal())
 DEFINE_GETTER(QNameLocalName_getter,
-              if (obj->getClass() == &QNameClass)
+              if (obj->getClass() == &js_QNameClass)
                   *vp = obj->getQNameLocalNameVal())
 
 static JSBool
 qname_identity(JSObject *qna, JSObject *qnb)
 {
     JSLinearString *uri1 = qna->getNameURI();
     JSLinearString *uri2 = qnb->getNameURI();
 
@@ -319,23 +319,23 @@ qname_identity(JSObject *qna, JSObject *
 }
 
 static JSBool
 qname_equality(JSContext *cx, JSObject *qn, const Value *v, JSBool *bp)
 {
     JSObject *obj2;
 
     obj2 = v->toObjectOrNull();
-    *bp = (!obj2 || obj2->getClass() != &QNameClass)
+    *bp = (!obj2 || obj2->getClass() != &js_QNameClass)
           ? JS_FALSE
           : qname_identity(qn, obj2);
     return JS_TRUE;
 }
 
-JS_FRIEND_DATA(Class) js::QNameClass = {
+JS_FRIEND_DATA(Class) js_QNameClass = {
     "QName",
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_CLASS_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_QName),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -359,31 +359,31 @@ JS_FRIEND_DATA(Class) js::QNameClass = {
 };
 
 /*
  * Classes for the ECMA-357-internal types AttributeName and AnyName, which
  * are like QName, except that they have no property getters.  They share the
  * qname_toString method, and therefore are exposed as constructable objects
  * in this implementation.
  */
-JS_FRIEND_DATA(Class) js::AttributeNameClass = {
+JS_FRIEND_DATA(Class) js_AttributeNameClass = {
     js_AttributeName_str,
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_CLASS_RESERVED_SLOTS) |
     JSCLASS_IS_ANONYMOUS,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub,
     FinalizeStub
 };
 
-JS_FRIEND_DATA(Class) js::AnyNameClass = {
+JS_FRIEND_DATA(Class) js_AnyNameClass = {
     js_AnyName_str,
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_CLASS_RESERVED_SLOTS) |
     JSCLASS_IS_ANONYMOUS,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -417,17 +417,17 @@ ConvertQNameToString(JSContext *cx, JSOb
         str = js_ConcatStrings(cx, uri, qualstr);
         if (!str)
             return NULL;
     }
     str = js_ConcatStrings(cx, str, obj->getQNameLocalName());
     if (!str)
         return NULL;
 
-    if (obj->getClass() == &AttributeNameClass) {
+    if (obj->getClass() == &js_AttributeNameClass) {
         JS::Anchor<JSString *> anchor(str);
         size_t length = str->length();
         jschar *chars = (jschar *) cx->malloc_((length + 2) * sizeof(jschar));
         if (!chars)
             return JS_FALSE;
         *chars = '@';
         const jschar *strChars = str->getChars(cx);
         if (!strChars) {
@@ -448,17 +448,17 @@ ConvertQNameToString(JSContext *cx, JSOb
 static JSBool
 qname_toString(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     if (!obj->isQName()) {
-        ReportIncompatibleMethod(cx, vp, &QNameClass);
+        ReportIncompatibleMethod(cx, vp, &js_QNameClass);
         return false;
     }
 
     JSString *str = ConvertQNameToString(cx, obj);
     if (!str)
         return false;
 
     vp->setString(str);
@@ -492,34 +492,34 @@ InitXMLQName(JSContext *cx, JSObject *ob
         obj->setQNameLocalName(localName);
     return true;
 }
 
 static JSObject *
 NewXMLQName(JSContext *cx, JSLinearString *uri, JSLinearString *prefix,
             JSAtom *localName)
 {
-    JSObject *obj = NewBuiltinClassInstanceXML(cx, &QNameClass);
+    JSObject *obj = NewBuiltinClassInstanceXML(cx, &js_QNameClass);
     if (!obj)
         return NULL;
     if (!InitXMLQName(cx, obj, uri, prefix, localName))
         return NULL;
     return obj;
 }
 
 static JSObject *
 NewXMLAttributeName(JSContext *cx, JSLinearString *uri, JSLinearString *prefix,
                     JSAtom *localName)
 {
     /*
      * AttributeName is an internal anonymous class which instances are not
      * exposed to scripts.
      */
     JSObject *parent = GetGlobalForScopeChain(cx);
-    JSObject *obj = NewNonFunction<WithProto::Given>(cx, &AttributeNameClass, NULL, parent);
+    JSObject *obj = NewNonFunction<WithProto::Given>(cx, &js_AttributeNameClass, NULL, parent);
     if (!obj)
         return NULL;
     JS_ASSERT(obj->isQName());
     if (!InitXMLQName(cx, obj, uri, prefix, localName))
         return NULL;
     return obj;
 }
 
@@ -529,23 +529,23 @@ js_ConstructXMLQNameObject(JSContext *cx
     Value argv[2];
 
     /*
      * ECMA-357 11.1.2,
      * The _QualifiedIdentifier : PropertySelector :: PropertySelector_
      * production, step 2.
      */
     if (nsval.isObject() &&
-        nsval.toObject().getClass() == &AnyNameClass) {
+        nsval.toObject().getClass() == &js_AnyNameClass) {
         argv[0].setNull();
     } else {
         argv[0] = nsval;
     }
     argv[1] = lnval;
-    return js_ConstructObject(cx, &QNameClass, NULL, NULL, 2, argv);
+    return js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 2, argv);
 }
 
 static JSBool
 IsXMLName(const jschar *cp, size_t n)
 {
     JSBool rv;
     jschar c;
 
@@ -611,30 +611,30 @@ NamespaceHelper(JSContext *cx, JSObject 
 #endif
     if (argc <= 0) {
         urival = JSVAL_VOID;
     } else {
         urival = argv[argc > 1];
         if (!JSVAL_IS_PRIMITIVE(urival)) {
             uriobj = JSVAL_TO_OBJECT(urival);
             clasp = uriobj->getClass();
-            isNamespace = (clasp == &NamespaceClass);
-            isQName = (clasp == &QNameClass);
+            isNamespace = (clasp == &js_NamespaceClass);
+            isQName = (clasp == &js_QNameClass);
         }
     }
 
     if (!obj) {
         /* Namespace called as function. */
         if (argc == 1 && isNamespace) {
             /* Namespace called with one Namespace argument is identity. */
             *rval = urival;
             return JS_TRUE;
         }
 
-        obj = NewBuiltinClassInstanceXML(cx, &NamespaceClass);
+        obj = NewBuiltinClassInstanceXML(cx, &js_NamespaceClass);
         if (!obj)
             return JS_FALSE;
     }
 
     /* Per ECMA-357, 13.2.5, these properties must be "own". */
     if (!JS_DefineProperties(cx, obj, namespace_props))
         return JS_FALSE;
 
@@ -727,29 +727,29 @@ QNameHelper(JSContext *cx, JSObject *obj
     JSAtom *name;
     if (argc <= 0) {
         nameval = JSVAL_VOID;
         isQName = JS_FALSE;
     } else {
         nameval = argv[argc > 1];
         isQName =
             !JSVAL_IS_PRIMITIVE(nameval) &&
-            JSVAL_TO_OBJECT(nameval)->getClass() == &QNameClass;
+            JSVAL_TO_OBJECT(nameval)->getClass() == &js_QNameClass;
     }
 
     if (!obj) {
         /* QName called as function. */
         if (argc == 1 && isQName) {
             /* QName called with one QName argument is identity. */
             *rval = nameval;
             return JS_TRUE;
         }
 
         /* Create and return a new QName object exactly as if constructed. */
-        obj = NewBuiltinClassInstanceXML(cx, &QNameClass);
+        obj = NewBuiltinClassInstanceXML(cx, &js_QNameClass);
         if (!obj)
             return JS_FALSE;
     }
     *rval = OBJECT_TO_JSVAL(obj);
 
     if (isQName) {
         /* If namespace is not specified and name is a QName, clone it. */
         qn = JSVAL_TO_OBJECT(nameval);
@@ -777,35 +777,35 @@ QNameHelper(JSContext *cx, JSObject *obj
         nsval = argv[0];
     } else if (IS_STAR(name)) {
         nsval = JSVAL_NULL;
     } else {
         if (!js_GetDefaultXMLNamespace(cx, &nsval))
             return JS_FALSE;
         JS_ASSERT(!JSVAL_IS_PRIMITIVE(nsval));
         JS_ASSERT(JSVAL_TO_OBJECT(nsval)->getClass() ==
-                  &NamespaceClass);
+                  &js_NamespaceClass);
     }
 
     if (JSVAL_IS_NULL(nsval)) {
         /* NULL prefix represents *undefined* in ECMA-357 13.3.2 5(a). */
         prefix = uri = NULL;
     } else {
         /*
          * Inline specialization of the Namespace constructor called with
          * nsval passed as the only argument, to compute the uri and prefix
          * for the constructed namespace, without actually allocating the
          * object or computing other members.  See ECMA-357 13.3.2 6(a) and
          * 13.2.2.
          */
         isNamespace = isQName = JS_FALSE;
         if (!JSVAL_IS_PRIMITIVE(nsval)) {
             obj2 = JSVAL_TO_OBJECT(nsval);
-            isNamespace = (obj2->getClass() == &NamespaceClass);
-            isQName = (obj2->getClass() == &QNameClass);
+            isNamespace = (obj2->getClass() == &js_NamespaceClass);
+            isQName = (obj2->getClass() == &js_QNameClass);
         }
 #ifdef __GNUC__         /* suppress bogus gcc warnings */
         else obj2 = NULL;
 #endif
 
         if (isNamespace) {
             uri = obj2->getNameURI();
             prefix = obj2->getNamePrefix();
@@ -1847,19 +1847,19 @@ ToXML(JSContext *cx, jsval v)
             return obj;
         }
 
         clasp = obj->getClass();
         if (clasp->flags & JSCLASS_DOCUMENT_OBSERVER) {
             JS_ASSERT(0);
         }
 
-        if (clasp != &StringClass &&
-            clasp != &NumberClass &&
-            clasp != &BooleanClass) {
+        if (clasp != &js_StringClass &&
+            clasp != &js_NumberClass &&
+            clasp != &js_BooleanClass) {
             goto bad;
         }
     }
 
     str = js_ValueToString(cx, Valueify(v));
     if (!str)
         return NULL;
     if (str->empty()) {
@@ -1928,19 +1928,19 @@ ToXMLList(JSContext *cx, jsval v)
             return obj;
         }
 
         clasp = obj->getClass();
         if (clasp->flags & JSCLASS_DOCUMENT_OBSERVER) {
             JS_ASSERT(0);
         }
 
-        if (clasp != &StringClass &&
-            clasp != &NumberClass &&
-            clasp != &BooleanClass) {
+        if (clasp != &js_StringClass &&
+            clasp != &js_NumberClass &&
+            clasp != &js_BooleanClass) {
             goto bad;
         }
     }
 
     str = js_ValueToString(cx, Valueify(v));
     if (!str)
         return NULL;
     if (str->empty()) {
@@ -2225,17 +2225,17 @@ GetNamespace(JSContext *cx, JSObject *qn
             }
         }
     }
 
     /* If we didn't match, make a new namespace from qn. */
     if (!match) {
         argv[0] = prefix ? STRING_TO_JSVAL(prefix) : JSVAL_VOID;
         argv[1] = STRING_TO_JSVAL(uri);
-        ns = js_ConstructObject(cx, &NamespaceClass, NULL, NULL,
+        ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL,
                                 2, Valueify(argv));
         if (!ns)
             return NULL;
         match = ns;
     }
     return match;
 }
 
@@ -2778,26 +2778,26 @@ ToAttributeName(JSContext *cx, jsval v)
         if (JSVAL_IS_PRIMITIVE(v)) {
             js_ReportValueError(cx, JSMSG_BAD_XML_ATTR_NAME,
                                 JSDVG_IGNORE_STACK, Valueify(v), NULL);
             return NULL;
         }
 
         obj = JSVAL_TO_OBJECT(v);
         clasp = obj->getClass();
-        if (clasp == &AttributeNameClass)
+        if (clasp == &js_AttributeNameClass)
             return obj;
 
-        if (clasp == &QNameClass) {
+        if (clasp == &js_QNameClass) {
             qn = obj;
             uri = qn->getNameURI();
             prefix = qn->getNamePrefix();
             name = qn->getQNameLocalName();
         } else {
-            if (clasp == &AnyNameClass) {
+            if (clasp == &js_AnyNameClass) {
                 name = cx->runtime->atomState.starAtom;
             } else {
                 if (!js_ValueToAtom(cx, Valueify(v), &name))
                     return NULL;
             }
             uri = prefix = cx->runtime->emptyString;
         }
     }
@@ -2848,19 +2848,19 @@ ToXMLName(JSContext *cx, jsval v, jsid *
     } else {
         if (JSVAL_IS_PRIMITIVE(v)) {
             ReportBadXMLName(cx, Valueify(v));
             return NULL;
         }
 
         obj = JSVAL_TO_OBJECT(v);
         clasp = obj->getClass();
-        if (clasp == &AttributeNameClass || clasp == &QNameClass)
+        if (clasp == &js_AttributeNameClass || clasp == &js_QNameClass)
             goto out;
-        if (clasp == &AnyNameClass) {
+        if (clasp == &js_AnyNameClass) {
             name = cx->runtime->atomState.starAtom;
             goto construct;
         }
         name = js_ValueToString(cx, Valueify(v));
         if (!name)
             return NULL;
     }
 
@@ -2889,17 +2889,17 @@ ToXMLName(JSContext *cx, jsval v, jsid *
         if (!name)
             return NULL;
         *funidp = JSID_VOID;
         return ToAttributeName(cx, STRING_TO_JSVAL(name));
     }
 
 construct:
     v = STRING_TO_JSVAL(name);
-    obj = js_ConstructObject(cx, &QNameClass, NULL, NULL, 1, Valueify(&v));
+    obj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, Valueify(&v));
     if (!obj)
         return NULL;
 
 out:
     if (!GetLocalNameFromFunctionQName(obj, funidp, cx))
         *funidp = JSID_VOID;
     return obj;
 
@@ -3202,31 +3202,31 @@ static JSBool
 DescendantsHelper(JSContext *cx, JSXML *xml, JSObject *nameqn, JSXML *list)
 {
     uint32 i, n;
     JSXML *attr, *kid;
 
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 
     if (xml->xml_class == JSXML_CLASS_ELEMENT &&
-        nameqn->getClass() == &AttributeNameClass) {
+        nameqn->getClass() == &js_AttributeNameClass) {
         for (i = 0, n = xml->xml_attrs.length; i < n; i++) {
             attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML);
             if (attr && MatchAttrName(nameqn, attr)) {
                 if (!Append(cx, list, attr))
                     return JS_FALSE;
             }
         }
     }
 
     for (i = 0, n = JSXML_LENGTH(xml); i < n; i++) {
         kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
         if (!kid)
             continue;
-        if (nameqn->getClass() != &AttributeNameClass &&
+        if (nameqn->getClass() != &js_AttributeNameClass &&
             MatchElemName(nameqn, kid)) {
             if (!Append(cx, list, kid))
                 return JS_FALSE;
         }
         if (!DescendantsHelper(cx, kid, nameqn, list))
             return JS_FALSE;
     }
     return JS_TRUE;
@@ -3665,17 +3665,17 @@ GetNamedProperty(JSContext *cx, JSXML *x
         JSXMLArrayCursor cursor(&xml->xml_kids);
         while (JSXML *kid = (JSXML *) cursor.getNext()) {
             if (kid->xml_class == JSXML_CLASS_ELEMENT &&
                 !GetNamedProperty(cx, kid, nameqn, list)) {
                 return JS_FALSE;
             }
         }
     } else if (xml->xml_class == JSXML_CLASS_ELEMENT) {
-        attrs = (nameqn->getClass() == &AttributeNameClass);
+        attrs = (nameqn->getClass() == &js_AttributeNameClass);
         if (attrs) {
             array = &xml->xml_attrs;
             matcher = MatchAttrName;
         } else {
             array = &xml->xml_kids;
             matcher = MatchElemName;
         }
 
@@ -3916,17 +3916,17 @@ PutProperty(JSContext *cx, JSObject *obj
             targetprop = xml->xml_targetprop;
             if (!targetprop || IS_STAR(targetprop->getQNameLocalName())) {
                 /* 2(c)(iv)(1-2), out of order w.r.t. 2(c)(iii). */
                 kid = js_NewXML(cx, JSXML_CLASS_TEXT);
                 if (!kid)
                     goto bad;
             } else {
                 nameobj = targetprop;
-                if (nameobj->getClass() == &AttributeNameClass) {
+                if (nameobj->getClass() == &js_AttributeNameClass) {
                     /*
                      * 2(c)(iii)(1-3).
                      * Note that rxml can't be null here, because target
                      * and targetprop are non-null.
                      */
                     ok = GetProperty(cx, rxml->object, id, &attrval);
                     if (!ok)
                         goto out;
@@ -4012,17 +4012,17 @@ PutProperty(JSContext *cx, JSObject *obj
 
         /* 2(e). */
         kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML);
         if (!kid)
             goto out;
         parent = kid->parent;
         if (kid->xml_class == JSXML_CLASS_ATTRIBUTE) {
             nameobj = kid->name;
-            if (nameobj->getClass() != &AttributeNameClass) {
+            if (nameobj->getClass() != &js_AttributeNameClass) {
                 nameobj = NewXMLAttributeName(cx, nameobj->getNameURI(), nameobj->getNamePrefix(),
                                               nameobj->getQNameLocalName());
                 if (!nameobj)
                     goto bad;
             }
             id = OBJECT_TO_JSID(nameobj);
 
             if (parent) {
@@ -4219,17 +4219,17 @@ PutProperty(JSContext *cx, JSObject *obj
         /*
          * 6.
          * Erratum: why is this done here, so early? use is way later....
          */
         ok = js_GetDefaultXMLNamespace(cx, &nsval);
         if (!ok)
             goto out;
 
-        if (nameobj->getClass() == &AttributeNameClass) {
+        if (nameobj->getClass() == &js_AttributeNameClass) {
             /* 7(a). */
             if (!js_IsXMLName(cx, OBJECT_TO_JSVAL(nameobj)))
                 goto out;
 
             /* 7(b-c). */
             if (vxml && vxml->xml_class == JSXML_CLASS_LIST) {
                 n = vxml->xml_kids.length;
                 if (n == 0) {
@@ -4472,17 +4472,17 @@ ResolveValue(JSContext *cx, JSXML *list,
 
     target = list->xml_target;
     targetprop = list->xml_targetprop;
     if (!target || !targetprop || IS_STAR(targetprop->getQNameLocalName())) {
         *result = NULL;
         return JS_TRUE;
     }
 
-    if (targetprop->getClass() == &AttributeNameClass) {
+    if (targetprop->getClass() == &js_AttributeNameClass) {
         *result = NULL;
         return JS_TRUE;
     }
 
     if (!ResolveValue(cx, target, &base))
         return JS_FALSE;
     if (!base) {
         *result = NULL;
@@ -4528,17 +4528,17 @@ HasNamedProperty(JSXML *xml, JSObject *n
             found = HasNamedProperty(kid, nameqn);
             if (found)
                 break;
         }
         return found;
     }
 
     if (xml->xml_class == JSXML_CLASS_ELEMENT) {
-        if (nameqn->getClass() == &AttributeNameClass) {
+        if (nameqn->getClass() == &js_AttributeNameClass) {
             array = &xml->xml_attrs;
             matcher = MatchAttrName;
         } else {
             array = &xml->xml_kids;
             matcher = MatchElemName;
         }
         for (i = 0, n = array->length; i < n; i++) {
             JSXML *kid = XMLARRAY_MEMBER(array, i, JSXML);
@@ -4567,17 +4567,17 @@ HasSimpleContent(JSXML *xml);
 
 static JSBool
 HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found)
 {
     JSObject *pobj;
     JSProperty *prop;
     JSXML *xml;
 
-    JS_ASSERT(obj->getClass() == &XMLClass);
+    JS_ASSERT(obj->getClass() == &js_XMLClass);
 
     if (!js_LookupProperty(cx, obj, funid, &pobj, &prop))
         return false;
     if (!prop) {
         xml = (JSXML *) obj->getPrivate();
         if (HasSimpleContent(xml)) {
             AutoObjectRooter tvr(cx);
 
@@ -4813,17 +4813,17 @@ xml_deleteProperty(JSContext *cx, JSObje
     } else {
         nameqn = ToXMLName(cx, idval, &funid);
         if (!nameqn)
             return false;
         if (!JSID_IS_VOID(funid))
             return js_DeleteProperty(cx, obj, funid, rval, false);
 
         DeleteNamedProperty(cx, xml, nameqn,
-                            nameqn->getClass() == &AttributeNameClass);
+                            nameqn->getClass() == &js_AttributeNameClass);
     }
 
     /*
      * If this object has its own (mutable) scope,  then we may have added a
      * property to the scope in xml_lookupProperty for it to return to mean
      * "found" and to provide a handle for access operations to call the
      * property's getter or setter. But now it's time to remove any such
      * property, to purge the property cache and remove the scope entry.
@@ -5107,17 +5107,17 @@ js_ConcatenateXML(JSContext *cx, JSObjec
         goto out;
 
     vp->setObject(*listobj);
 out:
     js_LeaveLocalRootScopeWithResult(cx, *vp);
     return ok;
 }
 
-JS_FRIEND_DATA(Class) js::XMLClass = {
+JS_FRIEND_DATA(Class) js_XMLClass = {
     js_XML_str,
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_XML),
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
@@ -5157,17 +5157,17 @@ StartNonListXMLMethod(JSContext *cx, jsv
 
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp));
     JS_ASSERT(JSVAL_TO_OBJECT(*vp)->isFunction());
 
     *objp = ToObject(cx, Valueify(&vp[1]));
     if (!*objp)
         return NULL;
     if (!(*objp)->isXML()) {
-        ReportIncompatibleMethod(cx, Valueify(vp), &XMLClass);
+        ReportIncompatibleMethod(cx, Valueify(vp), &js_XMLClass);
         return NULL;
     }
     xml = (JSXML *) (*objp)->getPrivate();
     if (!xml || xml->xml_class != JSXML_CLASS_LIST)
         return xml;
 
     if (xml->xml_kids.length == 1) {
         xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
@@ -5191,17 +5191,17 @@ StartNonListXMLMethod(JSContext *cx, jsv
 }
 
 /* Beware: these two are not bracketed by JS_BEGIN/END_MACRO. */
 #define XML_METHOD_PROLOG                                                     \
     JSObject *obj = ToObject(cx, Valueify(&vp[1]));                           \
     if (!obj)                                                                 \
         return JS_FALSE;                                                      \
     if (!obj->isXML()) {                                                      \
-        ReportIncompatibleMethod(cx, Valueify(vp), &XMLClass);                \
+        ReportIncompatibleMethod(cx, Valueify(vp), &js_XMLClass);             \
         return JS_FALSE;                                                      \
     }                                                                         \
     JSXML *xml = (JSXML *)obj->getPrivate();                                  \
     if (!xml)                                                                 \
         return JS_FALSE
 
 #define NON_LIST_XML_METHOD_PROLOG                                            \
     JSObject *obj;                                                            \
@@ -5678,17 +5678,17 @@ xml_hasOwnProperty(JSContext *cx, uintN 
 {
     jsval name;
     JSBool found;
 
     JSObject *obj = ToObject(cx, Valueify(&vp[1]));
     if (!obj)
         return JS_FALSE;
     if (!obj->isXML()) {
-        ReportIncompatibleMethod(cx, Valueify(vp), &XMLClass);
+        ReportIncompatibleMethod(cx, Valueify(vp), &js_XMLClass);
         return JS_FALSE;
     }
 
     name = argc != 0 ? vp[2] : JSVAL_VOID;
     if (!HasProperty(cx, obj, name, &found))
         return JS_FALSE;
     if (found) {
         *vp = JSVAL_TRUE;
@@ -6475,23 +6475,23 @@ xml_setName(JSContext *cx, uintN argc, j
     if (!JSXML_HAS_NAME(xml))
         return JS_TRUE;
 
     if (argc == 0) {
         name = STRING_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
     } else {
         name = vp[2];
         if (!JSVAL_IS_PRIMITIVE(name) &&
-            JSVAL_TO_OBJECT(name)->getClass() == &QNameClass &&
+            JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass &&
             !(nameqn = JSVAL_TO_OBJECT(name))->getNameURI()) {
             name = vp[2] = nameqn->getQNameLocalNameVal();
         }
     }
 
-    nameqn = js_ConstructObject(cx, &QNameClass, NULL, NULL, 1, Valueify(&name));
+    nameqn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, Valueify(&name));
     if (!nameqn)
         return JS_FALSE;
 
     /* ECMA-357 13.4.4.35 Step 4. */
     if (xml->xml_class == JSXML_CLASS_PROCESSING_INSTRUCTION)
         nameqn->setNameURI(cx->runtime->emptyString);
 
     xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
@@ -6583,26 +6583,26 @@ xml_setNamespace(JSContext *cx, uintN ar
     NON_LIST_XML_METHOD_PROLOG;
     if (!JSXML_HAS_NAME(xml))
         return JS_TRUE;
 
     xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
     if (!xml)
         return JS_FALSE;
 
-    ns = js_ConstructObject(cx, &NamespaceClass, NULL, obj,
+    ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj,
                             argc == 0 ? 0 : 1, Valueify(vp + 2));
     if (!ns)
         return JS_FALSE;
     vp[0] = OBJECT_TO_JSVAL(ns);
     ns->setNamespaceDeclared(JSVAL_TRUE);
 
     qnargv[0] = OBJECT_TO_JSVAL(ns);
     qnargv[1] = OBJECT_TO_JSVAL(xml->name);
-    qn = js_ConstructObject(cx, &QNameClass, NULL, NULL, 2, Valueify(qnargv));
+    qn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 2, Valueify(qnargv));
     if (!qn)
         return JS_FALSE;
 
     xml->name = qn;
 
     /*
      * Erratum: the spec fails to update the governing in-scope namespaces.
      * See the erratum noted in xml_setName, above.
@@ -6920,17 +6920,17 @@ XML(JSContext *cx, uintN argc, Value *vp
     xobj = ToXML(cx, v);
     if (!xobj)
         return JS_FALSE;
     xml = (JSXML *) xobj->getPrivate();
 
     if (IsConstructing(vp) && !JSVAL_IS_PRIMITIVE(v)) {
         vobj = JSVAL_TO_OBJECT(v);
         clasp = vobj->getClass();
-        if (clasp == &XMLClass ||
+        if (clasp == &js_XMLClass ||
             (clasp->flags & JSCLASS_DOCUMENT_OBSERVER)) {
             copy = DeepCopy(cx, xml, NULL, 0);
             if (!copy)
                 return JS_FALSE;
             vp->setObject(*copy->object);
             return JS_TRUE;
         }
     }
@@ -7066,17 +7066,17 @@ js_NewXMLObject(JSContext *cx, JSXMLClas
 }
 
 static JSObject *
 NewXMLObject(JSContext *cx, JSXML *xml)
 {
     JSObject *obj;
 
     JSObject *parent = GetGlobalForScopeChain(cx);
-    obj = NewNonFunction<WithProto::Class>(cx, &XMLClass, NULL, parent);
+    obj = NewNonFunction<WithProto::Class>(cx, &js_XMLClass, NULL, parent);
     if (!obj)
         return NULL;
     obj->setPrivate(xml);
     return obj;
 }
 
 JSObject *
 js_GetXMLObject(JSContext *cx, JSXML *xml)
@@ -7098,26 +7098,26 @@ js_GetXMLObject(JSContext *cx, JSXML *xm
 
 JSObject *
 js_InitNamespaceClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     GlobalObject *global = obj->asGlobal();
 
-    JSObject *namespaceProto = global->createBlankPrototype(cx, &NamespaceClass);
+    JSObject *namespaceProto = global->createBlankPrototype(cx, &js_NamespaceClass);
     if (!namespaceProto)
         return NULL;
     JSFlatString *empty = cx->runtime->emptyString;
     namespaceProto->setNamePrefix(empty);
     namespaceProto->setNameURI(empty);
     namespaceProto->syncSpecialEquality();
 
     const uintN NAMESPACE_CTOR_LENGTH = 2;
-    JSFunction *ctor = global->createConstructor(cx, Namespace, &NamespaceClass,
+    JSFunction *ctor = global->createConstructor(cx, Namespace, &js_NamespaceClass,
                                                  CLASS_ATOM(cx, Namespace),
                                                  NAMESPACE_CTOR_LENGTH);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, namespaceProto))
         return NULL;
 
@@ -7132,26 +7132,26 @@ js_InitNamespaceClass(JSContext *cx, JSO
 
 JSObject *
 js_InitQNameClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     GlobalObject *global = obj->asGlobal();
 
-    JSObject *qnameProto = global->createBlankPrototype(cx, &QNameClass);
+    JSObject *qnameProto = global->createBlankPrototype(cx, &js_QNameClass);
     if (!qnameProto)
         return NULL;
     JSAtom *empty = cx->runtime->emptyString;
     if (!InitXMLQName(cx, qnameProto, empty, empty, empty))
         return NULL;
     qnameProto->syncSpecialEquality();
 
     const uintN QNAME_CTOR_LENGTH = 2;
-    JSFunction *ctor = global->createConstructor(cx, QName, &QNameClass,
+    JSFunction *ctor = global->createConstructor(cx, QName, &js_QNameClass,
                                                  CLASS_ATOM(cx, QName), QNAME_CTOR_LENGTH);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, qnameProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, qnameProto, NULL, qname_methods))
@@ -7165,33 +7165,33 @@ js_InitQNameClass(JSContext *cx, JSObjec
 
 JSObject *
 js_InitXMLClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
     GlobalObject *global = obj->asGlobal();
 
-    JSObject *xmlProto = global->createBlankPrototype(cx, &XMLClass);
+    JSObject *xmlProto = global->createBlankPrototype(cx, &js_XMLClass);
     if (!xmlProto)
         return NULL;
     JSXML *xml = js_NewXML(cx, JSXML_CLASS_TEXT);
     if (!xml)
         return NULL;
     xmlProto->setPrivate(xml);
     xml->object = xmlProto;
 
     /* Don't count this as a real content-created XML object. */
     if (!cx->runningWithTrustedPrincipals()) {
         JS_ASSERT(sE4XObjectsCreated > 0);
         --sE4XObjectsCreated;
     }
 
     const uintN XML_CTOR_LENGTH = 1;
-    JSFunction *ctor = global->createConstructor(cx, XML, &XMLClass, CLASS_ATOM(cx, XML),
+    JSFunction *ctor = global->createConstructor(cx, XML, &js_XMLClass, CLASS_ATOM(cx, XML),
                                                  XML_CTOR_LENGTH);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, xmlProto))
         return NULL;
 
     if (!DefinePropertiesAndBrand(cx, xmlProto, NULL, xml_methods) ||
@@ -7288,28 +7288,28 @@ js_GetDefaultXMLNamespace(JSContext *cx,
     JSObject *ns, *obj, *tmp;
     jsval v;
 
     JSObject *scopeChain = GetScopeChain(cx);
 
     obj = NULL;
     for (tmp = scopeChain; tmp; tmp = tmp->getParent()) {
         Class *clasp = tmp->getClass();
-        if (clasp == &BlockClass || clasp == &WithClass)
+        if (clasp == &js_BlockClass || clasp == &js_WithClass)
             continue;
         if (!tmp->getProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, Valueify(&v)))
             return JS_FALSE;
         if (!JSVAL_IS_PRIMITIVE(v)) {
             *vp = v;
             return JS_TRUE;
         }
         obj = tmp;
     }
 
-    ns = js_ConstructObject(cx, &NamespaceClass, NULL, obj, 0, NULL);
+    ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj, 0, NULL);
     if (!ns)
         return JS_FALSE;
     v = OBJECT_TO_JSVAL(ns);
     if (!obj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, Valueify(v),
                              PropertyStub, StrictPropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
     }
     *vp = v;
@@ -7317,17 +7317,17 @@ js_GetDefaultXMLNamespace(JSContext *cx,
 }
 
 JSBool
 js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
 {
     Value argv[2];
     argv[0].setString(cx->runtime->emptyString);
     argv[1] = v;
-    JSObject *ns = js_ConstructObject(cx, &NamespaceClass, NULL, NULL, 2, argv);
+    JSObject *ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, 2, argv);
     if (!ns)
         return JS_FALSE;
 
     JSObject &varobj = cx->fp()->varObj();
     if (!varobj.defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
                                PropertyStub, StrictPropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
     }
@@ -7402,17 +7402,17 @@ js_ValueToXMLString(JSContext *cx, const
 }
 
 JSBool
 js_GetAnyName(JSContext *cx, jsid *idp)
 {
     JSObject *global = cx->hasfp() ? cx->fp()->scopeChain().getGlobal() : cx->globalObject;
     Value v = global->getReservedSlot(JSProto_AnyName);
     if (v.isUndefined()) {
-        JSObject *obj = NewNonFunction<WithProto::Given>(cx, &AnyNameClass, NULL, global);
+        JSObject *obj = NewNonFunction<WithProto::Given>(cx, &js_AnyNameClass, NULL, global);
         if (!obj)
             return false;
 
         JS_ASSERT(!obj->getProto());
 
         JSRuntime *rt = cx->runtime;
         if (!InitXMLQName(cx, obj, rt->emptyString, rt->emptyString, rt->atomState.starAtom))
             return false;
@@ -7434,36 +7434,36 @@ js_FindXMLProperty(JSContext *cx, const 
     jsid funid;
     JSObject *obj, *target, *proto, *pobj;
     JSXML *xml;
     JSBool found;
     JSProperty *prop;
 
     JS_ASSERT(nameval.isObject());
     nameobj = &nameval.toObject();
-    if (nameobj->getClass() == &AnyNameClass) {
+    if (nameobj->getClass() == &js_AnyNameClass) {
         v = STRING_TO_JSVAL(cx->runtime->atomState.starAtom);
-        nameobj = js_ConstructObject(cx, &QNameClass, NULL, NULL, 1,
+        nameobj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1,
                                      Valueify(&v));
         if (!nameobj)
             return JS_FALSE;
     } else {
-        JS_ASSERT(nameobj->getClass() == &AttributeNameClass ||
-                  nameobj->getClass() == &QNameClass);
+        JS_ASSERT(nameobj->getClass() == &js_AttributeNameClass ||
+                  nameobj->getClass() == &js_QNameClass);
     }
 
     qn = nameobj;
     if (!GetLocalNameFromFunctionQName(qn, &funid, cx))
         funid = JSID_VOID;
 
     obj = cx->stack.currentScriptedScopeChain();
     do {
         /* Skip any With object that can wrap XML. */
         target = obj;
-        while (target->getClass() == &WithClass) {
+        while (target->getClass() == &js_WithClass) {
              proto = target->getProto();
              if (!proto)
                  break;
              target = proto;
         }
 
         if (target->isXML()) {
             if (JSID_IS_VOID(funid)) {
--- a/js/src/jsxml.h
+++ b/js/src/jsxml.h
@@ -214,22 +214,58 @@ extern void
 js_TraceXML(JSTracer *trc, JSXML *xml);
 
 extern JSObject *
 js_NewXMLObject(JSContext *cx, JSXMLClass xml_class);
 
 extern JSObject *
 js_GetXMLObject(JSContext *cx, JSXML *xml);
 
+extern JS_FRIEND_DATA(js::Class) js_XMLClass;
+extern JS_FRIEND_DATA(js::Class) js_NamespaceClass;
+extern JS_FRIEND_DATA(js::Class) js_QNameClass;
+extern JS_FRIEND_DATA(js::Class) js_AttributeNameClass;
+extern JS_FRIEND_DATA(js::Class) js_AnyNameClass;
+extern js::Class                 js_XMLFilterClass;
+
 /*
  * Methods to test whether an object or a value is of type "xml" (per typeof).
  */
+inline bool
+JSObject::isXML() const
+{
+    return getClass() == &js_XMLClass;
+}
+
+inline bool
+JSObject::isXMLId() const
+{
+    js::Class *clasp = getClass();
+    return clasp == &js_QNameClass ||
+           clasp == &js_AttributeNameClass ||
+           clasp == &js_AnyNameClass;
+}
 
 #define VALUE_IS_XML(v)      (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isXML())
 
+inline bool
+JSObject::isNamespace() const
+{
+    return getClass() == &js_NamespaceClass;
+}
+
+inline bool
+JSObject::isQName() const
+{
+    js::Class* clasp = getClass();
+    return clasp == &js_QNameClass ||
+           clasp == &js_AttributeNameClass ||
+           clasp == &js_AnyNameClass;
+}
+
 static inline bool
 IsXML(const js::Value &v)
 {
     return v.isObject() && v.toObject().isXML();
 }
 
 extern JSObject *
 js_InitNamespaceClass(JSContext *cx, JSObject *obj);
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -199,18 +199,18 @@ static const JSC::MacroAssembler::Regist
     }
 
     Jump guardShape(RegisterID objReg, JSObject *obj) {
         return branch32(NotEqual, Address(objReg, offsetof(JSObject, objShape)),
                         Imm32(obj->shape()));
     }
 
     Jump testFunction(Condition cond, RegisterID fun) {
-        return branchPtr(cond, Address(fun, JSObject::offsetOfClassPointer()),
-                         ImmPtr(&FunctionClass));
+        return branchPtr(cond, Address(fun, offsetof(JSObject, clasp)),
+                         ImmPtr(&js_FunctionClass));
     }
 
     /*
      * Finds and returns the address of a known object and slot.
      */
     Address objSlotRef(JSObject *obj, RegisterID reg, uint32 slot) {
         move(ImmPtr(obj), reg);
         if (obj->isFixedSlot(slot)) {
@@ -806,25 +806,25 @@ static const JSC::MacroAssembler::Regist
         move(Imm32(fun->nargs), reg);
         overflowArgs.linkTo(label(), this);
         lshiftPtr(Imm32(3), reg);
         negPtr(reg);
         addPtr(JSFrameReg, reg);
     }
 
     void loadObjClass(RegisterID objReg, RegisterID destReg) {
-        loadPtr(Address(objReg, JSObject::offsetOfClassPointer()), destReg);
+        loadPtr(Address(objReg, offsetof(JSObject, clasp)), destReg);
     }
 
     Jump testClass(Condition cond, RegisterID claspReg, js::Class *clasp) {
         return branchPtr(cond, claspReg, ImmPtr(clasp));
     }
 
     Jump testObjClass(Condition cond, RegisterID objReg, js::Class *clasp) {
-        return branchPtr(cond, Address(objReg, JSObject::offsetOfClassPointer()), ImmPtr(clasp));
+        return branchPtr(cond, Address(objReg, offsetof(JSObject, clasp)), ImmPtr(clasp));
     }
 
     void branchValue(Condition cond, RegisterID reg, int32 value, RegisterID result)
     {
         if (Registers::maskReg(result) & Registers::SingleByteRegs) {
             set32(cond, reg, Imm32(value), result);
         } else {
             Jump j = branch32(cond, reg, Imm32(value));
@@ -1284,17 +1284,17 @@ static const JSC::MacroAssembler::Regist
             addPtr(Imm32(-(int)sizeof(JSObject)), result);
         } else {
             JS_ASSERT(!templateObject->newType);
             addPtr(Imm32(-thingSize), result);
             storePtr(ImmPtr(NULL), Address(result, JSObject::offsetOfSlots()));
         }
 
         storePtr(ImmPtr(templateObject->lastProp), Address(result, offsetof(JSObject, lastProp)));
-        storePtr(ImmPtr(templateObject->getClass()), Address(result, JSObject::offsetOfClassPointer()));
+        storePtr(ImmPtr(templateObject->clasp), Address(result, offsetof(JSObject, clasp)));
         store32(Imm32(templateObject->flags), Address(result, offsetof(JSObject, flags)));
         store32(Imm32(templateObject->objShape), Address(result, offsetof(JSObject, objShape)));
         storePtr(ImmPtr(templateObject->newType), Address(result, offsetof(JSObject, newType)));
         storePtr(ImmPtr(templateObject->parent), Address(result, offsetof(JSObject, parent)));
         storePtr(ImmPtr(templateObject->privateData), Address(result, offsetof(JSObject, privateData)));
         storePtr(ImmPtr((void *) templateObject->capacity), Address(result, offsetof(JSObject, capacity)));
         storePtr(ImmPtr(templateObject->type()), Address(result, JSObject::offsetOfType()));
 
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -5589,17 +5589,17 @@ mjit::Compiler::iterNext()
     RegisterID reg = frame.tempRegForData(fe);
 
     /* Is it worth trying to pin this longer? Prolly not. */
     frame.pinReg(reg);
     RegisterID T1 = frame.allocReg();
     frame.unpinReg(reg);
 
     /* Test clasp */
-    Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass);
+    Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &js_IteratorClass);
     stubcc.linkExit(notFast, Uses(1));
 
     /* Get private from iter obj. */
     masm.loadObjPrivate(reg, T1);
 
     RegisterID T3 = frame.allocReg();
     RegisterID T4 = frame.allocReg();
 
@@ -5643,17 +5643,17 @@ mjit::Compiler::iterMore(jsbytecode *tar
     if (!frame.syncForBranch(target, Uses(1)))
         return false;
 
     FrameEntry *fe = frame.peek(-1);
     RegisterID reg = frame.tempRegForData(fe);
     RegisterID tempreg = frame.allocReg();
 
     /* Test clasp */
-    Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass);
+    Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &js_IteratorClass);
     stubcc.linkExitForBranch(notFast);
 
     /* Get private from iter obj. */
     masm.loadObjPrivate(reg, reg);
 
     /* Test that the iterator supports fast iteration. */
     notFast = masm.branchTest32(Assembler::NonZero, Address(reg, offsetof(NativeIterator, flags)),
                                 Imm32(JSITER_FOREACH));
@@ -5682,17 +5682,17 @@ mjit::Compiler::iterEnd()
     FrameEntry *fe= frame.peek(-1);
     RegisterID reg = frame.tempRegForData(fe);
 
     frame.pinReg(reg);
     RegisterID T1 = frame.allocReg();
     frame.unpinReg(reg);
 
     /* Test clasp */
-    Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass);
+    Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, &js_IteratorClass);
     stubcc.linkExit(notIterator, Uses(1));
 
     /* Get private from iter obj. */
     masm.loadObjPrivate(reg, T1);
 
     RegisterID T2 = frame.allocReg();
 
     /* Load flags. */
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -1565,17 +1565,17 @@ mjit::Compiler::jsop_setelem(bool popGua
     ic.fastPathStart = masm.label();
 
     // Create the common out-of-line sync block, taking care to link previous
     // guards here after.
     RESERVE_OOL_SPACE(stubcc.masm);
     ic.slowPathStart = stubcc.syncExit(Uses(3));
 
     // Guard obj is a dense array.
-    ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &ArrayClass);
+    ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &js_ArrayClass);
     stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart);
 
     // Guard in range of initialized length.
     Jump initlenGuard = masm.guardArrayExtent(offsetof(JSObject, initializedLength),
                                               ic.objReg, ic.key, Assembler::BelowOrEqual);
     stubcc.linkExitDirect(initlenGuard, ic.slowPathStart);
 
     // Load the dynamic slots vector.
@@ -2115,17 +2115,17 @@ mjit::Compiler::jsop_getelem(bool isCall
     if (id->mightBeType(JSVAL_TYPE_INT32)) {
         // Always test the type first (see comment in PolyIC.h).
         if (!id->isTypeKnown()) {
             ic.typeGuard = masm.testInt32(Assembler::NotEqual, ic.typeReg);
             stubcc.linkExitDirect(ic.typeGuard.get(), ic.slowPathStart);
         }
 
         // Guard on the clasp.
-        ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &ArrayClass);
+        ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &js_ArrayClass);
         stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart);
 
         Int32Key key = id->isConstant()
                        ? Int32Key::FromConstant(id->getValue().toInt32())
                        : Int32Key::FromRegister(ic.id.dataReg());
 
         Assembler::FastArrayLoadFails fails =
             masm.fastArrayLoad(ic.objReg, key, ic.typeReg, ic.objReg);
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -110,17 +110,17 @@ top:
             //       bytecode compiler cannot throw, so this is not possible.
             if (offset - tn->start > tn->length)
                 continue;
             if (tn->stackDepth > cx->regs().sp - fp->base())
                 continue;
 
             jsbytecode *pc = script->main() + tn->start + tn->length;
             cx->regs().pc = pc;
-            JSBool ok = UnwindScope(cx, tn->stackDepth, JS_TRUE);
+            JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE);
             JS_ASSERT(cx->regs().sp == fp->base() + tn->stackDepth);
 
             switch (tn->kind) {
                 case JSTRY_CATCH:
                   JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENTERBLOCK);
 
 #if JS_HAS_GENERATORS
                   /* Catch cannot intercept the closing of a generator. */
@@ -173,17 +173,17 @@ top:
 
 /*
  * Clean up a frame and return.
  */
 static void
 InlineReturn(VMFrame &f)
 {
     JS_ASSERT(f.fp() != f.entryfp);
-    JS_ASSERT(!IsActiveWithOrBlock(f.cx, f.fp()->scopeChain(), 0));
+    JS_ASSERT(!js_IsActiveWithOrBlock(f.cx, &f.fp()->scopeChain(), 0));
     f.cx->stack.popInlineFrame(f.regs);
 
     DebugOnly<JSOp> op = js_GetOpcode(f.cx, f.fp()->script(), f.regs.pc);
     JS_ASSERT(op == JSOP_CALL ||
               op == JSOP_NEW ||
               op == JSOP_EVAL ||
               op == JSOP_FUNCALL ||
               op == JSOP_FUNAPPLY);
@@ -598,17 +598,17 @@ js_InternalThrow(VMFrame &f)
             break;
 
         // The JIT guarantees that ScriptEpilogue() has always been run
         // upon exiting to its caller. This is important for consistency,
         // where execution modes make similar guarantees about prologues
         // and epilogues. RunTracer(), Interpret(), and Invoke() all
         // rely on this property.
         JS_ASSERT(!f.fp()->finishedInInterpreter());
-        UnwindScope(cx, 0, cx->isExceptionPending());
+        js_UnwindScope(cx, 0, cx->isExceptionPending());
         ScriptEpilogue(f.cx, f.fp(), false);
 
         // Don't remove the last frame, this is the responsibility of
         // JaegerShot()'s caller. We only guarantee that ScriptEpilogue()
         // has been run.
         if (f.entryfp == f.fp())
             break;
 
@@ -777,17 +777,17 @@ HandleErrorInExcessFrame(VMFrame &f, Sta
             }
         }
 
         /* Don't unwind if this was the entry frame. */
         if (fp == stopFp)
             break;
 
         /* Unwind and return. */
-        returnOK &= UnwindScope(cx, 0, returnOK || cx->isExceptionPending());
+        returnOK &= bool(js_UnwindScope(cx, 0, returnOK || cx->isExceptionPending()));
         returnOK = ScriptEpilogue(cx, fp, returnOK);
         InlineReturn(f);
     }
 
     JS_ASSERT(&f.regs == &cx->regs());
     JS_ASSERT_IF(!returnOK, cx->fp() == stopFp);
 
     return returnOK;
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -770,17 +770,17 @@ class CallCompiler : public BaseCompiler
         Assembler masm;
 
         Registers tempRegs(Registers::AvailRegs);
         tempRegs.takeReg(ic.funObjReg);
 
         RegisterID t0 = tempRegs.takeAnyReg().reg();
 
         /* Guard that it's actually a function object. */
-        Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, &FunctionClass);
+        Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, &js_FunctionClass);
 
         /* Guard that it's the same function. */
         JSFunction *fun = obj->getFunctionPrivate();
         masm.loadObjPrivate(ic.funObjReg, t0);
         Jump funGuard = masm.branchPtr(Assembler::NotEqual, t0, ImmPtr(fun));
         Jump done = masm.jump();
 
         LinkerHelper linker(masm, JSC::METHOD_CODE);
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -318,17 +318,17 @@ class SetPropCompiler : public PICStubCo
              */
             Jump typeGuard = masm.branchPtr(Assembler::NotEqual,
                                             Address(pic.objReg, JSObject::offsetOfType()),
                                             ImmPtr(obj->getType(cx)));
             if (!otherGuards.append(typeGuard))
                 return error();
         }
 
-        JS_ASSERT_IF(!shape->hasDefaultSetter(), obj->isCall());
+        JS_ASSERT_IF(!shape->hasDefaultSetter(), obj->getClass() == &js_CallClass);
 
         MaybeJump skipOver;
 
         if (adding) {
             JS_ASSERT(shape->hasSlot());
             pic.shapeRegHasBaseShape = false;
 
             /* Emit shape guards for the object's prototype chain. */
@@ -909,18 +909,18 @@ class GetPropCompiler : public PICStubCo
         return Lookup_Cacheable;
     }
 
     LookupStatus generateArrayLengthStub()
     {
         Assembler masm;
 
         masm.loadObjClass(pic.objReg, pic.shapeReg);
-        Jump isDense = masm.testClass(Assembler::Equal, pic.shapeReg, &ArrayClass);
-        Jump notArray = masm.testClass(Assembler::NotEqual, pic.shapeReg, &SlowArrayClass);
+        Jump isDense = masm.testClass(Assembler::Equal, pic.shapeReg, &js_ArrayClass);
+        Jump notArray = masm.testClass(Assembler::NotEqual, pic.shapeReg, &js_SlowArrayClass);
 
         isDense.linkTo(masm.label(), &masm);
         masm.load32(Address(pic.objReg, offsetof(JSObject, privateData)), pic.objReg);
         Jump oob = masm.branch32(Assembler::Above, pic.objReg, Imm32(JSVAL_INT_MAX));
         masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
         Jump done = masm.jump();
 
         pic.updatePCCounters(cx, masm);
@@ -1489,17 +1489,17 @@ class ScopeNameCompiler : public PICStub
         Jump finalShape = masm.branch32(Assembler::NotEqual, pic.shapeReg, Imm32(getprop.holder->shape()));
 
         /*
          * For CALLNAME we have to store the this-value. Since we guarded on
          * IsCacheableNonGlobalScope it's always undefined. This matches the decision
          * tree in ComputeImplicitThis.
          */
         if (pic.kind == ic::PICInfo::CALLNAME) {
-            JS_ASSERT(obj->isCall());
+            JS_ASSERT(obj->getClass() == &js_CallClass);
             Value *thisVp = &cx->regs().sp[1];
             Address thisSlot(JSFrameReg, StackFrame::offsetOfFixed(thisVp - cx->fp()->slots()));
             masm.storeValue(UndefinedValue(), thisSlot);
         }
 
         /* Get callobj's stack frame. */
         masm.loadObjPrivate(pic.objReg, pic.shapeReg);
 
@@ -1592,17 +1592,17 @@ class ScopeNameCompiler : public PICStub
         return update(getprop.obj);
     }
 
     LookupStatus update(JSObject *obj)
     {
         if (obj != getprop.holder)
             return disable("property is on proto of a scope object");
 
-        if (obj->isCall())
+        if (obj->getClass() == &js_CallClass)
             return generateCallStub(obj);
 
         LookupStatus status = getprop.testForGet();
         if (status != Lookup_Cacheable)
             return status;
 
         if (!obj->getParent())
             return generateGlobalStub(obj);
@@ -1636,17 +1636,17 @@ class ScopeNameCompiler : public PICStub
                 return false;
             if (thisvp)
                 return ComputeImplicitThis(cx, obj, *vp, thisvp);
             return true;
         }
 
         const Shape *shape = getprop.shape;
         JSObject *normalized = obj;
-        if (obj->isWith() && !shape->hasDefaultGetter())
+        if (obj->getClass() == &js_WithClass && !shape->hasDefaultGetter())
             normalized = js_UnwrapWithObject(cx, obj);
         NATIVE_GET(cx, normalized, holder, shape, JSGET_METHOD_BARRIER, vp, return false);
         if (thisvp)
             return ComputeImplicitThis(cx, normalized, *vp, thisvp);
         return true;
     }
 };
 
@@ -2044,17 +2044,17 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pi
             regs.sp[-1] = lval;
             regs.sp[-2] = rval;
         }
     }
 
 #if JS_HAS_NO_SUCH_METHOD
     if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) {
         regs.sp[-2].setString(JSID_TO_STRING(id));
-        if (!OnUnknownMethod(cx, regs.sp - 2))
+        if (!js_OnUnknownMethod(cx, regs.sp - 2))
             THROW();
     }
 #endif
 
     types::TypeScript::Monitor(f.cx, f.script(), f.pc(), regs.sp[-2]);
 
     if (monitor.recompiled())
         return;
@@ -2800,17 +2800,17 @@ ic::CallElement(VMFrame &f, ic::GetEleme
     /* Get or set the element. */
     if (!js_GetMethod(cx, thisObj, id, JSGET_NO_METHOD_BARRIER, &f.regs.sp[-2]))
         THROW();
 
 #if JS_HAS_NO_SUCH_METHOD
     if (JS_UNLIKELY(f.regs.sp[-2].isPrimitive()) && thisv.isObject()) {
         f.regs.sp[-2] = f.regs.sp[-1];
         f.regs.sp[-1].setObject(*thisObj);
-        if (!OnUnknownMethod(cx, f.regs.sp - 2))
+        if (!js_OnUnknownMethod(cx, f.regs.sp - 2))
             THROW();
     } else
 #endif
     {
         f.regs.sp[-1] = thisv;
     }
     if (!JSID_IS_INT(id))
         types::TypeScript::MonitorUnknown(f.cx, f.script(), f.pc());
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -384,17 +384,17 @@ NameOp(VMFrame &f, JSObject *obj, bool c
 
         /* Take the slow path if prop was not found in a native object. */
         if (!obj->isNative() || !obj2->isNative()) {
             if (!obj->getProperty(cx, id, &rval))
                 return NULL;
         } else {
             shape = (Shape *)prop;
             JSObject *normalized = obj;
-            if (normalized->isWith() && !shape->hasDefaultGetter())
+            if (normalized->getClass() == &js_WithClass && !shape->hasDefaultGetter())
                 normalized = js_UnwrapWithObject(cx, normalized);
             NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval, return NULL);
         }
 
         /*
          * If this is an incop, update the property's types themselves,
          * to capture the type effect on the intermediate value.
          */
@@ -547,17 +547,17 @@ stubs::CallElem(VMFrame &f)
     /* Get or set the element. */
     if (!js_GetMethod(cx, thisObj, id, JSGET_NO_METHOD_BARRIER, &regs.sp[-2]))
         THROW();
 
 #if JS_HAS_NO_SUCH_METHOD
     if (JS_UNLIKELY(regs.sp[-2].isPrimitive()) && thisv.isObject()) {
         regs.sp[-2] = regs.sp[-1];
         regs.sp[-1].setObject(*thisObj);
-        if (!OnUnknownMethod(cx, regs.sp - 2))
+        if (!js_OnUnknownMethod(cx, regs.sp - 2))
             THROW();
     } else
 #endif
     {
         regs.sp[-1] = thisv;
     }
     if (!JSID_IS_INT(id))
         TypeScript::MonitorUnknown(cx, f.script(), f.pc());
@@ -1346,17 +1346,17 @@ stubs::NewInitArray(VMFrame &f, uint32 c
 void JS_FASTCALL
 stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
 {
     JSContext *cx = f.cx;
     TypeObject *type = (TypeObject *) f.scratch;
 
     if (!baseobj) {
         gc::AllocKind kind = GuessObjectGCKind(0, false);
-        JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
+        JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
         if (!obj)
             THROW();
         if (type)
             obj->setType(type);
         f.regs.sp[0].setObject(*obj);
         return;
     }
 
@@ -1735,17 +1735,17 @@ stubs::CallProp(VMFrame &f, JSAtom *orig
             }
             regs.sp[-1] = lval;
             regs.sp[-2] = rval;
         }
     }
 #if JS_HAS_NO_SUCH_METHOD
     if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) {
         regs.sp[-2].setString(origAtom);
-        if (!OnUnknownMethod(cx, regs.sp - 2))
+        if (!js_OnUnknownMethod(cx, regs.sp - 2))
             THROW();
     }
 #endif
     TypeScript::Monitor(cx, f.script(), f.pc(), rval);
 }
 
 void JS_FASTCALL
 stubs::Iter(VMFrame &f, uint32 flags)
@@ -2011,19 +2011,20 @@ stubs::EnterBlock(VMFrame &f, JSObject *
     /*
      * The young end of fp->scopeChain() may omit blocks if we haven't closed
      * over them, but if there are any closure blocks on fp->scopeChain(), they'd
      * better be (clones of) ancestors of the block we're entering now;
      * anything else we should have popped off fp->scopeChain() when we left its
      * static scope.
      */
     JSObject *obj2 = &fp->scopeChain();
-    while (obj2->isWith())
+    Class *clasp;
+    while ((clasp = obj2->getClass()) == &js_WithClass)
         obj2 = obj2->getParent();
-    if (obj2->isBlock() &&
+    if (clasp == &js_BlockClass &&
         obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) {
         JSObject *youngestProto = obj2->getProto();
         JS_ASSERT(youngestProto->isStaticBlock());
         JSObject *parent = obj;
         while ((parent = parent->getParent()) != youngestProto)
             JS_ASSERT(parent);
     }
 #endif
@@ -2043,17 +2044,17 @@ stubs::LeaveBlock(VMFrame &f, JSObject *
 #endif
     /*
      * If we're about to leave the dynamic scope of a block that has been
      * cloned onto fp->scopeChain(), clear its private data, move its locals from
      * the stack into the clone, and pop it off the chain.
      */
     JSObject *obj = &fp->scopeChain();
     if (obj->getProto() == blockChain) {
-        JS_ASSERT(obj->isBlock());
+        JS_ASSERT(obj->getClass() == &js_BlockClass);
         if (!js_PutBlockObject(cx, JS_TRUE))
             THROW();
     }
 }
 
 void * JS_FASTCALL
 stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
 {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1555,19 +1555,19 @@ ValueToScript(JSContext *cx, jsval v)
 {
     JSScript *script = NULL;
     JSFunction *fun;
 
     if (!JSVAL_IS_PRIMITIVE(v)) {
         JSObject *obj = JSVAL_TO_OBJECT(v);
         JSClass *clasp = JS_GET_CLASS(cx, obj);
 
-        if (clasp == Jsvalify(&ScriptClass)) {
+        if (clasp == Jsvalify(&js_ScriptClass)) {
             script = (JSScript *) JS_GetPrivate(cx, obj);
-        } else if (clasp == Jsvalify(&GeneratorClass)) {
+        } else if (clasp == Jsvalify(&js_GeneratorClass)) {
             JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj);
             fun = gen->floatingFrame()->fun();
             script = fun->script();
         }
     }
 
     if (!script) {
         fun = JS_ValueToFunction(cx, v);
@@ -1615,18 +1615,18 @@ GetTrapArgs(JSContext *cx, uintN argc, j
     JSScript *script;
 
     *scriptp = JS_GetFrameScript(cx, JS_GetScriptedCaller(cx, NULL));
     *ip = 0;
     if (argc != 0) {
         v = argv[0];
         intarg = 0;
         if (!JSVAL_IS_PRIMITIVE(v) &&
-            (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&FunctionClass) ||
-             JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&ScriptClass))) {
+            (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&js_FunctionClass) ||
+             JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&js_ScriptClass))) {
             script = ValueToScript(cx, v);
             if (!script)
                 return JS_FALSE;
             *scriptp = script;
             intarg++;
         }
         if (argc > intarg) {
             if (!JS_ValueToInt32(cx, argv[intarg], ip))
--- a/js/src/shell/jsheaptools.cpp
+++ b/js/src/shell/jsheaptools.cpp
@@ -363,22 +363,22 @@ class ReferenceFinder {
      * If |cell|, of |kind|, is representable as a JavaScript value, return that
      * value; otherwise, return JSVAL_VOID.
      */
     jsval representable(void *cell, int kind) {
         if (kind == JSTRACE_OBJECT) {
             JSObject *object = static_cast<JSObject *>(cell);
 
             /* Certain classes of object are for internal use only. */
-            if (object->isBlock() ||
-                object->isCall() ||
-                object->isWith() ||
-                object->isDeclEnv()) {
+            JSClass *clasp = JS_GET_CLASS(context, object);
+            if (clasp == Jsvalify(&js_BlockClass) ||
+                clasp == Jsvalify(&js_CallClass) ||
+                clasp == Jsvalify(&js_WithClass) ||
+                clasp == Jsvalify(&js_DeclEnvClass))
                 return JSVAL_VOID;
-            }
 
             /* Internal function objects should also not be revealed. */
             if (JS_ObjectIsFunction(context, object) && IsInternalFunctionObject(object))
                 return JSVAL_VOID;
 
             return OBJECT_TO_JSVAL(object);
         }
 
--- a/js/src/tracejit/Writer.h
+++ b/js/src/tracejit/Writer.h
@@ -474,17 +474,17 @@ class Writer
 
     nj::LIns *ldiRuntimeProtoHazardShape(nj::LIns *runtime) const {
         return name(lir->insLoad(nj::LIR_ldi, runtime, offsetof(JSRuntime, protoHazardShape),
                                  ACCSET_RUNTIME),
                     "protoHazardShape");
     }
 
     nj::LIns *ldpObjClasp(nj::LIns *obj, nj::LoadQual loadQual) const {
-        return name(lir->insLoad(nj::LIR_ldp, obj, JSObject::offsetOfClassPointer(), ACCSET_OBJ_CLASP,
+        return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, clasp), ACCSET_OBJ_CLASP,
                                  loadQual),
                     "clasp");
     }
 
     nj::LIns *ldiObjFlags(nj::LIns *obj) const {
         return name(lir->insLoad(nj::LIR_ldi, obj, offsetof(JSObject, flags), ACCSET_OBJ_FLAGS),
                     "flags");
     }
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -146,17 +146,17 @@ struct ArgumentsData
  *     however, use getElement or getElements to avoid spreading arguments
  *     object implementation details around too much.
  */
 class ArgumentsObject : public ::JSObject
 {
     static const uint32 INITIAL_LENGTH_SLOT = 0;
     static const uint32 DATA_SLOT = 1;
 
-  public:
+  protected:
     static const uint32 RESERVED_SLOTS = 2;
 
   private:
     /* Lower-order bit stolen from the length slot. */
     static const uint32 LENGTH_OVERRIDDEN_BIT = 0x1;
     static const uint32 PACKED_BITS_COUNT = 1;
 
 #ifdef JS_TRACER
@@ -235,16 +235,18 @@ class ArgumentsObject : public ::JSObjec
  * Non-strict arguments have a private: the function's stack frame until the
  * function returns, when it is replaced with null.  When an arguments object
  * is created on-trace its private is JS_ARGUMENTS_OBJECT_ON_TRACE, and when
  * the trace exits its private is replaced with the stack frame or null, as
  * appropriate.
  */
 class NormalArgumentsObject : public ArgumentsObject
 {
+    static js::Class jsClass;
+
     friend bool JSObject::isNormalArguments() const;
     friend struct EmptyShape; // for EmptyShape::getEmptyArgumentsShape
     friend ArgumentsObject *
     ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee);
 
   public:
     /*
      * Stores arguments.callee, or MagicValue(JS_ARGS_HOLE) if the callee has
@@ -259,37 +261,57 @@ class NormalArgumentsObject : public Arg
 /*
  * Technically strict arguments have a private, but it's always null.
  * Conceptually it would be better to remove this oddity, but preserving it
  * allows us to work with arguments objects of either kind more abstractly,
  * so we keep it for now.
  */
 class StrictArgumentsObject : public ArgumentsObject
 {
+    static js::Class jsClass;
+
     friend bool JSObject::isStrictArguments() const;
     friend ArgumentsObject *
     ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee);
 };
 
 } // namespace js
 
+inline bool
+JSObject::isNormalArguments() const
+{
+    return getClass() == &js::NormalArgumentsObject::jsClass;
+}
+
 js::NormalArgumentsObject *
 JSObject::asNormalArguments()
 {
     JS_ASSERT(isNormalArguments());
     return reinterpret_cast<js::NormalArgumentsObject *>(this);
 }
 
+inline bool
+JSObject::isStrictArguments() const
+{
+    return getClass() == &js::StrictArgumentsObject::jsClass;
+}
+
 js::StrictArgumentsObject *
 JSObject::asStrictArguments()
 {
     JS_ASSERT(isStrictArguments());
     return reinterpret_cast<js::StrictArgumentsObject *>(this);
 }
 
+inline bool
+JSObject::isArguments() const
+{
+    return isNormalArguments() || isStrictArguments();
+}
+
 js::ArgumentsObject *
 JSObject::asArguments()
 {
     JS_ASSERT(isArguments());
     return reinterpret_cast<js::ArgumentsObject *>(this);
 }
 
 #endif /* ArgumentsObject_h___ */
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -342,19 +342,19 @@ Debugger::init(JSContext *cx)
 }
 
 JS_STATIC_ASSERT(uintN(JSSLOT_DEBUGFRAME_OWNER) == uintN(JSSLOT_DEBUGOBJECT_OWNER));
 JS_STATIC_ASSERT(uintN(JSSLOT_DEBUGFRAME_OWNER) == uintN(JSSLOT_DEBUGSCRIPT_OWNER));
 
 Debugger *
 Debugger::fromChildJSObject(JSObject *obj)
 {
-    JS_ASSERT(obj->getClass() == &DebuggerFrame_class ||
-              obj->getClass() == &DebuggerObject_class ||
-              obj->getClass() == &DebuggerScript_class);
+    JS_ASSERT(obj->clasp == &DebuggerFrame_class ||
+              obj->clasp == &DebuggerObject_class ||
+              obj->clasp == &DebuggerScript_class);
     JSObject *dbgobj = &obj->getReservedSlot(JSSLOT_DEBUGOBJECT_OWNER).toObject();
     return fromJSObject(dbgobj);
 }
 
 bool
 Debugger::getScriptFrame(JSContext *cx, StackFrame *fp, Value *vp)
 {
     JS_ASSERT(fp->isScriptFrame());
@@ -518,19 +518,19 @@ Debugger::wrapDebuggeeValue(JSContext *c
 }
 
 bool
 Debugger::unwrapDebuggeeValue(JSContext *cx, Value *vp)
 {
     assertSameCompartment(cx, object, *vp);
     if (vp->isObject()) {
         JSObject *dobj = &vp->toObject();
-        if (dobj->getClass() != &DebuggerObject_class) {
+        if (dobj->clasp != &DebuggerObject_class) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_EXPECTED_TYPE,
-                                 "Debugger", "Debugger.Object", dobj->getClass()->name);
+                                 "Debugger", "Debugger.Object", dobj->clasp->name);
             return false;
         }
 
         Value owner = dobj->getReservedSlot(JSSLOT_DEBUGOBJECT_OWNER);
         if (owner.toObjectOrNull() != object) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  owner.isNull()
                                  ? JSMSG_DEBUG_OBJECT_PROTO
@@ -582,17 +582,17 @@ Debugger::newCompletionValue(AutoCompart
         cx->clearPendingException();
         ac.leave();
     } else {
         ac.leave();
         vp->setNull();
         return true;
     }
 
-    JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
     if (!obj ||
         !wrapDebuggeeValue(cx, &val) ||
         !DefineNativeProperty(cx, obj, key, val, PropertyStub, StrictPropertyStub,
                               JSPROP_ENUMERATE, 0, 0))
     {
         return false;
     }
     vp->setObject(*obj);
@@ -1474,17 +1474,17 @@ Debugger::unwrapDebuggeeArgument(JSConte
      *   - a Debugger.Object belonging to this Debugger: return its referent
      *   - a cross-compartment wrapper: return the wrapped object
      *   - any other non-Debugger.Object object: return it
      * If it is a primitive, or a Debugger.Object that belongs to some other
      * Debugger, throw a TypeError.
      */
     JSObject *obj = NonNullObject(cx, v);
     if (obj) {
-        if (obj->getClass() == &DebuggerObject_class) {
+        if (obj->clasp == &DebuggerObject_class) {
             Value rv = v;
             if (!unwrapDebuggeeValue(cx, &rv))
                 return NULL;
             return &rv.toObject();
         }
         if (obj->isCrossCompartmentWrapper())
             return &obj->getProxyPrivate().toObject();
     }
@@ -1972,17 +1972,17 @@ static JSObject *
 DebuggerScript_check(JSContext *cx, const Value &v, const char *clsname, const char *fnname,
                      bool checkLive)
 {
     if (!v.isObject()) {
         ReportObjectRequired(cx);
         return NULL;
     }
     JSObject *thisobj = &v.toObject();
-    if (thisobj->getClass() != &DebuggerScript_class) {
+    if (thisobj->clasp != &DebuggerScript_class) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
                              clsname, fnname, thisobj->getClass()->name);
         return NULL;
     }
 
     /*
      * Check for Debugger.Script.prototype, which is of class DebuggerScript_class
      * but whose holding object is undefined.
@@ -2942,17 +2942,17 @@ DebuggerFrameEval(JSContext *cx, uintN a
         return false;
     JSObject *scobj = GetScopeChain(cx, fp);
     if (!scobj)
         return false;
 
     /* If evalWithBindings, create the inner scope object. */
     if (mode == WithBindings) {
         /* TODO - Should probably create a With object here. */
-        scobj = NewNonFunction<WithProto::Given>(cx, &ObjectClass, NULL, scobj);
+        scobj = NewNonFunction<WithProto::Given>(cx, &js_ObjectClass, NULL, scobj);
         if (!scobj)
             return false;
         for (size_t i = 0; i < keys.length(); i++) {
             if (!cx->compartment->wrap(cx, &values[i]) ||
                 !DefineNativeProperty(cx, scobj, keys[i], values[i], NULL, NULL, 0, 0, 0))
             {
                 return false;
             }
@@ -3035,17 +3035,17 @@ Class DebuggerObject_class = {
 static JSObject *
 DebuggerObject_checkThis(JSContext *cx, const CallArgs &args, const char *fnname)
 {
     if (!args.thisv().isObject()) {
         ReportObjectRequired(cx);
         return NULL;
     }
     JSObject *thisobj = &args.thisv().toObject();
-    if (thisobj->getClass() != &DebuggerObject_class) {
+    if (thisobj->clasp != &DebuggerObject_class) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
                              "Debugger.Object", fnname, thisobj->getClass()->name);
         return NULL;
     }
 
     /*
      * Forbid Debugger.Object.prototype, which is of class DebuggerObject_class
      * but isn't a real working Debugger.Object. The prototype object is
@@ -3093,17 +3093,17 @@ DebuggerObject_getProto(JSContext *cx, u
     args.rval() = protov;
     return true;
 }
 
 static JSBool
 DebuggerObject_getClass(JSContext *cx, uintN argc, Value *vp)
 {
     THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get class", args, refobj);
-    const char *s = refobj->getClass()->name;
+    const char *s = refobj->clasp->name;
     JSAtom *str = js_Atomize(cx, s, strlen(s));
     if (!str)
         return false;
     args.rval().setString(str);
     return true;
 }
 
 static JSBool
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -222,18 +222,18 @@ GlobalObject::createConstructor(JSContex
      */
     fun->setConstructorClass(clasp);
     return fun;
 }
 
 static JSObject *
 CreateBlankProto(JSContext *cx, Class *clasp, JSObject &proto, GlobalObject &global)
 {
-    JS_ASSERT(clasp != &ObjectClass);
-    JS_ASSERT(clasp != &FunctionClass);
+    JS_ASSERT(clasp != &js_ObjectClass);
+    JS_ASSERT(clasp != &js_FunctionClass);
 
     JSObject *blankProto = NewNonFunction<WithProto::Given>(cx, clasp, &proto, &global);
     if (!blankProto || !blankProto->setSingletonType(cx))
         return NULL;
 
     /*
      * Supply the created prototype object with an empty shape for the benefit
      * of callers of JSObject::initSharingEmptyShape.
@@ -295,17 +295,17 @@ GlobalDebuggees_class = {
 };
 
 GlobalObject::DebuggerVector *
 GlobalObject::getDebuggers()
 {
     Value debuggers = getReservedSlot(DEBUGGERS);
     if (debuggers.isUndefined())
         return NULL;
-    JS_ASSERT(debuggers.toObject().getClass() == &GlobalDebuggees_class);
+    JS_ASSERT(debuggers.toObject().clasp == &GlobalDebuggees_class);
     return (DebuggerVector *) debuggers.toObject().getPrivate();
 }
 
 GlobalObject::DebuggerVector *
 GlobalObject::getOrCreateDebuggers(JSContext *cx)
 {
     assertSameCompartment(cx, this);
     DebuggerVector *debuggers = getDebuggers();
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -353,17 +353,17 @@ StackFrame::setScopeChainWithOwnCallObj(
 }
 
 inline JSObject &
 StackFrame::callObj() const
 {
     JS_ASSERT_IF(isNonEvalFunctionFrame() || isStrictEvalFrame(), hasCallObj());
 
     JSObject *pobj = &scopeChain();
-    while (JS_UNLIKELY(!pobj->isCall())) {
+    while (JS_UNLIKELY(pobj->getClass() != &js_CallClass)) {
         JS_ASSERT(IsCacheableNonGlobalScope(pobj) || pobj->isWith());
         pobj = pobj->getParent();
     }
     return *pobj;
 }
 
 inline void
 StackFrame::putActivationObjects()
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -147,17 +147,17 @@ StackFrame::stealFrameAndSlots(Value *vp
      * js_LiveFrameToFloating comment in jsiter.h.
      */
     if (hasCallObj()) {
         JSObject &obj = callObj();
         obj.setPrivate(this);
         otherfp->flags_ &= ~HAS_CALL_OBJ;
         if (js_IsNamedLambda(fun())) {
             JSObject *env = obj.getParent();
-            JS_ASSERT(env->isDeclEnv());
+            JS_ASSERT(env->getClass() == &js_DeclEnvClass);
             env->setPrivate(this);
         }
     }
     if (hasArgsObj()) {
         ArgumentsObject &argsobj = argsObj();
         if (argsobj.isNormalArguments())
             argsobj.setPrivate(this);
         else
--- a/js/src/vm/StringObject-inl.h
+++ b/js/src/vm/StringObject-inl.h
@@ -50,30 +50,30 @@ JSObject::asString()
     return static_cast<js::StringObject *>(const_cast<JSObject *>(this));
 }
 
 namespace js {
 
 inline StringObject *
 StringObject::create(JSContext *cx, JSString *str)
 {
-    JSObject *obj = NewBuiltinClassInstance(cx, &StringClass);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass);
     if (!obj)
         return NULL;
     StringObject *strobj = obj->asString();
     if (!strobj->init(cx, str))
         return NULL;
     return strobj;
 }
 
 inline StringObject *
 StringObject::createWithProto(JSContext *cx, JSString *str, JSObject &proto)
 {
-    JS_ASSERT(gc::FINALIZE_OBJECT2 == gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(&StringClass)));
-    JSObject *obj = NewObjectWithClassProto(cx, &StringClass, &proto, gc::FINALIZE_OBJECT2);
+    JS_ASSERT(gc::FINALIZE_OBJECT2 == gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(&js_StringClass)));
+    JSObject *obj = NewObjectWithClassProto(cx, &js_StringClass, &proto, gc::FINALIZE_OBJECT2);
     if (!obj)
         return NULL;
     StringObject *strobj = obj->asString();
     if (!strobj->init(cx, str))
         return NULL;
     return strobj;
 }
 
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -803,31 +803,31 @@ nsXPConnect::Traverse(void *p, nsCycleCo
                     (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
                 si = p->GetScriptableInfo();
             }
             if(si)
             {
                 JS_snprintf(name, sizeof(name), "JS Object (%s - %s)",
                             clazz->name, si->GetJSClass()->name);
             }
-            else if(clazz == &js::ScriptClass)
+            else if(clazz == &js_ScriptClass)
             {
                 JSScript* script = (JSScript*) xpc_GetJSPrivate(obj);
                 if(script->filename)
                 {
                     JS_snprintf(name, sizeof(name),
                                 "JS Object (Script - %s)",
                                 script->filename);
                 }
                 else
                 {
                     JS_snprintf(name, sizeof(name), "JS Object (Script)");
                 }
             }
-            else if(clazz == &js::FunctionClass)
+            else if(clazz == &js_FunctionClass)
             {
                 JSFunction* fun = (JSFunction*) xpc_GetJSPrivate(obj);
                 JSString* str = JS_GetFunctionId(fun);
                 if(str)
                 {
                     NS_ConvertUTF16toUTF8 fname(JS_GetInternedStringChars(str));
                     JS_snprintf(name, sizeof(name),
                                 "JS Object (Function - %s)", fname.get());