[JAEGER] Merge from Tracemonkey.
authorDavid Mandelin <dmandelin@mozilla.com>
Thu, 29 Jul 2010 13:23:33 -0700
changeset 53244 0da455565838d667801967dacebd69f77c09794e
parent 53243 4e9eeb94a13ad790f79fff9a0f3f4e985846cf68 (current diff)
parent 48626 774cdd249639fefd79894e574591d933e53b327f (diff)
child 53245 ea3b9e22d2e10945302c76f96eb0ee7c761ec980
push idunknown
push userunknown
push dateunknown
milestone2.0b3pre
[JAEGER] Merge from Tracemonkey.
caps/src/nsScriptSecurityManager.cpp
content/base/src/nsContentUtils.cpp
dom/base/nsJSEnvironment.cpp
js/ipc/ObjectWrapperParent.cpp
js/jsd/jsd_val.c
js/src/jsapi-tests/testExtendedEq.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsbool.cpp
js/src/jsbuiltins.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsinterp.cpp
js/src/jsiter.cpp
js/src/jsiter.h
js/src/jslock.h
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsproxy.cpp
js/src/jsprvtd.h
js/src/jspubtd.h
js/src/jsregexp.cpp
js/src/jsscope.cpp
js/src/jsscope.h
js/src/jsscopeinlines.h
js/src/jsscript.cpp
js/src/jsstr.cpp
js/src/jstracer.cpp
js/src/jstypedarray.cpp
js/src/jsvalue.h
js/src/jswrapper.cpp
js/src/jsxml.cpp
js/src/jsxml.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/trace-test/trace-test.py
js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
js/src/xpconnect/src/XPCNativeWrapper.cpp
js/src/xpconnect/src/XPCNativeWrapper.h
js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
js/src/xpconnect/src/XPCWrapper.cpp
js/src/xpconnect/src/XPCWrapper.h
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpccomponents.cpp
js/src/xpconnect/src/xpcconvert.cpp
js/src/xpconnect/src/xpcprivate.h
js/src/xpconnect/src/xpcquickstubs.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
js/src/xpconnect/src/xpcwrappednativejsops.cpp
js/src/xpconnect/src/xpcwrappednativescope.cpp
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -2412,21 +2412,17 @@ nsScriptSecurityManager::doGetObjectPrin
 
     do {
         // Note: jsClass is set before this loop, and also at the
         // *end* of this loop.
 
         // NOTE: These class and equality hook checks better match
         // what IS_WRAPPER_CLASS() does in xpconnect!
         
-        JSEqualityOp op =
-            (jsClass->flags & JSCLASS_IS_EXTENDED) ?
-            reinterpret_cast<const JSExtendedClass*>(jsClass)->equality :
-            nsnull;
-        if (op == sXPCWrappedNativeEqualityOps) {
+        if (jsClass->ext.equality == js::Valueify(sXPCWrappedNativeEqualityOps)) {
             result = sXPConnect->GetPrincipal(aObj,
 #ifdef DEBUG
                                               aAllowShortCircuit
 #else
                                               PR_TRUE
 #endif
                                               );
             if (result) {
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5698,21 +5698,18 @@ CloneSimpleValues(JSContext* cx,
   // Do we support FileList?
 
   // Function objects don't get cloned.
   if (JS_ObjectIsFunction(cx, obj)) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 
   // Security wrapped objects are not allowed either.
-  JSClass* clasp = JS_GET_CLASS(cx, obj);
-  if ((clasp->flags & JSCLASS_IS_EXTENDED) &&
-      ((JSExtendedClass*)clasp)->wrappedObject) {
+  if (obj->getClass()->ext.wrappedObject)
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-  }
 
   // See if this JSObject is backed by some C++ object. If it is then we assume
   // that it is inappropriate to clone.
   nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
   nsContentUtils::XPConnect()->
     GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrapper));
   if (wrapper) {
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -67,16 +67,18 @@
 #include "nsLayoutUtils.h"
 #include "nsComputedDOMStyle.h"
 
 #if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK2)
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #endif
 
+#include "jsobj.h"
+
 static PRBool IsUniversalXPConnectCapable()
 {
   PRBool hasCap = PR_FALSE;
   nsresult rv = nsContentUtils::GetSecurityManager()->
                   IsCapabilityEnabled("UniversalXPConnect", &hasCap);
   NS_ENSURE_SUCCESS(rv, PR_FALSE);
   return hasCap;
 }
@@ -1342,24 +1344,20 @@ nsDOMWindowUtils::GetParent()
 
   // first argument must be an object
   if(JSVAL_IS_PRIMITIVE(argv[0]))
     return NS_ERROR_XPC_BAD_CONVERT_JS;
 
   JSObject *parent = JS_GetParent(cx, JSVAL_TO_OBJECT(argv[0]));
   *rval = OBJECT_TO_JSVAL(parent);
 
-  // Outerize if necessary.  Embrace the ugliness!
+  // Outerize if necessary.
   if (parent) {
-    JSClass* clasp = JS_GET_CLASS(cx, parent);
-    if (clasp->flags & JSCLASS_IS_EXTENDED) {
-      JSExtendedClass* xclasp = reinterpret_cast<JSExtendedClass*>(clasp);
-      if (JSObjectOp outerize = xclasp->outerObject)
-        *rval = OBJECT_TO_JSVAL(outerize(cx, parent));
-    }
+    if (JSObjectOp outerize = parent->getClass()->ext.outerObject)
+      *rval = OBJECT_TO_JSVAL(outerize(cx, parent));
   }
 
   cc->SetReturnValueWasSet(PR_TRUE);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetOuterWindowID(PRUint64 *aWindowID)
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -898,16 +898,30 @@ PrintWinCodebase(nsGlobalWindow *win)
 
 void
 DumpString(const nsAString &str)
 {
   printf("%s\n", NS_ConvertUTF16toUTF8(str).get());
 }
 #endif
 
+static void
+MaybeGC(JSContext *cx)
+{
+  size_t bytes = cx->runtime->gcBytes;
+  size_t lastBytes = cx->runtime->gcLastBytes;
+  if ((bytes > 8192 && bytes > lastBytes * 16)
+#ifdef DEBUG
+      || cx->runtime->gcZeal > 0
+#endif
+      ) {
+    JS_GC(cx);
+  }
+}
+
 static already_AddRefed<nsIPrompt>
 GetPromptFromContext(nsJSContext* ctx)
 {
   nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(ctx->GetGlobalObject()));
   NS_ENSURE_TRUE(win, nsnull);
 
   nsIDocShell *docShell = win->GetDocShell();
   NS_ENSURE_TRUE(docShell, nsnull);
@@ -936,17 +950,17 @@ nsJSContext::DOMOperationCallback(JSCont
 
   // XXX Save the operation callback time so we can restore it after the GC,
   // because GCing can cause JS to run on our context, causing our
   // ScriptEvaluated to be called, and clearing our operation callback time.
   // See bug 302333.
   PRTime callbackTime = ctx->mOperationCallbackTime;
   PRTime modalStateTime = ctx->mModalStateTime;
 
-  JS_MaybeGC(cx);
+  MaybeGC(cx);
 
   // Now restore the callback time and count, in case they got reset.
   ctx->mOperationCallbackTime = callbackTime;
   ctx->mModalStateTime = modalStateTime;
 
   // Check to see if we are running OOM
   nsCOMPtr<nsIMemory> mem;
   NS_GetMemoryManager(getter_AddRefs(mem));
@@ -3524,22 +3538,22 @@ nsJSContext::ScriptEvaluated(PRBool aTer
     }
     delete start;
   }
 
   mNumEvaluations++;
 
 #ifdef JS_GC_ZEAL
   if (mContext->runtime->gcZeal >= 2) {
-    JS_MaybeGC(mContext);
+    MaybeGC(mContext);
   } else
 #endif
   if (mNumEvaluations > 20) {
     mNumEvaluations = 0;
-    JS_MaybeGC(mContext);
+    MaybeGC(mContext);
   }
 
   if (aTerminated) {
     mOperationCallbackTime = 0;
     mModalStateTime = 0;
   }
 }
 
--- a/js/ipc/ObjectWrapperParent.cpp
+++ b/js/ipc/ObjectWrapperParent.cpp
@@ -164,46 +164,42 @@ with_error(JSContext* cx,
                RType rval,
                const char* error = NULL)
 {
     if (!JS_IsExceptionPending(cx))
         JS_ReportError(cx, error ? error : "Unspecified CPOW error");
     return rval;
 }
 
-const JSExtendedClass ObjectWrapperParent::sCPOW_JSClass = {
-    // JSClass (JSExtendedClass.base) initialization
-    { "CrossProcessObjectWrapper",
-      JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE | JSCLASS_IS_EXTENDED |
+const js::Class ObjectWrapperParent::sCPOW_JSClass = {
+      "CrossProcessObjectWrapper",
+      JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE |
       JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(sNumSlots),
-      ObjectWrapperParent::CPOW_AddProperty,
-      ObjectWrapperParent::CPOW_DelProperty,
-      ObjectWrapperParent::CPOW_GetProperty,
-      ObjectWrapperParent::CPOW_SetProperty,
+      js::Valueify(ObjectWrapperParent::CPOW_AddProperty),
+      js::Valueify(ObjectWrapperParent::CPOW_DelProperty),
+      js::Valueify(ObjectWrapperParent::CPOW_GetProperty),
+      js::Valueify(ObjectWrapperParent::CPOW_SetProperty),
       (JSEnumerateOp) ObjectWrapperParent::CPOW_NewEnumerate,
-        (JSResolveOp) ObjectWrapperParent::CPOW_NewResolve,
-      ObjectWrapperParent::CPOW_Convert,
+      (JSResolveOp) ObjectWrapperParent::CPOW_NewResolve,
+      js::Valueify(ObjectWrapperParent::CPOW_Convert),
       ObjectWrapperParent::CPOW_Finalize,
-      nsnull, // getObjectOps
+      nsnull, // reserved1
       nsnull, // checkAccess
-      ObjectWrapperParent::CPOW_Call,
-      ObjectWrapperParent::CPOW_Construct,
+      js::Valueify(ObjectWrapperParent::CPOW_Call),
+      js::Valueify(ObjectWrapperParent::CPOW_Construct),
       nsnull, // xdrObject
-      ObjectWrapperParent::CPOW_HasInstance,
+      js::Valueify(ObjectWrapperParent::CPOW_HasInstance),
       nsnull, // mark
-      nsnull, // reserveSlots
-    },
-
-    // JSExtendedClass initialization
-    ObjectWrapperParent::CPOW_Equality,
-    nsnull, // outerObject
-    nsnull, // innerObject
-    nsnull, // iterator
-    nsnull, // wrappedObject
-    JSCLASS_NO_RESERVED_MEMBERS
+      {
+          js::Valueify(ObjectWrapperParent::CPOW_Equality),
+          nsnull, // outerObject
+          nsnull, // innerObject
+          nsnull, // iteratorObject
+          nsnull, // wrappedObject
+    }
 };
 
 void
 ObjectWrapperParent::ActorDestroy(ActorDestroyReason)
 {
     if (mObj) {
         mObj->setPrivate(NULL);
         mObj = NULL;
@@ -215,28 +211,28 @@ ObjectWrapperParent::Manager()
 {
     PContextWrapperParent* pcwp = PObjectWrapperParent::Manager();
     return static_cast<ContextWrapperParent*>(pcwp);
 }
 
 JSObject*
 ObjectWrapperParent::GetJSObject(JSContext* cx) const
 {
-    JSClass* clasp = const_cast<JSClass*>(&ObjectWrapperParent::sCPOW_JSClass.base);
-    if (!mObj && (mObj = JS_NewObject(cx, clasp, NULL, NULL))) {
+    js::Class *clasp = const_cast<js::Class *>(&ObjectWrapperParent::sCPOW_JSClass);
+    if (!mObj && (mObj = JS_NewObject(cx, js::Jsvalify(clasp), NULL, NULL))) {
         JS_SetPrivate(cx, mObj, (void*)this);
         JS_SetReservedSlot(cx, mObj, sFlagsSlot, JSVAL_ZERO);
     }
     return mObj;
 }
 
 static ObjectWrapperParent*
 Unwrap(JSContext* cx, JSObject* obj)
 {
-    while (obj->getJSClass() != &ObjectWrapperParent::sCPOW_JSClass.base)
+    while (obj->getClass() != &ObjectWrapperParent::sCPOW_JSClass)
         if (!(obj = obj->getProto()))
             return NULL;
     
     ObjectWrapperParent* self =
         static_cast<ObjectWrapperParent*>(JS_GetPrivate(cx, obj));
 
     NS_ASSERTION(!self || self->GetJSObject(cx) == obj,
                  "Wrapper and wrapped object disagree?");
--- a/js/ipc/ObjectWrapperParent.h
+++ b/js/ipc/ObjectWrapperParent.h
@@ -38,16 +38,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_jsipc_ObjectWrapperParent_h__
 #define mozilla_jsipc_ObjectWrapperParent_h__
 
 #include "mozilla/jsipc/PObjectWrapperParent.h"
 #include "jsapi.h"
+#include "jsvalue.h"
 #include "nsAutoJSValHolder.h"
 
 namespace mozilla {
 namespace jsipc {
 
 class ContextWrapperParent;
 
 class OperationChecker {
@@ -70,17 +71,17 @@ public:
 
     jsval GetJSVal(JSContext* cx) const {
         return OBJECT_TO_JSVAL(GetJSObject(cx));
     }
 
     void CheckOperation(JSContext* cx,
                         OperationStatus* status);
 
-    static const JSExtendedClass sCPOW_JSClass;
+    static const js::Class sCPOW_JSClass;
 
 protected:
 
     void ActorDestroy(ActorDestroyReason why);
 
     ContextWrapperParent* Manager();
 
 private:
--- a/js/jsd/jsd_val.c
+++ b/js/jsd/jsd_val.c
@@ -37,30 +37,17 @@
 
 /*
  * JavaScript Debugging support - Value and Property support
  */
 
 #include "jsd.h"
 #include "jsapi.h"
 #include "jspubtd.h"
-
-/*
- * Lifted with slight modification from jsobj.h
- */
-
-#define OBJ_TO_OUTER_OBJECT(cx, obj)                                \
-do {                                                                \
-    JSClass *clasp_ = JS_GetClass(cx, obj);                         \
-    if (clasp_->flags & JSCLASS_IS_EXTENDED) {                      \
-        JSExtendedClass *xclasp_ = (JSExtendedClass*) clasp_;       \
-        if (xclasp_->outerObject)                                   \
-            obj = xclasp_->outerObject(cx, obj);                    \
-    }                                                               \
-} while(0)
+#include "jsprvtd.h"
 
 #ifdef DEBUG
 void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval)
 {
     JS_ASSERT(jsdval);
     JS_ASSERT(jsdval->nref > 0);
     if(!JS_CLIST_IS_EMPTY(&jsdval->props))
     {
@@ -309,18 +296,17 @@ jsd_DropValue(JSDContext* jsdc, JSDValue
 jsval
 jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
 {
     JSObject* obj;
     JSContext* cx;
     jsval val = jsdval->val;
     if (!JSVAL_IS_PRIMITIVE(val)) {
         cx = JSD_GetDefaultJSContext(jsdc);
-        obj = JSVAL_TO_OBJECT(val);
-        OBJ_TO_OUTER_OBJECT(cx, obj);
+        obj = js_ObjectToOuterObject(cx, JSVAL_TO_OBJECT(val));
         if (!obj)
         {
             JS_ClearPendingException(cx);
             val = JSVAL_NULL;
         }
         else
             val = OBJECT_TO_JSVAL(obj);
     }
--- a/js/src/jsapi-tests/testExtendedEq.cpp
+++ b/js/src/jsapi-tests/testExtendedEq.cpp
@@ -1,42 +1,56 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  *
  * This tests user-specified (via JSExtendedClass) equality operations on
  * trace.
  */
 
 #include "tests.h"
+#include "jsobj.h"
 
 static JSBool
 my_Equality(JSContext *cx, JSObject *obj, const jsval *, JSBool *bp)
 {
     *bp = JS_TRUE;
     return JS_TRUE;
 }
 
-JSExtendedClass TestExtendedEq_JSClass = {
-    { "TestExtendedEq",
-        JSCLASS_IS_EXTENDED,
-        JS_PropertyStub,    JS_PropertyStub,   JS_PropertyStub,   JS_PropertyStub,
-        JS_EnumerateStub,   JS_ResolveStub,    NULL,              NULL,
-        NULL,               NULL,              NULL,              NULL,
-        NULL,               NULL,              NULL,              NULL
-    },
-    // JSExtendedClass initialization
-    my_Equality,
-    NULL, NULL, NULL, NULL, JSCLASS_NO_RESERVED_MEMBERS
+js::Class TestExtendedEq_JSClass = {
+    "TestExtendedEq",
+    0,
+    js::PropertyStub, /* addProperty */
+    js::PropertyStub, /* delProperty */
+    js::PropertyStub, /* getProperty */
+    js::PropertyStub, /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    NULL,           /* convert */
+    NULL,           /* finalize */
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    NULL,           /* mark        */
+    {
+        js::Valueify(my_Equality),
+        NULL, /* outerObject    */
+        NULL, /* innerObject    */
+        NULL, /* iteratorObject */
+        NULL, /* wrappedObject  */
+    }
 };
 
 BEGIN_TEST(testExtendedEq_bug530489)
 {
     JSClass *clasp = (JSClass *) &TestExtendedEq_JSClass;
 
-    JSObject *global = JS_GetGlobalObject(cx);
     CHECK(JS_InitClass(cx, global, global, clasp, NULL, 0, NULL, NULL, NULL, NULL));
 
     CHECK(JS_DefineObject(cx, global, "obj1", clasp, NULL, 0));
     CHECK(JS_DefineObject(cx, global, "obj2", clasp, NULL, 0));
 
     jsval v;
     EVAL("(function() { var r; for (var i = 0; i < 10; ++i) r = obj1 == obj2; return r; })()", &v);
     CHECK_SAME(v, JSVAL_TRUE);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1337,21 +1337,20 @@ JS_InitStandardClasses(JSContext *cx, JS
 #if JS_HAS_GENERATORS
            js_InitIteratorClasses(cx, obj) &&
 #endif
            js_InitDateClass(cx, obj) &&
            js_InitProxyClass(cx, obj);
 }
 
 #define CLASP(name)                 (&js_##name##Class)
-#define XCLASP(name)                (&js_##name##Class.base)
+#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 EAGER_ATOM_AND_XCLASP(name) EAGER_CLASS_ATOM(name), XCLASP(name)
 #define LAZY_ATOM(name)             ATOM_OFFSET(lazy.name), js_##name##_str
 
 typedef struct JSStdName {
     JSObjectOp  init;
     size_t      atomOffset;     /* offset of atom pointer in JSAtomState */
     const char  *name;          /* null if atom is pre-pinned, else name */
     Class       *clasp;
 } JSStdName;
@@ -1387,18 +1386,18 @@ static JSStdName standard_class_atoms[] 
     {js_InitDateClass,                  EAGER_ATOM_AND_CLASP(Date)},
     {js_InitMathClass,                  EAGER_ATOM_AND_CLASP(Math)},
     {js_InitNumberClass,                EAGER_ATOM_AND_CLASP(Number)},
     {js_InitStringClass,                EAGER_ATOM_AND_CLASP(String)},
     {js_InitExceptionClasses,           EAGER_ATOM_AND_CLASP(Error)},
     {js_InitRegExpClass,                EAGER_ATOM_AND_CLASP(RegExp)},
 #if JS_HAS_XML_SUPPORT
     {js_InitXMLClass,                   EAGER_ATOM_AND_CLASP(XML)},
-    {js_InitNamespaceClass,             EAGER_ATOM_AND_XCLASP(Namespace)},
-    {js_InitQNameClass,                 EAGER_ATOM_AND_XCLASP(QName)},
+    {js_InitNamespaceClass,             EAGER_ATOM_AND_CLASP(Namespace)},
+    {js_InitQNameClass,                 EAGER_ATOM_AND_CLASP(QName)},
 #endif
 #if JS_HAS_GENERATORS
     {js_InitIteratorClasses,            EAGER_ATOM_AND_CLASP(StopIteration)},
 #endif
     {js_InitJSONClass,                  EAGER_ATOM_AND_CLASP(JSON)},
     {js_InitTypedArrayClasses,          EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
     {NULL,                              0, NULL, NULL}
 };
@@ -1443,31 +1442,32 @@ static JSStdName standard_class_names[] 
 #if JS_HAS_XML_SUPPORT
     {js_InitAnyNameClass,       EAGER_ATOM_AND_CLASP(AnyName)},
     {js_InitAttributeNameClass, EAGER_ATOM_AND_CLASP(AttributeName)},
     {js_InitXMLClass,           LAZY_ATOM(XMLList), CLASP(XML)},
     {js_InitXMLClass,           LAZY_ATOM(isXMLName), CLASP(XML)},
 #endif
 
 #if JS_HAS_GENERATORS
-    {js_InitIteratorClasses,    EAGER_ATOM_AND_XCLASP(Iterator)},
-    {js_InitIteratorClasses,    EAGER_ATOM_AND_XCLASP(Generator)},
+    {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Iterator)},
+    {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Generator)},
 #endif
 
     /* Typed Arrays */
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBuffer::jsclass},
-    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int8Array), &TypedArray::fastClasses[TypedArray::TYPE_INT8]},
-    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8Array), &TypedArray::fastClasses[TypedArray::TYPE_UINT8]},
-    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int16Array), &TypedArray::fastClasses[TypedArray::TYPE_INT16]},
-    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint16Array), &TypedArray::fastClasses[TypedArray::TYPE_UINT16]},
-    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int32Array), &TypedArray::fastClasses[TypedArray::TYPE_INT32]},
-    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint32Array), &TypedArray::fastClasses[TypedArray::TYPE_UINT32]},
-    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float32Array), &TypedArray::fastClasses[TypedArray::TYPE_FLOAT32]},
-    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float64Array), &TypedArray::fastClasses[TypedArray::TYPE_FLOAT64]},
-    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8ClampedArray), &TypedArray::fastClasses[TypedArray::TYPE_UINT8_CLAMPED]},
+    {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)},
+    {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8ClampedArray),
+                                TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
 
     {js_InitProxyClass,         EAGER_ATOM_AND_CLASP(Proxy)},
 
     {NULL,                      0, NULL, NULL}
 };
 
 static JSStdName object_prototype_names[] = {
     /* Object.prototype properties (global delegates to Object.prototype). */
@@ -1854,17 +1854,17 @@ JS_PUBLIC_API(void)
 JS_free(JSContext *cx, void *p)
 {
     return cx->free(p);
 }
 
 JS_PUBLIC_API(void)
 JS_updateMallocCounter(JSContext *cx, size_t nbytes)
 {
-    cx->runtime->updateMallocCounter(nbytes);
+    return cx->updateMallocCounter(nbytes);
 }
 
 JS_PUBLIC_API(char *)
 JS_strdup(JSContext *cx, const char *s)
 {
     size_t n;
     void *p;
 
@@ -2450,26 +2450,75 @@ JS_GC(JSContext *cx)
 JS_PUBLIC_API(void)
 JS_MaybeGC(JSContext *cx)
 {
     JSRuntime *rt;
     uint32 bytes, lastBytes;
 
     rt = cx->runtime;
 
+#ifdef JS_GC_ZEAL
+    if (rt->gcZeal > 0) {
+        JS_GC(cx);
+        return;
+    }
+#endif
+
     bytes = rt->gcBytes;
     lastBytes = rt->gcLastBytes;
 
-    if (rt->gcIsNeeded ||
-#ifdef JS_GC_ZEAL
-        rt->gcZeal > 0 ||
-#endif
-        (bytes > 8192 && bytes > lastBytes * 16) ||
-        bytes >= rt->gcTriggerBytes ||
-        rt->overQuota()) {
+    /*
+     * We run the GC if we used all available free GC cells and had to
+     * allocate extra 1/3 of GC arenas since the last run of GC, or if
+     * we have malloc'd more bytes through JS_malloc than we were told
+     * to allocate by JS_NewRuntime.
+     *
+     * The reason for
+     *   bytes > 4/3 lastBytes
+     * condition is the following. Bug 312238 changed bytes and lastBytes
+     * to mean the total amount of memory that the GC uses now and right
+     * after the last GC.
+     *
+     * Before the bug the variables meant the size of allocated GC things
+     * now and right after the last GC. That size did not include the
+     * memory taken by free GC cells and the condition was
+     *   bytes > 3/2 lastBytes.
+     * That is, we run the GC if we have half again as many bytes of
+     * GC-things as the last time we GC'd. To be compatible we need to
+     * express that condition through the new meaning of bytes and
+     * lastBytes.
+     *
+     * We write the original condition as
+     *   B*(1-F) > 3/2 Bl*(1-Fl)
+     * where B is the total memory size allocated by GC and F is the free
+     * cell density currently and Sl and Fl are the size and the density
+     * right after GC. The density by definition is memory taken by free
+     * cells divided by total amount of memory. In other words, B and Bl
+     * are bytes and lastBytes with the new meaning and B*(1-F) and
+     * Bl*(1-Fl) are bytes and lastBytes with the original meaning.
+     *
+     * Our task is to exclude F and Fl from the last statement. According
+     * to the stats from bug 331966 comment 23, Fl is about 10-25% for a
+     * typical run of the browser. It means that the original condition
+     * implied that we did not run GC unless we exhausted the pool of
+     * free cells. Indeed if we still have free cells, then B == Bl since
+     * we did not yet allocated any new arenas and the condition means
+     *   1 - F > 3/2 (1-Fl) or 3/2Fl > 1/2 + F
+     * That implies 3/2 Fl > 1/2 or Fl > 1/3. That cannot be fulfilled
+     * for the state described by the stats. So we can write the original
+     * condition as:
+     *   F == 0 && B > 3/2 Bl(1-Fl)
+     * Again using the stats we see that Fl is about 11% when the browser
+     * starts up and when we are far from hitting rt->gcMaxBytes. With
+     * this F we have
+     * F == 0 && B > 3/2 Bl(1-0.11)
+     * or approximately F == 0 && B > 4/3 Bl.
+     */
+    if ((bytes > 8192 && bytes > lastBytes + lastBytes / 3) ||
+        rt->isGCMallocLimitReached()) {
         JS_GC(cx);
     }
 }
 
 JS_PUBLIC_API(JSGCCallback)
 JS_SetGCCallback(JSContext *cx, JSGCCallback cb)
 {
     CHECK_REQUEST(cx);
@@ -2580,17 +2629,17 @@ JS_NewExternalString(JSContext *cx, jsch
 {
     CHECK_REQUEST(cx);
     JS_ASSERT(uintN(type) < JS_EXTERNAL_STRING_LIMIT);
 
     JSString *str = js_NewGCExternalString(cx, uintN(type));
     if (!str)
         return NULL;
     str->initFlat(chars, length);
-    cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
+    cx->updateMallocCounter((length + 1) * sizeof(jschar));
     return str;
 }
 
 JS_PUBLIC_API(intN)
 JS_GetExternalStringGCType(JSRuntime *rt, JSString *str)
 {
     /*
      * No need to test this in js_GetExternalStringGCType, which asserts its
@@ -3702,18 +3751,22 @@ JS_DeleteProperty(JSContext *cx, JSObjec
 }
 
 JS_PUBLIC_API(void)
 JS_ClearScope(JSContext *cx, JSObject *obj)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
-    if (obj->map->ops->clear)
-        obj->map->ops->clear(cx, obj);
+    JSFinalizeOp clearOp = obj->getOps()->clear;
+    if (clearOp)
+        clearOp(cx, obj);
+
+    if (obj->isNative())
+        js_ClearNative(cx, obj);
 
     /* Clear cached class objects on the global object. */
     if (obj->getClass()->flags & JSCLASS_IS_GLOBAL) {
         int key;
 
         for (key = JSProto_Null; key < JSProto_LIMIT * 3; key++)
             JS_SetReservedSlot(cx, obj, key, JSVAL_VOID);
     }
@@ -3776,20 +3829,31 @@ prop_iter_trace(JSTracer *trc, JSObject 
         MarkIdRange(trc, ida->length, ida->vector, "prop iter");
     }
 }
 
 static Class prop_iter_class = {
     "PropertyIterator",
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
     JSCLASS_MARK_IS_TRACE,
-    PropertyStub,     PropertyStub,    PropertyStub,    PropertyStub,
-    EnumerateStub,    ResolveStub,     ConvertStub,     prop_iter_finalize,
-    NULL,             NULL,            NULL,            NULL,
-    NULL,             NULL,            JS_CLASS_TRACE(prop_iter_trace), NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    prop_iter_finalize,
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    JS_CLASS_TRACE(prop_iter_trace)
 };
 
 JS_PUBLIC_API(JSObject *)
 JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
 {
     JSObject *iterobj;
     JSScope *scope;
     void *pdata;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1601,16 +1601,17 @@ JS_SetScriptStackQuota(JSContext *cx, si
 
 #define JS_DEFAULT_SCRIPT_STACK_QUOTA   ((size_t) 0x2000000)
 
 /************************************************************************/
 
 /*
  * Classes, objects, and properties.
  */
+typedef void (*JSClassInternal)();
 
 /* For detailed comments on the function pointer types, see jspubtd.h. */
 struct JSClass {
     const char          *name;
     uint32              flags;
 
     /* Mandatory non-null function pointer members. */
     JSPropertyOp        addProperty;
@@ -1618,38 +1619,26 @@ struct JSClass {
     JSPropertyOp        getProperty;
     JSPropertyOp        setProperty;
     JSEnumerateOp       enumerate;
     JSResolveOp         resolve;
     JSConvertOp         convert;
     JSFinalizeOp        finalize;
 
     /* Optionally non-null members start here. */
-    JSGetObjectOps      getObjectOps;
+    JSClassInternal     reserved0;
     JSCheckAccessOp     checkAccess;
     JSNative            call;
     JSNative            construct;
     JSXDRObjectOp       xdrObject;
     JSHasInstanceOp     hasInstance;
     JSMarkOp            mark;
-    void                (*reserved0)(void);
-};
-
-struct JSExtendedClass {
-    JSClass             base;
-    JSEqualityOp        equality;
-    JSObjectOp          outerObject;
-    JSObjectOp          innerObject;
-    JSIteratorOp        iteratorObject;
-    JSObjectOp          wrappedObject;          /* NB: infallible, null
-                                                   returns are treated as
-                                                   the original object */
-    void                (*reserved0)(void);
-    void                (*reserved1)(void);
-    void                (*reserved2)(void);
+
+    JSClassInternal     reserved1;
+    void                *reserved[19];
 };
 
 #define JSCLASS_HAS_PRIVATE             (1<<0)  /* objects have private slot */
 #define JSCLASS_NEW_ENUMERATE           (1<<1)  /* has JSNewEnumerateOp hook */
 #define JSCLASS_NEW_RESOLVE             (1<<2)  /* has JSNewResolveOp hook */
 #define JSCLASS_PRIVATE_IS_NSISUPPORTS  (1<<3)  /* private is (nsISupports *) */
 /* (1<<4) was JSCLASS_SHARE_ALL_PROPERTIES, now obsolete. See bug 527805. */
 #define JSCLASS_NEW_RESOLVE_GETS_START  (1<<5)  /* JSNewResolveOp gets starting
@@ -1672,25 +1661,23 @@ struct JSExtendedClass {
                                          << JSCLASS_RESERVED_SLOTS_SHIFT)
 #define JSCLASS_RESERVED_SLOTS(clasp)   (((clasp)->flags                      \
                                           >> JSCLASS_RESERVED_SLOTS_SHIFT)    \
                                          & JSCLASS_RESERVED_SLOTS_MASK)
 
 #define JSCLASS_HIGH_FLAGS_SHIFT        (JSCLASS_RESERVED_SLOTS_SHIFT +       \
                                          JSCLASS_RESERVED_SLOTS_WIDTH)
 
-/* True if JSClass is really a JSExtendedClass. */
-#define JSCLASS_IS_EXTENDED             (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0))
+#define JSCLASS_INTERNAL_FLAG1          (1<<(JSCLASS_HIGH_FLAGS_SHIFT+0))
 #define JSCLASS_IS_ANONYMOUS            (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1))
 #define JSCLASS_IS_GLOBAL               (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2))
 
 /* Indicates that JSClass.mark is a tracer with JSTraceOp type. */
 #define JSCLASS_MARK_IS_TRACE           (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3))
-
-#define JSCLASS_LAST_API_FLAG_SHIFT     (JSCLASS_HIGH_FLAGS_SHIFT+3)
+#define JSCLASS_INTERNAL_FLAG2          (1<<(JSCLASS_HIGH_FLAGS_SHIFT+4))
 
 /*
  * ECMA-262 requires that most constructors used internally create objects
  * with "the original Foo.prototype value" as their [[Prototype]] (__proto__)
  * member initial value.  The "original ... value" verbiage is there because
  * in ECMA-262, global properties naming class objects are read/write and
  * deleteable, for the most part.
  *
@@ -1710,18 +1697,18 @@ struct JSExtendedClass {
 #define JSCLASS_CACHED_PROTO_MASK       JS_BITMASK(JSCLASS_CACHED_PROTO_WIDTH)
 #define JSCLASS_HAS_CACHED_PROTO(key)   ((key) << JSCLASS_CACHED_PROTO_SHIFT)
 #define JSCLASS_CACHED_PROTO_KEY(clasp) ((JSProtoKey)                         \
                                          (((clasp)->flags                     \
                                            >> JSCLASS_CACHED_PROTO_SHIFT)     \
                                           & JSCLASS_CACHED_PROTO_MASK))
 
 /* Initializer for unused members of statically initialized JSClass structs. */
-#define JSCLASS_NO_OPTIONAL_MEMBERS     0,0,0,0,0,0,0,0
-#define JSCLASS_NO_RESERVED_MEMBERS     0,0,0
+#define JSCLASS_NO_INTERNAL_MEMBERS     0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
+#define JSCLASS_NO_OPTIONAL_MEMBERS     0,0,0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS
 
 struct JSIdArray {
     jsint length;
     jsid  vector[1];    /* actually, length jsid words */
 };
 
 extern JS_PUBLIC_API(void)
 JS_DestroyIdArray(JSContext *cx, JSIdArray *ida);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -979,17 +979,16 @@ array_finalize(JSContext *cx, JSObject *
 {
     obj->freeDenseArrayElements(cx);
 }
 
 static void
 array_trace(JSTracer *trc, JSObject *obj)
 {
     JS_ASSERT(obj->isDenseArray());
-    obj->traceProtoAndParent(trc);
 
     if (!obj->dslots)
         return;
 
     size_t holes = 0;
     uint32 capacity = obj->getDenseArrayCapacity();
     for (uint32 i = 0; i < capacity; i++) {
         Value v = obj->getDenseArrayElement(i);
@@ -1000,59 +999,63 @@ array_trace(JSTracer *trc, JSObject *obj
     }
 
     if (IS_GC_MARKING_TRACER(trc) && holes > MIN_SPARSE_INDEX && holes > capacity / 4 * 3) {
         /* This might fail, in which case we don't slowify it. */
         static_cast<GCMarker *>(trc)->arraysToSlowify.append(obj);
     }
 }
 
-extern JSObjectOps js_ArrayObjectOps;
-
-static const JSObjectMap SharedArrayMap(&js_ArrayObjectOps, JSObjectMap::SHAPELESS);
-
-JSObjectOps js_ArrayObjectOps = {
-    &SharedArrayMap,
-    array_lookupProperty,
-    array_defineProperty,
-    array_getProperty,
-    array_setProperty,
-    array_getAttributes,
-    array_setAttributes,
-    array_deleteProperty,
-    js_Enumerate,
-    array_typeOf,
-    array_trace,
-    NULL, /* thisObject */
-    NULL  /* clear */
-};
-
-static JSObjectOps *
-array_getObjectOps(JSContext *cx, Class *clasp)
-{
-    return &js_ArrayObjectOps;
-}
-
 Class js_ArrayClass = {
     "Array",
+    Class::NON_NATIVE |
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::DENSE_ARRAY_FIXED_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
-    PropertyStub,       PropertyStub,    PropertyStub,         PropertyStub,
-    EnumerateStub,      ResolveStub,     js_TryValueOf,        array_finalize,
-    array_getObjectOps, NULL,            NULL,                 NULL,
-    NULL,               NULL,            NULL,                 NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    js_TryValueOf,
+    array_finalize,
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    NULL,           /* mark        */
+    JS_NULL_CLASS_EXT,
+    {
+        array_lookupProperty,
+        array_defineProperty,
+        array_getProperty,
+        array_setProperty,
+        array_getAttributes,
+        array_setAttributes,
+        array_deleteProperty,
+        NULL,       /* enumerate      */
+        array_typeOf,
+        array_trace,
+        NULL,       /* thisObject     */
+        NULL,       /* clear          */
+    }
 };
 
 Class js_SlowArrayClass = {
     "Array",
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
-    slowarray_addProperty,  PropertyStub,   PropertyStub,      PropertyStub,
-    EnumerateStub,          ResolveStub,    js_TryValueOf,     NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
+    slowarray_addProperty,
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    js_TryValueOf
 };
 
 /*
  * Convert an array object from fast-and-dense to slow-and-flexible.
  */
 JSBool
 JSObject::makeDenseArraySlow(JSContext *cx)
 {
@@ -1068,17 +1071,17 @@ JSObject::makeDenseArraySlow(JSContext *
     if (arrayProto->getClass() == &js_ObjectClass) {
         /* obj is Array.prototype. */
         emptyShape = js_GenerateShape(cx, false);
     } else {
         /* arrayProto is Array.prototype. */
         JS_ASSERT(arrayProto->getClass() == &js_SlowArrayClass);
         emptyShape = arrayProto->scope()->emptyScope->shape;
     }
-    JSScope *scope = JSScope::create(cx, &js_ObjectOps, &js_SlowArrayClass, obj, emptyShape);
+    JSScope *scope = JSScope::create(cx, &js_SlowArrayClass, obj, emptyShape);
     if (!scope)
         return JS_FALSE;
 
     uint32 capacity = obj->getDenseArrayCapacity();
 
     /* For a brief moment the object has NULL dslots until we slowify it during construction. */
     if (obj->dslots)
         obj->dslots[-1].setPrivateUint32(JS_INITIAL_NSLOTS + capacity);
@@ -2987,17 +2990,17 @@ js_NewEmptyArray(JSContext* cx, JSObject
 
     JS_ASSERT(proto->isArray());
 
     JSObject* obj = js_NewGCObject(cx);
     if (!obj)
         return NULL;
 
     /* Initialize all fields of JSObject. */
-    obj->map = const_cast<JSObjectMap *>(&SharedArrayMap);
+    obj->map = const_cast<JSObjectMap *>(&JSObjectMap::sharedNonNative);
     obj->init(&js_ArrayClass, proto, proto->getParent(), NullValue());
     obj->setArrayLength(len);
     obj->setDenseArrayCapacity(0);
     return obj;
 }
 #ifdef JS_TRACER
 JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewEmptyArray, CONTEXT, OBJECT, INT32, 0,
                      nanojit::ACCSET_STORE_ANY)
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -51,25 +51,28 @@
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsstr.h"
 #include "jsvector.h"
 
 #include "jsobjinlines.h"
 
-
 using namespace js;
 
 Class js_BooleanClass = {
     "Boolean",
     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean),
-    PropertyStub,  PropertyStub,  PropertyStub,  PropertyStub,
-    EnumerateStub, ResolveStub,   ConvertStub,   NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub
 };
 
 #if JS_HAS_TOSOURCE
 #include "jsprf.h"
 
 static JSBool
 bool_toSource(JSContext *cx, uintN argc, Value *vp)
 {
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -251,17 +251,17 @@ js_AddAtomProperty(JSContext* cx, JSObje
 JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddAtomProperty, CONTEXT, OBJECT, SCOPEPROP,
                      0, ACCSET_STORE_ANY)
 
 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->map->ops->lookupProperty != js_LookupProperty)
+        if (pobj->getOps()->lookupProperty)
             return JS_NEITHER;
         Class* clasp = pobj->getClass();
         if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass)
             return JS_NEITHER;
     }
 
     JSObject* obj2;
     JSProperty* prop;
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -742,16 +742,17 @@ js_PurgeThreads(JSContext *cx)
              * The following is potentially suboptimal as it also zeros the
              * caches in data, but the code simplicity wins here.
              */
             thread->data.gcFreeLists.purge();
             DestroyThread(thread);
             e.removeFront();
         } else {
             thread->data.purge(cx);
+            thread->gcThreadMallocBytes = JS_GC_THREAD_MALLOC_LIMIT;
         }
     }
 #else
     cx->runtime->threadData.purge(cx);
 #endif
 }
 
 /*
@@ -1905,46 +1906,53 @@ js_InvokeOperationCallback(JSContext *cx
      * Reset the callback flag first, then yield. If another thread is racing
      * us here we will accumulate another callback request which will be
      * serviced at the next opportunity.
      */
     JS_ATOMIC_CLEAR_MASK(&JS_THREAD_DATA(cx)->interruptFlags,
                          JSThreadData::INTERRUPT_OPERATION_CALLBACK);
 
     /*
-     * Ideally this should never be hit. The embedding should call JS_MaybeGC()
-     * to schedule preemptive GCs.
+     * Unless we are going to run the GC, we automatically yield the current
+     * context every time the operation callback is hit since we might be
+     * called as a result of an impending GC, which would deadlock if we do
+     * not yield. Operation callbacks are supposed to happen rarely (seconds,
+     * not milliseconds) so it is acceptable to yield at every callback.
      */
     JSRuntime *rt = cx->runtime;
-    if (rt->gcIsNeeded || rt->overQuota()) {
-        JS_GC(cx);
-        /* If we are still over quota after the GC, report an error. */
-        if (rt->overQuota()) {
+    if (rt->gcIsNeeded) {
+        js_GC(cx, GC_NORMAL);
+
+        /*
+         * On trace we can exceed the GC quota, see comments in NewGCArena. So
+         * we check the quota and report OOM here when we are off trace.
+         */
+        bool delayedOutOfMemory;
+        JS_LOCK_GC(rt);
+        delayedOutOfMemory = (rt->gcBytes > rt->gcMaxBytes);
+        JS_UNLOCK_GC(rt);
+        if (delayedOutOfMemory) {
             js_ReportOutOfMemory(cx);
             return false;
         }
     }
+#ifdef JS_THREADSAFE
+    else {
+        JS_YieldRequest(cx);
+    }
+#endif
 
-    /*
-     * Automatically yield the current context every time the operation callback
-     * is hit since we might be called as a result of an impending GC, which
-     * would deadlock if we do not yield. Operation callbacks are supposed to
-     * happen rarely (seconds, not milliseconds) so it is acceptable to yield at
-     * every callback.
-     */
-#ifdef JS_THREADSAFE
-    JS_YieldRequest(cx);
-#endif
+    JSOperationCallback cb = cx->operationCallback;
 
     /*
      * Important: Additional callbacks can occur inside the callback handler
      * if it re-enters the JS engine. The embedding must ensure that the
      * callback is disconnected before attempting such re-entry.
      */
-    JSOperationCallback cb = cx->operationCallback;
+
     return !cb || cb(cx);
 }
 
 JSBool
 js_HandleExecutionInterrupt(JSContext *cx)
 {
     JSBool result = JS_TRUE;
     if (JS_THREAD_DATA(cx)->interruptFlags & JSThreadData::INTERRUPT_OPERATION_CALLBACK)
@@ -2172,16 +2180,57 @@ JSContext::containingSegment(const JSSta
             if (f == target)
                 return css;
         }
     }
 
     return NULL;
 }
 
+void
+JSContext::checkMallocGCPressure(void *p)
+{
+    if (!p) {
+        js_ReportOutOfMemory(this);
+        return;
+    }
+
+#ifdef JS_THREADSAFE
+    JS_ASSERT(thread);
+    JS_ASSERT(thread->gcThreadMallocBytes <= 0);
+    ptrdiff_t n = JS_GC_THREAD_MALLOC_LIMIT - thread->gcThreadMallocBytes;
+    thread->gcThreadMallocBytes = JS_GC_THREAD_MALLOC_LIMIT;
+
+    AutoLockGC lock(runtime);
+    runtime->gcMallocBytes -= n;
+
+    /*
+     * Trigger the GC on memory pressure but only if we are inside a request
+     * and not inside a GC.
+     */
+    if (runtime->isGCMallocLimitReached() && requestDepth != 0)
+#endif
+    {
+        if (!runtime->gcRunning) {
+            JS_ASSERT(runtime->isGCMallocLimitReached());
+            runtime->gcMallocBytes = -1;
+
+            /*
+             * Empty the GC free lists to trigger a last-ditch GC when any GC
+             * thing is allocated later on this thread. This makes unnecessary
+             * to check for the memory pressure on the fast path of the GC
+             * allocator. We cannot touch the free lists on other threads as
+             * their manipulation is not thread-safe.
+             */
+            JS_THREAD_DATA(this)->gcFreeLists.purge();
+            js_TriggerGC(this, true);
+        }
+    }
+}
+
 bool
 JSContext::isConstructing()
 {
 #ifdef JS_TRACER
     if (JS_ON_TRACE(this)) {
         JS_ASSERT(bailExit);
         return *bailExit->pc == JSOP_NEW;
     }
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1012,16 +1012,23 @@ struct JSThreadData {
     volatile jsword     interruptFlags;
 
     JSGCFreeLists       gcFreeLists;
 
     /* Keeper of the contiguous stack used by all contexts in this thread. */
     js::StackSpace      stackSpace;
 
     /*
+     * Flag indicating that we are waiving any soft limits on the GC heap
+     * because we want allocations to be infallible (except when we hit
+     * a hard quota).
+     */
+    bool                waiveGCQuota;
+
+    /*
      * The GSN cache is per thread since even multi-cx-per-thread embeddings
      * do not interleave js_GetSrcNote calls.
      */
     JSGSNCache          gsnCache;
 
     /* Property cache for faster call/get/set invocation. */
     js::PropertyCache   propertyCache;
 
@@ -1101,16 +1108,22 @@ struct JSThread {
 
     /* Opaque thread-id, from NSPR's PR_GetCurrentThread(). */
     void                *id;
 
     /* Indicates that the thread is waiting in ClaimTitle from jslock.cpp. */
     JSTitle             *titleToShare;
 
     /*
+     * Thread-local version of JSRuntime.gcMallocBytes to avoid taking
+     * locks on each JS_malloc.
+     */
+    ptrdiff_t           gcThreadMallocBytes;
+
+    /*
      * This thread is inside js_GC, either waiting until it can start GC, or
      * waiting for GC to finish on another thread. This thread holds no locks;
      * other threads may steal titles from it.
      *
      * Protected by rt->gcLock.
      */
     bool                gcWaiting;
 
@@ -1118,16 +1131,23 @@ struct JSThread {
      * The context running the requests.
      */
     JSContext           *requestContext;
 
     /* Factored out of JSThread for !JS_THREADSAFE embedding in JSRuntime. */
     JSThreadData        data;
 };
 
+/*
+ * Only when JSThread::gcThreadMallocBytes exhausts the following limit we
+ * update JSRuntime::gcMallocBytes.
+ * .
+ */
+const size_t JS_GC_THREAD_MALLOC_LIMIT = 1 << 19;
+
 #define JS_THREAD_DATA(cx)      (&(cx)->thread->data)
 
 extern JSThread *
 js_CurrentThread(JSRuntime *rt);
 
 /*
  * The function takes the GC lock and does not release in successful return.
  * On error (out of memory) the function releases the lock but delegates
@@ -1282,19 +1302,16 @@ struct JSCompartment {
     bool wrap(JSContext *cx, js::PropertyOp *op);
     bool wrap(JSContext *cx, js::PropertyDescriptor *desc);
     bool wrap(JSContext *cx, js::AutoIdVector &props);
     bool wrapException(JSContext *cx);
 
     void sweep(JSContext *cx);
 };
 
-extern JS_FRIEND_API(void)
-js_TriggerAllOperationCallbacks(JSRuntime *rt, JSBool gcLocked);
-
 struct JSRuntime {
     /* Default compartment. */
     JSCompartment       *defaultCompartment;
 
     /* List of compartments (protected by the GC lock). */
     js::Vector<JSCompartment *, 0, js::SystemAllocPolicy> compartments;
 
     /* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */
@@ -1368,17 +1385,17 @@ struct JSRuntime {
 #endif
 
     JSGCCallback        gcCallback;
 
     /*
      * Malloc counter to measure memory pressure for GC scheduling. It runs
      * from gcMaxMallocBytes down to zero.
      */
-    volatile ptrdiff_t  gcMallocBytes;
+    ptrdiff_t           gcMallocBytes;
 
 #ifdef JS_THREADSAFE
     JSBackgroundThread  gcHelperThread;
 #endif
 
     js::GCChunkAllocator    *gcChunkAllocator;
     
     void setCustomGCChunkAllocator(js::GCChunkAllocator *allocator) {
@@ -1653,57 +1670,29 @@ struct JSRuntime {
 
     JSWrapObjectCallback wrapObjectCallback;
 
     JSRuntime();
     ~JSRuntime();
 
     bool init(uint32 maxbytes);
 
-    inline void triggerGC(bool gcLocked) {
-        if (!gcIsNeeded) {
-            gcIsNeeded = true;
-            js_TriggerAllOperationCallbacks(this, gcLocked);
-        }
-    }
-
     void setGCTriggerFactor(uint32 factor);
     void setGCLastBytes(size_t lastBytes);
 
-    bool gcQuotaReached() {
-        return gcBytes >= gcMaxBytes;
-    }
-
-    void updateMallocCounter(size_t bytes) {
-        /* We tolerate races and lost counts here. */
-        if ((gcMallocBytes -= bytes) <= 0)
-            triggerGC(false);
-    }
-
-    bool mallocQuotaReached() {
-        return gcMallocBytes <= 0;
-    }
-
-    bool overQuota() {
-        return gcQuotaReached() || mallocQuotaReached();
-    }
-
-    void* malloc(size_t bytes) { updateMallocCounter(bytes); return ::js_malloc(bytes); }
-
-    void* calloc(size_t bytes) { updateMallocCounter(bytes); return ::js_calloc(bytes); }
-
-    void* realloc(void* p, size_t bytes) {
-        void* q = ::js_realloc(p, bytes);
-        if (p != q)
-            updateMallocCounter(bytes);
-        return q;
-    }
+    void* malloc(size_t bytes) { return ::js_malloc(bytes); }
+
+    void* calloc(size_t bytes) { return ::js_calloc(bytes); }
+
+    void* realloc(void* p, size_t bytes) { return ::js_realloc(p, bytes); }
 
     void free(void* p) { ::js_free(p); }
 
+    bool isGCMallocLimitReached() const { return gcMallocBytes <= 0; }
+
     void resetGCMallocBytes() { gcMallocBytes = ptrdiff_t(gcMaxMallocBytes); }
 
     void setGCMaxMallocBytes(size_t value) {
         /*
          * For compatibility treat any value that exceeds PTRDIFF_T_MAX to
          * mean that value.
          */
         gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
@@ -1788,19 +1777,16 @@ struct JSRegExpStatics {
 
     JSRegExpStatics(JSContext *cx) : cx(cx), parens(cx) {}
 
     bool copy(const JSRegExpStatics& other);
     void clearRoots();
     void clear();
 };
 
-extern JS_FRIEND_API(void)
-js_ReportOutOfMemory(JSContext *cx);
-
 struct JSContext
 {
     explicit JSContext(JSRuntime *rt);
 
     /* JSRuntime contextList linkage. */
     JSCList             link;
 
     /* Runtime version control identifier. */
@@ -2077,39 +2063,86 @@ struct JSContext
 
 #ifdef JS_THREADSAFE
     /*
      * The sweep task for this context.
      */
     js::BackgroundSweepTask *gcSweepTask;
 #endif
 
-    inline void *reportIfOutOfMemory(void *p) {
-        if (!p)
-            js_ReportOutOfMemory(this);
-        return p;
+    ptrdiff_t &getMallocCounter() {
+#ifdef JS_THREADSAFE
+        return thread->gcThreadMallocBytes;
+#else
+        return runtime->gcMallocBytes;
+#endif
+    }
+
+    /*
+     * Call this after allocating memory held by GC things, to update memory
+     * pressure counters or report the OOM error if necessary.
+     */
+    inline void updateMallocCounter(void *p, size_t nbytes) {
+        JS_ASSERT(ptrdiff_t(nbytes) >= 0);
+        ptrdiff_t &counter = getMallocCounter();
+        counter -= ptrdiff_t(nbytes);
+        if (!p || counter <= 0)
+            checkMallocGCPressure(p);
+    }
+
+    /*
+     * Call this after successfully allocating memory held by GC things, to
+     * update memory pressure counters.
+     */
+    inline void updateMallocCounter(size_t nbytes) {
+        JS_ASSERT(ptrdiff_t(nbytes) >= 0);
+        ptrdiff_t &counter = getMallocCounter();
+        counter -= ptrdiff_t(nbytes);
+        if (counter <= 0) {
+            /*
+             * Use 1 as an arbitrary non-null pointer indicating successful
+             * allocation.
+             */
+            checkMallocGCPressure(reinterpret_cast<void *>(jsuword(1)));
+        }
     }
 
     inline void* malloc(size_t bytes) {
         JS_ASSERT(bytes != 0);
-        return reportIfOutOfMemory(runtime->malloc(bytes));
+        void *p = runtime->malloc(bytes);
+        updateMallocCounter(p, bytes);
+        return p;
     }
 
     inline void* mallocNoReport(size_t bytes) {
         JS_ASSERT(bytes != 0);
-        return runtime->malloc(bytes);
+        void *p = runtime->malloc(bytes);
+        if (!p)
+            return NULL;
+        updateMallocCounter(bytes);
+        return p;
     }
 
     inline void* calloc(size_t bytes) {
         JS_ASSERT(bytes != 0);
-        return reportIfOutOfMemory(runtime->calloc(bytes));
+        void *p = runtime->calloc(bytes);
+        updateMallocCounter(p, bytes);
+        return p;
     }
 
     inline void* realloc(void* p, size_t bytes) {
-        return reportIfOutOfMemory(runtime->realloc(p, bytes));
+        void *orig = p;
+        p = runtime->realloc(p, bytes);
+
+        /*
+         * For compatibility we do not account for realloc that increases
+         * previously allocated memory.
+         */
+        updateMallocCounter(p, orig ? 0 : bytes);
+        return p;
     }
 
     inline void free(void* p) {
 #ifdef JS_THREADSAFE
         if (gcSweepTask) {
             gcSweepTask->freeLater(p);
             return;
         }
@@ -2166,16 +2199,26 @@ struct JSContext
 #ifdef DEBUG
     void assertValidStackDepth(uintN depth) {
         JS_ASSERT(0 <= regs->sp - fp->base());
         JS_ASSERT(depth <= uintptr_t(regs->sp - fp->base()));
     }
 #else
     void assertValidStackDepth(uintN /*depth*/) {}
 #endif
+
+private:
+
+    /*
+     * The allocation code calls the function to indicate either OOM failure
+     * when p is null or that a memory pressure counter has reached some
+     * threshold when p is not null. The function takes the pointer and not
+     * a boolean flag to minimize the amount of code in its inlined callers.
+     */
+    JS_FRIEND_API(void) checkMallocGCPressure(void *p);
 };
 
 JS_ALWAYS_INLINE JSObject *
 JSStackFrame::varobj(js::CallStackSegment *css) const
 {
     JS_ASSERT(css->contains(this));
     return fun ? callobj : css->getInitialVarObj();
 }
@@ -2924,16 +2967,19 @@ js_ReportErrorNumberVA(JSContext *cx, ui
 
 extern JSBool
 js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
                         void *userRef, const uintN errorNumber,
                         char **message, JSErrorReport *reportp,
                         bool charArgs, va_list ap);
 #endif
 
+extern void
+js_ReportOutOfMemory(JSContext *cx);
+
 /*
  * Report that cx->scriptStackQuota is exhausted.
  */
 void
 js_ReportOutOfScriptQuota(JSContext *cx);
 
 extern void
 js_ReportOverRecursed(JSContext *cx);
@@ -3025,16 +3071,25 @@ extern JSErrorFormatString js_ErrorForma
  * is to be terminated.
  */
 extern JSBool
 js_InvokeOperationCallback(JSContext *cx);
 
 extern JSBool
 js_HandleExecutionInterrupt(JSContext *cx);
 
+
+#ifndef JS_THREADSAFE
+# define js_TriggerAllOperationCallbacks(rt, gcLocked) \
+    js_TriggerAllOperationCallbacks (rt)
+#endif
+
+void
+js_TriggerAllOperationCallbacks(JSRuntime *rt, JSBool gcLocked);
+
 extern JSStackFrame *
 js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp);
 
 extern jsbytecode*
 js_GetCurrentBytecodePC(JSContext* cx);
 
 extern bool
 js_CurrentPCIsInImacro(JSContext *cx);
@@ -3060,17 +3115,17 @@ LeaveTrace(JSContext *cx)
     if (JS_ON_TRACE(cx))
         DeepBail(cx);
 #endif
 }
 
 static JS_INLINE void
 LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj)
 {
-    if (obj->fslots[JSSLOT_PARENT].isNull())
+    if (!obj->parent)
         LeaveTrace(cx);
 }
 
 static JS_INLINE JSBool
 CanLeaveTrace(JSContext *cx)
 {
     JS_ASSERT(JS_ON_TRACE(cx));
 #ifdef JS_TRACER
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -480,19 +480,23 @@ msFromTime(jsdouble t)
 /*
  * Other Support routines and definitions
  */
 
 Class js_DateClass = {
     js_Date_str,
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_FIXED_RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
-    PropertyStub,  PropertyStub,  PropertyStub,  PropertyStub,
-    EnumerateStub, ResolveStub,   ConvertStub,   NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub
 };
 
 /* for use by date_parse */
 
 static const char* wtb[] = {
     "am", "pm",
     "monday", "tuesday", "wednesday", "thursday", "friday",
     "saturday", "sunday",
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -83,20 +83,31 @@ exn_enumerate(JSContext *cx, JSObject *o
 static JSBool
 exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
             JSObject **objp);
 
 Class js_ErrorClass = {
     js_Error_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_MARK_IS_TRACE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Error),
-    PropertyStub,     PropertyStub,     PropertyStub,     PropertyStub,
-    exn_enumerate,    (JSResolveOp)exn_resolve, ConvertStub, exn_finalize,
-    NULL,             NULL,             NULL,             Exception,
-    NULL,             NULL,             JS_CLASS_TRACE(exn_trace), NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    exn_enumerate,
+    (JSResolveOp)exn_resolve,
+    ConvertStub,
+    exn_finalize,
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    Exception,      /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    JS_CLASS_TRACE(exn_trace)
 };
 
 typedef struct JSStackTraceElem {
     JSString            *funName;
     size_t              argc;
     const char          *filename;
     uintN               ulineno;
 } JSStackTraceElem;
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -683,40 +683,51 @@ args_or_call_trace(JSTracer *trc, JSObje
  * in a JSStackFrame with their corresponding property values in the frame's
  * arguments object.
  */
 Class js_ArgumentsClass = {
     "Arguments",
     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_FIXED_RESERVED_SLOTS) |
     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
-    PropertyStub,       args_delProperty,
-    PropertyStub,       PropertyStub,
-    args_enumerate,     (JSResolveOp) args_resolve,
-    ConvertStub,        NULL,
-    NULL,               NULL,
-    NULL,               NULL,
-    NULL,               NULL,
-    JS_CLASS_TRACE(args_or_call_trace), NULL
+    PropertyStub,   /* addProperty */
+    args_delProperty,
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    args_enumerate,
+    (JSResolveOp) args_resolve,
+    ConvertStub,
+    NULL,           /* finalize   */
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    JS_CLASS_TRACE(args_or_call_trace)
 };
 
 const uint32 JSSLOT_CALLEE =                    JSSLOT_PRIVATE + 1;
 const uint32 JSSLOT_CALL_ARGUMENTS =            JSSLOT_PRIVATE + 2;
 const uint32 CALL_CLASS_FIXED_RESERVED_SLOTS =  2;
 
 /*
  * A Declarative Environment object stores its active JSStackFrame pointer in
  * its private slot, just as Call and Arguments objects do.
  */
 Class js_DeclEnvClass = {
     js_Object_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
-    PropertyStub,     PropertyStub,     PropertyStub,     PropertyStub,
-    EnumerateStub,    ResolveStub,      ConvertStub,      NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub
 };
 
 static JSBool
 CheckForEscapingClosure(JSContext *cx, JSObject *obj, Value *vp)
 {
     JS_ASSERT(obj->getClass() == &js_CallClass ||
               obj->getClass() == &js_DeclEnvClass);
 
@@ -1264,24 +1275,31 @@ call_resolve(JSContext *cx, JSObject *ob
     return JS_TRUE;
 }
 
 JS_PUBLIC_DATA(Class) js_CallClass = {
     "Call",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(CALL_CLASS_FIXED_RESERVED_SLOTS) |
     JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
-    PropertyStub,       PropertyStub,
-    PropertyStub,       PropertyStub,
-    call_enumerate,     (JSResolveOp)call_resolve,
-    NULL,               NULL,
-    NULL,               NULL,
-    NULL,               NULL,
-    NULL,               NULL,
-    JS_CLASS_TRACE(args_or_call_trace), NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    call_enumerate,
+    (JSResolveOp)call_resolve,
+    NULL,           /* convert */
+    NULL,           /* finalize */
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    JS_CLASS_TRACE(args_or_call_trace)
 };
 
 bool
 JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
 {
     if (!fun) {
         *vp = argv ? argv[-2] : UndefinedValue();
         return true;
@@ -1907,24 +1925,31 @@ JSFunction::countInterpretedReservedSlot
  * 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_Function_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::FUN_FIXED_RESERVED_SLOTS) |
     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
-    PropertyStub,     PropertyStub,
-    PropertyStub,     PropertyStub,
-    fun_enumerate,    (JSResolveOp)fun_resolve,
-    ConvertStub,      fun_finalize,
-    NULL,             NULL,
-    NULL,             NULL,
-    js_XDRFunctionObject, fun_hasInstance,
-    JS_CLASS_TRACE(fun_trace), NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    fun_enumerate,
+    (JSResolveOp)fun_resolve,
+    ConvertStub,
+    fun_finalize,
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    js_XDRFunctionObject,
+    fun_hasInstance,
+    JS_CLASS_TRACE(fun_trace)
 };
 
 namespace js {
 
 JSString *
 fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent)
 {
     if (!obj->isFunction()) {
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -632,29 +632,39 @@ ReleaseGCChunk(JSRuntime *rt, jsuword ch
     METER(rt->gcStats.nchunks--);
     rt->gcChunkAllocator->free(p);
 }
 
 static JSGCArena *
 NewGCArena(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
+    if (!JS_THREAD_DATA(cx)->waiveGCQuota && rt->gcBytes >= rt->gcMaxBytes) {
+        /*
+         * FIXME bug 524051 We cannot run a last-ditch GC on trace for now, so
+         * just pretend we are out of memory which will throw us off trace and
+         * we will re-try this code path from the interpreter.
+         */
+        if (!JS_ON_TRACE(cx))
+            return NULL;
+        js_TriggerGC(cx, true);
+    }
 
     size_t nchunks = rt->gcChunks.length();
+
     JSGCChunkInfo *ci;
     for (;; ++rt->gcChunkCursor) {
         if (rt->gcChunkCursor == nchunks) {
             ci = NULL;
             break;
         }
         ci = rt->gcChunks[rt->gcChunkCursor];
         if (ci->numFreeArenas != 0)
             break;
     }
-
     if (!ci) {
         if (!rt->gcChunks.reserve(nchunks + 1))
             return NULL;
         void *chunkptr = GetGCChunk(rt);
         if (!chunkptr)
             return NULL;
         ci = JSGCChunkInfo::fromChunk(reinterpret_cast<jsuword>(chunkptr));
         ci->init(rt);
@@ -1688,55 +1698,107 @@ JSGCFreeLists::purge()
 void
 JSGCFreeLists::moveTo(JSGCFreeLists *another)
 {
     *another = *this;
     PodArrayZero(finalizables);
     JS_ASSERT(isEmpty());
 }
 
+static inline bool
+IsGCThresholdReached(JSRuntime *rt)
+{
+#ifdef JS_GC_ZEAL
+    if (rt->gcZeal >= 1)
+        return true;
+#endif
+
+    /*
+     * Since the initial value of the gcLastBytes parameter is not equal to
+     * zero (see the js_InitGC function) the return value is false when
+     * the gcBytes value is close to zero at the JS engine start.
+     */
+    return rt->isGCMallocLimitReached() || rt->gcBytes >= rt->gcTriggerBytes;
+}
+
+static void
+LastDitchGC(JSContext *cx)
+{
+    JS_ASSERT(!JS_ON_TRACE(cx));
+
+    /* The last ditch GC preserves weak roots and all atoms. */
+    AutoPreserveWeakRoots save(cx);
+    AutoKeepAtoms keep(cx->runtime);
+
+    /*
+     * Keep rt->gcLock across the call into the GC so we don't starve and
+     * lose to racing threads who deplete the heap just after the GC has
+     * replenished it (or has synchronized with a racing GC that collected a
+     * bunch of garbage).  This unfair scheduling can happen on certain
+     * operating systems. For the gory details, see bug 162779.
+     */
+    js_GC(cx, GC_LOCK_HELD);
+}
+
 static JSGCThing *
 RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
 {
     JS_ASSERT(!JS_THREAD_DATA(cx)->gcFreeLists.finalizables[thingKind]);
     JSRuntime *rt = cx->runtime;
     JSGCArenaList *arenaList;
     JSGCArena *a;
 
     {
         AutoLockGC lock(rt);
         JS_ASSERT(!rt->gcRunning);
         if (rt->gcRunning) {
             METER(rt->gcStats.finalfail++);
             return NULL;
         }
 
+        bool canGC = !JS_ON_TRACE(cx) && !JS_THREAD_DATA(cx)->waiveGCQuota;
+        bool doGC = canGC && IsGCThresholdReached(rt);
         arenaList = &rt->gcArenaList[thingKind];
-        while ((a = arenaList->cursor) != NULL) {
-            JSGCArenaInfo *ainfo = a->getInfo();
-            arenaList->cursor = ainfo->prev;
-            JSGCThing *freeList = ainfo->freeList;
-            if (freeList) {
-                ainfo->freeList = NULL;
-                return freeList;
+        for (;;) {
+            if (doGC) {
+                LastDitchGC(cx);
+                METER(cx->runtime->gcStats.arenaStats[thingKind].retry++);
+                canGC = false;
+
+                /*
+                 * The JSGC_END callback can legitimately allocate new GC
+                 * things and populate the free list. If that happens, just
+                 * return that list head.
+                 */
+                JSGCThing *freeList = JS_THREAD_DATA(cx)->gcFreeLists.finalizables[thingKind];
+                if (freeList)
+                    return freeList;
             }
+
+            while ((a = arenaList->cursor) != NULL) {
+                JSGCArenaInfo *ainfo = a->getInfo();
+                arenaList->cursor = ainfo->prev;
+                JSGCThing *freeList = ainfo->freeList;
+                if (freeList) {
+                    ainfo->freeList = NULL;
+                    return freeList;
+                }
+            }
+
+            a = NewGCArena(cx);
+            if (a)
+                break;
+            if (!canGC) {
+                METER(cx->runtime->gcStats.arenaStats[thingKind].fail++);
+                return NULL;
+            }
+            doGC = true;
         }
 
         /*
-         * If we have to allocate a new arena, check whether are bumping
-         * against our GC heap quota. If so, request a GC to happen soon.
-         */
-        if (rt->gcQuotaReached())
-            cx->runtime->triggerGC(true);
-
-        a = NewGCArena(cx);
-        if (!a)
-            return NULL;
-
-        /*
          * Do only minimal initialization of the arena inside the GC lock. We
          * can do the rest outside the lock because no other threads will see
          * the arena until the GC is run.
          */
         JSGCArenaInfo *ainfo = a->getInfo();
         ainfo->list = arenaList;
         ainfo->prev = arenaList->head;
         ainfo->freeList = NULL;
@@ -1850,17 +1912,22 @@ JS_PUBLIC_API(void)
 JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
 {
     switch (kind) {
       case JSTRACE_OBJECT: {
         /* If obj has no map, it must be a newborn. */
         JSObject *obj = (JSObject *) thing;
         if (!obj->map)
             break;
-        obj->map->ops->trace(trc, obj);
+        if (JSObject *proto = obj->getProto())
+            JS_CALL_OBJECT_TRACER(trc, proto, "proto");
+        if (JSObject *parent = obj->getParent())
+            JS_CALL_OBJECT_TRACER(trc, parent, "parent");
+        JSTraceOp op = obj->getOps()->trace;
+        (op ? op : js_TraceObject)(trc, obj);
         break;
       }
 
       case JSTRACE_STRING: {
         JSString *str = (JSString *) thing;
         if (str->isDependent())
             JS_CALL_STRING_TRACER(trc, str->dependentBase(), "base");
         else if (str->isRope()) {
@@ -2453,16 +2520,36 @@ js_TraceRuntime(JSTracer *trc)
                 JS_CALL_OBJECT_TRACER(trc, fun, "FunctionCountMap key");
             }
         }
     }
 #endif
 }
 
 void
+js_TriggerGC(JSContext *cx, JSBool gcLocked)
+{
+    JSRuntime *rt = cx->runtime;
+
+#ifdef JS_THREADSAFE
+    JS_ASSERT(cx->requestDepth > 0);
+#endif
+    JS_ASSERT(!rt->gcRunning);
+    if (rt->gcIsNeeded)
+        return;
+
+    /*
+     * Trigger the GC when it is safe to call an operation callback on any
+     * thread.
+     */
+    rt->gcIsNeeded = JS_TRUE;
+    js_TriggerAllOperationCallbacks(rt, gcLocked);
+}
+
+void
 js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data)
 {
     JSScript **listp, *script;
 
     for (size_t i = 0; i != JS_ARRAY_LENGTH(data->scriptsToGC); ++i) {
         listp = &data->scriptsToGC[i];
         while ((script = *listp) != NULL) {
             *listp = script->u.nextToGC;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -160,16 +160,26 @@ js_TraceStackFrame(JSTracer *trc, JSStac
 
 extern JS_REQUIRES_STACK void
 js_TraceRuntime(JSTracer *trc);
 
 extern JS_REQUIRES_STACK JS_FRIEND_API(void)
 js_TraceContext(JSTracer *trc, JSContext *acx);
 
 /*
+ * Schedule the GC call at a later safe point.
+ */
+#ifndef JS_THREADSAFE
+# define js_TriggerGC(cx, gcLocked)    js_TriggerGC (cx)
+#endif
+
+extern void
+js_TriggerGC(JSContext *cx, JSBool gcLocked);
+
+/*
  * Kinds of js_GC invocation.
  */
 typedef enum JSGCInvocationKind {
     /* Normal invocation. */
     GC_NORMAL           = 0,
 
     /*
      * Called from js_DestroyContext for last JSContext in a JSRuntime, when
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -310,19 +310,23 @@ ComputeThisFromArgv(JSContext *cx, Value
 #if JS_HAS_NO_SUCH_METHOD
 
 const uint32 JSSLOT_FOUND_FUNCTION  = JSSLOT_PRIVATE;
 const uint32 JSSLOT_SAVED_ID        = JSSLOT_PRIVATE + 1;
 
 Class js_NoSuchMethodClass = {
     "NoSuchMethod",
     JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
-    PropertyStub,     PropertyStub,     PropertyStub,      PropertyStub,
-    EnumerateStub,    ResolveStub,      ConvertStub,       NULL,
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
 };
 
 /*
  * When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of
  * the base object, we search for the __noSuchMethod__ method in the base.
  * If it exists, we store the method and the property's id into an object of
  * NoSuchMethod class and store this object into the callee's stack slot.
  * Later, js_Invoke will recognise such an object and transfer control to
@@ -658,17 +662,17 @@ DoSlowCall(JSContext *cx, uintN argc, Va
     JSStackFrame *fp = cx->fp;
     JSObject *obj = fp->getThisObject(cx);
     if (!obj)
         return false;
     JS_ASSERT(ObjectValue(*obj) == fp->thisv);
 
     JSObject *callee = &JS_CALLEE(cx, vp).toObject();
     Class *clasp = callee->getClass();
-    JS_ASSERT(!(clasp->flags & CLASS_CALL_IS_FAST));
+    JS_ASSERT(!(clasp->flags & Class::CALL_IS_FAST));
     if (!clasp->call) {
         js_ReportIsNotFunction(cx, &vp[0], 0);
         return JS_FALSE;
     }
     AutoValueRooter rval(cx);
     JSBool ok = clasp->call(cx, obj, argc, JS_ARGV(cx, vp), rval.addr());
     if (ok)
         JS_SET_RVAL(cx, vp, rval.value());
@@ -760,17 +764,17 @@ Invoke(JSContext *cx, const InvokeArgsGu
     /* Try a call or construct native object op. */
     if (flags & JSINVOKE_CONSTRUCT) {
         if (!vp[1].isObjectOrNull()) {
             if (!js_PrimitiveToObject(cx, &vp[1]))
                 return false;
         }
         return InvokeCommon(cx, NULL, NULL, DoConstruct, args, flags);
     }
-    CallOp callOp = (clasp->flags & CLASS_CALL_IS_FAST) ? (CallOp) clasp->call : DoSlowCall;
+    CallOp callOp = (clasp->flags & Class::CALL_IS_FAST) ? (CallOp) clasp->call : DoSlowCall;
     return InvokeCommon(cx, NULL, NULL, callOp, args, flags);
 }
 
 extern JS_REQUIRES_STACK JS_FRIEND_API(bool)
 InvokeFriendAPI(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
 {
     return Invoke(cx, args, flags);
 }
@@ -910,17 +914,17 @@ Execute(JSContext *cx, JSObject *chain, 
         if (!innerizedChain)
             return false;
         fp->scopeChain = innerizedChain;
 
         initialVarObj = (cx->options & JSOPTION_VAROBJFIX)
                         ? chain->getGlobal()
                         : chain;
     }
-    JS_ASSERT(initialVarObj->map->ops->defineProperty == js_DefineProperty);
+    JS_ASSERT(!initialVarObj->getOps()->defineProperty);
 
     fp->script = script;
     fp->imacpc = NULL;
     fp->rval.setUndefined();
     fp->blockChain = NULL;
 
     /* Initialize regs. */
     regs.pc = script->code;
@@ -1149,17 +1153,17 @@ TypeOfValue(JSContext *cx, const Value &
         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().map->ops->typeOf(cx, &v.toObject());
+        return v.toObject().typeOf(cx);
     JS_ASSERT(v.isBoolean());
     return JSTYPE_BOOLEAN;
 }
 
 bool
 InstanceOfSlow(JSContext *cx, JSObject *obj, Class *clasp, Value *argv)
 {
     JS_ASSERT(!obj || obj->getClass() != clasp);
@@ -2060,31 +2064,31 @@ 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->getClass() == &js_IteratorClass.base) {
+    if (iterobj->getClass() == &js_IteratorClass) {
         NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
         *cond = (ni->props_cursor < ni->props_end);
     } else {
         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->getClass() == &js_IteratorClass.base) {
+    if (iterobj->getClass() == &js_IteratorClass) {
         NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
         JS_ASSERT(ni->props_cursor < ni->props_end);
         if (ni->isKeyIter()) {
             jsid id = *ni->currentKey();
             if (JSID_IS_ATOM(id)) {
                 rval->setString(JSID_TO_STRING(id));
                 ni->incKeyCursor();
                 return true;
@@ -3330,30 +3334,28 @@ END_CASE(JSOP_BITAND)
     if ((lval.isObject() && lval.toObject().isXML()) ||                       \
         (rval.isObject() && rval.toObject().isXML())) {                       \
         if (!js_TestXMLEquality(cx, lval, rval, &cond))                       \
             goto error;                                                       \
         cond = cond OP JS_TRUE;                                               \
     } else
 
 #define EXTENDED_EQUALITY_OP(OP)                                              \
-    if (((clasp = l->getClass())->flags & JSCLASS_IS_EXTENDED) &&             \
-        ((ExtendedClass *)clasp)->equality) {                                 \
-        if (!((ExtendedClass *)clasp)->equality(cx, l, &rval, &cond))         \
+    if (EqualityOp eq = l->getClass()->ext.equality) {                        \
+        if (!eq(cx, l, &rval, &cond))                                         \
             goto error;                                                       \
         cond = cond OP JS_TRUE;                                               \
     } else
 #else
 #define XML_EQUALITY_OP(OP)             /* nothing */
 #define EXTENDED_EQUALITY_OP(OP)        /* nothing */
 #endif
 
 #define EQUALITY_OP(OP, IFNAN)                                                \
     JS_BEGIN_MACRO                                                            \
-        Class *clasp;                                                         \
         JSBool cond;                                                          \
         Value rval = regs.sp[-1];                                             \
         Value lval = regs.sp[-2];                                             \
         XML_EQUALITY_OP(OP)                                                   \
         if (SameType(lval, rval)) {                                           \
             if (lval.isString()) {                                            \
                 JSString *l = lval.toString(), *r = rval.toString();          \
                 cond = js_EqualStrings(l, r) OP JS_TRUE;                      \
@@ -4130,17 +4132,17 @@ BEGIN_CASE(JSOP_GETXPROP)
                     NATIVE_GET(cx, obj, obj2, sprop,
                                fp->imacpc ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
                                &rval);
                 }
                 break;
             }
 
             jsid id = ATOM_TO_JSID(atom);
-            if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)
+            if (JS_LIKELY(!aobj->getOps()->getProperty)
                 ? !js_GetPropertyHelper(cx, obj, id,
                                         (fp->imacpc ||
                                          regs.pc[JSOP_GETPROP_LENGTH + i] == JSOP_IFEQ)
                                         ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
                                         : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
                                         &rval)
                 : !obj->getProperty(cx, id, &rval)) {
                 goto error;
@@ -4234,26 +4236,26 @@ BEGIN_CASE(JSOP_CALLPROP)
      * PropertyCache::test.
      */
     jsid id;
     id = ATOM_TO_JSID(atom);
 
     PUSH_NULL();
     if (lval.isObject()) {
         if (!js_GetMethod(cx, &objv.toObject(), id,
-                          JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)
+                          JS_LIKELY(!aobj->getOps()->getProperty)
                           ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
                           : JSGET_NO_METHOD_BARRIER,
                           &rval)) {
             goto error;
         }
         regs.sp[-1] = objv;
         regs.sp[-2] = rval;
     } else {
-        JS_ASSERT(objv.toObject().map->ops->getProperty == js_GetProperty);
+        JS_ASSERT(!objv.toObject().getOps()->getProperty);
         if (!js_GetPropertyHelper(cx, &objv.toObject(), id,
                                   JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER,
                                   &rval)) {
             goto error;
         }
         regs.sp[-1] = lval;
         regs.sp[-2] = rval;
     }
@@ -4470,17 +4472,17 @@ BEGIN_CASE(JSOP_SETMETHOD)
             }
             if (sprop)
                 break;
         }
 
         if (!atom)
             LOAD_ATOM(0, atom);
         jsid id = ATOM_TO_JSID(atom);
-        if (entry && JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) {
+        if (entry && JS_LIKELY(!obj->getOps()->setProperty)) {
             uintN defineHow;
             if (op == JSOP_SETMETHOD)
                 defineHow = JSDNP_CACHE_RESULT | JSDNP_SET_METHOD;
             else if (op == JSOP_SETNAME)
                 defineHow = JSDNP_CACHE_RESULT | JSDNP_UNQUALIFIED;
             else
                 defineHow = JSDNP_CACHE_RESULT;
             if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval))
@@ -5483,17 +5485,17 @@ BEGIN_CASE(JSOP_DEFVAR)
     JSAtom *atom = atoms[index];
 
     /*
      * index is relative to atoms at this point but for global var
      * code below we need the absolute value.
      */
     index += atoms - script->atomMap.vector;
     JSObject *obj = fp->varobj(cx);
-    JS_ASSERT(obj->map->ops->defineProperty == js_DefineProperty);
+    JS_ASSERT(!obj->getOps()->defineProperty);
     uintN attrs = JSPROP_ENUMERATE;
     if (!(fp->flags & JSFRAME_EVAL))
         attrs |= JSPROP_PERMANENT;
     if (op == JSOP_DEFCONST)
         attrs |= JSPROP_READONLY;
 
     /* Lookup id in order to check for redeclaration problems. */
     jsid id = ATOM_TO_JSID(atom);
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -80,29 +80,41 @@
 #include "jsstrinlines.h"
 
 using namespace js;
 
 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);
 
-ExtendedClass js_IteratorClass = {
-  { "Iterator",
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) |
-    JSCLASS_MARK_IS_TRACE |
-    JSCLASS_IS_EXTENDED,
-    PropertyStub,     PropertyStub,    PropertyStub,     PropertyStub,
-    EnumerateStub,    ResolveStub,     ConvertStub,      iterator_finalize,
-    NULL,             NULL,            NULL,             NULL,
-    NULL,             NULL,            JS_CLASS_TRACE(iterator_trace), NULL },
-    NULL,             NULL,            NULL,             iterator_iterator,
-    NULL,
-    JSCLASS_NO_RESERVED_MEMBERS
+Class js_IteratorClass = {
+    "Iterator",
+    JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) | JSCLASS_MARK_IS_TRACE,
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    iterator_finalize,
+    NULL,           /* reserved    */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    JS_CLASS_TRACE(iterator_trace),
+    {
+        NULL,       /* equality       */
+        NULL,       /* outerObject    */
+        NULL,       /* innerObject    */
+        iterator_iterator,
+        NULL        /* wrappedObject  */
+    }
 };
 
 void
 NativeIterator::mark(JSTracer *trc)
 {
     if (isKeyIter())
         MarkIdRange(trc, beginKey(), endKey(), "props");
     else
@@ -113,17 +125,17 @@ NativeIterator::mark(JSTracer *trc)
 
 /*
  * Shared code to close iterator's state either through an explicit call or
  * when GC detects that the iterator is no longer reachable.
  */
 static void
 iterator_finalize(JSContext *cx, JSObject *obj)
 {
-    JS_ASSERT(obj->getClass() == &js_IteratorClass.base);
+    JS_ASSERT(obj->getClass() == &js_IteratorClass);
 
     /* Avoid double work if the iterator was closed by JSOP_ENDITER. */
     NativeIterator *ni = obj->getNativeIterator();
     if (ni) {
         cx->free(ni);
         obj->setNativeIterator(NULL);
     }
 }
@@ -303,17 +315,17 @@ Snapshot(JSContext *cx, JSObject *obj, u
     IdSet ht(cx);
     if (!ht.init(32))
         return NULL;
 
     JSObject *pobj = obj;
     do {
         Class *clasp = pobj->getClass();
         if (pobj->isNative() &&
-            pobj->map->ops->enumerate == js_Enumerate &&
+            !pobj->getOps()->enumerate &&
             !(clasp->flags & JSCLASS_NEW_ENUMERATE)) {
             if (!clasp->enumerate(cx, pobj))
                 return false;
             if (!EnumerateNativeProperties<EnumPolicy>(cx, obj, pobj, flags, ht, props))
                 return false;
         } else if (pobj->isDenseArray()) {
             if (!EnumerateDenseArrayProperties<EnumPolicy>(cx, obj, pobj, flags, ht, props))
                 return false;
@@ -444,21 +456,21 @@ NewIteratorObject(JSContext *cx, uintN f
          * are not stillborn, with the exception of "NoSuchMethod" internal
          * helper objects) expect it to have a non-null map pointer, so we
          * share an empty Enumerator scope in the runtime.
          */
         JSObject *obj = js_NewGCObject(cx);
         if (!obj)
             return false;
         obj->map = cx->runtime->emptyEnumeratorScope->hold();
-        obj->init(&js_IteratorClass.base, NULL, NULL, NullValue());
+        obj->init(&js_IteratorClass, NULL, NULL, NullValue());
         return obj;
     }
 
-    return NewBuiltinClassInstance(cx, &js_IteratorClass.base);
+    return NewBuiltinClassInstance(cx, &js_IteratorClass);
 }
 
 NativeIterator *
 NativeIterator::allocateKeyIterator(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));
@@ -605,17 +617,17 @@ GetIterator(JSContext *cx, JSObject *obj
              * The iterator object for JSITER_ENUMERATE never escapes, so we
              * don't care for the proper parent/proto to be set. This also
              * allows us to re-use a previous iterator object that was freed
              * by JSOP_ENDITER.
              */
             JSObject *pobj = obj;
             do {
                 if (!pobj->isNative() ||
-                    obj->map->ops->enumerate != js_Enumerate ||
+                    obj->getOps()->enumerate ||
                     pobj->getClass()->enumerate != JS_EnumerateStub) {
                     shapes.clear();
                     goto miss;
                 }
                 uint32 shape = pobj->shape();
                 key = (key + (key << 16)) ^ shape;
                 if (!shapes.append(shape))
                     return false;
@@ -693,17 +705,17 @@ js_ThrowStopIteration(JSContext *cx)
 }
 
 static JSBool
 iterator_next(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj;
 
     obj = ComputeThisFromVp(cx, vp);
-    if (!InstanceOf(cx, obj, &js_IteratorClass.base, vp + 2))
+    if (!InstanceOf(cx, obj, &js_IteratorClass, vp + 2))
         return false;
 
     if (!js_IteratorMore(cx, obj, vp))
         return false;
     if (!vp->toBoolean()) {
         js_ThrowStopIteration(cx);
         return false;
     }
@@ -755,45 +767,41 @@ js_ValueToIterator(JSContext *cx, uintN 
             obj = js_ValueToNonNullObject(cx, *vp);
             if (!obj)
                 return false;
         }
     }
 
     AutoObjectRooter tvr(cx, obj);
 
-    Class *clasp = obj->getClass();
-    ExtendedClass *xclasp;
-    if ((clasp->flags & JSCLASS_IS_EXTENDED) &&
-        (xclasp = (ExtendedClass *) clasp)->iteratorObject) {
-        /* Enumerate Iterator.prototype directly. */
-        if (clasp != &js_IteratorClass.base || obj->getNativeIterator()) {
-            JSObject *iterobj = xclasp->iteratorObject(cx, obj, !(flags & JSITER_FOREACH));
-            if (!iterobj)
-                return false;
-            vp->setObject(*iterobj);
-            return true;
-        }
+    /* Enumerate Iterator.prototype directly. */
+    JSIteratorOp op = obj->getClass()->ext.iteratorObject;
+    if (op && (obj->getClass() != &js_IteratorClass || obj->getNativeIterator())) {
+        JSObject *iterobj = op(cx, obj, !(flags & JSITER_FOREACH));
+        if (!iterobj)
+            return false;
+        vp->setObject(*iterobj);
+        return true;
     }
 
     return GetIterator(cx, obj, flags, vp);
 }
 
 #if JS_HAS_GENERATORS
 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);
 
     Class *clasp = obj->getClass();
-    if (clasp == &js_IteratorClass.base) {
+    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;
         }
 
         /* Cache the iterator object if possible. */
@@ -803,17 +811,17 @@ js_CloseIterator(JSContext *cx, JSObject
             ni->props_cursor = ni->props_array;
             ni->next = *hp;
             *hp = obj;
         } else {
             iterator_finalize(cx, obj);
         }
     }
 #if JS_HAS_GENERATORS
-    else if (clasp == &js_GeneratorClass.base) {
+    else if (clasp == &js_GeneratorClass) {
         return CloseGenerator(cx, obj);
     }
 #endif
     return JS_TRUE;
 }
 
 /*
  * Suppress enumeration of deleted properties. We maintain a list of all active
@@ -888,17 +896,17 @@ js_SuppressDeletedProperty(JSContext *cx
     }
     return true;
 }
 
 JSBool
 js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
 {
     /* Fast path for native iterators */
-    if (iterobj->getClass() == &js_IteratorClass.base) {
+    if (iterobj->getClass() == &js_IteratorClass) {
         /*
          * Implement next directly as all the methods of native iterator are
          * read-only and permanent.
          */
         NativeIterator *ni = iterobj->getNativeIterator();
         rval->setBoolean(ni->props_cursor < ni->props_end);
         return true;
     }
@@ -932,17 +940,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->getClass() == &js_IteratorClass.base) {
+    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();
         JS_ASSERT(ni->props_cursor < ni->props_end);
         if (ni->isKeyIter()) {
             *rval = IdToValue(*ni->currentKey());
@@ -981,24 +989,30 @@ stopiter_hasInstance(JSContext *cx, JSOb
 {
     *bp = js_ValueIsStopIteration(*v);
     return JS_TRUE;
 }
 
 Class js_StopIterationClass = {
     js_StopIteration_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration),
-    PropertyStub,     PropertyStub,
-    PropertyStub,     PropertyStub,
-    EnumerateStub,    ResolveStub,
-    ConvertStub,      NULL,
-    NULL,             NULL,
-    NULL,             NULL,
-    NULL,             stopiter_hasInstance,
-    NULL,             NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    NULL,           /* finalize    */
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    stopiter_hasInstance
 };
 
 #if JS_HAS_GENERATORS
 
 static void
 generator_finalize(JSContext *cx, JSObject *obj)
 {
     JSGenerator *gen = (JSGenerator *) obj->getPrivate();
@@ -1031,44 +1045,56 @@ generator_trace(JSTracer *trc, JSObject 
 
     JSStackFrame *fp = gen->getFloatingFrame();
     JS_ASSERT(gen->getLiveFrame() == fp);
     MarkValueRange(trc, gen->floatingStack, fp->argEnd(), "generator slots");
     js_TraceStackFrame(trc, fp);
     MarkValueRange(trc, fp->slots(), gen->savedRegs.sp, "generator slots");
 }
 
-ExtendedClass js_GeneratorClass = {
-  { js_Generator_str,
-    JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Generator) |
-    JSCLASS_IS_ANONYMOUS |
-    JSCLASS_MARK_IS_TRACE |
-    JSCLASS_IS_EXTENDED,
-    PropertyStub,     PropertyStub,    PropertyStub,    PropertyStub,
-    EnumerateStub,    ResolveStub,     ConvertStub,     generator_finalize,
-    NULL,             NULL,            NULL,            NULL,
-    NULL,             NULL,            JS_CLASS_TRACE(generator_trace), NULL },
-    NULL,             NULL,            NULL,            iterator_iterator,
-    NULL,
-    JSCLASS_NO_RESERVED_MEMBERS
+Class js_GeneratorClass = {
+    js_Generator_str,
+    JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator) |
+    JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    generator_finalize,
+    NULL,           /* reserved    */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    JS_CLASS_TRACE(generator_trace),
+    {
+        NULL,       /* equality       */
+        NULL,       /* outerObject    */
+        NULL,       /* innerObject    */
+        iterator_iterator,
+        NULL,       /* wrappedObject  */
+    }
 };
 
 /*
  * Called from the JSOP_GENERATOR case in the interpreter, with fp referring
  * to the frame by which the generator function was activated.  Create a new
  * JSGenerator object, which contains its own JSStackFrame 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, &js_GeneratorClass.base);
+    JSObject *obj = NewBuiltinClassInstance(cx, &js_GeneratorClass);
     if (!obj)
         return NULL;
 
     /* Load and compute stack slot counts. */
     JSStackFrame *fp = cx->fp;
     uintN argc = fp->argc;
     uintN nargs = JS_MAX(argc, fp->fun->nargs);
     uintN vplen = 2 + nargs;
@@ -1300,17 +1326,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->getClass() == &js_GeneratorClass.base);
+    JS_ASSERT(obj->getClass() == &js_GeneratorClass);
 
     JSGenerator *gen = (JSGenerator *) obj->getPrivate();
     if (!gen) {
         /* Generator prototype object. */
         return JS_TRUE;
     }
 
     if (gen->state == JSGEN_CLOSED)
@@ -1324,17 +1350,17 @@ CloseGenerator(JSContext *cx, JSObject *
  */
 static JSBool
 generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
 {
     JSObject *obj;
     LeaveTrace(cx);
 
     obj = ComputeThisFromVp(cx, vp);
-    if (!InstanceOf(cx, obj, &js_GeneratorClass.base, vp + 2))
+    if (!InstanceOf(cx, obj, &js_GeneratorClass, vp + 2))
         return JS_FALSE;
 
     JSGenerator *gen = (JSGenerator *) obj->getPrivate();
     if (!gen) {
         /* This happens when obj is the generator prototype. See bug 352885. */
         goto closed_generator;
     }
 
@@ -1419,24 +1445,24 @@ js_InitIteratorClasses(JSContext *cx, JS
     JSObject *proto, *stop;
 
     /* Idempotency required: we initialize several things, possibly lazily. */
     if (!js_GetClassObject(cx, obj, JSProto_StopIteration, &stop))
         return NULL;
     if (stop)
         return stop;
 
-    proto = js_InitClass(cx, obj, NULL, &js_IteratorClass.base, Iterator, 2,
+    proto = js_InitClass(cx, obj, NULL, &js_IteratorClass, Iterator, 2,
                          NULL, iterator_methods, NULL, NULL);
     if (!proto)
         return NULL;
 
 #if JS_HAS_GENERATORS
     /* Initialize the generator internals if configured. */
-    if (!js_InitClass(cx, obj, NULL, &js_GeneratorClass.base, NULL, 0,
+    if (!js_InitClass(cx, obj, NULL, &js_GeneratorClass, NULL, 0,
                       NULL, generator_methods, NULL, NULL)) {
         return NULL;
     }
 #endif
 
     return js_InitClass(cx, obj, NULL, &js_StopIterationClass, NULL, 0,
                         NULL, NULL, NULL, NULL);
 }
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -244,19 +244,19 @@ js_LiveFrameIfGenerator(JSStackFrame *fp
 {
     if (fp->flags & JSFRAME_GENERATOR)
         return js_FloatingFrameToGenerator(fp)->getLiveFrame();
     return fp;
 }
 
 #endif
 
-extern js::ExtendedClass js_GeneratorClass;
-extern js::ExtendedClass js_IteratorClass;
-extern js::Class         js_StopIterationClass;
+extern js::Class js_GeneratorClass;
+extern js::Class js_IteratorClass;
+extern js::Class js_StopIterationClass;
 
 static inline bool
 js_ValueIsStopIteration(const js::Value &v)
 {
     return v.isObject() && v.toObject().getClass() == &js_StopIterationClass;
 }
 
 extern JSObject *
--- a/js/src/jslock.h
+++ b/js/src/jslock.h
@@ -145,19 +145,17 @@ struct JSTitle {
 #define JS_UNLOCK(cx, tl)           js_Unlock(cx, tl)
 
 #define JS_LOCK_RUNTIME(rt)         js_LockRuntime(rt)
 #define JS_UNLOCK_RUNTIME(rt)       js_UnlockRuntime(rt)
 
 /*
  * NB: The JS_LOCK_OBJ and JS_UNLOCK_OBJ macros work *only* on native objects
  * (objects for which obj->isNative() returns true).  All uses of these macros in
- * the engine are predicated on obj->isNative or equivalent checks.  These uses
- * are for optimizations above the JSObjectOps layer, under which object locks
- * normally hide.
+ * the engine are predicated on obj->isNative or equivalent checks.
  */
 #define CX_OWNS_SCOPE_TITLE(cx,scope)   ((scope)->title.ownercx == (cx))
 
 #define JS_LOCK_OBJ(cx,obj)                                                   \
     JS_BEGIN_MACRO                                                            \
         JSObject *obj_ = (obj);                                               \
         if (!CX_OWNS_SCOPE_TITLE(cx, obj_->scope())) {                        \
             js_LockObj(cx, obj_);                                             \
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -92,19 +92,23 @@ static JSConstDoubleSpec math_constants[
     {M_SQRT2,   "SQRT2",        0, {0,0,0}},
     {M_SQRT1_2, "SQRT1_2",      0, {0,0,0}},
     {0,0,0,{0,0,0}}
 };
 
 Class js_MathClass = {
     js_Math_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Math),
-    PropertyStub,     PropertyStub,     PropertyStub,     PropertyStub,
-    EnumerateStub,    ResolveStub,      ConvertStub,      NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub
 };
 
 static JSBool
 math_abs(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -277,19 +277,23 @@ static JSFunctionSpec number_functions[]
     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 = {
     js_Number_str,
     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number),
-    PropertyStub,     PropertyStub,     PropertyStub,     PropertyStub,
-    EnumerateStub,    ResolveStub,      ConvertStub,      NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub
 };
 
 static JSBool
 Number(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
 {
     if (argc != 0) {
         if (!ValueToNumber(cx, &argv[0]))
             return JS_FALSE;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -97,40 +97,37 @@
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "jsautooplen.h"
 
 using namespace js;
 
-JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
-    NULL,
-    js_LookupProperty,
-    js_DefineProperty,
-    js_GetProperty,
-    js_SetProperty,
-    js_GetAttributes,
-    js_SetAttributes,
-    js_DeleteProperty,
-    js_Enumerate,
-    js_TypeOf,
-    js_TraceObject,
-    NULL,   /* thisObject */
-    js_Clear
-};
+JS_FRIEND_DATA(const JSObjectMap) JSObjectMap::sharedNonNative(JSObjectMap::SHAPELESS);
 
 Class js_ObjectClass = {
     js_Object_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
-    PropertyStub,     PropertyStub,     PropertyStub,     PropertyStub,
-    EnumerateStub,    ResolveStub,      ConvertStub,      NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub
 };
 
+JS_FRIEND_API(JSObject *)
+js_ObjectToOuterObject(JSContext *cx, JSObject *obj)
+{
+    OBJ_TO_OUTER_OBJECT(cx, obj);
+    return obj;
+}
+
 #if JS_HAS_OBJ_PROTO_PROP
 
 static JSBool
 obj_getProto(JSContext *cx, JSObject *obj, jsid id, Value *vp);
 
 static JSBool
 obj_setProto(JSContext *cx, JSObject *obj, jsid id, Value *vp);
 
@@ -912,40 +909,31 @@ js_CheckPrincipalsAccess(JSContext *cx, 
         }
     }
     return JS_TRUE;
 }
 
 JSObject *
 js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller)
 {
-    Class *clasp;
-    JSExtendedClass *xclasp;
     JSObject *inner;
 
     if (!scopeobj)
         goto bad;
 
     OBJ_TO_INNER_OBJECT(cx, scopeobj);
     if (!scopeobj)
         return NULL;
 
+    /* XXX This is an awful gross hack. */
     inner = scopeobj;
-
-    /* XXX This is an awful gross hack. */
     while (scopeobj) {
-        clasp = scopeobj->getClass();
-        if (clasp->flags & JSCLASS_IS_EXTENDED) {
-            xclasp = (JSExtendedClass*)clasp;
-            if (xclasp->innerObject &&
-                xclasp->innerObject(cx, scopeobj) != scopeobj) {
-                goto bad;
-            }
-        }
-
+        JSObjectOp op = scopeobj->getClass()->ext.innerObject;
+        if (op && op(cx, scopeobj) != scopeobj)
+            goto bad;
         scopeobj = scopeobj->getParent();
     }
 
     return inner;
 
 bad:
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_BAD_INDIRECT_CALL, caller);
@@ -1362,17 +1350,17 @@ obj_unwatch(JSContext *cx, uintN argc, V
  */
 
 /* Proposed ECMA 15.2.4.5. */
 static JSBool
 obj_hasOwnProperty(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ComputeThisFromVp(cx, vp);
     return obj &&
-           js_HasOwnPropertyHelper(cx, obj->map->ops->lookupProperty, argc, vp);
+           js_HasOwnPropertyHelper(cx, obj->getOps()->lookupProperty, argc, vp);
 }
 
 JSBool
 js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc,
                         Value *vp)
 {
     jsid id;
     if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id))
@@ -1401,32 +1389,28 @@ js_HasOwnPropertyHelper(JSContext *cx, J
     return JS_TRUE;
 }
 
 JSBool
 js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id,
                   JSObject **objp, JSProperty **propp)
 {
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING);
-    if (!lookup(cx, obj, id, objp, propp))
+    if (!(lookup ? lookup : js_LookupProperty)(cx, obj, id, objp, propp))
         return false;
     if (!*propp)
         return true;
 
     if (*objp == obj)
         return true;
 
-    JSExtendedClass *xclasp;
-    JSObject *outer;
     Class *clasp = (*objp)->getClass();
-    if (!(clasp->flags & JSCLASS_IS_EXTENDED) ||
-        !(xclasp = (JSExtendedClass *) clasp)->outerObject) {
-        outer = NULL;
-    } else {
-        outer = xclasp->outerObject(cx, *objp);
+    JSObject *outer = NULL;
+    if (JSObjectOp op = (*objp)->getClass()->ext.outerObject) {
+        outer = op(cx, *objp);
         if (!outer)
             return false;
     }
 
     if (outer != *objp) {
         if ((*objp)->isNative() && obj->getClass() == clasp) {
             /*
              * The combination of JSPROP_SHARED and JSPROP_PERMANENT in a
@@ -1702,17 +1686,17 @@ js_GetOwnPropertyDescriptor(JSContext *c
 {
     if (obj->isProxy()) {
         if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, vp))
             return false;
     }
 
     JSObject *pobj;
     JSProperty *prop;
-    if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &pobj, &prop))
+    if (!js_HasOwnProperty(cx, obj->getOps()->lookupProperty, obj, id, &pobj, &prop))
         return false;
     if (!prop) {
         vp->setUndefined();
         return true;
     }
 
     Value roots[] = { UndefinedValue(), UndefinedValue(), UndefinedValue() };
     AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots);
@@ -1978,32 +1962,32 @@ Reject(JSContext *cx, JSObject *obj, JSP
 
 static JSBool
 DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
                        bool throwError, bool *rval)
 {
     /* 8.12.9 step 1. */
     JSProperty *current;
     JSObject *obj2;
-    JS_ASSERT(obj->map->ops->lookupProperty == js_LookupProperty);
-    if (!js_HasOwnProperty(cx, js_LookupProperty, obj, desc.id, &obj2, &current))
+    JS_ASSERT(!obj->getOps()->lookupProperty);
+    if (!js_HasOwnProperty(cx, NULL, obj, desc.id, &obj2, &current))
         return JS_FALSE;
 
-    JS_ASSERT(obj->map->ops->defineProperty == js_DefineProperty);
+    JS_ASSERT(!obj->getOps()->defineProperty);
 
     /* 8.12.9 steps 2-4. */
     JSScope *scope = obj->scope();
     if (!current) {
         if (scope->sealed())
             return Reject(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
 
         *rval = true;
 
         if (desc.isGenericDescriptor() || desc.isDataDescriptor()) {
-            JS_ASSERT(obj->map->ops->defineProperty == js_DefineProperty);
+            JS_ASSERT(!obj->getOps()->defineProperty);
             return js_DefineProperty(cx, obj, desc.id, &desc.value,
                                      PropertyStub, PropertyStub, desc.attrs);
         }
 
         JS_ASSERT(desc.isAccessorDescriptor());
 
         /*
          * Getters and setters are just like watchpoints from an access
@@ -2298,17 +2282,17 @@ DefinePropertyOnArray(JSContext *cx, JSO
 
 static JSBool
 DefineProperty(JSContext *cx, JSObject *obj, const PropDesc &desc, bool throwError,
                bool *rval)
 {
     if (obj->isArray())
         return DefinePropertyOnArray(cx, obj, desc, throwError, rval);
 
-    if (obj->map->ops->lookupProperty != js_LookupProperty) {
+    if (obj->getOps()->lookupProperty) {
         if (obj->isProxy())
             return JSProxy::defineProperty(cx, obj, desc.id, desc.pd);
         return Reject(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
     }
 
     return DefinePropertyOnObject(cx, obj, desc, throwError, rval);
 }
 
@@ -2579,18 +2563,17 @@ js_Object(JSContext *cx, JSObject *obj, 
 }
 
 #ifdef JS_TRACER
 
 JSObject*
 js_NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto,
                            const Value &privateSlotValue)
 {
-    JS_ASSERT(!clasp->getObjectOps);
-    JS_ASSERT(proto->map->ops == &js_ObjectOps);
+    JS_ASSERT(clasp->isNative());
 
     JSObject* obj = js_NewGCObject(cx);
     if (!obj)
         return NULL;
 
     obj->initSharingEmptyScope(clasp, proto, proto->getParent(), privateSlotValue);
     return obj;
 }
@@ -2861,45 +2844,49 @@ with_TypeOf(JSContext *cx, JSObject *obj
 }
 
 static JSObject *
 with_ThisObject(JSContext *cx, JSObject *obj)
 {
     return obj->getWithThis();
 }
 
-JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
-    NULL,
-    with_LookupProperty,
-    js_DefineProperty,
-    with_GetProperty,
-    with_SetProperty,
-    with_GetAttributes,
-    with_SetAttributes,
-    with_DeleteProperty,
-    with_Enumerate,
-    with_TypeOf,
-    js_TraceObject,
-    with_ThisObject,
-    js_Clear
-};
-
-static JSObjectOps *
-with_getObjectOps(JSContext *cx, Class *clasp)
-{
-    return &js_WithObjectOps;
-}
-
 Class js_WithClass = {
     "With",
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
-    PropertyStub,     PropertyStub,     PropertyStub,     PropertyStub,
-    EnumerateStub,    ResolveStub,      ConvertStub,      NULL,
-    with_getObjectOps,
-    0,0,0,0,0,0,0
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    NULL,           /* finalize */
+    NULL,           /* reserved    */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    NULL,           /* mark        */
+    JS_NULL_CLASS_EXT,
+    {
+        with_LookupProperty,
+        NULL,       /* defineProperty */
+        with_GetProperty,
+        with_SetProperty,
+        with_GetAttributes,
+        with_SetAttributes,
+        with_DeleteProperty,
+        with_Enumerate,
+        with_TypeOf,
+        NULL,       /* trace          */
+        with_ThisObject,
+        NULL,       /* clear          */
+    }
 };
 
 JS_REQUIRES_STACK JSObject *
 js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
 {
     JSObject *obj;
 
     obj = js_NewGCObject(cx);
@@ -3236,19 +3223,23 @@ js_XDRBlockObject(JSXDRState *xdr, JSObj
     return true;
 }
 
 #endif
 
 Class js_BlockClass = {
     "Block",
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS,
-    PropertyStub,     PropertyStub,     PropertyStub,      PropertyStub,
-    EnumerateStub,    ResolveStub,      ConvertStub,       NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub
 };
 
 JSObject *
 js_InitObjectClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto = js_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1,
                                    object_props, object_methods, NULL, object_static_methods);
     if (!proto)
@@ -4467,17 +4458,17 @@ js_FindPropertyHelper(JSContext *cx, jsi
 
     /* Scan entries on the scope chain that we can cache across. */
     entry = JS_NO_PROP_CACHE_FILL;
     obj = scopeChain;
     parent = obj->getParent();
     for (scopeIndex = 0;
          parent
          ? js_IsCacheableNonGlobalScope(obj)
-         : obj->map->ops->lookupProperty == js_LookupProperty;
+         : !obj->getOps()->lookupProperty;
          ++scopeIndex) {
         protoIndex =
             js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
                                        &pobj, &prop);
         if (protoIndex < 0)
             return NULL;
 
         if (prop) {
@@ -4848,26 +4839,29 @@ js_GetProperty(JSContext *cx, JSObject *
     return js_GetPropertyHelper(cx, obj, id, JSGET_METHOD_BARRIER, vp);
 }
 
 JSBool
 js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, Value *vp)
 {
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
-    if (obj->map->ops == &js_ObjectOps ||
-        obj->map->ops->getProperty == js_GetProperty) {
+    PropertyIdOp op = obj->getOps()->getProperty;
+    if (!op) {
+#if JS_HAS_XML_SUPPORT
+        JS_ASSERT(!obj->isXML());
+#endif
         return js_GetPropertyHelper(cx, obj, id, getHow, vp);
     }
     JS_ASSERT_IF(getHow & JSGET_CACHE_RESULT, obj->isDenseArray());
 #if JS_HAS_XML_SUPPORT
     if (obj->isXML())
         return js_GetXMLMethod(cx, obj, id, vp);
 #endif
-    return obj->getProperty(cx, id, vp);
+    return op(cx, obj, id, vp);
 }
 
 JS_FRIEND_API(bool)
 js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
 {
     JSStackFrame *const fp = js_GetTopStackFrame(cx);
     if (!fp)
         return true;
@@ -5377,17 +5371,17 @@ DefaultValue(JSContext *cx, JSObject *ob
         return JS_FALSE;
     }
     *vp = v;
     return JS_TRUE;
 }
 
 } /* namespace js */
 
-JSBool
+JS_FRIEND_API(JSBool)
 js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, Value *statep, jsid *idp)
 {
     /* If the class has a custom JSCLASS_NEW_ENUMERATE hook, call it. */
     Class *clasp = obj->getClass();
     JSEnumerateOp enumerate = clasp->enumerate;
     if (clasp->flags & JSCLASS_NEW_ENUMERATE) {
         JS_ASSERT(enumerate != JS_EnumerateStub);
         return ((NewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp);
@@ -5931,18 +5925,16 @@ js_TraceObject(JSTracer *trc, JSObject *
         else if (IS_GC_MARKING_TRACER(trc))
             (void) clasp->mark(cx, obj, trc);
     }
     if (clasp->flags & JSCLASS_IS_GLOBAL) {
         JSCompartment *compartment = obj->getCompartment(cx);
         compartment->marked = true;
     }
 
-    obj->traceProtoAndParent(trc);
-
     /*
      * An unmutated object that shares a prototype object's scope. We can't
      * tell how many slots are in use in obj by looking at its scope, so we
      * use obj->numSlots().
      *
      * NB: In case clasp->mark mutates something, leave this code here --
      * don't move it up and unify it with the |if (!traceScope)| section
      * above.
@@ -5955,17 +5947,17 @@ js_TraceObject(JSTracer *trc, JSObject *
     for (uint32 i = JSSLOT_START(clasp); i != nslots; ++i) {
         const Value &v = obj->getSlot(i);
         JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i);
         MarkValueRaw(trc, v);
     }
 }
 
 void
-js_Clear(JSContext *cx, JSObject *obj)
+js_ClearNative(JSContext *cx, JSObject *obj)
 {
     JSScope *scope;
     uint32 i, n;
 
     /*
      * Clear our scope and the property cache of all obj's properties only if
      * obj owns the scope (i.e., not if obj is sharing another object's scope).
      * NB: we do not clear any reserved slots lying below JSSLOT_FREE(clasp).
@@ -6044,22 +6036,19 @@ js_SetReservedSlot(JSContext *cx, JSObje
     GC_POKE(cx, JS_NULL);
     JS_UNLOCK_SCOPE(cx, scope);
     return true;
 }
 
 JSObject *
 JSObject::wrappedObject(JSContext *cx) const
 {
-    Class *clasp = getClass();
-    if (clasp->flags & JSCLASS_IS_EXTENDED) {
-        if (JSObjectOp wrappedObject = reinterpret_cast<JSExtendedClass *>(clasp)->wrappedObject) {
-            if (JSObject *obj = wrappedObject(cx, const_cast<JSObject *>(this)))
-                return obj;
-        }
+    if (JSObjectOp op = getClass()->ext.wrappedObject) {
+        if (JSObject *obj = op(cx, const_cast<JSObject *>(this)))
+            return obj;
     }
     return const_cast<JSObject *>(this);
 }
 
 JSObject *
 JSObject::getGlobal()
 {
     JSObject *obj = this;
@@ -6085,17 +6074,17 @@ JSObject::getCompartment(JSContext *cx)
 
     Class *clasp = obj->getClass();
     if (!(clasp->flags & JSCLASS_IS_GLOBAL)) {
         // The magic AnyName object is runtime-wide.
         if (clasp == &js_AnyNameClass)
             return cx->runtime->defaultCompartment;
 
         // The magic function namespace object is runtime-wide.
-        if (clasp == &js_NamespaceClass.base &&
+        if (clasp == &js_NamespaceClass &&
             obj->getNameURI() == ATOM_TO_JSVAL(cx->runtime->atomState.lazy.functionNamespaceURIAtom)) {
             return cx->runtime->defaultCompartment;
         }
 
         // Compile-time Function, Block, and RegExp objects are not parented.
         if (clasp == &js_FunctionClass || clasp == &js_BlockClass || clasp == &js_RegExpClass) {
             // This is a bogus answer, but it'll do for now.
             return cx->runtime->defaultCompartment;
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -165,112 +165,99 @@ struct PropDesc {
     bool hasEnumerable : 1;
     bool hasConfigurable : 1;
 };
 
 namespace js {
 
 typedef Vector<PropDesc, 1> PropDescArray;
 
-/*
- * Flag and type-safe cast helper to denote that Class::call is a fast native.
- */
-const uint32 CLASS_CALL_IS_FAST = uint32(1) << (JSCLASS_LAST_API_FLAG_SHIFT + 1);
-
-inline Native CastCallOpAsNative(CallOp op)
-{
-    return reinterpret_cast<Native>(op);
-}
-
 } /* namespace js */
 
-/* For detailed comments on these function pointer types, see jsprvtd.h. */
-struct JSObjectOps {
-    /*
-     * Custom shared object map for non-native objects. For native objects
-     * this should be null indicating, that JSObject.map is an instance of
-     * JSScope.
-     */
-    const JSObjectMap   *objectMap;
-
-    /* Mandatory non-null function pointer members. */
-    JSLookupPropOp      lookupProperty;
-    js::DefinePropOp    defineProperty;
-    js::PropertyIdOp    getProperty;
-    js::PropertyIdOp    setProperty;
-    JSAttributesOp      getAttributes;
-    JSAttributesOp      setAttributes;
-    js::PropertyIdOp    deleteProperty;
-    js::NewEnumerateOp  enumerate;
-    JSTypeOfOp          typeOf;
-    JSTraceOp           trace;
+struct JSObjectMap {
+    static JS_FRIEND_DATA(const JSObjectMap) sharedNonNative;
 
-    /* Optionally non-null members start here. */
-    JSObjectOp          thisObject;
-    JSFinalizeOp        clear;
-
-    bool inline isNative() const;
-};
-
-extern JS_FRIEND_DATA(JSObjectOps) js_ObjectOps;
-extern JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps;
-
-/*
- * Test whether the ops is native. FIXME bug 492938: consider how it would
- * affect the performance to do just the !objectMap check.
- */
-inline bool
-JSObjectOps::isNative() const
-{
-    return JS_LIKELY(this == &js_ObjectOps) || !objectMap;
-}
-
-struct JSObjectMap {
-    const JSObjectOps * const   ops;    /* high level object operation vtable */
     uint32                      shape;  /* shape identifier */
 
-    explicit JSObjectMap(const JSObjectOps *ops, uint32 shape) : ops(ops), shape(shape) {}
+    explicit JSObjectMap(uint32 shape) : shape(shape) {}
 
     enum { INVALID_SHAPE = 0x8fffffff, SHAPELESS = 0xffffffff };
 
-private:
+    bool isNative() const { return this != &sharedNonNative; }
+
+  private:
     /* No copy or assignment semantics. */
     JSObjectMap(JSObjectMap &);
     void operator=(JSObjectMap &);
 };
 
+/*
+ * Unlike js_DefineNativeProperty, propp must be non-null. On success, and if
+ * id was found, return true with *objp non-null and locked, and with a held
+ * property stored in *propp. If successful but id was not found, return true
+ * with both *objp and *propp null. Therefore all callers who receive a
+ * non-null *propp must later call (*objp)->dropProperty(cx, *propp).
+ */
+extern JS_FRIEND_API(JSBool)
+js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
+                  JSProperty **propp);
+
+extern JSBool
+js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value *value,
+                  js::PropertyOp getter, js::PropertyOp setter, uintN attrs);
+
+extern JSBool
+js_GetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
+
+extern JSBool
+js_SetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
+
+extern JSBool
+js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
+
+extern JSBool
+js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
+
+extern JSBool
+js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *rval);
+
+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);
+
 struct NativeIterator;
 
-const uint32 JS_INITIAL_NSLOTS = 4;
-
-const uint32 JSSLOT_PARENT  = 0;
+const uint32 JS_INITIAL_NSLOTS = 3;
 
 /*
  * The first available slot to store generic value. For JSCLASS_HAS_PRIVATE
  * classes the slot stores a pointer to private data stuffed in a Value.
  * Such pointer is stored as is without an overhead of PRIVATE_TO_JSVAL
  * tagging and should be accessed using the (get|set)Private methods of
  * JSObject.
  */
-const uint32 JSSLOT_PRIVATE = 1;
+const uint32 JSSLOT_PRIVATE = 0;
 
 struct JSFunction;
 
 /*
  * 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.
  *
- * An object is a delegate if it is on another object's prototype (linked by
- * JSSLOT_PROTO) or scope (JSSLOT_PARENT) chain, and therefore the delegate
- * might be asked implicitly to get or set a property on behalf of another
- * object. Delegates may be accessed directly too, as may any object, but only
- * those objects linked after the head of any prototype or scope chain are
- * flagged as delegates. This definition helps to optimize shape-based property
- * cache invalidation (see Purge{Scope,Proto}Chain in jsobj.cpp).
+ * An object is a delegate if it is on another object's prototype (the proto
+ * field) or scope chain (the parent field), and therefore the delegate might
+ * be asked implicitly to get or set a property on behalf of another object.
+ * Delegates may be accessed directly too, as may any object, but only those
+ * objects linked after the head of any prototype or scope chain are flagged
+ * as delegates. This definition helps to optimize shape-based property cache
+ * invalidation (see Purge{Scope,Proto}Chain in jsobj.cpp).
  *
  * The meaning of the system object bit is defined by the API client. It is
  * set in JS_NewSystemObject and is queried by JS_IsSystemObject (jsdbgapi.h),
  * but it has no intrinsic meaning to SpiderMonkey. Further, JSFILENAME_SYSTEM
  * and JS_FlagScriptFilenamePrefix (also exported via jsdbgapi.h) are intended
  * to be complementary to this bit, but it is up to the API client to implement
  * any such association.
  *
@@ -287,40 +274,40 @@ struct JSObject {
      * manipulates JSObjects, which requires peeking under any encapsulation.
      */
     friend class js::TraceRecorder;
 
     JSObjectMap *map;                       /* property map, see jsscope.h */
     js::Class   *clasp;                     /* class pointer */
     jsuword     flags;                      /* see above */
     JSObject    *proto;                     /* object's prototype */
+    JSObject    *parent;                    /* object's parent */
     js::Value   *dslots;                    /* dynamically allocated slots */
-#if JS_BITS_PER_WORD == 32
-    // TODO: this is needed to pad out fslots. alternatively, clasp could be
-    // merged with flags and the padding removed, but I think the upcoming
-    // removal of JSScope will change this all anyway so I will leave this
-    // here for now.
-    uint32      padding;
-#endif
     js::Value   fslots[JS_INITIAL_NSLOTS];  /* small number of fixed slots */
 
-    bool isNative() const { return map->ops->isNative(); }
+    bool isNative() const {
+        return map->isNative();
+    }
 
     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 {
+        return &getClass()->ops;
+    }
+
     inline JSScope *scope() const;
     inline uint32 shape() const;
 
     bool isDelegate() const {
         return (flags & jsuword(1)) != jsuword(0);
     }
 
     void setDelegate() {
@@ -410,37 +397,30 @@ struct JSObject {
         for (JSObject *obj = newProto; obj; obj = obj->getProto())
             JS_ASSERT(obj != this);
 #endif
         setDelegateNullSafe(newProto);
         proto = newProto;
     }
 
     JSObject *getParent() const {
-        return fslots[JSSLOT_PARENT].toObjectOrNull();
+        return parent;
     }
 
     void clearParent() {
-        fslots[JSSLOT_PARENT].setNull();
+        parent = NULL;
     }
 
     void setParent(JSObject *newParent) {
 #ifdef DEBUG
         for (JSObject *obj = newParent; obj; obj = obj->getParent())
             JS_ASSERT(obj != this);
 #endif
         setDelegateNullSafe(newParent);
-        fslots[JSSLOT_PARENT].setObjectOrNull(newParent);
-    }
-
-    void traceProtoAndParent(JSTracer *trc) const {
-        if (JSObject *proto = getProto())
-            JS_CALL_OBJECT_TRACER(trc, proto, "__proto__");
-        if (JSObject *parent = getParent())
-            JS_CALL_OBJECT_TRACER(trc, parent, "parent");
+        parent = newParent;
     }
 
     JSObject *getGlobal();
 
     void *getPrivate() const {
         JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
         void *priv = fslots[JSSLOT_PRIVATE].toPrivate();
         return priv;
@@ -681,63 +661,72 @@ struct JSObject {
                                       JSObject *parent,
                                       const js::Value &privateSlotValue);
 
     inline bool hasSlotsArray() const { return !!dslots; }
 
     /* This method can only be called when hasSlotsArray() returns true. */
     inline void freeSlotsArray(JSContext *cx);
 
-    JSBool lookupProperty(JSContext *cx, jsid id,
-                          JSObject **objp, JSProperty **propp) {
-        return map->ops->lookupProperty(cx, this, id, objp, propp);
+    JSBool lookupProperty(JSContext *cx, jsid id, JSObject **objp, JSProperty **propp) {
+        JSLookupPropOp op = getOps()->lookupProperty;
+        return (op ? op : js_LookupProperty)(cx, this, id, objp, propp);
     }
 
     JSBool defineProperty(JSContext *cx, jsid id, const js::Value &value,
                           js::PropertyOp getter = js::PropertyStub,
                           js::PropertyOp setter = js::PropertyStub,
                           uintN attrs = JSPROP_ENUMERATE) {
-        return map->ops->defineProperty(cx, this, id, &value, getter, setter, attrs);
+        js::DefinePropOp op = getOps()->defineProperty;
+        return (op ? op : js_DefineProperty)(cx, this, id, &value, getter, setter, attrs);
     }
 
     JSBool getProperty(JSContext *cx, jsid id, js::Value *vp) {
-        return map->ops->getProperty(cx, this, id, vp);
+        js::PropertyIdOp op = getOps()->getProperty;
+        return (op ? op : js_GetProperty)(cx, this, id, vp);
     }
 
     JSBool setProperty(JSContext *cx, jsid id, js::Value *vp) {
-        return map->ops->setProperty(cx, this, id, vp);
+        js::PropertyIdOp op = getOps()->setProperty;
+        return (op ? op : js_SetProperty)(cx, this, id, vp);
     }
 
     JSBool getAttributes(JSContext *cx, jsid id, uintN *attrsp) {
-        return map->ops->getAttributes(cx, this, id, attrsp);
+        JSAttributesOp op = getOps()->getAttributes;
+        return (op ? op : js_GetAttributes)(cx, this, id, attrsp);
     }
 
     JSBool setAttributes(JSContext *cx, jsid id, uintN *attrsp) {
-        return map->ops->setAttributes(cx, this, id, attrsp);
+        JSAttributesOp op = getOps()->setAttributes;
+        return (op ? op : js_SetAttributes)(cx, this, id, attrsp);
     }
 
     JSBool deleteProperty(JSContext *cx, jsid id, js::Value *rval) {
-        return map->ops->deleteProperty(cx, this, id, rval);
+        js::PropertyIdOp op = getOps()->deleteProperty;
+        return (op ? op : js_DeleteProperty)(cx, this, id, rval);
     }
 
-    JSBool enumerate(JSContext *cx, JSIterateOp op, js::Value *statep,
-                     jsid *idp) {
-        return map->ops->enumerate(cx, this, op, statep, idp);
+    JSBool enumerate(JSContext *cx, JSIterateOp iterop, js::Value *statep, jsid *idp) {
+        js::NewEnumerateOp op = getOps()->enumerate;
+        return (op ? op : js_Enumerate)(cx, this, iterop, statep, idp);
     }
 
     JSType typeOf(JSContext *cx) {
-        return map->ops->typeOf(cx, this);
+        JSTypeOfOp op = getOps()->typeOf;
+        return (op ? op : js_TypeOf)(cx, this);
     }
 
     JSObject *wrappedObject(JSContext *cx) const;
 
     /* These four are time-optimized to avoid stub calls. */
     JSObject *thisObject(JSContext *cx) {
-        return map->ops->thisObject ? map->ops->thisObject(cx, this) : this;
+        JSObjectOp op = getOps()->thisObject;
+        return op ? op(cx, this) : this;
     }
+
     static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp);
 
     inline void dropProperty(JSContext *cx, JSProperty *prop);
 
     JS_FRIEND_API(JSCompartment *) getCompartment(JSContext *cx);
 
     void swap(JSObject *obj);
 
@@ -808,37 +797,29 @@ JS_STATIC_ASSERT(sizeof(JSObject) % JS_G
 #define CX_THREAD_IS_RUNNING_GC(cx)                                           \
     THREAD_IS_RUNNING_GC((cx)->runtime, (cx)->thread)
 
 #endif /* JS_THREADSAFE */
 
 inline void
 OBJ_TO_INNER_OBJECT(JSContext *cx, JSObject *&obj)
 {
-    js::Class *clasp = obj->getClass();
-    if (clasp->flags & JSCLASS_IS_EXTENDED) {
-        js::ExtendedClass *xclasp = (js::ExtendedClass *) clasp;
-        if (xclasp->innerObject)
-            obj = xclasp->innerObject(cx, obj);
-    }
+    if (JSObjectOp op = obj->getClass()->ext.innerObject)
+        obj = op(cx, obj);
 }
 
 /*
  * The following function has been copied to jsd/jsd_val.c. If making changes to
  * OBJ_TO_OUTER_OBJECT, please update jsd/jsd_val.c as well.
  */
 inline void
 OBJ_TO_OUTER_OBJECT(JSContext *cx, JSObject *&obj)
 {
-    js::Class *clasp = obj->getClass();
-    if (clasp->flags & JSCLASS_IS_EXTENDED) {
-        js::ExtendedClass *xclasp = (js::ExtendedClass *) clasp;
-        if (xclasp->outerObject)
-            obj = xclasp->outerObject(cx, obj);
-    }
+    if (JSObjectOp op = obj->getClass()->ext.outerObject)
+        obj = op(cx, obj);
 }
 
 class JSValueArray {
   public:
     jsval *array;
     size_t length;
 
     JSValueArray(jsval *v, size_t c) : array(v), length(c) {}
@@ -1070,24 +1051,22 @@ js_CheckForStringIndex(jsid id);
  * js_PurgeScopeChain does nothing if obj is not itself a prototype or parent
  * scope, else it reshapes the scope and prototype chains it links. It calls
  * js_PurgeScopeChainHelper, which asserts that obj is flagged as a delegate
  * (i.e., obj has ever been on a prototype or parent chain).
  */
 extern void
 js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id);
 
-#ifdef __cplusplus /* Aargh, libgjs, bug 492720. */
-static JS_INLINE void
+inline void
 js_PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id)
 {
     if (obj->isDelegate())
         js_PurgeScopeChainHelper(cx, obj, id);
 }
-#endif
 
 /*
  * Find or create a property named by id in obj's scope, with the given getter
  * and setter, slot, attributes, and other members.
  */
 extern JSScopeProperty *
 js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
                      js::PropertyOp getter, js::PropertyOp setter, uint32 slot,
@@ -1099,20 +1078,16 @@ js_AddNativeProperty(JSContext *cx, JSOb
  * or identical property.
  */
 extern JSScopeProperty *
 js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
                              JSScopeProperty *sprop, uintN attrs, uintN mask,
                              js::PropertyOp getter, js::PropertyOp setter);
 
 extern JSBool
-js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value *value,
-                  js::PropertyOp getter, js::PropertyOp setter, uintN attrs);
-
-extern JSBool
 js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id,
                      const js::Value &descriptor, JSBool *bp);
 
 /*
  * Flags for the defineHow parameter of js_DefineNativeProperty.
  */
 const uintN JSDNP_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */
 const uintN JSDNP_DONT_PURGE   = 2; /* suppress js_PurgeScopeChain */
@@ -1132,54 +1107,43 @@ const uintN JSDNP_UNQUALIFIED  = 8; /* U
  */
 extern JSBool
 js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value &value,
                         js::PropertyOp getter, js::PropertyOp setter, uintN attrs,
                         uintN flags, intN shortid, JSProperty **propp,
                         uintN defineHow = 0);
 
 /*
- * Unlike js_DefineNativeProperty, propp must be non-null. On success, and if
- * id was found, return true with *objp non-null and locked, and with a held
- * property stored in *propp. If successful but id was not found, return true
- * with both *objp and *propp null. Therefore all callers who receive a
- * non-null *propp must later call (*objp)->dropProperty(cx, *propp).
- */
-extern JS_FRIEND_API(JSBool)
-js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
-                  JSProperty **propp);
-
-/*
  * Specialized subroutine that allows caller to preset JSRESOLVE_* flags and
  * returns the index along the prototype chain in which *propp was found, or
  * the last index if not found, or -1 on error.
  */
 extern int
 js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
                            JSObject **objp, JSProperty **propp);
 
 
 /*
  * We cache name lookup results only for the global object or for native
  * non-global objects without prototype or with prototype that never mutates,
  * see bug 462734 and bug 487039.
  */
-static inline bool
+inline bool
 js_IsCacheableNonGlobalScope(JSObject *obj)
 {
     extern JS_FRIEND_DATA(js::Class) js_CallClass;
     extern JS_FRIEND_DATA(js::Class) js_DeclEnvClass;
     JS_ASSERT(obj->getParent());
 
     js::Class *clasp = obj->getClass();
     bool cacheable = (clasp == &js_CallClass ||
                       clasp == &js_BlockClass ||
                       clasp == &js_DeclEnvClass);
 
-    JS_ASSERT_IF(cacheable, obj->map->ops->lookupProperty == js_LookupProperty);
+    JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
     return cacheable;
 }
 
 /*
  * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success.
  */
 extern js::PropertyCacheEntry *
 js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
@@ -1230,19 +1194,16 @@ extern JSBool
 js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added,
              js::Value *vp);
 
 extern JSBool
 js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
                      js::Value *vp);
 
 extern JSBool
-js_GetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
-
-extern JSBool
 js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
 
 extern JSBool
 js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, js::Value *vp);
 
 /*
  * Check whether it is OK to assign an undeclared property with name
  * propname of the global object in the current script on cx.  Reports
@@ -1251,57 +1212,34 @@ js_GetMethod(JSContext *cx, JSObject *ob
  */
 extern JS_FRIEND_API(bool)
 js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname);
 
 extern JSBool
 js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
                      js::Value *vp);
 
-extern JSBool
-js_SetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
-
-extern JSBool
-js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
-
-extern JSBool
-js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
-
 /*
  * Change attributes for the given native property. The caller must ensure
  * that obj is locked and this function always unlocks obj on return.
  */
 extern JSBool
 js_SetNativeAttributes(JSContext *cx, JSObject *obj, JSScopeProperty *sprop,
                        uintN attrs);
 
-extern JSBool
-js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *rval);
-
 namespace js {
 
 extern JSBool
 DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp);
 
-}
-
-extern JSBool
-js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
-             js::Value *statep, jsid *idp);
-
-namespace js {
-
 extern JSBool
 CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
             js::Value *vp, uintN *attrsp);
 
-}
-
-extern JSType
-js_TypeOf(JSContext *cx, JSObject *obj);
+} /* namespace js */
 
 extern bool
 js_IsDelegate(JSContext *cx, JSObject *obj, const js::Value &v);
 
 /*
  * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
  * JSProto_Null, clasp must non-null.
  */
@@ -1346,17 +1284,17 @@ js_XDRObject(JSXDRState *xdr, JSObject *
 
 extern void
 js_TraceObject(JSTracer *trc, JSObject *obj);
 
 extern void
 js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize);
 
 extern void
-js_Clear(JSContext *cx, JSObject *obj);
+js_ClearNative(JSContext *cx, JSObject *obj);
 
 extern bool
 js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, js::Value *vp);
 
 extern bool
 js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, const js::Value &v);
 
 /*
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -488,41 +488,41 @@ class AutoPropertyDescriptorRooter : pri
         setter = desc->setter;
         value = desc->value;
     }
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 };
 
 static inline bool
-InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto, JSObjectOps* ops)
+InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto)
 {
-    JS_ASSERT(ops->isNative());
+    JS_ASSERT(clasp->isNative());
     JS_ASSERT(proto == obj->getProto());
 
     /* Share proto's emptyScope only if obj is similar to proto. */
     JSScope *scope = NULL;
 
     if (proto && proto->isNative()) {
         JS_LOCK_OBJ(cx, proto);
         scope = proto->scope();
-        if (scope->canProvideEmptyScope(ops, clasp)) {
+        if (scope->canProvideEmptyScope(clasp)) {
             JSScope *emptyScope = scope->getEmptyScope(cx, clasp);
             JS_UNLOCK_SCOPE(cx, scope);
             if (!emptyScope)
                 goto bad;
             scope = emptyScope;
         } else {
             JS_UNLOCK_SCOPE(cx, scope);
             scope = NULL;
         }
     }
 
     if (!scope) {
-        scope = JSScope::create(cx, ops, clasp, obj, js_GenerateShape(cx, false));
+        scope = JSScope::create(cx, clasp, obj, js_GenerateShape(cx, false));
         if (!scope)
             goto bad;
         uint32 freeslot = JSSLOT_FREE(clasp);
         JS_ASSERT(freeslot >= scope->freeslot);
         if (freeslot > JS_INITIAL_NSLOTS && !obj->allocSlots(cx, freeslot))
             goto bad;
         scope->freeslot = freeslot;
 #ifdef DEBUG
@@ -565,17 +565,17 @@ NewNativeClassInstance(JSContext *cx, Cl
         /*
          * Default parent to the parent of the prototype, which was set from
          * the parent of the prototype's constructor.
          */
         obj->init(clasp, proto, parent, JSObject::defaultPrivate(clasp));
 
         JS_LOCK_OBJ(cx, proto);
         JSScope *scope = proto->scope();
-        JS_ASSERT(scope->canProvideEmptyScope(&js_ObjectOps, clasp));
+        JS_ASSERT(scope->canProvideEmptyScope(clasp));
         scope = scope->getEmptyScope(cx, clasp);
         JS_UNLOCK_OBJ(cx, proto);
 
         if (!scope) {
             obj = NULL;
         } else {
             obj->map = scope;
         }
@@ -633,21 +633,16 @@ NewBuiltinClassInstance(JSContext *cx, C
  * proto->getParent() if proto is non-null (else to null). NB: only this helper
  * and NewObject can be used to construct full-sized JSFunction instances.
  */
 static inline JSObject *
 NewObjectWithGivenProto(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
 {
     DTrace::ObjectCreationScope objectCreationScope(cx, cx->fp, clasp);
 
-    /* Always call the class's getObjectOps hook if it has one. */
-    JSObjectOps *ops = clasp->getObjectOps
-                       ? clasp->getObjectOps(cx, clasp)
-                       : &js_ObjectOps;
-
     /*
      * Allocate an object from the GC heap and initialize all its fields before
      * doing any operation that can potentially trigger GC. Functions have a
      * larger non-standard allocation size.
      */
     JSObject* obj;
     if (clasp == &js_FunctionClass) {
         obj = (JSObject*) js_NewGCFunction(cx);
@@ -667,24 +662,23 @@ NewObjectWithGivenProto(JSContext *cx, C
      * Default parent to the parent of the prototype, which was set from
      * the parent of the prototype's constructor.
      */
     obj->init(clasp,
               proto,
               (!parent && proto) ? proto->getParent() : parent,
               JSObject::defaultPrivate(clasp));
 
-    if (ops->isNative()) {
-        if (!InitScopeForObject(cx, obj, clasp, proto, ops)) {
+    if (clasp->isNative()) {
+        if (!InitScopeForObject(cx, obj, clasp, proto)) {
             obj = NULL;
             goto out;
         }
     } else {
-        JS_ASSERT(ops->objectMap->ops == ops);
-        obj->map = const_cast<JSObjectMap *>(ops->objectMap);
+        obj->map = const_cast<JSObjectMap *>(&JSObjectMap::sharedNonNative);
     }
 
 out:
     objectCreationScope.handleCreation(obj);
     return obj;
 }
 
 static inline JSProtoKey
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -94,19 +94,23 @@ struct JSONParser
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
 Class js_JSONClass = {
     js_JSON_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_JSON),
-    PropertyStub,  PropertyStub,  PropertyStub,  PropertyStub,
-    EnumerateStub, ResolveStub,   ConvertStub,   NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub
 };
 
 JSBool
 js_json_parse(JSContext *cx, uintN argc, Value *vp)
 {
     JSString *s = NULL;
     Value *argv = vp + 2;
     AutoValueRooter reviver(cx);
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -883,92 +883,65 @@ proxy_DeleteProperty(JSContext *cx, JSOb
 static void
 proxy_TraceObject(JSTracer *trc, JSObject *obj)
 {
     JSContext *cx = trc->context;
 
     if (!JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList))
         js_TraceWatchPoints(trc, obj);
 
-    Class *clasp = obj->getClass();
-    if (clasp->mark) {
-        if (clasp->flags & JSCLASS_MARK_IS_TRACE)
-            ((JSTraceOp) clasp->mark)(trc, obj);
-        else if (IS_GC_MARKING_TRACER(trc))
-            (void) clasp->mark(cx, obj, trc);
-    }
-
-    obj->traceProtoAndParent(trc);
     obj->getProxyHandler()->trace(trc, obj);
     MarkValue(trc, obj->getProxyPrivate(), "private");
     if (obj->isFunctionProxy()) {
         MarkValue(trc, GetCall(obj), "call");
         MarkValue(trc, GetConstruct(obj), "construct");
     }
 }
 
-static JSType
-proxy_TypeOf_obj(JSContext *cx, JSObject *obj)
-{
-    return JSTYPE_OBJECT;
-}
-
 void
 proxy_Finalize(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isProxy());
     if (!obj->getSlot(JSSLOT_PROXY_HANDLER).isUndefined())
         obj->getProxyHandler()->finalize(cx, obj);
 }
 
-extern JSObjectOps js_ObjectProxyObjectOps;
-
-static const JSObjectMap SharedObjectProxyMap(&js_ObjectProxyObjectOps, JSObjectMap::SHAPELESS);
-
-JSObjectOps js_ObjectProxyObjectOps = {
-    &SharedObjectProxyMap,
-    proxy_LookupProperty,
-    proxy_DefineProperty,
-    proxy_GetProperty,
-    proxy_SetProperty,
-    proxy_GetAttributes,
-    proxy_SetAttributes,
-    proxy_DeleteProperty,
-    js_Enumerate,
-    proxy_TypeOf_obj,
-    proxy_TraceObject,
-    NULL,   /* thisObject */
-    proxy_Finalize
-};
-
-static JSObjectOps *
-obj_proxy_getObjectOps(JSContext *cx, Class *clasp)
-{
-    return &js_ObjectProxyObjectOps;
-}
-
 JS_FRIEND_API(Class) ObjectProxyClass = {
     "Proxy",
-    JSCLASS_HAS_RESERVED_SLOTS(2),
-    PropertyStub,
-    PropertyStub,
-    PropertyStub,
-    PropertyStub,
+    Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(2),
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub,
-    NULL,
-    obj_proxy_getObjectOps,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL
+    NULL,           /* finalize */
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    NULL,           /* mark        */
+    JS_NULL_CLASS_EXT,
+    {
+        proxy_LookupProperty,
+        proxy_DefineProperty,
+        proxy_GetProperty,
+        proxy_SetProperty,
+        proxy_GetAttributes,
+        proxy_SetAttributes,
+        proxy_DeleteProperty,
+        NULL,       /* enumerate       */
+        NULL,       /* typeof          */
+        proxy_TraceObject,
+        NULL,       /* thisObject      */
+        proxy_Finalize, /* clear */
+    }
 };
 
 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);
@@ -983,63 +956,51 @@ proxy_Construct(JSContext *cx, JSObject 
 }
 
 static JSType
 proxy_TypeOf_fun(JSContext *cx, JSObject *obj)
 {
     return JSTYPE_FUNCTION;
 }
 
-extern JSObjectOps js_FunctionProxyObjectOps;
-
-static const JSObjectMap SharedFunctionProxyMap(&js_FunctionProxyObjectOps, JSObjectMap::SHAPELESS);
-
 #define proxy_HasInstance js_FunctionClass.hasInstance
 
-JSObjectOps js_FunctionProxyObjectOps = {
-    &SharedFunctionProxyMap,
-    proxy_LookupProperty,
-    proxy_DefineProperty,
-    proxy_GetProperty,
-    proxy_SetProperty,
-    proxy_GetAttributes,
-    proxy_SetAttributes,
-    proxy_DeleteProperty,
-    js_Enumerate,
-    proxy_TypeOf_fun,
-    proxy_TraceObject,
-    NULL, /* thisObject */
-    NULL  /* clear */
-};
-
-static JSObjectOps *
-fun_proxy_getObjectOps(JSContext *cx, Class *clasp)
-{
-    return &js_FunctionProxyObjectOps;
-}
-
 JS_FRIEND_API(Class) FunctionProxyClass = {
     "Proxy",
-    JSCLASS_HAS_RESERVED_SLOTS(4) | CLASS_CALL_IS_FAST,
-    PropertyStub,
-    PropertyStub,
-    PropertyStub,
-    PropertyStub,
+    Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(4) | Class::CALL_IS_FAST,
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub,
-    NULL,
-    fun_proxy_getObjectOps,
-    NULL,
+    NULL,           /* finalize */
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
     CastCallOpAsNative(proxy_Call),
     proxy_Construct,
-    NULL,
+    NULL,           /* xdrObject   */
     proxy_HasInstance,
-    NULL,
-    NULL
+    NULL,           /* mark */
+    JS_NULL_CLASS_EXT,
+    {
+        proxy_LookupProperty,
+        proxy_DefineProperty,
+        proxy_GetProperty,
+        proxy_SetProperty,
+        proxy_GetAttributes,
+        proxy_SetAttributes,
+        proxy_DeleteProperty,
+        NULL,       /* enumerate       */
+        proxy_TypeOf_fun,
+        proxy_TraceObject,
+        NULL,       /* thisObject      */
+        NULL,       /* clear           */
+    }
 };
 
 JS_FRIEND_API(JSObject *)
 NewProxyObject(JSContext *cx, JSProxyHandler *handler, const Value &priv, JSObject *proto,
                JSObject *parent, JSObject *call, JSObject *construct)
 {
     bool fun = call || construct;
     Class *clasp = fun ? &FunctionProxyClass : &ObjectProxyClass;
@@ -1238,20 +1199,28 @@ callable_Construct(JSContext *cx, JSObje
         return true;
     }
     return InternalCall(cx, obj, fval, argc, argv, rval);
 }
 
 Class CallableObjectClass = {
     "Function",
     JSCLASS_HAS_RESERVED_SLOTS(2),
-    PropertyStub,           PropertyStub,    PropertyStub,    PropertyStub,
-    EnumerateStub,          ResolveStub,     ConvertStub,     NULL,
-    NULL,                   NULL,            callable_Call,   callable_Construct,
-    NULL,                   NULL,            NULL,            NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    NULL,           /* finalize    */
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    callable_Call,
+    callable_Construct,
 };
 
 JS_FRIEND_API(JSBool)
 FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
 {
     AutoValueRooter tvr(cx);
     if (!JSProxy::fix(cx, proxy, tvr.addr()))
         return false;
@@ -1299,19 +1268,23 @@ FixProxy(JSContext *cx, JSObject *proxy,
     return true;
 }
 
 }
 
 Class js_ProxyClass = {
     "Proxy",
     JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy),
-    PropertyStub,           PropertyStub,    PropertyStub,    PropertyStub,
-    EnumerateStub,          ResolveStub,     ConvertStub,     NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub
 };
 
 JS_FRIEND_API(JSObject *)
 js_InitProxyClass(JSContext *cx, JSObject *obj)
 {
     JSObject *module = NewObject(cx, &js_ProxyClass, NULL, obj);
     if (!module)
         return NULL;
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -341,20 +341,41 @@ typedef JSBool
  * The type of ops->call. Same argument types as JSFastNative, but a different
  * contract. A JSCallOp expects a dummy stack frame with the caller's
  * scopeChain.
  */
 typedef JSBool
 (* JSCallOp)(JSContext *cx, uintN argc, jsval *vp);
 
 /*
+ * A generic type for functions mapping an object to another object, or null
+ * if an error or exception was thrown on cx.
+ */
+typedef JSObject *
+(* JSObjectOp)(JSContext *cx, JSObject *obj);
+
+/*
+ * Hook that creates an iterator object for a given object. Returns the
+ * iterator object or null if an error or exception was thrown on cx.
+ */
+typedef JSObject *
+(* JSIteratorOp)(JSContext *cx, JSObject *obj, JSBool keysonly);
+
+/*
  * The following determines whether JS_EncodeCharacters and JS_DecodeBytes
  * treat char[] as utf-8 or simply as bytes that need to be inflated/deflated.
  */
 #ifdef JS_C_STRINGS_ARE_UTF8
 # define js_CStringsAreUTF8 JS_TRUE
 #else
 extern JSBool js_CStringsAreUTF8;
 #endif
 
+/*
+ * Hack to expose obj->getOps()->outer to the C implementation of the debugger
+ * interface.
+ */
+extern JS_FRIEND_API(JSObject *)
+js_ObjectToOuterObject(JSContext *cx, JSObject *obj);
+
 JS_END_EXTERN_C
 
 #endif /* jsprvtd_h___ */
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -102,17 +102,17 @@ typedef enum JSType {
 /* Dense index into cached prototypes and class atoms for standard objects. */
 typedef enum JSProtoKey {
 #define JS_PROTO(name,code,init) JSProto_##name = code,
 #include "jsproto.tbl"
 #undef JS_PROTO
     JSProto_LIMIT
 } JSProtoKey;
 
-/* JSObjectOps.checkAccess mode enumeration. */
+/* js_CheckAccess mode enumeration. */
 typedef enum JSAccessMode {
     JSACC_PROTO  = 0,           /* XXXbe redundant w.r.t. id */
     JSACC_PARENT = 1,           /* XXXbe redundant w.r.t. id */
 
                                 /*
                                  * enum value #2 formerly called JSACC_IMPORT,
                                  * gap preserved for ABI compatibility.
                                  */
@@ -140,28 +140,26 @@ typedef enum JSIterateOp {
     JSENUMERATE_NEXT,
 
     /* Destroy iterator state. */
     JSENUMERATE_DESTROY
 } JSIterateOp;
 
 /* Struct typedefs. */
 typedef struct JSClass           JSClass;
-typedef struct JSExtendedClass   JSExtendedClass;
 typedef struct JSConstDoubleSpec JSConstDoubleSpec;
 typedef struct JSContext         JSContext;
 typedef struct JSErrorReport     JSErrorReport;
 typedef struct JSFunction        JSFunction;
 typedef struct JSFunctionSpec    JSFunctionSpec;
 typedef struct JSTracer          JSTracer;
 typedef struct JSIdArray         JSIdArray;
 typedef struct JSPropertyDescriptor JSPropertyDescriptor;
 typedef struct JSPropertySpec    JSPropertySpec;
 typedef struct JSObjectMap       JSObjectMap;
-typedef struct JSObjectOps       JSObjectOps;
 typedef struct JSRuntime         JSRuntime;
 typedef struct JSScript          JSScript;
 typedef struct JSStackFrame      JSStackFrame;
 typedef struct JSXDRState        JSXDRState;
 typedef struct JSExceptionState  JSExceptionState;
 typedef struct JSLocaleCallbacks JSLocaleCallbacks;
 typedef struct JSSecurityCallbacks JSSecurityCallbacks;
 typedef struct JSONParser        JSONParser;
@@ -299,39 +297,16 @@ typedef void
 /*
  * Used by JS_AddExternalStringFinalizer and JS_RemoveExternalStringFinalizer
  * to extend and reduce the set of string types finalized by the GC.
  */
 typedef void
 (* JSStringFinalizeOp)(JSContext *cx, JSString *str);
 
 /*
- * The signature for JSClass.getObjectOps, used by JS_NewObject's internals
- * to discover the set of high-level object operations to use for new objects
- * of the given class.  All native objects have a JSClass, which is stored as
- * a private (int-tagged) pointer in obj slots. In contrast, all native and
- * host objects have a JSObjectMap at obj->map, which may be shared among a
- * number of objects, and which contains the JSObjectOps *ops pointer used to
- * dispatch object operations from API calls.
- *
- * Thus JSClass (which pre-dates JSObjectOps in the API) provides a low-level
- * interface to class-specific code and data, while JSObjectOps allows for a
- * higher level of operation, which does not use the object's class except to
- * find the class's JSObjectOps struct, by calling clasp->getObjectOps, and to
- * finalize the object.
- *
- * If this seems backwards, that's because it is!  API compatibility requires
- * a JSClass *clasp parameter to JS_NewObject, etc.  Most host objects do not
- * need to implement the larger JSObjectOps, and can share the common JSScope
- * code and data used by the native (js_ObjectOps, see jsobj.c) ops.
- */
-typedef JSObjectOps *
-(* JSGetObjectOps)(JSContext *cx, JSClass *clasp);
-
-/*
  * JSClass.checkAccess type: check whether obj[id] may be accessed per mode,
  * returning false on error/exception, true on success with obj[id]'s last-got
  * value in *vp, and its attributes in *attrsp.  As for JSPropertyOp above, id
  * is either a string or an int jsval.
  */
 typedef JSBool
 (* JSCheckAccessOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
                     jsval *vp);
@@ -413,36 +388,19 @@ typedef void
 
 /*
  * DEBUG only callback that JSTraceOp implementation can provide to return
  * a string describing the reference traced with JS_CallTracer.
  */
 typedef void
 (* JSTraceNamePrinter)(JSTracer *trc, char *buf, size_t bufsize);
 
-/* JSExtendedClass function pointer typedefs. */
-
 typedef JSBool
 (* JSEqualityOp)(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp);
 
-/*
- * A generic type for functions mapping an object to another object, or null
- * if an error or exception was thrown on cx.  Used by JSObjectOps.thisObject
- * at present.
- */
-typedef JSObject *
-(* JSObjectOp)(JSContext *cx, JSObject *obj);
-
-/*
- * Hook that creates an iterator object for a given object. Returns the
- * iterator object or null if an error or exception was thrown on cx.
- */
-typedef JSObject *
-(* JSIteratorOp)(JSContext *cx, JSObject *obj, JSBool keysonly);
-
 /* Typedef for native functions called by the JS VM. */
 
 typedef JSBool
 (* JSNative)(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
              jsval *rval);
 
 /* See jsapi.h, the JS_CALLEE, JS_THIS, etc. macros. */
 typedef JSBool
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -5412,24 +5412,31 @@ regexp_trace(JSTracer *trc, JSObject *ob
         JS_CALL_STRING_TRACER(trc, re->source, "source");
 }
 
 Class js_RegExpClass = {
     js_RegExp_str,
     JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::REGEXP_FIXED_RESERVED_SLOTS) |
     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
-    PropertyStub,       PropertyStub,
-    PropertyStub,       PropertyStub,
-    regexp_enumerate,   reinterpret_cast<JSResolveOp>(regexp_resolve),
-    ConvertStub,        regexp_finalize,
-    NULL,               NULL,
-    regexp_call,        NULL,
-    js_XDRRegExpObject, NULL,
-    JS_CLASS_TRACE(regexp_trace), 0
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    regexp_enumerate,
+    reinterpret_cast<JSResolveOp>(regexp_resolve),
+    ConvertStub,
+    regexp_finalize,
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    regexp_call,
+    NULL,           /* construct   */
+    js_XDRRegExpObject,
+    NULL,           /* hasInstance */
+    JS_CLASS_TRACE(regexp_trace)
 };
 
 static const jschar empty_regexp_ucstr[] = {'(', '?', ':', ')', 0};
 
 JSBool
 js_regexp_toString(JSContext *cx, JSObject *obj, Value *vp)
 {
     JSRegExp *re;
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -81,30 +81,30 @@ js_GenerateShape(JSContext *cx, bool gcL
         /*
          * FIXME bug 440834: The shape id space has overflowed. Currently we
          * cope badly with this and schedule the GC on the every call. But
          * first we make sure that increments from other threads would not
          * have a chance to wrap around shapeGen to zero.
          */
         rt->shapeGen = SHAPE_OVERFLOW_BIT;
         shape = SHAPE_OVERFLOW_BIT;
-        cx->runtime->triggerGC(gcLocked);
+        js_TriggerGC(cx, gcLocked);
     }
     return shape;
 }
 
 JSScope *
 js_GetMutableScope(JSContext *cx, JSObject *obj)
 {
     JSScope *scope = obj->scope();
     JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope));
     if (!scope->isSharedEmpty())
         return scope;
 
-    JSScope *newscope = JSScope::create(cx, scope->ops, obj->getClass(), obj, scope->shape);
+    JSScope *newscope = JSScope::create(cx, obj->getClass(), obj, scope->shape);
     if (!newscope)
         return NULL;
 
     /* The newly allocated scope is single-threaded and, as such, is locked. */
     JS_ASSERT(CX_OWNS_SCOPE_TITLE(cx, newscope));
     JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, newscope));
     obj->map = newscope;
 
@@ -195,52 +195,49 @@ JSScope::createTable(JSContext *cx, bool
 
     table = (JSScopeProperty **) js_calloc(JS_BIT(sizeLog2) * sizeof(JSScopeProperty *));
     if (!table) {
         if (report)
             JS_ReportOutOfMemory(cx);
         METER(tableAllocFails);
         return false;
     }
-    cx->runtime->updateMallocCounter(JS_BIT(sizeLog2) * sizeof(JSScopeProperty *));
+    cx->updateMallocCounter(JS_BIT(sizeLog2) * sizeof(JSScopeProperty *));
 
     hashShift = JS_DHASH_BITS - sizeLog2;
     for (sprop = lastProp; sprop; sprop = sprop->parent) {
         spp = search(sprop->id, true);
         SPROP_STORE_PRESERVING_COLLISION(spp, sprop);
     }
     return true;
 }
 
 JSScope *
-JSScope::create(JSContext *cx, const JSObjectOps *ops, Class *clasp,
-                JSObject *obj, uint32 shape)
+JSScope::create(JSContext *cx, Class *clasp, JSObject *obj, uint32 shape)
 {
-    JS_ASSERT(ops->isNative());
     JS_ASSERT(obj);
 
-    JSScope *scope = cx->create<JSScope>(ops, obj);
+    JSScope *scope = cx->create<JSScope>(obj);
     if (!scope)
         return NULL;
 
     scope->freeslot = JSSLOT_START(clasp);
     scope->flags = cx->runtime->gcRegenShapesScopeFlag;
     scope->initMinimal(cx, shape);
 
 #ifdef JS_THREADSAFE
     js_InitTitle(cx, &scope->title);
 #endif
     JS_RUNTIME_METER(cx->runtime, liveScopes);
     JS_RUNTIME_METER(cx->runtime, totalScopes);
     return scope;
 }
 
-JSEmptyScope::JSEmptyScope(JSContext *cx, const JSObjectOps *ops,
-                           Class *clasp)
-    : JSScope(ops, NULL), clasp(clasp)
+JSEmptyScope::JSEmptyScope(JSContext *cx, Class *clasp)
+    : JSScope(NULL), clasp(clasp)
 {
     /*
      * This scope holds a reference to the new empty scope. Our only caller,
      * getEmptyScope, also promises to incref on behalf of its caller.
      */
     nrefs = 2;
     freeslot = JSSLOT_START(clasp);
     flags = OWN_SHAPE | cx->runtime->gcRegenShapesScopeFlag;
@@ -285,24 +282,24 @@ JSScope::destroy(JSContext *cx)
 bool
 JSScope::initRuntimeState(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
 
 #define SCOPE(Name) rt->empty##Name##Scope
 #define CLASP(Name) &js_##Name##Class
 
-#define INIT_EMPTY_SCOPE(Name,NAME,ops)                                       \
-    INIT_EMPTY_SCOPE_WITH_CLASS(Name, NAME, ops, CLASP(Name))
+#define INIT_EMPTY_SCOPE(Name,NAME)                                           \
+    INIT_EMPTY_SCOPE_WITH_CLASS(Name, NAME, CLASP(Name))
 
-#define INIT_EMPTY_SCOPE_WITH_CLASS(Name,NAME,ops,clasp)                      \
-    INIT_EMPTY_SCOPE_WITH_FREESLOT(Name, NAME, ops, clasp, JSSLOT_FREE(clasp))
+#define INIT_EMPTY_SCOPE_WITH_CLASS(Name,NAME,clasp)                          \
+    INIT_EMPTY_SCOPE_WITH_FREESLOT(Name, NAME, clasp, JSSLOT_FREE(clasp))
 
-#define INIT_EMPTY_SCOPE_WITH_FREESLOT(Name,NAME,ops,clasp,slot)              \
-    SCOPE(Name) = cx->create<JSEmptyScope>(cx, ops, clasp);                   \
+#define INIT_EMPTY_SCOPE_WITH_FREESLOT(Name,NAME,clasp,slot)                  \
+    SCOPE(Name) = cx->create<JSEmptyScope>(cx, clasp);                        \
     if (!SCOPE(Name))                                                         \
         return false;                                                         \
     JS_ASSERT(SCOPE(Name)->shape == JSScope::EMPTY_##NAME##_SHAPE);           \
     JS_ASSERT(SCOPE(Name)->nrefs == 2);                                       \
     SCOPE(Name)->nrefs = 1;                                                   \
     SCOPE(Name)->freeslot = slot
 
     /*
@@ -318,39 +315,39 @@ JSScope::initRuntimeState(JSContext *cx)
      * is less than freeslot to succeed. As the shared emptyArgumentsScope is
      * never mutated, it's safe to pretend to have all the slots possible.
      *
      * Note how the fast paths in jsinterp.cpp for JSOP_LENGTH and JSOP_GETELEM
      * bypass resolution of scope properties for length and element indices on
      * arguments objects. This helps ensure that any arguments object needing
      * its own mutable scope (with unique shape) is a rare event.
      */
-    INIT_EMPTY_SCOPE_WITH_FREESLOT(Arguments, ARGUMENTS, &js_ObjectOps, CLASP(Arguments),
+    INIT_EMPTY_SCOPE_WITH_FREESLOT(Arguments, ARGUMENTS, CLASP(Arguments),
                                    JS_INITIAL_NSLOTS + JS_ARGS_LENGTH_MAX);
 
-    INIT_EMPTY_SCOPE(Block, BLOCK, &js_ObjectOps);
+    INIT_EMPTY_SCOPE(Block, BLOCK);
 
     /*
      * Initialize the shared scope for all empty Call objects so gets for args
      * and vars do not force the creation of a mutable scope for the particular
      * call object being accessed.
      *
      * See comment above for rt->emptyArgumentsScope->freeslot initialization.
      */
-    INIT_EMPTY_SCOPE_WITH_FREESLOT(Call, CALL, &js_ObjectOps, CLASP(Call),
+    INIT_EMPTY_SCOPE_WITH_FREESLOT(Call, CALL, CLASP(Call),
                                    JS_INITIAL_NSLOTS + JSFunction::MAX_ARGS_AND_VARS);
 
     /* A DeclEnv object holds the name binding for a named function expression. */
-    INIT_EMPTY_SCOPE(DeclEnv, DECL_ENV, &js_ObjectOps);
+    INIT_EMPTY_SCOPE(DeclEnv, DECL_ENV);
 
     /* Non-escaping native enumerator objects share this empty scope. */
-    INIT_EMPTY_SCOPE_WITH_CLASS(Enumerator, ENUMERATOR, &js_ObjectOps, &js_IteratorClass.base);
+    INIT_EMPTY_SCOPE_WITH_CLASS(Enumerator, ENUMERATOR, &js_IteratorClass);
 
     /* Same drill for With objects. */
-    INIT_EMPTY_SCOPE(With, WITH, &js_WithObjectOps);
+    INIT_EMPTY_SCOPE_WITH_CLASS(With, WITH, &js_WithClass);
 
 #undef SCOPE
 #undef CLASP
 #undef INIT_EMPTY_SCOPE
 #undef INIT_EMPTY_SCOPE_WITH_CLASS
 #undef INIT_EMPTY_SCOPE_WITH_FREESLOT
 
     return true;
@@ -511,17 +508,17 @@ JSScope::changeTable(JSContext *cx, int 
 
     /* Now that we have newtable allocated, update members. */
     hashShift = JS_DHASH_BITS - newlog2;
     removedCount = 0;
     oldtable = table;
     table = newtable;
 
     /* Treat the above calloc as a JS_malloc, to match CreateScopeTable. */
-    cx->runtime->updateMallocCounter(nbytes);
+    cx->updateMallocCounter(nbytes);
 
     /* Copy only live entries, leaving removed and free ones behind. */
     for (oldspp = oldtable; oldsize != 0; oldspp++) {
         sprop = SPROP_FETCH(oldspp);
         if (sprop) {
             spp = search(sprop->id, true);
             JS_ASSERT(SPROP_IS_FREE(*spp));
             *spp = sprop;
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -287,37 +287,36 @@ struct JSScope : public JSObjectMap
 
     JSScopeProperty *addPropertyHelper(JSContext *cx, jsid id,
                                        js::PropertyOp getter, js::PropertyOp setter,
                                        uint32 slot, uintN attrs,
                                        uintN flags, intN shortid,
                                        JSScopeProperty **spp);
 
   public:
-    JSScope(const JSObjectOps *ops, JSObject *obj)
-      : JSObjectMap(ops, 0), object(obj) {}
+    JSScope(JSObject *obj)
+      : JSObjectMap(0), object(obj) {}
 
     /* Create a mutable, owned, empty scope. */
-    static JSScope *create(JSContext *cx, const JSObjectOps *ops,
-                           js::Class *clasp, JSObject *obj, uint32 shape);
+    static JSScope *create(JSContext *cx, js::Class *clasp, JSObject *obj, uint32 shape);
 
     void destroy(JSContext *cx);
 
     /*
      * Return an immutable, shareable, empty scope with the same ops as this
      * and the same freeslot as this had when empty.
      *
      * If |this| is the scope of an object |proto|, the resulting scope can be
      * used as the scope of a new object whose prototype is |proto|.
      */
     inline JSEmptyScope *getEmptyScope(JSContext *cx, js::Class *clasp);
 
     inline bool ensureEmptyScope(JSContext *cx, js::Class *clasp);
 
-    inline bool canProvideEmptyScope(JSObjectOps *ops, js::Class *clasp);
+    inline bool canProvideEmptyScope(js::Class *clasp);
 
     JSScopeProperty *lookup(jsid id);
 
     inline bool hasProperty(jsid id) { return lookup(id) != NULL; }
     inline bool hasProperty(JSScopeProperty *sprop);
 
     /* Add a property whose id is not yet in this scope. */
     JSScopeProperty *addProperty(JSContext *cx, jsid id,
@@ -450,18 +449,18 @@ struct JSScope : public JSObjectMap
     void setIndexedProperties() { flags |= INDEXED_PROPERTIES; }
 
     bool hasOwnShape()          { return flags & OWN_SHAPE; }
 
     bool hasRegenFlag(uint8 regenFlag) { return (flags & SHAPE_REGEN) == regenFlag; }
 
     /*
      * A scope has a method barrier when some compiler-created "null closure"
-     * function objects (functions that do not use lexical bindings above their
-     * scope, only free variable names) that have a correct JSSLOT_PARENT value
+     * function objects (functions that do not use lexical bindings above
+     * their scope, only free variable names) that have a correct parent value
      * thanks to the COMPILE_N_GO optimization are stored as newly added direct
      * property values of the scope's object.
      *
      * The de-facto standard JS language requires each evaluation of such a
      * closure to result in a unique (according to === and observable effects)
      * function object. ES3 tried to allow implementations to "join" such
      * objects to a single compiler-created object, but this makes an overt
      * mutation hazard, also an "identity hazard" against interoperation among
@@ -521,17 +520,17 @@ struct JSScope : public JSObjectMap
     };
 };
 
 struct JSEmptyScope : public JSScope
 {
     js::Class * const clasp;
     jsrefcount        nrefs;              /* count of all referencing objects */
 
-    JSEmptyScope(JSContext *cx, const JSObjectOps *ops, js::Class *clasp);
+    JSEmptyScope(JSContext *cx, js::Class *clasp);
 
     JSEmptyScope *hold() {
         /* The method is only called for already held objects. */
         JS_ASSERT(nrefs >= 1);
         JS_ATOMIC_INCREMENT(&nrefs);
         return this;
     }
 
@@ -893,16 +892,20 @@ JSScope::insertDictionaryProperty(JSScop
  */
 #define SPROP_USERID(sprop)                                                   \
     ((sprop)->hasShortID() ? INT_TO_JSID((sprop)->shortid)                    \
                            : (sprop)->id)
 
 #define SLOT_IN_SCOPE(slot,scope)         ((slot) < (scope)->freeslot)
 #define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope)
 
+#ifndef JS_THREADSAFE
+# define js_GenerateShape(cx, gcLocked)    js_GenerateShape (cx)
+#endif
+
 extern uint32
 js_GenerateShape(JSContext *cx, bool gcLocked);
 
 #ifdef DEBUG
 struct JSScopeStats {
     jsrefcount          searches;
     jsrefcount          hits;
     jsrefcount          misses;
@@ -953,25 +956,25 @@ JSScope::search(jsid id, bool adding)
         return spp;
     }
     return searchTable(id, adding);
 }
 
 #undef METER
 
 inline bool
-JSScope::canProvideEmptyScope(JSObjectOps *ops, js::Class *clasp)
+JSScope::canProvideEmptyScope(js::Class *clasp)
 {
     /*
      * An empty scope cannot provide another empty scope, or wrongful two-level
      * prototype shape sharing ensues -- see bug 497789.
      */
     if (!object)
         return false;
-    return this->ops == ops && (!emptyScope || emptyScope->clasp == clasp);
+    return !emptyScope || emptyScope->clasp == clasp;
 }
 
 inline bool
 JSScopeProperty::isSharedPermanent() const
 {
     return (~attrs & (JSPROP_SHARED | JSPROP_PERMANENT)) == 0;
 }
 
--- a/js/src/jsscopeinlines.h
+++ b/js/src/jsscopeinlines.h
@@ -48,17 +48,17 @@
 
 #include "jscntxtinlines.h"
 
 inline JSEmptyScope *
 JSScope::createEmptyScope(JSContext *cx, js::Class *clasp)
 {
     JS_ASSERT(!isSharedEmpty());
     JS_ASSERT(!emptyScope);
-    emptyScope = cx->create<JSEmptyScope>(cx, ops, clasp);
+    emptyScope = cx->create<JSEmptyScope>(cx, clasp);
     return emptyScope;
 }
 
 inline JSEmptyScope *
 JSScope::getEmptyScope(JSContext *cx, js::Class *clasp)
 {
     if (emptyScope) {
         JS_ASSERT(clasp == emptyScope->clasp);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -415,20 +415,31 @@ script_trace(JSTracer *trc, JSObject *ob
     if (script)
         js_TraceScript(trc, script);
 }
 
 Class js_ScriptClass = {
     "Script",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
-    PropertyStub,     PropertyStub,     PropertyStub,     PropertyStub,
-    EnumerateStub,    ResolveStub,      ConvertStub,      script_finalize,
-    NULL,             NULL,             NULL,             NULL,/*XXXbe xdr*/
-    NULL,             NULL,             JS_CLASS_TRACE(script_trace), NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    script_finalize,
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    JS_CLASS_TRACE(script_trace)
 };
 
 /*
  * Shared script filename management.
  */
 static int
 js_compare_strings(const void *k1, const void *k2)
 {
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -801,19 +801,23 @@ str_resolve(JSContext *cx, JSObject *obj
     }
     return JS_TRUE;
 }
 
 Class js_StringClass = {
     js_String_str,
     JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_String),
-    PropertyStub,    PropertyStub,     str_getProperty,     PropertyStub,
-    str_enumerate,   (JSResolveOp)str_resolve, ConvertStub, NULL,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    str_getProperty,
+    PropertyStub,   /* setProperty */
+    str_enumerate,
+    (JSResolveOp)str_resolve,
+    ConvertStub
 };
 
 #define NORMALIZE_THIS(cx,vp,str)                                             \
     JS_BEGIN_MACRO                                                            \
         if (vp[1].isString()) {                                               \
             str = vp[1].toString();                                           \
         } else {                                                              \
             str = NormalizeThis(cx, vp);                                      \
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -2906,17 +2906,17 @@ NativeToValue(JSContext* cx, Value& v, J
       }
       case JSVAL_TYPE_STRORNULL:
         debug_only_printf(LC_TMTracer, "nullablestr<%p> ", v.isNull() ? NULL : (void *)v.toString());
         break;
       case JSVAL_TYPE_OBJORNULL:
         debug_only_printf(LC_TMTracer, "nullablestr<%p> ", v.isNull() ? NULL : (void *)&v.toObject());
         break;
       case JSVAL_TYPE_BOXED:
-        debug_only_printf(LC_TMTracer, "box<%llx> ", v.asRawBits());
+        debug_only_printf(LC_TMTracer, "box<%llx> ", (long long unsigned int)v.asRawBits());
         break;
       default:
         JS_NOT_REACHED("unexpected type");
         break;
     }
 #endif
 }
 
@@ -3002,16 +3002,17 @@ public:
         mCx(cx),
         mTypeMap(typeMap),
         mGlobal(global)
     {}
 
     JS_REQUIRES_STACK JS_ALWAYS_INLINE void
     visitGlobalSlot(Value *vp, unsigned n, unsigned slot) {
         debug_only_printf(LC_TMTracer, "global%d=", n);
+        JS_ASSERT(JS_THREAD_DATA(mCx)->waiveGCQuota);
         NativeToValue(mCx, *vp, *mTypeMap++, &mGlobal[slot]);
     }
 };
 
 class FlushNativeStackFrameVisitor : public SlotVisitorBase
 {
     JSContext *mCx;
     const JSValueType *mInitTypeMap;
@@ -3035,31 +3036,33 @@ public:
 
     const JSValueType* getTypeMap()
     {
         return mTypeMap;
     }
 
     JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
     visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) {
+        JS_ASSERT(JS_THREAD_DATA(mCx)->waiveGCQuota);
         for (size_t i = 0; i < count; ++i) {
             if (vp == mStop)
                 return false;
             debug_only_printf(LC_TMTracer, "%s%u=", stackSlotKind(), unsigned(i));
             if (unsigned(mTypeMap - mInitTypeMap) >= mIgnoreSlots)
                 NativeToValue(mCx, *vp, *mTypeMap, mStack);
             vp++;
             mTypeMap++;
             mStack++;
         }
         return true;
     }
 
     JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
     visitFrameObjPtr(JSObject **p, JSStackFrame* fp) {
+        JS_ASSERT(JS_THREAD_DATA(mCx)->waiveGCQuota);
         if ((Value *)p == mStop)
             return false;
         debug_only_printf(LC_TMTracer, "%s%u=", stackSlotKind(), 0);
         if (unsigned(mTypeMap - mInitTypeMap) >= mIgnoreSlots) {
             *p = *(JSObject **)mStack;
 #ifdef DEBUG
             JSValueType type = *mTypeMap;
             if (type == JSVAL_TYPE_NULL) {
@@ -6743,23 +6746,41 @@ ExecuteTree(JSContext* cx, TreeFragment*
     LeaveTree(tm, state, lr);
 
     *lrp = state.innermost;
     bool ok = !(state.builtinStatus & BUILTIN_ERROR);
     JS_ASSERT_IF(cx->throwing, !ok);
     return ok;
 }
 
+class Guardian {
+    bool *flagp;
+public:
+    Guardian(bool *flagp) {
+        this->flagp = flagp;
+        JS_ASSERT(!*flagp);
+        *flagp = true;
+    }
+
+    ~Guardian() {
+        JS_ASSERT(*flagp);
+        *flagp = false;
+    }
+};
+
 static JS_FORCES_STACK void
 LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr)
 {
     VOUCH_DOES_NOT_REQUIRE_STACK();
 
     JSContext* cx = state.cx;
 
+    /* Temporary waive the soft GC quota to make sure LeaveTree() doesn't fail. */
+    Guardian waiver(&JS_THREAD_DATA(cx)->waiveGCQuota);
+
     FrameInfo** callstack = state.callstackBase;
     double* stack = state.stackBase;
 
     /*
      * Except if we find that this is a nested bailout, the guard the call
      * returned is the one we have to use to adjust pc and sp.
      */
     VMSideExit* innermost = lr;
@@ -8965,18 +8986,17 @@ TraceRecorder::equalityHelper(Value& l, 
      */
 
     if (getPromotedType(l) == getPromotedType(r)) {
         if (l.isUndefined() || l.isNull()) {
             cond = true;
             if (l.isNull())
                 op = LIR_eqp;
         } else if (l.isObject()) {
-            Class *clasp = l.toObject().getClass();
-            if ((clasp->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*) clasp)->equality)
+            if (l.toObject().getClass()->ext.equality)
                 RETURN_STOP_A("Can't trace extended class equality operator");
             op = LIR_eqp;
             cond = (l == r);
         } else if (l.isBoolean()) {
             JS_ASSERT(r.isBoolean());
             cond = (l == r);
         } else if (l.isString()) {
             args[0] = r_ins, args[1] = l_ins;
@@ -9376,18 +9396,16 @@ void
 TraceRecorder::forgetGuardedShapes()
 {
 #if defined DEBUG_notme && defined XP_UNIX
     dumpGuardedShapes("forget-all");
 #endif
     guardedShapeTable.clear();
 }
 
-JS_STATIC_ASSERT(offsetof(JSObjectOps, objectMap) == 0);
-
 inline LIns*
 TraceRecorder::map(LIns* obj_ins)
 {
     return addName(lir->insLoad(LIR_ldp, obj_ins, (int) offsetof(JSObject, map), ACCSET_OTHER), "map");
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2, PCVal& pcval)
@@ -9964,17 +9982,17 @@ TraceRecorder::box_value_into_alloc(cons
     return alloc_ins;
 }
 
 #endif  /* JS_BITS_PER_WORD */
 
 LIns*
 TraceRecorder::stobj_get_parent(nanojit::LIns* obj_ins)
 {
-    return stobj_get_fslot_ptr(obj_ins, JSSLOT_PARENT);
+    return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, parent), ACCSET_OTHER);
 }
 
 LIns*
 TraceRecorder::stobj_get_private(nanojit::LIns* obj_ins)
 {
     return stobj_get_fslot_ptr(obj_ins, JSSLOT_PRIVATE);
 }
 
@@ -11385,17 +11403,17 @@ TraceRecorder::callNative(uintN argc, JS
         JS_ASSERT(((jsuword) clasp & 3) == 0);
 
         // Abort on |new Function|. js_NewInstance would allocate a regular-
         // sized JSObject, not a Function-sized one. (The Function ctor would
         // deep-bail anyway but let's not go there.)
         if (clasp == &js_FunctionClass)
             RETURN_STOP("new Function");
 
-        if (clasp->getObjectOps)
+        if (!clasp->isNative())
             RETURN_STOP("new with non-native ops");
 
         args[0] = INS_CONSTOBJ(funobj);
         args[1] = INS_CONSTPTR(clasp);
         args[2] = cx_ins;
         newobj_ins = lir->insCall(&js_NewInstance_ci, args);
         guard(false, lir->insEqP_0(newobj_ins), OOM_EXIT);
         this_ins = newobj_ins;
@@ -11813,17 +11831,17 @@ TraceRecorder::record_JSOP_GETPROP()
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_JSOP_SETPROP()
 {
     Value& l = stackval(-2);
     if (l.isPrimitive())
         RETURN_STOP_A("primitive this for SETPROP");
 
     JSObject* obj = &l.toObject();
-    if (obj->map->ops->setProperty != js_SetProperty)
+    if (obj->getOps()->setProperty)
         RETURN_STOP_A("non-native JSObjectOps::setProperty");
     return ARECORD_CONTINUE;
 }
 
 /* Emit a specialized, inlined copy of js_NativeSet. */
 JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop,
                          const Value &v, LIns* v_ins)
@@ -13520,17 +13538,17 @@ TraceRecorder::prop(JSObject* obj, LIns*
 {
     /*
      * Insist that obj have js_SetProperty as its set object-op. This suffices
      * to prevent a rogue obj from being used on-trace (loaded via obj_ins),
      * because we will guard on shape (or else global object identity) and any
      * object not having the same op must have a different class, and therefore
      * must differ in its shape (or not be the global object).
      */
-    if (!obj->isDenseArray() && obj->map->ops->getProperty != js_GetProperty)
+    if (!obj->isDenseArray() && obj->getOps()->getProperty)
         RETURN_STOP_A("non-dense-array, non-native JSObjectOps::getProperty");
 
     JS_ASSERT((slotp && v_insp && !outp) || (!slotp && !v_insp && outp));
 
     /*
      * Property cache ensures that we are dealing with an existing property,
      * and guards the shape for us.
      */
@@ -14203,34 +14221,34 @@ TraceRecorder::record_JSOP_MOREITER()
     RETURN_IF_XML_A(iterobj_val);
 
     JSObject* iterobj = &iterobj_val.toObject();
     LIns* iterobj_ins = get(&iterobj_val);
     bool cond;
     LIns* cond_ins;
 
     /* JSOP_FOR* already guards on this, but in certain rare cases we might record misformed loop traces. */
-    if (iterobj->hasClass(&js_IteratorClass.base)) {
-        guardClass(iterobj_ins, &js_IteratorClass.base, 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();
         void *cursor = ni->props_cursor;
         void *end = ni->props_end;
 
         LIns *ni_ins = stobj_get_const_private_ptr(iterobj_ins);
         LIns *cursor_ins =
             addName(lir->insLoad(LIR_ldp, ni_ins,
                                  offsetof(NativeIterator, props_cursor), ACCSET_OTHER), "cursor");
         LIns *end_ins = addName(lir->insLoad(LIR_ldp, ni_ins, offsetof(NativeIterator, props_end),
                                 ACCSET_OTHER), "end");
 
         /* Figure out whether the native iterator contains more values. */
         cond = cursor < end;
         cond_ins = lir->ins2(LIR_ltp, cursor_ins, end_ins);
     } else {
-        guardNotClass(iterobj_ins, &js_IteratorClass.base, snapshot(BRANCH_EXIT), LOAD_NORMAL);
+        guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
 
         enterDeepBailCall();
 
         LIns* vp_ins = lir->insAlloc(sizeof(Value));
         LIns* args[] = { vp_ins, iterobj_ins, cx_ins };
         LIns* ok_ins = lir->insCall(&IteratorMore_ci, args);
 
         /*
@@ -14318,18 +14336,18 @@ TraceRecorder::storeMagic(JSWhyMagic why
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::unboxNextValue(LIns* &v_ins)
 {
     Value &iterobj_val = stackval(-1);
     JSObject *iterobj = &iterobj_val.toObject();
     LIns* iterobj_ins = get(&iterobj_val);
 
-    if (iterobj->hasClass(&js_IteratorClass.base)) {
-        guardClass(iterobj_ins, &js_IteratorClass.base, 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 = stobj_get_const_private_ptr(iterobj_ins);
         LIns *cursor_ins = addName(lir->insLoad(LIR_ldp, ni_ins, offsetof(NativeIterator, props_cursor), ACCSET_OTHER), "cursor");
 
         /* Emit code to stringify the id if necessary. */
         if (!(((NativeIterator *) iterobj->getPrivate())->flags & JSITER_FOREACH)) {
             /* Read the next id from the iterator. */
@@ -14359,19 +14377,20 @@ TraceRecorder::unboxNextValue(LIns* &v_i
             /* Read the next value from the iterator. */
             Value v = *ni->currentValue();
             v_ins = unbox_value(v, cursor_ins, 0, snapshot(BRANCH_EXIT));
 
             /* Increment the cursor by one Value and store it back. */
             cursor_ins = lir->ins2(LIR_addp, cursor_ins, INS_CONSTWORD(sizeof(Value)));
         }
 
-        lir->insStore(LIR_stp, cursor_ins, ni_ins, offsetof(NativeIterator, props_cursor), ACCSET_OTHER);
-    } else {
-        guardNotClass(iterobj_ins, &js_IteratorClass.base, snapshot(BRANCH_EXIT), LOAD_NORMAL);
+        lir->insStore(LIR_stp, cursor_ins, ni_ins, offsetof(NativeIterator, props_cursor),
+                      ACCSET_OTHER);
+    } else {
+        guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
 
         v_ins = unbox_value(cx->iterValue, cx_ins, offsetof(JSContext, iterValue),
                             snapshot(BRANCH_EXIT));
         storeMagic(JS_NO_ITER_VALUE, cx_ins, offsetof(JSContext, iterValue), ACCSET_OTHER);
     }
 
     return ARECORD_CONTINUE;
 }
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -313,19 +313,16 @@ TypedArray::obj_lookupProperty(JSContext
     return proto->lookupProperty(cx, id, objp, propp);
 }
 
 void
 TypedArray::obj_trace(JSTracer *trc, JSObject *obj)
 {
     TypedArray *tarray = fromJSObject(obj);
     JS_ASSERT(tarray);
-
-    obj->traceProtoAndParent(trc);
-
     JS_CALL_OBJECT_TRACER(trc, tarray->bufferJS, "typedarray.buffer");
 }
 
 JSBool
 TypedArray::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     *attrsp = (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
               ? JSPROP_PERMANENT | JSPROP_READONLY
@@ -488,36 +485,28 @@ class TypedArrayTemplate
   : public TypedArray
 {
   public:
     typedef TypedArrayTemplate<NativeType> ThisTypeArray;
     static const int ArrayTypeID() { return TypeIDOfType<NativeType>(); }
     static const bool ArrayTypeIsUnsigned() { return TypeIsUnsigned<NativeType>(); }
     static const bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint<NativeType>(); }
 
-    static JSObjectOps fastObjectOps;
-    static JSObjectMap fastObjectMap;
-
     static JSFunctionSpec jsfuncs[];
 
     static inline Class *slowClass()
     {
         return &TypedArray::slowClasses[ArrayTypeID()];
     }
 
     static inline Class *fastClass()
     {
         return &TypedArray::fastClasses[ArrayTypeID()];
     }
 
-    static JSObjectOps *getObjectOps(JSContext *cx, Class *clasp)
-    {
-        return &fastObjectOps;
-    }
-
     static JSBool
     obj_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
     {
         ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
         JS_ASSERT(tarray);
 
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
             vp->setNumber(tarray->length);
@@ -921,17 +910,17 @@ class TypedArrayTemplate
 
     // helper used by both the constructor and Slice()
     static void
     makeFastWithPrivate(JSContext *cx, JSObject *obj, ThisTypeArray *tarray)
     {
         JS_ASSERT(obj->getClass() == slowClass());
         obj->setPrivate(tarray);
         obj->clasp = fastClass();
-        obj->map = &fastObjectMap;
+        obj->map = const_cast<JSObjectMap *>(&JSObjectMap::sharedNonNative);
     }
 
   public:
     TypedArrayTemplate() { }
 
     bool
     init(JSContext *cx, uint32 len)
     {
@@ -1259,19 +1248,24 @@ TypedArrayTemplate<double>::copyIndexToV
 
 /*
  * ArrayBuffer (base)
  */
 
 Class ArrayBuffer::jsclass = {
     "ArrayBuffer",
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
-    PropertyStub,     PropertyStub,   PropertyStub,   PropertyStub,
-    EnumerateStub,    ResolveStub,    ConvertStub,    ArrayBuffer::class_finalize,
-    JSCLASS_NO_OPTIONAL_MEMBERS
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    ArrayBuffer::class_finalize,
 };
 
 JSPropertySpec ArrayBuffer::jsprops[] = {
     { "byteLength",
       -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY,
       Jsvalify(ArrayBuffer::prop_getByteLength), Jsvalify(ArrayBuffer::prop_getByteLength) },
     {0,0,0,0,0}
 };
@@ -1296,56 +1290,69 @@ JSPropertySpec TypedArray::jsprops[] = {
     {0,0,0,0,0}
 };
 
 /*
  * TypedArray boilerplate
  */
 
 #define IMPL_TYPED_ARRAY_STATICS(_typedArray)                                  \
-template<> JSObjectMap _typedArray::fastObjectMap(&_typedArray::fastObjectOps, \
-                                                  JSObjectMap::SHAPELESS);     \
-template<> JSObjectOps _typedArray::fastObjectOps = {                          \
-    &_typedArray::fastObjectMap,                                               \
-    _typedArray::obj_lookupProperty,                                           \
-    _typedArray::obj_defineProperty,                                           \
-    _typedArray::obj_getProperty,                                              \
-    _typedArray::obj_setProperty,                                              \
-    _typedArray::obj_getAttributes,                                            \
-    _typedArray::obj_setAttributes,                                            \
-    _typedArray::obj_deleteProperty,                                           \
-    _typedArray::obj_enumerate,                                                \
-    _typedArray::obj_typeOf,                                                   \
-    _typedArray::obj_trace,                                                    \
-    NULL,   /* thisObject */                                                   \
-    NULL    /* clear */                                                        \
-};                                                                             \
 template<> JSFunctionSpec _typedArray::jsfuncs[] = {                           \
     JS_FN("slice", _typedArray::fun_slice, 2, 0),                              \
     JS_FS_END                                                                  \
 }
 
 #define IMPL_TYPED_ARRAY_SLOW_CLASS(_typedArray)                               \
 {                                                                              \
     #_typedArray,                                                              \
     JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray),     \
-    PropertyStub, PropertyStub, PropertyStub, PropertyStub,                    \
-    EnumerateStub, ResolveStub, ConvertStub, FinalizeStub,                     \
-    JSCLASS_NO_OPTIONAL_MEMBERS                                                \
+    PropertyStub,   /* addProperty */                                          \
+    PropertyStub,   /* delProperty */                                          \
+    PropertyStub,   /* getProperty */                                          \
+    PropertyStub,   /* setProperty */                                          \
+    EnumerateStub,                                                             \
+    ResolveStub,                                                               \
+    ConvertStub,                                                               \
+    FinalizeStub                                                               \
 }
 
 #define IMPL_TYPED_ARRAY_FAST_CLASS(_typedArray)                               \
 {                                                                              \
     #_typedArray,                                                              \
-    JSCLASS_HAS_PRIVATE,                                                       \
-    PropertyStub, PropertyStub, PropertyStub, PropertyStub,                    \
-    EnumerateStub, ResolveStub, ConvertStub,                                   \
+    Class::NON_NATIVE | JSCLASS_HAS_PRIVATE,                                   \
+    PropertyStub,   /* addProperty */                                          \
+    PropertyStub,   /* delProperty */                                          \
+    PropertyStub,   /* getProperty */                                          \
+    PropertyStub,   /* setProperty */                                          \
+    EnumerateStub,                                                             \
+    ResolveStub,                                                               \
+    ConvertStub,                                                               \
     _typedArray::class_finalize,                                               \
-    _typedArray::getObjectOps, NULL, NULL, NULL,                               \
-    NULL, NULL, NULL, NULL                                                     \
+    NULL,           /* reserved0   */                                          \
+    NULL,           /* checkAccess */                                          \
+    NULL,           /* call        */                                          \
+    NULL,           /* construct   */                                          \
+    NULL,           /* xdrObject   */                                          \
+    NULL,           /* hasInstance */                                          \
+    NULL,           /* mark        */                                          \
+    JS_NULL_CLASS_EXT,                                                         \
+    {                                                                          \
+        _typedArray::obj_lookupProperty,                                       \
+        _typedArray::obj_defineProperty,                                       \
+        _typedArray::obj_getProperty,                                          \
+        _typedArray::obj_setProperty,                                          \
+        _typedArray::obj_getAttributes,                                        \
+        _typedArray::obj_setAttributes,                                        \
+        _typedArray::obj_deleteProperty,                                       \
+        _typedArray::obj_enumerate,                                            \
+        _typedArray::obj_typeOf,                                               \
+        _typedArray::obj_trace,                                                \
+        NULL,       /* thisObject      */                                      \
+        NULL,       /* clear           */                                      \
+    }                                                                          \
 }
 
 #define INIT_TYPED_ARRAY_CLASS(_typedArray,_type)                              \
 do {                                                                           \
     proto = js_InitClass(cx, obj, NULL,                                        \
                          &TypedArray::slowClasses[TypedArray::_type],          \
                          _typedArray::class_constructor, 3,                    \
                          _typedArray::jsprops,                                 \
--- a/js/src/jsvalue.h
+++ b/js/src/jsvalue.h
@@ -774,18 +774,16 @@ typedef JSBool
 typedef JSBool
 (* NewEnumerateOp)(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                    Value *statep, jsid *idp);
 typedef JSBool
 (* HasInstanceOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp);
 typedef JSBool
 (* CheckAccessOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
                   Value *vp);
-typedef JSObjectOps *
-(* GetObjectOps)(JSContext *cx, Class *clasp);
 typedef JSBool
 (* EqualityOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp);
 typedef JSBool
 (* DefinePropOp)(JSContext *cx, JSObject *obj, jsid id, const Value *value,
                  PropertyOp getter, PropertyOp setter, uintN attrs);
 typedef JSBool
 (* PropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp);
 typedef JSBool
@@ -800,101 +798,135 @@ static inline JSPropertyOp      Jsvalify
 static inline ConvertOp         Valueify(JSConvertOp f)       { return (ConvertOp)f; }
 static inline JSConvertOp       Jsvalify(ConvertOp f)         { return (JSConvertOp)f; }
 static inline NewEnumerateOp    Valueify(JSNewEnumerateOp f)  { return (NewEnumerateOp)f; }
 static inline JSNewEnumerateOp  Jsvalify(NewEnumerateOp f)    { return (JSNewEnumerateOp)f; }
 static inline HasInstanceOp     Valueify(JSHasInstanceOp f)   { return (HasInstanceOp)f; }
 static inline JSHasInstanceOp   Jsvalify(HasInstanceOp f)     { return (JSHasInstanceOp)f; }
 static inline CheckAccessOp     Valueify(JSCheckAccessOp f)   { return (CheckAccessOp)f; }
 static inline JSCheckAccessOp   Jsvalify(CheckAccessOp f)     { return (JSCheckAccessOp)f; }
-static inline GetObjectOps      Valueify(JSGetObjectOps f)    { return (GetObjectOps)f; }
-static inline JSGetObjectOps    Jsvalify(GetObjectOps f)      { return (JSGetObjectOps)f; }
 static inline EqualityOp        Valueify(JSEqualityOp f);     /* Same type as JSHasInstanceOp */
 static inline JSEqualityOp      Jsvalify(EqualityOp f);       /* Same type as HasInstanceOp */
 static inline DefinePropOp      Valueify(JSDefinePropOp f)    { return (DefinePropOp)f; }
 static inline JSDefinePropOp    Jsvalify(DefinePropOp f)      { return (JSDefinePropOp)f; }
 static inline PropertyIdOp      Valueify(JSPropertyIdOp f);   /* Same type as JSPropertyOp */
 static inline JSPropertyIdOp    Jsvalify(PropertyIdOp f);     /* Same type as PropertyOp */
 static inline CallOp            Valueify(JSCallOp f);         /* Same type as JSFastNative */
 static inline JSCallOp          Jsvalify(CallOp f);           /* Same type as FastNative */
 
 static const PropertyOp    PropertyStub  = (PropertyOp)JS_PropertyStub;
 static const JSEnumerateOp EnumerateStub = JS_EnumerateStub;
 static const JSResolveOp   ResolveStub   = JS_ResolveStub;
 static const ConvertOp     ConvertStub   = (ConvertOp)JS_ConvertStub;
 static const JSFinalizeOp  FinalizeStub  = JS_FinalizeStub;
 
-struct Class {
-    const char          *name;
-    uint32              flags;
+#define JS_CLASS_MEMBERS                                                      \
+    const char          *name;                                                \
+    uint32              flags;                                                \
+                                                                              \
+    /* Mandatory non-null function pointer members. */                        \
+    PropertyOp          addProperty;                                          \
+    PropertyOp          delProperty;                                          \
+    PropertyOp          getProperty;                                          \
+    PropertyOp          setProperty;                                          \
+    JSEnumerateOp       enumerate;                                            \
+    JSResolveOp         resolve;                                              \
+    ConvertOp           convert;                                              \
+    JSFinalizeOp        finalize;                                             \
+                                                                              \
+    /* Optionally non-null members start here. */                             \
+    JSClassInternal     reserved0;                                            \
+    CheckAccessOp       checkAccess;                                          \
+    Native              call;                                                 \
+    Native              construct;                                            \
+    JSXDRObjectOp       xdrObject;                                            \
+    HasInstanceOp       hasInstance;                                          \
+    JSMarkOp            mark
+
+
+/*
+ * The helper struct to measure the size of JS_CLASS_MEMBERS to know how much
+ * we have to padd js::Class to match the size of JSClass;
+ */
+struct ClassSizeMeasurement {
+    JS_CLASS_MEMBERS;
+};
+
+struct ClassExtension {
+    EqualityOp          equality;
+    JSObjectOp          outerObject;
+    JSObjectOp          innerObject;
+    JSIteratorOp        iteratorObject;
+    JSObjectOp          wrappedObject;  /* NB: infallible, null returns are
+                                           treated as the original object */
+};
+
+#define JS_NULL_CLASS_EXT   {NULL,NULL,NULL,NULL,NULL}
 
-    /* Mandatory non-null function pointer members. */
-    PropertyOp          addProperty;
-    PropertyOp          delProperty;
-    PropertyOp          getProperty;
-    PropertyOp          setProperty;
-    JSEnumerateOp       enumerate;
-    JSResolveOp         resolve;
-    ConvertOp           convert;
-    JSFinalizeOp        finalize;
+struct ObjectOps {
+    JSLookupPropOp      lookupProperty;
+    js::DefinePropOp    defineProperty;
+    js::PropertyIdOp    getProperty;
+    js::PropertyIdOp    setProperty;
+    JSAttributesOp      getAttributes;
+    JSAttributesOp      setAttributes;
+    js::PropertyIdOp    deleteProperty;
+    js::NewEnumerateOp  enumerate;
+    JSTypeOfOp          typeOf;
+    JSTraceOp           trace;
+    JSObjectOp          thisObject;
+    JSFinalizeOp        clear;
+};
+
+#define JS_NULL_OBJECT_OPS  {NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL}
 
-    /* Optionally non-null members start here. */
-    GetObjectOps        getObjectOps;
-    CheckAccessOp       checkAccess;
-    Native              call;
-    Native              construct;
-    JSXDRObjectOp       xdrObject;
-    HasInstanceOp       hasInstance;
-    JSMarkOp            mark;
-    void                (*reserved0)(void);
+struct Class {
+    JS_CLASS_MEMBERS;
+    ClassExtension      ext;
+    ObjectOps           ops;
+    uint8               pad[sizeof(JSClass) - sizeof(ClassSizeMeasurement) -
+                            sizeof(ClassExtension) - sizeof(ObjectOps)];
+
+    /* Flag indicating that Class::call is a fast native. */
+    static const uint32 CALL_IS_FAST = JSCLASS_INTERNAL_FLAG1;
+
+    /* Class is not native and its map is not a scope. */
+    static const uint32 NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
+
+    bool isNative() const {
+        return !(flags & NON_NATIVE);
+    }
 };
+
+/* Helper to initialize Class::call when Class::CALL_IS_FAST. */
+inline Native
+CastCallOpAsNative(CallOp op)
+{
+    return reinterpret_cast<Native>(op);
+}
+
 JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name));
 JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags));
 JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty));
 JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty));
 JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty));
 JS_STATIC_ASSERT(offsetof(JSClass, setProperty) == offsetof(Class, setProperty));
 JS_STATIC_ASSERT(offsetof(JSClass, enumerate) == offsetof(Class, enumerate));
 JS_STATIC_ASSERT(offsetof(JSClass, resolve) == offsetof(Class, resolve));
 JS_STATIC_ASSERT(offsetof(JSClass, convert) == offsetof(Class, convert));
 JS_STATIC_ASSERT(offsetof(JSClass, finalize) == offsetof(Class, finalize));
-JS_STATIC_ASSERT(offsetof(JSClass, getObjectOps) == offsetof(Class, getObjectOps));
+JS_STATIC_ASSERT(offsetof(JSClass, reserved0) == offsetof(Class, reserved0));
 JS_STATIC_ASSERT(offsetof(JSClass, checkAccess) == offsetof(Class, checkAccess));
 JS_STATIC_ASSERT(offsetof(JSClass, call) == offsetof(Class, call));
 JS_STATIC_ASSERT(offsetof(JSClass, construct) == offsetof(Class, construct));
 JS_STATIC_ASSERT(offsetof(JSClass, xdrObject) == offsetof(Class, xdrObject));
 JS_STATIC_ASSERT(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance));
 JS_STATIC_ASSERT(offsetof(JSClass, mark) == offsetof(Class, mark));
-JS_STATIC_ASSERT(offsetof(JSClass, reserved0) == offsetof(Class, reserved0));
 JS_STATIC_ASSERT(sizeof(JSClass) == sizeof(Class));
 
-struct ExtendedClass {
-    Class               base;
-    EqualityOp          equality;
-    JSObjectOp          outerObject;
-    JSObjectOp          innerObject;
-    JSIteratorOp        iteratorObject;
-    JSObjectOp          wrappedObject;          /* NB: infallible, null
-                                                   returns are treated as
-                                                   the original object */
-    void                (*reserved0)(void);
-    void                (*reserved1)(void);
-    void                (*reserved2)(void);
-};
-JS_STATIC_ASSERT(offsetof(JSExtendedClass, base) == offsetof(ExtendedClass, base));
-JS_STATIC_ASSERT(offsetof(JSExtendedClass, equality) == offsetof(ExtendedClass, equality));
-JS_STATIC_ASSERT(offsetof(JSExtendedClass, outerObject) == offsetof(ExtendedClass, outerObject));
-JS_STATIC_ASSERT(offsetof(JSExtendedClass, innerObject) == offsetof(ExtendedClass, innerObject));
-JS_STATIC_ASSERT(offsetof(JSExtendedClass, iteratorObject) == offsetof(ExtendedClass, iteratorObject));
-JS_STATIC_ASSERT(offsetof(JSExtendedClass, wrappedObject) == offsetof(ExtendedClass, wrappedObject));
-JS_STATIC_ASSERT(offsetof(JSExtendedClass, reserved0) == offsetof(ExtendedClass, reserved0));
-JS_STATIC_ASSERT(offsetof(JSExtendedClass, reserved1) == offsetof(ExtendedClass, reserved1));
-JS_STATIC_ASSERT(offsetof(JSExtendedClass, reserved2) == offsetof(ExtendedClass, reserved2));
-JS_STATIC_ASSERT(sizeof(JSExtendedClass) == sizeof(ExtendedClass));
-
 struct PropertyDescriptor {
     JSObject     *obj;
     uintN        attrs;
     PropertyOp   getter;
     PropertyOp   setter;
     Value        value;
     uintN        shortid;
 };
@@ -903,18 +935,16 @@ JS_STATIC_ASSERT(offsetof(JSPropertyDesc
 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, getter) == offsetof(PropertyDescriptor, getter));
 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, setter) == offsetof(PropertyDescriptor, setter));
 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, value) == offsetof(PropertyDescriptor, value));
 JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, shortid) == offsetof(PropertyDescriptor, shortid));
 JS_STATIC_ASSERT(sizeof(JSPropertyDescriptor) == sizeof(PropertyDescriptor));
 
 static JS_ALWAYS_INLINE JSClass *              Jsvalify(Class *c)                { return (JSClass *)c; }
 static JS_ALWAYS_INLINE Class *                Valueify(JSClass *c)              { return (Class *)c; }
-static JS_ALWAYS_INLINE JSExtendedClass *      Jsvalify(ExtendedClass *c)        { return (JSExtendedClass *)c; }
-static JS_ALWAYS_INLINE ExtendedClass *        Valueify(JSExtendedClass *c)      { return (ExtendedClass *)c; }
 static JS_ALWAYS_INLINE JSPropertyDescriptor * Jsvalify(PropertyDescriptor *p) { return (JSPropertyDescriptor *) p; }
 static JS_ALWAYS_INLINE PropertyDescriptor *   Valueify(JSPropertyDescriptor *p) { return (PropertyDescriptor *) p; }
 
 /******************************************************************************/
 
 /*
  * In some cases (quickstubs) we want to take a value in whatever manner is
  * appropriate for the architecture and normalize to a const js::Value &. On
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -679,17 +679,17 @@ JSCrossCompartmentWrapper::enumerateOwn(
  * 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() == &js_IteratorClass.base &&
+           (obj = &vp->toObject())->getClass() == &js_IteratorClass &&
            (obj->getNativeIterator()->flags & JSITER_ENUMERATE);
 }
 
 static bool
 Reify(JSContext *cx, JSCompartment *origin, Value *vp)
 {
     JSObject *iterObj = &vp->toObject();
     NativeIterator *ni = iterObj->getNativeIterator();
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -185,17 +185,17 @@ GetLocalName(const JSObject *obj)
     return JSVAL_TO_STRING(v);
 }
 
 static JSBool
 IsDeclared(const JSObject *obj)
 {
     jsval v;
 
-    JS_ASSERT(obj->getClass() == &js_NamespaceClass.base);
+    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, JSObject *obj, uintN argc, jsval *argv,
               jsval *rval)
@@ -219,51 +219,67 @@ AppendString(JSCharBuffer &cb, JSString 
         code;                                                                  \
         return true;                                                           \
     }
 
 /*
  * Namespace class and library functions.
  */
 DEFINE_GETTER(NamePrefix_getter,
-              if (obj->getClass() == &js_NamespaceClass.base) *vp = obj->getNamePrefix())
+              if (obj->getClass() == &js_NamespaceClass) *vp = obj->getNamePrefix())
 DEFINE_GETTER(NameURI_getter,
-              if (obj->getClass() == &js_NamespaceClass.base) *vp = obj->getNameURI())
+              if (obj->getClass() == &js_NamespaceClass) *vp = obj->getNameURI())
 
 static void
 namespace_finalize(JSContext *cx, JSObject *obj)
 {
     if (cx->runtime->functionNamespaceObject == obj)
         cx->runtime->functionNamespaceObject = NULL;
 }
 
 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() != &js_NamespaceClass.base)
+    *bp = (!obj2 || obj2->getClass() != &js_NamespaceClass)
           ? JS_FALSE
           : js_EqualStrings(GetURI(obj), GetURI(obj2));
     return JS_TRUE;
 }
 
-JS_FRIEND_DATA(ExtendedClass) js_NamespaceClass = {
-  { "Namespace",
-    JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED |
+JS_FRIEND_DATA(Class) js_NamespaceClass = {
+    "Namespace",
+    JSCLASS_CONSTRUCT_PROTOTYPE |
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::NAMESPACE_FIXED_RESERVED_SLOTS) |
     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Namespace),
-    PropertyStub,      PropertyStub,      PropertyStub,      PropertyStub,
-    EnumerateStub,     ResolveStub,       ConvertStub,       namespace_finalize,
-    NULL,              NULL,              NULL,              NULL,
-    NULL,              NULL,              NULL,              NULL },
-    namespace_equality,NULL,              NULL,              NULL,
-    NULL,              NULL,              NULL,              NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    namespace_finalize,
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    NULL,           /* mark        */
+    {
+        namespace_equality,
+        NULL,       /* outerObject    */
+        NULL,       /* innerObject    */
+        NULL,       /* iteratorObject */
+        NULL,       /* wrappedObject  */
+    }
 };
 
 #define NAMESPACE_ATTRS                                                       \
     (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED)
 
 static JSPropertySpec namespace_props[] = {
     {js_prefix_str, 0, NAMESPACE_ATTRS, NamePrefix_getter, 0},
     {js_uri_str,    0, NAMESPACE_ATTRS, NameURI_getter,    0},
@@ -271,33 +287,33 @@ static JSPropertySpec namespace_props[] 
 };
 
 static JSBool
 namespace_toString(JSContext *cx, uintN argc, jsval *vp)
 {
     JSObject *obj;
 
     obj = JS_THIS_OBJECT(cx, vp);
-    if (!JS_InstanceOf(cx, obj, Jsvalify(&js_NamespaceClass.base), vp + 2))
+    if (!JS_InstanceOf(cx, obj, Jsvalify(&js_NamespaceClass), vp + 2))
         return JS_FALSE;
     *vp = obj->getNameURI();
     return JS_TRUE;
 }
 
 static JSFunctionSpec namespace_methods[] = {
     JS_FN(js_toString_str,  namespace_toString,        0,0),
     JS_FS_END
 };
 
 static JSObject *
 NewXMLNamespace(JSContext *cx, JSString *prefix, JSString *uri, JSBool declared)
 {
     JSObject *obj;
 
-    obj = NewBuiltinClassInstance(cx, &js_NamespaceClass.base);
+    obj = NewBuiltinClassInstance(cx, &js_NamespaceClass);
     if (!obj)
         return JS_FALSE;
     JS_ASSERT(JSVAL_IS_VOID(obj->getNamePrefix()));
     JS_ASSERT(JSVAL_IS_VOID(obj->getNameURI()));
     JS_ASSERT(JSVAL_IS_VOID(obj->getNamespaceDeclared()));
     if (prefix)
         obj->setNamePrefix(STRING_TO_JSVAL(prefix));
     if (uri)
@@ -307,20 +323,20 @@ NewXMLNamespace(JSContext *cx, JSString 
     METER(xml_stats.xmlnamespace);
     return obj;
 }
 
 /*
  * QName class and library functions.
  */
 DEFINE_GETTER(QNameNameURI_getter,
-              if (obj->getClass() == &js_QNameClass.base)
+              if (obj->getClass() == &js_QNameClass)
                   *vp = JSVAL_IS_VOID(obj->getNameURI()) ? JSVAL_NULL : obj->getNameURI())
 DEFINE_GETTER(QNameLocalName_getter,
-              if (obj->getClass() == &js_QNameClass.base)
+              if (obj->getClass() == &js_QNameClass)
                   *vp = obj->getQNameLocalName())
 
 static void
 anyname_finalize(JSContext* cx, JSObject* obj)
 {
     /* Make sure the next call to js_GetAnyName doesn't try to use obj. */
     if (cx->runtime->anynameObject == obj)
         cx->runtime->anynameObject = NULL;
@@ -340,65 +356,87 @@ 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() != &js_QNameClass.base)
+    *bp = (!obj2 || obj2->getClass() != &js_QNameClass)
           ? JS_FALSE
           : qname_identity(qn, obj2);
     return JS_TRUE;
 }
 
-JS_FRIEND_DATA(ExtendedClass) js_QNameClass = {
-  { "QName",
-    JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED |
+JS_FRIEND_DATA(Class) js_QNameClass = {
+    "QName",
+    JSCLASS_CONSTRUCT_PROTOTYPE |
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_FIXED_RESERVED_SLOTS) |
     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_QName),
-    PropertyStub,      PropertyStub,      PropertyStub,      PropertyStub,
-    EnumerateStub,     ResolveStub,       ConvertStub,       NULL,
-    NULL,              NULL,              NULL,              NULL,
-    NULL,              NULL,              NULL,              NULL },
-    qname_equality,    NULL,              NULL,              NULL,
-    NULL,              NULL,              NULL,              NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    FinalizeStub,
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    NULL,           /* mark        */
+    {
+        qname_equality,
+        NULL,       /* outerObject    */
+        NULL,       /* innerObject    */
+        NULL,       /* iteratorObject */
+        NULL,       /* wrappedObject  */
+    }
 };
 
 /*
  * 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_AttributeName_str,
     JSCLASS_CONSTRUCT_PROTOTYPE |
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_FIXED_RESERVED_SLOTS) |
     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_AttributeName),
-    PropertyStub,      PropertyStub,      PropertyStub,      PropertyStub,
-    EnumerateStub,     ResolveStub,       ConvertStub,       NULL,
-    NULL,              NULL,              NULL,              NULL,
-    NULL,              NULL,              NULL,              NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub
 };
 
 JS_FRIEND_DATA(Class) js_AnyNameClass = {
     js_AnyName_str,
     JSCLASS_CONSTRUCT_PROTOTYPE |
     JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_FIXED_RESERVED_SLOTS) |
     JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_AnyName),
-    PropertyStub,      PropertyStub,      PropertyStub,      PropertyStub,
-    EnumerateStub,     ResolveStub,       ConvertStub,       anyname_finalize,
-    NULL,              NULL,              NULL,              NULL,
-    NULL,              NULL,              NULL,              NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    anyname_finalize
 };
 
-#define QNAME_ATTRS                                                           \
-    (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED)
+#define QNAME_ATTRS (JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED)
 
 static JSPropertySpec qname_props[] = {
     {js_uri_str,       0, QNAME_ATTRS, QNameNameURI_getter,   0},
     {js_localName_str, 0, QNAME_ATTRS, QNameLocalName_getter, 0},
     {0,0,0,0,0}
 };
 
 static JSBool
@@ -411,17 +449,17 @@ qname_toString(JSContext *cx, uintN argc
     jschar *chars;
 
     obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
     clasp = obj->getClass();
     if (clasp != &js_AttributeNameClass &&
         clasp != &js_AnyNameClass &&
-        !JS_InstanceOf(cx, obj, Jsvalify(&js_QNameClass.base), vp + 2)) {
+        !JS_InstanceOf(cx, obj, Jsvalify(&js_QNameClass), vp + 2)) {
             return JS_FALSE;
     }
 
     uri = GetURI(obj);
     if (!uri) {
         /* No uri means wildcard qualifier. */
         str = ATOM_TO_STRING(cx->runtime->atomState.starQualifierAtom);
     } else if (uri->empty()) {
@@ -474,17 +512,17 @@ InitXMLQName(JSObject *obj, JSString *ur
     if (prefix)
         obj->setNamePrefix(STRING_TO_JSVAL(prefix));
     if (localName)
         obj->setQNameLocalName(STRING_TO_JSVAL(localName));
 }
 
 static JSObject *
 NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix, JSString *localName,
-            Class *clasp = &js_QNameClass.base)
+            Class *clasp = &js_QNameClass)
 {
     JSObject *obj = NewBuiltinClassInstance(cx, clasp);
     if (!obj)
         return NULL;
     JS_ASSERT(obj->isQName());
     InitXMLQName(obj, uri, prefix, localName);
     METER(xml_stats.qname);
     return obj;
@@ -502,17 +540,17 @@ js_ConstructXMLQNameObject(JSContext *cx
      */
     if (nsval.isObject() &&
         nsval.toObject().getClass() == &js_AnyNameClass) {
         argv[0].setNull();
     } else {
         argv[0] = nsval;
     }
     argv[1] = lnval;
-    return js_ConstructObject(cx, &js_QNameClass.base, 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;
 
@@ -576,30 +614,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 == &js_NamespaceClass.base);
-            isQName = (clasp == &js_QNameClass.base);
+            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 = NewBuiltinClassInstance(cx, &js_NamespaceClass.base);
+        obj = NewBuiltinClassInstance(cx, &js_NamespaceClass);
         if (!obj)
             return JS_FALSE;
         *rval = OBJECT_TO_JSVAL(obj);
     }
     METER(xml_stats.xmlnamespace);
 
     empty = cx->runtime->emptyString;
     obj->setNamePrefix(STRING_TO_JSVAL(empty));
@@ -672,26 +710,26 @@ QNameHelper(JSContext *cx, JSObject *obj
             jsval *argv, jsval *rval)
 {
     jsval nameval, nsval;
     JSBool isQName, isNamespace;
     JSObject *qn;
     JSString *uri, *prefix, *name;
     JSObject *obj2;
 
-    JS_ASSERT(clasp == &js_QNameClass.base ||
+    JS_ASSERT(clasp == &js_QNameClass ||
               clasp == &js_AttributeNameClass);
     if (argc <= 0) {
         nameval = JSVAL_VOID;
         isQName = JS_FALSE;
     } else {
         nameval = argv[argc > 1];
         isQName =
             !JSVAL_IS_PRIMITIVE(nameval) &&
-            JSVAL_TO_OBJECT(nameval)->getClass() == &js_QNameClass.base;
+            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;
@@ -737,17 +775,17 @@ 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() ==
-                  &js_NamespaceClass.base);
+                  &js_NamespaceClass);
     }
 
     if (JSVAL_IS_NULL(nsval)) {
         /* NULL prefix represents *undefined* in ECMA-357 13.3.2 5(a). */
         uri = prefix = NULL;
     } else {
         /*
          * Inline specialization of the Namespace constructor called with
@@ -755,18 +793,18 @@ QNameHelper(JSContext *cx, JSObject *obj
          * 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);
             clasp = obj2->getClass();
-            isNamespace = (clasp == &js_NamespaceClass.base);
-            isQName = (clasp == &js_QNameClass.base);
+            isNamespace = (clasp == &js_NamespaceClass);
+            isQName = (clasp == &js_QNameClass);
         }
 #ifdef __GNUC__         /* suppress bogus gcc warnings */
         else obj2 = NULL;
 #endif
 
         if (isNamespace) {
             uri = GetURI(obj2);
             prefix = GetPrefix(obj2);
@@ -789,17 +827,17 @@ out:
     InitXMLQName(obj, uri, prefix, name);
     return JS_TRUE;
 }
 
 static JSBool
 QName(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval)
 {
     return QNameHelper(cx, cx->isConstructing() ? obj : NULL,
-                       &js_QNameClass.base, argc, Jsvalify(argv), Jsvalify(rval));
+                       &js_QNameClass, argc, Jsvalify(argv), Jsvalify(rval));
 }
 
 static JSBool
 AttributeName(JSContext *cx, JSObject *obj, uintN argc, Value *argv,
               Value *rval)
 {
     return QNameHelper(cx, cx->isConstructing() ? obj : NULL,
                        &js_AttributeNameClass, argc, Jsvalify(argv), Jsvalify(rval));
@@ -2154,17 +2192,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, &js_NamespaceClass.base, NULL, NULL,
+        ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL,
                                 2, Valueify(argv));
         if (!ns)
             return NULL;
         match = ns;
     }
     return match;
 }
 
@@ -2709,17 +2747,17 @@ ToAttributeName(JSContext *cx, jsval v)
             return NULL;
         }
 
         obj = JSVAL_TO_OBJECT(v);
         clasp = obj->getClass();
         if (clasp == &js_AttributeNameClass)
             return obj;
 
-        if (clasp == &js_QNameClass.base) {
+        if (clasp == &js_QNameClass) {
             qn = obj;
             uri = GetURI(qn);
             prefix = GetPrefix(qn);
             name = GetLocalName(qn);
         } else {
             if (clasp == &js_AnyNameClass) {
                 name = ATOM_TO_STRING(cx->runtime->atomState.starAtom);
             } else {
@@ -2758,17 +2796,17 @@ IsFunctionQName(JSContext *cx, JSObject 
     }
     *funidp = JSID_VOID;
     return JS_TRUE;
 }
 
 JSBool
 js_IsFunctionQName(JSContext *cx, JSObject *obj, jsid *funidp)
 {
-    if (obj->getClass() == &js_QNameClass.base)
+    if (obj->getClass() == &js_QNameClass)
         return IsFunctionQName(cx, obj, funidp);
     *funidp = JSID_VOID;
     return JS_TRUE;
 }
 
 static JSObject *
 ToXMLName(JSContext *cx, jsval v, jsid *funidp)
 {
@@ -2783,17 +2821,17 @@ 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 == &js_AttributeNameClass || clasp == &js_QNameClass.base)
+        if (clasp == &js_AttributeNameClass || clasp == &js_QNameClass)
             goto out;
         if (clasp == &js_AnyNameClass) {
             name = ATOM_TO_STRING(cx->runtime->atomState.starAtom);
             goto construct;
         }
         name = js_ValueToString(cx, Valueify(v));
         if (!name)
             return NULL;
@@ -2824,17 +2862,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, &js_QNameClass.base, NULL, NULL, 1, Valueify(&v));
+    obj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, Valueify(&v));
     if (!obj)
         return NULL;
 
 out:
     if (!IsFunctionQName(cx, obj, funidp))
         return NULL;
     return obj;
 
@@ -4596,23 +4634,23 @@ xml_trace_vector(JSTracer *trc, JSXML **
         if (xml) {
             JS_SET_TRACING_INDEX(trc, "xml_vector", i);
             Mark(trc, xml, JSTRACE_XML);
         }
     }
 }
 
 /*
- * js_XMLObjectOps.newObjectMap is null, so XML objects appear to be native.
- * Thus xml_lookupProperty must return a valid JSScopeProperty pointer
- * parameter via *propp to signify "property found".  Since the only call to
- * xml_lookupProperty is via JSObject::lookupProperty, and then only from
- * js_FindProperty (in jsobj.c, called from jsinterp.c) or from JSOP_IN case
- * in the interpreter, the only time we add a JSScopeProperty here is when an
- * unqualified name is being accessed or when "name in xml" is called.
+ * XML objects are native. Thus xml_lookupProperty must return a valid
+ * JSScopeProperty pointer parameter via *propp to signify "property found".
+ * Since the only call to xml_lookupProperty is via JSObject::lookupProperty,
+ * and then only from js_FindProperty (in jsobj.c, called from jsinterp.c) or
+ * from JSOP_IN case in the interpreter, the only time we add a
+ * JSScopeProperty here is when an unqualified name is being accessed or when
+ * "name in xml" is called.
  *
  * This scope property keeps the JSOP_NAME code in js_Interpret happy by
  * giving it an sprop with (getter, setter) == (GetProperty, PutProperty).
  *
  * NB: xml_deleteProperty must take care to remove any property added here.
  *
  * FIXME This clashes with the function namespace implementation which also
  * uses native properties. Effectively after xml_lookupProperty any property
@@ -5025,47 +5063,49 @@ js_ConcatenateXML(JSContext *cx, JSObjec
         goto out;
 
     vp->setObject(*listobj);
 out:
     js_LeaveLocalRootScopeWithResult(cx, *vp);
     return ok;
 }
 
-/* Use NULL for objectMap so XML objects satisfy obj->isNative() tests. */
-JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps = {
-    NULL,
-    xml_lookupProperty,
-    xml_defineProperty,
-    xml_getProperty,
-    xml_setProperty,
-    xml_getAttributes,
-    xml_setAttributes,
-    xml_deleteProperty,
-    xml_enumerate,
-    xml_typeOf,
-    js_TraceObject,
-    NULL,   /* thisObject */
-    xml_clear
-};
-
-static JSObjectOps *
-xml_getObjectOps(JSContext *cx, Class *clasp)
-{
-    return &js_XMLObjectOps;
-}
-
 JS_FRIEND_DATA(Class) js_XMLClass = {
     js_XML_str,
-    JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_XML),
-    PropertyStub,      PropertyStub,      PropertyStub,      PropertyStub,
-    EnumerateStub,     ResolveStub,       xml_convert,       xml_finalize,
-    xml_getObjectOps,  NULL,              NULL,              NULL,
-    NULL,              xml_hasInstance,   JS_CLASS_TRACE(xml_trace), NULL
+    JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_XML),
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    xml_convert,
+    xml_finalize,
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    xml_hasInstance,
+    JS_CLASS_TRACE(xml_trace),
+    JS_NULL_CLASS_EXT,
+    {
+        xml_lookupProperty,
+        xml_defineProperty,
+        xml_getProperty,
+        xml_setProperty,
+        xml_getAttributes,
+        xml_setAttributes,
+        xml_deleteProperty,
+        xml_enumerate,
+        xml_typeOf,
+        NULL,       /* trace */
+        NULL,       /* thisObject     */
+        xml_clear
+    }
 };
 
 static JSXML *
 StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp)
 {
     JSXML *xml;
     JSFunction *fun;
     char numBuf[12];
@@ -6249,17 +6289,17 @@ xml_replace(JSContext *cx, uintN argc, j
     if (!xml)
         return JS_FALSE;
 
     if (argc == 0 || !js_IdValIsIndex(vp[2], &index)) {
         /*
          * Call function QName per spec, not ToXMLName, to avoid attribute
          * names.
          */
-        if (!QNameHelper(cx, NULL, &js_QNameClass.base, argc == 0 ? -1 : 1,
+        if (!QNameHelper(cx, NULL, &js_QNameClass, argc == 0 ? -1 : 1,
                          vp + 2, vp)) {
             return JS_FALSE;
         }
         JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp));
         nameqn = JSVAL_TO_OBJECT(*vp);
 
         i = xml->xml_kids.length;
         index = XML_NOT_FOUND;
@@ -6312,17 +6352,17 @@ xml_setLocalName(JSContext *cx, uintN ar
     if (!JSXML_HAS_NAME(xml))
         return JS_TRUE;
 
     if (argc == 0) {
         namestr = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
     } else {
         name = vp[2];
         if (!JSVAL_IS_PRIMITIVE(name) &&
-            JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass.base) {
+            JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass) {
             nameqn = JSVAL_TO_OBJECT(name);
             namestr = GetLocalName(nameqn);
         } else {
             if (!JS_ConvertValue(cx, name, JSTYPE_STRING, &vp[2]))
                 return JS_FALSE;
             name = vp[2];
             namestr = JSVAL_TO_STRING(name);
         }
@@ -6349,23 +6389,23 @@ xml_setName(JSContext *cx, uintN argc, j
     if (!JSXML_HAS_NAME(xml))
         return JS_TRUE;
 
     if (argc == 0) {
         name = ATOM_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]);
     } else {
         name = vp[2];
         if (!JSVAL_IS_PRIMITIVE(name) &&
-            JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass.base &&
+            JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass &&
             !GetURI(nameqn = JSVAL_TO_OBJECT(name))) {
             name = vp[2] = nameqn->getQNameLocalName();
         }
     }
 
-    nameqn = js_ConstructObject(cx, &js_QNameClass.base, 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(STRING_TO_JSVAL(cx->runtime->emptyString));
 
     xml = CHECK_COPY_ON_WRITE(cx, xml, obj);
@@ -6454,26 +6494,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, &js_NamespaceClass.base, 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] = vp[2] = OBJECT_TO_JSVAL(ns);
     qnargv[1] = OBJECT_TO_JSVAL(xml->name);
-    qn = js_ConstructObject(cx, &js_QNameClass.base, 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.
@@ -6990,24 +7030,24 @@ js_GetXMLObject(JSContext *cx, JSXML *xm
         return NULL;
     xml->object = obj;
     return obj;
 }
 
 JSObject *
 js_InitNamespaceClass(JSContext *cx, JSObject *obj)
 {
-    return js_InitClass(cx, obj, NULL, &js_NamespaceClass.base, Namespace, 2,
+    return js_InitClass(cx, obj, NULL, &js_NamespaceClass, Namespace, 2,
                         namespace_props, namespace_methods, NULL, NULL);
 }
 
 JSObject *
 js_InitQNameClass(JSContext *cx, JSObject *obj)
 {
-    return js_InitClass(cx, obj, NULL, &js_QNameClass.base, QName, 2,
+    return js_InitClass(cx, obj, NULL, &js_QNameClass, QName, 2,
                         qname_props, qname_methods, NULL, NULL);
 }
 
 JSObject *
 js_InitAttributeNameClass(JSContext *cx, JSObject *obj)
 {
     return js_InitClass(cx, obj, NULL, &js_AttributeNameClass, AttributeName, 2,
                         qname_props, qname_methods, NULL, NULL);
@@ -7193,17 +7233,17 @@ js_GetDefaultXMLNamespace(JSContext *cx,
             return JS_FALSE;
         if (!JSVAL_IS_PRIMITIVE(v)) {
             *vp = v;
             return JS_TRUE;
         }
         obj = tmp;
     }
 
-    ns = js_ConstructObject(cx, &js_NamespaceClass.base, 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, PropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
     }
     *vp = v;
@@ -7214,17 +7254,17 @@ JSBool
 js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
 {
     Value argv[2];
     JSObject *ns, *varobj;
     JSStackFrame *fp;
 
     argv[0].setString(cx->runtime->emptyString);
     argv[1] = v;
-    ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, NULL, 2, argv);
+    ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, 2, argv);
     if (!ns)
         return JS_FALSE;
 
     fp = js_GetTopStackFrame(cx);
     varobj = fp->varobj(cx);
     if (!varobj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
                                 PropertyStub, PropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
@@ -7380,23 +7420,23 @@ js_FindXMLProperty(JSContext *cx, const 
     JSBool found;
     JSProperty *prop;
     const char *printable;
 
     JS_ASSERT(nameval.isObject());
     nameobj = &nameval.toObject();
     if (nameobj->getClass() == &js_AnyNameClass) {
         v = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom);
-        nameobj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1,
+        nameobj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1,
                                      Valueify(&v));
         if (!nameobj)
             return JS_FALSE;
     } else {
         JS_ASSERT(nameobj->getClass() == &js_AttributeNameClass ||
-                  nameobj->getClass() == &js_QNameClass.base);
+                  nameobj->getClass() == &js_QNameClass);
     }
 
     qn = nameobj;
     if (!IsFunctionQName(cx, qn, &funid))
         return JS_FALSE;
 
     obj = js_GetTopStackFrame(cx)->scopeChain;
     do {
@@ -7561,20 +7601,31 @@ xmlfilter_finalize(JSContext *cx, JSObje
         return;
 
     cx->destroy(filter);
 }
 
 Class js_XMLFilterClass = {
     "XMLFilter",
     JSCLASS_HAS_PRIVATE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
-    PropertyStub,      PropertyStub,    PropertyStub,      PropertyStub,
-    EnumerateStub,     ResolveStub,     ConvertStub,       xmlfilter_finalize,
-    NULL,              NULL,            NULL,              NULL,
-    NULL,              NULL,            JS_CLASS_TRACE(xmlfilter_trace), NULL
+    PropertyStub,   /* addProperty */
+    PropertyStub,   /* delProperty */
+    PropertyStub,   /* getProperty */
+    PropertyStub,   /* setProperty */
+    EnumerateStub,
+    ResolveStub,
+    ConvertStub,
+    xmlfilter_finalize,
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    JS_CLASS_TRACE(xmlfilter_trace)
 };
 
 JSBool
 js_StepXMLListFilter(JSContext *cx, JSBool initialized)
 {
     jsval *sp;
     JSObject *obj, *filterobj, *resobj, *kidobj;
     JSXML *xml, *list;
--- a/js/src/jsxml.h
+++ b/js/src/jsxml.h
@@ -211,55 +211,54 @@ extern void
 js_FinalizeXML(JSContext *cx, JSXML *xml);
 
 extern JSObject *
 js_NewXMLObject(JSContext *cx, JSXMLClass xml_class);
 
 extern JSObject *
 js_GetXMLObject(JSContext *cx, JSXML *xml);
 
-extern JS_FRIEND_DATA(JSObjectOps)       js_XMLObjectOps;
-extern JS_FRIEND_DATA(js::Class)         js_XMLClass;
-extern JS_FRIEND_DATA(js::ExtendedClass) js_NamespaceClass;
-extern JS_FRIEND_DATA(js::ExtendedClass) js_QNameClass;
-extern JS_FRIEND_DATA(js::Class)         js_AttributeNameClass;
-extern JS_FRIEND_DATA(js::Class)         js_AnyNameClass;
-extern js::Class                         js_XMLFilterClass;
+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 map->ops == &js_XMLObjectOps;
+    return getClass() == &js_XMLClass;
 }
 
 inline bool
 JSObject::isXMLId() const
 {
     js::Class *clasp = getClass();
-    return clasp == &js_QNameClass.base ||
+    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.base;
+    return getClass() == &js_NamespaceClass;
 }
 
 inline bool
 JSObject::isQName() const
 {
     js::Class* clasp = getClass();
-    return clasp == &js_QNameClass.base ||
+    return clasp == &js_QNameClass ||
            clasp == &js_AttributeNameClass ||
            clasp == &js_AnyNameClass;
 }
 
 static inline bool
 IsXML(const js::Value &v)
 {
     return v.isObject() && v.toObject().isXML();
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -2483,17 +2483,17 @@ mjit::Compiler::jsop_bindname(uint32 ind
 
     pic.shapeReg = frame.allocReg();
     pic.objReg = frame.allocReg();
     pic.typeReg = Registers::ReturnReg;
     pic.atom = script->getAtom(index);
     pic.hasTypeCheck = false;
     pic.hotPathBegin = masm.label();
 
-    Address parent(pic.objReg, offsetof(JSObject, fslots) + JSSLOT_PARENT * sizeof(jsval));
+    Address parent(pic.objReg, offsetof(JSObject, parent));
     masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, scopeChain)), pic.objReg);
 
     pic.shapeGuard = masm.label();
 #if defined JS_NUNBOX32
     Jump j = masm.branchPtr(Assembler::NotEqual, masm.payloadOf(parent), ImmPtr(0));
 #elif defined JS_PUNBOX64
     masm.loadPayload(parent, Registers::ValueReg);
     Jump j = masm.branchPtr(Assembler::NotEqual, Registers::ValueReg, ImmPtr(0));
@@ -2795,17 +2795,17 @@ mjit::Compiler::iterNext()
 
     /* Is it worth trying to pin this longer? Prolly not. */
     frame.pinReg(reg);
     RegisterID T1 = frame.allocReg();
     frame.unpinReg(reg);
 
     /* Test clasp */
     masm.loadPtr(Address(reg, offsetof(JSObject, clasp)), T1);
-    Jump notFast = masm.branchPtr(Assembler::NotEqual, T1, ImmPtr(&js_IteratorClass.base));
+    Jump notFast = masm.branchPtr(Assembler::NotEqual, T1, ImmPtr(&js_IteratorClass));
     stubcc.linkExit(notFast, Uses(1));
 
     /* Get private from iter obj. */
     masm.loadFunctionPrivate(reg, T1);
 
     RegisterID T3 = frame.allocReg();
     RegisterID T4 = frame.allocReg();
 
@@ -2851,17 +2851,17 @@ mjit::Compiler::iterMore()
     RegisterID reg = frame.tempRegForData(fe);
 
     frame.pinReg(reg);
     RegisterID T1 = frame.allocReg();
     frame.unpinReg(reg);
 
     /* Test clasp */
     masm.loadPtr(Address(reg, offsetof(JSObject, clasp)), T1);
-    Jump notFast = masm.branchPtr(Assembler::NotEqual, T1, ImmPtr(&js_IteratorClass.base));
+    Jump notFast = masm.branchPtr(Assembler::NotEqual, T1, ImmPtr(&js_IteratorClass));
     stubcc.linkExit(notFast, Uses(1));
 
     /* Get private from iter obj. */
     masm.loadFunctionPrivate(reg, T1);
 
     /* Get props_cursor, test */
     RegisterID T2 = frame.allocReg();
     frame.forgetEverything();
@@ -3169,18 +3169,18 @@ mjit::Compiler::jsop_instanceof()
     RegisterID temp = frame.allocReg();
 
     MaybeJump isFalse;
     if (!lhs->isTypeKnown())
         isFalse = frame.testPrimitive(Assembler::Equal, lhs);
 
     /* Quick test to avoid wrapped objects. */
     masm.loadPtr(Address(obj, offsetof(JSObject, clasp)), temp);
-    masm.load32(Address(temp, offsetof(JSClass, flags)), temp);
-    masm.and32(Imm32(JSCLASS_IS_EXTENDED), temp);
+    masm.load32(Address(temp, offsetof(Class, ext)), temp);
+    masm.load32(Address(temp, offsetof(ClassExtension, wrappedObject)), temp);
     j = masm.branchTest32(Assembler::NonZero, temp, temp);
     stubcc.linkExit(j, Uses(3));
 
     Address protoAddr(obj, offsetof(JSObject, proto));
     Label loop = masm.label();
 
     /* Walk prototype chain, break out on NULL or hit. */
     masm.loadPayload(protoAddr, obj);
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -1271,17 +1271,17 @@ class ScopeNameCompiler : public PICStub
             
             /* Guard on intervening shapes. */
             masm.loadShape(pic.objReg, pic.shapeReg);
             Jump j = masm.branch32(Assembler::NotEqual, pic.shapeReg, Imm32(tobj->shape()));
             if (!fails.append(j))
                 return false;
 
             /* Load the next link in the scope chain. */
-            Address parent(pic.objReg, offsetof(JSObject, fslots) + JSSLOT_PARENT * sizeof(Value));
+            Address parent(pic.objReg, offsetof(JSObject, parent));
             masm.load32(parent, pic.objReg);
 
             tobj = tobj->getParent();
         }
 
         found = tobj == holder;
 
         return true;
@@ -1535,17 +1535,17 @@ class BindNameCompiler : public PICStubC
         /* Guard on the shape of the scope chain. */
         masm.load32(Address(JSFrameReg, offsetof(JSStackFrame, scopeChain)), pic.objReg);
         masm.loadShape(pic.objReg, pic.shapeReg);
         Jump firstShape = masm.branch32(Assembler::NotEqual, pic.shapeReg,
                                         Imm32(scopeChain->shape()));
 
         /* Walk up the scope chain. */
         JSObject *tobj = scopeChain;
-        Address parent(pic.objReg, offsetof(JSObject, fslots) + JSSLOT_PARENT * sizeof(Value));
+        Address parent(pic.objReg, offsetof(JSObject, parent));
         while (tobj && tobj != obj) {
             if (!js_IsCacheableNonGlobalScope(tobj))
                 return disable("non-cacheable obj in scope chain");
             masm.load32(parent, pic.objReg);
             Jump nullTest = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg);
             if (!fails.append(nullTest))
                 return false;
             masm.loadShape(pic.objReg, pic.shapeReg);
@@ -1864,26 +1864,26 @@ ic::CallProp(VMFrame &f, uint32 index)
      */
     jsid id;
     id = ATOM_TO_JSID(origAtom);
 
     regs.sp++;
     regs.sp[-1].setNull();
     if (lval.isObject()) {
         if (!js_GetMethod(cx, &objv.toObject(), id,
-                          JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)
+                          JS_LIKELY(!js_GetProperty)
                           ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
                           : JSGET_NO_METHOD_BARRIER,
                           &rval)) {
             THROW();
         }
         regs.sp[-1] = objv;
         regs.sp[-2] = rval;
     } else {
-        JS_ASSERT(objv.toObject().map->ops->getProperty == js_GetProperty);
+        JS_ASSERT(!objv.toObject().getOps()->getProperty);
         if (!js_GetPropertyHelper(cx, &objv.toObject(), id,
                                   JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER,
                                   &rval)) {
             THROW();
         }
         regs.sp[-1] = lval;
         regs.sp[-2] = rval;
     }
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -282,17 +282,17 @@ mjit::stubs::SetName(VMFrame &f, JSAtom 
             }
             if (sprop)
                 break;
         }
 
         if (!atom)
             atom = origAtom;
         jsid id = ATOM_TO_JSID(atom);
-        if (entry && JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) {
+        if (entry && JS_LIKELY(obj->getOps()->setProperty == js_SetProperty)) {
             uintN defineHow;
             JSOp op = JSOp(*f.regs.pc);
             if (op == JSOP_SETMETHOD)
                 defineHow = JSDNP_CACHE_RESULT | JSDNP_SET_METHOD;
             else if (op == JSOP_SETNAME)
                 defineHow = JSDNP_CACHE_RESULT | JSDNP_UNQUALIFIED;
             else
                 defineHow = JSDNP_CACHE_RESULT;
@@ -424,17 +424,17 @@ stubs::GetGlobalName(VMFrame &f)
     JSObject *globalObj = f.fp->scopeChain->getGlobal();
     if (!NameOp(f, globalObj))
          THROW();
 }
 
 static inline bool
 IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
 {
-    if (iterobj->getClass() == &js_IteratorClass.base) {
+    if (iterobj->getClass() == &js_IteratorClass) {
         NativeIterator *ni = (NativeIterator *) iterobj->getPrivate();
         JS_ASSERT(ni->props_cursor < ni->props_end);
         if (ni->isKeyIter()) {
             jsid id = *ni->currentKey();
             if (JSID_IS_ATOM(id)) {
                 rval->setString(JSID_TO_STRING(id));
                 ni->incKeyCursor();
                 return true;
@@ -1011,17 +1011,16 @@ stubs::Not(VMFrame &f)
     JSBool b = !js_ValueToBoolean(f.regs.sp[-1]);
     f.regs.sp[-1].setBoolean(b);
 }
 
 template <JSBool EQ, bool IFNAN>
 static inline bool
 StubEqualityOp(VMFrame &f)
 {
-    Class *clasp;
     JSContext *cx = f.cx;
     JSFrameRegs &regs = f.regs;
 
     Value rval = regs.sp[-1];
     Value lval = regs.sp[-2];
 
     JSBool cond;
 
@@ -1043,19 +1042,18 @@ StubEqualityOp(VMFrame &f)
             double l = lval.toDouble();
             double r = rval.toDouble();
             if (EQ)
                 cond = JSDOUBLE_COMPARE(l, ==, r, IFNAN);
             else
                 cond = JSDOUBLE_COMPARE(l, !=, r, IFNAN);
         } else if (lval.isObject()) {
             JSObject *l = &lval.toObject(), *r = &rval.toObject();
-            if (((clasp = l->getClass())->flags & JSCLASS_IS_EXTENDED) &&
-                ((ExtendedClass  *)clasp)->equality) {
-                if (!((ExtendedClass *)clasp)->equality(cx, l, &rval, &cond))
+            if (EqualityOp eq = l->getClass()->ext.equality) {
+                if (!eq(cx, l, &rval, &cond))
                     return false;
                 cond = cond == EQ;
             } else {
                 cond = (l == r) == EQ;
             }
         } else if (lval.isNullOrUndefined()) {
             cond = EQ;
         } else {
@@ -1866,17 +1864,17 @@ InlineGetProp(VMFrame &f)
                 NATIVE_GET(cx, obj, obj2, sprop,
                         f.fp->imacpc ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
                         &rval, return false);
             }
             break;
         }
 
         jsid id = ATOM_TO_JSID(atom);
-        if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)
+        if (JS_LIKELY(!aobj->getOps()->getProperty)
                 ? !js_GetPropertyHelper(cx, obj, id,
                     f.fp->imacpc
                     ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
                     : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
                     &rval)
                 : !obj->getProperty(cx, id, &rval)) {
             return false;
         }
@@ -1956,26 +1954,26 @@ stubs::CallProp(VMFrame &f, JSAtom *orig
      */
     jsid id;
     id = ATOM_TO_JSID(origAtom);
 
     regs.sp++;
     regs.sp[-1].setNull();
     if (lval.isObject()) {
         if (!js_GetMethod(cx, &objv.toObject(), id,
-                          JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)
+                          JS_LIKELY(!aobj->getOps()->getProperty)
                           ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
                           : JSGET_NO_METHOD_BARRIER,
                           &rval)) {
             THROW();
         }
         regs.sp[-1] = objv;
         regs.sp[-2] = rval;
     } else {
-        JS_ASSERT(objv.toObject().map->ops->getProperty == js_GetProperty);
+        JS_ASSERT(!objv.toObject().getOps()->getProperty);
         if (!js_GetPropertyHelper(cx, &objv.toObject(), id,
                                   JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER,
                                   &rval)) {
             THROW();
         }
         regs.sp[-1] = lval;
         regs.sp[-2] = rval;
     }
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1411,17 +1411,17 @@ ValueToScript(JSContext *cx, jsval v)
     JSFunction *fun;
 
     if (!JSVAL_IS_PRIMITIVE(v)) {
         JSObject *obj = JSVAL_TO_OBJECT(v);
         JSClass *clasp = JS_GET_CLASS(cx, obj);
 
         if (clasp == Jsvalify(&js_ScriptClass)) {
             script = (JSScript *) JS_GetPrivate(cx, obj);
-        } else if (clasp == Jsvalify(&js_GeneratorClass.base)) {
+        } else if (clasp == Jsvalify(&js_GeneratorClass)) {
             JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj);
             fun = gen->getFloatingFrame()->fun;
             script = FUN_SCRIPT(fun);
         }
     }
 
     if (!script) {
         fun = JS_ValueToFunction(cx, v);
@@ -2761,28 +2761,16 @@ static JSObject *
 split_thisObject(JSContext *cx, JSObject *obj)
 {
     OBJ_TO_OUTER_OBJECT(cx, obj);
     if (!obj)
         return NULL;
     return obj;
 }
 
-static JSObjectOps split_objectops;
-
-static JSObjectOps *
-split_getObjectOps(JSContext *cx, JSClass *clasp)
-{
-    if (!split_objectops.thisObject) {
-        memcpy(&split_objectops, &js_ObjectOps, sizeof split_objectops);
-        split_objectops.thisObject = split_thisObject;
-    }
-
-    return &split_objectops;
-}
 
 static JSBool
 split_equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp);
 
 static JSObject *
 split_innerObject(JSContext *cx, JSObject *obj)
 {
     ComplexObject *cpx;
@@ -2790,40 +2778,66 @@ split_innerObject(JSContext *cx, JSObjec
     cpx = (ComplexObject *) JS_GetPrivate(cx, obj);
     if (cpx->frozen) {
         JS_ASSERT(!cpx->isInner);
         return obj;
     }
     return !cpx->isInner ? cpx->inner : obj;
 }
 
-static JSExtendedClass split_global_class = {
-    {"split_global",
-    JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE | JSCLASS_HAS_PRIVATE |
-    JSCLASS_GLOBAL_FLAGS | JSCLASS_IS_EXTENDED,
-    split_addProperty, split_delProperty,
-    split_getProperty, split_setProperty,
+static Class split_global_class = {
+    "split_global",
+    JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE | JSCLASS_HAS_PRIVATE | JSCLASS_GLOBAL_FLAGS,
+    Valueify(split_addProperty),
+    Valueify(split_delProperty),
+    Valueify(split_getProperty),
+    Valueify(split_setProperty),
     (JSEnumerateOp)split_enumerate,
     (JSResolveOp)split_resolve,
-    JS_ConvertStub, split_finalize,
-    split_getObjectOps, NULL, NULL, NULL, NULL, NULL,
-    split_mark, NULL},
-    split_equality, split_outerObject, split_innerObject,
-    NULL, NULL, NULL, NULL, NULL
+    ConvertStub,
+    split_finalize,
+    NULL,           /* reserved0   */
+    NULL,           /* checkAccess */
+    NULL,           /* call        */
+    NULL,           /* construct   */
+    NULL,           /* xdrObject   */
+    NULL,           /* hasInstance */
+    split_mark,
+    {
+        Valueify(split_equality),
+        split_outerObject,
+        split_innerObject,
+        NULL, /* iteratorObject */
+        NULL, /* wrappedObject  */
+    },
+    {
+        NULL, /* lookupProperty */
+        NULL, /* defineProperty */
+        NULL, /* getProperty    */
+        NULL, /* setProperty    */
+        NULL, /* getAttributes  */
+        NULL, /* setAttributes  */
+        NULL, /* deleteProperty */
+        NULL, /* enumerate      */
+        NULL, /* typeOf         */
+        NULL, /* trace          */
+        split_thisObject,
+        NULL, /* clear          */
+    },
 };
 
 static JSBool
 split_equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp)
 {
     *bp = JS_FALSE;
     if (JSVAL_IS_PRIMITIVE(*v))
         return JS_TRUE;
 
     JSObject *obj2 = JSVAL_TO_OBJECT(*v);
-    if (JS_GET_CLASS(cx, obj2) != &split_global_class.base)
+    if (obj2->getClass() != &split_global_class)
         return JS_TRUE;
 
     ComplexObject *cpx = (ComplexObject *) JS_GetPrivate(cx, obj2);
     JS_ASSERT(!cpx->isInner);
 
     ComplexObject *ourCpx = (ComplexObject *) JS_GetPrivate(cx, obj);
     JS_ASSERT(!ourCpx->isInner);
 
@@ -2840,17 +2854,17 @@ split_create_outer(JSContext *cx)
     cpx = (ComplexObject *) JS_malloc(cx, sizeof *obj);
     if (!cpx)
         return NULL;
     cpx->isInner = JS_FALSE;
     cpx->frozen = JS_TRUE;
     cpx->inner = NULL;
     cpx->outer = NULL;
 
-    obj = JS_NewGlobalObject(cx, &split_global_class.base);
+    obj = JS_NewGlobalObject(cx, Jsvalify(&split_global_class));
     if (!obj || !JS_SetParent(cx, obj, NULL)) {
         JS_free(cx, cpx);
         return NULL;
     }
 
     if (!JS_SetPrivate(cx, obj, cpx)) {
         JS_free(cx, cpx);
         return NULL;
@@ -2860,44 +2874,44 @@ split_create_outer(JSContext *cx)
 }
 
 static JSObject *
 split_create_inner(JSContext *cx, JSObject *outer)
 {
     ComplexObject *cpx, *outercpx;
     JSObject *obj;
 
-    JS_ASSERT(JS_GET_CLASS(cx, outer) == &split_global_class.base);
+    JS_ASSERT(outer->getClass() == &split_global_class);
 
     cpx = (ComplexObject *) JS_malloc(cx, sizeof *cpx);
     if (!cpx)
         return NULL;
     cpx->isInner = JS_TRUE;
     cpx->frozen = JS_FALSE;
     cpx->inner = NULL;
     cpx->outer = outer;
 
-    obj = JS_NewGlobalObject(cx, &split_global_class.base);
+    obj = JS_NewGlobalObject(cx, Jsvalify(&split_global_class));
     if (!obj || !JS_SetParent(cx, obj, NULL) || !JS_SetPrivate(cx, obj, cpx)) {
         JS_free(cx, cpx);
         return NULL;
     }
 
     outercpx = (ComplexObject *) JS_GetPrivate(cx, outer);
     outercpx->inner = obj;
     outercpx->frozen = JS_FALSE;
 
     return obj;
 }
 
 static ComplexObject *
 split_get_private(JSContext *cx, JSObject *obj)
 {
     do {
-        if (JS_GET_CLASS(cx, obj) == &split_global_class.base)
+        if (obj->getClass() == &split_global_class)
             return (ComplexObject *) JS_GetPrivate(cx, obj);
         obj = JS_GetParent(cx, obj);
     } while (obj);
 
     return NULL;
 }
 
 static JSBool
@@ -3672,22 +3686,18 @@ Parent(JSContext *cx, uintN argc, jsval 
         return JS_FALSE;
     }
 
     JSObject *parent = JS_GetParent(cx, JSVAL_TO_OBJECT(v));
     *vp = OBJECT_TO_JSVAL(parent);
 
     /* Outerize if necessary.  Embrace the ugliness! */
     if (parent) {
-        JSClass *clasp = JS_GET_CLASS(cx, parent);
-        if (clasp->flags & JSCLASS_IS_EXTENDED) {
-            JSExtendedClass *xclasp = reinterpret_cast<JSExtendedClass *>(clasp);
-            if (JSObjectOp outerize = xclasp->outerObject)
-                *vp = OBJECT_TO_JSVAL(outerize(cx, parent));
-        }
+        if (JSObjectOp op = parent->getClass()->ext.outerObject)
+            *vp = OBJECT_TO_JSVAL(op(cx, parent));
     }
 
     return JS_TRUE;
 }
 
 #ifdef XP_UNIX
 
 #include <fcntl.h>
--- a/js/src/trace-test/trace-test.py
+++ b/js/src/trace-test/trace-test.py
@@ -281,16 +281,17 @@ if __name__ == '__main__':
                   help='Enable the |valgrind| flag, if valgrind is in $PATH.')
     op.add_option('--valgrind-all', dest='valgrind_all', action='store_true',
                   help='Run all tests with valgrind, if valgrind is in $PATH.')
     (OPTIONS, args) = op.parse_args()
     if len(args) < 1:
         op.error('missing JS_SHELL argument')
     # We need to make sure we are using backslashes on Windows.
     JS, test_args = os.path.normpath(args[0]), args[1:]
+    JS = os.path.realpath(JS) # Burst through the symlinks!
 
     if OPTIONS.retest:
         OPTIONS.read_tests = OPTIONS.retest
         OPTIONS.write_failures = OPTIONS.retest
 
     test_list = []
     read_all = True
 
--- a/js/src/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/src/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -54,16 +54,17 @@
 #include "nsDependentString.h"
 #include "nsAutoPtr.h"
 #include "nsNetUtil.h"
 #include "nsIProtocolHandler.h"
 #include "nsIFileURL.h"
 
 #include "jsapi.h"
 #include "jsdbgapi.h"
+#include "jsobj.h"
 
 #include "mozilla/FunctionTimer.h"
 
 /* load() error msgs, XXX localize? */
 #define LOAD_ERROR_NOSERVICE "Error creating IO Service."
 #define LOAD_ERROR_NOURI "Error creating URI (invalid URL scheme?)"
 #define LOAD_ERROR_NOSCHEME "Failed to get URI scheme.  This is bad."
 #define LOAD_ERROR_URI_NOT_LOCAL "Trying to load a non-local URI."
@@ -199,28 +200,23 @@ mozJSSubScriptLoader::LoadSubScript (con
         }
 #ifdef DEBUG_rginda
         fprintf (stderr, "\n");
 #endif  
     }
 
     // Innerize the target_obj so that we compile the loaded script in the
     // correct (inner) scope.
-    JSClass *target_class = JS_GET_CLASS(cx, target_obj);
-    if (target_class->flags & JSCLASS_IS_EXTENDED)
+    if (JSObjectOp op = target_obj->getClass()->ext.innerObject)
     {
-        JSExtendedClass *extended = (JSExtendedClass*)target_class;
-        if (extended->innerObject)
-        {
-            target_obj = extended->innerObject(cx, target_obj);
-            if (!target_obj) return NS_ERROR_FAILURE;
+        target_obj = op(cx, target_obj);
+        if (!target_obj) return NS_ERROR_FAILURE;
 #ifdef DEBUG_rginda
-            fprintf (stderr, "Final global: %p\n", target_obj);
+        fprintf (stderr, "Final global: %p\n", target_obj);
 #endif
-        }
     }
 
     /* load up the url.  From here on, failures are reflected as ``custom''
      * js exceptions */
     PRInt32   len = -1;
     PRUint32  readcount = 0;  // Total amount of data read
     PRUint32  lastReadCount = 0;  // Amount of data read in last Read() call
     nsAutoArrayPtr<char> buf;
--- a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
+++ b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp
@@ -246,49 +246,55 @@ XPC_COW_WrappedObject(JSContext *cx, JSO
 
 static JSBool
 WrapFunction(JSContext *cx, JSObject *scope, JSObject *funobj, jsval *vp);
 
 using namespace XPCWrapper;
 
 namespace ChromeObjectWrapper {
 
-JSExtendedClass COWClass = {
-  // JSClass (JSExtendedClass.base) initialization
-  { "ChromeObjectWrapper",
-    JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
+js::Class COWClass = {
+    "ChromeObjectWrapper",
+    JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_RESERVED_SLOTS(XPCWrapper::sNumSlots + 1),
-    XPC_COW_AddProperty, XPC_COW_DelProperty,
-    XPC_COW_GetProperty, XPC_COW_SetProperty,
-    XPC_COW_Enumerate,   (JSResolveOp)XPC_COW_NewResolve,
-    XPC_COW_Convert,     JS_FinalizeStub,
-    nsnull,              XPC_COW_CheckAccess,
-    nsnull,              nsnull,
-    nsnull,              nsnull,
-    nsnull,              nsnull
-  },
+    js::Valueify(XPC_COW_AddProperty),
+    js::Valueify(XPC_COW_DelProperty),
+    js::Valueify(XPC_COW_GetProperty),
+    js::Valueify(XPC_COW_SetProperty),
+    XPC_COW_Enumerate,
+    (JSResolveOp)XPC_COW_NewResolve,
+    js::Valueify(XPC_COW_Convert),
+    JS_FinalizeStub,
+    nsnull,   // reserved0
+    js::Valueify(XPC_COW_CheckAccess),
+    nsnull,   // call
+    nsnull,   // construct
+    nsnull,   // xdrObject
+    nsnull,   // hasInstance
+    nsnull,   // mark
 
-  // JSExtendedClass initialization
-  XPC_COW_Equality,
-  nsnull,             // outerObject
-  nsnull,             // innerObject
-  XPC_COW_Iterator,
-  XPC_COW_WrappedObject,
-  JSCLASS_NO_RESERVED_MEMBERS
+    // ClassExtension
+    {
+      js::Valueify(XPC_COW_Equality),
+      nsnull, // outerObject
+      nsnull, // innerObject
+      XPC_COW_Iterator,
+      XPC_COW_WrappedObject
+    }
 };
 
 JSBool
 WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp)
 {
   if (JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(v))) {
     return WrapFunction(cx, parent, JSVAL_TO_OBJECT(v), vp);
   }
 
   JSObject *wrapperObj =
-    JS_NewObjectWithGivenProto(cx, &COWClass.base, NULL, parent);
+    JS_NewObjectWithGivenProto(cx, js::Jsvalify(&COWClass), NULL, parent);
   if (!wrapperObj) {
     return JS_FALSE;
   }
 
   *vp = OBJECT_TO_JSVAL(wrapperObj);
 
   js::AutoValueRooter exposedProps(cx);
 
@@ -318,41 +324,36 @@ ThrowException(nsresult rv, JSContext *c
 }
 
 // Like GetWrappedObject, but works on other types of wrappers, too.
 // See also JSObject::wrappedObject in jsobj.cpp.
 // TODO Move to XPCWrapper?
 static inline JSObject *
 GetWrappedJSObject(JSContext *cx, JSObject *obj)
 {
-  JSClass *clasp = obj->getJSClass();
-  if (!(clasp->flags & JSCLASS_IS_EXTENDED)) {
-    return obj;
-  }
-
-  JSExtendedClass *xclasp = (JSExtendedClass *)clasp;
-  if (!xclasp->wrappedObject) {
+  JSObjectOp op = obj->getClass()->ext.wrappedObject;
+  if (!op) {
     if (XPCNativeWrapper::IsNativeWrapper(obj)) {
       XPCWrappedNative *wn = XPCNativeWrapper::SafeGetWrappedNative(obj);
       return wn ? wn->GetFlatJSObject() : nsnull;
     }
 
     return obj;
   }
 
-  return xclasp->wrappedObject(cx, obj);
+  return op(cx, obj);
 }
 
 // Get the (possibly nonexistent) COW off of an object
 // TODO Move to XPCWrapper and share with other wrappers.
 static inline
 JSObject *
 GetWrapper(JSObject *obj)
 {
-  while (obj->getJSClass() != &COWClass.base) {
+  while (obj->getClass() != &COWClass) {
     obj = obj->getProto();
     if (!obj) {
       break;
     }
   }
 
   return obj;
 }
@@ -743,18 +744,17 @@ XPC_COW_Equality(JSContext *cx, JSObject
     *bp = JS_FALSE;
     return JS_TRUE;
   }
 
   XPCWrappedNative *me = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
   obj = me->GetFlatJSObject();
   test = other->GetFlatJSObject();
   jsval testVal = OBJECT_TO_JSVAL(test);
-  return ((JSExtendedClass *)obj->getJSClass())->
-    equality(cx, obj, &testVal, bp);
+  return js::Jsvalify(obj->getClass()->ext.equality)(cx, obj, &testVal, bp);
 }
 
 static JSObject *
 XPC_COW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
 {
   JSObject *wrappedObj = GetWrappedObject(cx, obj);
   if (!wrappedObj) {
     ThrowException(NS_ERROR_INVALID_ARG, cx);
--- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
+++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp
@@ -120,17 +120,17 @@ ThrowException(nsresult ex, JSContext *c
   return JS_FALSE;
 }
 
 // Get the (possibly nonexistent) XOW off of an object
 static inline
 JSObject *
 GetWrapper(JSObject *obj)
 {
-  while (obj->getJSClass() != &XPCCrossOriginWrapper::XOWClass.base) {
+  while (obj->getClass() != &XPCCrossOriginWrapper::XOWClass) {
     obj = obj->getProto();
     if (!obj) {
       break;
     }
   }
 
   return obj;
 }
@@ -151,38 +151,44 @@ XPC_XOW_FunctionWrapper(JSContext *cx, J
 static const PRUint32 FLAG_IS_UXPC_OBJECT = XPCWrapper::LAST_FLAG << 1;
 
 // This flag is set on objects that have to clear their wrapped native's XOW
 // cache when they get finalized.
 static const PRUint32 FLAG_IS_CACHED = XPCWrapper::LAST_FLAG << 2;
 
 namespace XPCCrossOriginWrapper {
 
-JSExtendedClass XOWClass = {
-  // JSClass (JSExtendedClass.base) initialization
-  { "XPCCrossOriginWrapper",
-    JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
+js::Class XOWClass = {
+    "XPCCrossOriginWrapper",
+    JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_RESERVED_SLOTS(XPCWrapper::sNumSlots + 2),
-    XPC_XOW_AddProperty, XPC_XOW_DelProperty,
-    XPC_XOW_GetProperty, XPC_XOW_SetProperty,
-    XPC_XOW_Enumerate,   (JSResolveOp)XPC_XOW_NewResolve,
-    XPC_XOW_Convert,     XPC_XOW_Finalize,
-    nsnull,              XPC_XOW_CheckAccess,
-    XPC_XOW_Call,        XPC_XOW_Construct,
-    nsnull,              XPC_XOW_HasInstance,
-    nsnull,              nsnull
-  },
+    js::Valueify(XPC_XOW_AddProperty),
+    js::Valueify(XPC_XOW_DelProperty),
+    js::Valueify(XPC_XOW_GetProperty),
+    js::Valueify(XPC_XOW_SetProperty),
+    XPC_XOW_Enumerate,
+    (JSResolveOp)XPC_XOW_NewResolve,
+    js::Valueify(XPC_XOW_Convert),
+    XPC_XOW_Finalize,
+    nsnull,   // reserved0 
+    js::Valueify(XPC_XOW_CheckAccess),
+    js::Valueify(XPC_XOW_Call),
+    js::Valueify(XPC_XOW_Construct),
+    nsnull,   // xdrObject
+    js::Valueify(XPC_XOW_HasInstance),
+    nsnull,   // mark
 
-  // JSExtendedClass initialization
-  XPC_XOW_Equality,
-  nsnull,             // outerObject
-  nsnull,             // innerObject
-  XPC_XOW_Iterator,
-  XPC_XOW_WrappedObject,
-  JSCLASS_NO_RESERVED_MEMBERS
+    // ClassExtension
+    {
+      js::Valueify(XPC_XOW_Equality),
+      nsnull, // outerObject
+      nsnull, // innerObject
+      XPC_XOW_Iterator,
+      XPC_XOW_WrappedObject
+    }
 };
 
 JSBool
 WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj,
                      XPCWrappedNativeScope *newScope)
 {
   typedef WrappedNative2WrapperMap::Link Link;
   XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
@@ -371,17 +377,17 @@ RewrapIfNeeded(JSContext *cx, JSObject *
 
   JSObject *obj = JSVAL_TO_OBJECT(*vp);
 
   if (JS_ObjectIsFunction(cx, obj)) {
     return WrapFunction(cx, outerObj, obj, vp);
   }
 
   XPCWrappedNative *wn = nsnull;
-  if (obj->getJSClass() == &XOWClass.base &&
+  if (obj->getClass() == &XOWClass &&
       outerObj->getParent() != obj->getParent()) {
     *vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, obj));
   } else if (!(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, obj))) {
     return JS_TRUE;
   }
 
   return WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp, wn);
 }
@@ -392,17 +398,17 @@ WrapObject(JSContext *cx, JSObject *pare
   NS_ASSERTION(XPCPerThreadData::IsMainThread(cx),
                "Can't do this off the main thread!");
 
   // Our argument should be a wrapped native object, but the caller may have
   // passed it in as an optimization.
   JSObject *wrappedObj;
   if (JSVAL_IS_PRIMITIVE(*vp) ||
       !(wrappedObj = JSVAL_TO_OBJECT(*vp)) ||
-      wrappedObj->getJSClass() == &XOWClass.base) {
+      wrappedObj->getClass() == &XOWClass) {
     return JS_TRUE;
   }
 
   if (!wn &&
       !(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, wrappedObj))) {
     return JS_TRUE;
   }
 
@@ -440,30 +446,30 @@ WrapObject(JSContext *cx, JSObject *pare
     parentScope = XPCWrappedNativeScope::FindInJSObjectScope(cx, parent);
   }
 
   JSObject *outerObj = nsnull;
   WrappedNative2WrapperMap *map = parentScope->GetWrapperMap();
 
   outerObj = map->Find(wrappedObj);
   if (outerObj) {
-    NS_ASSERTION(outerObj->getJSClass() == &XOWClass.base,
+    NS_ASSERTION(outerObj->getClass() == &XOWClass,
                  "What crazy object are we getting here?");
     *vp = OBJECT_TO_JSVAL(outerObj);
 
     if (wnxow) {
       // NB: wnxow->GetXOW() must have returned false.
       SetFlags(cx, outerObj, AddFlags(GetFlags(cx, outerObj), FLAG_IS_CACHED));
       wnxow->SetXOW(outerObj);
     }
 
     return JS_TRUE;
   }
 
-  outerObj = JS_NewObjectWithGivenProto(cx, &XOWClass.base, nsnull,
+  outerObj = JS_NewObjectWithGivenProto(cx, js::Jsvalify(&XOWClass), nsnull,
                                         parent);
   if (!outerObj) {
     return JS_FALSE;
   }
 
   jsval flags = INT_TO_JSVAL(wnxow ? FLAG_IS_CACHED : 0);
   if (!JS_SetReservedSlot(cx, outerObj, sWrappedObjSlot, *vp) ||
       !JS_SetReservedSlot(cx, outerObj, sFlagsSlot, flags) ||
@@ -585,24 +591,24 @@ WrapSameOriginProp(JSContext *cx, JSObje
 {
   // Don't call RewrapIfNeeded for same origin properties. We only
   // need to wrap window, document and location.
   if (JSVAL_IS_PRIMITIVE(*vp)) {
     return JS_TRUE;
   }
 
   JSObject *wrappedObj = JSVAL_TO_OBJECT(*vp);
-  JSClass *clasp = wrappedObj->getJSClass();
+  js::Class *clasp = wrappedObj->getClass();
   if (ClassNeedsXOW(clasp->name)) {
     return WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp);
   }
 
   // Check if wrappedObj is an XOW. If so, verify that it's from the
   // right scope.
-  if (clasp == &XOWClass.base &&
+  if (clasp == &XOWClass &&
       wrappedObj->getParent() != outerObj->getParent()) {
     *vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, wrappedObj));
     return WrapObject(cx, outerObj->getParent(), vp);
   }
 
   return JS_TRUE;
 }
 
@@ -615,17 +621,17 @@ XPC_XOW_AddProperty(JSContext *cx, JSObj
   obj = GetWrapper(obj);
   jsval resolving;
   if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &resolving)) {
     return JS_FALSE;
   }
 
   if (!JSVAL_IS_PRIMITIVE(*vp)) {
     JSObject *addedObj = JSVAL_TO_OBJECT(*vp);
-    if (addedObj->getJSClass() == &XOWClass.base &&
+    if (addedObj->getClass() == &XOWClass &&
         addedObj->getParent() != obj->getParent()) {
       *vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, addedObj));
       if (!WrapObject(cx, obj->getParent(), vp, nsnull)) {
         return JS_FALSE;
       }
     }
   }
 
@@ -837,17 +843,17 @@ XPC_XOW_Enumerate(JSContext *cx, JSObjec
 // UXPCObject (which is just a XOW for the same object). This causes the JS
 // engine to do all of its work on another object, not polluting the main
 // object. However, if the get results in calling a setter, the engine still
 // uses the regular object as 'this', ensuring that the UXPCObject doesn't
 // leak to script.
 static JSObject *
 GetUXPCObject(JSContext *cx, JSObject *obj)
 {
-  NS_ASSERTION(obj->getJSClass() == &XOWClass.base, "wrong object");
+  NS_ASSERTION(obj->getClass() == &XOWClass, "wrong object");
 
   jsval v;
   if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &v)) {
     return nsnull;
   }
 
   if (HAS_FLAGS(v, FLAG_IS_UXPC_OBJECT)) {
     return obj;
@@ -857,17 +863,18 @@ GetUXPCObject(JSContext *cx, JSObject *o
     return nsnull;
   }
 
   if (JSVAL_IS_OBJECT(v)) {
     return JSVAL_TO_OBJECT(v);
   }
 
   JSObject *uxpco =
-    JS_NewObjectWithGivenProto(cx, &XOWClass.base, nsnull, obj->getParent());
+    JS_NewObjectWithGivenProto(cx, js::Jsvalify(&XOWClass), nsnull,
+                               obj->getParent());
   if (!uxpco) {
     return nsnull;
   }
 
   js::AutoObjectRooter tvr(cx, uxpco);
 
   jsval wrappedObj, parentScope;
   if (!JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &wrappedObj) ||
@@ -1176,17 +1183,17 @@ XPC_XOW_Equality(JSContext *cx, JSObject
 
   // Convert both sides to XPCWrappedNative and see if they match.
   if (JSVAL_IS_PRIMITIVE(v)) {
     *bp = JS_FALSE;
     return JS_TRUE;
   }
 
   JSObject *test = JSVAL_TO_OBJECT(v);
-  if (test->getJSClass() == &XOWClass.base) {
+  if (test->getClass() == &XOWClass) {
     if (!JS_GetReservedSlot(cx, test, sWrappedObjSlot, &v)) {
       return JS_FALSE;
     }
 
     if (JSVAL_IS_PRIMITIVE(v)) {
       *bp = JS_FALSE;
       return JS_TRUE;
     }
@@ -1204,18 +1211,17 @@ XPC_XOW_Equality(JSContext *cx, JSObject
     *bp = JS_FALSE;
     return JS_TRUE;
   }
 
   XPCWrappedNative *me = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
   obj = me->GetFlatJSObject();
   test = other->GetFlatJSObject();
   jsval testVal = OBJECT_TO_JSVAL(test);
-  return ((JSExtendedClass *)obj->getJSClass())->
-    equality(cx, obj, &testVal, bp);
+  return js::Jsvalify(obj->getClass()->ext.equality)(cx, obj, &testVal, bp);
 }
 
 static JSObject *
 XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
 {
   JSObject *wrappedObj = GetWrappedObject(cx, obj);
   if (!wrappedObj) {
     ThrowException(NS_ERROR_INVALID_ARG, cx);
@@ -1235,17 +1241,17 @@ XPC_XOW_Iterator(JSContext *cx, JSObject
       ThrowException(rv, cx);
       return nsnull;
     }
 
     ThrowException(NS_ERROR_FAILURE, cx);
     return nsnull;
   }
 
-  JSObject *wrapperIter = JS_NewObject(cx, &XOWClass.base, nsnull,
+  JSObject *wrapperIter = JS_NewObject(cx, js::Jsvalify(&XOWClass), nsnull,
                                        JS_GetGlobalForObject(cx, obj));
   if (!wrapperIter) {
     return nsnull;
   }
 
   js::AutoObjectRooter tvr(cx, wrapperIter);
 
   // Initialize our XOW.
--- a/js/src/xpconnect/src/XPCNativeWrapper.cpp
+++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp
@@ -104,66 +104,78 @@ using namespace XPCWrapper;
 // not have expando properties set on implicit native wrappers.
 static const PRUint32 FLAG_EXPLICIT = XPCWrapper::LAST_FLAG << 1;
 
 namespace XPCNativeWrapper { namespace internal {
 
 // JS class for XPCNativeWrapper (and this doubles as the constructor
 // for XPCNativeWrapper for the moment too...)
 
-JSExtendedClass NW_NoCall_Class = {
-  // JSClass (JSExtendedClass.base) initialization
-  { "XPCNativeWrapper",
+js::Class NW_NoCall_Class = {
+    "XPCNativeWrapper",
     JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
     // Our one reserved slot holds a jsint of flag bits
     JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) |
-    JSCLASS_MARK_IS_TRACE | JSCLASS_IS_EXTENDED | JSCLASS_CONSTRUCT_PROTOTYPE,
-    XPC_NW_AddProperty, XPC_NW_DelProperty,
-    XPC_NW_GetProperty, XPC_NW_SetProperty,
-    XPC_NW_Enumerate,   (JSResolveOp)XPC_NW_NewResolve,
-    XPC_NW_Convert,     XPC_NW_Finalize,
-    nsnull,             XPC_NW_CheckAccess,
-    nsnull,             XPC_NW_Construct,
-    nsnull,             XPC_NW_HasInstance,
-    JS_CLASS_TRACE(XPC_NW_Trace), nsnull
-  },
+    JSCLASS_MARK_IS_TRACE | JSCLASS_CONSTRUCT_PROTOTYPE,
+    js::Valueify(XPC_NW_AddProperty),
+    js::Valueify(XPC_NW_DelProperty),
+    js::Valueify(XPC_NW_GetProperty),
+    js::Valueify(XPC_NW_SetProperty),
+    XPC_NW_Enumerate,
+    (JSResolveOp)XPC_NW_NewResolve,
+    js::Valueify(XPC_NW_Convert),
+    XPC_NW_Finalize,
+    nsnull,   // reserved0
+    js::Valueify(XPC_NW_CheckAccess),
+    nsnull,   // call
+    js::Valueify(XPC_NW_Construct),
+    nsnull,   // xdrObject
+    js::Valueify(XPC_NW_HasInstance),
+    JS_CLASS_TRACE(XPC_NW_Trace),
 
-  // JSExtendedClass initialization
-  XPC_NW_Equality,
-  nsnull,             // outerObject
-  nsnull,             // innerObject
-  XPC_NW_Iterator,
-  nsnull,             // wrappedObject
-  JSCLASS_NO_RESERVED_MEMBERS
+    // ClassExtension
+    {
+      js::Valueify(XPC_NW_Equality),
+      nsnull, // outerObject
+      nsnull, // innerObject
+      XPC_NW_Iterator,
+      nsnull, // wrappedObject
+    }
 };
 
-JSExtendedClass NW_Call_Class = {
-  // JSClass (JSExtendedClass.base) initialization
-  { "XPCNativeWrapper",
+js::Class NW_Call_Class = {
+    "XPCNativeWrapper",
     JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
     // Our one reserved slot holds a jsint of flag bits
     JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) |
-    JSCLASS_MARK_IS_TRACE | JSCLASS_IS_EXTENDED | JSCLASS_CONSTRUCT_PROTOTYPE,
-    XPC_NW_AddProperty, XPC_NW_DelProperty,
-    XPC_NW_GetProperty, XPC_NW_SetProperty,
-    XPC_NW_Enumerate,   (JSResolveOp)XPC_NW_NewResolve,
-    XPC_NW_Convert,     XPC_NW_Finalize,
-    nsnull,             XPC_NW_CheckAccess,
-    XPC_NW_Call,        XPC_NW_Construct,
-    nsnull,             XPC_NW_HasInstance,
-    JS_CLASS_TRACE(XPC_NW_Trace), nsnull
-  },
+    JSCLASS_MARK_IS_TRACE | JSCLASS_CONSTRUCT_PROTOTYPE,
+    js::Valueify(XPC_NW_AddProperty),
+    js::Valueify(XPC_NW_DelProperty),
+    js::Valueify(XPC_NW_GetProperty),
+    js::Valueify(XPC_NW_SetProperty),
+    XPC_NW_Enumerate,
+    (JSResolveOp)XPC_NW_NewResolve,
+    js::Valueify(XPC_NW_Convert),
+    XPC_NW_Finalize,
+    nsnull,   // reserved0
+    js::Valueify(XPC_NW_CheckAccess),
+    js::Valueify(XPC_NW_Call),
+    js::Valueify(XPC_NW_Construct),
+    nsnull,   // xdrObject
+    js::Valueify(XPC_NW_HasInstance),
+    JS_CLASS_TRACE(XPC_NW_Trace),
 
-  // JSExtendedClass initialization
-  XPC_NW_Equality,
-  nsnull,             // outerObject
-  nsnull,             // innerObject
-  XPC_NW_Iterator,
-  nsnull,             // wrappedObject
-  JSCLASS_NO_RESERVED_MEMBERS
+    // ClassExtension
+    {
+      js::Valueify(XPC_NW_Equality),
+      nsnull, // outerObject
+      nsnull, // innerObject
+      XPC_NW_Iterator,
+      nsnull, // wrappedObject
+    }
 };
 
 } // namespace internal
 
 JSBool
 GetWrappedNative(JSContext *cx, JSObject *obj,
                  XPCWrappedNative **aWrappedNative)
 {
@@ -1023,17 +1035,18 @@ static JSFunctionSpec static_functions[]
 };
 
 // static
 PRBool
 XPCNativeWrapper::AttachNewConstructorObject(XPCCallContext &ccx,
                                              JSObject *aGlobalObject)
 {
   JSObject *class_obj =
-    ::JS_InitClass(ccx, aGlobalObject, nsnull, &internal::NW_Call_Class.base,
+    ::JS_InitClass(ccx, aGlobalObject, nsnull,
+                   js::Jsvalify(&internal::NW_Call_Class),
                    XPCNativeWrapperCtor, 0, nsnull, nsnull,
                    nsnull, static_functions);
   if (!class_obj) {
     NS_WARNING("can't initialize the XPCNativeWrapper class");
     return PR_FALSE;
   }
   
   // Make sure our prototype chain is empty and that people can't mess
@@ -1041,17 +1054,17 @@ XPCNativeWrapper::AttachNewConstructorOb
   ::JS_SetPrototype(ccx, class_obj, nsnull);
   if (!::JS_SealObject(ccx, class_obj, JS_FALSE)) {
     NS_WARNING("Failed to seal XPCNativeWrapper.prototype");
     return PR_FALSE;
   }
 
   JSBool found;
   return ::JS_SetPropertyAttributes(ccx, aGlobalObject,
-                                    internal::NW_Call_Class.base.name,
+                                    internal::NW_Call_Class.name,
                                     JSPROP_READONLY | JSPROP_PERMANENT,
                                     &found);
 }
 
 // static
 JSObject *
 XPCNativeWrapper::GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper,
                                JSObject *scope, nsIPrincipal *aObjectPrincipal)
--- a/js/src/xpconnect/src/XPCNativeWrapper.h
+++ b/js/src/xpconnect/src/XPCNativeWrapper.h
@@ -40,40 +40,40 @@
 #include "nscore.h"
 #include "jsapi.h"
 
 class nsIPrincipal;
 
 namespace XPCNativeWrapper {
 
 namespace internal {
-  extern JSExtendedClass NW_NoCall_Class;
-  extern JSExtendedClass NW_Call_Class;
+extern js::Class NW_NoCall_Class;
+extern js::Class NW_Call_Class;
 }
 
 PRBool
 AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject);
 
 JSObject *
 GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper,
              JSObject *scope, nsIPrincipal *aObjectPrincipal);
 JSBool
 CreateExplicitWrapper(JSContext *cx, XPCWrappedNative *wrapper, jsval *rval);
 
 inline PRBool
-IsNativeWrapperClass(JSClass *clazz)
+IsNativeWrapperClass(js::Class *clazz)
 {
-  return clazz == &internal::NW_NoCall_Class.base ||
-         clazz == &internal::NW_Call_Class.base;
+  return clazz == &internal::NW_NoCall_Class ||
+         clazz == &internal::NW_Call_Class;
 }
 
 inline PRBool
 IsNativeWrapper(JSObject *obj)
 {
-  return IsNativeWrapperClass(obj->getJSClass());
+  return IsNativeWrapperClass(obj->getClass());
 }
 
 JSBool
 GetWrappedNative(JSContext *cx, JSObject *obj,
                  XPCWrappedNative **aWrappedNative);
 
 // NB: Use the following carefully.
 inline XPCWrappedNative *
@@ -81,16 +81,16 @@ SafeGetWrappedNative(JSObject *obj)
 {
   return static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));
 }
 
 inline JSClass *
 GetJSClass(bool call)
 {
   return call
-    ? &internal::NW_Call_Class.base
-    : &internal::NW_NoCall_Class.base;
+    ? js::Jsvalify(&internal::NW_Call_Class)
+    : js::Jsvalify(&internal::NW_NoCall_Class);
 }
 
 void
 ClearWrappedNativeScopes(JSContext* cx, XPCWrappedNative* wrapper);
 
 }
--- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
+++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
@@ -228,17 +228,17 @@ FindObjectPrincipals(JSContext *cx, JSOb
 
   // The wrapper owns the principal now.
   return objPrincipal.forget().get();
 }
 
 static inline JSObject *
 FindSafeObject(JSObject *obj)
 {
-  while (obj->getJSClass() != &SJOWClass.base) {
+  while (obj->getClass() != &SJOWClass) {
     obj = obj->getProto();
 
     if (!obj) {
       break;
     }
   }
 
   return obj;
@@ -248,37 +248,44 @@ static JSBool
 XPC_SJOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
                   jsval *rval);
 
 namespace XPCSafeJSObjectWrapper {
 
 // JS class for XPCSafeJSObjectWrapper (and this doubles as the
 // constructor for XPCSafeJSObjectWrapper for the moment too...)
 
-JSExtendedClass SJOWClass = {
-  // JSClass (JSExtendedClass.base) initialization
-  { "XPCSafeJSObjectWrapper",
-    JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
+js::Class SJOWClass = {
+    "XPCSafeJSObjectWrapper",
+    JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_RESERVED_SLOTS(sSJOWSlots),
-    XPC_SJOW_AddProperty, XPC_SJOW_DelProperty,
-    XPC_SJOW_GetProperty, XPC_SJOW_SetProperty,
-    XPC_SJOW_Enumerate,   (JSResolveOp)XPC_SJOW_NewResolve,
-    XPC_SJOW_Convert,     XPC_SJOW_Finalize,
-    nsnull,               XPC_SJOW_CheckAccess,
-    XPC_SJOW_Call,        XPC_SJOW_Create,
-    nsnull,               nsnull,
-    nsnull,               nsnull
-  },
-  // JSExtendedClass initialization
-  XPC_SJOW_Equality,
-  nsnull, // outerObject
-  nsnull, // innerObject
-  XPC_SJOW_Iterator,
-  XPC_SJOW_WrappedObject,
-  JSCLASS_NO_RESERVED_MEMBERS
+    js::Valueify(XPC_SJOW_AddProperty),
+    js::Valueify(XPC_SJOW_DelProperty),
+    js::Valueify(XPC_SJOW_GetProperty),
+    js::Valueify(XPC_SJOW_SetProperty),
+    XPC_SJOW_Enumerate,
+    (JSResolveOp)XPC_SJOW_NewResolve,
+    js::Valueify(XPC_SJOW_Convert),
+    XPC_SJOW_Finalize,
+    nsnull,   // reserved0
+    js::Valueify(XPC_SJOW_CheckAccess),
+    js::Valueify(XPC_SJOW_Call),
+    js::Valueify(XPC_SJOW_Create),
+    nsnull,   // xdrObject
+    nsnull,   // hasInstance
+    nsnull,   // mark
+
+    // ClassExtension
+    {
+      js::Valueify(XPC_SJOW_Equality),
+      nsnull, // outerObject
+      nsnull, // innerObject
+      XPC_SJOW_Iterator,
+      XPC_SJOW_WrappedObject
+    }
 };
 
 JSBool
 WrapObject(JSContext *cx, JSObject *scope, jsval v, jsval *vp)
 {
   // This might be redundant if called from XPC_SJOW_Construct, but it should
   // be cheap in that case.
   JSObject *objToWrap = UnsafeUnwrapSecurityWrapper(cx, JSVAL_TO_OBJECT(v));
@@ -313,17 +320,17 @@ WrapObject(JSContext *cx, JSObject *scop
   }
 
   SLIM_LOG_WILL_MORPH(cx, objToWrap);
   if (IS_SLIM_WRAPPER(objToWrap) && !MorphSlimWrapper(cx, objToWrap)) {
     return ThrowException(NS_ERROR_FAILURE, cx);
   }
 
   JSObject *wrapperObj =
-    JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull, scope);
+    JS_NewObjectWithGivenProto(cx, js::Jsvalify(&SJOWClass), nsnull, scope);
 
   if (!wrapperObj) {
     // JS_NewObjectWithGivenProto already threw.
     return JS_FALSE;
   }
 
   *vp = OBJECT_TO_JSVAL(wrapperObj);
   if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot,
@@ -341,17 +348,17 @@ AttachNewConstructorObject(XPCCallContex
   // Initialize sEvalNative the first time we attach a constructor.
   // NB: This always happens before any cross origin wrappers are
   // created, so it's OK to do this here.
   if (!XPCWrapper::FindEval(ccx, aGlobalObject)) {
     return PR_FALSE;
   }
 
   JSObject *class_obj =
-    ::JS_InitClass(ccx, aGlobalObject, nsnull, &SJOWClass.base,
+    ::JS_InitClass(ccx, aGlobalObject, nsnull, js::Jsvalify(&SJOWClass),
                    XPC_SJOW_Construct, 0, nsnull, nsnull, nsnull, nsnull);
   if (!class_obj) {
     NS_WARNING("can't initialize the XPCSafeJSObjectWrapper class");
     return PR_FALSE;
   }
 
   if (!::JS_DefineFunction(ccx, class_obj, "toString", XPC_SJOW_toString,
                            0, 0)) {
@@ -363,17 +370,17 @@ AttachNewConstructorObject(XPCCallContex
   ::JS_SetPrototype(ccx, class_obj, nsnull);
   if (!::JS_SealObject(ccx, class_obj, JS_FALSE)) {
     NS_WARNING("Failed to seal XPCSafeJSObjectWrapper.prototype");
     return PR_FALSE;
   }
 
   JSBool found;
   return ::JS_SetPropertyAttributes(ccx, aGlobalObject,
-                                    SJOWClass.base.name,
+                                    SJOWClass.name,
                                     JSPROP_READONLY | JSPROP_PERMANENT,
                                     &found);
 }
 
 JSObject *
 GetUnsafeObject(JSContext *cx, JSObject *obj)
 {
   obj = FindSafeObject(obj);
@@ -441,17 +448,17 @@ WrapJSValue(JSContext *cx, JSObject *obj
     if (!RewrapObject(cx, obj->getParent(), JSVAL_TO_OBJECT(val), SJOW,
                       rval)) {
       return JS_FALSE;
     }
     // Construct a new safe wrapper. Note that it doesn't matter what
     // parent we pass in here, the construct hook will ensure we get
     // the right parent for the wrapper.
     JSObject *safeObj = JSVAL_TO_OBJECT(*rval);
-    if (safeObj->getJSClass() == &SJOWClass.base &&
+    if (safeObj->getClass() == &SJOWClass &&
         JS_GetGlobalForObject(cx, obj) != JS_GetGlobalForObject(cx, safeObj)) {
       // Check to see if the new object we just wrapped is accessible
       // from the unsafe object we got the new object through. If not,
       // force the new wrapper to use the principal of the unsafe
       // object we got the new object from.
       nsCOMPtr<nsIPrincipal> srcObjPrincipal;
       nsCOMPtr<nsIPrincipal> subjPrincipal;
       nsCOMPtr<nsIPrincipal> valObjPrincipal;
@@ -1025,17 +1032,17 @@ XPC_SJOW_Iterator(JSContext *cx, JSObjec
   // Check that the caller can access the unsafe object.
   if (!CanCallerAccess(cx, obj, unsafeObj)) {
     // CanCallerAccess() already threw for us.
     return nsnull;
   }
 
   // Create our dummy SJOW.
   JSObject *wrapperIter =
-    JS_NewObjectWithGivenProto(cx, &SJOWClass.base, nsnull,
+    JS_NewObjectWithGivenProto(cx, js::Jsvalify(&SJOWClass), nsnull,
                                JS_GetGlobalForObject(cx, obj));
   if (!wrapperIter) {
     return nsnull;
   }
 
   if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot,
                           OBJECT_TO_JSVAL(unsafeObj)) ||
       !JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot,
--- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
+++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp
@@ -93,52 +93,58 @@ ThrowException(nsresult rv, JSContext *c
 {
   return DoThrowException(rv, cx);
 }
 
 static const char prefix[] = "chrome://global/";
 
 namespace SystemOnlyWrapper {
 
-JSExtendedClass SOWClass = {
-  // JSClass (JSExtendedClass.base) initialization
-  { "SystemOnlyWrapper",
-    JSCLASS_NEW_RESOLVE | JSCLASS_IS_EXTENDED |
+js::Class SOWClass = {
+    "SystemOnlyWrapper",
+    JSCLASS_NEW_RESOLVE |
     JSCLASS_HAS_RESERVED_SLOTS(XPCWrapper::sNumSlots),
-    XPC_SOW_AddProperty, XPC_SOW_DelProperty,
-    XPC_SOW_GetProperty, XPC_SOW_SetProperty,
-    XPC_SOW_Enumerate,   (JSResolveOp)XPC_SOW_NewResolve,
-    XPC_SOW_Convert,     nsnull,
-    nsnull,              XPC_SOW_CheckAccess,
-    nsnull,              nsnull,
-    nsnull,              XPC_SOW_HasInstance,
-    nsnull,              nsnull
-  },
+    js::Valueify(XPC_SOW_AddProperty),
+    js::Valueify(XPC_SOW_DelProperty),
+    js::Valueify(XPC_SOW_GetProperty),
+    js::Valueify(XPC_SOW_SetProperty),
+    XPC_SOW_Enumerate,
+    (JSResolveOp)XPC_SOW_NewResolve,
+    js::Valueify(XPC_SOW_Convert),
+    nsnull,   // finalize
+    nsnull,   // reserved0
+    js::Valueify(XPC_SOW_CheckAccess),
+    nsnull,   // call
+    nsnull,   // construct
+    nsnull,   // xdrObject
+    js::Valueify(XPC_SOW_HasInstance),
+    nsnull,   // mark
 
-  // JSExtendedClass initialization
-  XPC_SOW_Equality,
-  nsnull,             // outerObject
-  nsnull,             // innerObject
-  XPC_SOW_Iterator,
-  XPC_SOW_WrappedObject,
-  JSCLASS_NO_RESERVED_MEMBERS
+    // ClassExtension
+    {
+      js::Valueify(XPC_SOW_Equality),
+      nsnull, // outerObject
+      nsnull, // innerObject
+      XPC_SOW_Iterator,
+      XPC_SOW_WrappedObject
+    }
 };
 
 JSBool
 WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp)
 {
   // Slim wrappers don't expect to be wrapped, so morph them to fat wrappers
   // if we're about to wrap one.
   JSObject *innerObj = JSVAL_TO_OBJECT(v);
   if (IS_SLIM_WRAPPER(innerObj) && !MorphSlimWrapper(cx, innerObj)) {
     return ThrowException(NS_ERROR_FAILURE, cx);
   }
 
   JSObject *wrapperObj =
-    JS_NewObjectWithGivenProto(cx, &SOWClass.base, NULL, parent);
+    JS_NewObjectWithGivenProto(cx, js::Jsvalify(&SOWClass), NULL, parent);
   if (!wrapperObj) {
     return JS_FALSE;
   }
 
   *vp = OBJECT_TO_JSVAL(wrapperObj);
   js::AutoObjectRooter tvr(cx, wrapperObj);
 
   if (!JS_SetReservedSlot(cx, wrapperObj, sWrappedObjSlot, v) ||
@@ -149,19 +155,19 @@ WrapObject(JSContext *cx, JSObject *pare
   return JS_TRUE;
 }
 
 JSBool
 MakeSOW(JSContext *cx, JSObject *obj)
 {
 #ifdef DEBUG
   {
-    JSClass *clasp = obj->getJSClass();
-    NS_ASSERTION(clasp != &SystemOnlyWrapper::SOWClass.base &&
-                 clasp != &XPCCrossOriginWrapper::XOWClass.base,
+    js::Class *clasp = obj->getClass();
+    NS_ASSERTION(clasp != &SystemOnlyWrapper::SOWClass &&
+                 clasp != &XPCCrossOriginWrapper::XOWClass,
                  "bad call");
   }
 #endif
 
   jsval flags;
   return JS_GetReservedSlot(cx, obj, sFlagsSlot, &flags) &&
          JS_SetReservedSlot(cx, obj, sFlagsSlot,
                             INT_TO_JSVAL(JSVAL_TO_INT(flags) | FLAG_SOW));
@@ -263,35 +269,27 @@ CheckFilename(JSContext *cx, jsid id, JS
 
 using namespace SystemOnlyWrapper;
 
 // Like GetWrappedObject, but works on other types of wrappers, too.
 // TODO Move to XPCWrapper?
 static inline JSObject *
 GetWrappedJSObject(JSContext *cx, JSObject *obj)
 {
-  JSClass *clasp = obj->getJSClass();
-  if (!(clasp->flags & JSCLASS_IS_EXTENDED)) {
-    return obj;
-  }
-
-  JSExtendedClass *xclasp = (JSExtendedClass *)clasp;
-  if (!xclasp->wrappedObject) {
-    return obj;
-  }
-
-  return xclasp->wrappedObject(cx, obj);
+  if (JSObjectOp op = obj->getClass()->ext.wrappedObject)
+    return op(cx, obj);
+  return obj;
 }
 
 // Get the (possibly nonexistent) SOW off of an object
 static inline
 JSObject *
 GetWrapper(JSObject *obj)
 {
-  while (obj->getJSClass() != &SOWClass.base) {
+  while (obj->getClass() != &SOWClass) {
     obj = obj->getProto();
     if (!obj) {
       break;
     }
   }
 
   return obj;
 }
@@ -400,17 +398,17 @@ XPC_SOW_RewrapValue(JSContext *cx, JSObj
         return JS_FALSE;
       }
       obj = JSVAL_TO_OBJECT(v);
     }
 
     return XPC_SOW_WrapFunction(cx, wrapperObj, obj, vp);
   }
 
-  if (obj->getJSClass() == &SOWClass.base) {
+  if (obj->getClass() == &SOWClass) {
     // We are extra careful about content-polluted wrappers here. I don't know
     // if it's possible to reach them through objects that we wrap, but figuring
     // that out is more expensive (and harder) than simply checking and
     // rewrapping here.
     if (wrapperObj->getParent() == obj->getParent()) {
       // Already wrapped.
       return JS_TRUE;
     }
@@ -425,17 +423,17 @@ XPC_SOW_RewrapValue(JSContext *cx, JSObj
   }
 
   return WrapObject(cx, wrapperObj->getParent(), v, vp);
 }
 
 static JSBool
 XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
-  NS_ASSERTION(obj->getJSClass() == &SOWClass.base, "Wrong object");
+  NS_ASSERTION(obj->getClass() == &SOWClass, "Wrong object");
 
   jsval resolving;
   if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &resolving)) {
     return JS_FALSE;
   }
 
   if (HAS_FLAGS(resolving, FLAG_RESOLVING)) {
     // Allow us to define a property on ourselves.
@@ -648,49 +646,42 @@ XPC_SOW_Equality(JSContext *cx, JSObject
   JSObject *lhs = GetWrappedObject(cx, obj);
   JSObject *rhs = GetWrappedJSObject(cx, JSVAL_TO_OBJECT(v));
   if (lhs == rhs) {
     *bp = JS_TRUE;
     return JS_TRUE;
   }
 
   if (lhs) {
-    // Delegate to our wrapped object if we can.
-    JSClass *clasp = lhs->getJSClass();
-    if (clasp->flags & JSCLASS_IS_EXTENDED) {
-      JSExtendedClass *xclasp = (JSExtendedClass *) clasp;
-      // NB: JSExtendedClass.equality is a required field.
+    if (JSEqualityOp op = js::Jsvalify(lhs->getClass()->ext.equality)) {
       jsval rhsVal = OBJECT_TO_JSVAL(rhs);
-      return xclasp->equality(cx, lhs, &rhsVal, bp);
+      return op(cx, lhs, &rhsVal, bp);
     }
   }
 
   // We know rhs is non-null.
-  JSClass *clasp = rhs->getJSClass();
-  if (clasp->flags & JSCLASS_IS_EXTENDED) {
-    JSExtendedClass *xclasp = (JSExtendedClass *) clasp;
-    // NB: JSExtendedClass.equality is a required field.
+  if (JSEqualityOp op = js::Jsvalify(rhs->getClass()->ext.equality)) {
     jsval lhsVal = OBJECT_TO_JSVAL(lhs);
-    return xclasp->equality(cx, rhs, &lhsVal, bp);
+    return op(cx, rhs, &lhsVal, bp);
   }
 
   *bp = JS_FALSE;
   return JS_TRUE;
 }
 
 static JSObject *
 XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
 {
   JSObject *wrappedObj = GetWrappedObject(cx, obj);
   if (!wrappedObj) {
     ThrowException(NS_ERROR_INVALID_ARG, cx);
     return nsnull;
   }
 
-  JSObject *wrapperIter = JS_NewObject(cx, &SOWClass.base, nsnull,
+  JSObject *wrapperIter = JS_NewObject(cx, js::Jsvalify(&SOWClass), nsnull,
                                        JS_GetGlobalForObject(cx, obj));
   if (!wrapperIter) {
     return nsnull;
   }
 
   js::AutoObjectRooter tvr(cx, wrapperIter);
 
   // Initialize our SOW.
--- a/js/src/xpconnect/src/XPCWrapper.cpp
+++ b/js/src/xpconnect/src/XPCWrapper.cpp
@@ -55,48 +55,48 @@ const PRUint32 FLAG_SOW = 0x2;
 const PRUint32 LAST_FLAG = FLAG_SOW;
 
 const PRUint32 sSecMgrSetProp = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
 const PRUint32 sSecMgrGetProp = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
 
 JSObject *
 Unwrap(JSContext *cx, JSObject *wrapper)
 {
-  JSClass *clasp = wrapper->getJSClass();
-  if (clasp == &XPCCrossOriginWrapper::XOWClass.base) {
+  js::Class *clasp = wrapper->getClass();
+  if (clasp == &XPCCrossOriginWrapper::XOWClass) {
     return UnwrapXOW(cx, wrapper);
   }
 
   if (XPCNativeWrapper::IsNativeWrapperClass(clasp)) {
     XPCWrappedNative *wrappedObj;
     if (!XPCNativeWrapper::GetWrappedNative(cx, wrapper, &wrappedObj) ||
         !wrappedObj) {
       return nsnull;
     }
 
     return wrappedObj->GetFlatJSObject();
   }
 
-  if (clasp == &XPCSafeJSObjectWrapper::SJOWClass.base) {
+  if (clasp == &XPCSafeJSObjectWrapper::SJOWClass) {
     JSObject *wrappedObj =
       XPCSafeJSObjectWrapper::GetUnsafeObject(cx, wrapper);
 
     if (NS_FAILED(XPCCrossOriginWrapper::CanAccessWrapper(cx, nsnull, wrappedObj, nsnull))) {
       JS_ClearPendingException(cx);
 
       return nsnull;
     }
 
     return wrappedObj;
   }
 
-  if (clasp == &SystemOnlyWrapper::SOWClass.base) {
+  if (clasp == &SystemOnlyWrapper::SOWClass) {
     return UnwrapSOW(cx, wrapper);
   }
-  if (clasp == &ChromeObjectWrapper::COWClass.base) {
+  if (clasp == &ChromeObjectWrapper::COWClass) {
     return UnwrapCOW(cx, wrapper);
   }
 
   return nsnull;
 }
 
 static void
 IteratorFinalize(JSContext *cx, JSObject *obj)
@@ -155,32 +155,43 @@ IteratorNext(JSContext *cx, uintN argc, 
 }
 
 static JSObject *
 IteratorIterator(JSContext *, JSObject *obj, JSBool)
 {
   return obj;
 }
 
-static JSExtendedClass IteratorClass = {
-  { "Wrapper iterator",
-    JSCLASS_HAS_RESERVED_SLOTS(3) | JSCLASS_IS_EXTENDED,
-    JS_PropertyStub, JS_PropertyStub,
-    JS_PropertyStub, JS_PropertyStub,
-    JS_EnumerateStub, JS_ResolveStub,
-    JS_ConvertStub, IteratorFinalize,
+static js::Class IteratorClass = {
+    "Wrapper iterator",
+    JSCLASS_HAS_RESERVED_SLOTS(3),
+    js::PropertyStub,   // addProperty
+    js::PropertyStub,   // delProperty 
+    js::PropertyStub,   // getProperty
+    js::PropertyStub,   // setProperty
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    js::ConvertStub,
+    IteratorFinalize,
+    nsnull,             // reserved0
+    nsnull,             // checkAccess
+    nsnull,             // call
+    nsnull,             // construct
+    nsnull,             // xdrObject
+    nsnull,             // hasInstance
+    nsnull,             // mark
 
-    JSCLASS_NO_OPTIONAL_MEMBERS
-  },
-
-  nsnull,             // equality
-  nsnull, nsnull,     // innerObject/outerObject
-  IteratorIterator,
-  nsnull,             // wrappedObject
-  JSCLASS_NO_RESERVED_MEMBERS
+    // ClassExtension
+    {
+      nsnull, // equality
+      nsnull, // outerObject
+      nsnull, // innerObject
+      IteratorIterator,
+      nsnull, // wrappedObject
+    }
 };
 
 JSBool
 RewrapObject(JSContext *cx, JSObject *scope, JSObject *obj, WrapperType hint,
              jsval *vp)
 {
   obj = UnsafeUnwrapSecurityWrapper(cx, obj);
   if (!obj) {
@@ -326,17 +337,17 @@ CreateIteratorObj(JSContext *cx, JSObjec
 {
   // This is rather ugly: we want to use the trick seen in Enumerate,
   // where we use our wrapper's resolve hook to determine if we should
   // enumerate a given property. However, we don't want to pollute the
   // identifiers with a next method, so we create an object that
   // delegates (via the __proto__ link) to the wrapper.
 
   JSObject *iterObj =
-    JS_NewObjectWithGivenProto(cx, &IteratorClass.base, tempWrapper, wrapperObj);
+    JS_NewObjectWithGivenProto(cx, js::Jsvalify(&IteratorClass), tempWrapper, wrapperObj);
   if (!iterObj) {
     return nsnull;
   }
 
   js::AutoObjectRooter tvr(cx, iterObj);
 
   // Do this sooner rather than later to avoid complications in
   // IteratorFinalize.
@@ -389,17 +400,17 @@ SimpleEnumerate(JSContext *cx, JSObject 
 
   return JS_TRUE;
 }
 
 JSObject *
 CreateSimpleIterator(JSContext *cx, JSObject *scope, JSBool keysonly,
                      JSObject *propertyContainer)
 {
-  JSObject *iterObj = JS_NewObjectWithGivenProto(cx, &IteratorClass.base,
+  JSObject *iterObj = JS_NewObjectWithGivenProto(cx, js::Jsvalify(&IteratorClass),
                                                  propertyContainer, scope);
   if (!iterObj) {
     return nsnull;
   }
 
   js::AutoObjectRooter tvr(cx, iterObj);
   if (!propertyContainer) {
     if (!JS_SetReservedSlot(cx, iterObj, 0, PRIVATE_TO_JSVAL(nsnull)) ||
--- a/js/src/xpconnect/src/XPCWrapper.h
+++ b/js/src/xpconnect/src/XPCWrapper.h
@@ -157,20 +157,20 @@ MakeSOW(JSContext *cx, JSObject *obj);
 JSBool
 AllowedToAct(JSContext *cx, jsid id);
 
 JSBool
 CheckFilename(JSContext *cx, jsid id, JSStackFrame *fp);
 
 }
 
-namespace ChromeObjectWrapper    { extern JSExtendedClass COWClass; }
-namespace XPCSafeJSObjectWrapper { extern JSExtendedClass SJOWClass; }
-namespace SystemOnlyWrapper      { extern JSExtendedClass SOWClass; }
-namespace XPCCrossOriginWrapper  { extern JSExtendedClass XOWClass; }
+namespace ChromeObjectWrapper    { extern js::Class COWClass; }
+namespace XPCSafeJSObjectWrapper { extern js::Class SJOWClass; }
+namespace SystemOnlyWrapper      { extern js::Class SOWClass; }
+namespace XPCCrossOriginWrapper  { extern js::Class XOWClass; }
 
 extern nsIScriptSecurityManager *gScriptSecurityManager;
 
 // This namespace wraps some common functionality between the three existing
 // wrappers. Its main purpose is to allow XPCCrossOriginWrapper to act both
 // as an XPCSafeJSObjectWrapper and as an XPCNativeWrapper when required to
 // do so (the decision is based on the principals of the wrapper and wrapped
 // objects).
@@ -316,19 +316,17 @@ MaybePreserveWrapper(JSContext *cx, XPCW
       ci->PreserveWrapper(wn->Native());
     }
   }
 }
 
 inline JSBool
 IsSecurityWrapper(JSObject *wrapper)
 {
-  JSClass *clasp = wrapper->getJSClass();
-  return (clasp->flags & JSCLASS_IS_EXTENDED) &&
-    ((JSExtendedClass*)clasp)->wrappedObject;
+  return !!wrapper->getClass()->ext.wrappedObject;
 }
 
 /**
  * Given an arbitrary object, Unwrap will return the wrapped object if the
  * passed-in object is a wrapper that Unwrap knows about *and* the
  * currently running code has permission to access both the wrapper and
  * wrapped object.
  *
@@ -338,19 +336,19 @@ IsSecurityWrapper(JSObject *wrapper)
  */
 JSObject *
 Unwrap(JSContext *cx, JSObject *wrapper);
 
 /**
  * Unwraps objects whose class is |xclasp|.
  */
 inline JSObject *
-UnwrapGeneric(JSContext *cx, const JSExtendedClass *xclasp, JSObject *wrapper)
+UnwrapGeneric(JSContext *cx, const js::Class *xclasp, JSObject *wrapper)
 {
-  if (wrapper->getJSClass() != &xclasp->base) {
+  if (wrapper->getClass() != xclasp) {
     return nsnull;
   }
 
   jsval v;
   if (!JS_GetReservedSlot(cx, wrapper, XPCWrapper::sWrappedObjSlot, &v)) {
     JS_ClearPendingException(cx);
     return nsnull;
   }
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -622,30 +622,30 @@ nsXPConnect::IsGray(void *thing)
 
 NS_IMETHODIMP
 nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb)
 {
     JSContext *cx = mCycleCollectionContext->GetJSContext();
 
     uint32 traceKind = js_GetGCThingTraceKind(p);
     JSObject *obj;
-    JSClass *clazz;
+    js::Class *clazz;
 
     // We do not want to add wrappers to the cycle collector if they're not
     // explicitly marked as main thread only, because the cycle collector isn't
     // able to deal with objects that might be used off of the main thread. We
     // do want to explicitly mark them for cycle collection if the wrapper has
     // an external reference, because the wrapper would mark the JS object if
     // we did add the wrapper to the cycle collector.
     JSBool dontTraverse = PR_FALSE;
     JSBool markJSObject = PR_FALSE;
     if(traceKind == JSTRACE_OBJECT)
     {
         obj = static_cast<JSObject*>(p);
-        clazz = obj->getJSClass();
+        clazz = obj->getClass();
 
         if(clazz == &XPC_WN_Tearoff_JSClass)
         {
             XPCWrappedNative *wrapper =
                 (XPCWrappedNative*)xpc_GetJSPrivate(obj->getParent());
             dontTraverse = WrapperIsNotMainThreadOnly(wrapper);
         }
         else if(IS_WRAPPER_CLASS(clazz) && IS_WN_WRAPPER_OBJECT(obj))
@@ -684,17 +684,17 @@ nsXPConnect::Traverse(void *p, nsCycleCo
         type = !markJSObject && IsGray(p) ? GCUnmarked : GCMarked;
     }
 
     if (cb.WantDebugInfo()) {
         char name[72];
         if(traceKind == JSTRACE_OBJECT)
         {
             JSObject *obj = static_cast<JSObject*>(p);
-            JSClass *clazz = obj->getJSClass();
+            js::Class *clazz = obj->getClass();
             if(XPCNativeWrapper::IsNativeWrapperClass(clazz))
             {
                 XPCWrappedNative* wn;
                 if(XPCNativeWrapper::GetWrappedNative(cx, obj, &wn) && wn)
                 {
                     XPCNativeScriptableInfo* si = wn->GetScriptableInfo();
                     if(si)
                     {
@@ -744,31 +744,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 == Jsvalify(&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 == Jsvalify(&js_FunctionClass))
+                else if(clazz == &js_FunctionClass)
                 {
                     JSFunction* fun = (JSFunction*) xpc_GetJSPrivate(obj);
                     JSString* str = JS_GetFunctionId(fun);
                     if(str)
                     {
                         NS_ConvertUTF16toUTF8
                             fname(reinterpret_cast<const PRUnichar*>(JS_GetStringChars(str)));
                         JS_snprintf(name, sizeof(name),
@@ -1011,19 +1011,16 @@ nsXPConnect::InitClasses(JSContext * aJS
     // Nest frame chain save/restore in request created by XPCCallContext.
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if(!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
     SaveFrame sf(aJSContext);
 
     xpc_InitJSxIDClassObjects();
 
-    if(!xpc_InitWrappedNativeJSOps())
-        return UnexpectedFailure(NS_ERROR_FAILURE);
-
     XPCWrappedNativeScope* scope =
         XPCWrappedNativeScope::GetNewOrUsed(ccx, aGlobalJSObj);
 
     if(!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     scope->RemoveWrappedNativeProtos();
 
@@ -1912,17 +1909,17 @@ nsXPConnect::RestoreWrappedNativePrototy
     if(!aClassInfo || !aPrototype)
         return UnexpectedFailure(NS_ERROR_INVALID_ARG);
 
     JSObject *protoJSObject;
     nsresult rv = aPrototype->GetJSObject(&protoJSObject);
     if(NS_FAILED(rv))
         return UnexpectedFailure(rv);
 
-    if(!IS_PROTO_CLASS(protoJSObject->getJSClass()))
+    if(!IS_PROTO_CLASS(protoJSObject->getClass()))
         return UnexpectedFailure(NS_ERROR_INVALID_ARG);
 
     XPCWrappedNativeScope* scope =
         XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
     if(!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     XPCWrappedNativeProto *proto =
--- a/js/src/xpconnect/src/xpcJSWeakReference.cpp
+++ b/js/src/xpconnect/src/xpcJSWeakReference.cpp
@@ -129,18 +129,18 @@ xpcJSWeakReference::Get()
             // Most users of XPCWrappedJS don't need to worry about
             // re-wrapping because things are implicitly rewrapped by
             // xpcconvert. However, because we're doing this directly
             // through the native call context, we need to call
             // nsXPConnect::GetWrapperForObject. But it takes a lot of
             // arguments! It turns out that the thisObject hook on XPConnect
             // objects does the right thing though, so...
 
-            if (obj->map->ops->thisObject &&
-                !(obj = obj->map->ops->thisObject(cx, obj)))
+            if (obj->getOps()->thisObject &&
+                !(obj = obj->getOps()->thisObject(cx, obj)))
             {
                 return NS_ERROR_FAILURE;
             }
 
             *retval = OBJECT_TO_JSVAL(obj);
         }
     }
 
--- a/js/src/xpconnect/src/xpccomponents.cpp
+++ b/js/src/xpconnect/src/xpccomponents.cpp
@@ -3112,17 +3112,17 @@ static JSBool
 sandbox_setProto(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     if (!JSVAL_IS_OBJECT(*vp)) {
         return JS_TRUE;
     }
 
     JSObject *pobj = JSVAL_TO_OBJECT(*vp);
     if (pobj) {
-        if (pobj->getJSClass() == &XPCCrossOriginWrapper::XOWClass.base &&
+        if (pobj->getClass() == &XPCCrossOriginWrapper::XOWClass &&
             !XPCWrapper::RewrapObject(cx, obj, pobj,
                                       XPCWrapper::XPCNW_EXPLICIT, vp)) {
             return JS_FALSE;
         }
     }
 
     return JS_SetPrototype(cx, obj, JSVAL_TO_OBJECT(*vp));
 }
@@ -3820,23 +3820,19 @@ nsXPCComponents_Utils::GetGlobalForObjec
 
   // first argument must be an object
   if(JSVAL_IS_PRIMITIVE(argv[0]))
     return NS_ERROR_XPC_BAD_CONVERT_JS;
 
   JSObject *obj = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(argv[0]));
   *rval = OBJECT_TO_JSVAL(obj);
 
-  // Outerize if necessary.  Embrace the ugliness!
-  JSClass *clasp = JS_GetClass(cx, obj);
-  if (clasp->flags & JSCLASS_IS_EXTENDED) {
-    JSExtendedClass *xclasp = reinterpret_cast<JSExtendedClass *>(clasp);
-    if (JSObjectOp outerize = xclasp->outerObject)
+  // Outerize if necessary.
+  if (JSObjectOp outerize = obj->getClass()->ext.outerObject)
       *rval = OBJECT_TO_JSVAL(outerize(cx, obj));
-  }
 
   cc->SetReturnValueWasSet(PR_TRUE);
   return NS_OK;
 }
 
 #ifdef XPC_USE_SECURITY_CHECKED_COMPONENT
 /* string canCreateWrapper (in nsIIDPtr iid); */
 NS_IMETHODIMP
--- a/js/src/xpconnect/src/xpcconvert.cpp
+++ b/js/src/xpconnect/src/xpcconvert.cpp
@@ -596,17 +596,16 @@ XPCConvert::JSData2Native(XPCCallContext
             {
                 return JS_FALSE;
             }
 #ifdef DEBUG
             const jschar* chars=nsnull;
             if(nsnull!=(chars = JS_GetStringCharsZ(cx, str)))
             {
                 NS_ASSERTION((! ILLEGAL_RANGE(chars[0])),"U+0080/U+0100 - U+FFFF data lost");
-                return JS_FALSE;
             }
 #endif // DEBUG
             *((char*)d) = bytes[0];
             break;
         }
     case nsXPTType::T_WCHAR  :
         {
             const jschar* chars=nsnull;
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -1262,60 +1262,102 @@ private:
 * Core classes for wrapped native objects for use from JavaScript...
 *
 ****************************************************************************
 ***************************************************************************/
 
 // These are the various JSClasses and callbacks whose use that required
 // visibility from more than one .cpp file.
 
-extern JSExtendedClass XPC_WN_NoHelper_JSClass;
-extern JSClass XPC_WN_NoMods_WithCall_Proto_JSClass;
-extern JSClass XPC_WN_NoMods_NoCall_Proto_JSClass;
-extern JSClass XPC_WN_ModsAllowed_WithCall_Proto_JSClass;
-extern JSClass XPC_WN_ModsAllowed_NoCall_Proto_JSClass;
-extern JSClass XPC_WN_Tearoff_JSClass;
-extern JSClass XPC_WN_NoHelper_Proto_JSClass;
+extern js::Class XPC_WN_NoHelper_JSClass;
+extern js::Class XPC_WN_NoMods_WithCall_Proto_JSClass;
+extern js::Class XPC_WN_NoMods_NoCall_Proto_JSClass;
+extern js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass;
+extern js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass;
+extern js::Class XPC_WN_Tearoff_JSClass;
+extern js::Class XPC_WN_NoHelper_Proto_JSClass;
 
 extern JSBool
 XPC_WN_Equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp);
 
-extern JSObjectOps *
-XPC_WN_Proto_GetObjectOps(JSContext *cx, JSClass *clazz);
-
 extern JSBool
 XPC_WN_CallMethod(JSContext *cx, JSObject *obj,
                   uintN argc, jsval *argv, jsval *vp);
 
 extern JSBool
 XPC_WN_GetterSetter(JSContext *cx, JSObject *obj,
                     uintN argc, jsval *argv, jsval *vp);
 
 extern JSBool
-xpc_InitWrappedNativeJSOps();
+XPC_WN_JSOp_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
+                      jsval *statep, jsid *idp);
+
+extern JSType
+XPC_WN_JSOp_TypeOf_Object(JSContext *cx, JSObject *obj);
+
+extern JSType
+XPC_WN_JSOp_TypeOf_Function(JSContext *cx, JSObject *obj);
+
+extern void
+XPC_WN_JSOp_Clear(JSContext *cx, JSObject *obj);
+
+extern JSObject*
+XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj);
+
+// Macros to initialize Object or Function like XPC_WN classes
+#define XPC_WN_WithCall_ObjectOps                                             \
+    {                                                                         \
+        nsnull, /* lookupProperty */                                          \
+        nsnull, /* defineProperty */                                          \
+        nsnull, /* getProperty    */                                          \
+        nsnull, /* setProperty    */                                          \
+        nsnull, /* getAttributes  */                                          \
+        nsnull, /* setAttributes  */                                          \
+        nsnull, /* deleteProperty */                                          \
+        js::Valueify(XPC_WN_JSOp_Enumerate),                                  \
+        XPC_WN_JSOp_TypeOf_Function,                                          \
+        nsnull, /* trace          */                                          \
+        XPC_WN_JSOp_ThisObject,                                               \
+        XPC_WN_JSOp_Clear                                                     \
+    }
+
+#define XPC_WN_NoCall_ObjectOps                                               \
+    {                                                                         \
+        nsnull, /* lookupProperty */                                          \
+        nsnull, /* defineProperty */                                          \
+        nsnull, /* getProperty    */                                          \
+        nsnull, /* setProperty    */                                          \
+        nsnull, /* getAttributes  */                                          \
+        nsnull, /* setAttributes  */                                          \
+        nsnull, /* deleteProperty */                                          \
+        js::Valueify(XPC_WN_JSOp_Enumerate),                                  \
+        XPC_WN_JSOp_TypeOf_Object,                                            \
+        nsnull, /* trace          */                                          \
+        XPC_WN_JSOp_ThisObject,                                               \
+        XPC_WN_JSOp_Clear                                                     \
+    }
 
 // Maybe this macro should check for class->enumerate ==
 // XPC_WN_Shared_Proto_Enumerate or something rather than checking for
 // 4 classes?
 #define IS_PROTO_CLASS(clazz)                                                 \
-          ((clazz) == &XPC_WN_NoMods_WithCall_Proto_JSClass ||                \
-           (clazz) == &XPC_WN_NoMods_NoCall_Proto_JSClass ||                  \
-           (clazz) == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||           \
-           (clazz) == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass)
+    ((clazz) == &XPC_WN_NoMods_WithCall_Proto_JSClass ||                      \
+     (clazz) == &XPC_WN_NoMods_NoCall_Proto_JSClass ||                        \
+     (clazz) == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||                 \
+     (clazz) == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass)
 
 // NOTE!!!
 //
 // If this ever changes,
 // nsScriptSecurityManager::doGetObjectPrincipal() *must* be updated
 // also!
 //
 // NOTE!!!
 #define IS_WRAPPER_CLASS(clazz)                                               \
-    (((clazz)->flags & JSCLASS_IS_EXTENDED) &&                                \
-     reinterpret_cast<JSExtendedClass*>(clazz)->equality == XPC_WN_Equality)
+    (clazz->ext.equality == js::Valueify(XPC_WN_Equality))
 
 inline JSBool
 DebugCheckWrapperClass(JSObject* obj)
 {
     NS_ASSERTION(IS_WRAPPER_CLASS(obj->getClass()),
                  "Forgot to check if this is a wrapper?");
     return JS_TRUE;
 }
@@ -1910,28 +1952,30 @@ public:
 // XPCNativeScriptableShared is used to hold the JSClass and the
 // associated scriptable flags for XPCWrappedNatives. These are shared across
 // the runtime and are garbage collected by xpconnect. We *used* to just store
 // this inside the XPCNativeScriptableInfo (usually owned by instances of
 // XPCWrappedNativeProto. This had two problems... It was wasteful, and it
 // was a big problem when wrappers are reparented to different scopes (and
 // thus different protos (the DOM does this).
 
-struct XPCNativeScriptableSharedJSClass : public JSExtendedClass
+struct XPCNativeScriptableSharedJSClass
 {
+    js::Class base;
     PRUint32 interfacesBitmap;
 };
 
 class XPCNativeScriptableShared
 {
 public:
     const XPCNativeScriptableFlags& GetFlags() const {return mFlags;}
     PRUint32                        GetInterfacesBitmap() const
         {return mJSClass.interfacesBitmap;}
-    JSClass*                        GetJSClass() {return &mJSClass.base;}
+    JSClass*                        GetJSClass()
+        {return js::Jsvalify(&mJSClass.base);}
     JSClass*                        GetSlimJSClass()
         {if(mCanBeSlim) return GetJSClass(); return nsnull;}
 
     XPCNativeScriptableShared(JSUint32 aFlags, char* aName,
                               PRUint32 interfacesBitmap)
         : mFlags(aFlags),
           mCanBeSlim(JS_FALSE)
         {memset(&mJSClass, 0, sizeof(mJSClass));
--- a/js/src/xpconnect/src/xpcquickstubs.cpp
+++ b/js/src/xpconnect/src/xpcquickstubs.cpp
@@ -291,17 +291,17 @@ LookupGetterOrSetter(JSContext *cx, JSBo
     // ensuring that we have an XPConnect prototype object ensures that
     // we are only going to expose quickstubbed properties to script.
     // Also be careful not to overwrite existing properties!
 
     const char *name = JSVAL_IS_STRING(idval)
                        ? JS_GetStringBytes(JSVAL_TO_STRING(idval))
                        : nsnull;
     if(!name ||
-       !IS_PROTO_CLASS(desc.obj->getJSClass()) ||
+       !IS_PROTO_CLASS(desc.obj->getClass()) ||
        (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) ||
        !(desc.getter || desc.setter) ||
        desc.setter == desc.obj->getJSClass()->setProperty)
     {
         JS_SET_RVAL(cx, vp, JSVAL_VOID);
         return JS_TRUE;
     }
 
@@ -358,17 +358,17 @@ DefineGetterOrSetter(JSContext *cx, uint
                                                 &found, &getter, &setter)))
         return JS_FALSE;
 
     // The property didn't exist, already has a getter or setter, or is not
     // our property, then just forward now.
     if(!obj2 ||
        (attrs & (JSPROP_GETTER | JSPROP_SETTER)) ||
        !(getter || setter) ||
-       !IS_PROTO_CLASS(obj2->getJSClass()))
+       !IS_PROTO_CLASS(obj2->getClass()))
         return forward(cx, argc, vp);
 
     // Reify the getter and setter...
     if(!ReifyPropertyOps(cx, obj, id, interned_id, name, getter, setter,
                          nsnull, nsnull))
         return JS_FALSE;
 
     return forward(cx, argc, vp);
@@ -499,18 +499,18 @@ GetMemberInfo(JSObject *obj,
 {
     // Get the interface name.  From DefinePropertyIfFound (in
     // xpcwrappednativejsops.cpp) and XPCThrower::Verbosify.
     //
     // We could instead make the quick stub could pass in its interface name,
     // but this code often produces a more specific error message, e.g.
     *ifaceName = "Unknown";
 
-    NS_ASSERTION(IS_WRAPPER_CLASS(obj->getJSClass()) ||
-                 obj->getJSClass() == &XPC_WN_Tearoff_JSClass,
+    NS_ASSERTION(IS_WRAPPER_CLASS(obj->getClass()) ||
+                 obj->getClass() == &XPC_WN_Tearoff_JSClass,
                  "obj must be a wrapper");
     XPCWrappedNativeProto *proto;
     if(IS_SLIM_WRAPPER(obj))
     {
         proto = GetSlimWrapperProto(obj);
     }
     else
     {
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -1119,17 +1119,19 @@ XPCWrappedNative::Init(XPCCallContext& c
             if(HasProto() && !HasSharedProto())
                 GetProto()->SetScriptableInfo(mScriptableInfo);
         }
     }
     XPCNativeScriptableInfo* si = mScriptableInfo;
 
     // create our flatJSObject
 
-    JSClass* jsclazz = si ? si->GetJSClass() : &XPC_WN_NoHelper_JSClass.base;
+    js::Class* jsclazz = si
+                         ? js::Valueify(si->GetJSClass())
+                         : &XPC_WN_NoHelper_JSClass;
 
     if(isGlobal)
     {
         // Resolving a global object's class can cause us to create a global's
         // JS class without the proper global flags. Notice that here and fix
         // the problem.
         if(!(jsclazz->flags & JSCLASS_IS_GLOBAL))
             jsclazz->flags |= JSCLASS_GLOBAL_FLAGS;
@@ -1153,18 +1155,18 @@ XPCWrappedNative::Init(XPCCallContext& c
     JSObject* protoJSObject = HasProto() ?
                                 GetProto()->GetJSProtoObject() :
                                 GetScope()->GetPrototypeNoHelper(ccx);
 
     if (!protoJSObject) {
         return JS_FALSE;
     }
 
-    mFlatJSObject = xpc_NewSystemInheritingJSObject(ccx, jsclazz, protoJSObject,
-                                                    parent);
+    mFlatJSObject = xpc_NewSystemInheritingJSObject(ccx, js::Jsvalify(jsclazz),
+                                                    protoJSObject, parent);
     if(!mFlatJSObject)
         return JS_FALSE;
 
     return FinishInit(ccx);
 }
 
 JSBool
 XPCWrappedNative::Init(XPCCallContext &ccx, JSObject *existingJSObject)
@@ -1678,17 +1680,17 @@ XPCWrappedNative::GetWrappedNativeOfJSOb
     // If we were passed a function object then we need to find the correct
     // wrapper out of those that might be in the callee obj's proto chain.
 
     if(funobj)
     {
         JSObject* funObjParent = funobj->getParent();
         NS_ASSERTION(funObjParent, "funobj has no parent");
 
-        JSClass* funObjParentClass = funObjParent->getJSClass();
+        js::Class* funObjParentClass = funObjParent->getClass();
 
         if(IS_PROTO_CLASS(funObjParentClass))
         {
             NS_ASSERTION(funObjParent->getParent(), "funobj's parent (proto) is global");
             proto = (XPCWrappedNativeProto*) xpc_GetJSPrivate(funObjParent);
             if(proto)
                 protoClassInfo = proto->GetClassInfo();
         }
@@ -1708,18 +1710,18 @@ XPCWrappedNative::GetWrappedNativeOfJSOb
             NS_ERROR("function object has parent of unknown class!");
             return nsnull;
         }
     }
 
     for(cur = obj; cur; cur = cur->getProto())
     {
         // this is on two lines to make the compiler happy given the goto.
-        JSClass* clazz;
-        clazz = cur->getJSClass();
+        js::Class* clazz;
+        clazz = cur->getClass();
 
         if(IS_WRAPPER_CLASS(clazz))
         {
 return_wrapper:
             JSBool isWN = IS_WN_WRAPPER_OBJECT(cur);
             XPCWrappedNative* wrapper =
                 isWN ? (XPCWrappedNative*) xpc_GetJSPrivate(cur) : nsnull;
             if(proto)
@@ -1766,22 +1768,19 @@ return_tearoff:
         if((unsafeObj = XPCWrapper::Unwrap(cx, cur)))
             return GetWrappedNativeOfJSObject(cx, unsafeObj, funobj, pobj2,
                                               pTearOff);
     }
 
     // If we didn't find a wrapper using the given funobj and obj, try
     // again with obj's outer object, if it's got one.
 
-    JSClass *clazz = obj->getJSClass();
-
-    if((clazz->flags & JSCLASS_IS_EXTENDED) &&
-        ((JSExtendedClass*)clazz)->outerObject)
+    if(JSObjectOp op = obj->getClass()->ext.outerObject)
     {
-        JSObject *outer = ((JSExtendedClass*)clazz)->outerObject(cx, obj);
+        JSObject *outer = op(cx, obj);
         if(outer && outer != obj)
             return GetWrappedNativeOfJSObject(cx, outer, funobj, pobj2,
                                               pTearOff);
     }
 
     if(pobj2)
         *pobj2 = nsnull;
     return nsnull;
@@ -2113,17 +2112,17 @@ XPCWrappedNative::InitTearOff(XPCCallCon
 
 JSBool
 XPCWrappedNative::InitTearOffJSObject(XPCCallContext& ccx,
                                       XPCWrappedNativeTearOff* to)
 {
     // This is only called while locked (during XPCWrappedNative::FindTearOff).
 
     JSObject* obj =
-        xpc_NewSystemInheritingJSObject(ccx, &XPC_WN_Tearoff_JSClass,
+        xpc_NewSystemInheritingJSObject(ccx, js::Jsvalify(&XPC_WN_Tearoff_JSClass),
                                         GetScope()->GetPrototypeJSObject(),
                                         mFlatJSObject);
 
     if(!obj || !JS_SetPrivate(ccx, obj, to))
         return JS_FALSE;
 
     to->SetJSObject(obj);
     return JS_TRUE;
--- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp
@@ -808,17 +808,17 @@ XPC_WN_Equality(JSContext *cx, JSObject 
     XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo();
     if(si && si->GetFlags().WantEquality())
     {
         nsresult rv = si->GetCallback()->Equality(wrapper, cx, obj, v, bp);
         if(NS_FAILED(rv))
             return Throw(rv, cx);
 
         if(!*bp && !JSVAL_IS_PRIMITIVE(v) &&
-           JSVAL_TO_OBJECT(v)->getJSClass() == &XPCSafeJSObjectWrapper::SJOWClass.base)
+           JSVAL_TO_OBJECT(v)->getClass() == &XPCSafeJSObjectWrapper::SJOWClass)
         {
             v = OBJECT_TO_JSVAL(XPCSafeJSObjectWrapper::GetUnsafeObject(cx, JSVAL_TO_OBJECT(v)));
 
             rv = si->GetCallback()->Equality(wrapper, cx, obj, v, bp);
             if(NS_FAILED(rv))
                 return Throw(rv, cx);
         }
     }
@@ -907,51 +907,66 @@ XPC_WN_InnerObject(JSContext *cx, JSObje
         }
 
         obj = newThis;
     }
 
     return obj;
 }
 
-JSObjectOps *XPC_WN_GetObjectOpsNoCall(JSContext *cx, JSClass *clazz);
-
-JSExtendedClass XPC_WN_NoHelper_JSClass = {
-    {
-        "XPCWrappedNative_NoHelper",    // name;
-        WRAPPER_SLOTS |
-        JSCLASS_PRIVATE_IS_NSISUPPORTS |
-        JSCLASS_MARK_IS_TRACE |
-        JSCLASS_IS_EXTENDED, // flags;
-
-        /* Mandatory non-null function pointer members. */
-        XPC_WN_OnlyIWrite_PropertyStub, // addProperty;
-        XPC_WN_CannotModifyPropertyStub,// delProperty;
-        JS_PropertyStub,                // getProperty;
-        XPC_WN_OnlyIWrite_PropertyStub, // setProperty;
+js::Class XPC_WN_NoHelper_JSClass = {
+    "XPCWrappedNative_NoHelper",    // name;
+    WRAPPER_SLOTS |
+    JSCLASS_PRIVATE_IS_NSISUPPORTS |
+    JSCLASS_MARK_IS_TRACE, // flags;
 
-        XPC_WN_Shared_Enumerate,        // enumerate;
-        XPC_WN_NoHelper_Resolve,        // resolve;
-        XPC_WN_Shared_Convert,          // convert;
-        XPC_WN_NoHelper_Finalize,       // finalize;
+    /* Mandatory non-null function pointer members. */
+    js::Valueify(XPC_WN_OnlyIWrite_PropertyStub), // addProperty
+    js::Valueify(XPC_WN_CannotModifyPropertyStub),// delProperty
+    js::PropertyStub,                             // getProperty
+    js::Valueify(XPC_WN_OnlyIWrite_PropertyStub), // setProperty
+   
+    XPC_WN_Shared_Enumerate,                      // enumerate
+    XPC_WN_NoHelper_Resolve,                      // resolve
+    js::Valueify(XPC_WN_Shared_Convert),          // convert
+    XPC_WN_NoHelper_Finalize,                     // finalize
+   
+    /* Optionally non-null members start here. */
+    nsnull,                         // reserved0
+    nsnull,                         // checkAccess
+    nsnull,                         // call
+    nsnull,                         // construct
+    nsnull,                         // xdrObject;
+    nsnull,                         // hasInstance
+    JS_CLASS_TRACE(XPC_WN_Shared_Trace), // mark/trace
 
-        /* Optionally non-null members start here. */
-        XPC_WN_GetObjectOpsNoCall,      // getObjectOps;
-        nsnull,                         // checkAccess;
-        nsnull,                         // call;
-        nsnull,                         // construct;
-        nsnull,                         // xdrObject;
-        nsnull,                         // hasInstance;
-        JS_CLASS_TRACE(XPC_WN_Shared_Trace), // mark/trace;
-        nsnull                          // spare;
+    // ClassExtension
+    {
+        js::Valueify(XPC_WN_Equality),
+        XPC_WN_OuterObject,
+        XPC_WN_InnerObject,
+        nsnull, // iteratorObject
+        nsnull, // wrappedObject
     },
-    XPC_WN_Equality,
-    XPC_WN_OuterObject,
-    XPC_WN_InnerObject,
-    nsnull,nsnull,nsnull,nsnull,nsnull
+   
+    // ObjectOps
+    {
+        nsnull, // lookupProperty
+        nsnull, // defineProperty
+        nsnull, // getProperty
+        nsnull, // setProperty
+        nsnull, // getAttributes
+        nsnull, // setAttributes
+        nsnull, // deleteProperty
+        js::Valueify(XPC_WN_JSOp_Enumerate),
+        XPC_WN_JSOp_TypeOf_Object,
+        nsnull, // trace
+        XPC_WN_JSOp_ThisObject,
+        XPC_WN_JSOp_Clear
+    }
 };
 
 
 /***************************************************************************/
 
 static JSBool
 XPC_WN_MaybeResolvingPropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
@@ -1233,21 +1248,16 @@ XPC_WN_Helper_NewResolve(JSContext *cx, 
         }
     }
 
     return retval;
 }
 
 /***************************************************************************/
 
-extern JS_IMPORT_DATA(JSObjectOps) js_ObjectOps;
-
-static JSObjectOps XPC_WN_WithCall_JSOps;
-static JSObjectOps XPC_WN_NoCall_JSOps;
-
 /*
     Here are the enumerator cases:
 
     set jsclass enumerate to stub (unless noted otherwise)
 
     if( helper wants new enumerate )
         if( DONT_ENUM_STATICS )
             forward to scriptable enumerate
@@ -1273,28 +1283,28 @@ static JSObjectOps XPC_WN_NoCall_JSOps;
 
     else //... if( helper wants NO enumerate )
         if( DONT_ENUM_STATICS )
             use enumerate stub - don't use this JSOp thing at all
         else
             do shared enumerate - don't use this JSOp thing at all
 */
 
-static JSBool
+JSBool
 XPC_WN_JSOp_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                       jsval *statep, jsid *idp)
 {
-    JSClass *clazz = obj->getJSClass();
-    if(!IS_WRAPPER_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base)
+    js::Class *clazz = obj->getClass();
+    if(!IS_WRAPPER_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass)
     {
         // obj must be a prototype object or a wrapper w/o a
-        // helper. Short circuit this call to
-        // js_ObjectOps.enumerate().
+        // helper. Short circuit this call to the default
+        // implementation.
 
-        return js_ObjectOps.enumerate(cx, obj, enum_op, js::Valueify(statep), idp);
+        return js_Enumerate(cx, obj, enum_op, js::Valueify(statep), idp);
     }
 
     MORPH_SLIM_WRAPPER(cx, obj);
 
     XPCCallContext ccx(JS_CALLER, cx, obj);
     XPCWrappedNative* wrapper = ccx.GetWrapper();
     THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper);
 
@@ -1351,38 +1361,38 @@ XPC_WN_JSOp_Enumerate(JSContext *cx, JSO
 
             if(NS_FAILED(rv) || !retval)
                 *statep = JSVAL_NULL;
 
             if(NS_FAILED(rv))
                 return Throw(rv, cx);
             if(!retval)
                 return JS_FALSE;
-            // Then fall through and call js_ObjectOps.enumerate...
+            // Then fall through and call the default implementation...
         }
     }
 
     // else call js_ObjectOps.enumerate...
 
-    return js_ObjectOps.enumerate(cx, obj, enum_op, js::Valueify(statep), idp);
+    return js_Enumerate(cx, obj, enum_op, js::Valueify(statep), idp);
 }
 
-static JSType
+JSType
 XPC_WN_JSOp_TypeOf_Object(JSContext *cx, JSObject *obj)
 {
     return JSTYPE_OBJECT;
 }
 
-static JSType
+JSType
 XPC_WN_JSOp_TypeOf_Function(JSContext *cx, JSObject *obj)
 {
     return JSTYPE_FUNCTION;
 }
 
-static void
+void
 XPC_WN_JSOp_Clear(JSContext *cx, JSObject *obj)
 {
     // We're likely to enter this JSOp with a wrapper prototype
     // object. In that case we won't find a wrapper, so we'll just
     // call into js_ObjectOps.clear(), which is exactly what we want.
 
     // If our scope is cleared, make sure we clear the scope of our
     // native wrapper as well.
@@ -1391,18 +1401,16 @@ XPC_WN_JSOp_Clear(JSContext *cx, JSObjec
 
     if(wrapper && wrapper->IsValid())
     {
         XPCNativeWrapper::ClearWrappedNativeScopes(cx, wrapper);
 
         nsXPConnect* xpc = nsXPConnect::GetXPConnect();
         xpc->UpdateXOWs(cx, wrapper, nsIXPConnect::XPC_XOW_CLEARSCOPE);
     }
-
-    js_ObjectOps.clear(cx, obj);
 }
 
 namespace {
 
 NS_STACK_CLASS class AutoPopJSContext
 {
 public:
   AutoPopJSContext(XPCJSContextStack *stack)
@@ -1431,17 +1439,17 @@ public:
 
 private:
   JSContext *mCx;
   XPCJSContextStack *mStack;
 };
 
 } // namespace
 
-static JSObject*
+JSObject*
 XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj)
 {
     // None of the wrappers we could potentially hand out are threadsafe so
     // just hand out the given object.
     if(!XPCPerThreadData::IsMainThread(cx))
         return obj;
 
     OBJ_TO_OUTER_OBJECT(cx, obj);
@@ -1528,47 +1536,16 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
             XPCThrower::Throw(rv, cx);
             return nsnull;
         }
     }
 
     return JSVAL_TO_OBJECT(retval.jsval_value());
 }
 
-JSObjectOps *
-XPC_WN_GetObjectOpsNoCall(JSContext *cx, JSClass *clazz)
-{
-    return &XPC_WN_NoCall_JSOps;
-}
-
-JSObjectOps *
-XPC_WN_GetObjectOpsWithCall(JSContext *cx, JSClass *clazz)
-{
-    return &XPC_WN_WithCall_JSOps;
-}
-
-JSBool xpc_InitWrappedNativeJSOps()
-{
-    if(!XPC_WN_NoCall_JSOps.lookupProperty)
-    {
-        memcpy(&XPC_WN_NoCall_JSOps, &js_ObjectOps, sizeof(JSObjectOps));
-        XPC_WN_NoCall_JSOps.enumerate = js::Valueify(XPC_WN_JSOp_Enumerate);
-        XPC_WN_NoCall_JSOps.typeOf = XPC_WN_JSOp_TypeOf_Object;
-        XPC_WN_NoCall_JSOps.clear = XPC_WN_JSOp_Clear;
-        XPC_WN_NoCall_JSOps.thisObject = XPC_WN_JSOp_ThisObject;
-
-        memcpy(&XPC_WN_WithCall_JSOps, &js_ObjectOps, sizeof(JSObjectOps));
-        XPC_WN_WithCall_JSOps.enumerate = js::Valueify(XPC_WN_JSOp_Enumerate);
-        XPC_WN_WithCall_JSOps.typeOf = XPC_WN_JSOp_TypeOf_Function;
-        XPC_WN_WithCall_JSOps.clear = XPC_WN_JSOp_Clear;
-        XPC_WN_WithCall_JSOps.thisObject = XPC_WN_JSOp_ThisObject;
-    }
-    return JS_TRUE;
-}
-
 /***************************************************************************/
 
 // static
 XPCNativeScriptableInfo*
 XPCNativeScriptableInfo::Construct(XPCCallContext& ccx,
                                    JSBool isGlobal,
                                    const XPCNativeScriptableCreateInfo* sci)
 {
@@ -1609,117 +1586,122 @@ XPCNativeScriptableInfo::Construct(XPCCa
 void
 XPCNativeScriptableShared::PopulateJSClass(JSBool isGlobal)
 {
     NS_ASSERTION(mJSClass.base.name, "bad state!");
 
     mJSClass.base.flags = WRAPPER_SLOTS |
                           JSCLASS_PRIVATE_IS_NSISUPPORTS |
                           JSCLASS_NEW_RESOLVE |
-                          JSCLASS_MARK_IS_TRACE |
-                          JSCLASS_IS_EXTENDED;
+                          JSCLASS_MARK_IS_TRACE;
 
     if(isGlobal)
         mJSClass.base.flags |= JSCLASS_GLOBAL_FLAGS;
 
+    JSPropertyOp addProperty;
     if(mFlags.WantAddProperty())
-        mJSClass.base.addProperty = XPC_WN_Helper_AddProperty;
+        addProperty = XPC_WN_Helper_AddProperty;
     else if(mFlags.UseJSStubForAddProperty())
-        mJSClass.base.addProperty = JS_PropertyStub;
+        addProperty = JS_PropertyStub;
     else if(mFlags.AllowPropModsDuringResolve())
-        mJSClass.base.addProperty = XPC_WN_MaybeResolvingPropertyStub;
+        addProperty = XPC_WN_MaybeResolvingPropertyStub;
     else
-        mJSClass.base.addProperty = XPC_WN_CannotModifyPropertyStub;
+        addProperty = XPC_WN_CannotModifyPropertyStub;
+    mJSClass.base.addProperty = js::Valueify(addProperty);
 
+    JSPropertyOp delProperty;
     if(mFlags.WantDelProperty())
-        mJSClass.base.delProperty = XPC_WN_Helper_DelProperty;
+        delProperty = XPC_WN_Helper_DelProperty;
     else if(mFlags.UseJSStubForDelProperty())
-        mJSClass.base.delProperty = JS_PropertyStub;
+        delProperty = JS_PropertyStub;
     else if(mFlags.AllowPropModsDuringResolve())
-        mJSClass.base.delProperty = XPC_WN_MaybeResolvingPropertyStub;
+        delProperty = XPC_WN_MaybeResolvingPropertyStub;
     else
-        mJSClass.base.delProperty = XPC_WN_CannotModifyPropertyStub;
+        delProperty = XPC_WN_CannotModifyPropertyStub;
+    mJSClass.base.delProperty = js::Valueify(delProperty);
 
     if(mFlags.WantGetProperty())
-        mJSClass.base.getProperty = XPC_WN_Helper_GetProperty;
+        mJSClass.base.getProperty = js::Valueify(XPC_WN_Helper_GetProperty);
     else
-        mJSClass.base.getProperty = JS_PropertyStub;
+        mJSClass.base.getProperty = js::PropertyStub;
 
+    JSPropertyOp setProperty;
     if(mFlags.WantSetProperty())
-        mJSClass.base.setProperty = XPC_WN_Helper_SetProperty;
+        setProperty = XPC_WN_Helper_SetProperty;
     else if(mFlags.UseJSStubForSetProperty())
-        mJSClass.base.setProperty = JS_PropertyStub;
+        setProperty = JS_PropertyStub;
     else if(mFlags.AllowPropModsDuringResolve())
-        mJSClass.base.setProperty = XPC_WN_MaybeResolvingPropertyStub;
+        setProperty = XPC_WN_MaybeResolvingPropertyStub;
     else
-        mJSClass.base.setProperty = XPC_WN_CannotModifyPropertyStub;
+        setProperty = XPC_WN_CannotModifyPropertyStub;
+    mJSClass.base.setProperty = js::Valueify(setProperty);
 
     // We figure out most of the enumerate strategy at call time.
 
     if(mFlags.WantNewEnumerate() || mFlags.WantEnumerate() ||
        mFlags.DontEnumStaticProps())
-        mJSClass.base.enumerate = JS_EnumerateStub;
+        mJSClass.base.enumerate = js::EnumerateStub;
     else
         mJSClass.base.enumerate = XPC_WN_Shared_Enumerate;
 
     // We have to figure out resolve strategy at call time
     mJSClass.base.resolve = (JSResolveOp) XPC_WN_Helper_NewResolve;
 
     if(mFlags.WantConvert())
-        mJSClass.base.convert = XPC_WN_Helper_Convert;
+        mJSClass.base.convert = js::Valueify(XPC_WN_Helper_Convert);
     else
-        mJSClass.base.convert = XPC_WN_Shared_Convert;
+        mJSClass.base.convert = js::Valueify(XPC_WN_Shared_Convert);
 
     if(mFlags.WantFinalize())
         mJSClass.base.finalize = XPC_WN_Helper_Finalize;
     else
         mJSClass.base.finalize = XPC_WN_NoHelper_Finalize;
 
     // We let the rest default to nsnull unless the helper wants them...
     if(mFlags.WantCheckAccess())
-        mJSClass.base.checkAccess = XPC_WN_Helper_CheckAccess;
+        mJSClass.base.checkAccess = js::Valueify(XPC_WN_Helper_CheckAccess);
 
-    // Note that we *must* set
-    //   mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsNoCall
-    // or
-    //   mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsWithCall
-    // (even for the cases were it does not do much) because with these
-    // dynamically generated JSClasses, the code in
-    // XPCWrappedNative::GetWrappedNativeOfJSObject() needs to look for
-    // that this callback pointer in order to identify that a given
+    // Note that we *must* set the ObjectOps (even for the cases were it does
+    // not do much) because with these dynamically generated JSClasses, the
+    // code in XPCWrappedNative::GetWrappedNativeOfJSObject() needs to look
+    // for that these callback pointers in order to identify that a given
     // JSObject represents a wrapper.
+    js::ObjectOps *ops = &mJSClass.base.ops;
+    ops->enumerate = js::Valueify(XPC_WN_JSOp_Enumerate);
+    ops->clear = XPC_WN_JSOp_Clear;
+    ops->thisObject = XPC_WN_JSOp_ThisObject;
 
     if(mFlags.WantCall() || mFlags.WantConstruct())
     {
-        mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsWithCall;
+        ops->typeOf = XPC_WN_JSOp_TypeOf_Function;
         if(mFlags.WantCall())
-            mJSClass.base.call = XPC_WN_Helper_Call;
+            mJSClass.base.call = js::Valueify(XPC_WN_Helper_Call);
         if(mFlags.WantConstruct())
-            mJSClass.base.construct = XPC_WN_Helper_Construct;
+            mJSClass.base.construct = js::Valueify(XPC_WN_Helper_Construct);
     }
     else
     {
-        mJSClass.base.getObjectOps = XPC_WN_GetObjectOpsNoCall;
+        ops->typeOf = XPC_WN_JSOp_TypeOf_Object;
     }
 
+    // Equality is a required hook.
+    mJSClass.base.ext.equality = js::Valueify(XPC_WN_Equality);
+
     if(mFlags.WantHasInstance())
-        mJSClass.base.hasInstance = XPC_WN_Helper_HasInstance;
+        mJSClass.base.hasInstance = js::Valueify(XPC_WN_Helper_HasInstance);
 
     if(mFlags.WantTrace())
         mJSClass.base.mark = JS_CLASS_TRACE(XPC_WN_Helper_Trace);
     else
         mJSClass.base.mark = JS_CLASS_TRACE(XPC_WN_Shared_Trace);
 
-    // Equality is a required hook.
-    mJSClass.equality = XPC_WN_Equality;
-
     if(mFlags.WantOuterObject())
-        mJSClass.outerObject = XPC_WN_OuterObject;
+        mJSClass.base.ext.outerObject = XPC_WN_OuterObject;
     if(mFlags.WantInnerObject())
-        mJSClass.innerObject = XPC_WN_InnerObject;
+        mJSClass.base.ext.innerObject = XPC_WN_InnerObject;
 
     if(!(mFlags & (nsIXPCScriptable::WANT_OUTER_OBJECT |
                    nsIXPCScriptable::WANT_INNER_OBJECT)))
         mCanBeSlim = JS_TRUE;
 }
 
 /***************************************************************************/
 /***************************************************************************/
@@ -1801,22 +1783,20 @@ XPC_WN_GetterSetter(JSContext *cx, JSObj
 }
 
 /***************************************************************************/
 
 static JSBool
 XPC_WN_Shared_Proto_Enumerate(JSContext *cx, JSObject *obj)
 {
     NS_ASSERTION(
-        JS_InstanceOf(cx, obj, &XPC_WN_ModsAllowed_WithCall_Proto_JSClass,
-                      nsnull) ||
-        JS_InstanceOf(cx, obj, &XPC_WN_ModsAllowed_NoCall_Proto_JSClass,
-                      nsnull) ||
-        JS_InstanceOf(cx, obj, &XPC_WN_NoMods_WithCall_Proto_JSClass, nsnull) ||
-        JS_InstanceOf(cx, obj, &XPC_WN_NoMods_NoCall_Proto_JSClass, nsnull),
+        obj->getClass() == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||
+        obj->getClass() == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass ||
+        obj->getClass() == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
+        obj->getClass() == &XPC_WN_NoMods_NoCall_Proto_JSClass,
         "bad proto");
     XPCWrappedNativeProto* self =
         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
     if(!self)
         return JS_FALSE;
 
     if(self->GetScriptableInfo() &&
        self->GetScriptableInfo()->GetFlags().DontEnumStaticProps())
@@ -1874,21 +1854,19 @@ XPC_WN_Shared_Proto_Trace(JSTracer *trc,
 }
 
 /*****************************************************/
 
 static JSBool
 XPC_WN_ModsAllowed_Proto_Resolve(JSContext *cx, JSObject *obj, jsid id)
 {
     NS_ASSERTION(
-        JS_InstanceOf(cx, obj, &XPC_WN_ModsAllowed_WithCall_Proto_JSClass,
-                      nsnull) ||
-        JS_InstanceOf(cx, obj, &XPC_WN_ModsAllowed_NoCall_Proto_JSClass,
-                      nsnull),
-                 "bad proto");
+        obj->getClass() == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||
+        obj->getClass() == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass,
+        "bad proto");
 
     XPCWrappedNativeProto* self =
         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
     if(!self)
         return JS_FALSE;
 
     XPCCallContext ccx(JS_CALLER, cx);
     if(!ccx.IsValid())
@@ -1900,103 +1878,77 @@ XPC_WN_ModsAllowed_Proto_Resolve(JSConte
 
     return DefinePropertyIfFound(ccx, obj, id,
                                  self->GetSet(), nsnull, nsnull,
                                  self->GetScope(),
                                  JS_TRUE, nsnull, nsnull, si,
                                  enumFlag, nsnull);
 }
 
-// Give our proto classes object ops that match the respective
-// wrappers so that the JS engine can share scope (maps) among
-// wrappers. This essentially duplicates the number of JSClasses we
-// use for prototype objects (from 2 to 4), but the scope sharing
-// benefit is well worth it.
-JSObjectOps *
-XPC_WN_Proto_GetObjectOps(JSContext *cx, JSClass *clazz)
-{
-    // Protos for wrappers that want calls to their call() hooks get
-    // jsops with a call hook, others get jsops w/o a call hook.
-
-    if(clazz == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass ||
-       clazz == &XPC_WN_NoMods_WithCall_Proto_JSClass)
-        return &XPC_WN_WithCall_JSOps;
-
-    NS_ASSERTION(clazz == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass ||
-                 clazz == &XPC_WN_NoMods_NoCall_Proto_JSClass ||
-                 clazz == &XPC_WN_NoHelper_Proto_JSClass,
-                 "bad proto");
-
-    return &XPC_WN_NoCall_JSOps;
-}
-
-JSClass XPC_WN_ModsAllowed_WithCall_Proto_JSClass = {
+js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass = {
     "XPC_WN_ModsAllowed_WithCall_Proto_JSClass", // name;
     WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
 
     /* Mandatory non-null function pointer members. */
-    JS_PropertyStub,                // addProperty;
-    JS_PropertyStub,                // delProperty;
-    JS_PropertyStub,                // getProperty;
-    JS_PropertyStub,                // setProperty;
-    XPC_WN_Shared_Proto_Enumerate,         // enumerate;
-    XPC_WN_ModsAllowed_Proto_Resolve,      // resolve;
-    XPC_WN_Shared_Proto_Convert,           // convert;
-    XPC_WN_Shared_Proto_Finalize,          // finalize;
+    js::PropertyStub,               // addProperty;
+    js::PropertyStub,               // delProperty;
+    js::PropertyStub,               // getProperty;
+    js::PropertyStub,               // setProperty;
+    XPC_WN_Shared_Proto_Enumerate,  // enumerate;
+    XPC_WN_ModsAllowed_Proto_Resolve, // resolve;
+    js::Valueify(XPC_WN_Shared_Proto_Convert), // convert;
+    XPC_WN_Shared_Proto_Finalize,   // finalize;
 
     /* Optionally non-null members start here. */
-    XPC_WN_Proto_GetObjectOps,      // getObjectOps;
+    nsnull,                         // reserved0;
     nsnull,                         // checkAccess;
     nsnull,                         // call;
     nsnull,                         // construct;
     nsnull,                         // xdrObject;
     nsnull,                         // hasInstance;
     JS_CLASS_TRACE(XPC_WN_Shared_Proto_Trace), // mark/trace;
-    nsnull                          // spare;
+
+    JS_NULL_CLASS_EXT,
+    XPC_WN_WithCall_ObjectOps
 };
 
-JSObjectOps *
-XPC_WN_ModsAllowedProto_NoCall_GetObjectOps(JSContext *cx, JSClass *clazz)
-{
-    return &XPC_WN_NoCall_JSOps;
-}
-
-JSClass XPC_WN_ModsAllowed_NoCall_Proto_JSClass = {
+js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass = {
     "XPC_WN_ModsAllowed_NoCall_Proto_JSClass", // name;
     WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
 
     /* Mandatory non-null function pointer members. */
-    JS_PropertyStub,                // addProperty;
-    JS_PropertyStub,                // delProperty;
-    JS_PropertyStub,                // getProperty;
-    JS_PropertyStub,                // setProperty;
-    XPC_WN_Shared_Proto_Enumerate,         // enumerate;
-    XPC_WN_ModsAllowed_Proto_Resolve,      // resolve;
-    XPC_WN_Shared_Proto_Convert,           // convert;
-    XPC_WN_Shared_Proto_Finalize,          // finalize;
+    js::PropertyStub,               // addProperty;
+    js::PropertyStub,               // delProperty;
+    js::PropertyStub,               // getProperty;
+    js::PropertyStub,               // setProperty;
+    XPC_WN_Shared_Proto_Enumerate,  // enumerate;
+    XPC_WN_ModsAllowed_Proto_Resolve,// resolve;
+    js::Valueify(XPC_WN_Shared_Proto_Convert), // convert;
+    XPC_WN_Shared_Proto_Finalize,    // finalize;
 
     /* Optionally non-null members start here. */
-    XPC_WN_Proto_GetObjectOps,      // getObjectOps;
+    nsnull,                         // reserved0;
     nsnull,                         // checkAccess;
     nsnull,                         // call;
     nsnull,                         // construct;
     nsnull,                         // xdrObject;
     nsnull,                         // hasInstance;
     JS_CLASS_TRACE(XPC_WN_Shared_Proto_Trace), // mark/trace;
-    nsnull                          // spare;
+
+    JS_NULL_CLASS_EXT,
+    XPC_WN_NoCall_ObjectOps
 };
 
 /***************************************************************************/
 
 static JSBool
 XPC_WN_OnlyIWrite_Proto_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
-    NS_ASSERTION(
-        JS_InstanceOf(cx, obj, &XPC_WN_NoMods_WithCall_Proto_JSClass, nsnull) ||
-        JS_InstanceOf(cx, obj, &XPC_WN_NoMods_NoCall_Proto_JSClass, nsnull),
+    NS_ASSERTION(obj->getClass() == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
+                 obj->getClass() == &XPC_WN_NoMods_NoCall_Proto_JSClass,
                  "bad proto");
 
     XPCWrappedNativeProto* self =
         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
     if(!self)
         return JS_FALSE;
 
     XPCCallContext ccx(JS_CALLER, cx);
@@ -2008,19 +1960,18 @@ XPC_WN_OnlyIWrite_Proto_PropertyStub(JSC
         return JS_TRUE;
 
     return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
 }
 
 static JSBool
 XPC_WN_NoMods_Proto_Resolve(JSContext *cx, JSObject *obj, jsid id)
 {
-    NS_ASSERTION(
-        JS_InstanceOf(cx, obj, &XPC_WN_NoMods_WithCall_Proto_JSClass, nsnull) ||
-        JS_InstanceOf(cx, obj, &XPC_WN_NoMods_NoCall_Proto_JSClass, nsnull),
+    NS_ASSERTION(obj->getClass() == &XPC_WN_NoMods_WithCall_Proto_JSClass ||
+                 obj->getClass() == &XPC_WN_NoMods_NoCall_Proto_JSClass,
                  "bad proto");
 
     XPCWrappedNativeProto* self =
         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
     if(!self)
         return JS_FALSE;
 
     XPCCallContext ccx(JS_CALLER, cx);
@@ -2035,64 +1986,68 @@ XPC_WN_NoMods_Proto_Resolve(JSContext *c
                                  self->GetSet(), nsnull, nsnull,
                                  self->GetScope(),
                                  JS_TRUE, nsnull, nsnull, si,
                                  JSPROP_READONLY |
                                  JSPROP_PERMANENT |
                                  enumFlag, nsnull);
 }
 
-JSClass XPC_WN_NoMods_WithCall_Proto_JSClass = {
+js::Class XPC_WN_NoMods_WithCall_Proto_JSClass = {
     "XPC_WN_NoMods_WithCall_Proto_JSClass",      // name;
     WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
 
     /* Mandatory non-null function pointer members. */
-    XPC_WN_OnlyIWrite_Proto_PropertyStub,  // addProperty;
-    XPC_WN_CannotModifyPropertyStub,       // delProperty;
-    JS_PropertyStub,                       // getProperty;
-    XPC_WN_OnlyIWrite_Proto_PropertyStub,  // setProperty;
-    XPC_WN_Shared_Proto_Enumerate,         // enumerate;
-    XPC_WN_NoMods_Proto_Resolve,           // resolve;
-    XPC_WN_Shared_Proto_Convert,           // convert;
-    XPC_WN_Shared_Proto_Finalize,          // finalize;
+    js::Valueify(XPC_WN_OnlyIWrite_Proto_PropertyStub), // addProperty;
+    js::Valueify(XPC_WN_CannotModifyPropertyStub),      // delProperty;
+    js::PropertyStub,                                   // getProperty;
+    js::Valueify(XPC_WN_OnlyIWrite_Proto_PropertyStub), // setProperty;
+    XPC_WN_Shared_Proto_Enumerate,                      // enumerate;
+    XPC_WN_NoMods_Proto_Resolve,                        // resolve;
+    js::Valueify(XPC_WN_Shared_Proto_Convert),          // convert;
+    XPC_WN_Shared_Proto_Finalize,                       // finalize;
 
     /* Optionally non-null members start here. */
-    XPC_WN_Proto_GetObjectOps,      // getObjectOps;
+    nsnull,                         // reserved0;
     nsnull,                         // checkAccess;
     nsnull,                         // call;
     nsnull,                         // construct;
     nsnull,                         // xdrObject;
     nsnull,                         // hasInstance;
     JS_CLASS_TRACE(XPC_WN_Shared_Proto_Trace), // mark/trace;
-    nsnull                          // spare;
+
+    JS_NULL_CLASS_EXT,
+    XPC_WN_WithCall_ObjectOps
 };
 
-JSClass XPC_WN_NoMods_NoCall_Proto_JSClass = {
-    "XPC_WN_NoMods_NoCall_Proto_JSClass",      // name;
-    WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
+js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = {
+    "XPC_WN_NoMods_NoCall_Proto_JSClass",               // name;
+    WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE,              // flags;
 
     /* Mandatory non-null function pointer members. */
-    XPC_WN_OnlyIWrite_Proto_PropertyStub,  // addProperty;
-    XPC_WN_CannotModifyPropertyStub,       // delProperty;
-    JS_PropertyStub,                       // getProperty;
-    XPC_WN_OnlyIWrite_Proto_PropertyStub,  // setProperty;
-    XPC_WN_Shared_Proto_Enumerate,         // enumerate;
-    XPC_WN_NoMods_Proto_Resolve,           // resolve;
-    XPC_WN_Shared_Proto_Convert,           // convert;
-    XPC_WN_Shared_Proto_Finalize,          // finalize;
+    js::Valueify(XPC_WN_OnlyIWrite_Proto_PropertyStub), // addProperty;
+    js::Valueify(XPC_WN_CannotModifyPropertyStub),      // delProperty;
+    js::PropertyStub,                                   // getProperty;
+    js::Valueify(XPC_WN_OnlyIWrite_Proto_PropertyStub), // setProperty;
+    XPC_WN_Shared_Proto_Enumerate,                      // enumerate;
+    XPC_WN_NoMods_Proto_Resolve,                        // resolve;
+    js::Valueify(XPC_WN_Shared_Proto_Convert),          // convert;
+    XPC_WN_Shared_Proto_Finalize,                       // finalize;
 
     /* Optionally non-null members start here. */
-    XPC_WN_Proto_GetObjectOps,      // getObjectOps;
+    nsnull,                         // reserved0;
     nsnull,                         // checkAccess;
     nsnull,                         // call;
     nsnull,                         // construct;
     nsnull,                         // xdrObject;
     nsnull,                         // hasInstance;
     JS_CLASS_TRACE(XPC_WN_Shared_Proto_Trace), // mark/trace;
-    nsnull                          // spare;
+
+    JS_NULL_CLASS_EXT,
+    XPC_WN_NoCall_ObjectOps
 };
 
 /***************************************************************************/
 
 static JSBool
 XPC_WN_TearOff_Enumerate(JSContext *cx, JSObject *obj)
 {
     MORPH_SLIM_WRAPPER(cx, obj);
@@ -2143,32 +2098,21 @@ XPC_WN_TearOff_Finalize(JSContext *cx, J
 {
     XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*)
         xpc_GetJSPrivate(obj);
     if(!p)
         return;
     p->JSObjectFinalized();
 }
 
-JSClass XPC_WN_Tearoff_JSClass = {
-    "WrappedNative_TearOff",            // name;
-    WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE, // flags;
+js::Class XPC_WN_Tearoff_JSClass = {
+    "WrappedNative_TearOff",                        // name;
+    WRAPPER_SLOTS | JSCLASS_MARK_IS_TRACE,          // flags;
 
-    /* Mandatory non-null function pointer members. */
-    XPC_WN_OnlyIWrite_PropertyStub,     // addProperty;
-    XPC_WN_CannotModifyPropertyStub,    // delProperty;
-    JS_PropertyStub,                    // getProperty;
-    XPC_WN_OnlyIWrite_PropertyStub,     // setProperty;
-    XPC_WN_TearOff_Enumerate,           // enumerate;
-    XPC_WN_TearOff_Resolve,             // resolve;
-    XPC_WN_Shared_Convert,              // convert;
-    XPC_WN_TearOff_Finalize,            // finalize;
-
-    /* Optionally non-null members start here. */
-    nsnull,                         // getObjectOps;
-    nsnull,                         // checkAccess;
-    nsnull,                         // call;
-    nsnull,                         // construct;
-    nsnull,                         // xdrObject;
-    nsnull,                         // hasInstance;
-    nsnull,                         // mark/trace;
-    nsnull                          // spare;
+    js::Valueify(XPC_WN_OnlyIWrite_PropertyStub),   // addProperty;
+    js::Valueify(XPC_WN_CannotModifyPropertyStub),  // delProperty;
+    js::PropertyStub,                               // getProperty;
+    js::Valueify(XPC_WN_OnlyIWrite_PropertyStub),   // setProperty;
+    XPC_WN_TearOff_Enumerate,                       // enumerate;
+    XPC_WN_TearOff_Resolve,                         // resolve;
+    js::Valueify(XPC_WN_Shared_Convert),            // convert;
+    XPC_WN_TearOff_Finalize                        // finalize;
 };
--- a/js/src/xpconnect/src/xpcwrappednativeproto.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativeproto.cpp
@@ -99,17 +99,17 @@ XPCWrappedNativeProto::Init(
     if(callback)
     {
         mScriptableInfo =
             XPCNativeScriptableInfo::Construct(ccx, isGlobal, scriptableCreateInfo);
         if(!mScriptableInfo)
             return JS_FALSE;
     }
 
-    JSClass* jsclazz;
+    js::Class* jsclazz;
 
 
     if(mScriptableInfo)
     {
         const XPCNativeScriptableFlags& flags(mScriptableInfo->GetFlags());
 
         if(flags.AllowPropModsToPrototype())
         {
@@ -127,17 +127,17 @@ XPCWrappedNativeProto::Init(
     else
     {
         jsclazz = &XPC_WN_NoMods_NoCall_Proto_JSClass;
     }
 
     JSObject *parent = mScope->GetGlobalJSObject();
 
     mJSProtoObject =
-        xpc_NewSystemInheritingJSObject(ccx, jsclazz,
+        xpc_NewSystemInheritingJSObject(ccx, js::Jsvalify(jsclazz),
                                         mScope->GetPrototypeJSObject(),
                                         parent);
 
     JSBool ok = mJSProtoObject && JS_SetPrivate(ccx, mJSProtoObject, this);
 
     if(ok && callback)
     {
         nsresult rv = callback->PostCreatePrototype(ccx, mJSProtoObject);
--- a/js/src/xpconnect/src/xpcwrappednativescope.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativescope.cpp
@@ -199,39 +199,41 @@ XPCWrappedNativeScope::SetComponents(nsX
 // scopes. By doing this we avoid allocating a new scope for every
 // wrapper on creation of the wrapper, and most wrappers won't need
 // their own scope at all for the lifetime of the wrapper.
 // WRAPPER_SLOTS is key here (even though there's never anything
 // in the private data slot in these prototypes), as the number of
 // reserved slots in this class needs to match that of the wrappers
 // for the JS engine to share scopes.
 
-JSClass XPC_WN_NoHelper_Proto_JSClass = {
+js::Class XPC_WN_NoHelper_Proto_JSClass = {
     "XPC_WN_NoHelper_Proto_JSClass",// name;
     WRAPPER_SLOTS,                  // flags;
 
     /* Mandatory non-null function pointer members. */
-    JS_PropertyStub,                // addProperty;
-    JS_PropertyStub,                // delProperty;
-    JS_PropertyStub,                // getProperty;
-    JS_PropertyStub,                // setProperty;
-    JS_EnumerateStub,               // enumerate;
+    js::PropertyStub,               // addProperty;
+    js::PropertyStub,               // delProperty;
+    js::PropertyStub,               // getProperty;
+    js::PropertyStub,               // setProperty;
+    js::EnumerateStub,              // enumerate;
     JS_ResolveStub,                 // resolve;
-    JS_ConvertStub,                 // convert;
+    js::ConvertStub,                // convert;
     nsnull,                         // finalize;
 
     /* Optionally non-null members start here. */
-    XPC_WN_Proto_GetObjectOps,      // getObjectOps;
+    nsnull,                         // reserved0;
     nsnull,                         // checkAccess;
     nsnull,                         // call;
     nsnull,                         // construct;
     nsnull,                         // xdrObject;
     nsnull,                         // hasInstance;
     nsnull,                         // mark/trace;
-    nsnull                          // spare;
+
+    JS_NULL_CLASS_EXT,
+    XPC_WN_NoCall_ObjectOps
 };
 
 
 void
 XPCWrappedNativeScope::SetGlobal(XPCCallContext& ccx, JSObject* aGlobal)
 {
     // We allow for calling this more than once. This feature is used by
     // nsXPConnect::InitClassesWithNewWrappedGlobal.
@@ -345,17 +347,18 @@ JSObject *
 XPCWrappedNativeScope::GetPrototypeNoHelper(XPCCallContext& ccx)
 {
     // We could create this prototype in SetGlobal(), but all scopes
     // don't need one, so we save ourselves a bit of space if we
     // create these when they're needed.
     if(!mPrototypeNoHelper)
     {
         mPrototypeNoHelper =
-            xpc_NewSystemInheritingJSObject(ccx, &XPC_WN_NoHelper_Proto_JSClass,
+            xpc_NewSystemInheritingJSObject(ccx,
+                                            js::Jsvalify(&XPC_WN_NoHelper_Proto_JSClass),
                                             mPrototypeJSObject,
                                             mGlobalJSObject);
 
         NS_ASSERTION(mPrototypeNoHelper,
                      "Failed to create prototype for wrappers w/o a helper");
     }
 
     return mPrototypeNoHelper;
@@ -720,17 +723,17 @@ XPCWrappedNativeScope::SystemIsBeingShut
 
 /***************************************************************************/
 
 static
 XPCWrappedNativeScope*
 GetScopeOfObject(JSObject* obj)
 {
     nsISupports* supports;
-    JSClass* clazz = obj->getJSClass();
+    js::Class* clazz = obj->getClass();
     JSBool isWrapper = IS_WRAPPER_CLASS(clazz);
 
     if(isWrapper && IS_SLIM_WRAPPER_OBJECT(obj))
         return GetSlimWrapperProto(obj)->GetScope();
 
     if(!isWrapper || !(supports = (nsISupports*) xpc_GetJSPrivate(obj)))
     {
 #ifdef DEBUG