Bug 1318815 - Remove ClassSpec delegation and point target ClassSpec directly from prototype class. r=jandem
authorTooru Fujisawa <arai_a@mac.com>
Tue, 22 Nov 2016 16:47:29 +0900
changeset 323776 177b7924440c450525d1127c9c2f1d3d642e4a2c
parent 323775 68240063e11a7274c5b593aaa3fda9b714a4b139
child 323777 f4cac94feb53415a51d9966dd60b1ccdecc43c36
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewersjandem
bugs1318815
milestone53.0a1
Bug 1318815 - Remove ClassSpec delegation and point target ClassSpec directly from prototype class. r=jandem
js/public/Class.h
js/src/builtin/MapObject.cpp
js/src/builtin/MapObject.h
js/src/builtin/Promise.cpp
js/src/jsdate.cpp
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
js/src/vm/SharedArrayObject.cpp
js/src/vm/SharedArrayObject.h
js/src/vm/TypedArrayObject.cpp
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -539,37 +539,31 @@ typedef JSObject* (*ClassObjectCreationO
 /** Callback for custom post-processing after class initialization via ClassSpec. */
 typedef bool (*FinishClassInitOp)(JSContext* cx, JS::HandleObject ctor,
                                   JS::HandleObject proto);
 
 const size_t JSCLASS_CACHED_PROTO_WIDTH = 6;
 
 struct ClassSpec
 {
-    // All properties except flags should be accessed through accessor.
-    ClassObjectCreationOp createConstructor_;
-    ClassObjectCreationOp createPrototype_;
-    const JSFunctionSpec* constructorFunctions_;
-    const JSPropertySpec* constructorProperties_;
-    const JSFunctionSpec* prototypeFunctions_;
-    const JSPropertySpec* prototypeProperties_;
-    FinishClassInitOp finishInit_;
+    ClassObjectCreationOp createConstructor;
+    ClassObjectCreationOp createPrototype;
+    const JSFunctionSpec* constructorFunctions;
+    const JSPropertySpec* constructorProperties;
+    const JSFunctionSpec* prototypeFunctions;
+    const JSPropertySpec* prototypeProperties;
+    FinishClassInitOp finishInit;
     uintptr_t flags;
 
     static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH;
 
     static const uintptr_t ProtoKeyMask = (1 << ProtoKeyWidth) - 1;
     static const uintptr_t DontDefineConstructor = 1 << ProtoKeyWidth;
-    static const uintptr_t IsDelegated = 1 << (ProtoKeyWidth + 1);
 
-    bool defined() const { return !!createConstructor_; }
-
-    bool delegated() const {
-        return (flags & IsDelegated);
-    }
+    bool defined() const { return !!createConstructor; }
 
     // The ProtoKey this class inherits from.
     JSProtoKey inheritanceProtoKey() const {
         MOZ_ASSERT(defined());
         static_assert(JSProto_Null == 0, "zeroed key must be null");
 
         // Default: Inherit from Object.
         if (!(flags & ProtoKeyMask))
@@ -577,57 +571,16 @@ struct ClassSpec
 
         return JSProtoKey(flags & ProtoKeyMask);
     }
 
     bool shouldDefineConstructor() const {
         MOZ_ASSERT(defined());
         return !(flags & DontDefineConstructor);
     }
-
-    const ClassSpec* delegatedClassSpec() const {
-        MOZ_ASSERT(delegated());
-        return reinterpret_cast<ClassSpec*>(createConstructor_);
-    }
-
-    ClassObjectCreationOp createConstructorHook() const {
-        if (delegated())
-            return delegatedClassSpec()->createConstructorHook();
-        return createConstructor_;
-    }
-    ClassObjectCreationOp createPrototypeHook() const {
-        if (delegated())
-            return delegatedClassSpec()->createPrototypeHook();
-        return createPrototype_;
-    }
-    const JSFunctionSpec* constructorFunctions() const {
-        if (delegated())
-            return delegatedClassSpec()->constructorFunctions();
-        return constructorFunctions_;
-    }
-    const JSPropertySpec* constructorProperties() const {
-        if (delegated())
-            return delegatedClassSpec()->constructorProperties();
-        return constructorProperties_;
-    }
-    const JSFunctionSpec* prototypeFunctions() const {
-        if (delegated())
-            return delegatedClassSpec()->prototypeFunctions();
-        return prototypeFunctions_;
-    }
-    const JSPropertySpec* prototypeProperties() const {
-        if (delegated())
-            return delegatedClassSpec()->prototypeProperties();
-        return prototypeProperties_;
-    }
-    FinishClassInitOp finishInitHook() const {
-        if (delegated())
-            return delegatedClassSpec()->finishInitHook();
-        return finishInit_;
-    }
 };
 
 struct ClassExtension
 {
     /**
      * If an object is used as a key in a weakmap, it may be desirable for the
      * garbage collector to keep that object around longer than it otherwise
      * would. A common case is when the key is a wrapper around an object in
@@ -649,20 +602,16 @@ struct ClassExtension
      *
      * Note that this hook can be called before JS_NewObject() returns if a GC
      * is triggered during construction of the object. This can happen for
      * global objects for example.
      */
     JSObjectMovedOp objectMovedOp;
 };
 
-inline ClassObjectCreationOp DELEGATED_CLASSSPEC(const ClassSpec* spec) {
-    return reinterpret_cast<ClassObjectCreationOp>(const_cast<ClassSpec*>(spec));
-}
-
 #define JS_NULL_CLASS_SPEC  nullptr
 #define JS_NULL_CLASS_EXT   nullptr
 
 struct ObjectOps
 {
     LookupPropertyOp lookupProperty;
     DefinePropertyOp defineProperty;
     HasPropertyOp    hasProperty;
@@ -867,29 +816,29 @@ struct Class
     static size_t offsetOfFlags() { return offsetof(Class, flags); }
 
     bool specDefined()         const { return spec ? spec->defined()   : false; }
     JSProtoKey specInheritanceProtoKey()
                                const { return spec ? spec->inheritanceProtoKey() : JSProto_Null; }
     bool specShouldDefineConstructor()
                                const { return spec ? spec->shouldDefineConstructor() : true; }
     ClassObjectCreationOp specCreateConstructorHook()
-                               const { return spec ? spec->createConstructorHook()   : nullptr; }
+                               const { return spec ? spec->createConstructor        : nullptr; }
     ClassObjectCreationOp specCreatePrototypeHook()
-                               const { return spec ? spec->createPrototypeHook()     : nullptr; }
+                               const { return spec ? spec->createPrototype          : nullptr; }
     const JSFunctionSpec* specConstructorFunctions()
-                               const { return spec ? spec->constructorFunctions()    : nullptr; }
+                               const { return spec ? spec->constructorFunctions     : nullptr; }
     const JSPropertySpec* specConstructorProperties()
-                               const { return spec ? spec->constructorProperties()   : nullptr; }
+                               const { return spec ? spec->constructorProperties    : nullptr; }
     const JSFunctionSpec* specPrototypeFunctions()
-                               const { return spec ? spec->prototypeFunctions()      : nullptr; }
+                               const { return spec ? spec->prototypeFunctions       : nullptr; }
     const JSPropertySpec* specPrototypeProperties()
-                               const { return spec ? spec->prototypeProperties()     : nullptr; }
+                               const { return spec ? spec->prototypeProperties      : nullptr; }
     FinishClassInitOp specFinishInitHook()
-                               const { return spec ? spec->finishInitHook()          : nullptr; }
+                               const { return spec ? spec->finishInit               : nullptr; }
 
     JSWeakmapKeyDelegateOp extWeakmapKeyDelegateOp()
                                const { return ext ? ext->weakmapKeyDelegateOp        : nullptr; }
     JSObjectMovedOp extObjectMovedOp()
                                const { return ext ? ext->objectMovedOp               : nullptr; }
 
     LookupPropertyOp getOpsLookupProperty() const { return oOps ? oOps->lookupProperty : nullptr; }
     DefinePropertyOp getOpsDefineProperty() const { return oOps ? oOps->defineProperty : nullptr; }
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -252,38 +252,20 @@ MapIteratorObject::createResultPair(JSCo
     AddTypePropertyId(cx, resultPairObj, JSID_VOID, TypeSet::UnknownType());
 
     return resultPairObj;
 }
 
 
 /*** Map *****************************************************************************************/
 
-static const ClassSpec MapObjectProtoClassSpec = {
-    DELEGATED_CLASSSPEC(MapObject::class_.spec),
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    ClassSpec::IsDelegated
-};
-
-static const Class MapObjectProtoClass = {
-    js_Object_str,
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Map),
-    JS_NULL_CLASS_OPS,
-    &MapObjectProtoClassSpec
-};
-
 static JSObject*
-CreatMapPrototype(JSContext* cx, JSProtoKey key)
+CreateMapPrototype(JSContext* cx, JSProtoKey key)
 {
-    return cx->global()->createBlankPrototype(cx, &MapObjectProtoClass);
+    return cx->global()->createBlankPrototype(cx, &MapObject::protoClass_);
 }
 
 const ClassOps MapObject::classOps_ = {
     nullptr, // addProperty
     nullptr, // delProperty
     nullptr, // getProperty
     nullptr, // setProperty
     nullptr, // enumerate
@@ -293,33 +275,40 @@ const ClassOps MapObject::classOps_ = {
     nullptr, // call
     nullptr, // hasInstance
     nullptr, // construct
     mark
 };
 
 const ClassSpec MapObject::classSpec_ = {
     GenericCreateConstructor<MapObject::construct, 0, gc::AllocKind::FUNCTION>,
-    CreatMapPrototype,
+    CreateMapPrototype,
     nullptr,
     MapObject::staticProperties,
     MapObject::methods,
     MapObject::properties,
 };
 
 const Class MapObject::class_ = {
     "Map",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(MapObject::SlotCount) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Map) |
     JSCLASS_FOREGROUND_FINALIZE,
     &MapObject::classOps_,
     &MapObject::classSpec_
 };
 
+const Class MapObject::protoClass_ = {
+    js_Object_str,
+    JSCLASS_HAS_CACHED_PROTO(JSProto_Map),
+    JS_NULL_CLASS_OPS,
+    &MapObject::classSpec_
+};
+
 const JSPropertySpec MapObject::properties[] = {
     JS_PSG("size", size, 0),
     JS_STRING_SYM_PS(toStringTag, "Map", JSPROP_READONLY),
     JS_PS_END
 };
 
 const JSFunctionSpec MapObject::methods[] = {
     JS_FN("get", get, 1, 0),
@@ -981,38 +970,20 @@ SetIteratorObject::createResult(JSContex
     AddTypePropertyId(cx, resultObj, JSID_VOID, TypeSet::UnknownType());
 
     return resultObj;
 }
 
 
 /*** Set *****************************************************************************************/
 
-static const ClassSpec SetObjectProtoClassSpec = {
-    DELEGATED_CLASSSPEC(SetObject::class_.spec),
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    ClassSpec::IsDelegated
-};
-
-static const Class SetObjectProtoClass = {
-    js_Object_str,
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Set),
-    JS_NULL_CLASS_OPS,
-    &SetObjectProtoClassSpec
-};
-
 static JSObject*
 CreateSetPrototype(JSContext* cx, JSProtoKey key)
 {
-    return cx->global()->createBlankPrototype(cx, &SetObjectProtoClass);
+    return cx->global()->createBlankPrototype(cx, &SetObject::protoClass_);
 }
 
 const ClassOps SetObject::classOps_ = {
     nullptr, // addProperty
     nullptr, // delProperty
     nullptr, // getProperty
     nullptr, // setProperty
     nullptr, // enumerate
@@ -1039,16 +1010,23 @@ const Class SetObject::class_ = {
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(SetObject::SlotCount) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Set) |
     JSCLASS_FOREGROUND_FINALIZE,
     &SetObject::classOps_,
     &SetObject::classSpec_,
 };
 
+const Class SetObject::protoClass_ = {
+    js_Object_str,
+    JSCLASS_HAS_CACHED_PROTO(JSProto_Set),
+    JS_NULL_CLASS_OPS,
+    &SetObject::classSpec_
+};
+
 const JSPropertySpec SetObject::properties[] = {
     JS_PSG("size", size, 0),
     JS_STRING_SYM_PS(toStringTag, "Set", JSPROP_READONLY),
     JS_PS_END
 };
 
 const JSFunctionSpec SetObject::methods[] = {
     JS_FN("has", has, 1, 0),
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -89,16 +89,17 @@ class MapObject : public NativeObject {
                   "IteratorKind Keys must match self-hosting define for item kind key.");
     static_assert(Values == ITEM_KIND_VALUE,
                   "IteratorKind Values must match self-hosting define for item kind value.");
     static_assert(Entries == ITEM_KIND_KEY_AND_VALUE,
                   "IteratorKind Entries must match self-hosting define for item kind "
                   "key-and-value.");
 
     static const Class class_;
+    static const Class protoClass_;
 
     enum { NurseryKeysSlot, SlotCount };
 
     static MOZ_MUST_USE bool getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj,
                                             JS::MutableHandle<GCVector<JS::Value>> entries);
     static MOZ_MUST_USE bool entries(JSContext* cx, unsigned argc, Value* vp);
     static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp);
     static MapObject* create(JSContext* cx, HandleObject proto = nullptr);
