Backed out 4 changesets (bug 973238) for build bustage on a CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Fri, 16 May 2014 13:52:49 -0700
changeset 202847 a1a599888834c784e2db167d9d5aec852862aefe
parent 202846 505f38b0649b153adb70834fb1d1808bfc91d227
child 202848 7dabcbd22f0943f0d40705d644bc2c1577ec7429
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs973238
milestone32.0a1
backs outcc81a0f56362553c66ac50ccb1d41ae7e8352662
472dffac7f217819e028cd3886b09c48d88a7ff7
e40e2dbf7d9e0860ca3e6975cc2722a311aa3484
2ca44eb13ecf1014d45de955afc93bb71b4ac359
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
Backed out 4 changesets (bug 973238) for build bustage on a CLOSED TREE Backed out changeset cc81a0f56362 (bug 973238) Backed out changeset 472dffac7f21 (bug 973238) Backed out changeset e40e2dbf7d9e (bug 973238) Backed out changeset 2ca44eb13ecf (bug 973238)
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/builtin/TypedObject.js
js/src/builtin/TypedObjectConstants.h
js/src/gc/Marking.cpp
js/src/jit-test/tests/TypedObject/prototypes.js
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/IonBuilder.cpp
js/src/jit/LIR-Common.h
js/src/jit/LOpcodes.h
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/ParallelSafetyAnalysis.cpp
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/vm/TypedArrayObject.h
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -817,17 +817,18 @@ js::IsTypedObjectArray(JSObject &obj)
 }
 
 /*********************************
  * StructType class
  */
 
 const Class StructTypeDescr::class_ = {
     "StructType",
-    JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
+    JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) |
+    JSCLASS_HAS_PRIVATE, // used to store FieldList
     JS_PropertyStub,
     JS_DeletePropertyStub,
     JS_PropertyStub,
     JS_StrictPropertyStub,
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub,
     nullptr, /* finalize */
@@ -1478,16 +1479,27 @@ TypedObject::createUnattachedWithClass(J
         return nullptr;
 
     obj->setPrivate(nullptr);
     obj->initReservedSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET, Int32Value(0));
     obj->initReservedSlot(JS_TYPEDOBJ_SLOT_BYTELENGTH, Int32Value(0));
     obj->initReservedSlot(JS_TYPEDOBJ_SLOT_OWNER, NullValue());
     obj->initReservedSlot(JS_TYPEDOBJ_SLOT_NEXT_VIEW, PrivateValue(nullptr));
     obj->initReservedSlot(JS_TYPEDOBJ_SLOT_LENGTH, Int32Value(length));
+    obj->initReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR, ObjectValue(*type));
+
+    // Tag the type object for this instance with the type
+    // representation, if that has not been done already.
+    if (!type->is<SimpleTypeDescr>()) { // FIXME Bug 929651
+        RootedTypeObject typeObj(cx, obj->getType(cx));
+        if (typeObj) {
+            if (!typeObj->addTypedObjectAddendum(cx, type))
+                return nullptr;
+        }
+    }
 
     return static_cast<TypedObject*>(&*obj);
 }
 
 void
 TypedObject::attach(ArrayBufferObject &buffer, int32_t offset)
 {
     JS_ASSERT(offset >= 0);
@@ -1621,16 +1633,19 @@ ReportTypedObjTypeError(JSContext *cx,
 
     JS_free(cx, (void *) typeReprStr);
     return false;
 }
 
 /*static*/ void
 TypedObject::obj_trace(JSTracer *trace, JSObject *object)
 {
+    gc::MarkSlot(trace, &object->getReservedSlotRef(JS_TYPEDOBJ_SLOT_TYPE_DESCR),
+                 "TypedObjectTypeDescr");
+
     ArrayBufferViewObject::trace(trace, object);
 
     JS_ASSERT(object->is<TypedObject>());
     TypedObject &typedObj = object->as<TypedObject>();
     TypeDescr &descr = typedObj.typeDescr();
     if (descr.opaque()) {
         uint8_t *mem = typedObj.typedMem();
         if (!mem)
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -650,22 +650,18 @@ class TypedObject : public ArrayBufferVi
     int32_t offset() const {
         return getReservedSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET).toInt32();
     }
 
     ArrayBufferObject &owner() const {
         return getReservedSlot(JS_TYPEDOBJ_SLOT_OWNER).toObject().as<ArrayBufferObject>();
     }
 
-    TypedProto &typedProto() const {
-        return getProto()->as<TypedProto>();
-    }
-
     TypeDescr &typeDescr() const {
-        return typedProto().typeDescr();
+        return getReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR).toObject().as<TypeDescr>();
     }
 
     uint8_t *typedMem() const {
         return (uint8_t*) getPrivate();
     }
 
     int32_t byteLength() const {
         return getReservedSlot(JS_TYPEDOBJ_SLOT_BYTELENGTH).toInt32();
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -23,39 +23,32 @@
     TO_INT32(UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_SIZED_ARRAY_LENGTH))
 #define DESCR_STRUCT_FIELD_NAMES(obj) \
     UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_NAMES)
 #define DESCR_STRUCT_FIELD_TYPES(obj) \
     UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_TYPES)
 #define DESCR_STRUCT_FIELD_OFFSETS(obj) \
     UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS)
 
