Bug 1235408: Lazily resolve SIMD types; r=jandem
authorBenjamin Bouvier <benj@benj.me>
Mon, 11 Jan 2016 16:03:02 +0100
changeset 279417 84e9f142912599540e4b32e9055cddd33cc8c969
parent 279416 8dcf131a146d0e759263b6ada2d19e8fed55f5fd
child 279418 7f283083d5037b5115743585cc649956dc2ae731
push id29882
push usercbook@mozilla.com
push dateTue, 12 Jan 2016 10:54:59 +0000
treeherdermozilla-central@e790bba372f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1235408
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1235408: Lazily resolve SIMD types; r=jandem
js/public/Class.h
js/src/asmjs/AsmJS.cpp
js/src/builtin/SIMD.cpp
js/src/builtin/SIMD.h
js/src/builtin/TypedObject.cpp
js/src/jit/BaselineIC.cpp
js/src/vm/CommonPropertyNames.h
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -332,18 +332,18 @@ typedef JSString*
 (* JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, unsigned indent);
 
 /**
  * Resolve a lazy property named by id in obj by defining it directly in obj.
  * Lazy properties are those reflected from some peer native property space
  * (e.g., the DOM attributes for a given node reflected as obj) on demand.
  *
  * JS looks for a property in an object, and if not found, tries to resolve
- * the given id. *resolvedp should be set to true iff the property was
- * was defined on |obj|.
+ * the given id. *resolvedp should be set to true iff the property was defined
+ * on |obj|.
  */
 typedef bool
 (* JSResolveOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
                 bool* resolvedp);
 
 /**
  * A class with a resolve hook can optionally have a mayResolve hook. This hook
  * must have no side effects and must return true for a given id if the resolve
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -3055,25 +3055,25 @@ CheckNewArrayView(ModuleValidator& m, Pr
         return false;
 
     return m.addArrayView(varName, type, field);
 }
 
 static bool
 IsSimdTypeName(ModuleValidator& m, PropertyName* name, AsmJSSimdType* type)
 {
-    if (name == m.cx()->names().int32x4) {
+    if (name == m.cx()->names().Int32x4) {
         *type = AsmJSSimdType_int32x4;
         return true;
     }
-    if (name == m.cx()->names().float32x4) {
+    if (name == m.cx()->names().Float32x4) {
         *type = AsmJSSimdType_float32x4;
         return true;
     }
-    if (name == m.cx()->names().bool32x4) {
+    if (name == m.cx()->names().Bool32x4) {
         *type = AsmJSSimdType_bool32x4;
         return true;
     }
     return false;
 }
 
 static bool
 IsSimdValidOperationType(AsmJSSimdType type, AsmJSSimdOperation op)
@@ -7491,19 +7491,19 @@ ValidateMathBuiltinFunction(JSContext* c
 
     return true;
 }
 
 static PropertyName*
 SimdTypeToName(JSContext* cx, AsmJSSimdType type)
 {
     switch (type) {
-      case AsmJSSimdType_int32x4:   return cx->names().int32x4;
-      case AsmJSSimdType_float32x4: return cx->names().float32x4;
-      case AsmJSSimdType_bool32x4:  return cx->names().bool32x4;
+      case AsmJSSimdType_int32x4:   return cx->names().Int32x4;
+      case AsmJSSimdType_float32x4: return cx->names().Float32x4;
+      case AsmJSSimdType_bool32x4:  return cx->names().Bool32x4;
     }
     MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected SIMD type");
 }
 
 static SimdTypeDescr::Type
 AsmJSSimdTypeToTypeDescrType(AsmJSSimdType type)
 {
     switch (type) {
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -56,25 +56,34 @@ CheckVectorObject(HandleValue v, SimdTyp
 
 template<class V>
 bool
 js::IsVectorObject(HandleValue v)
 {
     return CheckVectorObject(v, V::type);
 }
 
-template bool js::IsVectorObject<Int8x16>(HandleValue v);
-template bool js::IsVectorObject<Int16x8>(HandleValue v);
-template bool js::IsVectorObject<Int32x4>(HandleValue v);
-template bool js::IsVectorObject<Float32x4>(HandleValue v);
-template bool js::IsVectorObject<Float64x2>(HandleValue v);
-template bool js::IsVectorObject<Bool8x16>(HandleValue v);
-template bool js::IsVectorObject<Bool16x8>(HandleValue v);
-template bool js::IsVectorObject<Bool32x4>(HandleValue v);
-template bool js::IsVectorObject<Bool64x2>(HandleValue v);
+#define FOR_EACH_SIMD(macro) \
+  macro(Int8x16)             \
+  macro(Int16x8)             \
+  macro(Int32x4)             \
+  macro(Uint8x16)            \
+  macro(Uint16x8)            \
+  macro(Uint32x4)            \
+  macro(Float32x4)           \
+  macro(Float64x2)           \
+  macro(Bool8x16)            \
+  macro(Bool16x8)            \
+  macro(Bool32x4)            \
+  macro(Bool64x2)
+
+#define InstantiateIsVectorObject_(T) \
+    template bool js::IsVectorObject<T>(HandleValue v);
+FOR_EACH_SIMD(InstantiateIsVectorObject_)
+#undef InstantiateIsVectorObject_
 
 static inline bool
 ErrorBadArgs(JSContext* cx)
 {
     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
     return false;
 }
 
@@ -95,17 +104,18 @@ ErrorWrongTypeArg(JSContext* cx, size_t 
     JS_free(cx, typeNameStr);
     return false;
 }
 
 template<typename T>
 static SimdTypeDescr*
 GetTypeDescr(JSContext* cx)
 {
-    return cx->global()->getOrCreateSimdTypeDescr<T>(cx);
+    RootedGlobalObject global(cx, cx->global());
+    return GlobalObject::getOrCreateSimdTypeDescr<T>(cx, global);
 }
 
 template<typename V>
 bool
 js::ToSimdConstant(JSContext* cx, HandleValue v, jit::SimdConstant* out)
 {
     typedef typename V::Elem Elem;
     Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx));
@@ -142,77 +152,28 @@ const Class SimdTypeDescr::class_ = {
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     TypeDescr::finalize,
     call
 };
 
 namespace {
 
-// These classes just exist to group together various properties and so on.
-class Int8x16Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Int8x16;
-    static const JSFunctionSpec Methods[];
-};
-class Int16x8Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Int16x8;
-    static const JSFunctionSpec Methods[];
-};
-class Int32x4Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Int32x4;
-    static const JSFunctionSpec Methods[];
-};
-class Uint8x16Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Uint8x16;
-    static const JSFunctionSpec Methods[];
-};
-class Uint16x8Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Uint16x8;
-    static const JSFunctionSpec Methods[];
-};
-class Uint32x4Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Uint32x4;
-    static const JSFunctionSpec Methods[];
+// Define classes (Int8x16Defn, Int16x8Defn, etc.) to group together various
+// properties and so on.
+#define DEFINE_DEFN_(TypeName)                                       \
+class TypeName##Defn {                                               \
+  public:                                                            \
+    static const SimdTypeDescr::Type type = SimdTypeDescr::TypeName; \
+    static const JSFunctionSpec Methods[];                           \
 };
-class Float32x4Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Float32x4;
-    static const JSFunctionSpec Methods[];
-};
-class Float64x2Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Float64x2;
-    static const JSFunctionSpec Methods[];
-};
-class Bool8x16Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Bool8x16;
-    static const JSFunctionSpec Methods[];
-};
-class Bool16x8Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Bool16x8;
-    static const JSFunctionSpec Methods[];
-};
-class Bool32x4Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Bool32x4;
-    static const JSFunctionSpec Methods[];
-};
-class Bool64x2Defn {
-  public:
-    static const SimdTypeDescr::Type type = SimdTypeDescr::Bool64x2;
-    static const JSFunctionSpec Methods[];
-};
+
+FOR_EACH_SIMD(DEFINE_DEFN_)
+#undef DEFINE_DEFN_
+
 } // namespace
 
 // Shared type descriptor methods for all SIMD types.
 static const JSFunctionSpec TypeDescriptorMethods[] = {
     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
     JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
     JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
     JS_FS_END
@@ -315,78 +276,16 @@ const JSFunctionSpec Bool32x4Defn::Metho
 const JSFunctionSpec Bool64x2Defn::Methods[] = {
 #define SIMD_BOOL64X2_FUNCTION_ITEM(Name, Func, Operands) \
     JS_FN(#Name, js::simd_bool64x2_##Name, Operands, 0),
     BOOL64X2_FUNCTION_LIST(SIMD_BOOL64X2_FUNCTION_ITEM)
 #undef SIMD_BOOL64x2_FUNCTION_ITEM
     JS_FS_END
 };
 
-template<typename T>
-static JSObject*
-CreateAndBindSimdClass(JSContext* cx, Handle<GlobalObject*> global, HandleObject globalSimdObject,
-                       HandlePropertyName stringRepr)
-{
-    const SimdTypeDescr::Type type = T::type;
-
-    RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
-    if (!funcProto)
-        return nullptr;
-
-    // Create type constructor itself and initialize its reserved slots.
-    Rooted<SimdTypeDescr*> typeDescr(cx);
-    typeDescr = NewObjectWithGivenProto<SimdTypeDescr>(cx, funcProto, SingletonObject);
-    if (!typeDescr)
-        return nullptr;
-
-    typeDescr->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(type::Simd));
-    typeDescr->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
-    typeDescr->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(SimdTypeDescr::alignment(type)));
-    typeDescr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(SimdTypeDescr::size(type)));
-    typeDescr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false));
-    typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
-
-    if (!CreateUserSizeAndAlignmentProperties(cx, typeDescr))
-        return nullptr;
-
-    // Create prototype property, which inherits from Object.prototype.
-    RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
-    if (!objProto)
-        return nullptr;
-    Rooted<TypedProto*> proto(cx);
-    proto = NewObjectWithGivenProto<TypedProto>(cx, objProto, SingletonObject);
-    if (!proto)
-        return nullptr;
-    typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto));
-
-    // Link constructor to prototype and install properties.
-    if (!JS_DefineFunctions(cx, typeDescr, TypeDescriptorMethods))
-        return nullptr;
-
-    if (!LinkConstructorAndPrototype(cx, typeDescr, proto) ||
-        !JS_DefineFunctions(cx, proto, SimdTypedObjectMethods))
-    {
-        return nullptr;
-    }
-
-    // Bind type descriptor to the global SIMD object
-    RootedValue typeValue(cx, ObjectValue(*typeDescr));
-    if (!JS_DefineFunctions(cx, typeDescr, T::Methods) ||
-        !DefineProperty(cx, globalSimdObject, stringRepr, typeValue, nullptr, nullptr,
-                        JSPROP_READONLY | JSPROP_PERMANENT))
-    {
-        return nullptr;
-    }
-
-    uint32_t slot = uint32_t(typeDescr->type());
-    globalSimdObject->as<NativeObject>().setReservedSlot(slot, ObjectValue(*typeDescr));
-
-    return typeDescr;
-}
-
 template <typename T>
 static bool
 FillLanes(JSContext* cx, Handle<TypedObject*> result, const CallArgs& args)
 {
     typedef typename T::Elem Elem;
     Elem tmp;
     for (unsigned i = 0; i < T::lanes; i++) {
         if (!T::Cast(cx, args.get(i), &tmp))
@@ -405,43 +304,42 @@ SimdTypeDescr::call(JSContext* cx, unsig
     Rooted<SimdTypeDescr*> descr(cx, &args.callee().as<SimdTypeDescr>());
     MOZ_ASSERT(size_t(static_cast<TypeDescr*>(descr)->size()) <= InlineTypedObject::MaximumSize,
                "inline storage is needed for using InternalHandle belows");
 
     Rooted<TypedObject*> result(cx, TypedObject::createZeroed(cx, descr, 0));
     if (!result)
         return false;
 
+#define CASE_CALL_(Type) \
+      case SimdTypeDescr::Type:   return FillLanes< ::Type>(cx, result, args);
+
     switch (descr->type()) {
-      case SimdTypeDescr::Int8x16:   return FillLanes< ::Int8x16>(cx, result, args);
-      case SimdTypeDescr::Int16x8:   return FillLanes< ::Int16x8>(cx, result, args);
-      case SimdTypeDescr::Int32x4:   return FillLanes< ::Int32x4>(cx, result, args);
-      case SimdTypeDescr::Uint8x16:  return FillLanes< ::Uint8x16>(cx, result, args);
-      case SimdTypeDescr::Uint16x8:  return FillLanes< ::Uint16x8>(cx, result, args);
-      case SimdTypeDescr::Uint32x4:  return FillLanes< ::Uint32x4>(cx, result, args);
-      case SimdTypeDescr::Float32x4: return FillLanes< ::Float32x4>(cx, result, args);
-      case SimdTypeDescr::Float64x2: return FillLanes< ::Float64x2>(cx, result, args);
-      case SimdTypeDescr::Bool8x16:  return FillLanes< ::Bool8x16>(cx, result, args);
-      case SimdTypeDescr::Bool16x8:  return FillLanes< ::Bool16x8>(cx, result, args);
-      case SimdTypeDescr::Bool32x4:  return FillLanes< ::Bool32x4>(cx, result, args);
-      case SimdTypeDescr::Bool64x2:  return FillLanes< ::Bool64x2>(cx, result, args);
+      FOR_EACH_SIMD(CASE_CALL_)
     }
 
+#undef CASE_CALL_
     MOZ_CRASH("unexpected SIMD descriptor");
     return false;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // SIMD class
 
 static const uint32_t SIMD_SLOTS_COUNT = SimdTypeDescr::LAST_TYPE + 1;
 
 const Class SIMDObject::class_ = {
     "SIMD",
-    JSCLASS_HAS_RESERVED_SLOTS(SIMD_SLOTS_COUNT)
+    JSCLASS_HAS_RESERVED_SLOTS(SIMD_SLOTS_COUNT),
+    nullptr, /* addProperty */
+    nullptr, /* delProperty */
+    nullptr, /* getProperty */
+    nullptr, /* setProperty */
+    nullptr, /* enumerate */
+    resolve  /* resolve */
 };
 
 bool
 GlobalObject::initSimdObject(JSContext* cx, Handle<GlobalObject*> global)
 {
     // SIMD relies on the TypedObject module being initialized.
     // In particular, the self-hosted code for array() wants
     // to be able to call GetTypedObjectModule(). It is NOT necessary
@@ -465,87 +363,116 @@ GlobalObject::initSimdObject(JSContext* 
     {
         return false;
     }
 
     global->setConstructor(JSProto_SIMD, globalSimdValue);
     return true;
 }
 
+template<typename /* TypeDefn */ T>
+static bool
+CreateSimdType(JSContext* cx, Handle<GlobalObject*> global, HandlePropertyName stringRepr)
+{
+    RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
+    if (!funcProto)
+        return false;
+
+    // Create type constructor itself and initialize its reserved slots.
+    Rooted<SimdTypeDescr*> typeDescr(cx);
+    typeDescr = NewObjectWithGivenProto<SimdTypeDescr>(cx, funcProto, SingletonObject);
+    if (!typeDescr)
+        return false;
+
+    const SimdTypeDescr::Type type = T::type;
+    typeDescr->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(type::Simd));
+    typeDescr->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
+    typeDescr->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(SimdTypeDescr::alignment(type)));
+    typeDescr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(SimdTypeDescr::size(type)));
+    typeDescr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false));
+    typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
+
+    if (!CreateUserSizeAndAlignmentProperties(cx, typeDescr))
+        return false;
+
+    // Create prototype property, which inherits from Object.prototype.
+    RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
+    if (!objProto)
+        return false;
+    Rooted<TypedProto*> proto(cx);
+    proto = NewObjectWithGivenProto<TypedProto>(cx, objProto, SingletonObject);
+    if (!proto)
+        return false;
+    typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto));
+
+    // Link constructor to prototype and install properties.
+    if (!JS_DefineFunctions(cx, typeDescr, TypeDescriptorMethods))
+        return false;
+
+    if (!LinkConstructorAndPrototype(cx, typeDescr, proto) ||
+        !JS_DefineFunctions(cx, proto, SimdTypedObjectMethods))
+    {
+        return false;
+    }
+
+    // Bind type descriptor to the global SIMD object
+    RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx));
+    MOZ_ASSERT(globalSimdObject);
+
+    RootedValue typeValue(cx, ObjectValue(*typeDescr));
+    if (!JS_DefineFunctions(cx, typeDescr, T::Methods) ||
+        !DefineProperty(cx, globalSimdObject, stringRepr, typeValue, nullptr, nullptr,
+                        JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_RESOLVING))
+    {
+        return false;
+    }
+
+    uint32_t slot = uint32_t(typeDescr->type());
+    MOZ_ASSERT(globalSimdObject->as<NativeObject>().getReservedSlot(slot).isUndefined());
+    globalSimdObject->as<NativeObject>().setReservedSlot(slot, ObjectValue(*typeDescr));
+    return !!typeDescr;
+}
+
+bool
+GlobalObject::initSimdType(JSContext* cx, Handle<GlobalObject*> global, uint32_t simdTypeDescrType)
+{
+#define CREATE_(Type) \
+    case SimdTypeDescr::Type: return CreateSimdType<Type##Defn>(cx, global, cx->names().Type);
+
+    switch (SimdTypeDescr::Type(simdTypeDescrType)) {
+      FOR_EACH_SIMD(CREATE_)
+    }
+    MOZ_CRASH("unexpected simd type");
+
+#undef CREATE_
+}
+
+bool
+SIMDObject::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolved)
+{
+    *resolved = false;
+    if (!JSID_IS_ATOM(id))
+        return true;
+    JSAtom* str = JSID_TO_ATOM(id);
+    Rooted<GlobalObject*> global(cx, cx->global());
+#define TRY_RESOLVE_(Type)                                                    \
+    if (str == cx->names().Type) {                                            \
+        *resolved = CreateSimdType<Type##Defn>(cx, global, cx->names().Type); \
+        return *resolved;                                                     \
+    }
+    FOR_EACH_SIMD(TRY_RESOLVE_)
+#undef TRY_RESOLVE_
+    return true;
+}
+
 JSObject*
 js::InitSIMDClass(JSContext* cx, HandleObject obj)
 {
-    MOZ_ASSERT(obj->is<GlobalObject>());
     Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
-
-    RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx));
-    if (!globalSimdObject)
-        return nullptr;
-
-    RootedObject i8x16(cx);
-    i8x16 = CreateAndBindSimdClass<Int8x16Defn>(cx, global, globalSimdObject, cx->names().int8x16);
-    if (!i8x16)
-        return nullptr;
-
-    RootedObject i16x8(cx);
-    i16x8 = CreateAndBindSimdClass<Int16x8Defn>(cx, global, globalSimdObject, cx->names().int16x8);
-    if (!i16x8)
-        return nullptr;
-
-    RootedObject i32x4(cx);
-    i32x4 = CreateAndBindSimdClass<Int32x4Defn>(cx, global, globalSimdObject, cx->names().int32x4);
-    if (!i32x4)
-        return nullptr;
-
-    RootedObject u8x16(cx);
-    u8x16 = CreateAndBindSimdClass<Uint8x16Defn>(cx, global, globalSimdObject, cx->names().uint8x16);
-    if (!u8x16)
-        return nullptr;
-
-    RootedObject u16x8(cx);
-    u16x8 = CreateAndBindSimdClass<Uint16x8Defn>(cx, global, globalSimdObject, cx->names().uint16x8);
-    if (!u16x8)
-        return nullptr;
-
-    RootedObject u32x4(cx);
-    u32x4 = CreateAndBindSimdClass<Uint32x4Defn>(cx, global, globalSimdObject, cx->names().uint32x4);
-    if (!u32x4)
-        return nullptr;
-
-    RootedObject f32x4(cx);
-    f32x4 = CreateAndBindSimdClass<Float32x4Defn>(cx, global, globalSimdObject, cx->names().float32x4);
-    if (!f32x4)
-        return nullptr;
-
-    RootedObject f64x2(cx);
-    f64x2 = CreateAndBindSimdClass<Float64x2Defn>(cx, global, globalSimdObject, cx->names().float64x2);
-    if (!f64x2)
-        return nullptr;
-
-    RootedObject b8x16(cx);
-    b8x16 = CreateAndBindSimdClass<Bool8x16Defn>(cx, global, globalSimdObject, cx->names().bool8x16);
-    if (!b8x16)
-        return nullptr;
-
-    RootedObject b16x8(cx);
-    b16x8 = CreateAndBindSimdClass<Bool16x8Defn>(cx, global, globalSimdObject, cx->names().bool16x8);
-    if (!b16x8)
-        return nullptr;
-
-    RootedObject b32x4(cx);
-    b32x4 = CreateAndBindSimdClass<Bool32x4Defn>(cx, global, globalSimdObject, cx->names().bool32x4);
-    if (!b32x4)
-        return nullptr;
-
-    RootedObject b64x2(cx);
-    b64x2 = CreateAndBindSimdClass<Bool64x2Defn>(cx, global, globalSimdObject, cx->names().bool64x2);
-    if (!b64x2)
-        return nullptr;
-
-    return globalSimdObject;
+    return global->getOrCreateSimdGlobalObject(cx);
 }
 
 template<typename V>
 JSObject*
 js::CreateSimd(JSContext* cx, const typename V::Elem* data)
 {
     typedef typename V::Elem Elem;
     Rooted<TypeDescr*> typeDescr(cx, GetTypeDescr<V>(cx));
@@ -556,25 +483,24 @@ js::CreateSimd(JSContext* cx, const type
     if (!result)
         return nullptr;
 
     Elem* resultMem = reinterpret_cast<Elem*>(result->typedMem());
     memcpy(resultMem, data, sizeof(Elem) * V::lanes);
     return result;
 }
 
-template JSObject* js::CreateSimd<Int8x16>(JSContext* cx, const Int8x16::Elem* data);
-template JSObject* js::CreateSimd<Int16x8>(JSContext* cx, const Int16x8::Elem* data);
-template JSObject* js::CreateSimd<Int32x4>(JSContext* cx, const Int32x4::Elem* data);
-template JSObject* js::CreateSimd<Float32x4>(JSContext* cx, const Float32x4::Elem* data);
-template JSObject* js::CreateSimd<Float64x2>(JSContext* cx, const Float64x2::Elem* data);
-template JSObject* js::CreateSimd<Bool8x16>(JSContext* cx, const Bool8x16::Elem* data);
-template JSObject* js::CreateSimd<Bool16x8>(JSContext* cx, const Bool16x8::Elem* data);
-template JSObject* js::CreateSimd<Bool32x4>(JSContext* cx, const Bool32x4::Elem* data);
-template JSObject* js::CreateSimd<Bool64x2>(JSContext* cx, const Bool64x2::Elem* data);
+#define InstantiateCreateSimd_(Type) \
+    template JSObject* js::CreateSimd<Type>(JSContext* cx, const Type::Elem* data);
+
+FOR_EACH_SIMD(InstantiateCreateSimd_)
+
+#undef InstantiateCreateSimd_
+
+#undef FOR_EACH_SIMD
 
 namespace js {
 // Unary SIMD operators
 template<typename T>
 struct Identity {
     static T apply(T x) { return x; }
 };
 template<typename T>
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -779,16 +779,17 @@
 
 namespace js {
 
 class SIMDObject : public JSObject
 {
   public:
     static const Class class_;
     static bool toString(JSContext* cx, unsigned int argc, Value* vp);
+    static bool resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId, bool* resolved);
 };
 
 // These classes implement the concept containing the following constraints:
 // - requires typename Elem: this is the scalar lane type, stored in each lane
 // of the SIMD vector.
 // - requires static const unsigned lanes: this is the number of lanes (length)
 // of the SIMD vector.
 // - requires static const SimdTypeDescr::Type type: this is the SimdTypeDescr
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2590,127 +2590,127 @@ js::GetTypedObjectModule(JSContext* cx, 
 }
 
 bool
 js::GetFloat32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Float32x4>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Float32x4>(cx, global));
     return true;
 }
 
 bool
 js::GetFloat64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Float64x2>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Float64x2>(cx, global));
     return true;
 }
 
 bool
 js::GetInt8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Int8x16>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Int8x16>(cx, global));
     return true;
 }
 
 bool
 js::GetInt16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Int16x8>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Int16x8>(cx, global));
     return true;
 }
 
 bool
 js::GetInt32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Int32x4>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Int32x4>(cx, global));
     return true;
 }
 
 bool
 js::GetUint8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Uint8x16>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Uint8x16>(cx, global));
     return true;
 }
 
 bool
 js::GetUint16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Uint16x8>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Uint16x8>(cx, global));
     return true;
 }
 
 bool
 js::GetUint32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Uint32x4>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Uint32x4>(cx, global));
     return true;
 }
 
 bool
 js::GetBool8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Bool8x16>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool8x16>(cx, global));
     return true;
 }
 
 bool
 js::GetBool16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Bool16x8>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool16x8>(cx, global));
     return true;
 }
 
 bool
 js::GetBool32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Bool32x4>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool32x4>(cx, global));
     return true;
 }
 
 bool
 js::GetBool64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