@@ -195,16 +196,17 @@ class SetObject : public NativeObject {
                   "IteratorKind Keys must match self-hosting define for item kind key.");
     static_assert(Values == ITEM_KIND_VALUE,
                   "IteratorKind Values must match self-hosting define for item kind value.");
     static_assert(Entries == ITEM_KIND_KEY_AND_VALUE,
                   "IteratorKind Entries must match self-hosting define for item kind "
                   "key-and-value.");
 
     static const Class class_;
+    static const Class protoClass_;
 
     enum { NurseryKeysSlot, SlotCount };
 
     static MOZ_MUST_USE bool keys(JSContext *cx, HandleObject obj,
                                   JS::MutableHandle<GCVector<JS::Value>> keys);
     static MOZ_MUST_USE bool values(JSContext *cx, unsigned argc, Value *vp);
     static MOZ_MUST_USE bool add(JSContext *cx, HandleObject obj, HandleValue key);
     static MOZ_MUST_USE bool has(JSContext *cx, unsigned argc, Value *vp);
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -2761,25 +2761,14 @@ static const ClassSpec PromiseObjectClas
 const Class PromiseObject::class_ = {
     "Promise",
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Promise) |
     JSCLASS_HAS_XRAYED_CONSTRUCTOR,
     JS_NULL_CLASS_OPS,
     &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),
     JS_NULL_CLASS_OPS,
