Bug 914220 - Move TypedObject global names into a TypedObject module r=waldo
authorNicholas D. Matsakis <nmatsakis@mozilla.com>
Mon, 09 Sep 2013 11:52:11 -0400
changeset 150945 89600e65912368d6bf02974029b7bec611e8ee3b
parent 150944 e2c492172295ca050b275c2370a97f13b6320337
child 150946 1406ff031c196382bed11fe810d48f746daa3858
push id35014
push usernmatsakis@mozilla.com
push dateWed, 16 Oct 2013 13:29:25 +0000
treeherdermozilla-inbound@89600e659123 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswaldo
bugs914220
milestone27.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 914220 - Move TypedObject global names into a TypedObject module r=waldo
dom/tests/mochitest/general/test_interfaces.html
js/public/Class.h
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/jit-test/tests/TypedObject/fuzz1.js
js/src/jit-test/tests/TypedObject/fuzz10.js
js/src/jit-test/tests/TypedObject/fuzz11.js
js/src/jit-test/tests/TypedObject/fuzz2.js
js/src/jit-test/tests/TypedObject/fuzz3.js
js/src/jit-test/tests/TypedObject/fuzz4.js
js/src/jit-test/tests/TypedObject/fuzz5.js
js/src/jit-test/tests/TypedObject/fuzz6.js
js/src/jit-test/tests/TypedObject/fuzz7.js
js/src/jit-test/tests/TypedObject/fuzz8.js
js/src/jit-test/tests/TypedObject/fuzz9.js
js/src/jit-test/tests/TypedObject/jit-complex.js
js/src/jit-test/tests/TypedObject/jit-prefix.js
js/src/jit-test/tests/TypedObject/jit-read-float64.js
js/src/jit-test/tests/TypedObject/jit-read-int.js
js/src/jsapi.cpp
js/src/jsprototypes.h
js/src/tests/ecma_6/TypedObject/architecture.js
js/src/tests/ecma_6/TypedObject/arrayofstructs.js
js/src/tests/ecma_6/TypedObject/arraytype.js
js/src/tests/ecma_6/TypedObject/memory.js
js/src/tests/ecma_6/TypedObject/numerictypes.js
js/src/tests/ecma_6/TypedObject/size_and_alignment.js
js/src/tests/ecma_6/TypedObject/structequiv.js
js/src/tests/ecma_6/TypedObject/structtypeenumerate.js
js/src/tests/ecma_6/TypedObject/structtypeindexedfields.js
js/src/tests/ecma_6/TypedObject/structtypeprototype.js
js/src/tests/ecma_6/TypedObject/structtypereflection.js
js/src/tests/ecma_6/TypedObject/structtypestructuralassign.js
js/src/vm/CommonPropertyNames.h
js/src/vm/GlobalObject.h
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -23,21 +23,19 @@ https://bugzilla.mozilla.org/show_bug.cg
 // This is a list of all interfaces that are exposed to every webpage.  Please only
 // add things to this list with great care.
 
 // IMPORTANT: Do not change this list without review from a JavaScript Engine peer!
 var ecmaGlobals =
   [
     "Array",
     "ArrayBuffer",
-    {name: "ArrayType", nightly: true},
     "Boolean",
     "DataView",
     "Date",
-    {name: "Data", nightly: true},
     "Error",
     "EvalError",
     "Float32Array",
     "Float64Array",
     "Function",
     "Infinity",
     "Int16Array",
     "Int32Array",
@@ -54,19 +52,18 @@ var ecmaGlobals =
     {name: "ParallelArray", nightly: true},
     "Proxy",
     "RangeError",
     "ReferenceError",
     "RegExp",
     "Set",
     "StopIteration",
     "String",
-    {name: "StructType", nightly: true},
     "SyntaxError",
-    {name: "Type", nightly: true},
+    {name: "TypedObject", nightly: true},
     "TypeError",
     "Uint16Array",
     "Uint32Array",
     "Uint8Array",
     "Uint8ClampedArray",
     "URIError",
     "WeakMap",
   ];
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -555,17 +555,17 @@ struct JSClass {
 // member initial value.  The "original ... value" verbiage is there because
 // in ECMA-262, global properties naming class objects are read/write and
 // deleteable, for the most part.
 //
 // 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.
 //
-#define JSCLASS_GLOBAL_SLOT_COUNT      (3 + JSProto_LIMIT * 3 + 26)
+#define JSCLASS_GLOBAL_SLOT_COUNT      (3 + JSProto_LIMIT * 3 + 27)
 #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/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -24,16 +24,28 @@
 #include "jsobjinlines.h"
 
 #include "vm/Shape-inl.h"
 
 using mozilla::DebugOnly;
 
 using namespace js;
 
+const Class js::TypedObjectClass = {
+    "TypedObject",
+    JSCLASS_HAS_CACHED_PROTO(JSProto_TypedObject),
+    JS_PropertyStub,         /* addProperty */
+    JS_DeletePropertyStub,   /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub,   /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub
+};
+
 /*
  * Reify() converts a binary value into a JS Object.
  *
  * The type of the value to be converted is described by `typeRepr`,
  * and `type` is an associated type descriptor object with that
  * same representation (note that there may be many descriptors
  * that all share the same `typeRepr`).
  *
@@ -48,28 +60,16 @@ static bool Reify(JSContext *cx, TypeRep
 /*
  * ConvertAndCopyTo() converts `from` to type `type` and stores the result in
  * `mem`, which MUST be pre-allocated to the appropriate size for instances of
  * `type`.
  */
 static bool ConvertAndCopyTo(JSContext *cx, TypeRepresentation *typeRepr,
                              HandleValue from, uint8_t *mem);
 
-static bool
-TypeThrowError(JSContext *cx, unsigned argc, Value *vp)
-{
-    return ReportIsNotFunction(cx, *vp);
-}
-
-static bool
-DataThrowError(JSContext *cx, unsigned argc, Value *vp)
-{
-    return ReportIsNotFunction(cx, *vp);
-}
-
 static void
 ReportCannotConvertTo(JSContext *cx, HandleValue fromValue, const char *toType)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
                          InformalValueTypeName(fromValue), toType);
 }
 
 static void
@@ -234,39 +234,21 @@ IsBlockOfKind(JSContext *cx, HandleObjec
 }
 
 static inline bool
 IsBinaryArray(JSContext *cx, HandleObject obj)
 {
     return IsBlockOfKind(cx, obj, TypeRepresentation::Array);
 }
 
-const Class js::DataClass = {
-    "Data",
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Data),
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
-};
-
-const Class js::TypeClass = {
-    "Type",
-    JSCLASS_HAS_CACHED_PROTO(JSProto_Type),
-    JS_PropertyStub,
-    JS_DeletePropertyStub,
-    JS_PropertyStub,
-    JS_StrictPropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub
-};
+static inline bool
+IsBinaryStruct(JSContext *cx, HandleObject obj)
+{
+    return IsBlockOfKind(cx, obj, TypeRepresentation::Struct);
+}
 
 static bool
 TypeEquivalent(JSContext *cx, unsigned int argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     RootedObject thisObj(cx, ToObjectIfObject(args.thisv()));
     if (!thisObj || !IsBinaryType(thisObj)) {
@@ -293,18 +275,17 @@ TypeEquivalent(JSContext *cx, unsigned i
     TypeRepresentation *otherRepr = typeRepresentation(otherObj);
     args.rval().setBoolean(thisRepr == otherRepr);
     return true;
 }
 
 #define BINARYDATA_NUMERIC_CLASSES(constant_, type_, name_)                   \
 {                                                                             \
     #name_,                                                                   \
-    JSCLASS_HAS_RESERVED_SLOTS(1) |                                           \
-    JSCLASS_HAS_CACHED_PROTO(JSProto_##name_),                                \
+    JSCLASS_HAS_RESERVED_SLOTS(TYPE_RESERVED_SLOTS),                          \
     JS_PropertyStub,       /* addProperty */                                  \
     JS_DeletePropertyStub, /* delProperty */                                  \
     JS_PropertyStub,       /* getProperty */                                  \
     JS_StrictPropertyStub, /* setProperty */                                  \
     JS_EnumerateStub,                                                         \
     JS_ResolveStub,                                                           \
     JS_ConvertStub,                                                           \
     nullptr,                                                                  \
@@ -380,18 +361,30 @@ NumericType<ScalarTypeRepresentation::TY
     } else {
         if (!ToDoubleForTypedArray(cx, val, &d))
             return false;
     }
     *converted = ClampDoubleToUint8(d);
     return true;
 }
 
+} // namespace js
 
-} // namespace js
+template<ScalarTypeRepresentation::Type N>
+static bool
+NumericTypeToString(JSContext *cx, unsigned int argc, Value *vp)
+{
+    static_assert(N < ScalarTypeRepresentation::TYPE_MAX, "bad numeric type");
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSString *s = JS_NewStringCopyZ(cx, ScalarTypeRepresentation::typeName(N));
+    if (!s)
+        return false;
+    args.rval().setString(s);
+    return true;
+}
 
 static bool
 ConvertAndCopyScalarTo(JSContext *cx, ScalarTypeRepresentation *typeRepr,
                        HandleValue from, uint8_t *mem)
 {
 #define CONVERT_CASES(constant_, type_, name_)                                \
     case constant_: {                                                         \
         type_ temp;                                                           \
@@ -447,93 +440,176 @@ NumericType<type, T>::call(JSContext *cx
     if (!NumericType<type, T>::reify(cx, &answer, &reified)) {
         return false;
     }
 
     args.rval().set(reified);
     return true;
 }
 
-template<ScalarTypeRepresentation::Type N>
-bool
-NumericTypeToString(JSContext *cx, unsigned int argc, Value *vp)
-{
-    JS_STATIC_ASSERT(N < ScalarTypeRepresentation::TYPE_MAX);
-    CallArgs args = CallArgsFromVp(argc, vp);
-    JSString *s = JS_NewStringCopyZ(cx, ScalarTypeRepresentation::typeName(N));
-    if (!s)
-        return false;
-    args.rval().set(StringValue(s));
-    return true;
-}
-
 /*
- * When creating:
- *   var A = new ArrayType(uint8, 10)
- * or
- *   var S = new StructType({...})
+ * For code like:
+ *
+ *   var A = new TypedObject.ArrayType(uint8, 10);
+ *   var S = new TypedObject.StructType({...});
+ *
+ * As usual, the [[Prototype]] of A is
+ * TypedObject.ArrayType.prototype.  This permits adding methods to
+ * all ArrayType types, by setting
+ * TypedObject.ArrayType.prototype.methodName = function() { ... }.
+ * The same holds for S with respect to TypedObject.StructType.
+ *
+ * We may also want to add methods to *instances* of an ArrayType:
+ *
+ *   var a = new A();
+ *   var s = new S();
  *
- * A.prototype.__proto__ === ArrayType.prototype.prototype (and similar for
- * StructType).
+ * As usual, the [[Prototype]] of a is A.prototype.  What's
+ * A.prototype?  It's an empty object, and you can set
+ * A.prototype.methodName = function() { ... } to add a method to all
+ * A instances.  (And the same with respect to s and S.)
  *
- * This function takes a reference to either ArrayType or StructType and
- * returns a JSObject which can be set as A.prototype.
+ * But what if you want to add a method to all ArrayType instances,
+ * not just all A instances?  (Or to all StructType instances.)  The
+ * [[Prototype]] of the A.prototype empty object is
+ * TypedObject.ArrayType.prototype.prototype (two .prototype levels!).
+ * So just set TypedObject.ArrayType.prototype.prototype.methodName =
+ * function() { ... } to add a method to all ArrayType instances.
+ * (And, again, same with respect to s and S.)
+ *
+ * This function creates the A.prototype/S.prototype object.  It takes
+ * as an argument either the TypedObject.ArrayType or the
+ * TypedObject.StructType constructor function, then returns an empty
+ * object with the .prototype.prototype object as its [[Prototype]].
  */
 static JSObject *
-SetupAndGetPrototypeObjectForComplexTypeInstance(JSContext *cx,
-                                                 HandleObject complexTypeGlobal)
+CreateComplexTypeInstancePrototype(JSContext *cx,
+                                   HandleObject typeObjectCtor)
 {
-    RootedObject global(cx, cx->compartment()->maybeGlobal());
-    RootedValue complexTypePrototypeVal(cx);
-    RootedValue complexTypePrototypePrototypeVal(cx);
+    RootedValue ctorPrototypeVal(cx);
+    if (!JSObject::getProperty(cx, typeObjectCtor, typeObjectCtor,
+                               cx->names().prototype,
+                               &ctorPrototypeVal))
+    {
+        return nullptr;
+    }
+    JS_ASSERT(ctorPrototypeVal.isObject()); // immutable binding
+    RootedObject ctorPrototypeObj(cx, &ctorPrototypeVal.toObject());
+
+    RootedValue ctorPrototypePrototypeVal(cx);
+    if (!JSObject::getProperty(cx, ctorPrototypeObj, ctorPrototypeObj,
+                               cx->names().prototype,
+                               &ctorPrototypePrototypeVal))
+    {
+        return nullptr;
+    }
 
-    if (!JSObject::getProperty(cx, complexTypeGlobal, complexTypeGlobal,
-                               cx->names().prototype, &complexTypePrototypeVal))
+    JS_ASSERT(ctorPrototypePrototypeVal.isObject()); // immutable binding
+    RootedObject proto(cx, &ctorPrototypePrototypeVal.toObject());
+    return NewObjectWithGivenProto(cx, &JSObject::class_, proto,
+                                   &typeObjectCtor->global());
+}
+
+template<typename T>
+static JSObject *
+CreateMetaTypeObject(JSContext *cx,
+                     Handle<GlobalObject*> global)
+{
+    RootedAtom className(cx, Atomize(cx, T::class_.name,
+                                     strlen(T::class_.name)));
+    if (!className)
+        return nullptr;
+
+    RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
+    if (!funcProto)
         return nullptr;
 
-    JS_ASSERT(complexTypePrototypeVal.isObject()); // immutable binding
-    RootedObject complexTypePrototypeObj(cx,
-        &complexTypePrototypeVal.toObject());
+    // Create ctor.prototype, which inherits from Function.prototype
+
+    RootedObject proto(
+        cx, NewObjectWithGivenProto(cx, &JSObject::class_, funcProto,
+                                    global, SingletonObject));
+    if (!proto)
+        return nullptr;
 
-    if (!JSObject::getProperty(cx, complexTypePrototypeObj,
-                               complexTypePrototypeObj,
-                               cx->names().prototype,
-                               &complexTypePrototypePrototypeVal))
+    // Create ctor.prototype.prototype, which inherits from Object.__proto__
+
+    RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
+    if (!objProto)
+        return nullptr;
+    RootedObject protoProto(
+        cx, NewObjectWithGivenProto(cx, &JSObject::class_, objProto,
+                                    global, SingletonObject));
+    if (!proto)
         return nullptr;
 
-    RootedObject prototypeObj(cx,
-        NewObjectWithGivenProto(cx, &JSObject::class_, nullptr, global));
-
-    JS_ASSERT(complexTypePrototypePrototypeVal.isObject()); // immutable binding
-    RootedObject proto(cx, &complexTypePrototypePrototypeVal.toObject());
-    if (!JS_SetPrototype(cx, prototypeObj, proto))
+    RootedValue protoProtoValue(cx, ObjectValue(*protoProto));
+    if (!JSObject::defineProperty(cx, proto, cx->names().prototype,
+                                  protoProtoValue,
+                                  nullptr, nullptr,
+                                  JSPROP_READONLY | JSPROP_PERMANENT))
         return nullptr;
 
-    return prototypeObj;
+    // Create ctor itself
+
+    RootedFunction ctor(
+        cx, global->createConstructor(cx, T::construct, className, 2));
+    if (!ctor ||
+        !LinkConstructorAndPrototype(cx, ctor, proto) ||
+        !DefinePropertiesAndBrand(cx, proto,
+                                  T::typeObjectProperties,
+                                  T::typeObjectMethods) ||
+        !DefinePropertiesAndBrand(cx, protoProto,
+                                  T::typedObjectProperties,
+                                  T::typedObjectMethods))
+    {
+        return nullptr;
+    }
+
+    return ctor;
 }
 
 const Class ArrayType::class_ = {
     "ArrayType",
-    JSCLASS_HAS_RESERVED_SLOTS(ARRAY_TYPE_RESERVED_SLOTS) |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayType),
+    JSCLASS_HAS_RESERVED_SLOTS(ARRAY_TYPE_RESERVED_SLOTS),
     JS_PropertyStub,
     JS_DeletePropertyStub,
     JS_PropertyStub,
     JS_StrictPropertyStub,
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     nullptr,
     nullptr,
     nullptr,
     nullptr,
     BinaryBlock::construct,
     nullptr
 };
 
+const JSPropertySpec ArrayType::typeObjectProperties[] = {
+    JS_PS_END
+};
+
+const JSFunctionSpec ArrayType::typeObjectMethods[] = {
+    JS_FN("repeat", ArrayType::repeat, 1, 0),
+    JS_FN("toSource", ArrayType::toSource, 0, 0),
+    JS_FS_END
+};
+
+const JSPropertySpec ArrayType::typedObjectProperties[] = {
+    JS_PS_END
+};
+
+const JSFunctionSpec ArrayType::typedObjectMethods[] = {
+    JS_FN("subarray", ArrayType::subarray, 2, 0),
+    {"forEach", {nullptr, nullptr}, 1, 0, "ArrayForEach"},
+    JS_FS_END
+};
+
 static JSObject *
 ArrayElementType(HandleObject array)
 {
     JS_ASSERT(IsArrayType(array));
     return &array->getFixedSlot(SLOT_ARRAY_ELEM_TYPE).toObject();
 }
 
 static bool
@@ -592,45 +668,16 @@ ConvertAndCopyArrayTo(JSContext *cx, Arr
 
         p += elementType->size();
     }
 
     return true;
 }
 
 static bool
