Bug 1031203 - Implemented float64x2. r=bbouvier
authorProgramFOX <programfox@hotmail.be>
Fri, 16 Jan 2015 17:17:37 +0100
changeset 224469 7ce5ad5a753977da71636825fa09ca8c2451c97c
parent 224468 856679a135f2017c8fd1af9694491f91ecb190dc
child 224470 a1118794ba7cb9b81c8140f05df477e357eafcbc
push id54242
push usercbook@mozilla.com
push dateMon, 19 Jan 2015 09:03:35 +0000
treeherdermozilla-inbound@33a81cbadb6e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1031203
milestone38.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 1031203 - Implemented float64x2. r=bbouvier
js/public/Class.h
js/src/builtin/SIMD.cpp
js/src/builtin/SIMD.h
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/builtin/TypedObject.js
js/src/builtin/TypedObjectConstants.h
js/src/vm/CommonPropertyNames.h
js/src/vm/GlobalObject.h
js/src/vm/SelfHosting.cpp
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -457,17 +457,17 @@ struct JSClass {
 // Implementing this efficiently requires that global objects have classes
 // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
 // previously allowed, but is now an ES5 violation and thus unsupported.
 //
 // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
 // the beginning of every global object's slots for use by the
 // application.
 #define JSCLASS_GLOBAL_APPLICATION_SLOTS 4
-#define JSCLASS_GLOBAL_SLOT_COUNT      (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 30)
+#define JSCLASS_GLOBAL_SLOT_COUNT      (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 31)
 #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n)                                    \
     (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
 #define JSCLASS_GLOBAL_FLAGS                                                  \
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
 #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp)                              \
   (((clasp)->flags & JSCLASS_IS_GLOBAL)                                       \
    && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
 
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -26,16 +26,17 @@ using namespace js;
 
 using mozilla::ArrayLength;
 using mozilla::IsFinite;
 using mozilla::IsNaN;
 using mozilla::FloorLog2;
 
 namespace js {
 extern const JSFunctionSpec Float32x4Methods[];
+extern const JSFunctionSpec Float64x2Methods[];
 extern const JSFunctionSpec Int32x4Methods[];
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // SIMD
 
 static const char *laneNames[] = {"lane 0", "lane 1", "lane 2", "lane3"};
 
@@ -60,16 +61,17 @@ template<class V>
 bool
 js::IsVectorObject(HandleValue v)
 {
     return CheckVectorObject(v, V::type);
 }
 
 template bool js::IsVectorObject<Int32x4>(HandleValue v);
 template bool js::IsVectorObject<Float32x4>(HandleValue v);
+template bool js::IsVectorObject<Float64x2>(HandleValue v);
 
 template<typename V>
 bool
 js::ToSimdConstant(JSContext *cx, HandleValue v, jit::SimdConstant *out)
 {
     typedef typename V::Elem Elem;
     if (!IsVectorObject<V>(v)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_SIMD_NOT_A_VECTOR);
@@ -119,16 +121,19 @@ static bool type##Lane##lane(JSContext *
     LANE_ACCESSOR(type, 0); \
     LANE_ACCESSOR(type, 1); \
     LANE_ACCESSOR(type, 2); \
     LANE_ACCESSOR(type, 3);
 
     FOUR_LANES_ACCESSOR(Int32x4);
     FOUR_LANES_ACCESSOR(Float32x4);
 #undef FOUR_LANES_ACCESSOR
+
+    LANE_ACCESSOR(Float64x2, 0);
+    LANE_ACCESSOR(Float64x2, 1);
 #undef LANE_ACCESSOR
 
 template<typename SimdType>
 static bool SignMask(JSContext *cx, unsigned argc, Value *vp)
 {
     typedef typename SimdType::Elem Elem;
 
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -163,16 +168,17 @@ static bool SignMask(JSContext *cx, unsi
     return true;
 }
 
 #define SIGN_MASK(type) \
 static bool type##SignMask(JSContext *cx, unsigned argc, Value *vp) { \
     return SignMask<type>(cx, argc, vp); \
 }
     SIGN_MASK(Float32x4);
+    SIGN_MASK(Float64x2);
     SIGN_MASK(Int32x4);
 #undef SIGN_MASK
 
 const Class SimdTypeDescr::class_ = {
     "SIMD",
     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE,
     nullptr, /* addProperty */
     nullptr, /* delProperty */
@@ -196,16 +202,23 @@ class Int32x4Defn {
 };
 class Float32x4Defn {
   public:
     static const SimdTypeDescr::Type type = SimdTypeDescr::TYPE_FLOAT32;
     static const JSFunctionSpec TypeDescriptorMethods[];
     static const JSPropertySpec TypedObjectProperties[];
     static const JSFunctionSpec TypedObjectMethods[];
 };
+class Float64x2Defn {
+  public:
+    static const SimdTypeDescr::Type type = SimdTypeDescr::TYPE_FLOAT64;
+    static const JSFunctionSpec TypeDescriptorMethods[];
+    static const JSPropertySpec TypedObjectProperties[];
+    static const JSFunctionSpec TypedObjectMethods[];
+};
 } // namespace js
 
 const JSFunctionSpec js::Float32x4Defn::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
 };
@@ -219,16 +232,35 @@ const JSPropertySpec js::Float32x4Defn::
     JS_PS_END
 };
 
 const JSFunctionSpec js::Float32x4Defn::TypedObjectMethods[] = {
     JS_SELF_HOSTED_FN("toSource", "SimdToSource", 0, 0),
     JS_FS_END
 };
 
+const JSFunctionSpec js::Float64x2Defn::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
+};
+
+const JSPropertySpec js::Float64x2Defn::TypedObjectProperties[] = {
+    JS_PSG("x", Float64x2Lane0, JSPROP_PERMANENT),
+    JS_PSG("y", Float64x2Lane1, JSPROP_PERMANENT),
+    JS_PSG("signMask", Float64x2SignMask, JSPROP_PERMANENT),
+    JS_PS_END
+};
+
+const JSFunctionSpec js::Float64x2Defn::TypedObjectMethods[] = {
+    JS_SELF_HOSTED_FN("toSource", "SimdToSource", 0, 0),
+    JS_FS_END
+};
+
 const JSFunctionSpec js::Int32x4Defn::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,
 };
 
 const JSPropertySpec js::Int32x4Defn::TypedObjectProperties[] = {
@@ -263,16 +295,17 @@ CreateSimdClass(JSContext *cx, Handle<Gl
         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));
+    typeDescr->initReservedSlot(JS_DESCR_SLOT_LANES, Int32Value(SimdTypeDescr::lanes(type)));
 
     if (!CreateUserSizeAndAlignmentProperties(cx, typeDescr))
         return nullptr;
 
     // Create prototype property, which inherits from Object.prototype.
 
     RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
     if (!objProto)
@@ -293,16 +326,28 @@ CreateSimdClass(JSContext *cx, Handle<Gl
                                       T::TypedObjectMethods))
     {
         return nullptr;
     }
 
     return typeDescr;
 }
 
