Bug 1260984 (part 3) - Separate js::ClassSpec from js::Class. r=jorendorff.
authorNicholas Nethercote <nnethercote@mozilla.com>
Fri, 01 Apr 2016 10:59:54 +1100
changeset 291443 f29f34e249d2ca3a438beb108c1139a858b32ea1
parent 291442 e86362173ca4fd8365f0b9ceeb9e4851d488a1a5
child 291444 8167849e665a754e6301a617642cf3acfcb0b64a
push id18504
push userryanvm@gmail.com
push dateMon, 04 Apr 2016 01:41:59 +0000
treeherderfx-team@fc4a988ca8d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1260984
milestone48.0a1
Bug 1260984 (part 3) - Separate js::ClassSpec from js::Class. r=jorendorff. js::ClassSpec is often all null. When it's not all null, it's often duplicated among classes. By pulling it out into its own struct, and using a (possibly null) pointer in js::Class, we can save 138 KiB per process on 64-bit, and half that on 32-bit.
js/public/Class.h
js/src/builtin/Object.cpp
js/src/builtin/Promise.cpp
js/src/jsarray.cpp
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/vm/ErrorObject.h
js/src/vm/GlobalObject.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/SavedFrame.h
js/src/vm/SavedStacks.cpp
js/src/vm/TypedArrayObject.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -619,17 +619,17 @@ struct ClassExtension
      */
     JSObjectMovedOp objectMovedOp;
 };
 
 inline ClassObjectCreationOp DELEGATED_CLASSSPEC(const ClassSpec* spec) {
     return reinterpret_cast<ClassObjectCreationOp>(const_cast<ClassSpec*>(spec));
 }
 
-#define JS_NULL_CLASS_SPEC  {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}
+#define JS_NULL_CLASS_SPEC  nullptr
 #define JS_NULL_CLASS_EXT   {false,nullptr}
 
 struct ObjectOps
 {
     LookupPropertyOp lookupProperty;
     DefinePropertyOp defineProperty;
     HasPropertyOp    hasProperty;
     GetPropertyOp    getProperty;
@@ -649,17 +649,17 @@ struct ObjectOps
 
 // Classes, objects, and properties.
 
 typedef void (*JSClassInternal)();
 
 struct JSClass {
     JS_CLASS_MEMBERS(JSFinalizeOp);
 
-    void*               reserved[12];
+    void*               reserved[5];
 };
 
 #define JSCLASS_HAS_PRIVATE             (1<<0)  // objects have private slot
 #define JSCLASS_DELAY_METADATA_CALLBACK (1<<1)  // class's initialization code
                                                 // will call
                                                 // SetNewObjectMetadata itself
 #define JSCLASS_PRIVATE_IS_NSISUPPORTS  (1<<3)  // private is (nsISupports*)
 #define JSCLASS_IS_DOMJSCLASS           (1<<4)  // objects are DOM
@@ -751,17 +751,17 @@ struct JSClass {
 #define JSCLASS_NO_INTERNAL_MEMBERS     {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,JSCLASS_NO_INTERNAL_MEMBERS
 
 namespace js {
 
 struct Class
 {
     JS_CLASS_MEMBERS(FinalizeOp);
-    ClassSpec          spec;
+    const ClassSpec*    spec;
     ClassExtension      ext;
     const ObjectOps*    ops;
 
     /*
      * Objects of this class aren't native objects. They don't have Shapes that
      * describe their properties and layout. Classes using this flag must
      * provide their own property behavior, either by being proxy classes (do
      * this) or by overriding all the ObjectOps except getElements, watch and
@@ -799,16 +799,36 @@ struct Class
     }
 
     bool shouldDelayMetadataCallback() const {
         return flags & JSCLASS_DELAY_METADATA_CALLBACK;
     }
 
     static size_t offsetOfFlags() { return offsetof(Class, flags); }
 
+    bool specDefined()         const { return spec ? spec->defined()   : false; }
+    bool specDependent()       const { return spec ? spec->dependent() : false; }
+    JSProtoKey specParentKey() const { return spec ? spec->parentKey() : JSProto_Null; }
+    bool specShouldDefineConstructor()
+                               const { return spec ? spec->shouldDefineConstructor() : true; }
+    ClassObjectCreationOp specCreateConstructorHook()
+                               const { return spec ? spec->createConstructorHook()   : nullptr; }
+    ClassObjectCreationOp specCreatePrototypeHook()
+                               const { return spec ? spec->createPrototypeHook()     : nullptr; }
+    const JSFunctionSpec* specConstructorFunctions()
+                               const { return spec ? spec->constructorFunctions()    : nullptr; }
+    const JSPropertySpec* specConstructorProperties()
+                               const { return spec ? spec->constructorProperties()   : nullptr; }
+    const JSFunctionSpec* specPrototypeFunctions()
+                               const { return spec ? spec->prototypeFunctions()      : nullptr; }
+    const JSPropertySpec* specPrototypeProperties()
+                               const { return spec ? spec->prototypeProperties()     : nullptr; }
+    FinishClassInitOp specFinishInitHook()
+                               const { return spec ? spec->finishInitHook()          : nullptr; }
+
     LookupPropertyOp getOpsLookupProperty() const { return ops ? ops->lookupProperty : nullptr; }
     DefinePropertyOp getOpsDefineProperty() const { return ops ? ops->defineProperty : nullptr; }
     HasPropertyOp    getOpsHasProperty()    const { return ops ? ops->hasProperty    : nullptr; }
     GetPropertyOp    getOpsGetProperty()    const { return ops ? ops->getProperty    : nullptr; }
     SetPropertyOp    getOpsSetProperty()    const { return ops ? ops->setProperty    : nullptr; }
     GetOwnPropertyOp getOpsGetOwnPropertyDescriptor()
                                             const { return ops ? ops->getOwnPropertyDescriptor
                                                                                      : nullptr; }
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -1206,35 +1206,37 @@ FinishObjectClassInit(JSContext* cx, JS:
     Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
     if (global->shouldSplicePrototype(cx)) {
         if (!global->splicePrototype(cx, global->getClass(), tagged))
             return false;
     }
     return true;
 }
 
+static const ClassSpec PlainObjectClassSpec = {
+    CreateObjectConstructor,
+    CreateObjectPrototype,
+    object_static_methods,
+    nullptr,
+    object_methods,
+    object_properties,
+    FinishObjectClassInit
+};
+
 const Class PlainObject::class_ = {
     js_Object_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
     nullptr,  /* addProperty */
     nullptr,  /* delProperty */
     nullptr,  /* getProperty */
     nullptr,  /* setProperty */
     nullptr,  /* enumerate */
     nullptr,  /* resolve */
     nullptr,  /* mayResolve */
     nullptr,  /* finalize */
     nullptr,  /* call */
     nullptr,  /* hasInstance */
     nullptr,  /* construct */
     nullptr,  /* trace */
-    {
-        CreateObjectConstructor,
-        CreateObjectPrototype,
-        object_static_methods,
-        nullptr,
-        object_methods,
-        object_properties,
-        FinishObjectClassInit
-    }
+    &PlainObjectClassSpec
 };
 
 const Class* const js::ObjectClassPtr = &PlainObject::class_;
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -392,39 +392,52 @@ PromiseObject::reject(JSContext* cx, Han
 } // namespace js
 
 static JSObject*
 CreatePromisePrototype(JSContext* cx, JSProtoKey key)
 {
     return cx->global()->createBlankPrototype(cx, &PromiseObject::protoClass_);
 }
 
+static const ClassSpec PromiseObjectClassSpec = {
+    GenericCreateConstructor<PromiseConstructor, 1, gc::AllocKind::FUNCTION>,
+    CreatePromisePrototype,
+    promise_static_methods,
+    promise_static_properties,
+    promise_methods
+};
+
 const Class PromiseObject::class_ = {
     "Promise",
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Promise) |
     JSCLASS_HAS_XRAYED_CONSTRUCTOR,
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* getProperty */
     nullptr, /* setProperty */
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     nullptr, /* finalize */
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
     nullptr, /* trace */
-    {
-        GenericCreateConstructor<PromiseConstructor, 1, gc::AllocKind::FUNCTION>,
-        CreatePromisePrototype,
-        promise_static_methods,
-        promise_static_properties,
-        promise_methods
-    }
+    &PromiseObjectClassSpec
+};
+
+static const ClassSpec PromiseObjectProtoClassSpec = {
+    DELEGATED_CLASSSPEC(PromiseObject::class_.spec),
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    ClassSpec::IsDelegated
 };
 
 const Class PromiseObject::protoClass_ = {
     "PromiseProto",
     JSCLASS_HAS_CACHED_PROTO(JSProto_Promise),
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* getProperty */
@@ -432,19 +445,10 @@ const Class PromiseObject::protoClass_ =
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     nullptr, /* finalize */
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
     nullptr, /* trace  */
-    {
-        DELEGATED_CLASSSPEC(&PromiseObject::class_.spec),
-        nullptr,
-        nullptr,
-        nullptr,
-        nullptr,
-        nullptr,
-        nullptr,
-        ClassSpec::IsDelegated
-    }
+    &PromiseObjectProtoClassSpec
 };
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3257,40 +3257,42 @@ array_proto_finish(JSContext* cx, JS::Ha
         return false;
     }
 
     RootedId id(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().get(JS::SymbolCode::unscopables)));
     value.setObject(*unscopables);
     return DefineProperty(cx, proto, id, value, nullptr, nullptr, JSPROP_READONLY);
 }
 