-DataInstanceUpdate(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,
-                             "update()", "0", "s");
-        return false;
-    }
-
-    RootedObject thisObj(cx, ToObjectIfObject(args.thisv()));
-    if (!thisObj || !IsBlock(thisObj)) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
-                             JSMSG_INCOMPATIBLE_PROTO,
-                             "Data", "update",
-                             InformalValueTypeName(args.thisv()));
-        return false;
-    }
-
-    RootedValue val(cx, args[0]);
-    if (!ConvertAndCopyTo(cx, val, thisObj))
-        return false;
-
-    args.rval().setUndefined();
-    return true;
-}
-
-static bool
 FillBinaryArrayWithValue(JSContext *cx, HandleObject array, HandleValue val)
 {
     JS_ASSERT(IsBinaryArray(cx, array));
 
     // set array[0] = [[Convert]](val)
     RootedObject type(cx, GetType(array));
     ArrayTypeRepresentation *typeRepr = typeRepresentation(type)->asArray();
     uint8_t *base = BlockMem(array);
@@ -642,18 +689,18 @@ FillBinaryArrayWithValue(JSContext *cx, 
     for (size_t i = 1; i < typeRepr->length(); i++) {
         uint8_t *dest = base + elementSize * i;
         memcpy(dest, base, elementSize);
     }
 
     return true;
 }
 
-static bool
-ArrayRepeat(JSContext *cx, unsigned int argc, Value *vp)
+bool
+ArrayType::repeat(JSContext *cx, unsigned int argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() < 1) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage,
                              nullptr, JSMSG_MORE_ARGS_NEEDED,
                              "repeat()", "0", "s");
         return false;
@@ -721,18 +768,18 @@ ArrayType::toSource(JSContext *cx, unsig
  *     return ret
  *
  * The range specified by the begin and end values is clamped to the valid
  * index range for the current array. If the computed length of the new
  * TypedArray would be negative, it is clamped to zero.
  * see: http://www.khronos.org/registry/typedarray/specs/latest/#7
  *
  */
-static bool
-ArraySubarray(JSContext *cx, unsigned int argc, Value *vp)
+/* static */ bool
+ArrayType::subarray(JSContext *cx, unsigned int argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() < 1) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage,
                              nullptr, JSMSG_MORE_ARGS_NEEDED,
                              "subarray()", "0", "s");
         return false;