-    args.rval().setObject(*global->getOrCreateSimdTypeDescr<Bool64x2>(cx));
+    args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr<Bool64x2>(cx, global));
     return true;
 }
 
 #define JS_STORE_SCALAR_CLASS_IMPL(_constant, T, _name)                         \
 bool                                                                            \
 js::StoreScalar##T::Func(JSContext*, unsigned argc, Value* vp)         \
 {                                                                               \
     CallArgs args = CallArgsFromVp(argc, vp);                                   \
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -5695,52 +5695,53 @@ GetTemplateObjectForNative(JSContext* cx
 
     if (native == obj_create && args.length() == 1 && args[0].isObjectOrNull()) {
         RootedObject proto(cx, args[0].toObjectOrNull());
         res.set(ObjectCreateImpl(cx, proto, TenuredObject));
         return !!res;
     }
 
     if (JitSupportsSimd()) {
+        RootedGlobalObject global(cx, cx->global());
 #define ADD_INT32X4_SIMD_OP_NAME_(OP) || native == js::simd_int32x4_##OP
 #define ADD_BOOL32X4_SIMD_OP_NAME_(OP) || native == js::simd_bool32x4_##OP
 #define ADD_FLOAT32X4_SIMD_OP_NAME_(OP) || native == js::simd_float32x4_##OP
         // Operations producing an int32x4.
         if (false
             ION_COMMONX4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
             FOREACH_BITWISE_SIMD_UNOP(ADD_INT32X4_SIMD_OP_NAME_)
             FOREACH_BITWISE_SIMD_BINOP(ADD_INT32X4_SIMD_OP_NAME_)
             FOREACH_SHIFT_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
             ADD_INT32X4_SIMD_OP_NAME_(fromFloat32x4)
             ADD_INT32X4_SIMD_OP_NAME_(fromFloat32x4Bits))
         {
-            Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Int32x4>(cx));
+            Rooted<SimdTypeDescr*> descr(cx, GlobalObject::getOrCreateSimdTypeDescr<Int32x4>(cx, global));
             res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
             return !!res;
         }
         // Operations producing a bool32x4.
         if (false
             FOREACH_BITWISE_SIMD_UNOP(ADD_BOOL32X4_SIMD_OP_NAME_)
             FOREACH_BITWISE_SIMD_BINOP(ADD_BOOL32X4_SIMD_OP_NAME_)
             FOREACH_COMP_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
             FOREACH_COMP_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
         {
-            Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Bool32x4>(cx));
+            Rooted<SimdTypeDescr*> descr(cx, GlobalObject::getOrCreateSimdTypeDescr<Bool32x4>(cx, global));
             res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
             return !!res;
         }
         // Operations producing a float32x4.
         if (false
             FOREACH_FLOAT_SIMD_UNOP(ADD_FLOAT32X4_SIMD_OP_NAME_)
             FOREACH_FLOAT_SIMD_BINOP(ADD_FLOAT32X4_SIMD_OP_NAME_)
             ADD_FLOAT32X4_SIMD_OP_NAME_(fromInt32x4)
             ADD_FLOAT32X4_SIMD_OP_NAME_(fromInt32x4Bits)
             ION_COMMONX4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
         {
-            Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Float32x4>(cx));
+            Rooted<SimdTypeDescr*> descr(cx, GlobalObject::getOrCreateSimdTypeDescr<Float32x4>(cx, global));
             res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
             return !!res;
         }
 #undef ADD_BOOL32X4_SIMD_OP_NAME_
 #undef ADD_INT32X4_SIMD_OP_NAME_
 #undef ADD_FLOAT32X4_SIMD_OP_NAME_
     }
 
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -19,20 +19,20 @@
     macro(apply, apply, "apply") \
     macro(arguments, arguments, "arguments") \
     macro(as, as, "as") \
     macro(ArrayIteratorNext, ArrayIteratorNext, "ArrayIteratorNext") \
     macro(ArrayType, ArrayType, "ArrayType") \
     macro(ArrayValues, ArrayValues, "ArrayValues") \
     macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
     macro(Async, Async, "Async") \
-    macro(bool8x16, bool8x16, "Bool8x16") \
-    macro(bool16x8, bool16x8, "Bool16x8") \
-    macro(bool32x4, bool32x4, "Bool32x4") \
-    macro(bool64x2, bool64x2, "Bool64x2") \
+    macro(Bool8x16, Bool8x16, "Bool8x16") \
+    macro(Bool16x8, Bool16x8, "Bool16x8") \
+    macro(Bool32x4, Bool32x4, "Bool32x4") \
+    macro(Bool64x2, Bool64x2, "Bool64x2") \
     macro(breakdown, breakdown, "breakdown") \
     macro(buffer, buffer, "buffer") \
     macro(builder, builder, "builder") \
     macro(by, by, "by") \
     macro(byteLength, byteLength, "byteLength") \
     macro(byteAlignment, byteAlignment, "byteAlignment") \
     macro(byteOffset, byteOffset, "byteOffset") \
     macro(bytes, bytes, "bytes") \
@@ -91,19 +91,19 @@
     macro(eval, eval, "eval") \
     macro(false, false_, "false") \
     macro(fieldOffsets, fieldOffsets, "fieldOffsets") \
     macro(fieldTypes, fieldTypes, "fieldTypes") \
     macro(fileName, fileName, "fileName") \
     macro(fix, fix, "fix") \
     macro(flags, flags, "flags") \
     macro(float32, float32, "float32") \
-    macro(float32x4, float32x4, "Float32x4") \
+    macro(Float32x4, Float32x4, "Float32x4") \
     macro(float64, float64, "float64") \
-    macro(float64x2, float64x2, "Float64x2") \
+    macro(Float64x2, Float64x2, "Float64x2") \
     macro(forceInterpreter, forceInterpreter, "forceInterpreter") \
     macro(forEach, forEach, "forEach") \
     macro(format, format, "format") \
     macro(formatToParts, formatToParts, "formatToParts") \
     macro(frame, frame, "frame") \
     macro(from, from, "from") \
     macro(gcCycleNumber, gcCycleNumber, "gcCycleNumber") \
     macro(GeneratorFunction, GeneratorFunction, "GeneratorFunction") \
@@ -122,19 +122,19 @@
     macro(ignorePunctuation, ignorePunctuation, "ignorePunctuation") \
     macro(index, index, "index") \
     macro(InitializeCollator, InitializeCollator, "InitializeCollator") \
     macro(InitializeDateTimeFormat, InitializeDateTimeFormat, "InitializeDateTimeFormat") \
     macro(InitializeNumberFormat, InitializeNumberFormat, "InitializeNumberFormat") \
     macro(inNursery, inNursery, "inNursery") \
     macro(innermost, innermost, "innermost") \
     macro(input, input, "input") \
-    macro(int8x16, int8x16, "Int8x16") \
-    macro(int16x8, int16x8, "Int16x8") \
-    macro(int32x4, int32x4, "Int32x4") \
+    macro(Int8x16, Int8x16, "Int8x16") \
+    macro(Int16x8, Int16x8, "Int16x8") \
+    macro(Int32x4, Int32x4, "Int32x4") \
     macro(isFinite, isFinite, "isFinite") \
     macro(isNaN, isNaN, "isNaN") \
     macro(isPrototypeOf, isPrototypeOf, "isPrototypeOf") \
     macro(iterate, iterate, "iterate") \
     macro(Infinity, Infinity, "Infinity") \
     macro(InterpretGeneratorResume, InterpretGeneratorResume, "InterpretGeneratorResume") \
     macro(int8, int8, "int8") \
     macro(int16, int16, "int16") \
@@ -247,19 +247,19 @@
     macro(unescape, unescape, "unescape") \
     macro(uneval, uneval, "uneval") \
     macro(unicode, unicode, "unicode") \
     macro(uninitialized, uninitialized, "uninitialized") \
     macro(uint8, uint8, "uint8") \
     macro(uint8Clamped, uint8Clamped, "uint8Clamped") \
     macro(uint16, uint16, "uint16") \
     macro(uint32, uint32, "uint32") \
-    macro(uint8x16, uint8x16, "Uint8x16") \
-    macro(uint16x8, uint16x8, "Uint16x8") \
-    macro(uint32x4, uint32x4, "Uint32x4") \
+    macro(Uint8x16, Uint8x16, "Uint8x16") \
+    macro(Uint16x8, Uint16x8, "Uint16x8") \
+    macro(Uint32x4, Uint32x4, "Uint32x4") \
     macro(unsized, unsized, "unsized") \
     macro(unwatch, unwatch, "unwatch") \
     macro(url, url, "url") \
     macro(usage, usage, "usage") \
     macro(useGrouping, useGrouping, "useGrouping") \
     macro(useAsm, useAsm, "use asm") \
     macro(useStrict, useStrict, "use strict") \
     macro(value, value, "value") \
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -19,17 +19,16 @@
 #include "builtin/Eval.h"
 #if EXPOSE_INTL_API
 # include "builtin/Intl.h"
 #endif
 #include "builtin/MapObject.h"
 #include "builtin/ModuleObject.h"
 #include "builtin/Object.h"
 #include "builtin/RegExp.h"
-#include "builtin/SIMD.h"
 #include "builtin/SymbolObject.h"
 #include "builtin/TypedObject.h"
 #include "builtin/WeakMapObject.h"
 #include "builtin/WeakSetObject.h"
 #include "vm/HelperThreads.h"
 #include "vm/PIC.h"
 #include "vm/RegExpStatics.h"
 #include "vm/RegExpStaticsObject.h"
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -438,21 +438,28 @@ class GlobalObject : public NativeObject
         return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_TypedObject, initTypedObjectModule);
     }
 
     JSObject* getOrCreateSimdGlobalObject(JSContext* cx) {
         return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_SIMD, initSimdObject);
     }
 
     template<class /* SimdTypeDescriptor (cf SIMD.h) */ T>