+static const ClassSpec ArrayObjectClassSpec = {
+    GenericCreateConstructor<ArrayConstructor, 1, AllocKind::FUNCTION, &jit::JitInfo_Array>,
+    CreateArrayPrototype,
+    array_static_methods,
+    nullptr,
+    array_methods,
+    nullptr,
+    array_proto_finish
+};
+
 const Class ArrayObject::class_ = {
     "Array",
     JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | JSCLASS_DELAY_METADATA_CALLBACK,
     array_addProperty,
     nullptr, /* delProperty */
     nullptr, /* getProperty */
     nullptr, /* setProperty */
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     nullptr, /* finalize */
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
     nullptr, /* trace */
-    {
-        GenericCreateConstructor<ArrayConstructor, 1, AllocKind::FUNCTION, &jit::JitInfo_Array>,
-        CreateArrayPrototype,
-        array_static_methods,
-        nullptr,
-        array_methods,
-        nullptr,
-        array_proto_finish
-    }
+    &ArrayObjectClassSpec
 };
 
 /*
  * Array allocation functions.
  */
 
 static inline bool
 EnsureNewArrayElements(ExclusiveContext* cx, ArrayObject* obj, uint32_t length)
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -3267,41 +3267,54 @@ FinishDateClassInit(JSContext* cx, Handl
     RootedValue toUTCStringFun(cx);
     RootedId toUTCStringId(cx, NameToId(cx->names().toUTCString));
     RootedId toGMTStringId(cx, NameToId(cx->names().toGMTString));
     return NativeGetProperty(cx, proto.as<NativeObject>(), toUTCStringId, &toUTCStringFun) &&
            NativeDefineProperty(cx, proto.as<NativeObject>(), toGMTStringId, toUTCStringFun,
                                 nullptr, nullptr, 0);
 }
 