@@ -776,17 +823,17 @@ ArraySubarray(JSContext *cx, unsigned in
     end = Clamp(end, 0, length);
 
     int32_t sublength = end - begin; // end exclusive
     sublength = Clamp(sublength, 0, length);
 
     RootedObject globalObj(cx, cx->compartment()->maybeGlobal());
     JS_ASSERT(globalObj);
     Rooted<GlobalObject*> global(cx, &globalObj->as<GlobalObject>());
-    RootedObject arrayTypeGlobal(cx, global->getOrCreateArrayTypeObject(cx));
+    RootedObject arrayTypeGlobal(cx, global->getArrayType(cx));
 
     RootedObject elementType(cx, ArrayElementType(type));
     RootedObject subArrayType(cx, ArrayType::create(cx, arrayTypeGlobal,
                                                     elementType, sublength));
     if (!subArrayType)
         return false;
 
     int32_t elementSize = typeRepr->element()->size();
@@ -824,76 +871,101 @@ ArrayFillSubarray(JSContext *cx, unsigne
     Value funArrayTypeVal = GetFunctionNativeReserved(&args.callee(), 0);
     JS_ASSERT(funArrayTypeVal.isObject());
 
     RootedObject type(cx, GetType(thisObj));
     TypeRepresentation *typeRepr = typeRepresentation(type);
     RootedObject funArrayType(cx, &funArrayTypeVal.toObject());
     TypeRepresentation *funArrayTypeRepr = typeRepresentation(funArrayType);
     if (typeRepr != funArrayTypeRepr) {
-        RootedValue thisObjVal(cx, ObjectValue(*thisObj));
-        ReportCannotConvertTo(cx, thisObjVal, funArrayTypeRepr);
+        RootedValue thisObjValue(cx, ObjectValue(*thisObj));
+        ReportCannotConvertTo(cx, thisObjValue, funArrayTypeRepr);
         return false;
     }
 
     args.rval().setUndefined();
     RootedValue val(cx, args[0]);
     return FillBinaryArrayWithValue(cx, thisObj, val);
 }
 
 static bool
 InitializeCommonTypeDescriptorProperties(JSContext *cx,
                                          HandleObject obj,
                                          HandleObject typeReprOwnerObj)
 {
     TypeRepresentation *typeRepr =
         TypeRepresentation::fromOwnerObject(typeReprOwnerObj);
 
+    // equivalent()
+    if (!JS_DefineFunction(cx, obj, "equivalent",
+                           TypeEquivalent, 1, 0))
+    {
+        return false;
+    }
+
     // byteLength
     RootedValue typeByteLength(cx, NumberValue(typeRepr->size()));
     if (!JSObject::defineProperty(cx, obj, cx->names().byteLength,
                                   typeByteLength,
                                   nullptr, nullptr,
                                   JSPROP_READONLY | JSPROP_PERMANENT))
+    {
         return false;
+    }
 
     // byteAlignment
     RootedValue typeByteAlignment(cx, NumberValue(typeRepr->alignment()));
     if (!JSObject::defineProperty(cx, obj, cx->names().byteAlignment,
                                   typeByteAlignment,
                                   nullptr, nullptr,
                                   JSPROP_READONLY | JSPROP_PERMANENT))
+    {
         return false;
+    }
 
     // variable -- always false since we do not yet support variable-size types
     RootedValue variable(cx, JSVAL_FALSE);
     if (!JSObject::defineProperty(cx, obj, cx->names().variable,
                                   variable,
                                   nullptr, nullptr,
                                   JSPROP_READONLY | JSPROP_PERMANENT))
+    {
         return false;
+    }
 
     return true;
 }
 
 JSObject *
-ArrayType::create(JSContext *cx, HandleObject arrayTypeGlobal,
-                  HandleObject elementType, size_t length)
+ArrayType::create(JSContext *cx,
+                  HandleObject metaTypeObject,
+                  HandleObject elementType,
+                  size_t length)
 {
     JS_ASSERT(elementType);
     JS_ASSERT(IsBinaryType(elementType));
 
     TypeRepresentation *elementTypeRepr = typeRepresentation(elementType);
     RootedObject typeReprObj(
-        cx,
-        ArrayTypeRepresentation::Create(cx, elementTypeRepr, length));
+        cx, ArrayTypeRepresentation::Create(cx, elementTypeRepr, length));
     if (!typeReprObj)
         return nullptr;
 
-    RootedObject obj(cx, NewBuiltinClassInstance(cx, &ArrayType::class_));
+    RootedValue prototypeVal(cx);
+    if (!JSObject::getProperty(cx, metaTypeObject, metaTypeObject,
+                               cx->names().prototype,
+                               &prototypeVal))
+    {
+        return nullptr;
+    }
+    JS_ASSERT(prototypeVal.isObject()); // immutable binding
+
+    RootedObject obj(
+        cx, NewObjectWithClassProto(cx, &ArrayType::class_,
+                                    &prototypeVal.toObject(), cx->global()));
     if (!obj)
         return nullptr;
     obj->initFixedSlot(SLOT_TYPE_REPR, ObjectValue(*typeReprObj));
 
     RootedValue elementTypeVal(cx, ObjectValue(*elementType));
     if (!JSObject::defineProperty(cx, obj, cx->names().elementType,
                                   elementTypeVal, nullptr, nullptr,
                                   JSPROP_READONLY | JSPROP_PERMANENT))
@@ -905,19 +977,18 @@ ArrayType::create(JSContext *cx, HandleO
     if (!JSObject::defineProperty(cx, obj, cx->names().length,
                                   lengthVal, nullptr, nullptr,
                                   JSPROP_READONLY | JSPROP_PERMANENT))
         return nullptr;
 
     if (!InitializeCommonTypeDescriptorProperties(cx, obj, typeReprObj))
         return nullptr;
 
-    RootedObject prototypeObj(cx,
-        SetupAndGetPrototypeObjectForComplexTypeInstance(cx, arrayTypeGlobal));
-
+    RootedObject prototypeObj(
+        cx, CreateComplexTypeInstancePrototype(cx, metaTypeObject));
     if (!prototypeObj)
         return nullptr;
 
     if (!LinkConstructorAndPrototype(cx, obj, prototypeObj))
         return nullptr;
 
     JSFunction *fillFun = DefineFunctionWithReserved(cx, prototypeObj, "fill", ArrayFillSubarray, 1, 0);
     if (!fillFun)
@@ -979,36 +1050,53 @@ ArrayType::construct(JSContext *cx, unsi
         return false;
     args.rval().setObject(*obj);
     return true;
 }
 
 /*********************************
  * Structs
  *********************************/
+
 const Class StructType::class_ = {
     "StructType",
     JSCLASS_HAS_RESERVED_SLOTS(STRUCT_TYPE_RESERVED_SLOTS) |
-    JSCLASS_HAS_PRIVATE | // used to store FieldList
-    JSCLASS_HAS_CACHED_PROTO(JSProto_StructType),
+    JSCLASS_HAS_PRIVATE, // used to store FieldList
     JS_PropertyStub,
     JS_DeletePropertyStub,
     JS_PropertyStub,
     JS_StrictPropertyStub,
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     nullptr, /* finalize */
     nullptr, /* checkAccess */
     nullptr, /* call */
     nullptr, /* hasInstance */
     BinaryBlock::construct,
     nullptr  /* trace */
 };
 
+const JSPropertySpec StructType::typeObjectProperties[] = {
+    JS_PS_END
+};
+
+const JSFunctionSpec StructType::typeObjectMethods[] = {
+    JS_FN("toSource", StructType::toSource, 0, 0),
+    JS_FS_END
+};
+
+const JSPropertySpec StructType::typedObjectProperties[] = {
+    JS_PS_END
+};
+
+const JSFunctionSpec StructType::typedObjectMethods[] = {
+    JS_FS_END
+};
+
 static bool
 ConvertAndCopyStructTo(JSContext *cx,
                        StructTypeRepresentation *typeRepr,
                        HandleValue from,
                        uint8_t *mem)
 {
     if (!from.isObject()) {
         ReportCannotConvertTo(cx, from, typeRepr);
@@ -1087,45 +1175,43 @@ StructType::layout(JSContext *cx, Handle
         if (!fieldTypeReprObjs.append(typeRepresentationOwnerObj(fieldType))) {
             js_ReportOutOfMemory(cx);
             return false;
         }
     }
 
     // Construct the `TypeRepresentation*`.
     RootedObject typeReprObj(
-        cx,
-        StructTypeRepresentation::Create(cx, ids, fieldTypeReprObjs));
+        cx, StructTypeRepresentation::Create(cx, ids, fieldTypeReprObjs));
     if (!typeReprObj)
         return false;
     StructTypeRepresentation *typeRepr =
         TypeRepresentation::fromOwnerObject(typeReprObj)->asStruct();
-    structType->initFixedSlot(SLOT_TYPE_REPR, ObjectValue(*typeReprObj));
+    structType->initReservedSlot(SLOT_TYPE_REPR, ObjectValue(*typeReprObj));
 
     // Construct for internal use an array with the type object for each field.
     RootedObject fieldTypeVec(
-        cx,
-        NewDenseCopiedArray(cx, fieldTypeObjs.length(), fieldTypeObjs.begin()));
+        cx, NewDenseCopiedArray(cx, fieldTypeObjs.length(),
+                                fieldTypeObjs.begin()));
     if (!fieldTypeVec)
         return false;
 
     structType->initFixedSlot(SLOT_STRUCT_FIELD_TYPES,
                              ObjectValue(*fieldTypeVec));
 
     // Construct the fieldNames vector
     AutoValueVector fieldNameValues(cx);
     for (unsigned int i = 0; i < ids.length(); i++) {
         RootedValue value(cx, IdToValue(ids[i]));
         if (!fieldNameValues.append(value))
             return false;
     }
     RootedObject fieldNamesVec(
-        cx,
-        NewDenseCopiedArray(cx, fieldNameValues.length(),
-                            fieldNameValues.begin()));
+        cx, NewDenseCopiedArray(cx, fieldNameValues.length(),
+                                fieldNameValues.begin()));
     if (!fieldNamesVec)
         return false;
     RootedValue fieldNamesVecValue(cx, ObjectValue(*fieldNamesVec));
     if (!JSObject::defineProperty(cx, structType, cx->names().fieldNames,
                                   fieldNamesVecValue, nullptr, nullptr,
                                   JSPROP_READONLY | JSPROP_PERMANENT))
         return false;
 
@@ -1147,18 +1233,17 @@ StructType::layout(JSContext *cx, Handle
         RootedValue offset(cx, NumberValue(field.offset));
         if (!JSObject::defineGeneric(cx, fieldOffsets, fieldId,
                                      offset, nullptr, nullptr,
                                      JSPROP_READONLY | JSPROP_PERMANENT))
             return false;
 
         // fieldTypes[id] = typeObj
         if (!JSObject::defineGeneric(cx, fieldTypes, fieldId,
-                                     fieldTypeObjs.handleAt(i),
-                                     nullptr, nullptr,
+                                     fieldTypeObjs.handleAt(i), nullptr, nullptr,
                                      JSPROP_READONLY | JSPROP_PERMANENT))
             return false;
     }
 
     RootedValue fieldOffsetsValue(cx, ObjectValue(*fieldOffsets));
     if (!JSObject::defineProperty(cx, structType, cx->names().fieldOffsets,
                                   fieldOffsetsValue, nullptr, nullptr,
                                   JSPROP_READONLY | JSPROP_PERMANENT))
@@ -1169,37 +1254,45 @@ StructType::layout(JSContext *cx, Handle
                                   fieldTypesValue, nullptr, nullptr,
                                   JSPROP_READONLY | JSPROP_PERMANENT))
         return false;
 
     return true;
 }
 
 JSObject *
-StructType::create(JSContext *cx, HandleObject structTypeGlobal,
+StructType::create(JSContext *cx, HandleObject metaTypeObject,
                    HandleObject fields)
 {
-    RootedObject obj(cx, NewBuiltinClassInstance(cx, &StructType::class_));
+    RootedValue prototypeVal(cx);
+    if (!JSObject::getProperty(cx, metaTypeObject, metaTypeObject,
+                               cx->names().prototype,
+                               &prototypeVal))
+        return nullptr;
+    JS_ASSERT(prototypeVal.isObject()); // immutable binding
+
+    RootedObject obj(
+        cx, NewObjectWithClassProto(cx, &StructType::class_,
+                                    &prototypeVal.toObject(), cx->global()));
     if (!obj)
         return nullptr;
 
     if (!StructType::layout(cx, obj, fields))
         return nullptr;
 
     RootedObject fieldsProto(cx);
     if (!JSObject::getProto(cx, fields, &fieldsProto))
         return nullptr;
 
     RootedObject typeReprObj(cx, typeRepresentationOwnerObj(obj));
     if (!InitializeCommonTypeDescriptorProperties(cx, obj, typeReprObj))
         return nullptr;
 
-    RootedObject prototypeObj(cx,
-        SetupAndGetPrototypeObjectForComplexTypeInstance(cx, structTypeGlobal));
-
+    RootedObject prototypeObj(
+        cx, CreateComplexTypeInstancePrototype(cx, metaTypeObject));
     if (!prototypeObj)
         return nullptr;
 
     if (!LinkConstructorAndPrototype(cx, obj, prototypeObj))
         return nullptr;
 
     return obj;
 }
@@ -1211,19 +1304,19 @@ StructType::construct(JSContext *cx, uns
 
     if (!args.isConstructing()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                              JSMSG_NOT_FUNCTION, "StructType");
         return false;
     }
 
     if (args.length() >= 1 && args[0].isObject()) {
-        RootedObject structTypeGlobal(cx, &args.callee());
+        RootedObject metaTypeObject(cx, &args.callee());
         RootedObject fields(cx, &args[0].toObject());
-        RootedObject obj(cx, create(cx, structTypeGlobal, fields));
+        RootedObject obj(cx, create(cx, metaTypeObject, fields));
         if (!obj)
             return false;
         args.rval().setObject(*obj);
         return true;
     }
 
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                          JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS);
@@ -1300,243 +1393,169 @@ Reify(JSContext *cx, TypeRepresentation 
         return ReifyScalar(cx, typeRepr->asScalar(), type, owner, offset, to);
       case TypeRepresentation::Struct:
       case TypeRepresentation::Array:
         return ReifyComplex(cx, type, owner, offset, to);
     }
     MOZ_ASSUME_UNREACHABLE("Invalid typeRepr kind");
 }
 
-bool
-GlobalObject::initDataObject(JSContext *cx, Handle<GlobalObject *> global)
-{
-    RootedObject DataProto(cx);
-    DataProto = NewObjectWithGivenProto(cx, &DataClass,
-                                        global->getOrCreateObjectPrototype(cx),
-                                        global, SingletonObject);
-    if (!DataProto)
-        return false;
-
-    RootedAtom DataName(cx, ClassName(JSProto_Data, cx));
-    RootedFunction DataCtor(cx,
-            global->createConstructor(cx, DataThrowError, DataName,
-                                      1, JSFunction::ExtendedFinalizeKind));
-
-    if (!DataCtor)
-        return false;
-
-    if (!JS_DefineFunction(cx, DataProto, "update", DataInstanceUpdate, 1, 0))
-        return false;
-
-    if (!LinkConstructorAndPrototype(cx, DataCtor, DataProto))
-        return false;
-
-    if (!DefineConstructorAndPrototype(cx, global, JSProto_Data,
-                                       DataCtor, DataProto))
-        return false;
-
-    global->setConstructor(JSProto_Data, ObjectValue(*DataCtor));
-    return true;
-}
-
-bool
-GlobalObject::initTypeObject(JSContext *cx, Handle<GlobalObject *> global)
-{
-    RootedObject TypeProto(cx, global->getOrCreateDataObject(cx));
-    if (!TypeProto)
-        return false;
-
-    RootedAtom TypeName(cx, ClassName(JSProto_Type, cx));
-    RootedFunction TypeCtor(cx,
-            global->createConstructor(cx, TypeThrowError, TypeName,
-                                      1, JSFunction::ExtendedFinalizeKind));
-    if (!TypeCtor)
-        return false;
-
-    if (!LinkConstructorAndPrototype(cx, TypeCtor, TypeProto))
-        return false;
+///////////////////////////////////////////////////////////////////////////
+// Creating the TypedObject "module"
+//
+// We create one global, `TypedObject`, which contains the following
+// members:
+//
+// 1. uint8, uint16, etc
+// 2. ArrayType
+// 3. StructType
+//
+// These are all callable/constructable objects whose [[Prototype]]s
+// are Function.prototype, but they are not functions in the JSAPI
+// sense (as in having the class JSFunction::class_).
+//
+// Each type object also has its own `prototype` field. Therefore,
+// using `StructType` as an example, the basic setup is as shown here
+// (each edge is labeled with a property name, and [[P]] is short for
+// [[Prototype]]):
+//
+//   StructType --[[P]]--> Function.[[P]]
+//        |
+//    prototype
+//        |
+//        v
+//       { } -----[[P]]--> Function.[[P]]
+//        |
+//    prototype
+//        |
+//        v
+//       { } -----[[P]]--> Object.[[P]]
+//
+// When a new type object (e.g., an instance of StructType) is created,
+// it will look as follows:
+//
+//   MyStruct -[[P]]-> StructType.prototype -[[P]]-> Function.[[P]]
+//        |
+//    prototype
+//        |
+//        v
+//       { } --[[P]]-> StructType.prototype.prototype
+//
+// Finally, when an instance of `MyStruct` is created, its
+// structure is as follows:
+//
+//    object -[[P]]--> MyStruct.prototype
+//
+// This structure permits users to install methods for all struct
+// types (by modifying StructType.prototype); for all struct instances
+// (by modifying StructType.prototype.prototype); or for all instances
+// of `MyStruct` specifically (MyStruct.prototype).
 
-    if (!DefineConstructorAndPrototype(cx, global, JSProto_Type,
-                                       TypeCtor, TypeProto))
-        return false;
-
-    global->setConstructor(JSProto_Type, ObjectValue(*TypeCtor));
-    return true;
-}
+template<ScalarTypeRepresentation::Type type>
+static bool
+DefineNumericClass(JSContext *cx, Handle<GlobalObject*> global,
+                   HandleObject module, HandlePropertyName className);
 