-    SimdTypeDescr* getOrCreateSimdTypeDescr(JSContext* cx) {
-        RootedObject globalSimdObject(cx, cx->global()->getOrCreateSimdGlobalObject(cx));
+    static SimdTypeDescr*
+    getOrCreateSimdTypeDescr(JSContext* cx, Handle<GlobalObject*> global) {
+        RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx));
         if (!globalSimdObject)
             return nullptr;
-        const Value& slot = globalSimdObject->as<NativeObject>().getReservedSlot(uint32_t(T::type));
+        uint32_t typeSlotIndex(T::type);
+        if (globalSimdObject->as<NativeObject>().getReservedSlot(typeSlotIndex).isUndefined() &&
+            !GlobalObject::initSimdType(cx, global, typeSlotIndex))
+        {
+            return nullptr;
+        }
+        const Value& slot = globalSimdObject->as<NativeObject>().getReservedSlot(typeSlotIndex);
         MOZ_ASSERT(slot.isObject());
         return &slot.toObject().as<SimdTypeDescr>();
     }
 
     TypedObjectModuleObject& getTypedObjectModule() const;
 
     JSObject* getLegacyIteratorPrototype() {
         return &getPrototype(JSProto_Iterator).toObject();
@@ -698,16 +705,17 @@ class GlobalObject : public NativeObject
     static bool initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
     static bool initExportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
 
     // Implemented in builtin/TypedObject.cpp
     static bool initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global);
 
     // Implemented in builtim/SIMD.cpp
     static bool initSimdObject(JSContext* cx, Handle<GlobalObject*> global);
+    static bool initSimdType(JSContext* cx, Handle<GlobalObject*> global, uint32_t simdTypeDescrType);
 
     static bool initStandardClasses(JSContext* cx, Handle<GlobalObject*> global);
     static bool initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> global,
                                         const JSFunctionSpec* builtins);
 
     typedef js::Vector<js::Debugger*, 0, js::SystemAllocPolicy> DebuggerVector;
 
     /*