+const char*
+SimdTypeToMinimumLanesNumber(SimdTypeDescr &descr) {
+    switch (descr.type()) {
+      case SimdTypeDescr::TYPE_INT32:
+      case SimdTypeDescr::TYPE_FLOAT32:
+        return "3";
+      case SimdTypeDescr::TYPE_FLOAT64:
+        return "1";
+    }
+    MOZ_CRASH("Unexpected SIMD type description.");
+}
+
 bool
 SimdTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     Rooted<SimdTypeDescr*> descr(cx, &args.callee().as<SimdTypeDescr>());
     if (args.length() == 1) {
         // SIMD type used as a coercion
@@ -331,16 +376,23 @@ SimdTypeDescr::call(JSContext *cx, unsig
       case SimdTypeDescr::TYPE_FLOAT32: {
         float *mem = reinterpret_cast<float*>(result->typedMem());
         for (unsigned i = 0; i < 4; i++) {
             if (!RoundFloat32(cx, args.get(i), &mem[i]))
                 return false;
         }
         break;
       }
+      case SimdTypeDescr::TYPE_FLOAT64: {
+        double *mem = reinterpret_cast<double*>(result->typedMem());
+        for (unsigned i = 0; i < 2; i++) {
+            if (!ToNumber(cx, args[i], &mem[i]))
+                return false;
+        }
+      }
     }
     args.rval().setObject(*result);
     return true;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // SIMD class
 
@@ -381,16 +433,33 @@ SIMDObject::initClass(JSContext *cx, Han
     if (!JS_DefineFunctions(cx, float32x4Object, Float32x4Methods) ||
         !DefineProperty(cx, SIMD, cx->names().float32x4,
                         float32x4Value, nullptr, nullptr,
                         JSPROP_READONLY | JSPROP_PERMANENT))
     {
         return nullptr;
     }
 
+    // float64x2
+    RootedObject float64x2Object(cx);
+    float64x2Object = CreateSimdClass<Float64x2Defn>(cx, global,
+                                                     cx->names().float64x2);
+    if (!float64x2Object)
+        return nullptr;
+
+    // Define float64x2 functions and install as a property of the SIMD object.
+    RootedValue float64x2Value(cx, ObjectValue(*float64x2Object));
+    if (!JS_DefineFunctions(cx, float64x2Object, Float64x2Methods) ||
+        !DefineProperty(cx, SIMD, cx->names().float64x2,
+                        float64x2Value, nullptr, nullptr,
+                        JSPROP_READONLY | JSPROP_PERMANENT))
+    {
+        return nullptr;
+    }
+
     // int32x4
     RootedObject int32x4Object(cx);
     int32x4Object = CreateSimdClass<Int32x4Defn>(cx, global,
                                                  cx->names().int32x4);
     if (!int32x4Object)
         return nullptr;
 
     // Define int32x4 functions and install as a property of the SIMD object.
@@ -406,16 +475,17 @@ SIMDObject::initClass(JSContext *cx, Han
     RootedValue SIMDValue(cx, ObjectValue(*SIMD));
 
     // Everything is set up, install SIMD on the global object.
     if (!DefineProperty(cx, global, cx->names().SIMD, SIMDValue, nullptr, nullptr, 0))
         return nullptr;
 
     global->setConstructor(JSProto_SIMD, SIMDValue);
     global->setFloat32x4TypeDescr(*float32x4Object);
+    global->setFloat64x2TypeDescr(*float64x2Object);
     global->setInt32x4TypeDescr(*int32x4Object);
     return SIMD;
 }
 
 JSObject *
 js_InitSIMDClass(JSContext *cx, HandleObject obj)
 {
     MOZ_ASSERT(obj->is<GlobalObject>());
@@ -436,16 +506,17 @@ js::CreateSimd(JSContext *cx, typename V
         return nullptr;
 
     Elem *resultMem = reinterpret_cast<Elem *>(result->typedMem());
     memcpy(resultMem, data, sizeof(Elem) * V::lanes);
     return result;
 }
 
 template JSObject *js::CreateSimd<Float32x4>(JSContext *cx, Float32x4::Elem *data);
+template JSObject *js::CreateSimd<Float64x2>(JSContext *cx, Float64x2::Elem *data);
 template JSObject *js::CreateSimd<Int32x4>(JSContext *cx, Int32x4::Elem *data);
 
 namespace js {
 // Unary SIMD operators
 template<typename T>
 struct Abs {
     static inline T apply(T x) { return mozilla::Abs(x); }
 };
@@ -762,18 +833,20 @@ CompareFunc(JSContext *cx, unsigned argc
 
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 2 || !IsVectorObject<In>(args[0]) || !IsVectorObject<In>(args[1]))
         return ErrorBadArgs(cx);
 
     int32_t result[Int32x4::lanes];
     InElem *left = TypedObjectMemory<InElem *>(args[0]);
     InElem *right = TypedObjectMemory<InElem *>(args[1]);
-    for (unsigned i = 0; i < Int32x4::lanes; i++)
-        result[i] = Op<InElem>::apply(left[i], right[i]);
+    for (unsigned i = 0; i < Int32x4::lanes; i++) {
+        unsigned j = (i * In::lanes) / Int32x4::lanes;
+        result[i] = Op<InElem>::apply(left[j], right[j]);
+    }
 
     return StoreResult<Int32x4>(cx, args, result);
 }
 
 template<typename V, typename Vret>
 static bool
 FuncConvert(JSContext *cx, unsigned argc, Value *vp)
 {
@@ -782,17 +855,18 @@ FuncConvert(JSContext *cx, unsigned argc
 
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1 || !IsVectorObject<V>(args[0]))
         return ErrorBadArgs(cx);
 
     Elem *val = TypedObjectMemory<Elem *>(args[0]);
     RetElem result[Vret::lanes];
     for (unsigned i = 0; i < Vret::lanes; i++)
-        result[i] = ConvertScalar<RetElem>(val[i]);
+        result[i] = i < V::lanes ? ConvertScalar<RetElem>(val[i]) : 0;
+
     return StoreResult<Vret>(cx, args, result);
 }
 
 template<typename V, typename Vret>
 static bool
 FuncConvertBits(JSContext *cx, unsigned argc, Value *vp)
 {
     typedef typename Vret::Elem RetElem;
@@ -853,37 +927,39 @@ Int32x4Bool(JSContext *cx, unsigned argc
     }
 
     int32_t result[Int32x4::lanes];
     for (unsigned i = 0; i < Int32x4::lanes; i++)
         result[i] = args[i].toBoolean() ? 0xFFFFFFFF : 0x0;
     return StoreResult<Int32x4>(cx, args, result);
 }
 
+template<typename In>
 static bool
-Float32x4Clamp(JSContext *cx, unsigned argc, Value *vp)
+Clamp(JSContext *cx, unsigned argc, Value *vp)
 {
+    typedef typename In::Elem InElem;
     CallArgs args = CallArgsFromVp(argc, vp);
-    if (args.length() != 3 || !IsVectorObject<Float32x4>(args[0]) ||
-        !IsVectorObject<Float32x4>(args[1]) || !IsVectorObject<Float32x4>(args[2]))
+    if (args.length() != 3 || !IsVectorObject<In>(args[0]) ||
+        !IsVectorObject<In>(args[1]) || !IsVectorObject<In>(args[2]))
     {
         return ErrorBadArgs(cx);
     }
 
-    float *val = TypedObjectMemory<float *>(args[0]);
-    float *lowerLimit = TypedObjectMemory<float *>(args[1]);
-    float *upperLimit = TypedObjectMemory<float *>(args[2]);
+    InElem *val = TypedObjectMemory<InElem *>(args[0]);
+    InElem *lowerLimit = TypedObjectMemory<InElem *>(args[1]);
+    InElem *upperLimit = TypedObjectMemory<InElem *>(args[2]);
 
-    float result[Float32x4::lanes];
-    for (unsigned i = 0; i < Float32x4::lanes; i++) {
+    InElem result[In::lanes];
+    for (unsigned i = 0; i < In::lanes; i++) {
         result[i] = val[i] < lowerLimit[i] ? lowerLimit[i] : val[i];
         result[i] = result[i] > upperLimit[i] ? upperLimit[i] : result[i];
     }
 
-    return StoreResult<Float32x4>(cx, args, result);
+    return StoreResult<In>(cx, args, result);
 }
 
 template<typename V>
 static bool
 BitSelect(JSContext *cx, unsigned argc, Value *vp)
 {
     typedef typename V::Elem Elem;
 
@@ -982,18 +1058,17 @@ Load(JSContext *cx, unsigned argc, Value
 
     Rooted<TypeDescr*> typeDescr(cx, &V::GetTypeDescr(*cx->global()));
     MOZ_ASSERT(typeDescr);
     Rooted<TypedObject *> result(cx, OutlineTypedObject::createZeroed(cx, typeDescr, 0));
     if (!result)
         return false;
 
     Elem *dest = reinterpret_cast<Elem*>(result->typedMem());
-    for (unsigned i = 0; i < NumElem; i++)
-        dest[i] = typedArrayData[i];
+    memcpy(dest, typedArrayData, sizeof(Elem) * NumElem);
 
     args.rval().setObject(*result);
     return true;
 }
 
 template<class V, unsigned NumElem>
 static bool
 Store(JSContext *cx, unsigned argc, Value *vp)
@@ -1007,31 +1082,39 @@ Store(JSContext *cx, unsigned argc, Valu
     Elem *typedArrayData = nullptr;
     if (!TypedArrayDataPtrFromArgs<Elem, NumElem>(cx, args, &typedArrayData))
         return false;
 
     if (!IsVectorObject<V>(args[2]))
         return ErrorBadArgs(cx);
 
     Elem *src = TypedObjectMemory<Elem*>(args[2]);
-    for (unsigned i = 0; i < NumElem; i++)
-        typedArrayData[i] = src[i];
+    memcpy(typedArrayData, src, sizeof(Elem) * NumElem);
 
     args.rval().setObject(args[2].toObject());
     return true;
 }
 
 #define DEFINE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands, Flags) \
 bool                                                                \
 js::simd_float32x4_##Name(JSContext *cx, unsigned argc, Value *vp)  \
 {                                                                   \
     return Func(cx, argc, vp);                                      \
 }
 FLOAT32X4_FUNCTION_LIST(DEFINE_SIMD_FLOAT32X4_FUNCTION)
-#undef DEFINE_SIMD_FLOAT32x4_FUNCTION
+#undef DEFINE_SIMD_FLOAT32X4_FUNCTION
+
+#define DEFINE_SIMD_FLOAT64X2_FUNCTION(Name, Func, Operands, Flags) \
+bool                                                                \
+js::simd_float64x2_##Name(JSContext *cx, unsigned argc, Value *vp)  \
+{                                                                   \
+    return Func(cx, argc, vp);                                      \
+}
+FLOAT64X2_FUNCTION_LIST(DEFINE_SIMD_FLOAT64X2_FUNCTION)
+#undef DEFINE_SIMD_FLOAT64X2_FUNCTION
 
 #define DEFINE_SIMD_INT32X4_FUNCTION(Name, Func, Operands, Flags)   \
 bool                                                                \
 js::simd_int32x4_##Name(JSContext *cx, unsigned argc, Value *vp)    \
 {                                                                   \
     return Func(cx, argc, vp);                                      \
 }
 INT32X4_FUNCTION_LIST(DEFINE_SIMD_INT32X4_FUNCTION)
@@ -1040,15 +1123,23 @@ INT32X4_FUNCTION_LIST(DEFINE_SIMD_INT32X
 const JSFunctionSpec js::Float32x4Methods[] = {
 #define SIMD_FLOAT32X4_FUNCTION_ITEM(Name, Func, Operands, Flags)   \
         JS_FN(#Name, js::simd_float32x4_##Name, Operands, Flags),
         FLOAT32X4_FUNCTION_LIST(SIMD_FLOAT32X4_FUNCTION_ITEM)
 #undef SIMD_FLOAT32x4_FUNCTION_ITEM
         JS_FS_END
 };
 
+const JSFunctionSpec js::Float64x2Methods[] = {
+#define SIMD_FLOAT64X2_FUNCTION_ITEM(Name, Func, Operands, Flags)       \
+        JS_FN(#Name, js::simd_float64x2_##Name, Operands, Flags),
+        FLOAT64X2_FUNCTION_LIST(SIMD_FLOAT64X2_FUNCTION_ITEM)
+#undef SIMD_FLOAT64X2_FUNCTION_ITEM
+        JS_FS_END
+};
+
 const JSFunctionSpec js::Int32x4Methods[] = {
 #define SIMD_INT32X4_FUNCTION_ITEM(Name, Func, Operands, Flags)     \
         JS_FN(#Name, js::simd_int32x4_##Name, Operands, Flags),
         INT32X4_FUNCTION_LIST(SIMD_INT32X4_FUNCTION_ITEM)
 #undef SIMD_INT32X4_FUNCTION_ITEM
         JS_FS_END
 };
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -17,16 +17,18 @@
 /*
  * JS SIMD functions.
  * Spec matching polyfill:
  * https://github.com/johnmccutchan/ecmascript_simd/blob/master/src/ecmascript_simd.js
  */
 
 #define FLOAT32X4_UNARY_FUNCTION_LIST(V)                                            \
   V(abs, (UnaryFunc<Float32x4, Abs, Float32x4>), 1, 0)                              \
+  V(fromFloat64x2, (FuncConvert<Float64x2, Float32x4> ), 1, 0)                      \
+  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Float32x4>), 1, 0)               \
   V(fromInt32x4, (FuncConvert<Int32x4, Float32x4> ), 1, 0)                          \
   V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Float32x4>), 1, 0)                   \
   V(neg, (UnaryFunc<Float32x4, Neg, Float32x4>), 1, 0)                              \
   V(not, (CoercedUnaryFunc<Float32x4, Int32x4, Not, Float32x4>), 1, 0)              \
   V(reciprocal, (UnaryFunc<Float32x4, Rec, Float32x4>), 1, 0)                       \
   V(reciprocalSqrt, (UnaryFunc<Float32x4, RecSqrt, Float32x4>), 1, 0)               \
   V(splat, (FuncSplat<Float32x4>), 1, 0)                                            \
   V(sqrt, (UnaryFunc<Float32x4, Sqrt, Float32x4>), 1, 0)
@@ -59,32 +61,83 @@
   V(withX, (FuncWith<Float32x4, WithX>), 2, 0)                                      \
   V(withY, (FuncWith<Float32x4, WithY>), 2, 0)                                      \
   V(withZ, (FuncWith<Float32x4, WithZ>), 2, 0)                                      \
   V(withW, (FuncWith<Float32x4, WithW>), 2, 0)                                      \
   V(xor, (CoercedBinaryFunc<Float32x4, Int32x4, Xor, Float32x4>), 2, 0)
 
 #define FLOAT32X4_TERNARY_FUNCTION_LIST(V)                                          \
   V(bitselect, BitSelect<Float32x4>, 3, 0)                                          \
-  V(clamp, Float32x4Clamp, 3, 0)                                                    \
+  V(clamp, Clamp<Float32x4>, 3, 0)                                                  \
   V(select, Select<Float32x4>, 3, 0)
 
 #define FLOAT32X4_SHUFFLE_FUNCTION_LIST(V)                                          \
   V(swizzle, Swizzle<Float32x4>, 2, 0)                                              \
   V(shuffle, Shuffle<Float32x4>, 3, 0)
 
 #define FLOAT32X4_FUNCTION_LIST(V)                                                  \
   FLOAT32X4_UNARY_FUNCTION_LIST(V)                                                  \
   FLOAT32X4_BINARY_FUNCTION_LIST(V)                                                 \
   FLOAT32X4_TERNARY_FUNCTION_LIST(V)                                                \
   FLOAT32X4_SHUFFLE_FUNCTION_LIST(V)
 
+#define FLOAT64X2_UNARY_FUNCTION_LIST(V)                                            \
+  V(abs, (UnaryFunc<Float64x2, Abs, Float64x2>), 1, 0)                              \
+  V(fromFloat32x4, (FuncConvert<Float32x4, Float64x2> ), 1, 0)                      \
+  V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Float64x2>), 1, 0)               \
+  V(fromInt32x4, (FuncConvert<Int32x4, Float64x2> ), 1, 0)                          \
+  V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Float64x2>), 1, 0)                   \
+  V(neg, (UnaryFunc<Float64x2, Neg, Float64x2>), 1, 0)                              \
+  V(reciprocal, (UnaryFunc<Float64x2, Rec, Float64x2>), 1, 0)                       \
+  V(reciprocalSqrt, (UnaryFunc<Float64x2, RecSqrt, Float64x2>), 1, 0)               \
+  V(splat, (FuncSplat<Float64x2>), 1, 0)                                            \
+  V(sqrt, (UnaryFunc<Float64x2, Sqrt, Float64x2>), 1, 0)
+
+#define FLOAT64X2_BINARY_FUNCTION_LIST(V)                                           \
+  V(add, (BinaryFunc<Float64x2, Add, Float64x2>), 2, 0)                             \
+  V(div, (BinaryFunc<Float64x2, Div, Float64x2>), 2, 0)                             \
+  V(equal, (CompareFunc<Float64x2, Equal>), 2, 0)                                   \
+  V(greaterThan, (CompareFunc<Float64x2, GreaterThan>), 2, 0)                       \
+  V(greaterThanOrEqual, (CompareFunc<Float64x2, GreaterThanOrEqual>), 2, 0)         \
+  V(lessThan, (CompareFunc<Float64x2, LessThan>), 2, 0)                             \
+  V(lessThanOrEqual, (CompareFunc<Float64x2, LessThanOrEqual>), 2, 0)               \
+  V(load,    (Load<Float64x2, 2>), 2, 0)                                            \
+  V(loadX,   (Load<Float64x2, 1>), 2, 0)                                            \
+  V(max, (BinaryFunc<Float64x2, Maximum, Float64x2>), 2, 0)                         \
+  V(maxNum, (BinaryFunc<Float64x2, MaxNum, Float64x2>), 2, 0)                       \
+  V(min, (BinaryFunc<Float64x2, Minimum, Float64x2>), 2, 0)                         \
+  V(minNum, (BinaryFunc<Float64x2, MinNum, Float64x2>), 2, 0)                       \
+  V(mul, (BinaryFunc<Float64x2, Mul, Float64x2>), 2, 0)                             \
+  V(notEqual, (CompareFunc<Float64x2, NotEqual>), 2, 0)                             \
+  V(store,    (Store<Float64x2, 2>), 3, 0)                                          \
+  V(storeX,   (Store<Float64x2, 1>), 3, 0)                                          \
+  V(sub, (BinaryFunc<Float64x2, Sub, Float64x2>), 2, 0)                             \
+  V(withX, (FuncWith<Float64x2, WithX>), 2, 0)                                      \
+  V(withY, (FuncWith<Float64x2, WithY>), 2, 0)
+
+#define FLOAT64X2_TERNARY_FUNCTION_LIST(V)                                          \
+  V(bitselect, BitSelect<Float64x2>, 3, 0)                                          \
+  V(clamp, Clamp<Float64x2>, 3, 0)                                                  \
+  V(select, Select<Float64x2>, 3, 0)
+
+#define FLOAT64X2_SHUFFLE_FUNCTION_LIST(V)                                          \
+  V(swizzle, Swizzle<Float64x2>, 2, 0)                                              \
+  V(shuffle, Shuffle<Float64x2>, 3, 0)
+
+#define FLOAT64X2_FUNCTION_LIST(V)                                                  \
+  FLOAT64X2_UNARY_FUNCTION_LIST(V)                                                  \
+  FLOAT64X2_BINARY_FUNCTION_LIST(V)                                                 \
+  FLOAT64X2_TERNARY_FUNCTION_LIST(V)                                                \
+  FLOAT64X2_SHUFFLE_FUNCTION_LIST(V)
+
 #define INT32X4_UNARY_FUNCTION_LIST(V)                                              \
   V(fromFloat32x4, (FuncConvert<Float32x4, Int32x4>), 1, 0)                         \
   V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int32x4>), 1, 0)                 \