-bool
-GlobalObject::initArrayTypeObject(JSContext *cx, Handle<GlobalObject *> global)
-{
-    RootedFunction ctor(cx,
-        global->createConstructor(cx, ArrayType::construct,
-                                  cx->names().ArrayType, 2));
-
-    global->setConstructor(JSProto_ArrayTypeObject, ObjectValue(*ctor));
-    return true;
-}
-
-static JSObject *
-SetupComplexHeirarchy(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey protoKey,
-                      HandleObject complexObject, MutableHandleObject proto,
-                      MutableHandleObject protoProto)
+JSObject *
+js_InitTypedObjectClass(JSContext *cx, HandleObject obj)
 {
-    // get the 'Type' constructor
-    RootedObject TypeObject(cx, global->getOrCreateTypeObject(cx));
-    if (!TypeObject)
-        return nullptr;
-
-    // Set complexObject.__proto__ = Type
-    if (!JS_SetPrototype(cx, complexObject, TypeObject))
-        return nullptr;
-
-    RootedObject DataObject(cx, global->getOrCreateDataObject(cx));
-    if (!DataObject)
-        return nullptr;
+    /*
+     * The initialization strategy for TypedObjects is mildly unusual
+     * compared to other classes. Because all of the types are members
+     * of a single global, `TypedObject`, we basically make the
+     * initialized for the `TypedObject` class populate the
+     * `TypedObject` global (which is referred to as "module" herein).
+     */
 
-    RootedValue DataProtoVal(cx);
-    if (!JSObject::getProperty(cx, DataObject, DataObject,
-                               cx->names().prototype, &DataProtoVal))
-        return nullptr;
-
-    RootedObject DataProto(cx, &DataProtoVal.toObject());
-    if (!DataProto)
-        return nullptr;
+    JS_ASSERT(obj->is<GlobalObject>());
+    Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>());
 
-    RootedObject prototypeObj(cx,
-        NewObjectWithGivenProto(cx, &JSObject::class_, nullptr, global));
-    if (!prototypeObj)
-        return nullptr;
-    if (!LinkConstructorAndPrototype(cx, complexObject, prototypeObj))
-        return nullptr;
-    if (!DefineConstructorAndPrototype(cx, global, protoKey,
-                                       complexObject, prototypeObj))
+    RootedObject objProto(cx, global->getOrCreateObjectPrototype(cx));
+    if (!objProto)
         return nullptr;
 
-    // Set complexObject.prototype.__proto__ = Data
-    if (!JS_SetPrototype(cx, prototypeObj, DataObject))
-        return nullptr;
+    RootedObject module(cx, NewObjectWithClassProto(cx, &JSObject::class_,
+                                                    objProto, global));
 
-    proto.set(prototypeObj);
+    // Define TypedObject global.
+
+    RootedValue moduleValue(cx, ObjectValue(*module));
+
+    // uint8, uint16, etc
 
-    // Set complexObject.prototype.prototype.__proto__ = Data.prototype
-    RootedObject prototypePrototypeObj(cx, JS_NewObject(cx, nullptr, nullptr,
-                                       global));
+#define BINARYDATA_NUMERIC_DEFINE(constant_, type_, name_)                      \
+    if (!DefineNumericClass<constant_>(cx, global, module, cx->names().name_))  \
+        return nullptr;
+    JS_FOR_EACH_SCALAR_TYPE_REPR(BINARYDATA_NUMERIC_DEFINE)
+#undef BINARYDATA_NUMERIC_DEFINE
 
-    if (!LinkConstructorAndPrototype(cx, prototypeObj,
-                                     prototypePrototypeObj))
-        return nullptr;
+    // ArrayType.
 
-    if (!JS_SetPrototype(cx, prototypePrototypeObj, DataProto))
+    RootedObject arrayType(cx, CreateMetaTypeObject<ArrayType>(cx, global));
+    if (!arrayType)
         return nullptr;
 
-    protoProto.set(prototypePrototypeObj);
+    RootedValue arrayTypeValue(cx, ObjectValue(*arrayType));
+    if (!JSObject::defineProperty(cx, module, cx->names().ArrayType,
+                                  arrayTypeValue,
+                                  nullptr, nullptr,
+                                  JSPROP_READONLY | JSPROP_PERMANENT))
+        return nullptr;
 
-    return complexObject;
-}
+    // StructType.
+
+    RootedObject structType(cx, CreateMetaTypeObject<StructType>(cx, global));
+    if (!structType)
+        return nullptr;
 
-static bool
-InitType(JSContext *cx, HandleObject globalObj)
-{
-    JS_ASSERT(globalObj->isNative());
-    Rooted<GlobalObject*> global(cx, &globalObj->as<GlobalObject>());
-    RootedObject ctor(cx, global->getOrCreateTypeObject(cx));
-    if (!ctor)
-        return false;
+    RootedValue structTypeValue(cx, ObjectValue(*structType));
+    if (!JSObject::defineProperty(cx, module, cx->names().StructType,
+                                  structTypeValue,
+                                  nullptr, nullptr,
+                                  JSPROP_READONLY | JSPROP_PERMANENT))
+        return nullptr;
 
-    RootedValue protoVal(cx);
-    if (!JSObject::getProperty(cx, ctor, ctor,
-                               cx->names().prototype, &protoVal))
-        return false;
+    // Everything is setup, install module on the global object:
+    if (!JSObject::defineProperty(cx, global, cx->names().TypedObject,
+                                  moduleValue,
+                                  nullptr, nullptr,
+                                  0))
+        return nullptr;
+    global->setReservedSlot(JSProto_TypedObject, moduleValue);
+    global->setArrayType(arrayType);
+    global->markStandardClassInitializedNoProto(&TypedObjectClass);
 
-    JS_ASSERT(protoVal.isObject());
-    RootedObject protoObj(cx, &protoVal.toObject());
-
-    if (!JS_DefineFunction(cx, protoObj, "equivalent", TypeEquivalent, 0, 0))
-        return false;
-
-    return true;
+    return module;
 }
 
-static bool
-InitArrayType(JSContext *cx, HandleObject globalObj)
+JSObject *
+js_InitTypedObjectDummy(JSContext *cx, HandleObject obj)
 {
-    JS_ASSERT(globalObj->isNative());
-    Rooted<GlobalObject*> global(cx, &globalObj->as<GlobalObject>());
-    RootedObject ctor(cx, global->getOrCreateArrayTypeObject(cx));
-    if (!ctor)
-        return false;
-
-    RootedObject proto(cx);
-    RootedObject protoProto(cx);
-    if (!SetupComplexHeirarchy(cx, global, JSProto_ArrayType,
-                               ctor, &proto, &protoProto))
-        return false;
-
-    if (!JS_DefineFunction(cx, proto, "repeat", ArrayRepeat, 1, 0))
-        return false;
-
-    if (!JS_DefineFunction(cx, proto, "toSource", ArrayType::toSource, 0, 0))
-        return false;
-
-    RootedObject arrayProto(cx);
-    if (!FindProto(cx, &ArrayObject::class_, &arrayProto))
-        return false;
-
-    RootedValue forEachFunVal(cx);
-    RootedAtom forEachAtom(cx, Atomize(cx, "forEach", 7));
-    RootedId forEachId(cx, AtomToId(forEachAtom));
-    if (!JSObject::getProperty(cx, arrayProto, arrayProto, forEachAtom->asPropertyName(), &forEachFunVal))
-        return false;
+    /*
+     * This function is entered into the jsprototypes.h table
+     * as the initializer for `TypedObject`. It should not
+     * be executed via the `standard_class_atoms` mechanism.
+     */
 
-    if (!JSObject::defineGeneric(cx, protoProto, forEachId, forEachFunVal, nullptr, nullptr, 0))
-        return false;
-
-    if (!JS_DefineFunction(cx, protoProto, "subarray",
-                           ArraySubarray, 1, 0))
-        return false;
-
-    return true;
-}
-
-static bool
-InitStructType(JSContext *cx, HandleObject obj)
-{
-    JS_ASSERT(obj->isNative());
-    Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
-    RootedFunction ctor(cx,
-        global->createConstructor(cx, StructType::construct,
-                                  cx->names().StructType, 1));
-
-    if (!ctor)
-        return false;
-
-    RootedObject proto(cx);
-    RootedObject protoProto(cx);
-    if (!SetupComplexHeirarchy(cx, global, JSProto_StructType,
-                               ctor, &proto, &protoProto))
-        return false;
-
-    if (!JS_DefineFunction(cx, proto, "toSource", StructType::toSource, 0, 0))
-        return false;
-
-    return true;
+    MOZ_ASSUME_UNREACHABLE("shouldn't be initializing TypedObject via the JSProtoKey initializer mechanism");
 }
 
 template<ScalarTypeRepresentation::Type type>
 static bool
 DefineNumericClass(JSContext *cx,
-                   HandleObject global,
-                   const char *name)
+                   Handle<GlobalObject*> global,
+                   HandleObject module,
+                   HandlePropertyName className)
 {
-    RootedObject globalProto(cx, JS_GetFunctionPrototype(cx, global));
-    RootedObject numFun(
-        cx,
-        JS_DefineObject(cx, global, name,
-                        (const JSClass *) &NumericTypeClasses[type],
-                        globalProto, 0));
+    RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx));
+    if (!funcProto)
+        return false;
+
+    RootedObject numFun(cx, NewObjectWithClassProto(cx, &NumericTypeClasses[type],
+                                                    funcProto, global));
     if (!numFun)
         return false;
 
     RootedObject typeReprObj(cx, ScalarTypeRepresentation::Create(cx, type));
     if (!typeReprObj)
         return false;
 
     numFun->initFixedSlot(SLOT_TYPE_REPR, ObjectValue(*typeReprObj));
@@ -1545,55 +1564,37 @@ DefineNumericClass(JSContext *cx,
         return false;
 
     if (!JS_DefineFunction(cx, numFun, "toString",
                            NumericTypeToString<type>, 0, 0))
         return false;
 
     if (!JS_DefineFunction(cx, numFun, "toSource",
                            NumericTypeToString<type>, 0, 0))
+    {
+        return false;
+    }
+
+    RootedValue numFunValue(cx, ObjectValue(*numFun));
+    if (!JSObject::defineProperty(cx, module, className,
+                                  numFunValue, nullptr, nullptr, 0))
         return false;
 
     return true;
 }
 
-JSObject *
-js_InitTypedObjectClasses(JSContext *cx, HandleObject obj)
-{
-    JS_ASSERT(obj->is<GlobalObject>());
-    Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>());
-
-    if (!InitType(cx, obj))
-        return nullptr;
-
-#define BINARYDATA_NUMERIC_DEFINE(constant_, type_, name_)                    \
-    if (!DefineNumericClass<constant_>(cx, global, #name_))                   \
-        return nullptr;
-    JS_FOR_EACH_SCALAR_TYPE_REPR(BINARYDATA_NUMERIC_DEFINE)
-#undef BINARYDATA_NUMERIC_DEFINE
-
-    if (!InitArrayType(cx, obj))
-        return nullptr;
-
-    if (!InitStructType(cx, obj))
-        return nullptr;
-
-    return global;
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Binary blocks
 
 const Class BinaryBlock::class_ = {
     "BinaryBlock",
     Class::NON_NATIVE |
     JSCLASS_HAS_RESERVED_SLOTS(BLOCK_RESERVED_SLOTS) |
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_IMPLEMENTS_BARRIERS |
-    JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayType),
+    JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub,
     JS_DeletePropertyStub,
     JS_PropertyStub,
     JS_StrictPropertyStub,
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     BinaryBlock::obj_finalize,
@@ -1655,36 +1656,36 @@ ReportBlockTypeError(JSContext *cx,
 
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                          errorNumber, typeReprStr);
 
     JS_free(cx, (void *) typeReprStr);
     return false;
 }
 
-/*static*/ void
+/* static */ void
 BinaryBlock::obj_trace(JSTracer *trace, JSObject *object)
 {
     JS_ASSERT(object->hasClass(&class_));
 
     for (size_t i = 0; i < BLOCK_RESERVED_SLOTS; i++)
         gc::MarkSlot(trace, &object->getReservedSlotRef(i), "BinaryBlockSlot");
 }
 
-/*static*/ void
+/* static */ void
 BinaryBlock::obj_finalize(js::FreeOp *op, JSObject *obj)
 {
     if (!obj->getFixedSlot(SLOT_BLOCKREFOWNER).isNull())
         return;
 
     if (void *mem = obj->getPrivate())
         op->free_(mem);
 }
 
-/*static*/ JSObject *
+/* static */ JSObject *
 BinaryBlock::createNull(JSContext *cx, HandleObject type, HandleValue owner)
 {
     JS_ASSERT(IsBinaryType(type));
 
     RootedValue protoVal(cx);
     if (!JSObject::getProperty(cx, type, type,
                                cx->names().prototype, &protoVal))
         return nullptr;
@@ -1703,17 +1704,17 @@ BinaryBlock::createNull(JSContext *cx, H
             if (!typeObj->addTypedObjectAddendum(cx, typeRepr))
                 return nullptr;
         }
     }
 
     return obj;
 }
 