+static const ClassSpec DateObjectClassSpec = {
+    GenericCreateConstructor<DateConstructor, 7, gc::AllocKind::FUNCTION>,
+    CreateDatePrototype,
+    date_static_methods,
+    nullptr,
+    date_methods,
+    nullptr,
+    FinishDateClassInit
+};
+
 const Class DateObject::class_ = {
     js_Date_str,
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* getProperty */
     nullptr, /* setProperty */
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     nullptr, /* finalize */
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
     nullptr, /* trace */
-    {
-        GenericCreateConstructor<DateConstructor, 7, gc::AllocKind::FUNCTION>,
-        CreateDatePrototype,
-        date_static_methods,
-        nullptr,
-        date_methods,
-        nullptr,
-        FinishDateClassInit
-    }
+    &DateObjectClassSpec
+};
+
+static const ClassSpec DateObjectProtoClassSpec = {
+    DELEGATED_CLASSSPEC(DateObject::class_.spec),
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    ClassSpec::IsDelegated
 };
 
 const Class DateObject::protoClass_ = {
     js_Object_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* getProperty */
@@ -3309,26 +3322,17 @@ const Class DateObject::protoClass_ = {
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     nullptr, /* finalize */
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
     nullptr, /* trace  */
-    {
-        DELEGATED_CLASSSPEC(&DateObject::class_.spec),
-        nullptr,
-        nullptr,
-        nullptr,
-        nullptr,
-        nullptr,
-        nullptr,
-        ClassSpec::IsDelegated
-    }
+    &DateObjectProtoClassSpec
 };
 
 JSObject*
 js::NewDateObjectMsec(JSContext* cx, ClippedTime t, HandleObject proto /* = nullptr */)
 {
     JSObject* obj = NewObjectWithClassProto(cx, &DateObject::class_, proto);
     if (!obj)
         return nullptr;
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -60,87 +60,86 @@ static const JSPropertySpec exception_pr
 static const JSFunctionSpec exception_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str, exn_toSource, 0, 0),
 #endif
     JS_SELF_HOSTED_FN(js_toString_str, "ErrorToString", 0,0),
     JS_FS_END
 };
 
-#define IMPLEMENT_ERROR_SUBCLASS_EXTRA_FLAGS(name, extraClassSpecFlags)  \
+#define IMPLEMENT_ERROR_CLASS(name, classSpecPtr) \
     { \
         js_Error_str, /* yes, really */ \
         JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
         JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS), \
         nullptr,                 /* addProperty */ \
         nullptr,                 /* delProperty */ \
         nullptr,                 /* getProperty */ \
         nullptr,                 /* setProperty */ \
         nullptr,                 /* enumerate */ \
         nullptr,                 /* resolve */ \
         nullptr,                 /* mayResolve */ \
         exn_finalize, \
         nullptr,                 /* call        */ \
         nullptr,                 /* hasInstance */ \
         nullptr,                 /* construct   */ \
         nullptr,                 /* trace       */ \
-        { \
-            ErrorObject::createConstructor, \
-            ErrorObject::createProto, \
-            nullptr, \
-            nullptr, \
-            exception_methods, \
-            exception_properties, \
-            nullptr, \
-            JSProto_Error | extraClassSpecFlags \
-        } \
+        classSpecPtr \
     }
 
-#define IMPLEMENT_ERROR_SUBCLASS(name) \
-    IMPLEMENT_ERROR_SUBCLASS_EXTRA_FLAGS(name, 0)
+const ClassSpec
+ErrorObject::errorClassSpec_ = {
+    ErrorObject::createConstructor,
+    ErrorObject::createProto,
+    nullptr,
+    nullptr,
+    exception_methods,
+    exception_properties,
+    nullptr,
+    0
+};
+
+const ClassSpec
+ErrorObject::subErrorClassSpec_ = {
+    ErrorObject::createConstructor,
+    ErrorObject::createProto,
+    nullptr,
+    nullptr,
+    exception_methods,
+    exception_properties,
+    nullptr,
+    JSProto_Error
+};
+
+const ClassSpec
+ErrorObject::debuggeeWouldRunClassSpec_ = {
+    ErrorObject::createConstructor,
+    ErrorObject::createProto,
+    nullptr,
+    nullptr,
+    exception_methods,
+    exception_properties,
+    nullptr,
+    JSProto_Error | ClassSpec::DontDefineConstructor
+};
 
 const Class
 ErrorObject::classes[JSEXN_LIMIT] = {
-    {
-        js_Error_str,
-        JSCLASS_HAS_CACHED_PROTO(JSProto_Error) |
-        JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS),
-        nullptr,                 /* addProperty */
-        nullptr,                 /* delProperty */
-        nullptr,                 /* getProperty */
-        nullptr,                 /* setProperty */
-        nullptr,                 /* enumerate */
-        nullptr,                 /* resolve */
-        nullptr,                 /* mayResolve */
-        exn_finalize,
-        nullptr,                 /* call        */
-        nullptr,                 /* hasInstance */
-        nullptr,                 /* construct   */
-        nullptr,                 /* trace       */
-        {
-            ErrorObject::createConstructor,
-            ErrorObject::createProto,
-            nullptr,
-            nullptr,
-            exception_methods,
-            exception_properties,
-            nullptr
-        }
-    },
-    IMPLEMENT_ERROR_SUBCLASS(InternalError),
-    IMPLEMENT_ERROR_SUBCLASS(EvalError),
-    IMPLEMENT_ERROR_SUBCLASS(RangeError),
-    IMPLEMENT_ERROR_SUBCLASS(ReferenceError),
-    IMPLEMENT_ERROR_SUBCLASS(SyntaxError),
-    IMPLEMENT_ERROR_SUBCLASS(TypeError),
-    IMPLEMENT_ERROR_SUBCLASS(URIError),
+    IMPLEMENT_ERROR_CLASS(Error,          &ErrorObject::errorClassSpec_),
+    IMPLEMENT_ERROR_CLASS(InternalError,  &ErrorObject::subErrorClassSpec_),
+    IMPLEMENT_ERROR_CLASS(EvalError,      &ErrorObject::subErrorClassSpec_),
+    IMPLEMENT_ERROR_CLASS(RangeError,     &ErrorObject::subErrorClassSpec_),
+    IMPLEMENT_ERROR_CLASS(ReferenceError, &ErrorObject::subErrorClassSpec_),
+    IMPLEMENT_ERROR_CLASS(SyntaxError,    &ErrorObject::subErrorClassSpec_),
+    IMPLEMENT_ERROR_CLASS(TypeError,      &ErrorObject::subErrorClassSpec_),
+    IMPLEMENT_ERROR_CLASS(URIError,       &ErrorObject::subErrorClassSpec_),
 
     // DebuggeeWouldRun is a subclass of Error but is accessible via the
     // Debugger constructor, not the global.
