Bug 1235408: Lazily resolve SIMD types; r=jandem draft
authorBenjamin Bouvier <benj@benj.me>
Mon, 11 Jan 2016 16:03:02 +0100
changeset 320492 552c34977142aa1bb89eced6d709ea3645460f04
parent 320442 18b1262883cdf2c95293d43fd8e468fe279d697f
child 512750 262d426b82d31ce3c9d42e5214073891c85931f3
push id9211
push userbenj@benj.me
push dateMon, 11 Jan 2016 15:07:56 +0000
reviewersjandem
bugs1235408
milestone46.0a1
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;
 
     /*