-    &PromiseObjectProtoClassSpec
+    &PromiseObjectClassSpec
 };
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -3256,32 +3256,21 @@ static const ClassSpec DateObjectClassSp
 const Class DateObject::class_ = {
     js_Date_str,
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
     JS_NULL_CLASS_OPS,
     &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),
     JS_NULL_CLASS_OPS,
-    &DateObjectProtoClassSpec
+    &DateObjectClassSpec
 };
 
 JSObject*
 js::NewDateObjectMsec(JSContext* cx, ClippedTime t, HandleObject proto /* = nullptr */)
 {
     JSObject* obj = NewObjectWithClassProto(cx, &DateObject::class_, proto);
     if (!obj)
         return nullptr;
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -114,38 +114,20 @@ arraybuffer_static_slice(JSContext* cx, 
  * access.  It can be created explicitly and passed to a TypedArrayObject, or
  * can be created implicitly by constructing a TypedArrayObject with a size.
  */
 
 /*
  * ArrayBufferObject (base)
  */
 
-static const ClassSpec ArrayBufferObjectProtoClassSpec = {
-    DELEGATED_CLASSSPEC(ArrayBufferObject::class_.spec),
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    ClassSpec::IsDelegated
-};
-
-static const Class ArrayBufferObjectProtoClass = {
-    "ArrayBufferPrototype",
-    JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
-    JS_NULL_CLASS_OPS,
-    &ArrayBufferObjectProtoClassSpec
-};
-
 static JSObject*
 CreateArrayBufferPrototype(JSContext* cx, JSProtoKey key)
 {
-    return cx->global()->createBlankPrototype(cx, &ArrayBufferObjectProtoClass);
+    return cx->global()->createBlankPrototype(cx, &ArrayBufferObject::protoClass_);
 }
 
 static const ClassOps ArrayBufferObjectClassOps = {
     nullptr,        /* addProperty */
     nullptr,        /* delProperty */
     nullptr,        /* getProperty */
     nullptr,        /* setProperty */
     nullptr,        /* enumerate */
@@ -201,16 +183,23 @@ const Class ArrayBufferObject::class_ = 
     JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer) |
     JSCLASS_BACKGROUND_FINALIZE,
     &ArrayBufferObjectClassOps,
     &ArrayBufferObjectClassSpec,
     &ArrayBufferObjectClassExtension
 };
 
+const Class ArrayBufferObject::protoClass_ = {
+    "ArrayBufferPrototype",
+    JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
+    JS_NULL_CLASS_OPS,
+    &ArrayBufferObjectClassSpec
+};
+
 bool
 js::IsArrayBuffer(HandleValue v)
 {
     return v.isObject() && v.toObject().is<ArrayBufferObject>();
 }
 
 bool
 js::IsArrayBuffer(HandleObject obj)
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -224,16 +224,17 @@ class ArrayBufferObject : public ArrayBu
         uint8_t* data() const { return data_; }
         BufferKind kind() const { return kind_; }
 
         explicit operator bool() const { return data_ != nullptr; }
         WasmArrayRawBuffer* wasmBuffer() const;
     };
 
     static const Class class_;