+  V(fromFloat64x2, (FuncConvert<Float64x2, Int32x4>), 1, 0)                         \
+  V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int32x4>), 1, 0)                 \
   V(neg, (UnaryFunc<Int32x4, Neg, Int32x4>), 1, 0)                                  \
   V(not, (UnaryFunc<Int32x4, Not, Int32x4>), 1, 0)                                  \
   V(splat, (FuncSplat<Int32x4>), 0, 0)
 
 #define INT32X4_BINARY_FUNCTION_LIST(V)                                             \
   V(add, (BinaryFunc<Int32x4, Add, Int32x4>), 2, 0)                                 \
   V(and, (BinaryFunc<Int32x4, And, Int32x4>), 2, 0)                                 \
   V(equal, (CompareFunc<Int32x4, Equal>), 2, 0)                                     \
@@ -207,16 +260,36 @@ struct Float32x4 {
         *out = v.toNumber();
         return true;
     }
     static void setReturn(CallArgs &args, Elem value) {
         args.rval().setDouble(JS::CanonicalizeNaN(value));
     }
 };
 
+struct Float64x2 {
+    typedef double Elem;
+    static const unsigned lanes = 2;
+    static const SimdTypeDescr::Type type = SimdTypeDescr::TYPE_FLOAT64;
+
+    static TypeDescr &GetTypeDescr(GlobalObject &global) {
+        return global.float64x2TypeDescr().as<TypeDescr>();
+    }
+    static Elem toType(Elem a) {
+        return a;
+    }
+    static bool toType(JSContext *cx, JS::HandleValue v, Elem *out) {
+        *out = v.toNumber();
+        return true;
+    }
+    static void setReturn(CallArgs &args, Elem value) {
+        args.rval().setDouble(JS::CanonicalizeNaN(value));
+    }
+};
+
 struct Int32x4 {
     typedef int32_t Elem;
     static const unsigned lanes = 4;
     static const SimdTypeDescr::Type type = SimdTypeDescr::TYPE_INT32;
 
     static TypeDescr &GetTypeDescr(GlobalObject &global) {
         return global.int32x4TypeDescr().as<TypeDescr>();
     }
@@ -241,16 +314,22 @@ template<typename V>
 bool ToSimdConstant(JSContext *cx, HandleValue v, jit::SimdConstant *out);
 
 #define DECLARE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands, Flags) \
 extern bool                                                          \
 simd_float32x4_##Name(JSContext *cx, unsigned argc, Value *vp);
 FLOAT32X4_FUNCTION_LIST(DECLARE_SIMD_FLOAT32X4_FUNCTION)
 #undef DECLARE_SIMD_FLOAT32X4_FUNCTION
 
+#define DECLARE_SIMD_FLOAT64X2_FUNCTION(Name, Func, Operands, Flags) \
+extern bool                                                          \
+simd_float64x2_##Name(JSContext *cx, unsigned argc, Value *vp);
+FLOAT64X2_FUNCTION_LIST(DECLARE_SIMD_FLOAT64X2_FUNCTION)
+#undef DECLARE_SIMD_FLOAT64X2_FUNCTION
+
 #define DECLARE_SIMD_INT32x4_FUNCTION(Name, Func, Operands, Flags)   \
 extern bool                                                          \
 simd_int32x4_##Name(JSContext *cx, unsigned argc, Value *vp);
 INT32X4_FUNCTION_LIST(DECLARE_SIMD_INT32x4_FUNCTION)
 #undef DECLARE_SIMD_INT32x4_FUNCTION
 
 }  /* namespace js */
 
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -401,40 +401,53 @@ js::ReferenceTypeDescr::call(JSContext *
         return true;
       }
     }
 
     MOZ_CRASH("Unhandled Reference type");
 }
 
 /***************************************************************************
- * X4 type objects
+ * SIMD type objects
  *
  * Note: these are partially defined in SIMD.cpp
  */
 
 static const int32_t SimdSizes[] = {
-#define SIMD_SIZE(_kind, _type, _name)                        \
-    sizeof(_type) * 4,
+#define SIMD_SIZE(_kind, _type, _name, _lanes)                 \
+    sizeof(_type) * _lanes,
     JS_FOR_EACH_SIMD_TYPE_REPR(SIMD_SIZE) 0
 #undef SIMD_SIZE
 };
 