-    IMPLEMENT_ERROR_SUBCLASS_EXTRA_FLAGS(DebuggeeWouldRun, ClassSpec::DontDefineConstructor),
+    IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun, &ErrorObject::debuggeeWouldRunClassSpec_)
 };
 
 JSErrorReport*
 js::CopyErrorReport(JSContext* cx, JSErrorReport* report)
 {
     /*
      * We use a single malloc block to make a deep copy of JSErrorReport with
      * the following layout:
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -638,17 +638,17 @@ ProtoKeyToClass(JSProtoKey key);
 // Returns true if the standard class identified by |key| inherits from
 // another standard class (in addition to Object) along its proto chain.
 //
 // In practice, this only returns true for Error subtypes.
 inline bool
 StandardClassIsDependent(JSProtoKey key)
 {
     const Class* clasp = ProtoKeyToClass(key);
-    return clasp && clasp->spec.defined() && clasp->spec.dependent();
+    return clasp && clasp->specDefined() && clasp->specDependent();
 }
 
 // Returns the key for the class inherited by a given standard class (that
 // is to say, the prototype of this standard class's prototype).
 //
 // You must be sure that this corresponds to a standard class with a cached
 // JSProtoKey before calling this function. In general |key| will match the
 // cached proto key, except in cases where multiple JSProtoKeys share a
@@ -657,17 +657,17 @@ inline JSProtoKey
 ParentKeyForStandardClass(JSProtoKey key)
 {
     // [Object] has nothing to inherit from.
     if (key == JSProto_Object)
         return JSProto_Null;
 
     // If we're dependent, return the key of the class we depend on.
     if (StandardClassIsDependent(key))
-        return ProtoKeyToClass(key)->spec.parentKey();
+        return ProtoKeyToClass(key)->specParentKey();
 
     // Otherwise, we inherit [Object].
     return JSProto_Object;
 }
 
 JS_FRIEND_API(bool)
 IsFunctionObject(JSObject* obj);
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -829,39 +829,41 @@ CreateFunctionPrototype(JSContext* cx, J
     if (!throwTypeError || !PreventExtensions(cx, throwTypeError))
         return nullptr;
 
     self->setThrowTypeError(throwTypeError);
 
     return functionProto;
 }
 
+static const ClassSpec JSFunctionClassSpec = {
+    CreateFunctionConstructor,
+    CreateFunctionPrototype,
+    nullptr,
+    nullptr,
+    function_methods,
+    function_properties
+};
+
 const Class JSFunction::class_ = {
     js_Function_str,
     JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
     nullptr,                 /* addProperty */
     nullptr,                 /* delProperty */
     nullptr,                 /* getProperty */
     nullptr,                 /* setProperty */
     fun_enumerate,
     fun_resolve,
     fun_mayResolve,
     nullptr,                 /* finalize    */
     nullptr,                 /* call        */
     fun_hasInstance,
     nullptr,                 /* construct   */
     fun_trace,
-    {
-        CreateFunctionConstructor,
-        CreateFunctionPrototype,
-        nullptr,
-        nullptr,
-        function_methods,
-        function_properties
-    }
+    &JSFunctionClassSpec
 };
 
 const Class* const js::FunctionClassPtr = &JSFunction::class_;
 
 /* Find the body of a function (not including braces). */
 bool
 js::FindBody(JSContext* cx, HandleFunction fun, HandleLinearString src, size_t* bodyStart,
              size_t* bodyEnd)
--- a/js/src/vm/ErrorObject.h
+++ b/js/src/vm/ErrorObject.h
@@ -36,16 +36,20 @@ class ErrorObject : public NativeObject
     static bool
     init(JSContext* cx, Handle<ErrorObject*> obj, JSExnType type,
          ScopedJSFreePtr<JSErrorReport>* errorReport, HandleString fileName, HandleObject stack,
          uint32_t lineNumber, uint32_t columnNumber, HandleString message);
 
     static bool checkAndUnwrapThis(JSContext* cx, CallArgs& args, const char* fnName,
                                    MutableHandle<ErrorObject*> error);
 