+    static const Class protoClass_;
 
     static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
 
     static bool fun_slice(JSContext* cx, unsigned argc, Value* vp);
 
     static bool fun_isView(JSContext* cx, unsigned argc, Value* vp);
 
     static bool fun_species(JSContext* cx, unsigned argc, Value* vp);
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -336,38 +336,20 @@ SharedArrayBufferObject::copyData(Handle
     MOZ_ASSERT(fromBuffer->byteLength() >= fromIndex);
     MOZ_ASSERT(fromBuffer->byteLength() >= fromIndex + count);
 
     jit::AtomicOperations::memcpySafeWhenRacy(toBuffer->dataPointerShared(),
                                               fromBuffer->dataPointerShared() + fromIndex,
                                               count);
 }
 
-static const ClassSpec SharedArrayBufferObjectProtoClassSpec = {
-    DELEGATED_CLASSSPEC(SharedArrayBufferObject::class_.spec),
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr,
-    ClassSpec::IsDelegated
-};
-
-static const Class SharedArrayBufferObjectProtoClass = {
-    "SharedArrayBufferPrototype",
-    JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
-    JS_NULL_CLASS_OPS,
-    &SharedArrayBufferObjectProtoClassSpec
-};
-
 static JSObject*
 CreateSharedArrayBufferPrototype(JSContext* cx, JSProtoKey key)
 {
-    return cx->global()->createBlankPrototype(cx, &SharedArrayBufferObjectProtoClass);
+    return cx->global()->createBlankPrototype(cx, &SharedArrayBufferObject::protoClass_);
 }
 
 static const ClassOps SharedArrayBufferObjectClassOps = {
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* getProperty */
     nullptr, /* setProperty */
     nullptr, /* enumerate */
@@ -395,36 +377,43 @@ static const JSFunctionSpec prototype_fu
 };
 
 static const JSPropertySpec prototype_properties[] = {
     JS_PSG("byteLength", SharedArrayBufferObject::byteLengthGetter, 0),
     JS_STRING_SYM_PS(toStringTag, "SharedArrayBuffer", JSPROP_READONLY),
     JS_PS_END
 };
 