+static int32_t SimdLanes[] = {
+#define SIMD_LANE(_kind, _type, _name, _lanes)                 \
+    _lanes,
+    JS_FOR_EACH_SIMD_TYPE_REPR(SIMD_LANE) 0
+#undef SIMD_LANE
+};
+
 int32_t
 SimdTypeDescr::size(Type t)
 {
     return SimdSizes[t];
 }
 
 int32_t
 SimdTypeDescr::alignment(Type t)
 {
     return SimdSizes[t];
 }
 
+int32_t
+SimdTypeDescr::lanes(Type t)
+{
+    return SimdLanes[t];
+}
+
 /***************************************************************************
  * ArrayMetaTypeDescr class
  */
 
 /*
  * For code like:
  *
  *   var A = new TypedObject.ArrayType(uint8, 10);
@@ -2690,16 +2703,26 @@ js::GetFloat32x4TypeDescr(JSContext *cx,
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     MOZ_ASSERT(global);
     args.rval().setObject(global->float32x4TypeDescr());
     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->float64x2TypeDescr());
+    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->int32x4TypeDescr());
     return true;
 }
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -320,43 +320,46 @@ class ComplexTypeDescr : public TypeDesc
     // Returns the prototype that instances of this type descriptor
     // will have.
     TypedProto &instancePrototype() const {
         return getReservedSlot(JS_DESCR_SLOT_TYPROTO).toObject().as<TypedProto>();
     }
 };
 
 /*
- * Type descriptors `float32x4` and `int32x4`
+ * Type descriptors `float32x4`, `int32x4` and `float64x2`
  */
 class SimdTypeDescr : public ComplexTypeDescr
 {
   public:
     enum Type {
         TYPE_INT32 = JS_SIMDTYPEREPR_INT32,
         TYPE_FLOAT32 = JS_SIMDTYPEREPR_FLOAT32,
+        TYPE_FLOAT64 = JS_SIMDTYPEREPR_FLOAT64
     };
 
     static const type::Kind Kind = type::Simd;
     static const bool Opaque = false;
     static const Class class_;
     static int32_t size(Type t);
     static int32_t alignment(Type t);
+    static int32_t lanes(Type t);
 
     SimdTypeDescr::Type type() const {
         return (SimdTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
     }
 
     static bool call(JSContext *cx, unsigned argc, Value *vp);
     static bool is(const Value &v);
 };
 
 #define JS_FOR_EACH_SIMD_TYPE_REPR(macro_)                             \
-    macro_(SimdTypeDescr::TYPE_INT32, int32_t, int32)                  \
-    macro_(SimdTypeDescr::TYPE_FLOAT32, float, float32)
+    macro_(SimdTypeDescr::TYPE_INT32, int32_t, int32, 4)               \
+    macro_(SimdTypeDescr::TYPE_FLOAT32, float, float32, 4)             \
+    macro_(SimdTypeDescr::TYPE_FLOAT64, double, float64, 2)
 
 bool IsTypedObjectClass(const Class *clasp); // Defined below
 bool IsTypedObjectArray(JSObject& obj);
 
 bool CreateUserSizeAndAlignmentProperties(JSContext *cx, HandleTypeDescr obj);
 
 class ArrayTypeDescr;
 
@@ -876,16 +879,24 @@ bool GetTypedObjectModule(JSContext *cx,
  * Usage: GetFloat32x4TypeDescr()
  *
  * Returns the float32x4 type object. SIMD pseudo-module must have
  * been initialized for this to be safe.
  */
 bool GetFloat32x4TypeDescr(JSContext *cx, unsigned argc, Value *vp);
 
 /*
+ * Usage: GetFloat64x2TypeDescr()
+ *
+ * Returns the float64x2 type object. SIMD pseudo-module must have
+ * been initialized for this to be safe.
+ */
+bool GetFloat64x2TypeDescr(JSContext *cx, unsigned argc, Value *vp);
+
+/*
  * Usage: GetInt32x4TypeDescr()
  *
  * Returns the int32x4 type object. SIMD pseudo-module must have
  * been initialized for this to be safe.
  */
 bool GetInt32x4TypeDescr(JSContext *cx, unsigned argc, Value *vp);
 
 /*
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -147,16 +147,21 @@ function TypedObjectGetSimd(descr, typed
   switch (type) {
   case JS_SIMDTYPEREPR_FLOAT32:
     var x = Load_float32(typedObj, offset + 0);
     var y = Load_float32(typedObj, offset + 4);
     var z = Load_float32(typedObj, offset + 8);
     var w = Load_float32(typedObj, offset + 12);
     return GetFloat32x4TypeDescr()(x, y, z, w);
 
+  case JS_SIMDTYPEREPR_FLOAT64:
+    var x = Load_float64(typedObj, offset + 0);
+    var y = Load_float64(typedObj, offset + 8);
+    return GetFloat64x2TypeDescr()(x, y);
+
   case JS_SIMDTYPEREPR_INT32:
     var x = Load_int32(typedObj, offset + 0);
     var y = Load_int32(typedObj, offset + 4);
     var z = Load_int32(typedObj, offset + 8);
     var w = Load_int32(typedObj, offset + 12);
     return GetInt32x4TypeDescr()(x, y, z, w);
   }
 
@@ -317,16 +322,20 @@ function TypedObjectSetSimd(descr, typed
   var type = DESCR_TYPE(descr);
   switch (type) {
     case JS_SIMDTYPEREPR_FLOAT32:
       Store_float32(typedObj, offset + 0, Load_float32(fromValue, 0));
       Store_float32(typedObj, offset + 4, Load_float32(fromValue, 4));
       Store_float32(typedObj, offset + 8, Load_float32(fromValue, 8));
       Store_float32(typedObj, offset + 12, Load_float32(fromValue, 12));
       break;
+    case JS_SIMDTYPEREPR_FLOAT64:
+      Store_float64(typedObj, offset + 0, Load_float64(fromValue, 0));
+      Store_float64(typedObj, offset + 8, Load_float64(fromValue, 8));
+      break;
     case JS_SIMDTYPEREPR_INT32:
       Store_int32(typedObj, offset + 0, Load_int32(fromValue, 0));
       Store_int32(typedObj, offset + 4, Load_int32(fromValue, 4));
       Store_int32(typedObj, offset + 8, Load_int32(fromValue, 8));
       Store_int32(typedObj, offset + 12, Load_int32(fromValue, 12));
       break;
     default:
       assert(false, "Unhandled Simd type: " + type);
@@ -452,33 +461,53 @@ function TypedObjectArrayRedimension(new
 // SIMD
 
 function SimdProtoString(type) {
   switch (type) {
   case JS_SIMDTYPEREPR_INT32:
     return "int32x4";
   case JS_SIMDTYPEREPR_FLOAT32:
     return "float32x4";
+  case JS_SIMDTYPEREPR_FLOAT64:
+    return "float64x2";
+  }
+
+  assert(false, "Unhandled type constant");
+  return undefined;
+}
+
+function SimdTypeToLength(type) {
+  switch (type) {
+  case JS_SIMDTYPEREPR_INT32:
+  case JS_SIMDTYPEREPR_FLOAT32:
+    return 4;
+  case JS_SIMDTYPEREPR_FLOAT64:
+    return 2;
   }
 
   assert(false, "Unhandled type constant");
   return undefined;
 }
 
 function SimdToSource() {
   if (!IsObject(this) || !ObjectIsTypedObject(this))
     ThrowError(JSMSG_INCOMPATIBLE_PROTO, "SIMD", "toSource", typeof this);
 
   var descr = TypedObjectTypeDescr(this);
 
   if (DESCR_KIND(descr) != JS_TYPEREPR_SIMD_KIND)
     ThrowError(JSMSG_INCOMPATIBLE_PROTO, "SIMD", "toSource", typeof this);
 
   var type = DESCR_TYPE(descr);
-  return SimdProtoString(type)+"("+this.x+", "+this.y+", "+this.z+", "+this.w+")";
+  var protoString = SimdProtoString(type);
+  var length = SimdTypeToLength(type);
+  if (length == 4)
+    return protoString+"("+this.x+", "+this.y+", "+this.z+", "+this.w+")";
+  else if (length == 2)
+    return protoString+"("+this.x+", "+this.y+")";
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Miscellaneous
 
 function DescrsEquiv(descr1, descr2) {
   assert(IsObject(descr1) && ObjectIsTypeDescr(descr1), "descr1 not descr");
   assert(IsObject(descr2) && ObjectIsTypeDescr(descr2), "descr2 not descr");
--- a/js/src/builtin/TypedObjectConstants.h
+++ b/js/src/builtin/TypedObjectConstants.h
@@ -27,18 +27,19 @@
 #define JS_DESCR_SLOT_STRING_REPR        1  // Atomized string representation
 #define JS_DESCR_SLOT_ALIGNMENT          2  // Alignment in bytes
 #define JS_DESCR_SLOT_SIZE               3  // Size in bytes, else 0
 #define JS_DESCR_SLOT_OPAQUE             4  // Atomized string representation
 #define JS_DESCR_SLOT_TYPROTO            5  // Prototype for instances, if any
 #define JS_DESCR_SLOT_ARRAYPROTO         6  // Lazily created prototype for arrays
 #define JS_DESCR_SLOT_TRACE_LIST         7  // List of references for use in tracing
 
-// Slots on scalars, references, and x4s
+// Slots on scalars, references, and SIMD objects
 #define JS_DESCR_SLOT_TYPE               8  // Type code
+#define JS_DESCR_SLOT_LANES              9
 
 // Slots on array descriptors
 #define JS_DESCR_SLOT_ARRAY_ELEM_TYPE    8
 #define JS_DESCR_SLOT_ARRAY_LENGTH       9
 
 // Slots on struct type objects
 #define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 8
 #define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 9
@@ -80,10 +81,11 @@
 #define JS_REFERENCETYPEREPR_STRING     2
 
 // These constants are for use exclusively in JS code.  In C++ code,
 // prefer SimdTypeRepresentation::TYPE_INT32 etc, since that allows
 // you to write a switch which will receive a warning if you omit a
 // case.
 #define JS_SIMDTYPEREPR_INT32         0
 #define JS_SIMDTYPEREPR_FLOAT32       1
+#define JS_SIMDTYPEREPR_FLOAT64       2
 
 #endif
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -74,16 +74,17 @@
     macro(false, false_, "false") \
     macro(fieldOffsets, fieldOffsets, "fieldOffsets") \
     macro(fieldTypes, fieldTypes, "fieldTypes") \
     macro(fileName, fileName, "fileName") \
     macro(fix, fix, "fix") \
     macro(float32, float32, "float32") \
     macro(float32x4, float32x4, "float32x4") \
     macro(float64, float64, "float64") \
+    macro(float64x2, float64x2, "float64x2") \
     macro(forceInterpreter, forceInterpreter, "forceInterpreter") \
     macro(format, format, "format") \
     macro(frame, frame, "frame") \
     macro(from, from, "from") \
     macro(get, get, "get") \
     macro(getInternals, getInternals, "getInternals") \
     macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \
     macro(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -99,18 +99,19 @@ class GlobalObject : public NativeObject
     static const unsigned NUMBER_FORMAT_PROTO     = COLLATOR_PROTO + 1;
     static const unsigned DATE_TIME_FORMAT_PROTO  = NUMBER_FORMAT_PROTO + 1;
     static const unsigned REGEXP_STATICS          = DATE_TIME_FORMAT_PROTO + 1;
     static const unsigned WARNED_WATCH_DEPRECATED = REGEXP_STATICS + 1;
     static const unsigned WARNED_PROTO_SETTING_SLOW = WARNED_WATCH_DEPRECATED + 1;
     static const unsigned RUNTIME_CODEGEN_ENABLED = WARNED_PROTO_SETTING_SLOW + 1;
     static const unsigned DEBUGGERS               = RUNTIME_CODEGEN_ENABLED + 1;
     static const unsigned INTRINSICS              = DEBUGGERS + 1;
-    static const unsigned FLOAT32X4_TYPE_DESCR   = INTRINSICS + 1;
-    static const unsigned INT32X4_TYPE_DESCR     = FLOAT32X4_TYPE_DESCR + 1;
+    static const unsigned FLOAT32X4_TYPE_DESCR    = INTRINSICS + 1;
+    static const unsigned FLOAT64X2_TYPE_DESCR    = FLOAT32X4_TYPE_DESCR + 1;
+    static const unsigned INT32X4_TYPE_DESCR      = FLOAT64X2_TYPE_DESCR + 1;
     static const unsigned FOR_OF_PIC_CHAIN        = INT32X4_TYPE_DESCR + 1;
 
     /* Total reserved-slot count for global objects. */
     static const unsigned RESERVED_SLOTS = FOR_OF_PIC_CHAIN + 1;
 
     /*
      * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, and
      * we won't expose GlobalObject, so just assert that the two values are
@@ -403,16 +404,26 @@ class GlobalObject : public NativeObject
         setSlot(FLOAT32X4_TYPE_DESCR, ObjectValue(obj));
     }
 
     JSObject &float32x4TypeDescr() {
         MOZ_ASSERT(getSlotRef(FLOAT32X4_TYPE_DESCR).isObject());
         return getSlotRef(FLOAT32X4_TYPE_DESCR).toObject();
     }
 
+    void setFloat64x2TypeDescr(JSObject &obj) {
+        MOZ_ASSERT(getSlotRef(FLOAT64X2_TYPE_DESCR).isUndefined());
+        setSlot(FLOAT64X2_TYPE_DESCR, ObjectValue(obj));
+    }
+
+    JSObject &float64x2TypeDescr() {
+        MOZ_ASSERT(getSlotRef(FLOAT64X2_TYPE_DESCR).isObject());
+        return getSlotRef(FLOAT64X2_TYPE_DESCR).toObject();
+    }
+
     void setInt32x4TypeDescr(JSObject &obj) {
         MOZ_ASSERT(getSlotRef(INT32X4_TYPE_DESCR).isUndefined());
         setSlot(INT32X4_TYPE_DESCR, ObjectValue(obj));
     }
 
     JSObject &int32x4TypeDescr() {
         MOZ_ASSERT(getSlotRef(INT32X4_TYPE_DESCR).isObject());
         return getSlotRef(INT32X4_TYPE_DESCR).toObject();
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -964,16 +964,17 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("TypedObjectIsAttached",          js::TypedObjectIsAttached, 1, 0),
     JS_FN("TypedObjectTypeDescr",           js::TypedObjectTypeDescr, 1, 0),
     JS_FN("ObjectIsOpaqueTypedObject",      js::ObjectIsOpaqueTypedObject, 1, 0),
     JS_FN("TypeDescrIsArrayType",           js::TypeDescrIsArrayType, 1, 0),
     JS_FN("TypeDescrIsSimpleType",          js::TypeDescrIsSimpleType, 1, 0),
     JS_FN("ClampToUint8",                   js::ClampToUint8, 1, 0),
     JS_FN("GetTypedObjectModule",           js::GetTypedObjectModule, 0, 0),
     JS_FN("GetFloat32x4TypeDescr",          js::GetFloat32x4TypeDescr, 0, 0),
+    JS_FN("GetFloat64x2TypeDescr",          js::GetFloat64x2TypeDescr, 0, 0),
     JS_FN("GetInt32x4TypeDescr",            js::GetInt32x4TypeDescr, 0, 0),
 
 #define LOAD_AND_STORE_SCALAR_FN_DECLS(_constant, _type, _name)         \
     JS_FN("Store_" #_name, js::StoreScalar##_type::Func, 3, 0),         \
     JS_FN("Load_" #_name,  js::LoadScalar##_type::Func, 3, 0),
     JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(LOAD_AND_STORE_SCALAR_FN_DECLS)
 #undef LOAD_AND_STORE_SCALAR_FN_DECLS