+    static const ClassSpec errorClassSpec_;
+    static const ClassSpec subErrorClassSpec_;
+    static const ClassSpec debuggeeWouldRunClassSpec_;
+
   protected:
     static const uint32_t EXNTYPE_SLOT          = 0;
     static const uint32_t STACK_SLOT            = EXNTYPE_SLOT + 1;
     static const uint32_t ERROR_REPORT_SLOT     = STACK_SLOT + 1;
     static const uint32_t FILENAME_SLOT         = ERROR_REPORT_SLOT + 1;
     static const uint32_t LINENUMBER_SLOT       = FILENAME_SLOT + 1;
     static const uint32_t COLUMNNUMBER_SLOT     = LINENUMBER_SLOT + 1;
     static const uint32_t MESSAGE_SLOT          = COLUMNNUMBER_SLOT + 1;
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -157,17 +157,17 @@ GlobalObject::resolveConstructor(JSConte
         return true;
 
     // Some classes have no init routine, which means that they're disabled at
     // compile-time. We could try to enforce that callers never pass such keys
     // to resolveConstructor, but that would cramp the style of consumers like
     // GlobalObject::initStandardClasses that want to just carpet-bomb-call
     // ensureConstructor with every JSProtoKey. So it's easier to just handle
     // it here.
-    bool haveSpec = clasp && clasp->spec.defined();
+    bool haveSpec = clasp && clasp->specDefined();
     if (!init && !haveSpec)
         return true;
 
     // See if there's an old-style initialization hook.
     if (init) {
         MOZ_ASSERT(!haveSpec);
         return init(cx, global);
     }
@@ -190,77 +190,79 @@ GlobalObject::resolveConstructor(JSConte
     // Function will also be resolved before we return.
     if (key == JSProto_Function && global->getPrototype(JSProto_Object).isUndefined())
         return resolveConstructor(cx, global, JSProto_Object);
 
     // We don't always have a prototype (i.e. Math and JSON). If we don't,
     // |createPrototype|, |prototypeFunctions|, and |prototypeProperties|
     // should all be null.
     RootedObject proto(cx);
-    if (clasp->spec.createPrototypeHook()) {
-        proto = clasp->spec.createPrototypeHook()(cx, key);
+    if (ClassObjectCreationOp createPrototype = clasp->specCreatePrototypeHook()) {
+        proto = createPrototype(cx, key);
         if (!proto)
             return false;
 
         // Make sure that creating the prototype didn't recursively resolve our
         // own constructor. We can't just assert that there's no prototype; OOMs
         // can result in incomplete resolutions in which the prototype is saved
         // but not the constructor. So use the same criteria that protects entry
         // into this function.
         MOZ_ASSERT(!global->isStandardClassResolved(key));
 
         global->setPrototype(key, ObjectValue(*proto));
     }
 
     // Create the constructor.
-    RootedObject ctor(cx, clasp->spec.createConstructorHook()(cx, key));
+    RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, key));
     if (!ctor)
         return false;
 
     RootedId id(cx, NameToId(ClassName(key, cx)));
-    if (clasp->spec.shouldDefineConstructor()) {
+    if (clasp->specShouldDefineConstructor()) {
         if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
             return false;
     }
 
     global->setConstructor(key, ObjectValue(*ctor));
     global->setConstructorPropertySlot(key, ObjectValue(*ctor));
 
     // Define any specified functions and properties, unless we're a dependent
     // standard class (in which case they live on the prototype), or we're
     // operating on the self-hosting global, in which case we don't want any
     // functions and properties on the builtins and their prototypes.
     if (!StandardClassIsDependent(key) && !cx->runtime()->isSelfHostingGlobal(global)) {
-        if (const JSFunctionSpec* funs = clasp->spec.prototypeFunctions()) {
+        if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) {
             if (!JS_DefineFunctions(cx, proto, funs))
                 return false;
         }
-        if (const JSPropertySpec* props = clasp->spec.prototypeProperties()) {
+        if (const JSPropertySpec* props = clasp->specPrototypeProperties()) {
             if (!JS_DefineProperties(cx, proto, props))
                 return false;
         }
-        if (const JSFunctionSpec* funs = clasp->spec.constructorFunctions()) {
+        if (const JSFunctionSpec* funs = clasp->specConstructorFunctions()) {
             if (!JS_DefineFunctions(cx, ctor, funs))
                 return false;
         }
-        if (const JSPropertySpec* props = clasp->spec.constructorProperties()) {
+        if (const JSPropertySpec* props = clasp->specConstructorProperties()) {
             if (!JS_DefineProperties(cx, ctor, props))
                 return false;
         }
     }
 
     // If the prototype exists, link it with the constructor.
     if (proto && !LinkConstructorAndPrototype(cx, ctor, proto))
         return false;
 
     // Call the post-initialization hook, if provided.
-    if (clasp->spec.finishInitHook() && !clasp->spec.finishInitHook()(cx, ctor, proto))
-        return false;
+    if (FinishClassInitOp finishInit = clasp->specFinishInitHook()) {
+        if (!finishInit(cx, ctor, proto))
+            return false;
+    }
 
-    if (clasp->spec.shouldDefineConstructor()) {
+    if (clasp->specShouldDefineConstructor()) {
         // Stash type information, so that what we do here is equivalent to
         // initBuiltinConstructor.
         AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
     }
 
     return true;
 }
 
@@ -411,21 +413,21 @@ GlobalObject::initStandardClasses(JSCont
  * self-hosted builtins.
  */
 static bool
 InitBareBuiltinCtor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey protoKey)
 {
     MOZ_ASSERT(cx->runtime()->isSelfHostingGlobal(global));
     const Class* clasp = ProtoKeyToClass(protoKey);
     RootedObject proto(cx);
-    proto = clasp->spec.createPrototypeHook()(cx, protoKey);
+    proto = clasp->specCreatePrototypeHook()(cx, protoKey);
     if (!proto)
         return false;
 
-    RootedObject ctor(cx, clasp->spec.createConstructorHook()(cx, protoKey));
+    RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, protoKey));
     if (!ctor)
         return false;
 
     return GlobalObject::initBuiltinConstructor(cx, global, protoKey, ctor, proto);
 }
 
 /**
  * The self-hosting global only gets a small subset of all standard classes.
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -180,16 +180,25 @@ RegExpObject::trace(JSTracer* trc, JSObj
         !obj->asTenured().zone()->isPreservingCode())
     {
         obj->as<RegExpObject>().NativeObject::setPrivate(nullptr);
     } else {
         shared->trace(trc);
     }
 }
 
+static const ClassSpec RegExpObjectClassSpec = {
+    GenericCreateConstructor<js::regexp_construct, 2, gc::AllocKind::FUNCTION>,
+    CreateRegExpPrototype,
+    nullptr,
+    js::regexp_static_props,
+    js::regexp_methods,
+    js::regexp_properties
+};
+
 const Class RegExpObject::class_ = {
     js_RegExp_str,
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(RegExpObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp),
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* getProperty */
@@ -197,26 +206,17 @@ const Class RegExpObject::class_ = {
     nullptr, /* enumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     nullptr, /* finalize */
     nullptr, /* call */
     nullptr, /* hasInstance */
     nullptr, /* construct */
     RegExpObject::trace,
-
-    // ClassSpec
-    {
-        GenericCreateConstructor<js::regexp_construct, 2, gc::AllocKind::FUNCTION>,
-        CreateRegExpPrototype,
-        nullptr,
-        js::regexp_static_props,
-        js::regexp_methods,
-        js::regexp_properties
-    }
+    &RegExpObjectClassSpec
 };
 
 RegExpObject*
 RegExpObject::create(ExclusiveContext* cx, const char16_t* chars, size_t length, RegExpFlag flags,
                      TokenStream* tokenStream, LifoAlloc& alloc)
 {
     RootedAtom source(cx, AtomizeChars(cx, chars, length));
     if (!source)
--- a/js/src/vm/SavedFrame.h
+++ b/js/src/vm/SavedFrame.h
@@ -13,16 +13,18 @@
 #include "js/UbiNode.h"
 
 namespace js {
 
 class SavedFrame : public NativeObject {
     friend class SavedStacks;
     friend struct ::JSStructuredCloneReader;
 
+    static const ClassSpec      classSpec_;
+
   public:
     static const Class          class_;
     static const JSPropertySpec protoAccessors[];
     static const JSFunctionSpec protoFunctions[];
     static const JSFunctionSpec staticFunctions[];
 
     // Prototype methods and properties to be exposed to JS.
     static bool construct(JSContext* cx, unsigned argc, Value* vp);
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -284,16 +284,27 @@ SavedFrame::finishSavedFrameInit(JSConte
 {
     // The only object with the SavedFrame::class_ that doesn't have a source
     // should be the prototype.
     proto->as<NativeObject>().setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue());
 
     return FreezeObject(cx, proto);
 }
 
+const ClassSpec SavedFrame::classSpec_ = {
+    GenericCreateConstructor<SavedFrame::construct, 0, gc::AllocKind::FUNCTION>,
+    GenericCreatePrototype,
+    SavedFrame::staticFunctions,
+    nullptr,
+    SavedFrame::protoFunctions,
+    SavedFrame::protoAccessors,
+    SavedFrame::finishSavedFrameInit,
+    ClassSpec::DontDefineConstructor
+};
+
 /* static */ const Class SavedFrame::class_ = {
     "SavedFrame",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_SavedFrame) |
     JSCLASS_IS_ANONYMOUS,
     nullptr,                    // addProperty
     nullptr,                    // delProperty
@@ -302,28 +313,17 @@ SavedFrame::finishSavedFrameInit(JSConte
     nullptr,                    // enumerate
     nullptr,                    // resolve
     nullptr,                    // mayResolve
     SavedFrame::finalize,       // finalize
     nullptr,                    // call
     nullptr,                    // hasInstance
     nullptr,                    // construct
     nullptr,                    // trace
-
-    // ClassSpec
-    {
-        GenericCreateConstructor<SavedFrame::construct, 0, gc::AllocKind::FUNCTION>,
-        GenericCreatePrototype,
-        SavedFrame::staticFunctions,
-        nullptr,
-        SavedFrame::protoFunctions,
-        SavedFrame::protoAccessors,
-        SavedFrame::finishSavedFrameInit,
-        ClassSpec::DontDefineConstructor
-    }
+    &SavedFrame::classSpec_
 };
 
 /* static */ const JSFunctionSpec
 SavedFrame::staticFunctions[] = {
     JS_FS_END
 };
 
 /* static */ const JSFunctionSpec
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -856,16 +856,28 @@ TypedArrayObject::protoFunctions[] = {
 
 /* static */ const JSFunctionSpec
 TypedArrayObject::staticFunctions[] = {
     JS_SELF_HOSTED_FN("from", "TypedArrayStaticFrom", 3, 0),
     JS_SELF_HOSTED_FN("of", "TypedArrayStaticOf", 0, 0),
     JS_FS_END
 };
 
+static const ClassSpec
+TypedArrayObjectSharedTypedArrayPrototypeClassSpec = {
+    GenericCreateConstructor<TypedArrayConstructor, 3, gc::AllocKind::FUNCTION>,
+    GenericCreatePrototype,
+    TypedArrayObject::staticFunctions,
+    nullptr,
+    TypedArrayObject::protoFunctions,
+    TypedArrayObject::protoAccessors,
+    nullptr,
+    ClassSpec::DontDefineConstructor
+};
+
 /* static */ const Class
 TypedArrayObject::sharedTypedArrayPrototypeClass = {
     // Actually ({}).toString.call(%TypedArray%.prototype) should throw,
     // because %TypedArray%.prototype lacks the the typed array internal
     // slots.  (It's not clear this is desirable -- particularly applied to
     // the actual typed array prototypes, see below -- but it's what ES6
     // draft 20140824 requires.)  But this is about as much as we can do
     // until we implement @@toStringTag.
@@ -878,26 +890,17 @@ TypedArrayObject::sharedTypedArrayProtot
     nullptr,                /* enumerate */
     nullptr,                /* resolve */
     nullptr,                /* mayResolve */
     nullptr,                /* finalize */
     nullptr,                /* call */
     nullptr,                /* hasInstance */
     nullptr,                /* construct */
     nullptr,                /* trace */
-    {
-        GenericCreateConstructor<TypedArrayConstructor, 3, gc::AllocKind::FUNCTION>,
-        GenericCreatePrototype,
-        TypedArrayObject::staticFunctions,
-        nullptr,
-        TypedArrayObject::protoFunctions,
-        TypedArrayObject::protoAccessors,
-        nullptr,
-        ClassSpec::DontDefineConstructor
-    }
+    &TypedArrayObjectSharedTypedArrayPrototypeClassSpec
 };
 
 template<typename T>
 bool
 ArrayBufferObject::createTypedArrayFromBufferImpl(JSContext* cx, const CallArgs& args)
 {
     typedef TypedArrayObjectTemplate<T> ArrayType;
     MOZ_ASSERT(IsArrayBuffer(args.thisv()));
@@ -1900,114 +1903,141 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uin
 IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint8Clamped, uint8_t, uint8_clamped)
 IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int16, int16_t, int16_t)
 IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint16, uint16_t, uint16_t)
 IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int32, int32_t, int32_t)
 IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint32, uint32_t, uint32_t)
 IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float32, float, float)
 IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
 
-#define TYPED_ARRAY_CLASS_SPEC(_typedArray)                                    \
+#define IMPL_TYPED_ARRAY_CLASS_SPEC(_type)                                     \
 {                                                                              \
-    _typedArray::createConstructor,                                            \
-    _typedArray::createPrototype,                                              \
+    _type##Array::createConstructor,                                           \
+    _type##Array::createPrototype,                                             \
     nullptr,                                                                   \
     nullptr,                                                                   \
     nullptr,                                                                   \
     nullptr,                                                                   \
-    _typedArray::finishClassInit,                                              \
+    _type##Array::finishClassInit,                                             \
     JSProto_TypedArray                                                         \
 }
 
-#define IMPL_TYPED_ARRAY_CLASS(_typedArray)                                    \
+static const ClassSpec TypedArrayObjectClassSpecs[Scalar::MaxTypedArrayViewType] = {
+    IMPL_TYPED_ARRAY_CLASS_SPEC(Int8),
+    IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8),
+    IMPL_TYPED_ARRAY_CLASS_SPEC(Int16),
+    IMPL_TYPED_ARRAY_CLASS_SPEC(Uint16),
+    IMPL_TYPED_ARRAY_CLASS_SPEC(Int32),
+    IMPL_TYPED_ARRAY_CLASS_SPEC(Uint32),
+    IMPL_TYPED_ARRAY_CLASS_SPEC(Float32),
+    IMPL_TYPED_ARRAY_CLASS_SPEC(Float64),
+    IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8Clamped)
+};
+
+#define IMPL_TYPED_ARRAY_CLASS(_type)                                          \
 {                                                                              \
-    #_typedArray,                                                              \
+    #_type "Array",                                                            \
     JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) |             \
     JSCLASS_HAS_PRIVATE |                                                      \