-static const ClassSpec ArrayBufferObjectClassSpec = {
+static const ClassSpec SharedArrayBufferObjectClassSpec = {
     GenericCreateConstructor<SharedArrayBufferObject::class_constructor, 1, gc::AllocKind::FUNCTION>,
     CreateSharedArrayBufferPrototype,
     static_functions,
     static_properties,
     prototype_functions,
     prototype_properties
 };
 
 const Class SharedArrayBufferObject::class_ = {
     "SharedArrayBuffer",
     JSCLASS_DELAY_METADATA_BUILDER |
     JSCLASS_HAS_RESERVED_SLOTS(SharedArrayBufferObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer) |
     JSCLASS_BACKGROUND_FINALIZE,
     &SharedArrayBufferObjectClassOps,
-    &ArrayBufferObjectClassSpec,
+    &SharedArrayBufferObjectClassSpec,
     JS_NULL_CLASS_EXT
 };
 
+const Class SharedArrayBufferObject::protoClass_ = {
+    "SharedArrayBufferPrototype",
+    JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
+    JS_NULL_CLASS_OPS,
+    &SharedArrayBufferObjectClassSpec
+};
+
 bool
 js::IsSharedArrayBuffer(HandleValue v)
 {
     return v.isObject() && v.toObject().is<SharedArrayBufferObject>();
 }
 
 bool
 js::IsSharedArrayBuffer(HandleObject o)
--- a/js/src/vm/SharedArrayObject.h
+++ b/js/src/vm/SharedArrayObject.h
@@ -122,16 +122,17 @@ class SharedArrayBufferObject : public A
   public:
     // RAWBUF_SLOT holds a pointer (as "private" data) to the
     // SharedArrayRawBuffer object, which is manually managed storage.
     static const uint8_t RAWBUF_SLOT = 0;
 
     static const uint8_t RESERVED_SLOTS = 1;
 
     static const Class class_;
+    static const Class protoClass_;
 
     static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
 
     static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
 
     // Create a SharedArrayBufferObject with a new SharedArrayRawBuffer.
     static SharedArrayBufferObject* New(JSContext* cx,
                                         uint32_t length,
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -2681,40 +2681,16 @@ const Class TypedArrayObject::classes[Sc
     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(_type) \
@@ -2724,17 +2700,17 @@ static const ClassSpec TypedArrayObjectP
      * 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.
      */ \
     #_type "ArrayPrototype", \
     JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array), \
     JS_NULL_CLASS_OPS, \
-    &TypedArrayObjectProtoClassSpecs[Scalar::Type::_type] \
+    &TypedArrayObjectClassSpecs[Scalar::Type::_type] \
 }
 
 const Class TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
     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),