-// Typed prototype slots
-
-#define TYPROTO_DESCR(obj) \
-    UnsafeGetReservedSlot(obj, JS_TYPROTO_SLOT_DESCR)
-
 // Typed object slots
 
 #define TYPEDOBJ_BYTEOFFSET(obj) \
     TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_BYTEOFFSET))
 #define TYPEDOBJ_BYTELENGTH(obj) \
     TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_BYTELENGTH))
+#define TYPEDOBJ_TYPE_DESCR(obj) \
+    UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_TYPE_DESCR)
 #define TYPEDOBJ_OWNER(obj) \
     UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_OWNER)
 #define TYPEDOBJ_LENGTH(obj) \
     TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_LENGTH))
 
 #define HAS_PROPERTY(obj, prop) \
     callFunction(std_Object_hasOwnProperty, obj, prop)
 
-function TypedObjectTypeDescr(typedObj) {
-  return TYPROTO_DESCR(typedObj.__proto__);
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Getting values
 //
 // The methods in this section read from the memory pointed at
 // by `this` and produce JS values. This process is called *reification*
 // in the spec.
 
 // Reifies the value referenced by the pointer, meaning that it
@@ -194,17 +187,17 @@ function TypedObjectGetX4(descr, typedOb
 // and works for any type.
 function TypedObjectSet(descr, typedObj, offset, fromValue) {
   assert(TypedObjectIsAttached(typedObj), "set() called with unattached typedObj");
 
   // Fast path: `fromValue` is a typed object with same type
   // representation as the destination. In that case, we can just do a
   // memcpy.
   if (IsObject(fromValue) && ObjectIsTypedObject(fromValue)) {
-    if (!descr.variable && DescrsEquiv(descr, TypedObjectTypeDescr(fromValue))) {
+    if (!descr.variable && DescrsEquiv(descr, TYPEDOBJ_TYPE_DESCR(fromValue))) {
       if (!TypedObjectIsAttached(fromValue))
         ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
 
       var size = DESCR_SIZE(descr);
       Memcpy(typedObj, offset, fromValue, 0, size);
       return;
     }
   }
@@ -388,17 +381,17 @@ function Reify(sourceDescr,
 
   return TypedObjectGet(sourceDescr, sourceTypedObj, sourceOffset);
 }
 
 function FillTypedArrayWithValue(destArray, fromValue) {
   assert(IsObject(handle) && ObjectIsTypedObject(destArray),
          "FillTypedArrayWithValue: not typed handle");
 
-  var descr = TypedObjectTypeDescr(destArray);
+  var descr = TYPEDOBJ_TYPE_DESCR(destArray);
   var length = DESCR_SIZED_ARRAY_LENGTH(descr);
   if (length === 0)
     return;
 
   // Use convert and copy to to produce the first element:
   var elemDescr = DESCR_ARRAY_ELEMENT_TYPE(descr);
   TypedObjectSet(elemDescr, destArray, 0, fromValue);
 
@@ -442,17 +435,17 @@ function TypedArrayRedimension(newArrayT
   if (!IsObject(this) || !ObjectIsTypedObject(this))
     ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   if (!IsObject(newArrayType) || !ObjectIsTypeDescr(newArrayType))
     ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   // Peel away the outermost array layers from the type of `this` to find
   // the core element type. In the process, count the number of elements.
-  var oldArrayType = TypedObjectTypeDescr(this);
+  var oldArrayType = TYPEDOBJ_TYPE_DESCR(this);
   var oldArrayReprKind = DESCR_KIND(oldArrayType);
   var oldElementType = oldArrayType;
   var oldElementCount = 1;
   switch (oldArrayReprKind) {
   case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
     oldElementCount *= this.length;
     oldElementType = oldElementType.elementType;
     break;
@@ -509,17 +502,17 @@ function X4ProtoString(type) {
   assert(false, "Unhandled type constant");
   return undefined;
 }
 
 function X4ToSource() {
   if (!IsObject(this) || !ObjectIsTypedObject(this))
     ThrowError(JSMSG_INCOMPATIBLE_PROTO, "X4", "toSource", typeof this);
 
-  var descr = TypedObjectTypeDescr(this);
+  var descr = TYPEDOBJ_TYPE_DESCR(this);
 
   if (DESCR_KIND(descr) != JS_TYPEREPR_X4_KIND)
     ThrowError(JSMSG_INCOMPATIBLE_PROTO, "X4", "toSource", typeof this);
 
   var type = DESCR_TYPE(descr);
   return X4ProtoString(type)+"("+this.x+", "+this.y+", "+this.z+", "+this.w+")";
 }
 
@@ -587,17 +580,17 @@ function StorageOfTypedObject(obj) {
 }
 
 // This is the `objectType()` function defined in the spec.
 // It returns the type of its argument.
 //
 // Warning: user exposed!
 function TypeOfTypedObject(obj) {
   if (IsObject(obj) && ObjectIsTypedObject(obj))
-    return TypedObjectTypeDescr(obj);
+    return TYPEDOBJ_TYPE_DESCR(obj);
 
   // Note: Do not create bindings for `Any`, `String`, etc in
   // Utilities.js, but rather access them through
   // `GetTypedObjectModule()`. The reason is that bindings
   // you create in Utilities.js are part of the self-hosted global,
   // vs the user-accessible global, and hence should not escape to
   // user script.
   var T = GetTypedObjectModule();
@@ -681,17 +674,17 @@ function TypedObjectArrayTypeFrom(a, b, 
       return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
   }
 }
 
 // Warning: user exposed!
 function TypedArrayMap(a, b) {
   if (!IsObject(this) || !ObjectIsTypedObject(this))
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
-  var thisType = TypedObjectTypeDescr(this);
+  var thisType = TYPEDOBJ_TYPE_DESCR(this);
   if (!TypeDescrIsArrayType(thisType))
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   // Arguments: [depth], func
   if (typeof a === "number" && typeof b === "function")
     return MapTypedSeqImpl(this, a, thisType, b);
   else if (typeof a === "function")
     return MapTypedSeqImpl(this, 1, thisType, a);
@@ -701,49 +694,49 @@ function TypedArrayMap(a, b) {
 // Warning: user exposed!
 function TypedArrayMapPar(a, b) {
   // Arguments: [depth], func
 
   // Defer to the sequential variant for error cases or
   // when not working with typed objects.
   if (!IsObject(this) || !ObjectIsTypedObject(this))
     return callFunction(TypedArrayMap, this, a, b);
-  var thisType = TypedObjectTypeDescr(this);
+  var thisType = TYPEDOBJ_TYPE_DESCR(this);
   if (!TypeDescrIsArrayType(thisType))
     return callFunction(TypedArrayMap, this, a, b);
 
   if (typeof a === "number" && IsCallable(b))
     return MapTypedParImpl(this, a, thisType, b);
   else if (IsCallable(a))
     return MapTypedParImpl(this, 1, thisType, a);
   return callFunction(TypedArrayMap, this, a, b);
 }
 
 // Warning: user exposed!
 function TypedArrayReduce(a, b) {
   // Arguments: func, [initial]
   if (!IsObject(this) || !ObjectIsTypedObject(this))
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
-  var thisType = TypedObjectTypeDescr(this);
+  var thisType = TYPEDOBJ_TYPE_DESCR(this);
   if (!TypeDescrIsArrayType(thisType))
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   if (a !== undefined && typeof a !== "function")
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   var outputType = thisType.elementType;
   return ReduceTypedSeqImpl(this, outputType, a, b);
 }
 
 // Warning: user exposed!
 function TypedArrayScatter(a, b, c, d) {
   // Arguments: outputArrayType, indices, defaultValue, conflictFunction
   if (!IsObject(this) || !ObjectIsTypedObject(this))
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
-  var thisType = TypedObjectTypeDescr(this);
+  var thisType = TYPEDOBJ_TYPE_DESCR(this);
   if (!TypeDescrIsArrayType(thisType))
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   if (!IsObject(a) || !ObjectIsTypeDescr(a) || !TypeDescrIsSizedArrayType(a))
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   if (d !== undefined && typeof d !== "function")
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
@@ -751,17 +744,17 @@ function TypedArrayScatter(a, b, c, d) {
   return ScatterTypedSeqImpl(this, a, b, c, d);
 }
 
 // Warning: user exposed!
 function TypedArrayFilter(func) {
   // Arguments: predicate
   if (!IsObject(this) || !ObjectIsTypedObject(this))
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
-  var thisType = TypedObjectTypeDescr(this);
+  var thisType = TYPEDOBJ_TYPE_DESCR(this);
   if (!TypeDescrIsArrayType(thisType))
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   if (typeof func !== "function")
     return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 
   return FilterTypedSeqImpl(this, func);
 }
@@ -1134,17 +1127,17 @@ function RedirectPointer(typedObj, offse
     // Therefore, we reuse a pointer if we are both in parallel mode
     // and we have a transparent output type.  It'd be nice to loosen
     // this condition later by using fancy ion optimizations that
     // assume the value won't escape and copy it if it does. But those
     // don't exist yet. Moreover, checking if the type is transparent
     // is an overapproximation: users can manually declare opaque
     // types that nonetheless only contain scalar data.
 
-    typedObj = NewDerivedTypedObject(TypedObjectTypeDescr(typedObj),
+    typedObj = NewDerivedTypedObject(TYPEDOBJ_TYPE_DESCR(typedObj),
                                      typedObj, 0);
   }
 
   SetTypedObjectOffset(typedObj, offset);
   return typedObj;
 }
 SetScriptHints(RedirectPointer,         { inline: true });
 
--- a/js/src/builtin/TypedObjectConstants.h
+++ b/js/src/builtin/TypedObjectConstants.h
@@ -94,17 +94,17 @@
 #define JS_TYPEDOBJ_SLOT_BYTEOFFSET       0
 #define JS_TYPEDOBJ_SLOT_BYTELENGTH       1
 #define JS_TYPEDOBJ_SLOT_OWNER            2
 #define JS_TYPEDOBJ_SLOT_NEXT_VIEW        3
 
 #define JS_DATAVIEW_SLOTS              4 // Number of slots for data views
 
 #define JS_TYPEDOBJ_SLOT_LENGTH           4 // Length of array (see (*) below)
-#define JS_TYPEDARR_SLOT_TYPE             5 // For typed arrays only, type code
+#define JS_TYPEDOBJ_SLOT_TYPE_DESCR       5 // For typed objects, type descr
 
 #define JS_TYPEDOBJ_SLOT_DATA             7 // private slot, based on alloc kind
 #define JS_TYPEDOBJ_SLOTS                 6 // Number of slots for typed objs
 
 // (*) The JS_TYPEDOBJ_SLOT_LENGTH slot stores the length for typed objects of
 // sized and unsized array type. The slot contains 0 for non-arrays.
 // The slot also contains 0 for *unattached* typed objects, no matter what
 // type they have.
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1254,16 +1254,18 @@ ScanTypeObject(GCMarker *gcmarker, types
         PushMarkStack(gcmarker, type->proto().toObject());
 
     if (type->singleton() && !type->lazy())
         PushMarkStack(gcmarker, type->singleton());
 
     if (type->hasNewScript()) {
         PushMarkStack(gcmarker, type->newScript()->fun);
         PushMarkStack(gcmarker, type->newScript()->templateObject);
+    } else if (type->hasTypedObject()) {
+        PushMarkStack(gcmarker, type->typedObject()->descrHeapPtr());
     }
 
     if (type->interpretedFunction)
         PushMarkStack(gcmarker, type->interpretedFunction);
 }
 
 static void
 gc::MarkChildren(JSTracer *trc, types::TypeObject *type)
@@ -1279,16 +1281,18 @@ gc::MarkChildren(JSTracer *trc, types::T
         MarkObject(trc, &type->protoRaw(), "type_proto");
 
     if (type->singleton() && !type->lazy())
         MarkObject(trc, &type->singletonRaw(), "type_singleton");
 
     if (type->hasNewScript()) {
         MarkObject(trc, &type->newScript()->fun, "type_new_function");
         MarkObject(trc, &type->newScript()->templateObject, "type_new_template");
+    } else if (type->hasTypedObject()) {
+        MarkObject(trc, &type->typedObject()->descrHeapPtr(), "type_heap_ptr");
     }
 
     if (type->interpretedFunction)
         MarkObject(trc, &type->interpretedFunction, "type_function");
 }
 
 static void
 gc::MarkChildren(JSTracer *trc, jit::JitCode *code)
--- a/js/src/jit-test/tests/TypedObject/prototypes.js
+++ b/js/src/jit-test/tests/TypedObject/prototypes.js
@@ -1,33 +1,22 @@
 // API Surface Test: check that mutating prototypes
-// of type objects has no effect, and that mutating
-// the prototypes of typed objects is an error.
+// of type descriptors has no effect.
 
 if (!this.hasOwnProperty("TypedObject"))
   quit();
 
-load(libdir + "asserts.js");
-
 var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
 
 function main() { // once a C programmer, always a C programmer.
   var Uints = new StructType({f: uint32, g: uint32});
   var p = Uints.prototype;
   Uints.prototype = {}; // no effect
   assertEq(p, Uints.prototype);
 
-  var uints = new Uints();
-  assertEq(uints.__proto__, p);
-  assertThrowsInstanceOf(function() uints.__proto__ = {},
-                         TypeError);
-  assertThrowsInstanceOf(function() Object.setPrototypeOf(uints, {}),
-                         TypeError);
-  assertEq(uints.__proto__, p);
-
   var Uintss = Uints.array(2);
   var p = Uintss.prototype;
   Uintss.prototype = {}; // no effect
   assertEq(p, Uintss.prototype);
 
   print("Tests complete");
 }
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4302,33 +4302,16 @@ CodeGenerator::visitNeuterCheck(LNeuterC
     Imm32 flag(ArrayBufferObject::neuteredFlag());
     if (!bailoutTest32(Assembler::NonZero, temp, flag, lir->snapshot()))
         return false;
 
     return true;
 }
 
 bool
-CodeGenerator::visitTypedObjectProto(LTypedObjectProto *lir)
-{
-    Register obj = ToRegister(lir->object());
-    JS_ASSERT(ToRegister(lir->output()) == ReturnReg);
-
-    // Eventually we ought to inline this helper function for
-    // efficiency, but it's mildly non-trivial since we must reach
-    // into the type object and so on.
-
-    const Register tempReg = ToRegister(lir->temp());
-    masm.setupUnalignedABICall(1, tempReg);
-    masm.passABIArg(obj);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, TypedObjectProto));
-    return true;
-}
-
-bool
 CodeGenerator::visitTypedObjectElements(LTypedObjectElements *lir)
 {
     Register obj = ToRegister(lir->object());
     Register out = ToRegister(lir->output());
     masm.loadPtr(Address(obj, TypedObject::offsetOfDataSlot()), out);
     return true;
 }
 
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -166,17 +166,16 @@ class CodeGenerator : public CodeGenerat
     bool visitLoadArrowThis(LLoadArrowThis *lir);
     bool visitArrayLength(LArrayLength *lir);
     bool visitSetArrayLength(LSetArrayLength *lir);
     bool visitTypedArrayLength(LTypedArrayLength *lir);
     bool visitTypedArrayElements(LTypedArrayElements *lir);
     bool visitNeuterCheck(LNeuterCheck *lir);
     bool visitTypedObjectElements(LTypedObjectElements *lir);
     bool visitSetTypedObjectOffset(LSetTypedObjectOffset *lir);
-    bool visitTypedObjectProto(LTypedObjectProto *ins);
     bool visitStringLength(LStringLength *lir);
     bool visitInitializedLength(LInitializedLength *lir);
     bool visitSetInitializedLength(LSetInitializedLength *lir);
     bool visitNotO(LNotO *ins);
     bool visitNotV(LNotV *ins);
     bool visitBoundsCheck(LBoundsCheck *lir);
     bool visitBoundsCheckRange(LBoundsCheckRange *lir);
     bool visitBoundsCheckLower(LBoundsCheckLower *lir);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -10245,56 +10245,44 @@ IonBuilder::typeSetToTypeDescrSet(types:
 
     // And only known objects.
     if (types->unknownObject())
         return true;
 
     TypeDescrSetBuilder set;
     for (uint32_t i = 0; i < types->getObjectCount(); i++) {
         types::TypeObject *type = types->getTypeObject(i);
-        if (!type)
-            return true;
-
-        if (!IsTypedObjectClass(type->clasp()))
+        if (!type || type->unknownProperties())
             return true;
 
-        TaggedProto proto = type->proto();
-
-        // typed objects have immutable prototypes, and they are
-        // always instances of TypedProto
-        JS_ASSERT(proto.isObject() && proto.toObject()->is<TypedProto>());
-
-        TypedProto &typedProto = proto.toObject()->as<TypedProto>();
-        if (!set.insert(&typedProto.typeDescr()))
+        if (!type->hasTypedObject())
+            return true;
+
+        TypeDescr &descr = type->typedObject()->descr();
+        if (!set.insert(&descr))
             return false;
     }
 
     return set.build(*this, out);
 }
 
 MDefinition *
 IonBuilder::loadTypedObjectType(MDefinition *typedObj)
 {
     // Shortcircuit derived type objects, meaning the intermediate
     // objects created to represent `a.b` in an expression like
     // `a.b.c`. In that case, the type object can be simply pulled
     // from the operands of that instruction.
     if (typedObj->isNewDerivedTypedObject())
         return typedObj->toNewDerivedTypedObject()->type();
 
-    MInstruction *proto = MTypedObjectProto::New(alloc(), typedObj);
-    current->add(proto);
-
-    MInstruction *load = MLoadFixedSlot::New(alloc(), proto, JS_TYPROTO_SLOT_DESCR);
+    MInstruction *load = MLoadFixedSlot::New(alloc(), typedObj,
+                                             JS_TYPEDOBJ_SLOT_TYPE_DESCR);
     current->add(load);
-
-    MInstruction *unbox = MUnbox::New(alloc(), load, MIRType_Object, MUnbox::Infallible);
-    current->add(unbox);
-
-    return unbox;
+    return load;
 }
 
 // Given a typed object `typedObj` and an offset `offset` into that
 // object's data, returns another typed object and adusted offset
 // where the data can be found. Often, these returned values are the
 // same as the inputs, but in cases where intermediate derived type
 // objects have been created, the return values will remove
 // intermediate layers (often rendering those derived type objects
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -3689,35 +3689,16 @@ class LTypedArrayElements : public LInst
     LTypedArrayElements(const LAllocation &object) {
         setOperand(0, object);
     }
     const LAllocation *object() {
         return getOperand(0);
     }
 };
 
-// Load a typed object's prototype, which is guaranteed to be a
-// TypedProto object.
-class LTypedObjectProto : public LCallInstructionHelper<1, 1, 1>
-{
-  public:
-    LIR_HEADER(TypedObjectProto)
-
-    LTypedObjectProto(const LAllocation &object, const LDefinition &temp1) {
-        setOperand(0, object);
-        setTemp(0, temp1);
-    }
-    const LAllocation *object() {
-        return getOperand(0);
-    }
-    const LDefinition *temp() {
-        return getTemp(0);
-    }
-};
-
 // Load a typed array's elements vector.
 class LTypedObjectElements : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(TypedObjectElements)
 
     LTypedObjectElements(const LAllocation &object) {
         setOperand(0, object);
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -245,17 +245,16 @@
     _(IteratorStart)                \
     _(IteratorNext)                 \
     _(IteratorMore)                 \
     _(IteratorEnd)                  \
     _(ArrayLength)                  \
     _(SetArrayLength)               \
     _(TypedArrayLength)             \
     _(TypedArrayElements)           \
-    _(TypedObjectProto)             \
     _(TypedObjectElements)          \
     _(SetTypedObjectOffset)         \
     _(StringLength)                 \
     _(ArgumentsLength)              \
     _(GetFrameArgument)             \
     _(SetFrameArgumentT)            \
     _(SetFrameArgumentC)            \
     _(SetFrameArgumentV)            \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2357,26 +2357,16 @@ LIRGenerator::visitTypedArrayLength(MTyp
 bool
 LIRGenerator::visitTypedArrayElements(MTypedArrayElements *ins)
 {
     JS_ASSERT(ins->type() == MIRType_Elements);
     return define(new(alloc()) LTypedArrayElements(useRegisterAtStart(ins->object())), ins);
 }
 
 bool
-LIRGenerator::visitTypedObjectProto(MTypedObjectProto *ins)
-{
-    JS_ASSERT(ins->type() == MIRType_Object);
-    return defineReturn(new(alloc()) LTypedObjectProto(
-                            useFixed(ins->object(), CallTempReg0),
-                            tempFixed(CallTempReg1)),
-                        ins);
-}
-
-bool
 LIRGenerator::visitTypedObjectElements(MTypedObjectElements *ins)
 {
     JS_ASSERT(ins->type() == MIRType_Elements);
     return define(new(alloc()) LTypedObjectElements(useRegisterAtStart(ins->object())), ins);
 }
 
 bool
 LIRGenerator::visitSetTypedObjectOffset(MSetTypedObjectOffset *ins)
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -177,17 +177,16 @@ class LIRGenerator : public LIRGenerator
     bool visitPostWriteBarrier(MPostWriteBarrier *ins);
     bool visitArrayLength(MArrayLength *ins);
     bool visitSetArrayLength(MSetArrayLength *ins);
     bool visitTypedArrayLength(MTypedArrayLength *ins);
     bool visitTypedArrayElements(MTypedArrayElements *ins);
     bool visitNeuterCheck(MNeuterCheck *lir);
     bool visitTypedObjectElements(MTypedObjectElements *ins);
     bool visitSetTypedObjectOffset(MSetTypedObjectOffset *ins);
-    bool visitTypedObjectProto(MTypedObjectProto *ins);
     bool visitInitializedLength(MInitializedLength *ins);
     bool visitSetInitializedLength(MSetInitializedLength *ins);
     bool visitNot(MNot *ins);
     bool visitBoundsCheck(MBoundsCheck *ins);
     bool visitBoundsCheckLower(MBoundsCheckLower *ins);
     bool visitLoadElement(MLoadElement *ins);
     bool visitLoadElementHole(MLoadElementHole *ins);
     bool visitStoreElement(MStoreElement *ins);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1612,49 +1612,16 @@ class MNewPar : public MUnaryInstruction
         return getOperand(0);
     }
 
     JSObject *templateObject() const {
         return templateObject_;
     }
 };
 
-class MTypedObjectProto
-  : public MUnaryInstruction,
-    public SingleObjectPolicy
-{
-  private:
-    MTypedObjectProto(MDefinition *object)
-      : MUnaryInstruction(object)
-    {
-        setResultType(MIRType_Object);
-        setMovable();
-    }
-
-  public:
-    INSTRUCTION_HEADER(TypedObjectProto)
-
-    static MTypedObjectProto *New(TempAllocator &alloc, MDefinition *object) {
-        return new(alloc) MTypedObjectProto(object);
-    }
-
-    TypePolicy *typePolicy() {
-        return this;
-    }
-    MDefinition *object() const {
-        return getOperand(0);
-    }
-    bool congruentTo(const MDefinition *ins) const {
-        return congruentIfOperandsEqual(ins);
-    }
-    AliasSet getAliasSet() const {
-        return AliasSet::Load(AliasSet::ObjectFields);
-    }
-};
-
 // Creates a new derived type object. At runtime, this is just a call
 // to `BinaryBlock::createDerived()`. That is, the MIR itself does not
 // compile to particularly optimized code. However, using a distinct
 // MIR for creating derived type objects allows the compiler to
 // optimize ephemeral typed objects as would be created for a
 // reference like `a.b.c` -- here, the `a.b` will create an ephemeral
 // derived type object that aliases the memory of `a` itself. The
 // specific nature of `a.b` is revealed by using
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -131,17 +131,16 @@ namespace jit {
     _(GuardShapePolymorphic)                                                \
     _(GuardObjectType)                                                      \
     _(GuardObjectIdentity)                                                  \
     _(GuardClass)                                                           \
     _(ArrayLength)                                                          \
     _(SetArrayLength)                                                       \
     _(TypedArrayLength)                                                     \
     _(TypedArrayElements)                                                   \
-    _(TypedObjectProto)                                                     \
     _(TypedObjectElements)                                                  \
     _(SetTypedObjectOffset)                                                 \
     _(InitializedLength)                                                    \
     _(SetInitializedLength)                                                 \
     _(Not)                                                                  \
     _(NeuterCheck)                                                          \
     _(BoundsCheck)                                                          \
     _(BoundsCheckLower)                                                     \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -219,17 +219,16 @@ class ParallelSafetyVisitor : public MIn
     SAFE_OP(GuardObjectType)
     SAFE_OP(GuardObjectIdentity)
     SAFE_OP(GuardClass)
     SAFE_OP(AssertRange)
     SAFE_OP(ArrayLength)
     WRITE_GUARDED_OP(SetArrayLength, elements)
     SAFE_OP(TypedArrayLength)
     SAFE_OP(TypedArrayElements)
-    SAFE_OP(TypedObjectProto)
     SAFE_OP(TypedObjectElements)
     SAFE_OP(SetTypedObjectOffset)
     SAFE_OP(InitializedLength)
     WRITE_GUARDED_OP(SetInitializedLength, elements)
     SAFE_OP(Not)
     SAFE_OP(NeuterCheck)
     SAFE_OP(BoundsCheck)
     SAFE_OP(BoundsCheckLower)
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1150,19 +1150,10 @@ AssertValidValue(JSContext *cx, Value *v
     }
     if (v->isString()) {
         AssertValidStringPtr(cx, v->toString());
         return;
     }
 }
 #endif
 
-// Definition of the MTypedObjectProto MIR.
-JSObject *
-TypedObjectProto(JSObject *obj)
-{
-    JS_ASSERT(obj->is<TypedObject>());
-    TypedObject &typedObj = obj->as<TypedObject>();
-    return &typedObj.typedProto();
-}
-
 } // namespace jit
 } // namespace js
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -685,14 +685,12 @@ bool SetDenseElement(JSContext *cx, Hand
                      bool strict);
 
 #ifdef DEBUG
 void AssertValidObjectPtr(JSContext *cx, JSObject *obj);
 void AssertValidStringPtr(JSContext *cx, JSString *str);
 void AssertValidValue(JSContext *cx, Value *v);
 #endif
 
-JSObject *TypedObjectProto(JSObject *obj);
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_VMFunctions_h */
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3035,39 +3035,16 @@ TypeObject::markUnknown(ExclusiveContext
         if (prop) {
             prop->types.addType(cx, Type::UnknownType());
             prop->types.setNonDataProperty(cx);
         }
     }
 }
 
 void
-TypeObject::maybeClearNewScriptAddendumOnOOM()
-{
-    if (!isMarked())
-        return;
-
-    if (!addendum || addendum->kind != TypeObjectAddendum::NewScript)
-        return;
-
-    for (unsigned i = 0; i < getPropertyCount(); i++) {
-        Property *prop = getProperty(i);
-        if (!prop)
-            continue;
-        if (prop->types.definiteProperty())
-            prop->types.setNonDataPropertyIgnoringConstraints();
-    }
-
-    // This method is called during GC sweeping, so there is no write barrier
-    // that needs to be triggered.
-    js_free(addendum);
-    addendum.unsafeSet(nullptr);
-}
-
-void
 TypeObject::clearAddendum(ExclusiveContext *cx)
 {
     JS_ASSERT(!(flags() & OBJECT_FLAG_ADDENDUM_CLEARED));
 
     addFlags(OBJECT_FLAG_ADDENDUM_CLEARED);
 
     /*
      * It is possible for the object to not have a new script or other
@@ -3081,16 +3058,20 @@ TypeObject::clearAddendum(ExclusiveConte
      */
     if (!addendum)
         return;
 
     switch (addendum->kind) {
       case TypeObjectAddendum::NewScript:
         clearNewScriptAddendum(cx);
         break;
+
+      case TypeObjectAddendum::TypedObject:
+        clearTypedObjectAddendum(cx);
+        break;
     }
 
     /* We nullptr out addendum *before* freeing it so the write barrier works. */
     TypeObjectAddendum *savedAddendum = addendum;
     addendum = nullptr;
     js_free(savedAddendum);
 
     markStateChange(cx);
@@ -3196,16 +3177,44 @@ TypeObject::clearNewScriptAddendum(Exclu
         }
     } else {
         // Threads with an ExclusiveContext are not allowed to run scripts.
         JS_ASSERT(!cx->perThreadData->activation());
     }
 }
 
 void
+TypeObject::maybeClearNewScriptAddendumOnOOM()
+{
+    if (!isMarked())
+        return;
+
+    if (!addendum || addendum->kind != TypeObjectAddendum::NewScript)
+        return;
+
+    for (unsigned i = 0; i < getPropertyCount(); i++) {
+        Property *prop = getProperty(i);
+        if (!prop)
+            continue;
+        if (prop->types.definiteProperty())
+            prop->types.setNonDataPropertyIgnoringConstraints();
+    }
+
+    // This method is called during GC sweeping, so there is no write barrier
+    // that needs to be triggered.
+    js_free(addendum);
+    addendum.unsafeSet(nullptr);
+}
+
+void
+TypeObject::clearTypedObjectAddendum(ExclusiveContext *cx)
+{
+}
+
+void
 TypeObject::print()
 {
     TaggedProto tagged(proto());
     fprintf(stderr, "%s : %s",
             TypeObjectString(this),
             tagged.isObject() ? TypeString(Type::ObjectType(tagged.toObject()))
                               : (tagged.isLazy() ? "(lazy)" : "(null)"));
 
@@ -4546,22 +4555,67 @@ TypeScript::printTypes(JSContext *cx, Ha
             fprintf(stderr, "\n");
         }
     }
 
     fprintf(stderr, "\n");
 }
 #endif /* DEBUG */
 
+/////////////////////////////////////////////////////////////////////
+// Binary data
+/////////////////////////////////////////////////////////////////////
+
 void
 TypeObject::setAddendum(TypeObjectAddendum *addendum)
 {
     this->addendum = addendum;
 }
 
+bool
+TypeObject::addTypedObjectAddendum(JSContext *cx, Handle<TypeDescr*> descr)
+{
+    // Type descriptors are always pre-tenured. This is both because
+    // we expect them to live a long time and so that they can be
+    // safely accessed during ion compilation.
+    JS_ASSERT(!IsInsideNursery(cx->runtime(), descr));
+    JS_ASSERT(descr);
+
+    if (flags() & OBJECT_FLAG_ADDENDUM_CLEARED)
+        return true;
+
+    JS_ASSERT(!unknownProperties());
+
+    if (addendum) {
+        JS_ASSERT(hasTypedObject());
+        JS_ASSERT(&typedObject()->descr() == descr);
+        return true;
+    }
+
+    TypeTypedObject *typedObject = js_new<TypeTypedObject>(descr);
+    if (!typedObject)
+        return false;
+    addendum = typedObject;
+    return true;
+}
+
+/////////////////////////////////////////////////////////////////////
+// Type object addenda constructor
+/////////////////////////////////////////////////////////////////////
+
 TypeObjectAddendum::TypeObjectAddendum(Kind kind)
   : kind(kind)
 {}
 
 TypeNewScript::TypeNewScript()
   : TypeObjectAddendum(NewScript)
 {}
 
+TypeTypedObject::TypeTypedObject(Handle<TypeDescr*> descr)
+  : TypeObjectAddendum(TypedObject),
+    descr_(descr)
+{
+}
+
+TypeDescr &
+js::types::TypeTypedObject::descr() {
+    return descr_->as<TypeDescr>();
+}
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -807,36 +807,47 @@ struct Property
       : id(o.id.get()), types(o.types)
     {}
 
     static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); }
     static jsid getKey(Property *p) { return p->id; }
 };
 
 struct TypeNewScript;