-    JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray) |                          \
+    JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array) |                         \
     JSCLASS_DELAY_METADATA_CALLBACK,                                           \
     nullptr,                 /* addProperty */                                 \
     nullptr,                 /* delProperty */                                 \
     nullptr,                 /* getProperty */                                 \
     nullptr,                 /* setProperty */                                 \
     nullptr,                 /* enumerate   */                                 \
     nullptr,                 /* resolve     */                                 \
     nullptr,                 /* mayResolve  */                                 \
     nullptr,                 /* finalize    */                                 \
     nullptr,                 /* call        */                                 \
     nullptr,                 /* hasInstance */                                 \
     nullptr,                 /* construct   */                                 \
     TypedArrayObject::trace, /* trace  */                                      \
-    TYPED_ARRAY_CLASS_SPEC(_typedArray)                                        \
+    &TypedArrayObjectClassSpecs[Scalar::Type::_type]                           \
 }
 
 const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
-    IMPL_TYPED_ARRAY_CLASS(Int8Array),
-    IMPL_TYPED_ARRAY_CLASS(Uint8Array),
-    IMPL_TYPED_ARRAY_CLASS(Int16Array),
-    IMPL_TYPED_ARRAY_CLASS(Uint16Array),
-    IMPL_TYPED_ARRAY_CLASS(Int32Array),
-    IMPL_TYPED_ARRAY_CLASS(Uint32Array),
-    IMPL_TYPED_ARRAY_CLASS(Float32Array),
-    IMPL_TYPED_ARRAY_CLASS(Float64Array),
-    IMPL_TYPED_ARRAY_CLASS(Uint8ClampedArray)
+    IMPL_TYPED_ARRAY_CLASS(Int8),
+    IMPL_TYPED_ARRAY_CLASS(Uint8),
+    IMPL_TYPED_ARRAY_CLASS(Int16),
+    IMPL_TYPED_ARRAY_CLASS(Uint16),
+    IMPL_TYPED_ARRAY_CLASS(Int32),
+    IMPL_TYPED_ARRAY_CLASS(Uint32),
+    IMPL_TYPED_ARRAY_CLASS(Float32),
+    IMPL_TYPED_ARRAY_CLASS(Float64),
+    IMPL_TYPED_ARRAY_CLASS(Uint8Clamped)
+};
+
+#define IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(_type) \
+{ \
+    DELEGATED_CLASSSPEC(TypedArrayObject::classes[Scalar::Type::_type].spec), \
+    nullptr, \
+    nullptr, \
+    nullptr, \
+    nullptr, \
+    nullptr, \
+    nullptr, \
+    JSProto_TypedArray | ClassSpec::IsDelegated \
+}
+
+static const ClassSpec TypedArrayObjectProtoClassSpecs[Scalar::MaxTypedArrayViewType] = {
+    IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int8),
+    IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint8),
+    IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int16),
+    IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint16),
+    IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int32),
+    IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint32),
+    IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Float32),
+    IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Float64),
+    IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint8Clamped)
 };
 
 // The various typed array prototypes are supposed to 1) be normal objects,
 // 2) stringify to "[object <name of constructor>]", and 3) (Gecko-specific)
 // be xrayable.  The first and second requirements mandate (in the absence of
 // @@toStringTag) a custom class.  The third requirement mandates that each
 // prototype's class have the relevant typed array's cached JSProtoKey in them.
 // Thus we need one class with cached prototype per kind of typed array, with a
 // delegated ClassSpec.
