Bug 898356 Part 1 -- Separate out simple type descriptors from the rest so that they can be referenced by TypedArray.h without pulling in everything else r=sfink
authorNicholas D. Matsakis <nmatsakis@mozilla.com>
Mon, 03 Feb 2014 10:55:40 -0500
changeset 170069 94fda27a798e27bbbc6038bcebd2f9fee6942515
parent 170068 7a5cbe4dadf88785c687b75af0f48b26ba3494bc
child 170070 f163330fdc38e1d1075eb4052903c5f453afa148
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerssfink
bugs898356
milestone30.0a1
Bug 898356 Part 1 -- Separate out simple type descriptors from the rest so that they can be referenced by TypedArray.h without pulling in everything else r=sfink
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/builtin/TypedObjectSimple.cpp
js/src/builtin/TypedObjectSimple.h
js/src/moz.build
js/src/vm/TypedArrayObject.h
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -170,217 +170,16 @@ GetPrototype(JSContext *cx, HandleObject
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                              JSMSG_INVALID_PROTOTYPE);
         return nullptr;
     }
     return &prototypeVal.toObject();
 }
 
 /***************************************************************************
- * Type descriptors
- */
-
-TypeRepresentation *
-TypeDescr::typeRepresentation() const {
-    return TypeRepresentation::fromOwnerObject(typeRepresentationOwnerObj());
-}
-
-TypeDescr::Kind
-TypeDescr::kind() const {
-    return typeRepresentation()->kind();
-}
-
-/***************************************************************************
- * Scalar type objects
- *
- * Scalar type objects like `uint8`, `uint16`, are all instances of
- * the ScalarTypeDescr class. Like all type objects, they have a reserved
- * slot pointing to a TypeRepresentation object, which is used to
- * distinguish which scalar type object this actually is.
- */
-
-const Class js::ScalarTypeDescr::class_ = {
-    "Scalar",
-    JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
-    JS_PropertyStub,       /* getProperty */
-    JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,
-    ScalarTypeDescr::call,
-    nullptr,
-    nullptr,
-    nullptr
-};
-
-const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
-    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
-    {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
-    {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
-    JS_FS_END
-};
-
-static size_t ScalarSizes[] = {
-#define SCALAR_SIZE(_kind, _type, _name)                        \
-    sizeof(_type),
-    JS_FOR_EACH_SCALAR_TYPE_REPR(SCALAR_SIZE) 0
-#undef SCALAR_SIZE
-};
-
-size_t
-ScalarTypeDescr::size(Type t)
-{
-    return ScalarSizes[t];
-}
-
-size_t
-ScalarTypeDescr::alignment(Type t)
-{
-    return ScalarSizes[t];
-}
-
-/*static*/ const char *
-ScalarTypeDescr::typeName(Type type)
-{
-    switch (type) {
-#define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
-        case constant_: return #name_;
-        JS_FOR_EACH_SCALAR_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
-    }
-    MOZ_ASSUME_UNREACHABLE("Invalid type");
-}
-
-bool
-ScalarTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    if (args.length() < 1) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
-                             args.callee().getClass()->name, "0", "s");
-        return false;
-    }
-
-    ScalarTypeRepresentation *typeRepr =
-        args.callee().as<ScalarTypeDescr>().typeRepresentation()->asScalar();
-    ScalarTypeDescr::Type type = typeRepr->type();
-
-    double number;
-    if (!ToNumber(cx, args[0], &number))
-        return false;
-
-    if (type == ScalarTypeDescr::TYPE_UINT8_CLAMPED)
-        number = ClampDoubleToUint8(number);
-
-    switch (type) {
-#define SCALARTYPE_CALL(constant_, type_, name_)                             \
-      case constant_: {                                                       \
-          type_ converted = ConvertScalar<type_>(number);                     \
-          args.rval().setNumber((double) converted);                          \
-          return true;                                                        \
-      }
-
-        JS_FOR_EACH_SCALAR_TYPE_REPR(SCALARTYPE_CALL)
-#undef SCALARTYPE_CALL
-
-    }
-    return true;
-}
-
-/***************************************************************************
- * Reference type objects
- *
- * Reference type objects like `Any` or `Object` basically work the
- * same way that the scalar type objects do. There is one class with
- * many instances, and each instance has a reserved slot with a
- * TypeRepresentation object, which is used to distinguish which
- * reference type object this actually is.
- */
-
-const Class js::ReferenceTypeDescr::class_ = {
-    "Reference",
-    JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
-    JS_PropertyStub,       /* getProperty */
-    JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    nullptr,
-    ReferenceTypeDescr::call,
-    nullptr,
-    nullptr,
-    nullptr
-};
-
-const JSFunctionSpec js::ReferenceTypeDescr::typeObjectMethods[] = {
-    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
-    {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
-    {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
-    JS_FS_END
-};
-
-/*static*/ const char *
-ReferenceTypeDescr::typeName(Type type)
-{
-    switch (type) {
-#define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
-        case constant_: return #name_;
-        JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
-    }
-    MOZ_ASSUME_UNREACHABLE("Invalid type");
-}
-
-bool
-js::ReferenceTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    JS_ASSERT(args.callee().is<ReferenceTypeDescr>());
-    ReferenceTypeRepresentation *typeRepr =
-        args.callee().as<ReferenceTypeDescr>().typeRepresentation()->asReference();
-
-    if (args.length() < 1) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
-                             JSMSG_MORE_ARGS_NEEDED,
-                             typeRepr->typeName(), "0", "s");
-        return false;
-    }
-
-    switch (typeRepr->type()) {
-      case ReferenceTypeDescr::TYPE_ANY:
-        args.rval().set(args[0]);
-        return true;
-
-      case ReferenceTypeDescr::TYPE_OBJECT:
-      {
-        RootedObject obj(cx, ToObject(cx, args[0]));
-        if (!obj)
-            return false;
-        args.rval().setObject(*obj);
-        return true;
-      }
-
-      case ReferenceTypeDescr::TYPE_STRING:
-      {
-        RootedString obj(cx, ToString<CanGC>(cx, args[0]));
-        if (!obj)
-            return false;
-        args.rval().setString(&*obj);
-        return true;
-      }
-    }
-
-    MOZ_ASSUME_UNREACHABLE("Unhandled Reference type");
-}
-
-/***************************************************************************
  * ArrayMetaTypeDescr class
  */
 
 /*
  * For code like:
  *
  *   var A = new TypedObject.ArrayType(uint8, 10);
  *   var S = new TypedObject.StructType({...});
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef builtin_TypedObject_h
 #define builtin_TypedObject_h
 
 #include "jsobj.h"
 
 #include "builtin/TypedObjectConstants.h"
+#include "builtin/TypedObjectSimple.h"
+#include "vm/TypedArrayObject.h"
 
 /*
  * -------------
  * Typed Objects
  * -------------
  *
  * Typed objects are a special kind of JS object where the data is
  * given well-structured form. To use a typed object, users first
@@ -90,67 +92,16 @@
  * the derived object is alive. We always maintain the invariant that
  * JS_TYPEDOBJ_SLOT_OWNER is the true owner of the memory, meaning
  * that there is a shallow tree. This prevents an access pattern like
  * `a.b.c.d` from keeping all the intermediate objects alive.
  */
 
 namespace js {
 
-class TypeRepresentation;
-class ScalarTypeRepresentation;
-class ReferenceTypeRepresentation;
-class X4TypeRepresentation;
-class StructTypeDescr;
-
-/*
- * Helper method for converting a double into other scalar
- * types in the same way that JavaScript would. In particular,
- * simple C casting from double to int32_t gets things wrong
- * for values like 0xF0000000.
- */
-template <typename T>
-static T ConvertScalar(double d)
-{
-    if (TypeIsFloatingPoint<T>()) {
-        return T(d);
-    } else if (TypeIsUnsigned<T>()) {
-        uint32_t n = ToUint32(d);
-        return T(n);
-    } else {
-        int32_t n = ToInt32(d);
-        return T(n);
-    }
-}
-
-class TypeDescr : public JSObject
-{
-  public:
-    enum Kind {
-        Scalar = JS_TYPEREPR_SCALAR_KIND,
-        Reference = JS_TYPEREPR_REFERENCE_KIND,
-        X4 = JS_TYPEREPR_X4_KIND,
-        Struct = JS_TYPEREPR_STRUCT_KIND,
-        SizedArray = JS_TYPEREPR_SIZED_ARRAY_KIND,
-        UnsizedArray = JS_TYPEREPR_UNSIZED_ARRAY_KIND,
-    };
-
-    static bool isSized(Kind kind) {
-        return kind > JS_TYPEREPR_MAX_UNSIZED_KIND;
-    }
-
-    JSObject &typeRepresentationOwnerObj() const {
-        return getReservedSlot(JS_DESCR_SLOT_TYPE_REPR).toObject();
-    }
-
-    TypeRepresentation *typeRepresentation() const;
-
-    TypeDescr::Kind kind() const;
-};
-
 /*
  * This object exists in order to encapsulate the typed object types
  * somewhat, rather than sticking them all into the global object.
  * Eventually it will go away and become a module.
  */
 class TypedObjectModuleObject : public JSObject {
   public:
     enum Slot {
@@ -162,152 +113,20 @@ class TypedObjectModuleObject : public J
     static const Class class_;
 
     static bool getSuitableClaspAndProto(JSContext *cx,
                                          TypeDescr::Kind kind,
                                          const Class **clasp,
                                          MutableHandleObject proto);
 };
 
-typedef Handle<TypeDescr*> HandleTypeDescr;
-
 bool InitializeCommonTypeDescriptorProperties(JSContext *cx,
                                               HandleTypeDescr obj,
                                               HandleObject typeReprOwnerObj);
 
-class SizedTypeDescr : public TypeDescr
-{
-  public:
-    size_t size() {
-        return getReservedSlot(JS_DESCR_SLOT_SIZE).toInt32();
-    }
-};
-
-typedef Handle<SizedTypeDescr*> HandleSizedTypeDescr;
-
-class SimpleTypeDescr : public SizedTypeDescr
-{
-};
-
-// Type for scalar type constructors like `uint8`. All such type
-// constructors share a common js::Class and JSFunctionSpec. Scalar
-// types are non-opaque (their storage is visible unless combined with
-// an opaque reference type.)
-class ScalarTypeDescr : public SimpleTypeDescr
-{
-  public:
-    // Must match order of JS_FOR_EACH_SCALAR_TYPE_REPR below
-    enum Type {
-        TYPE_INT8 = JS_SCALARTYPEREPR_INT8,
-        TYPE_UINT8 = JS_SCALARTYPEREPR_UINT8,
-        TYPE_INT16 = JS_SCALARTYPEREPR_INT16,
-        TYPE_UINT16 = JS_SCALARTYPEREPR_UINT16,
-        TYPE_INT32 = JS_SCALARTYPEREPR_INT32,
-        TYPE_UINT32 = JS_SCALARTYPEREPR_UINT32,
-        TYPE_FLOAT32 = JS_SCALARTYPEREPR_FLOAT32,
-        TYPE_FLOAT64 = JS_SCALARTYPEREPR_FLOAT64,
-
-        /*
-         * Special type that's a uint8_t, but assignments are clamped to 0 .. 255.
-         * Treat the raw data type as a uint8_t.
-         */
-        TYPE_UINT8_CLAMPED = JS_SCALARTYPEREPR_UINT8_CLAMPED,
-    };
-    static const int32_t TYPE_MAX = TYPE_UINT8_CLAMPED + 1;
-
-    static size_t size(Type t);
-    static size_t alignment(Type t);
-    static const char *typeName(Type type);
-
-    static const Class class_;
-    static const JSFunctionSpec typeObjectMethods[];
-    typedef ScalarTypeRepresentation TypeRepr;
-
-    ScalarTypeDescr::Type type() const {
-        return (ScalarTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
-    }
-
-    static bool call(JSContext *cx, unsigned argc, Value *vp);
-};
-
-// Enumerates the cases of ScalarTypeDescr::Type which have
-// unique C representation. In particular, omits Uint8Clamped since it
-// is just a Uint8.
-#define JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                     \
-    macro_(ScalarTypeDescr::TYPE_INT8,    int8_t,   int8)            \
-    macro_(ScalarTypeDescr::TYPE_UINT8,   uint8_t,  uint8)           \
-    macro_(ScalarTypeDescr::TYPE_INT16,   int16_t,  int16)           \
-    macro_(ScalarTypeDescr::TYPE_UINT16,  uint16_t, uint16)          \
-    macro_(ScalarTypeDescr::TYPE_INT32,   int32_t,  int32)           \
-    macro_(ScalarTypeDescr::TYPE_UINT32,  uint32_t, uint32)          \
-    macro_(ScalarTypeDescr::TYPE_FLOAT32, float,    float32)         \
-    macro_(ScalarTypeDescr::TYPE_FLOAT64, double,   float64)
-
-// Must be in same order as the enum ScalarTypeDescr::Type:
-#define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_)                                    \
-    JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                           \
-    macro_(ScalarTypeDescr::TYPE_UINT8_CLAMPED, uint8_t, uint8Clamped)
-
-// Type for reference type constructors like `Any`, `String`, and
-// `Object`. All such type constructors share a common js::Class and
-// JSFunctionSpec. All these types are opaque.
-class ReferenceTypeDescr : public SimpleTypeDescr
-{
-  public:
-    // Must match order of JS_FOR_EACH_REFERENCE_TYPE_REPR below
-    enum Type {
-        TYPE_ANY = JS_REFERENCETYPEREPR_ANY,
-        TYPE_OBJECT = JS_REFERENCETYPEREPR_OBJECT,
-        TYPE_STRING = JS_REFERENCETYPEREPR_STRING,
-    };
-    static const int32_t TYPE_MAX = TYPE_STRING + 1;
-    static const char *typeName(Type type);
-
-    static const Class class_;
-    static const JSFunctionSpec typeObjectMethods[];
-    typedef ReferenceTypeRepresentation TypeRepr;
-
-    ReferenceTypeDescr::Type type() const {
-        return (ReferenceTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
-    }
-
-    static bool call(JSContext *cx, unsigned argc, Value *vp);
-};
-
-#define JS_FOR_EACH_REFERENCE_TYPE_REPR(macro_)                    \
-    macro_(ReferenceTypeDescr::TYPE_ANY,    HeapValue, Any)        \
-    macro_(ReferenceTypeDescr::TYPE_OBJECT, HeapPtrObject, Object) \
-    macro_(ReferenceTypeDescr::TYPE_STRING, HeapPtrString, string)
-
-/*
- * Type descriptors `float32x4` and `int32x4`
- */
-class X4TypeDescr : public SizedTypeDescr
-{
-  public:
-    enum Type {
-        TYPE_INT32 = JS_X4TYPEREPR_INT32,
-        TYPE_FLOAT32 = JS_X4TYPEREPR_FLOAT32,
-    };
-
-    static const Class class_;
-    typedef X4TypeRepresentation TypeRepr;
-
-    X4TypeDescr::Type type() const {
-        return (X4TypeDescr::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_X4_TYPE_REPR(macro_)                             \
-    macro_(X4TypeDescr::TYPE_INT32, int32_t, int32)                  \
-    macro_(X4TypeDescr::TYPE_FLOAT32, float, float32)
-
 /*
  * Properties and methods of the `ArrayType` meta type object. There
  * is no `class_` field because `ArrayType` is just a native
  * constructor function.
  */
 class ArrayMetaTypeDescr : public JSObject
 {
   private:
@@ -747,25 +566,25 @@ extern const JSJitInfo MemcpyJitInfo;
  * to access them; eventually this should be linked into the module
  * system.
  */
 bool GetTypedObjectModule(JSContext *cx, unsigned argc, Value *vp);
 
 /*
  * Usage: GetFloat32x4TypeDescr()
  *
- * Returns the float32x4 type object. SIMD pseudo-module must have 
+ * 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: GetInt32x4TypeDescr()
  *
- * Returns the int32x4 type object. SIMD pseudo-module must have 
+ * 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);
 
 /*
  * Usage: Store_int8(targetDatum, targetOffset, value)
  *        ...
  *        Store_uint8(targetDatum, targetOffset, value)
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/TypedObjectSimple.cpp
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "builtin/TypedObjectSimple.h"
+
+using mozilla::DebugOnly;
+
+using namespace js;
+
+/***************************************************************************
+ * Type descriptors
+ */
+
+TypeRepresentation *
+TypeDescr::typeRepresentation() const {
+    return TypeRepresentation::fromOwnerObject(typeRepresentationOwnerObj());
+}
+
+TypeDescr::Kind
+TypeDescr::kind() const {
+    return typeRepresentation()->kind();
+}
+
+/***************************************************************************
+ * Scalar type objects
+ *
+ * Scalar type objects like `uint8`, `uint16`, are all instances of
+ * the ScalarTypeDescr class. Like all type objects, they have a reserved
+ * slot pointing to a TypeRepresentation object, which is used to
+ * distinguish which scalar type object this actually is.
+ */
+
+const Class js::ScalarTypeDescr::class_ = {
+    "Scalar",
+    JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
+    JS_PropertyStub,       /* addProperty */
+    JS_DeletePropertyStub, /* delProperty */
+    JS_PropertyStub,       /* getProperty */
+    JS_StrictPropertyStub, /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    nullptr,
+    ScalarTypeDescr::call,
+    nullptr,
+    nullptr,
+    nullptr
+};
+
+const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
+    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
+    {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
+    {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
+    JS_FS_END
+};
+
+static size_t ScalarSizes[] = {
+#define SCALAR_SIZE(_kind, _type, _name)                        \
+    sizeof(_type),
+    JS_FOR_EACH_SCALAR_TYPE_REPR(SCALAR_SIZE) 0
+#undef SCALAR_SIZE
+};
+
+size_t
+ScalarTypeDescr::size(Type t)
+{
+    return ScalarSizes[t];
+}
+
+size_t
+ScalarTypeDescr::alignment(Type t)
+{
+    return ScalarSizes[t];
+}
+
+/*static*/ const char *
+ScalarTypeDescr::typeName(Type type)
+{
+    switch (type) {
+#define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
+        case constant_: return #name_;
+        JS_FOR_EACH_SCALAR_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
+    }
+    MOZ_ASSUME_UNREACHABLE("Invalid type");
+}
+
+bool
+ScalarTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (args.length() < 1) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
+                             args.callee().getClass()->name, "0", "s");
+        return false;
+    }
+
+    ScalarTypeRepresentation *typeRepr =
+        args.callee().as<ScalarTypeDescr>().typeRepresentation()->asScalar();
+    ScalarTypeDescr::Type type = typeRepr->type();
+
+    double number;
+    if (!ToNumber(cx, args[0], &number))
+        return false;
+
+    if (type == ScalarTypeDescr::TYPE_UINT8_CLAMPED)
+        number = ClampDoubleToUint8(number);
+
+    switch (type) {
+#define SCALARTYPE_CALL(constant_, type_, name_)                             \
+      case constant_: {                                                       \
+          type_ converted = ConvertScalar<type_>(number);                     \
+          args.rval().setNumber((double) converted);                          \
+          return true;                                                        \
+      }
+
+        JS_FOR_EACH_SCALAR_TYPE_REPR(SCALARTYPE_CALL)
+#undef SCALARTYPE_CALL
+
+    }
+    return true;
+}
+
+/***************************************************************************
+ * Reference type objects
+ *
+ * Reference type objects like `Any` or `Object` basically work the
+ * same way that the scalar type objects do. There is one class with
+ * many instances, and each instance has a reserved slot with a
+ * TypeRepresentation object, which is used to distinguish which
+ * reference type object this actually is.
+ */
+
+const Class js::ReferenceTypeDescr::class_ = {
+    "Reference",
+    JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
+    JS_PropertyStub,       /* addProperty */
+    JS_DeletePropertyStub, /* delProperty */
+    JS_PropertyStub,       /* getProperty */
+    JS_StrictPropertyStub, /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    nullptr,
+    ReferenceTypeDescr::call,
+    nullptr,
+    nullptr,
+    nullptr
+};
+
+const JSFunctionSpec js::ReferenceTypeDescr::typeObjectMethods[] = {
+    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
+    {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
+    {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
+    JS_FS_END
+};
+
+/*static*/ const char *
+ReferenceTypeDescr::typeName(Type type)
+{
+    switch (type) {
+#define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
+        case constant_: return #name_;
+        JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
+    }
+    MOZ_ASSUME_UNREACHABLE("Invalid type");
+}
+
+bool
+js::ReferenceTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    JS_ASSERT(args.callee().is<ReferenceTypeDescr>());
+    ReferenceTypeRepresentation *typeRepr =
+        args.callee().as<ReferenceTypeDescr>().typeRepresentation()->asReference();
+
+    if (args.length() < 1) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
+                             JSMSG_MORE_ARGS_NEEDED,
+                             typeRepr->typeName(), "0", "s");
+        return false;
+    }
+
+    switch (typeRepr->type()) {
+      case ReferenceTypeDescr::TYPE_ANY:
+        args.rval().set(args[0]);
+        return true;
+
+      case ReferenceTypeDescr::TYPE_OBJECT:
+      {
+        RootedObject obj(cx, ToObject(cx, args[0]));
+        if (!obj)
+            return false;
+        args.rval().setObject(*obj);
+        return true;
+      }
+
+      case ReferenceTypeDescr::TYPE_STRING:
+      {
+        RootedString obj(cx, ToString<CanGC>(cx, args[0]));
+        if (!obj)
+            return false;
+        args.rval().setString(&*obj);
+        return true;
+      }
+    }
+
+    MOZ_ASSUME_UNREACHABLE("Unhandled Reference type");
+}
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/TypedObjectSimple.h
@@ -0,0 +1,212 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef builtin_TypedObjectSimple_h
+#define builtin_TypedObjectSimple_h
+
+#include "jsobj.h"
+
+#include "builtin/TypedObjectConstants.h"
+
+/*
+ * Simple Typed Objects
+ * --------------------
+ *
+ * Contains definitions for the "simple" type descriptors like scalar
+ * and reference types. These are pulled apart from the rest of the
+ * typed object primarily so that this file can be included from
+ * TypedArrayObject.h, but it also helps to reduce the monolithic
+ * nature of TypedObject.h.
+ */
+
+namespace js {
+
+class TypeRepresentation;
+class ScalarTypeRepresentation;
+class ReferenceTypeRepresentation;
+class X4TypeRepresentation;
+class StructTypeDescr;
+
+/*
+ * Helper method for converting a double into other scalar
+ * types in the same way that JavaScript would. In particular,
+ * simple C casting from double to int32_t gets things wrong
+ * for values like 0xF0000000.
+ */
+template <typename T>
+static T ConvertScalar(double d)
+{
+    if (TypeIsFloatingPoint<T>()) {
+        return T(d);
+    } else if (TypeIsUnsigned<T>()) {
+        uint32_t n = ToUint32(d);
+        return T(n);
+    } else {
+        int32_t n = ToInt32(d);
+        return T(n);
+    }
+}
+
+class TypeDescr : public JSObject
+{
+  public:
+    enum Kind {
+        Scalar = JS_TYPEREPR_SCALAR_KIND,
+        Reference = JS_TYPEREPR_REFERENCE_KIND,
+        X4 = JS_TYPEREPR_X4_KIND,
+        Struct = JS_TYPEREPR_STRUCT_KIND,
+        SizedArray = JS_TYPEREPR_SIZED_ARRAY_KIND,
+        UnsizedArray = JS_TYPEREPR_UNSIZED_ARRAY_KIND,
+    };
+
+    static bool isSized(Kind kind) {
+        return kind > JS_TYPEREPR_MAX_UNSIZED_KIND;
+    }
+
+    JSObject &typeRepresentationOwnerObj() const {
+        return getReservedSlot(JS_DESCR_SLOT_TYPE_REPR).toObject();
+    }
+
+    TypeRepresentation *typeRepresentation() const;
+
+    TypeDescr::Kind kind() const;
+};
+
+typedef Handle<TypeDescr*> HandleTypeDescr;
+
+class SizedTypeDescr : public TypeDescr
+{
+  public:
+    size_t size() {
+        return getReservedSlot(JS_DESCR_SLOT_SIZE).toInt32();
+    }
+};
+
+typedef Handle<SizedTypeDescr*> HandleSizedTypeDescr;
+
+class SimpleTypeDescr : public SizedTypeDescr
+{
+};
+
+// Type for scalar type constructors like `uint8`. All such type
+// constructors share a common js::Class and JSFunctionSpec. Scalar
+// types are non-opaque (their storage is visible unless combined with
+// an opaque reference type.)
+class ScalarTypeDescr : public SimpleTypeDescr
+{
+  public:
+    // Must match order of JS_FOR_EACH_SCALAR_TYPE_REPR below
+    enum Type {
+        TYPE_INT8 = JS_SCALARTYPEREPR_INT8,
+        TYPE_UINT8 = JS_SCALARTYPEREPR_UINT8,
+        TYPE_INT16 = JS_SCALARTYPEREPR_INT16,
+        TYPE_UINT16 = JS_SCALARTYPEREPR_UINT16,
+        TYPE_INT32 = JS_SCALARTYPEREPR_INT32,
+        TYPE_UINT32 = JS_SCALARTYPEREPR_UINT32,
+        TYPE_FLOAT32 = JS_SCALARTYPEREPR_FLOAT32,
+        TYPE_FLOAT64 = JS_SCALARTYPEREPR_FLOAT64,
+
+        /*
+         * Special type that's a uint8_t, but assignments are clamped to 0 .. 255.
+         * Treat the raw data type as a uint8_t.
+         */
+        TYPE_UINT8_CLAMPED = JS_SCALARTYPEREPR_UINT8_CLAMPED,
+    };
+    static const int32_t TYPE_MAX = TYPE_UINT8_CLAMPED + 1;
+
+    static size_t size(Type t);
+    static size_t alignment(Type t);
+    static const char *typeName(Type type);
+
+    static const Class class_;
+    static const JSFunctionSpec typeObjectMethods[];
+    typedef ScalarTypeRepresentation TypeRepr;
+
+    ScalarTypeDescr::Type type() const {
+        return (ScalarTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
+    }
+
+    static bool call(JSContext *cx, unsigned argc, Value *vp);
+};
+
+// Enumerates the cases of ScalarTypeDescr::Type which have
+// unique C representation. In particular, omits Uint8Clamped since it
+// is just a Uint8.
+#define JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                     \
+    macro_(ScalarTypeDescr::TYPE_INT8,    int8_t,   int8)            \
+    macro_(ScalarTypeDescr::TYPE_UINT8,   uint8_t,  uint8)           \
+    macro_(ScalarTypeDescr::TYPE_INT16,   int16_t,  int16)           \
+    macro_(ScalarTypeDescr::TYPE_UINT16,  uint16_t, uint16)          \
+    macro_(ScalarTypeDescr::TYPE_INT32,   int32_t,  int32)           \
+    macro_(ScalarTypeDescr::TYPE_UINT32,  uint32_t, uint32)          \
+    macro_(ScalarTypeDescr::TYPE_FLOAT32, float,    float32)         \
+    macro_(ScalarTypeDescr::TYPE_FLOAT64, double,   float64)
+
+// Must be in same order as the enum ScalarTypeDescr::Type:
+#define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_)                                    \
+    JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                           \
+    macro_(ScalarTypeDescr::TYPE_UINT8_CLAMPED, uint8_t, uint8Clamped)
+
+// Type for reference type constructors like `Any`, `String`, and
+// `Object`. All such type constructors share a common js::Class and
+// JSFunctionSpec. All these types are opaque.
+class ReferenceTypeDescr : public SimpleTypeDescr
+{
+  public:
+    // Must match order of JS_FOR_EACH_REFERENCE_TYPE_REPR below
+    enum Type {
+        TYPE_ANY = JS_REFERENCETYPEREPR_ANY,
+        TYPE_OBJECT = JS_REFERENCETYPEREPR_OBJECT,
+        TYPE_STRING = JS_REFERENCETYPEREPR_STRING,
+    };
+    static const int32_t TYPE_MAX = TYPE_STRING + 1;
+    static const char *typeName(Type type);
+
+    static const Class class_;
+    static const JSFunctionSpec typeObjectMethods[];
+    typedef ReferenceTypeRepresentation TypeRepr;
+
+    ReferenceTypeDescr::Type type() const {
+        return (ReferenceTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
+    }
+
+    static bool call(JSContext *cx, unsigned argc, Value *vp);
+};
+
+#define JS_FOR_EACH_REFERENCE_TYPE_REPR(macro_)                    \
+    macro_(ReferenceTypeDescr::TYPE_ANY,    HeapValue, Any)        \
+    macro_(ReferenceTypeDescr::TYPE_OBJECT, HeapPtrObject, Object) \
+    macro_(ReferenceTypeDescr::TYPE_STRING, HeapPtrString, string)
+
+/*
+ * Type descriptors `float32x4` and `int32x4`
+ */
+class X4TypeDescr : public SizedTypeDescr
+{
+  public:
+    enum Type {
+        TYPE_INT32 = JS_X4TYPEREPR_INT32,
+        TYPE_FLOAT32 = JS_X4TYPEREPR_FLOAT32,
+    };
+
+    static const Class class_;
+    typedef X4TypeRepresentation TypeRepr;
+
+    X4TypeDescr::Type type() const {
+        return (X4TypeDescr::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_X4_TYPE_REPR(macro_)                             \
+    macro_(X4TypeDescr::TYPE_INT32, int32_t, int32)                  \
+    macro_(X4TypeDescr::TYPE_FLOAT32, float, float32)
+
+} // namespace js
+
+#endif
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -95,16 +95,17 @@ UNIFIED_SOURCES += [
     'builtin/Eval.cpp',
     'builtin/Intl.cpp',
     'builtin/MapObject.cpp',
     'builtin/Object.cpp',
     'builtin/Profilers.cpp',
     'builtin/SIMD.cpp',
     'builtin/TestingFunctions.cpp',
     'builtin/TypedObject.cpp',
+    'builtin/TypedObjectSimple.cpp',
     'builtin/TypeRepresentation.cpp',
     'devtools/sharkctl.cpp',
     'ds/LifoAlloc.cpp',
     'frontend/BytecodeCompiler.cpp',
     'frontend/BytecodeEmitter.cpp',
     'frontend/FoldConstants.cpp',
     'frontend/NameFunctions.cpp',
     'frontend/ParseMaps.cpp',
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef vm_TypedArrayObject_h
 #define vm_TypedArrayObject_h
 
 #include "jsobj.h"
 
-#include "builtin/TypedObject.h"
+#include "builtin/TypedObjectSimple.h"
 #include "gc/Barrier.h"
 #include "js/Class.h"
 
 typedef struct JSProperty JSProperty;
 
 namespace js {
 
 typedef Vector<ArrayBufferObject *, 0, SystemAllocPolicy> ArrayBufferVector;