+struct TypeTypedObject;
 
 struct TypeObjectAddendum
 {
     enum Kind {
-        NewScript
+        NewScript,
+        TypedObject
     };
 
     TypeObjectAddendum(Kind kind);
 
     const Kind kind;
 
     bool isNewScript() {
         return kind == NewScript;
     }
 
     TypeNewScript *asNewScript() {
         JS_ASSERT(isNewScript());
         return (TypeNewScript*) this;
     }
 
+    bool isTypedObject() {
+        return kind == TypedObject;
+    }
+
+    TypeTypedObject *asTypedObject() {
+        JS_ASSERT(isTypedObject());
+        return (TypeTypedObject*) this;
+    }
+
     static inline void writeBarrierPre(TypeObjectAddendum *type);
 
     static void writeBarrierPost(TypeObjectAddendum *newScript, void *addr) {}
 };
 
 /*
  * Information attached to a TypeObject if it is always constructed using 'new'
  * on a particular script. This is used to manage state related to the definite
@@ -883,16 +894,31 @@ struct TypeNewScript : public TypeObject
           : kind(kind), offset(offset)
         {}
     };
     Initializer *initializerList;
 
     static inline void writeBarrierPre(TypeNewScript *newScript);
 };
 
+struct TypeTypedObject : public TypeObjectAddendum
+{
+  private:
+    HeapPtrObject descr_;
+
+  public:
+    TypeTypedObject(Handle<TypeDescr*> descr);
+
+    HeapPtrObject &descrHeapPtr() {
+        return descr_;
+    }
+
+    TypeDescr &descr();
+};
+
 /*
  * Lazy type objects overview.
  *
  * Type objects which represent at most one JS object are constructed lazily.
  * These include types for native functions, standard classes, scripted
  * functions defined at the top level of global/eval scripts, and in some
  * other cases. Typical web workloads often create many windows (and many
  * copies of standard natives) and many scripts, with comparatively few
@@ -996,18 +1022,35 @@ struct TypeObject : gc::BarrieredCell<Ty
     bool hasNewScript() const {
         return addendum && addendum->isNewScript();
     }
 
     TypeNewScript *newScript() {
         return addendum->asNewScript();
     }
 
+    bool hasTypedObject() {
+        return addendum && addendum->isTypedObject();
+    }
+
+    TypeTypedObject *typedObject() {
+        return addendum->asTypedObject();
+    }
+
     void setAddendum(TypeObjectAddendum *addendum);
 
+    /*
+     * Tag the type object for a binary data type descriptor, instance,
+     * or handle with the type representation of the data it points at.
+     * If this type object is already tagged with a binary data addendum,
+     * this addendum must already be associated with the same TypeRepresentation,
+     * and the method has no effect.
+     */
+    bool addTypedObjectAddendum(JSContext *cx, Handle<TypeDescr*> descr);
+
   private:
     /*
      * Properties of this object. This may contain JSID_VOID, representing the
      * types of all integer indexes of the object, and/or JSID_EMPTY, holding
      * constraints listening to changes to the object's state.
      *
      * The type sets in the properties of a type object describe the possible
      * values that can be read out of that property in actual JS objects.
@@ -1109,19 +1152,20 @@ struct TypeObject : gc::BarrieredCell<Ty
     void addPrototype(JSContext *cx, TypeObject *proto);
     void addPropertyType(ExclusiveContext *cx, jsid id, Type type);
     void addPropertyType(ExclusiveContext *cx, jsid id, const Value &value);
     void markPropertyNonData(ExclusiveContext *cx, jsid id);
     void markPropertyNonWritable(ExclusiveContext *cx, jsid id);
     void markStateChange(ExclusiveContext *cx);
     void setFlags(ExclusiveContext *cx, TypeObjectFlags flags);
     void markUnknown(ExclusiveContext *cx);
-    void maybeClearNewScriptAddendumOnOOM();
     void clearAddendum(ExclusiveContext *cx);
     void clearNewScriptAddendum(ExclusiveContext *cx);
+    void clearTypedObjectAddendum(ExclusiveContext *cx);
+    void maybeClearNewScriptAddendumOnOOM();
     bool isPropertyNonData(jsid id);
     bool isPropertyNonWritable(jsid id);
 
     void print();
 
     inline void clearProperties();
     inline void sweep(FreeOp *fop, bool *oom);
 
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -1219,16 +1219,19 @@ TypeObjectAddendum::writeBarrierPre(Type
 {
 #ifdef JSGC_INCREMENTAL
     if (!type)
         return;
 
     switch (type->kind) {
       case NewScript:
         return TypeNewScript::writeBarrierPre(type->asNewScript());
+
+      case TypedObject:
+        return TypeTypedObject::writeBarrierPre(type->asTypedObject());
     }
 #endif
 }
 
 inline void
 TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
 {
 #ifdef JSGC_INCREMENTAL
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -27,17 +27,17 @@ namespace js {
  */
 
 class TypedArrayObject : public ArrayBufferViewObject
 {
   protected:
     // Typed array properties stored in slots, beyond those shared by all
     // ArrayBufferViews.
     static const size_t LENGTH_SLOT    = JS_TYPEDOBJ_SLOT_LENGTH;
-    static const size_t TYPE_SLOT      = JS_TYPEDARR_SLOT_TYPE;
+    static const size_t TYPE_SLOT      = JS_TYPEDOBJ_SLOT_TYPE_DESCR;
     static const size_t RESERVED_SLOTS = JS_TYPEDOBJ_SLOTS;
     static const size_t DATA_SLOT      = JS_TYPEDOBJ_SLOT_DATA;
 
   public:
     static const Class classes[ScalarTypeDescr::TYPE_MAX];
     static const Class protoClasses[ScalarTypeDescr::TYPE_MAX];
 
     static const size_t FIXED_DATA_START = DATA_SLOT + 1;