-#define IMPL_TYPED_ARRAY_PROTO_CLASS(typedArray, i) \
+#define IMPL_TYPED_ARRAY_PROTO_CLASS(_type) \
 { \
     /*
      * Actually ({}).toString.call(Uint8Array.prototype) should throw, because
      * Uint8Array.prototype lacks the the typed array internal slots.  (Same as
      * with %TypedArray%.prototype.)  It's not clear this is desirable (see
      * above), but it's what we've always done, so keep doing it till we
      * implement @@toStringTag or ES6 changes.
      */ \
-    #typedArray "Prototype", \
-    JSCLASS_HAS_CACHED_PROTO(JSProto_##typedArray), \
+    #_type "ArrayPrototype", \
+    JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array), \
     nullptr, /* addProperty */ \
     nullptr, /* delProperty */ \
     nullptr, /* getProperty */ \
     nullptr, /* setProperty */ \
     nullptr, /* enumerate */ \
     nullptr, /* resolve */ \
     nullptr, /* mayResolve */ \
     nullptr, /* finalize */ \
     nullptr, /* call */ \
     nullptr, /* hasInstance */ \
     nullptr, /* construct */ \
     nullptr, /* trace  */ \
-    { \
-        DELEGATED_CLASSSPEC(&TypedArrayObject::classes[i].spec), \
-        nullptr, \
-        nullptr, \
-        nullptr, \
-        nullptr, \
-        nullptr, \
-        nullptr, \
-        JSProto_TypedArray | ClassSpec::IsDelegated \
-    } \
+    &TypedArrayObjectProtoClassSpecs[Scalar::Type::_type] \
 }
 
 const Class TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