-/*static*/ JSObject *
+/* static */ JSObject *
 BinaryBlock::createZeroed(JSContext *cx, HandleObject type)
 {
     RootedValue owner(cx, NullValue());
     RootedObject obj(cx, createNull(cx, type, owner));
     if (!obj)
         return nullptr;
 
     TypeRepresentation *typeRepr = typeRepresentation(type);
@@ -1721,34 +1722,34 @@ BinaryBlock::createZeroed(JSContext *cx,
     void *memory = JS_malloc(cx, memsize);
     if (!memory)
         return nullptr;
     memset(memory, 0, memsize);
     obj->setPrivate(memory);
     return obj;
 }
 
-/*static*/ JSObject *
+/* static */ JSObject *
 BinaryBlock::createDerived(JSContext *cx, HandleObject type,
                            HandleObject owner, size_t offset)
 {
     JS_ASSERT(IsBlock(owner));
     JS_ASSERT(offset <= BlockSize(cx, owner));
     JS_ASSERT(offset + TypeSize(type) <= BlockSize(cx, owner));
 
     RootedValue ownerValue(cx, ObjectValue(*owner));
     RootedObject obj(cx, createNull(cx, type, ownerValue));
     if (!obj)
         return nullptr;
 
     obj->setPrivate(BlockMem(owner) + offset);
     return obj;
 }
 
-/*static*/ bool
+/* static */ bool
 BinaryBlock::construct(JSContext *cx, unsigned int argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     RootedObject callee(cx, &args.callee());
     JS_ASSERT(IsBinaryType(callee));
 
     RootedObject obj(cx, createZeroed(cx, callee));
@@ -2269,30 +2270,27 @@ BinaryBlock::obj_enumerate(JSContext *cx
         }
         break;
 
       case TypeRepresentation::Array:
         switch (enum_op) {
           case JSENUMERATE_INIT_ALL:
           case JSENUMERATE_INIT:
             statep.setInt32(0);
-            idp.set(INT_TO_JSID(typeRepr->asArray()->length() + 1));
+            idp.set(INT_TO_JSID(typeRepr->asArray()->length()));
             break;
 
           case JSENUMERATE_NEXT:
             index = static_cast<int32_t>(statep.toInt32());
 
             if (index < typeRepr->asArray()->length()) {
                 idp.set(INT_TO_JSID(index));
                 statep.setInt32(index + 1);
-            } else if (index == typeRepr->asArray()->length()) {
-                idp.set(NameToId(cx->names().length));
-                statep.setInt32(index + 1);
             } else {
-                JS_ASSERT(index == typeRepr->asArray()->length() + 1);
+                JS_ASSERT(index == typeRepr->asArray()->length());
                 statep.setNull();
             }
 
             break;
 
           case JSENUMERATE_DESTROY:
             statep.setNull();
             break;
@@ -2329,9 +2327,8 @@ BinaryBlock::obj_enumerate(JSContext *cx
     return true;
 }
 
 /* static */ size_t
 BinaryBlock::dataOffset()
 {
     return JSObject::getPrivateDataOffset(BLOCK_RESERVED_SLOTS + 1);
 }
-
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -8,16 +8,23 @@
 #define builtin_TypedObject_h
 
 #include "jsobj.h"
 
 #include "builtin/TypeRepresentation.h"
 
 namespace js {
 
+/*
+ * 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.
+ */
+extern const Class TypedObjectClass;
+
 // Slots common to all type descriptors:
 enum TypeCommonSlots {
     // Canonical type representation of this type (see TypeRepresentation.h).
     SLOT_TYPE_REPR=0,
     TYPE_RESERVED_SLOTS
 };
 
 // Slots for ArrayType type descriptors:
@@ -42,48 +49,63 @@ enum BlockCommonSlots {
     // If this value is nullptr, then the block instance owns the
     // uint8_t* in its priate data. Otherwise, this field contains the
     // owner, and thus keeps the owner alive.
     SLOT_BLOCKREFOWNER,
 
     BLOCK_RESERVED_SLOTS
 };
 
-extern const Class DataClass;
-
-extern const Class TypeClass;
-
 template <ScalarTypeRepresentation::Type type, typename T>
 class NumericType
 {
   private:
     static const Class * typeToClass();
   public:
     static bool convert(JSContext *cx, HandleValue val, T* converted);
     static bool reify(JSContext *cx, void *mem, MutableHandleValue vp);
     static bool call(JSContext *cx, unsigned argc, Value *vp);
 };
 
+/*
+ * These are the classes of the scalar type descriptors, like `uint8`,
+ * `uint16` etc. Each of these classes has exactly one instance that
+ * is pre-created.
+ */
 extern const Class NumericTypeClasses[ScalarTypeRepresentation::TYPE_MAX];
 
 /*
  * Type descriptor created by `new ArrayType(...)`
  */
 class ArrayType : public JSObject
 {
   private:
   public:
     static const Class class_;
 
+    // Properties and methods to be installed on ArrayType.prototype,
+    // and hence inherited by all array type objects:
+    static const JSPropertySpec typeObjectProperties[];
+    static const JSFunctionSpec typeObjectMethods[];
+
+    // Properties and methods to be installed on ArrayType.prototype.prototype,
+    // and hence inherited by all array *typed* objects:
+    static const JSPropertySpec typedObjectProperties[];
+    static const JSFunctionSpec typedObjectMethods[];
+
+    // This is the function that gets called when the user
+    // does `new ArrayType(elem)`. It produces an array type object.
+    static bool construct(JSContext *cx, unsigned argc, Value *vp);
+
     static JSObject *create(JSContext *cx, HandleObject arrayTypeGlobal,
                             HandleObject elementType, size_t length);
-    static bool construct(JSContext *cx, unsigned int argc, jsval *vp);
-    static bool repeat(JSContext *cx, unsigned int argc, jsval *vp);
+    static bool repeat(JSContext *cx, unsigned argc, Value *vp);
+    static bool subarray(JSContext *cx, unsigned argc, Value *vp);
 
-    static bool toSource(JSContext *cx, unsigned int argc, jsval *vp);
+    static bool toSource(JSContext *cx, unsigned argc, Value *vp);
 
     static JSObject *elementType(JSContext *cx, HandleObject obj);
 };
 
 /*
  * Type descriptor created by `new StructType(...)`
  */
 class StructType : public JSObject
@@ -96,23 +118,35 @@ class StructType : public JSObject
      * and alignment and stores fieldmap as well.
      */
     static bool layout(JSContext *cx, HandleObject structType,
                        HandleObject fields);
 
   public:
     static const Class class_;
 
-    static bool toSource(JSContext *cx, unsigned int argc, jsval *vp);
+    // Properties and methods to be installed on StructType.prototype,
+    // and hence inherited by all struct type objects:
+    static const JSPropertySpec typeObjectProperties[];
+    static const JSFunctionSpec typeObjectMethods[];
+
+    // Properties and methods to be installed on StructType.prototype.prototype,
+    // and hence inherited by all struct *typed* objects:
+    static const JSPropertySpec typedObjectProperties[];
+    static const JSFunctionSpec typedObjectMethods[];
+
+    // This is the function that gets called when the user
+    // does `new StructType(...)`. It produces a struct type object.
+    static bool construct(JSContext *cx, unsigned argc, Value *vp);
+
+    static bool toSource(JSContext *cx, unsigned argc, Value *vp);
 
     static bool convertAndCopyTo(JSContext *cx,
                                  StructTypeRepresentation *typeRepr,
                                  HandleValue from, uint8_t *mem);
-
-    static bool construct(JSContext *cx, unsigned int argc, jsval *vp);
 };
 
 /* Binary data objects and handles */
 class BinaryBlock
 {
   private:
     // Creates a binary data object of the given type and class, but with
     // a nullptr memory pointer. Caller must use setPrivate() to set the
@@ -208,15 +242,15 @@ class BinaryBlock
     static JSObject *createZeroed(JSContext *cx, HandleObject type);
 
     // creates a block that aliases the memory owned by `owner` at the
     // given offset
     static JSObject *createDerived(JSContext *cx, HandleObject type,
                                    HandleObject owner, size_t offset);
 
     // user-accessible constructor (`new TypeDescriptor(...)`)
-    static bool construct(JSContext *cx, unsigned int argc, jsval *vp);
+    static bool construct(JSContext *cx, unsigned argc, Value *vp);
 };
 
 
 } // namespace js
 
 #endif /* builtin_TypedObject_h */
--- a/js/src/jit-test/tests/TypedObject/fuzz1.js
+++ b/js/src/jit-test/tests/TypedObject/fuzz1.js
@@ -1,8 +1,10 @@
-if (!this.hasOwnProperty("Type"))
-  quit();
+// |jit-test| error:RangeError
+
+if (!this.hasOwnProperty("TypedObject"))
+  throw new RangeError();
 
 function eval() {
     yield(undefined)
 }
-new(StructType)
-(eval())
+new TypedObject.StructType();
+eval();
--- a/js/src/jit-test/tests/TypedObject/fuzz10.js
+++ b/js/src/jit-test/tests/TypedObject/fuzz10.js
@@ -1,8 +1,8 @@
 // |jit-test| error:Error
 
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   throw new Error("type too large");
 
-var AA = new ArrayType(new ArrayType(uint8, (2147483647)), 5);
+var AA = new TypedObject.ArrayType(new ArrayType(TypedObject.uint8, 2147483647), 5);
 var aa = new AA();
 var aa0 = aa[0];
--- a/js/src/jit-test/tests/TypedObject/fuzz11.js
+++ b/js/src/jit-test/tests/TypedObject/fuzz11.js
@@ -1,13 +1,13 @@
 // |jit-test| error:Error
 
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   throw new Error("type too large");
 
-var A = new ArrayType(uint8, (2147483647));
-var S = new StructType({a: A,
-                        b: A,
-                        c: A,
-                        d: A,
-                        e: A});
+var A = new TypedObject.ArrayType(TypedObject.uint8, 2147483647);
+var S = new TypedObject.StructType({a: A,
+                                    b: A,
+                                    c: A,
+                                    d: A,
+                                    e: A});
 var aa = new S();
 var aa0 = aa.a;
--- a/js/src/jit-test/tests/TypedObject/fuzz2.js
+++ b/js/src/jit-test/tests/TypedObject/fuzz2.js
@@ -1,4 +1,4 @@
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   quit();
 
-new StructType([])
+new TypedObject.StructType([]);
--- a/js/src/jit-test/tests/TypedObject/fuzz3.js
+++ b/js/src/jit-test/tests/TypedObject/fuzz3.js
@@ -1,7 +1,7 @@
 // |jit-test| error:RangeError;
 
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   throw new RangeError();
 
 this.__proto__ =  Proxy.create({});
-new StructType;
+new TypedObject.StructType;
--- a/js/src/jit-test/tests/TypedObject/fuzz4.js
+++ b/js/src/jit-test/tests/TypedObject/fuzz4.js
@@ -1,10 +1,10 @@
 // |jit-test| error:Error;
 
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   throw new Error();
 
-var A = new ArrayType(uint8, 10);
+var A = new TypedObject.ArrayType(TypedObject.uint8, 10);
 var a = new A();
 a.forEach(function(val, i) {
   assertEq(arguments[5], a);
 });
--- a/js/src/jit-test/tests/TypedObject/fuzz5.js
+++ b/js/src/jit-test/tests/TypedObject/fuzz5.js
@@ -1,6 +1,8 @@
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   quit();
 
-var Color = new StructType({r: uint8, g: uint8, b: uint8});
+var Color = new TypedObject.StructType({r: TypedObject.uint8,
+                                        g: TypedObject.uint8,
+                                        b: TypedObject.uint8});
 var white2 = new Color({r: 255, toString: null, b: 253});
 
--- a/js/src/jit-test/tests/TypedObject/fuzz6.js
+++ b/js/src/jit-test/tests/TypedObject/fuzz6.js
@@ -1,6 +1,6 @@
 // |jit-test| error:TypeError
 
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   throw new TypeError();
 
-new StructType(RegExp);
+new TypedObject.StructType(RegExp);
--- a/js/src/jit-test/tests/TypedObject/fuzz7.js
+++ b/js/src/jit-test/tests/TypedObject/fuzz7.js
@@ -1,4 +1,4 @@
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   quit();
 
-new StructType(RegExp());
+new TypedObject.StructType(RegExp());
--- a/js/src/jit-test/tests/TypedObject/fuzz8.js
+++ b/js/src/jit-test/tests/TypedObject/fuzz8.js
@@ -1,6 +1,6 @@
 // |jit-test| error:Error
 
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   throw new Error();
 
-new ArrayType(uint8, .0000000009);
+new TypedObject.ArrayType(TypedObject.uint8, .0000000009);
--- a/js/src/jit-test/tests/TypedObject/fuzz9.js
+++ b/js/src/jit-test/tests/TypedObject/fuzz9.js
@@ -1,10 +1,10 @@
 // |jit-test| error: TypeError
 
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   throw new TypeError();
 
-var Vec3 = new ArrayType(float32, 3);
-var Sprite = new ArrayType(Vec3, 3);
+var Vec3 = new TypedObject.ArrayType(TypedObject.float32, 3);
+var Sprite = new TypedObject.ArrayType(Vec3, 3);
 var mario = new Sprite();
 mario[/\u00ee[]/] = new Vec3([1, 0, 0]);
 
--- a/js/src/jit-test/tests/TypedObject/jit-complex.js
+++ b/js/src/jit-test/tests/TypedObject/jit-complex.js
@@ -1,18 +1,18 @@
 // Test that we can optimize stuff like line.target.x without
 // creating an intermediate object.
 
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   quit();
 
-var PointType = new StructType({x: float64,
-                                y: float64});
-var LineType = new StructType({source: PointType,
-                               target: PointType});
+var PointType = new TypedObject.StructType({x: TypedObject.float64,
+                                            y: TypedObject.float64});
+var LineType = new TypedObject.StructType({source: PointType,
+                                           target: PointType});
 
 function manhattenDistance(line) {
   return (Math.abs(line.target.x - line.source.x) +
           Math.abs(line.target.y - line.source.y));
 }
 
 function foo() {
   var N = 30000;
--- a/js/src/jit-test/tests/TypedObject/jit-prefix.js
+++ b/js/src/jit-test/tests/TypedObject/jit-prefix.js
@@ -1,17 +1,21 @@
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   quit();
 
-var PointType2 = new StructType({x: float64,
-                                 y: float64});
+var PointType2 =
+  new TypedObject.StructType({
+    x: TypedObject.float64,
+    y: TypedObject.float64});
 
-var PointType3 = new StructType({x: float64,
-                                 y: float64,
-                                 z: float64});
+var PointType3 =
+  new TypedObject.StructType({
+    x: TypedObject.float64,
+    y: TypedObject.float64,
+    z: TypedObject.float64});
 
 function xPlusY(p) {
   return p.x + p.y;
 }
 
 function xPlusYTweak(p) {
   p.x = 22;
   return xPlusY(p);
--- a/js/src/jit-test/tests/TypedObject/jit-read-float64.js
+++ b/js/src/jit-test/tests/TypedObject/jit-read-float64.js
@@ -1,14 +1,14 @@
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   quit();
 
-var PointType = new StructType({x: float64,
-                                y: float64,
-                                z: float64});
+var PointType = new TypedObject.StructType({x: TypedObject.float64,
+                                            y: TypedObject.float64,
+                                            z: TypedObject.float64});
 
 function foo() {
   for (var i = 0; i < 30000; i += 3) {
     var pt = new PointType({x: i, y: i+1, z: i+2});
     var sum = pt.x + pt.y + pt.z;
     print(pt.x, pt.y, pt.z);
     assertEq(sum, 3*i + 3);
   }
--- a/js/src/jit-test/tests/TypedObject/jit-read-int.js
+++ b/js/src/jit-test/tests/TypedObject/jit-read-int.js
@@ -1,14 +1,14 @@
-if (!this.hasOwnProperty("Type"))
+if (!this.hasOwnProperty("TypedObject"))
   quit();
 
-var PointType = new StructType({x: uint32,
-                                y: uint32,
-                                z: uint32});
+var PointType = new TypedObject.StructType({x: TypedObject.uint32,
+                                            y: TypedObject.uint32,
+                                            z: TypedObject.uint32});
 
 function foo() {
   for (var i = 0; i < 30000; i += 3) {
     var pt = new PointType({x: i, y: i+1, z: i+2});
     var sum = pt.x + pt.y + pt.z;
     assertEq(sum, 3*i + 3);
   }
 }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1428,17 +1428,17 @@ static const JSStdName standard_class_at
 #ifdef ENABLE_PARALLEL_JS
     {js_InitParallelArrayClass,         EAGER_ATOM_AND_OCLASP(ParallelArray)},
 #endif
     {js_InitProxyClass,                 EAGER_CLASS_ATOM(Proxy), &ProxyObject::uncallableClass_},
 #if EXPOSE_INTL_API
     {js_InitIntlClass,                  EAGER_ATOM_AND_CLASP(Intl)},
 #endif
 #ifdef ENABLE_BINARYDATA
-    {js_InitTypedObjectClasses,         EAGER_ATOM_AND_CLASP(Type)},
+    {js_InitTypedObjectClass,           EAGER_ATOM_AND_CLASP(TypedObject)},
 #endif
     {nullptr,                           0, nullptr}
 };
 
 /*
  * Table of top-level function and constant names and their init functions.
  * If you add a "standard" global function or property, remember to update
  * this table.
@@ -1486,27 +1486,16 @@ static const JSStdName standard_class_na
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int32Array),   TYPED_ARRAY_CLASP(TYPE_INT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint32Array),  TYPED_ARRAY_CLASP(TYPE_UINT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float32Array), TYPED_ARRAY_CLASP(TYPE_FLOAT32)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Float64Array), TYPED_ARRAY_CLASP(TYPE_FLOAT64)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8ClampedArray),
                                 TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(DataView),     &DataViewObject::class_},
 
-    /* Binary Data */
-#ifdef ENABLE_BINARYDATA
-    {js_InitTypedObjectClasses,   EAGER_ATOM_AND_CLASP(Type)},
-    {js_InitTypedObjectClasses,   EAGER_ATOM_AND_CLASP(Data)},
-#define BINARYDATA_NUMERIC_NAMES(constant_, type_, name_) \
-    {js_InitTypedObjectClasses,   EAGER_CLASS_ATOM(name_),      &NumericTypeClasses[constant_]},
-    JS_FOR_EACH_SCALAR_TYPE_REPR(BINARYDATA_NUMERIC_NAMES)
-#undef BINARYDATA_NUMERIC_NAMES
-    {js_InitTypedObjectClasses,   EAGER_CLASS_ATOM(ArrayType),  &js::ArrayType::class_},
-    {js_InitTypedObjectClasses,   EAGER_CLASS_ATOM(StructType), &js::StructType::class_},
-#endif
     {nullptr,                     0, nullptr}
 };
 
 static const JSStdName object_prototype_names[] = {
     /* Object.prototype properties (global delegates to Object.prototype). */
     {js_InitObjectClass,        EAGER_ATOM(proto), &JSObject::class_},
 #if JS_HAS_TOSOURCE
     {js_InitObjectClass,        EAGER_ATOM(toSource), &JSObject::class_},
--- a/js/src/jsprototypes.h
+++ b/js/src/jsprototypes.h
@@ -49,25 +49,12 @@
     macro(Uint8ClampedArray,     30,     js_InitTypedArrayClasses) \
     macro(Proxy,                 31,     js_InitProxyClass) \
     macro(WeakMap,               32,     js_InitWeakMapClass) \
     macro(Map,                   33,     js_InitMapClass) \
     macro(Set,                   34,     js_InitSetClass) \
     macro(DataView,              35,     js_InitTypedArrayClasses) \
     macro(ParallelArray,         36,     js_InitParallelArrayClass) \
     macro(Intl,                  37,     js_InitIntlClass) \
-    macro(Type,                  38,     js_InitTypedObjectClasses) \
-    macro(Data,                  39,     js_InitTypedObjectClasses) \
-    macro(uint8Clamped,          40,     js_InitTypedObjectClasses) \
-    macro(uint8,                 41,     js_InitTypedObjectClasses) \
-    macro(uint16,                42,     js_InitTypedObjectClasses) \
-    macro(uint32,                43,     js_InitTypedObjectClasses) \
-    macro(int8,                  44,     js_InitTypedObjectClasses) \
-    macro(int16,                 45,     js_InitTypedObjectClasses) \
-    macro(int32,                 46,     js_InitTypedObjectClasses) \
-    macro(float32,               47,     js_InitTypedObjectClasses) \
-    macro(float64,               48,     js_InitTypedObjectClasses) \
-    macro(ArrayType,             49,     js_InitTypedObjectClasses) \
-    macro(StructType,            50,     js_InitTypedObjectClasses) \
-    macro(ArrayTypeObject,       51,     js_InitTypedObjectClasses) \
-    macro(GeneratorFunction,     52,     js_InitIteratorClasses) \
+    macro(TypedObject,           38,     js_InitTypedObjectDummy) \
+    macro(GeneratorFunction,     39,     js_InitIteratorClasses) \
 
 #endif /* jsprototypes_h */
--- a/js/src/tests/ecma_6/TypedObject/architecture.js
+++ b/js/src/tests/ecma_6/TypedObject/architecture.js
@@ -1,9 +1,10 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
+
 var BUGNUMBER = 578700;
 var summary = 'Binary Data class diagram';
 
 function assertNotEq(a, b) {
     var ok = false;
     try {
         assertEq(a, b);
     } catch(exc) {
@@ -21,49 +22,34 @@ function assertThrows(f) {
     } catch (exc) {
         ok = true;
     }
     if (!ok)
         throw new TypeError("Assertion failed: " + f + " did not throw as expected");
 }
 
 function runTests() {
-    print(BUGNUMBER + ": " + summary);
+  print(BUGNUMBER + ": " + summary);
 
-    assertEq(Data.__proto__, Function.prototype);
-    assertEq(Data.prototype.__proto__, Object.prototype);
-    assertEq(Data.prototype.constructor, Data);
-    assertEq(typeof Data.prototype.update === "function", true);
+  var ArrayType = TypedObject.ArrayType;
+  var StructType = TypedObject.StructType;
 
-    assertEq(Type.__proto__, Function.prototype);
-    assertEq(Type.prototype, Data);
+  assertEq(ArrayType instanceof Function, true);
+  assertEq(ArrayType.prototype instanceof Function, true);
 
-    assertEq(ArrayType.__proto__, Type);
-    assertEq(ArrayType.prototype.__proto__, Type.prototype);
-    assertEq(typeof ArrayType.prototype.repeat === "function", true);
-
-    assertEq(ArrayType.prototype.prototype.__proto__, Data.prototype);
+  assertEq(ArrayType.__proto__, Function.__proto__);
+  assertEq(ArrayType.prototype.__proto__, Function.__proto__);
 
-    assertEq(StructType.__proto__, Type);
-    assertEq(StructType.prototype.__proto__, Type.prototype);
-    assertEq(StructType.prototype.prototype.__proto__, Data.prototype);
-
-    // Change global 'Type' and see if things stay sane.
-    Type = function() {
-        return 42;
-    }
+  assertEq(StructType instanceof Function, true);
+  assertEq(StructType.prototype instanceof Function, true);
 
-    Data = function() {
-        return 43;
-    }
-
-    assertNotEq(ArrayType.prototype.__proto__, Type.prototype);
-    assertNotEq(ArrayType.prototype.prototype.__proto__, Data.prototype);
+  assertEq(Object.getPrototypeOf(StructType),
+           Object.getPrototypeOf(Function));
+  assertEq(Object.getPrototypeOf(StructType.prototype),
+           Object.getPrototypeOf(Function));
 
-    assertNotEq(StructType.prototype.__proto__, Type.prototype);
-    assertNotEq(StructType.prototype.prototype.__proto__, Data.prototype);
+  if (typeof reportCompare === "function")
+    reportCompare(true, true);
 
-    if (typeof reportCompare === "function")
-        reportCompare(true, true);
-    print("Tests complete");
+  print("Tests complete");
 }
 
 runTests();
--- a/js/src/tests/ecma_6/TypedObject/arrayofstructs.js
+++ b/js/src/tests/ecma_6/TypedObject/arrayofstructs.js
@@ -1,12 +1,15 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 578700;
 var summary = 'TypedObjects StructType prototype chains';
 
+var ArrayType = TypedObject.ArrayType;
+var StructType = TypedObject.StructType;
+var float32 = TypedObject.float32;
 
 function runTests() {
   var Point = new ArrayType(float32, 3);
   var Line = new StructType({from: Point, to: Point});
   var Lines = new ArrayType(Line, 3);
 
   var lines = new Lines([
     {from: [1, 2, 3], to: [4, 5, 6]},
--- a/js/src/tests/ecma_6/TypedObject/arraytype.js
+++ b/js/src/tests/ecma_6/TypedObject/arraytype.js
@@ -1,23 +1,28 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 578700;
 var summary = 'TypedObjects ArrayType implementation';
 
 function assertThrows(f) {
     var ok = false;
     try {
         f();
     } catch (exc) {
         ok = true;
     }
     if (!ok)
         throw new TypeError("Assertion failed: " + f + " did not throw as expected");
 }
 
+var ArrayType = TypedObject.ArrayType;
+var uint8 = TypedObject.uint8;
+var float32 = TypedObject.float32;
+var uint32 = TypedObject.uint32;
+
 function runTests() {
     print(BUGNUMBER + ": " + summary);
 
     assertEq(typeof ArrayType.prototype.prototype.forEach == "function", true);
     assertEq(typeof ArrayType.prototype.prototype.subarray == "function", true);
 
     assertThrows(function() ArrayType(uint8, 10));
     assertThrows(function() new ArrayType());
@@ -101,27 +106,18 @@ function runTests() {
     assertEq(as.length, 65536);
 
     // test methods
     var c = new A();
     c.fill(3);
     for (var i = 0; i < c.length; i++)
         assertEq(c[i], 3);
 
-    assertThrows(function() c.update([3.14, 4.52, 5]));
-    //assertThrows(function() c.update([3000, 0, 1, 1, 1, 1, 1, 1, 1, 1]));
-
     assertThrows(function() Vec3.prototype.fill.call(c, 2));
 
-    var updatingPos = new Vec3();
-    updatingPos.update([5, 3, 1]);
-    assertEq(updatingPos[0], 5);
-    assertEq(updatingPos[1], 3);
-    assertEq(updatingPos[2], 1);
-
     var d = A.repeat(10);
     for (var i = 0; i < d.length; i++)
         assertEq(d[i], 10);
 
     assertThrows(function() ArrayType.prototype.repeat.call(d, 2));
 
     var MA = new ArrayType(uint32, 5);
     var ma = new MA([1, 2, 3, 4, 5]);
@@ -132,25 +128,16 @@ function runTests() {
     assertEq(mb[1], 4);
     assertEq(mb[2], 5);
 
     assertThrows(function() ma.subarray());
     assertThrows(function() ma.subarray(2.14));
     assertThrows(function() ma.subarray({}));
     assertThrows(function() ma.subarray(2, []));
 
-    // check similarity even though mb's ArrayType
-    // is not script accessible
-    var Similar = new ArrayType(uint32, 3);
-    var sim = new Similar();
-    sim.update(mb);
-    assertEq(sim[0], 3);
-    assertEq(sim[1], 4);
-    assertEq(sim[2], 5);
-
     var range = ma.subarray(0, 3);
     assertEq(range.length, 3);
     assertEq(range[0], 1);
     assertEq(range[1], 2);
     assertEq(range[2], 3);
 
     assertEq(ma.subarray(ma.length).length, 0);
     assertEq(ma.subarray(ma.length, ma.length-1).length, 0);
@@ -176,23 +163,28 @@ function runTests() {
     assertEq(modifyOriginal[2], 97);
 
     var indexPropDesc = Object.getOwnPropertyDescriptor(as, '0');
     assertEq(typeof indexPropDesc == "undefined", false);
     assertEq(indexPropDesc.configurable, false);
     assertEq(indexPropDesc.enumerable, true);
     assertEq(indexPropDesc.writable, true);
 
-
     var lengthPropDesc = Object.getOwnPropertyDescriptor(as, 'length');
     assertEq(typeof lengthPropDesc == "undefined", false);
     assertEq(lengthPropDesc.configurable, false);
     assertEq(lengthPropDesc.enumerable, false);
     assertEq(lengthPropDesc.writable, false);
 
+    var counter = 0;
+    for (var nm in as) {
+      assertEq(+nm, counter++);
+    }
+    assertEq(counter, as.length);
+
     assertThrows(function() Object.defineProperty(o, "foo", { value: "bar" }));
 
     // check if a reference acts the way it should
     var AA = new ArrayType(new ArrayType(uint8, 5), 5);
     var aa = new AA();
     var aa0 = aa[0];
     aa[0] = [0,1,2,3,4];
     for (var i = 0; i < aa0.length; i++)
--- a/js/src/tests/ecma_6/TypedObject/memory.js
+++ b/js/src/tests/ecma_6/TypedObject/memory.js
@@ -1,17 +1,30 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 578700;
 var summary = 'TypedObjects memory check';
 
 function spin() {
     for (var i = 0; i < 10000; i++)
         ;
 }
 
+var ArrayType = TypedObject.ArrayType;
+var StructType = TypedObject.StructType;
+var uint8 = TypedObject.uint8;
+var uint16 = TypedObject.uint16;
+var uint32 = TypedObject.uint32;
+var uint8Clamped = TypedObject.uint8Clamped;
+var int8 = TypedObject.int8;
+var int16 = TypedObject.int16;
+var int32 = TypedObject.int32;
+var float32 = TypedObject.float32;
+var float64 = TypedObject.float64;
+
+
 function runTests() {
     print(BUGNUMBER + ": " + summary);
 
     var AA = new ArrayType(new ArrayType(uint8, 5), 5);
     var aa = new AA();
     var aa0 = aa[0];
     aa[0] = [0,1,2,3,4];
 
@@ -44,17 +57,19 @@ function runTests() {
 
     var theOneISawWasJustBlack = Rainbow.repeat({'r': 0, 'g': 0, 'b': 0});
 
     var middleBand = theOneISawWasJustBlack[3];
     theOneISawWasJustBlack = null;
     gc();
     spin();
     assertEq(middleBand['r'] == 0 && middleBand['g'] == 0 && middleBand['b'] == 0, true);
-    middleBand.update({'r': 255, 'g': 207, 'b': 142});
+    middleBand.r = 255;
+    middleBand.g = 207;
+    middleBand.b = 142;
     assertEq(middleBand['r'] == 255 && middleBand['g'] == 207 && middleBand['b'] == 142, true);
 
     var scopedType = function() {
         var Point = new StructType({'x': int32, 'y': int32});
         var aPoint = new Point();
         aPoint.x = 4;
         aPoint.y = 5;
         return aPoint;
--- a/js/src/tests/ecma_6/TypedObject/numerictypes.js
+++ b/js/src/tests/ecma_6/TypedObject/numerictypes.js
@@ -1,14 +1,26 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 578700;
 var summary = 'TypedObjects numeric types';
 var actual = '';
 var expect = '';
 
+var ArrayType = TypedObject.ArrayType;
+var StructType = TypedObject.StructType;
+var uint8 = TypedObject.uint8;
+var uint16 = TypedObject.uint16;
+var uint32 = TypedObject.uint32;
+var uint8Clamped = TypedObject.uint8Clamped;
+var int8 = TypedObject.int8;
+var int16 = TypedObject.int16;
+var int32 = TypedObject.int32;
+var float32 = TypedObject.float32;
+var float64 = TypedObject.float64;
+
 function runTests()
 {
     printBugNumber(BUGNUMBER);
     printStatus(summary);
 
     var TestPassCount = 0;
     var TestFailCount = 0;
     var TestTodoCount = 0;
--- a/js/src/tests/ecma_6/TypedObject/size_and_alignment.js
+++ b/js/src/tests/ecma_6/TypedObject/size_and_alignment.js
@@ -1,14 +1,28 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 578700;
 var summary = 'Size and Alignment of TypedObjects types';
 var actual = '';
 var expect = '';
 
+
+var ArrayType = TypedObject.ArrayType;
+var StructType = TypedObject.StructType;
+var uint8 = TypedObject.uint8;
+var uint16 = TypedObject.uint16;
+var uint32 = TypedObject.uint32;
+var uint8Clamped = TypedObject.uint8Clamped;
+var int8 = TypedObject.int8;
+var int16 = TypedObject.int16;
+var int32 = TypedObject.int32;
+var float32 = TypedObject.float32;
+var float64 = TypedObject.float64;
+
+
 function runTests() {
   printBugNumber(BUGNUMBER);
   printStatus(summary);
 
   var typesAndAlignments = [
     {type: uint8, size: 1, alignment: 1},
     {type: uint8Clamped, size: 1, alignment: 1},
     {type: uint16, size: 2, alignment: 2},
--- a/js/src/tests/ecma_6/TypedObject/structequiv.js
+++ b/js/src/tests/ecma_6/TypedObject/structequiv.js
@@ -1,12 +1,24 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 578700;
 var summary = 'TypedObjects Equivalent StructTypes';
 
+var ArrayType = TypedObject.ArrayType;
+var StructType = TypedObject.StructType;
+var uint8 = TypedObject.uint8;
+var uint16 = TypedObject.uint16;
+var uint32 = TypedObject.uint32;
+var uint8Clamped = TypedObject.uint8Clamped;
+var int8 = TypedObject.int8;
+var int16 = TypedObject.int16;
+var int32 = TypedObject.int32;
+var float32 = TypedObject.float32;
+var float64 = TypedObject.float64;
+
 function assertEquivalent(t1, t2) {
   assertEq(true, t1.equivalent(t2));
   assertEq(true, t2.equivalent(t1));
 }
 
 function assertNotEquivalent(t1, t2) {
   assertEq(false, t1.equivalent(t2));
   assertEq(false, t2.equivalent(t1));
--- a/js/src/tests/ecma_6/TypedObject/structtypeenumerate.js
+++ b/js/src/tests/ecma_6/TypedObject/structtypeenumerate.js
@@ -1,12 +1,24 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 578700;
 var summary = 'TypedObjects StructType propery enumeration';
 
+var ArrayType = TypedObject.ArrayType;
+var StructType = TypedObject.StructType;
+var uint8 = TypedObject.uint8;
+var uint16 = TypedObject.uint16;
+var uint32 = TypedObject.uint32;
+var uint8Clamped = TypedObject.uint8Clamped;
+var int8 = TypedObject.int8;
+var int16 = TypedObject.int16;
+var int32 = TypedObject.int32;
+var float32 = TypedObject.float32;
+var float64 = TypedObject.float64;
+
 function runTests() {
   var RgbColor = new StructType({r: uint8, g: uint8, b: uint8});
   var Fade = new StructType({from: RgbColor, to: RgbColor});
 
   var white = new RgbColor({r: 255, g: 255, b: 255});
   var gray = new RgbColor({r: 129, g: 128, b: 127});
   var fade = new Fade({from: white, to: gray});
 
--- a/js/src/tests/ecma_6/TypedObject/structtypeindexedfields.js
+++ b/js/src/tests/ecma_6/TypedObject/structtypeindexedfields.js
@@ -1,12 +1,24 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 578700;
 var summary = 'TypedObjects: indexed properties are illegal in a StructType';
 
+var ArrayType = TypedObject.ArrayType;
+var StructType = TypedObject.StructType;
+var uint8 = TypedObject.uint8;
+var uint16 = TypedObject.uint16;
+var uint32 = TypedObject.uint32;
+var uint8Clamped = TypedObject.uint8Clamped;
+var int8 = TypedObject.int8;
+var int16 = TypedObject.int16;
+var int32 = TypedObject.int32;
+var float32 = TypedObject.float32;
+var float64 = TypedObject.float64;
+
 function runTests() {
   print(BUGNUMBER + ": " + summary);
 
   var failed;
   try {
     new StructType({1: int32, 2: uint8, 3: float64});
     failed = false;
   } catch (e) {
--- a/js/src/tests/ecma_6/TypedObject/structtypeprototype.js
+++ b/js/src/tests/ecma_6/TypedObject/structtypeprototype.js
@@ -1,21 +1,33 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 578700;
 var summary = 'TypedObjects StructType prototype chains';
 
+var ArrayType = TypedObject.ArrayType;
+var StructType = TypedObject.StructType;
+var uint8 = TypedObject.uint8;
+var uint16 = TypedObject.uint16;
+var uint32 = TypedObject.uint32;
+var uint8Clamped = TypedObject.uint8Clamped;
+var int8 = TypedObject.int8;
+var int16 = TypedObject.int16;
+var int32 = TypedObject.int32;
+var float32 = TypedObject.float32;
+var float64 = TypedObject.float64;
 
 function runTests() {
   var RgbColor1 = new StructType({r: uint8, g: uint8, b: uint8});
   var RgbColor2 = new StructType({r: uint8, g: uint8, b: uint8});
   var Fade1 = new StructType({from: RgbColor1, to: RgbColor1});
   var Fade2 = new StructType({from: RgbColor2, to: RgbColor2});
 
-  // Available on all objects
-  Data.prototype.sub = function(c) {
+  // Available on all struct types (even though it would only make
+  // sense on a RgbColor1 or RgbColor2 instance)
+  StructType.prototype.prototype.sub = function(c) {
     this.r -= c;
     this.g -= c;
     this.b -= c;
   };
 
   // Available on `RgbColor2` instances only
   RgbColor2.prototype.add = function(c) {
     this.r += c;
--- a/js/src/tests/ecma_6/TypedObject/structtypereflection.js
+++ b/js/src/tests/ecma_6/TypedObject/structtypereflection.js
@@ -1,12 +1,24 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 578700;
 var summary = 'TypedObjects: check reflection on StructType objects';
 
+var ArrayType = TypedObject.ArrayType;
+var StructType = TypedObject.StructType;
+var uint8 = TypedObject.uint8;
+var uint16 = TypedObject.uint16;
+var uint32 = TypedObject.uint32;
+var uint8Clamped = TypedObject.uint8Clamped;
+var int8 = TypedObject.int8;
+var int16 = TypedObject.int16;
+var int32 = TypedObject.int32;
+var float32 = TypedObject.float32;
+var float64 = TypedObject.float64;
+
 function runTests() {
     print(BUGNUMBER + ": " + summary);
 
     var S = new StructType({x: int32, y: uint8, z: float64});
     assertEq(S.__proto__, StructType.prototype);
     assertEq(S.prototype.__proto__, StructType.prototype.prototype);
     assertEq(S.toSource(), "StructType({x: int32, y: uint8, z: float64})");
     assertEq(S.variable, false);
--- a/js/src/tests/ecma_6/TypedObject/structtypestructuralassign.js
+++ b/js/src/tests/ecma_6/TypedObject/structtypestructuralassign.js
@@ -1,12 +1,24 @@
-// |reftest| skip-if(!this.hasOwnProperty("Type"))
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
 var BUGNUMBER = 578700;
 var summary = 'TypedObjects StructType structural assignment';
 
+var ArrayType = TypedObject.ArrayType;
+var StructType = TypedObject.StructType;
+var uint8 = TypedObject.uint8;
+var uint16 = TypedObject.uint16;
+var uint32 = TypedObject.uint32;
+var uint8Clamped = TypedObject.uint8Clamped;
+var int8 = TypedObject.int8;
+var int16 = TypedObject.int16;
+var int32 = TypedObject.int32;
+var float32 = TypedObject.float32;
+var float64 = TypedObject.float64;
+
 function assertEqColor(c1, c2) {
   assertEq(c1.r, c2.r);
   assertEq(c1.g, c2.g);
   assertEq(c1.b, c2.b);
 }
 
 function runTests() {
   var RgbColor = new StructType({r: uint8, g: uint8, b: uint8});
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -10,16 +10,17 @@
 #define vm_CommonPropertyNames_h
 
 #include "jsprototypes.h"
 
 #define FOR_EACH_COMMON_PROPERTYNAME(macro) \
     macro(anonymous, anonymous, "anonymous") \
     macro(apply, apply, "apply") \
     macro(arguments, arguments, "arguments") \
+    macro(ArrayType, ArrayType, "ArrayType") \
     macro(buffer, buffer, "buffer") \
     macro(builder, builder, "builder") \
     macro(byteLength, byteLength, "byteLength") \
     macro(byteAlignment, byteAlignment, "byteAlignment") \
     macro(byteOffset, byteOffset, "byteOffset") \
     macro(bytes, bytes, "bytes") \
     macro(BYTES_PER_ELEMENT, BYTES_PER_ELEMENT, "BYTES_PER_ELEMENT") \
     macro(call, call, "call") \
@@ -57,16 +58,18 @@
     macro(escape, escape, "escape") \
     macro(eval, eval, "eval") \
     macro(false, false_, "false") \
     macro(fieldNames, fieldNames, "fieldNames") \
     macro(fieldOffsets, fieldOffsets, "fieldOffsets") \
     macro(fieldTypes, fieldTypes, "fieldTypes") \
     macro(fileName, fileName, "fileName") \
     macro(fix, fix, "fix") \
+    macro(float32, float32, "float32") \
+    macro(float64, float64, "float64") \
     macro(format, format, "format") \
     macro(get, get, "get") \
     macro(getInternals, getInternals, "getInternals") \
     macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \
     macro(getOwnPropertyNames, getOwnPropertyNames, "getOwnPropertyNames") \
     macro(getPropertyDescriptor, getPropertyDescriptor, "getPropertyDescriptor") \
     macro(global, global, "global") \
     macro(has, has, "has") \
@@ -80,16 +83,19 @@
     macro(InitializeNumberFormat, InitializeNumberFormat, "InitializeNumberFormat") \
     macro(innermost, innermost, "innermost") \
     macro(input, input, "input") \
     macro(isFinite, isFinite, "isFinite") \
     macro(isNaN, isNaN, "isNaN") \
     macro(isPrototypeOf, isPrototypeOf, "isPrototypeOf") \
     macro(iterate, iterate, "iterate") \
     macro(Infinity, Infinity, "Infinity") \
+    macro(int8, int8, "int8") \
+    macro(int16, int16, "int16") \
+    macro(int32, int32, "int32") \
     macro(iterator, iterator, "iterator") \
     macro(iteratorIntrinsic, iteratorIntrinsic, "__iterator__") \
     macro(join, join, "join") \
     macro(keys, keys, "keys") \
     macro(lastIndex, lastIndex, "lastIndex") \
     macro(length, length, "length") \
     macro(line, line, "line") \
     macro(lineNumber, lineNumber, "lineNumber") \
@@ -126,30 +132,35 @@
     macro(prototype, prototype, "prototype") \
     macro(return, return_, "return") \
     macro(sensitivity, sensitivity, "sensitivity") \
     macro(set, set, "set") \
     macro(shape, shape, "shape") \
     macro(source, source, "source") \
     macro(stack, stack, "stack") \
     macro(sticky, sticky, "sticky") \
+    macro(StructType, StructType, "StructType") \
     macro(style, style, "style") \
     macro(test, test, "test") \
     macro(throw, throw_, "throw") \
     macro(timeZone, timeZone, "timeZone") \
     macro(toGMTString, toGMTString, "toGMTString") \
     macro(toISOString, toISOString, "toISOString") \
     macro(toJSON, toJSON, "toJSON") \
     macro(toLocaleString, toLocaleString, "toLocaleString") \
     macro(toSource, toSource, "toSource") \
     macro(toString, toString, "toString") \
     macro(toUTCString, toUTCString, "toUTCString") \
     macro(true, true_, "true") \
     macro(unescape, unescape, "unescape") \
     macro(uneval, uneval, "uneval") \
+    macro(uint8, uint8, "uint8") \
+    macro(uint8Clamped, uint8Clamped, "uint8Clamped") \
+    macro(uint16, uint16, "uint16") \
+    macro(uint32, uint32, "uint32") \
     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") \
     macro(valueOf, valueOf, "valueOf") \
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -21,17 +21,17 @@ js_InitObjectClass(JSContext *cx, js::Ha
 
 extern JSObject *
 js_InitFunctionClass(JSContext *cx, js::HandleObject obj);
 
 extern JSObject *
 js_InitTypedArrayClasses(JSContext *cx, js::HandleObject obj);
 
 extern JSObject *
-js_InitTypedObjectClasses(JSContext *cx, js::HandleObject obj);
+js_InitTypedObjectClass(JSContext *cx, js::HandleObject obj);
 
 namespace js {
 
 class Debugger;
 
 /*
  * Global object slots are reserved as follows:
  *
@@ -103,19 +103,20 @@ class GlobalObject : public JSObject
     static const unsigned COLLATOR_PROTO          = SET_ITERATOR_PROTO + 1;
     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 FUNCTION_NS             = REGEXP_STATICS + 1;
     static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1;
     static const unsigned DEBUGGERS               = RUNTIME_CODEGEN_ENABLED + 1;
     static const unsigned INTRINSICS              = DEBUGGERS + 1;
+    static const unsigned ARRAY_TYPE              = INTRINSICS + 1;
 
     /* Total reserved-slot count for global objects. */
-    static const unsigned RESERVED_SLOTS = INTRINSICS + 1;
+    static const unsigned RESERVED_SLOTS = ARRAY_TYPE + 1;
 
     void staticAsserts() {
         /*
          * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS,
          * and we aren't going to expose GlobalObject, so just assert that the
          * two values are synchronized.
          */
         JS_STATIC_ASSERT(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS);
@@ -410,41 +411,43 @@ class GlobalObject : public JSObject
     JSObject *getOrCreateIntlObject(JSContext *cx) {
         return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Intl, initIntlObject);
     }
 
     JSObject *getIteratorPrototype() {
         return &getPrototype(JSProto_Iterator).toObject();
     }
 
-    JSObject *getOrCreateDataObject(JSContext *cx) {
-        return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Data, initDataObject);
-    }
-
-    JSObject *getOrCreateTypeObject(JSContext *cx) {
-        return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Type, initTypeObject);
-    }
-
-    JSObject *getOrCreateArrayTypeObject(JSContext *cx) {
-        return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_ArrayTypeObject,
-                                 initArrayTypeObject);
-    }
-
     JSObject *getOrCreateCollatorPrototype(JSContext *cx) {
         return getOrCreateObject(cx, COLLATOR_PROTO, initCollatorProto);
     }
 
     JSObject *getOrCreateNumberFormatPrototype(JSContext *cx) {
         return getOrCreateObject(cx, NUMBER_FORMAT_PROTO, initNumberFormatProto);
     }
 
     JSObject *getOrCreateDateTimeFormatPrototype(JSContext *cx) {
         return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initDateTimeFormatProto);
     }
 
+    JSObject *getArrayType(JSContext *cx) {
+        const Value &v = getReservedSlot(ARRAY_TYPE);
+
+        MOZ_ASSERT(v.isObject(),
+                   "GlobalObject::arrayType must only be called from "
+                   "TypedObject code that can assume TypedObject has "
+                   "been initialized");
+
+        return &v.toObject();
+    }
+
+    void setArrayType(JSObject *obj) {
+        initReservedSlot(ARRAY_TYPE, ObjectValue(*obj));
+    }
+
   private:
     typedef bool (*ObjectInitOp)(JSContext *cx, Handle<GlobalObject*> global);
 
     JSObject *getOrCreateObject(JSContext *cx, unsigned slot, ObjectInitOp init) {
         Value v = getSlotRef(slot);
         if (v.isObject())
             return &v.toObject();
         Rooted<GlobalObject*> self(cx, this);
@@ -564,21 +567,16 @@ class GlobalObject : public JSObject
     static bool initSetIteratorProto(JSContext *cx, Handle<GlobalObject*> global);
 
     // Implemented in Intl.cpp.
     static bool initIntlObject(JSContext *cx, Handle<GlobalObject*> global);
     static bool initCollatorProto(JSContext *cx, Handle<GlobalObject*> global);
     static bool initNumberFormatProto(JSContext *cx, Handle<GlobalObject*> global);
     static bool initDateTimeFormatProto(JSContext *cx, Handle<GlobalObject*> global);
 
-    // Implemented in builtin/TypedObject.cpp
-    static bool initTypeObject(JSContext *cx, Handle<GlobalObject*> global);
-    static bool initDataObject(JSContext *cx, Handle<GlobalObject*> global);
-    static bool initArrayTypeObject(JSContext *cx, Handle<GlobalObject*> global);
-
     static bool initStandardClasses(JSContext *cx, Handle<GlobalObject*> global);
 
     typedef js::Vector<js::Debugger *, 0, js::SystemAllocPolicy> DebuggerVector;
 
     /*
      * The collection of Debugger objects debugging this global. If this global
      * is not a debuggee, this returns either nullptr or an empty vector.
      */