-    IMPL_TYPED_ARRAY_PROTO_CLASS(Int8Array, 0),
-    IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Array, 1),
-    IMPL_TYPED_ARRAY_PROTO_CLASS(Int16Array, 2),
-    IMPL_TYPED_ARRAY_PROTO_CLASS(Uint16Array, 3),
-    IMPL_TYPED_ARRAY_PROTO_CLASS(Int32Array, 4),
-    IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32Array, 5),
-    IMPL_TYPED_ARRAY_PROTO_CLASS(Float32Array, 6),
-    IMPL_TYPED_ARRAY_PROTO_CLASS(Float64Array, 7),
-    IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8ClampedArray, 8)
+    IMPL_TYPED_ARRAY_PROTO_CLASS(Int8),
+    IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8),
+    IMPL_TYPED_ARRAY_PROTO_CLASS(Int16),
+    IMPL_TYPED_ARRAY_PROTO_CLASS(Uint16),
+    IMPL_TYPED_ARRAY_PROTO_CLASS(Int32),
+    IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32),
+    IMPL_TYPED_ARRAY_PROTO_CLASS(Float32),
+    IMPL_TYPED_ARRAY_PROTO_CLASS(Float64),
+    IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Clamped)
 };
 
 /* static */ bool
 TypedArrayObject::isOriginalLengthGetter(Native native)
 {
     return native == TypedArray_lengthGetter;
 }
 
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -568,21 +568,21 @@ JSXrayTraits::resolveOwnProperty(JSConte
                             return false;
                         FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY,
                                                ObjectValue(*standardProto));
                         return true;
                     }
 
                     if (ShouldResolveStaticProperties(standardConstructor)) {
                         const js::Class* clasp = js::ProtoKeyToClass(standardConstructor);
-                        MOZ_ASSERT(clasp->spec.defined());
+                        MOZ_ASSERT(clasp->specDefined());
 
                         if (!TryResolvePropertyFromSpecs(cx, id, holder,
-                               clasp->spec.constructorFunctions(),
-                               clasp->spec.constructorProperties(), desc)) {
+                               clasp->specConstructorFunctions(),
+                               clasp->specConstructorProperties(), desc)) {
                             return false;
                         }
 
                         if (desc.object()) {
                             desc.object().set(wrapper);
                             return true;
                         }
                     }
@@ -651,23 +651,23 @@ JSXrayTraits::resolveOwnProperty(JSConte
     }
 
     // Handle the 'lastIndex' property for RegExp prototypes.
     if (key == JSProto_RegExp && id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_LASTINDEX))
         return getOwnPropertyFromWrapperIfSafe(cx, wrapper, id, desc);
 
     // Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
     const js::Class* clasp = js::GetObjectClass(target);
-    MOZ_ASSERT(clasp->spec.defined());
+    MOZ_ASSERT(clasp->specDefined());
 
     // Indexed array properties are handled above, so we can just work with the
     // class spec here.
     if (!TryResolvePropertyFromSpecs(cx, id, holder,
-                                     clasp->spec.prototypeFunctions(),
-                                     clasp->spec.prototypeProperties(),
+                                     clasp->specPrototypeFunctions(),
+                                     clasp->specPrototypeProperties(),
                                      desc)) {
         return false;
     }
 
     if (desc.object()) {
         desc.object().set(wrapper);
     }
 
@@ -859,21 +859,21 @@ JSXrayTraits::enumerateNames(JSContext* 
             // constructors.
             JSProtoKey standardConstructor = constructorFor(holder);
             if (standardConstructor != JSProto_Null) {
                 if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTOTYPE)))
                     return false;
 
                 if (ShouldResolveStaticProperties(standardConstructor)) {
                     const js::Class* clasp = js::ProtoKeyToClass(standardConstructor);
-                    MOZ_ASSERT(clasp->spec.defined());
+                    MOZ_ASSERT(clasp->specDefined());
 
                     if (!AppendNamesFromFunctionAndPropertySpecs(
-                           cx, clasp->spec.constructorFunctions(),
-                           clasp->spec.constructorProperties(), flags, props)) {
+                           cx, clasp->specConstructorFunctions(),
+                           clasp->specConstructorProperties(), flags, props)) {
                         return false;
                     }
                 }
             }
         } else if (IsErrorObjectKey(key)) {
             if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_FILENAME)) ||
                 !props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_LINENUMBER)) ||
                 !props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_COLUMNNUMBER)) ||
@@ -900,21 +900,21 @@ JSXrayTraits::enumerateNames(JSContext* 
         return false;
 
     // For RegExp protoypes, add the 'lastIndex' property.
     if (key == JSProto_RegExp && !props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_LASTINDEX)))
         return false;
 
     // Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
     const js::Class* clasp = js::GetObjectClass(target);
-    MOZ_ASSERT(clasp->spec.defined());
+    MOZ_ASSERT(clasp->specDefined());
 
     return AppendNamesFromFunctionAndPropertySpecs(
-        cx, clasp->spec.prototypeFunctions(),
-        clasp->spec.prototypeProperties(), flags, props);
+        cx, clasp->specPrototypeFunctions(),
+        clasp->specPrototypeProperties(), flags, props);
 }
 
 bool
 JSXrayTraits::construct(JSContext* cx, HandleObject wrapper,
                         const JS::CallArgs& args, const js::Wrapper& baseInstance)
 {
     JSXrayTraits& self = JSXrayTraits::singleton;
     JS::RootedObject holder(cx, self.ensureHolder(cx, wrapper));