Bug 966575 part 02 - Migrate away from accessing TypeRepresentation directly r=sfink
authorNicholas D. Matsakis <nmatsakis@mozilla.com>
Mon, 27 Jan 2014 18:54:07 -0500
changeset 168098 9ef576b3af3f7fc416a6a1fa6c08ba7f859b3fd3
parent 168097 1a05d8dffc6541b985d4495bacc41d87303031f9
child 168099 3a68d8735fcade66c2744f51401a35a7cc39c240
push id39654
push usernmatsakis@mozilla.com
push dateTue, 11 Feb 2014 19:39:16 +0000
treeherdermozilla-inbound@2ab85f86868a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs966575
milestone30.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 966575 part 02 - Migrate away from accessing TypeRepresentation directly r=sfink
js/src/builtin/SIMD.cpp
js/src/builtin/TypeRepresentation.cpp
js/src/builtin/TypeRepresentation.h
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/builtin/TypedObject.js
js/src/tests/ecma_6/TypedObject/structtypereflection.js
js/src/vm/CommonPropertyNames.h
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -128,17 +128,17 @@ class Float32x4Defn {
     static const X4TypeRepresentation::Type type = X4TypeRepresentation::TYPE_FLOAT32;
     static const JSFunctionSpec TypeDescriptorMethods[];
     static const JSPropertySpec TypedDatumProperties[];
     static const JSFunctionSpec TypedDatumMethods[];
 };
 } // namespace js
 
 const JSFunctionSpec js::Float32x4Defn::TypeDescriptorMethods[] = {
-    JS_FN("toSource", TypeDescrToSource, 0, 0),
+    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
     JS_SELF_HOSTED_FN("handle", "HandleCreate", 2, 0),
     JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
     JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
     JS_FS_END
 };
 
 const JSPropertySpec js::Float32x4Defn::TypedDatumProperties[] = {
     JS_PSG("x", Float32x4Lane0, JSPROP_PERMANENT),
@@ -150,17 +150,17 @@ const JSPropertySpec js::Float32x4Defn::
 };
 
 const JSFunctionSpec js::Float32x4Defn::TypedDatumMethods[] = {
     JS_SELF_HOSTED_FN("toSource", "X4ToSource", 0, 0),
     JS_FS_END
 };
 
 const JSFunctionSpec js::Int32x4Defn::TypeDescriptorMethods[] = {
-    JS_FN("toSource", TypeDescrToSource, 0, 0),
+    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
     JS_SELF_HOSTED_FN("handle", "HandleCreate", 2, 0),
     JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
     JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
     JS_FS_END,
 };
 
 const JSPropertySpec js::Int32x4Defn::TypedDatumProperties[] = {
     JS_PSG("x", Int32x4Lane0, JSPROP_PERMANENT),
--- a/js/src/builtin/TypeRepresentation.cpp
+++ b/js/src/builtin/TypeRepresentation.cpp
@@ -684,173 +684,38 @@ TypeRepresentation::obj_finalize(js::Fre
     TypeRepresentation *typeRepr = fromOwnerObject(*object);
     comp->typeReprs.remove(typeRepr);
     js_free(typeRepr);
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // To string
 
-bool
-TypeRepresentation::appendString(JSContext *cx, StringBuffer &contents)
-{
-    switch (kind()) {
-      case Scalar:
-        return asScalar()->appendStringScalar(cx, contents);
-
-      case Reference:
-        return asReference()->appendStringReference(cx, contents);
-
-      case X4:
-        return asX4()->appendStringX4(cx, contents);
-
-      case SizedArray:
-        return asSizedArray()->appendStringSizedArray(cx, contents);
-
-      case UnsizedArray:
-        return asUnsizedArray()->appendStringUnsizedArray(cx, contents);
-
-      case Struct:
-        return asStruct()->appendStringStruct(cx, contents);
-    }
-
-    MOZ_ASSUME_UNREACHABLE("Invalid kind");
-    return false;
-}
-
 /*static*/ const char *
 ScalarTypeRepresentation::typeName(Type type)
 {
     switch (type) {
 #define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
         case constant_: return #name_;
         JS_FOR_EACH_SCALAR_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
     }
     MOZ_ASSUME_UNREACHABLE("Invalid type");
 }
 
-bool
-ScalarTypeRepresentation::appendStringScalar(JSContext *cx, StringBuffer &contents)
-{
-    switch (type()) {
-#define NUMERIC_TYPE_APPEND_STRING(constant_, type_, name_)                   \
-        case constant_: return contents.append(#name_);
-        JS_FOR_EACH_SCALAR_TYPE_REPR(NUMERIC_TYPE_APPEND_STRING)
-    }
-    MOZ_ASSUME_UNREACHABLE("Invalid type");
-}
-
 /*static*/ const char *
 ReferenceTypeRepresentation::typeName(Type type)
 {
     switch (type) {
 #define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
         case constant_: return #name_;
         JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
     }
     MOZ_ASSUME_UNREACHABLE("Invalid type");
 }
 
-bool
-ReferenceTypeRepresentation::appendStringReference(JSContext *cx, StringBuffer &contents)
-{
-    switch (type()) {
-#define NUMERIC_TYPE_APPEND_STRING(constant_, type_, name_)                   \
-        case constant_: return contents.append(#name_);
-        JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_APPEND_STRING)
-    }
-    MOZ_ASSUME_UNREACHABLE("Invalid type");
-}
-
-bool
-X4TypeRepresentation::appendStringX4(JSContext *cx, StringBuffer &contents)
-{
-    switch (type()) {
-      case TYPE_FLOAT32:
-        return contents.append("float32x4");
-      case TYPE_INT32:
-        return contents.append("int32x4");
-    }
-    MOZ_ASSUME_UNREACHABLE("Invalid type");
-}
-
-bool
-SizedArrayTypeRepresentation::appendStringSizedArray(JSContext *cx, StringBuffer &contents)
-{
-    SizedTypeRepresentation *elementType = element();
-    while (elementType->isSizedArray())
-        elementType = elementType->asSizedArray()->element();
-    if (!elementType->appendString(cx, contents))
-        return false;
-
-    contents.append(".array(");
-    SizedArrayTypeRepresentation *arrayType = this;
-    while (arrayType != nullptr) {
-        if (!NumberValueToStringBuffer(cx, NumberValue(length()), contents))
-            return false;
-
-        if (arrayType->element()->isSizedArray()) {
-            if (!contents.append(","))
-                return false;
-            arrayType = arrayType->element()->asSizedArray();
-        } else {
-            break;
-        }
-    }
-
-    if (!contents.append(")"))
-        return false;
-
-    return true;
-}
-
-bool
-UnsizedArrayTypeRepresentation::appendStringUnsizedArray(JSContext *cx, StringBuffer &contents)
-{
-    if (!element()->appendString(cx, contents))
-        return false;
-
-    if (!contents.append(".array()"))
-        return false;
-
-    return true;
-}
-
-bool
-StructTypeRepresentation::appendStringStruct(JSContext *cx, StringBuffer &contents)
-{
-    if (!contents.append("StructType({"))
-        return false;
-
-    for (size_t i = 0; i < fieldCount(); i++) {
-        const StructField &fld = field(i);
-
-        if (i > 0)
-            contents.append(", ");
-
-        RootedString idString(cx, fld.propertyName);
-        if (!idString)
-            return false;
-
-        if (!contents.append(idString))
-            return false;
-
-        if (!contents.append(": "))
-            return false;
-
-        if (!fld.typeRepr->appendString(cx, contents))
-            return false;
-    }
-
-    if (!contents.append("})"))
-        return false;
-
-    return true;
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Walking memory
 
 template<typename V>
 static void
 visitReferences(SizedTypeRepresentation *repr,
                 uint8_t *mem,
                 V& visitor)
--- a/js/src/builtin/TypeRepresentation.h
+++ b/js/src/builtin/TypeRepresentation.h
@@ -155,20 +155,16 @@ class TypeRepresentation {
 
   public:
     Kind kind() const { return kind_; }
     bool opaque() const { return opaque_; }
     bool transparent() const { return !opaque_; }
     JSObject *ownerObject() const { return ownerObject_.get(); }
     types::TypeObject *typeObject() const { return typeObject_.get(); }
 
-    // Appends a stringified form of this type representation onto
-    // buffer, for use in error messages and the like.
-    bool appendString(JSContext *cx, StringBuffer &buffer);
-
     static bool isOwnerObject(JSObject &obj);
     static TypeRepresentation *fromOwnerObject(JSObject &obj);
 
     static bool isSized(Kind kind) {
         return kind > JS_TYPEREPR_MAX_UNSIZED_KIND;
     }
 
     bool isSized() const {
@@ -256,29 +252,23 @@ class ScalarTypeRepresentation : public 
          * Special type that's a uint8_t, but assignments are clamped to 0 .. 255.
          * Treat the raw data type as a uint8_t.
          */
         TYPE_UINT8_CLAMPED = JS_SCALARTYPEREPR_UINT8_CLAMPED,
     };
     static const int32_t TYPE_MAX = TYPE_UINT8_CLAMPED + 1;
 
   private:
-    // so TypeRepresentation can call appendStringScalar() etc
-    friend class TypeRepresentation;
-
     // in order to call constructor
     friend class TypeRepresentationHelper;
 
     const Type type_;
 
     explicit ScalarTypeRepresentation(Type type);
 
-    // See TypeRepresentation::appendString()
-    bool appendStringScalar(JSContext *cx, StringBuffer &buffer);
-
   public:
     Type type() const {
         return type_;
     }
 
     const char *typeName() const {
         return typeName(type());
     }
@@ -311,26 +301,20 @@ class ReferenceTypeRepresentation : publ
     enum Type {
         TYPE_ANY = JS_REFERENCETYPEREPR_ANY,
         TYPE_OBJECT = JS_REFERENCETYPEREPR_OBJECT,
         TYPE_STRING = JS_REFERENCETYPEREPR_STRING,
     };
     static const int32_t TYPE_MAX = TYPE_STRING + 1;
 
   private:
-    // so TypeRepresentation can call appendStringScalar() etc
-    friend class TypeRepresentation;
-
     Type type_;
 
     explicit ReferenceTypeRepresentation(Type type);
 
-    // See TypeRepresentation::appendString()
-    bool appendStringReference(JSContext *cx, StringBuffer &buffer);
-
   public:
     Type type() const {
         return type_;
     }
 
     const char *typeName() const {
         return typeName(type());
     }
@@ -347,83 +331,71 @@ class ReferenceTypeRepresentation : publ
 class X4TypeRepresentation : public SizedTypeRepresentation {
   public:
     enum Type {
         TYPE_INT32 = JS_X4TYPEREPR_INT32,
         TYPE_FLOAT32 = JS_X4TYPEREPR_FLOAT32,
     };
 
   private:
-    // so TypeRepresentation can call appendStringScalar() etc
-    friend class TypeRepresentation;
-
     // in order to call constructor
     friend class TypeRepresentationHelper;
 
     const Type type_;
 
     explicit X4TypeRepresentation(Type type);
 
-    // See TypeRepresentation::appendString()
-    bool appendStringX4(JSContext *cx, StringBuffer &buffer);
-
   public:
     Type type() const {
         return type_;
     }
 
     static JSObject *Create(JSContext *cx, Type type);
 };
 
 // Must be in same order as the enum ScalarTypeRepresentation::Type:
 #define JS_FOR_EACH_X4_TYPE_REPR(macro_)                                      \
     macro_(X4TypeRepresentation::TYPE_INT32, int32_t, int32)                  \
     macro_(X4TypeRepresentation::TYPE_FLOAT32, float, float32)
 
 class UnsizedArrayTypeRepresentation : public TypeRepresentation {
   private:
-    // so TypeRepresentation can call appendStringArray() etc
+    // so TypeRepresentation can call tracing routines
     friend class TypeRepresentation;
 
     SizedTypeRepresentation *element_;
 
     UnsizedArrayTypeRepresentation(SizedTypeRepresentation *element);
 
     // See TypeRepresentation::traceFields()
     void traceUnsizedArrayFields(JSTracer *trace);
 
-    // See TypeRepresentation::appendString()
-    bool appendStringUnsizedArray(JSContext *cx, StringBuffer &buffer);
-
   public:
     SizedTypeRepresentation *element() {
         return element_;
     }
 
     static JSObject *Create(JSContext *cx,
                             SizedTypeRepresentation *elementTypeRepr);
 };
 
 class SizedArrayTypeRepresentation : public SizedTypeRepresentation {
   private:
-    // so TypeRepresentation can call appendStringSizedArray() etc
+    // so TypeRepresentation can call traceSizedArrayFields()
     friend class TypeRepresentation;
 
     SizedTypeRepresentation *element_;
     size_t length_;
 
     SizedArrayTypeRepresentation(SizedTypeRepresentation *element,
                                  size_t length);
 
     // See TypeRepresentation::traceFields()
     void traceSizedArrayFields(JSTracer *trace);
 
-    // See TypeRepresentation::appendString()
-    bool appendStringSizedArray(JSContext *cx, StringBuffer &buffer);
-
   public:
     SizedTypeRepresentation *element() {
         return element_;
     }
 
     size_t length() {
         return length_;
     }
@@ -442,17 +414,17 @@ struct StructField {
     explicit StructField(size_t index,
                          PropertyName *propertyName,
                          SizedTypeRepresentation *typeRepr,
                          size_t offset);
 };
 
 class StructTypeRepresentation : public SizedTypeRepresentation {
   private:
-    // so TypeRepresentation can call appendStringStruct() etc
+    // so TypeRepresentation can call traceStructFields() etc
     friend class TypeRepresentation;
 
     size_t fieldCount_;
 
     // StructTypeRepresentations are allocated with extra space to
     // store the contents of the fields array.
     StructField* fields() {
         return (StructField*) (this+1);
@@ -464,19 +436,16 @@ class StructTypeRepresentation : public 
     StructTypeRepresentation();
     bool init(JSContext *cx,
               AutoPropertyNameVector &names,
               AutoObjectVector &typeReprOwners);
 
     // See TypeRepresentation::traceFields()
     void traceStructFields(JSTracer *trace);
 
-    // See TypeRepresentation::appendString()
-    bool appendStringStruct(JSContext *cx, StringBuffer &buffer);
-
   public:
     size_t fieldCount() const {
         return fieldCount_;
     }
 
     const StructField &field(size_t i) const {
         JS_ASSERT(i < fieldCount());
         return fields()[i];
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -62,41 +62,16 @@ ToObjectIf(HandleValue value)
         return nullptr;
 
     if (!value.toObject().is<T>())
         return nullptr;
 
     return &value.toObject().as<T>();
 }
 
-bool
-js::TypeDescrToSource(JSContext *cx, unsigned int argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    Rooted<TypeDescr*> thisObj(cx, ToObjectIf<TypeDescr>(args.thisv()));
-    if (!thisObj) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage,
-                             nullptr, JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS,
-                             "this", "type object");
-        return false;
-    }
-
-    StringBuffer contents(cx);
-    if (!thisObj->typeRepresentation()->appendString(cx, contents))
-        return false;
-
-    RootedString result(cx, contents.finishString());
-    if (!result)
-        return false;
-
-    args.rval().setString(result);
-    return true;
-}
-
 /*
  * Overwrites the contents of `datum` at offset `offset` with `val`
  * converted to the type `typeObj`. This is done by delegating to
  * self-hosted code. This is used for assignments and initializations.
  *
  * For example, consider the final assignment in this snippet:
  *
  *    var Point = new StructType({x: float32, y: float32});
@@ -125,25 +100,24 @@ ConvertAndCopyTo(JSContext *cx,
                  HandleValue val)
 {
     RootedFunction func(
         cx, SelfHostedFunction(cx, cx->names().ConvertAndCopyTo));
     if (!func)
         return false;
 
     InvokeArgs args(cx);
-    if (!args.init(5))
+    if (!args.init(4))
         return false;
 
     args.setCallee(ObjectValue(*func));
-    args[0].setObject(typeObj->typeRepresentationOwnerObj());
-    args[1].setObject(*typeObj);
-    args[2].setObject(*datum);
-    args[3].setInt32(offset);
-    args[4].set(val);
+    args[0].setObject(*typeObj);
+    args[1].setObject(*datum);
+    args[2].setInt32(offset);
+    args[3].set(val);
 
     return Invoke(cx, args);
 }
 
 static bool
 ConvertAndCopyTo(JSContext *cx, HandleTypedDatum datum, HandleValue val)
 {
     Rooted<TypeDescr*> type(cx, &datum->typeDescr());
@@ -162,24 +136,23 @@ Reify(JSContext *cx,
       size_t offset,
       MutableHandleValue to)
 {
     RootedFunction func(cx, SelfHostedFunction(cx, cx->names().Reify));
     if (!func)
         return false;
 
     InvokeArgs args(cx);
-    if (!args.init(4))
+    if (!args.init(3))
         return false;
 
     args.setCallee(ObjectValue(*func));
-    args[0].setObject(*typeRepr->ownerObject());
-    args[1].setObject(*type);
-    args[2].setObject(*datum);
-    args[3].setInt32(offset);
+    args[0].setObject(*type);
+    args[1].setObject(*datum);
+    args[2].setInt32(offset);
 
     if (!Invoke(cx, args))
         return false;
 
     to.set(args.rval());
     return true;
 }
 
@@ -224,17 +197,17 @@ const Class js::ScalarTypeDescr::class_ 
     nullptr,
     ScalarTypeDescr::call,
     nullptr,
     nullptr,
     nullptr
 };
 
 const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
-    JS_FN("toSource", TypeDescrToSource, 0, 0),
+    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
     {"handle", {nullptr, nullptr}, 2, 0, "HandleCreate"},
     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     JS_FS_END
 };
 
 bool
 ScalarTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
@@ -295,17 +268,17 @@ const Class js::ReferenceTypeDescr::clas
     nullptr,
     ReferenceTypeDescr::call,
     nullptr,
     nullptr,
     nullptr
 };
 
 const JSFunctionSpec js::ReferenceTypeDescr::typeObjectMethods[] = {
-    JS_FN("toSource", TypeDescrToSource, 0, 0),
+    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
     {"handle", {nullptr, nullptr}, 2, 0, "HandleCreate"},
     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     JS_FS_END
 };
 
 bool
 js::ReferenceTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
@@ -437,17 +410,17 @@ const Class SizedArrayTypeDescr::class_ 
 const JSPropertySpec ArrayMetaTypeDescr::typeObjectProperties[] = {
     JS_PS_END
 };
 
 const JSFunctionSpec ArrayMetaTypeDescr::typeObjectMethods[] = {
     {"handle", {nullptr, nullptr}, 2, 0, "HandleCreate"},
     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
     JS_FN("dimension", UnsizedArrayTypeDescr::dimension, 1, 0),
-    JS_FN("toSource", TypeDescrToSource, 0, 0),
+    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     JS_SELF_HOSTED_FN("build",    "TypedObjectArrayTypeBuild", 3, 0),
     JS_SELF_HOSTED_FN("buildPar", "TypedObjectArrayTypeBuildPar", 3, 0),
     JS_SELF_HOSTED_FN("from",     "TypedObjectArrayTypeFrom", 3, 0),
     JS_SELF_HOSTED_FN("fromPar",  "TypedObjectArrayTypeFromPar", 3, 0),
     JS_FS_END
 };
 
@@ -710,17 +683,17 @@ const Class StructTypeDescr::class_ = {
 
 const JSPropertySpec StructMetaTypeDescr::typeObjectProperties[] = {
     JS_PS_END
 };
 
 const JSFunctionSpec StructMetaTypeDescr::typeObjectMethods[] = {
     {"handle", {nullptr, nullptr}, 2, 0, "HandleCreate"},
     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
-    JS_FN("toSource", TypeDescrToSource, 0, 0),
+    JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     JS_FS_END
 };
 
 const JSPropertySpec StructMetaTypeDescr::typedObjectProperties[] = {
     JS_PS_END
 };
 
@@ -1391,23 +1364,30 @@ TypedDatum::createDerived(JSContext *cx,
     return obj;
 }
 
 static bool
 ReportDatumTypeError(JSContext *cx,
                      const unsigned errorNumber,
                      HandleTypedDatum obj)
 {
-    TypeRepresentation *typeRepr = obj->typeRepresentation();
-
-    StringBuffer contents(cx);
-    if (!typeRepr->appendString(cx, contents))
+    // Serialize type string using self-hosted function DescrToSource
+    RootedFunction func(
+        cx, SelfHostedFunction(cx, cx->names().DescrToSource));
+    if (!func)
         return false;
-
-    RootedString result(cx, contents.finishString());
+    InvokeArgs args(cx);
+    if (!args.init(1))
+        return false;
+    args.setCallee(ObjectValue(*func));
+    args[0].setObject(obj->typeDescr());
+    if (!Invoke(cx, args))
+        return false;
+
+    RootedString result(cx, args.rval().toString());
     if (!result)
         return false;
 
     char *typeReprStr = JS_EncodeString(cx, result.get());
     if (!typeReprStr)
         return false;
 
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -134,18 +134,16 @@ static T ConvertScalar(double d)
         uint32_t n = ToUint32(d);
         return T(n);
     } else {
         int32_t n = ToInt32(d);
         return T(n);
     }
 }
 
-bool TypeDescrToSource(JSContext *cx, unsigned int argc, Value *vp);
-
 class TypeDescr : public JSObject
 {
   public:
     JSObject &typeRepresentationOwnerObj() const {
         return getReservedSlot(JS_TYPEOBJ_SLOT_TYPE_REPR).toObject();
     }
 
     TypeRepresentation *typeRepresentation() const {
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -1,111 +1,195 @@
 #include "TypedObjectConstants.h"
 
 ///////////////////////////////////////////////////////////////////////////
 // Getters and setters for various slots.
 
+// Type repr slots
+
+#define REPR_KIND(obj)   \
+    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_KIND))
+#define REPR_SIZE(obj)   \
+    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_SIZE))
+#define REPR_LENGTH(obj)   \
+    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_LENGTH))
+#define REPR_TYPE(obj)   \
+    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_TYPE))
+
 // Type object slots
 
-#define TYPE_TYPE_REPR(obj) \
+#define DESCR_TYPE_REPR(obj) \
     UnsafeGetReservedSlot(obj, JS_TYPEOBJ_SLOT_TYPE_REPR)
+#define DESCR_KIND(obj) \
+    REPR_KIND(DESCR_TYPE_REPR(obj))
+#define DESCR_SIZE(obj) \
+    REPR_SIZE(DESCR_TYPE_REPR(obj))
+#define DESCR_LENGTH(obj) \
+    REPR_LENGTH(DESCR_TYPE_REPR(obj))
+#define DESCR_TYPE(obj)   \
+    REPR_TYPE(DESCR_TYPE_REPR(obj))
 
 // Typed object slots
 
 #define DATUM_TYPE_DESCR(obj) \
     UnsafeGetReservedSlot(obj, JS_DATUM_SLOT_TYPE_DESCR)
 #define DATUM_OWNER(obj) \
     UnsafeGetReservedSlot(obj, JS_DATUM_SLOT_OWNER)
 #define DATUM_LENGTH(obj) \
     TO_INT32(UnsafeGetReservedSlot(obj, JS_DATUM_SLOT_LENGTH))
 
-// Type repr slots
-
-#define REPR_KIND(obj)   \
-    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_KIND))
-#define REPR_SIZE(obj)   \
-    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_SIZE))
-#define REPR_ALIGNMENT(obj) \
-    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_ALIGNMENT))
-#define REPR_LENGTH(obj)   \
-    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_LENGTH))
-#define REPR_TYPE(obj)   \
-    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEREPR_SLOT_TYPE))
-
 #define HAS_PROPERTY(obj, prop) \
     callFunction(std_Object_hasOwnProperty, obj, prop)
 
 function DATUM_TYPE_REPR(obj) {
   // Eventually this will be a slot on typed objects
-  return TYPE_TYPE_REPR(DATUM_TYPE_DESCR(obj));
+  return DESCR_TYPE_REPR(DATUM_TYPE_DESCR(obj));
+}
+
+///////////////////////////////////////////////////////////////////////////
+// DescrToSource
+//
+// Converts a type descriptor to a descriptive string
+
+// toSource() for type descriptors.
+//
+// Warning: user exposed!
+function DescrToSourceMethod() {
+  if (!IsObject(this) || !ObjectIsTypeDescr(this))
+    ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Type", "toSource", "value");
+
+  return DescrToSource(this);
+}
+
+function DescrToSource(descr) {
+  assert(IsObject(descr) && ObjectIsTypeDescr(descr),
+         "DescrToSource: not type descr");
+
+  switch (DESCR_KIND(descr)) {
+  case JS_TYPEREPR_SCALAR_KIND:
+    switch (DESCR_TYPE(descr)) {
+    case JS_SCALARTYPEREPR_INT8: return "int8";
+    case JS_SCALARTYPEREPR_UINT8: return "uint8";
+    case JS_SCALARTYPEREPR_UINT8_CLAMPED: return "uint8Clamped";
+    case JS_SCALARTYPEREPR_INT16: return "int16";
+    case JS_SCALARTYPEREPR_UINT16: return "uint16";
+    case JS_SCALARTYPEREPR_INT32: return "int32";
+    case JS_SCALARTYPEREPR_UINT32: return "uint32";
+    case JS_SCALARTYPEREPR_FLOAT32: return "float32";
+    case JS_SCALARTYPEREPR_FLOAT64: return "float64";
+    }
+    assert(false, "Unhandled type: " + DESCR_TYPE(descr));
+    return undefined;
+
+  case JS_TYPEREPR_REFERENCE_KIND:
+    switch (DESCR_TYPE(descr)) {
+    case JS_REFERENCETYPEREPR_ANY: return "any";
+    case JS_REFERENCETYPEREPR_OBJECT: return "Object";
+    case JS_REFERENCETYPEREPR_STRING: return "string";
+    }
+    assert(false, "Unhandled type: " + DESCR_TYPE(descr));
+    return undefined;
+
+  case JS_TYPEREPR_X4_KIND:
+    switch (DESCR_TYPE(descr)) {
+    case JS_X4TYPEREPR_FLOAT32: return "float32x4";
+    case JS_X4TYPEREPR_INT32: return "int32x4";
+    }
+    assert(false, "Unhandled type: " + DESCR_TYPE(descr));
+    return undefined;
+
+  case JS_TYPEREPR_STRUCT_KIND:
+    var result = "new StructType({";
+    for (var i = 0; i < descr.fieldNames.length; i++) {
+      if (i != 0)
+        result += ", ";
+
+      var fieldName = descr.fieldNames[i];
+      var fieldDescr = descr.fieldTypes[fieldName];
+      result += fieldName;
+      result += ": ";
+      result += DescrToSource(fieldDescr);
+    }
+    result += "})";
+    return result;
+
+  case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
+    return "new ArrayType(" + DescrToSource(descr.elementType) + ")";
+
+  case JS_TYPEREPR_SIZED_ARRAY_KIND:
+    var result = ".array";
+    var sep = "(";
+    while (DESCR_KIND(descr) == JS_TYPEREPR_SIZED_ARRAY_KIND) {
+      result += sep + DESCR_LENGTH(descr);
+      descr = descr.elementType;
+      sep = ", ";
+    }
+    return DescrToSource(descr) + result + ")";
+  }
+
+  assert(false, "Unhandled kind: " + DESCR_KIND(descr));
+  return undefined;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // TypedObjectPointer
 //
 // TypedObjectPointers are internal structs used to represent a
 // pointer into typed object memory. They pull together:
-// - typeRepr: the internal type representation
-// - descr: the user-visible type object
+// - descr: the type descriptor
 // - datum: the typed object that contains the allocated block of memory
 // - offset: an offset into that typed object
 //
 // They are basically equivalent to a typed object, except that they
 // offer lots of internal unsafe methods and are not native objects.
 // These should never escape into user code; ideally ion would stack
 // allocate them.
 //
 // Most `TypedObjectPointers` methods are written in a "chaining"
 // style, meaning that they return `this`. This is true even though
 // they mutate the receiver in place, because it makes for prettier
 // code.
 
-function TypedObjectPointer(typeRepr, descr, datum, offset) {
-  this.typeRepr = typeRepr;
+function TypedObjectPointer(descr, datum, offset) {
   this.descr = descr;
   this.datum = datum;
   this.offset = offset;
 }
 
 MakeConstructible(TypedObjectPointer, {});
 
 TypedObjectPointer.fromTypedDatum = function(typed) {
-  return new TypedObjectPointer(DATUM_TYPE_REPR(typed),
-                                DATUM_TYPE_DESCR(typed),
-                                typed,
-                                0);
+  return new TypedObjectPointer(DATUM_TYPE_DESCR(typed), typed, 0);
 }
 
 #ifdef DEBUG
 TypedObjectPointer.prototype.toString = function() {
-  return "Ptr(" + this.descr.toSource() + " @ " + this.offset + ")";
+  return "Ptr(" + DescrToSource(this.descr) + " @ " + this.offset + ")";
 };
 #endif
 
 TypedObjectPointer.prototype.copy = function() {
-  return new TypedObjectPointer(this.typeRepr, this.descr,
-                                this.datum, this.offset);
+  return new TypedObjectPointer(this.descr, this.datum, this.offset);
 };
 
 TypedObjectPointer.prototype.reset = function(inPtr) {
-  this.typeRepr = inPtr.typeRepr;
   this.descr = inPtr.descr;
   this.datum = inPtr.datum;
   this.offset = inPtr.offset;
   return this;
 };
 
 TypedObjectPointer.prototype.kind = function() {
-  return REPR_KIND(this.typeRepr);
+  return DESCR_KIND(this.descr);
 }
 
 TypedObjectPointer.prototype.length = function() {
   switch (this.kind()) {
   case JS_TYPEREPR_SIZED_ARRAY_KIND:
-    return REPR_LENGTH(this.typeRepr);
+    return DESCR_LENGTH(this.descr);
 
   case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
     return DATUM_LENGTH(this.datum);
   }
   assert(false, "length() invoked on non-array-type");
   return 0;
 }
 
@@ -152,21 +236,19 @@ TypedObjectPointer.prototype.moveToElem 
   assert(this.kind() == JS_TYPEREPR_SIZED_ARRAY_KIND ||
          this.kind() == JS_TYPEREPR_UNSIZED_ARRAY_KIND,
          "moveToElem invoked on non-array");
   assert(TO_INT32(index) === index,
          "moveToElem invoked with non-integer index");
   assert(index >= 0 && index < this.length(),
          "moveToElem invoked with out-of-bounds index: " + index);
 
-  var elementTypeObj = this.descr.elementType;
-  var elementTypeRepr = TYPE_TYPE_REPR(elementTypeObj);
-  this.typeRepr = elementTypeRepr;
-  this.descr = elementTypeObj;
-  var elementSize = REPR_SIZE(elementTypeRepr);
+  var elementDescr = this.descr.elementType;
+  this.descr = elementDescr;
+  var elementSize = DESCR_SIZE(elementDescr);
 
   // Note: we do not allow construction of arrays where the offset
   // of an element cannot be represented by an int32.
   this.offset += std_Math_imul(index, elementSize);
 
   return this;
 };
 
@@ -174,20 +256,19 @@ TypedObjectPointer.prototype.moveToElem 
 // struct type and `propName` must be a valid field name. Returns
 // `this`.
 TypedObjectPointer.prototype.moveToField = function(propName) {
   assert(this.kind() == JS_TYPEREPR_STRUCT_KIND,
          "moveToField invoked on non-struct");
   assert(HAS_PROPERTY(this.descr.fieldTypes, propName),
          "moveToField invoked with undefined field");
 
-  var fieldTypeObj = this.descr.fieldTypes[propName];
+  var fieldDescr = this.descr.fieldTypes[propName];
   var fieldOffset = TO_INT32(this.descr.fieldOffsets[propName]);
-  this.descr = fieldTypeObj;
-  this.typeRepr = TYPE_TYPE_REPR(fieldTypeObj);
+  this.descr = fieldDescr;
 
   // Note: we do not allow construction of structs where the
   // offset of a field cannot be represented by an int32.
   this.offset += fieldOffset;
 
   return this;
 }
 
@@ -201,42 +282,42 @@ TypedObjectPointer.prototype.moveToField
 // Reifies the value referenced by the pointer, meaning that it
 // returns a new object pointing at the value. If the value is
 // a scalar, it will return a JS number, but otherwise the reified
 // result will be a typed object or handle, depending on the type
 // of the ptr's datum.
 TypedObjectPointer.prototype.get = function() {
   assert(ObjectIsAttached(this.datum), "get() called with unattached datum");
 
-  switch (REPR_KIND(this.typeRepr)) {
+  switch (this.kind()) {
   case JS_TYPEREPR_SCALAR_KIND:
     return this.getScalar();
 
   case JS_TYPEREPR_REFERENCE_KIND:
     return this.getReference();
 
   case JS_TYPEREPR_X4_KIND:
     return this.getX4();
 
   case JS_TYPEREPR_SIZED_ARRAY_KIND:
     return NewDerivedTypedDatum(this.descr, this.datum, this.offset);
 
   case JS_TYPEREPR_STRUCT_KIND:
     return NewDerivedTypedDatum(this.descr, this.datum, this.offset);
 
   case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
-    assert(false, "Unhandled repr kind: " + REPR_KIND(this.typeRepr));
+    assert(false, "Unhandled repr kind: " + this.kind());
   }
 
-  assert(false, "Unhandled kind: " + REPR_KIND(this.typeRepr));
+  assert(false, "Unhandled kind: " + this.kind());
   return undefined;
 }
 
 TypedObjectPointer.prototype.getScalar = function() {
-  var type = REPR_TYPE(this.typeRepr);
+  var type = DESCR_TYPE(this.descr);
   switch (type) {
   case JS_SCALARTYPEREPR_INT8:
     return Load_int8(this.datum, this.offset);
 
   case JS_SCALARTYPEREPR_UINT8:
   case JS_SCALARTYPEREPR_UINT8_CLAMPED:
     return Load_uint8(this.datum, this.offset);
 
@@ -259,34 +340,34 @@ TypedObjectPointer.prototype.getScalar =
     return Load_float64(this.datum, this.offset);
   }
 
   assert(false, "Unhandled scalar type: " + type);
   return undefined;
 }
 
 TypedObjectPointer.prototype.getReference = function() {
-  var type = REPR_TYPE(this.typeRepr);
+  var type = DESCR_TYPE(this.descr);
   switch (type) {
   case JS_REFERENCETYPEREPR_ANY:
     return Load_Any(this.datum, this.offset);
 
   case JS_REFERENCETYPEREPR_OBJECT:
     return Load_Object(this.datum, this.offset);
 
   case JS_REFERENCETYPEREPR_STRING:
     return Load_string(this.datum, this.offset);
   }
 
   assert(false, "Unhandled scalar type: " + type);
   return undefined;
 }
 
 TypedObjectPointer.prototype.getX4 = function() {
-  var type = REPR_TYPE(this.typeRepr);
+  var type = DESCR_TYPE(this.descr);
   switch (type) {
   case JS_X4TYPEREPR_FLOAT32:
     var x = Load_float32(this.datum, this.offset + 0);
     var y = Load_float32(this.datum, this.offset + 4);
     var z = Load_float32(this.datum, this.offset + 8);
     var w = Load_float32(this.datum, this.offset + 12);
     return GetFloat32x4TypeDescr()(x, y, z, w);
 
@@ -308,33 +389,32 @@ TypedObjectPointer.prototype.getX4 = fun
 // The methods in this section modify the data pointed at by `this`.
 
 // Assigns `fromValue` to the memory pointed at by `this`, adapting it
 // to `typeRepr` as needed. This is the most general entry point and
 // works for any type.
 TypedObjectPointer.prototype.set = function(fromValue) {
   assert(ObjectIsAttached(this.datum), "set() called with unattached datum");
 
-  var typeRepr = this.typeRepr;
-
   // 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) && ObjectIsTypedDatum(fromValue)) {
+    var typeRepr = DESCR_TYPE_REPR(this.descr);
     if (!typeRepr.variable && DATUM_TYPE_REPR(fromValue) === typeRepr) {
       if (!ObjectIsAttached(fromValue))
         ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
 
-      var size = REPR_SIZE(typeRepr);
+      var size = DESCR_SIZE(this.descr);
       Memcpy(this.datum, this.offset, fromValue, 0, size);
       return;
     }
   }
 
-  switch (REPR_KIND(typeRepr)) {
+  switch (this.kind()) {
   case JS_TYPEREPR_SCALAR_KIND:
     this.setScalar(fromValue);
     return;
 
   case JS_TYPEREPR_REFERENCE_KIND:
     this.setReference(fromValue);
     return;
 
@@ -350,17 +430,17 @@ TypedObjectPointer.prototype.set = funct
     // Check that "array-like" fromValue has an appropriate length.
     var length = this.length();
     if (fromValue.length !== length)
       break;
 
     // Adapt each element.
     if (length > 0) {
       var tempPtr = this.copy().moveToElem(0);
-      var size = REPR_SIZE(tempPtr.typeRepr);
+      var size = DESCR_SIZE(tempPtr.descr);
       for (var i = 0; i < length; i++) {
         tempPtr.set(fromValue[i]);
         tempPtr.offset += size;
       }
     }
     return;
 
   case JS_TYPEREPR_STRUCT_KIND:
@@ -374,25 +454,25 @@ TypedObjectPointer.prototype.set = funct
       var fieldName = fieldNames[i];
       tempPtr.reset(this).moveToField(fieldName).set(fromValue[fieldName]);
     }
     return;
   }
 
   ThrowError(JSMSG_CANT_CONVERT_TO,
              typeof(fromValue),
-             this.typeRepr.toSource());
+             DescrToSource(this.descr));
 }
 
 // Sets `fromValue` to `this` assuming that `this` is a scalar type.
 TypedObjectPointer.prototype.setScalar = function(fromValue) {
-  assert(REPR_KIND(this.typeRepr) == JS_TYPEREPR_SCALAR_KIND,
+  assert(this.kind() == JS_TYPEREPR_SCALAR_KIND,
          "setScalar called with non-scalar");
 
-  var type = REPR_TYPE(this.typeRepr);
+  var type = DESCR_TYPE(this.descr);
   switch (type) {
   case JS_SCALARTYPEREPR_INT8:
     return Store_int8(this.datum, this.offset,
                      TO_INT32(fromValue) & 0xFF);
 
   case JS_SCALARTYPEREPR_UINT8:
     return Store_uint8(this.datum, this.offset,
                       TO_UINT32(fromValue) & 0xFF);
@@ -424,17 +504,17 @@ TypedObjectPointer.prototype.setScalar =
     return Store_float64(this.datum, this.offset, +fromValue);
   }
 
   assert(false, "Unhandled scalar type: " + type);
   return undefined;
 }
 
 TypedObjectPointer.prototype.setReference = function(fromValue) {
-  var type = REPR_TYPE(this.typeRepr);
+  var type = DESCR_TYPE(this.descr);
   switch (type) {
   case JS_REFERENCETYPEREPR_ANY:
     return Store_Any(this.datum, this.offset, fromValue);
 
   case JS_REFERENCETYPEREPR_OBJECT:
     var value = (fromValue === null ? fromValue : ToObject(fromValue));
     return Store_Object(this.datum, this.offset, value);
 
@@ -449,92 +529,87 @@ TypedObjectPointer.prototype.setReferenc
 // Sets `fromValue` to `this` assuming that `this` is a scalar type.
 TypedObjectPointer.prototype.setX4 = function(fromValue) {
   // It is only permitted to set a float32x4/int32x4 value from another
   // float32x4/int32x4; in that case, the "fast path" that uses memcopy will
   // have already matched. So if we get to this point, we're supposed
   // to "adapt" fromValue, but there are no legal adaptions.
   ThrowError(JSMSG_CANT_CONVERT_TO,
              typeof(fromValue),
-             this.typeRepr.toSource());
+             DescrToSource(this.descr));
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // C++ Wrappers
 //
 // These helpers are invoked by C++ code or used as method bodies.
 
 // Wrapper for use from C++ code.
-function ConvertAndCopyTo(destTypeRepr,
-                          destTypeObj,
+function ConvertAndCopyTo(destDescr,
                           destDatum,
                           destOffset,
                           fromValue)
 {
-  assert(IsObject(destTypeRepr) && ObjectIsTypeRepresentation(destTypeRepr),
-         "ConvertAndCopyTo: not type repr");
-  assert(IsObject(destTypeObj) && ObjectIsTypeDescr(destTypeObj),
+  assert(IsObject(destDescr) && ObjectIsTypeDescr(destDescr),
          "ConvertAndCopyTo: not type obj");
   assert(IsObject(destDatum) && ObjectIsTypedDatum(destDatum),
          "ConvertAndCopyTo: not type datum");
 
   if (!ObjectIsAttached(destDatum))
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
 
-  var ptr = new TypedObjectPointer(destTypeRepr, destTypeObj,
-                                   destDatum, destOffset);
+  var ptr = new TypedObjectPointer(destDescr, destDatum, destOffset);
   ptr.set(fromValue);
 }
 
 // Wrapper for use from C++ code.
-function Reify(sourceTypeRepr,
-               sourceTypeObj,
+function Reify(sourceDescr,
                sourceDatum,
                sourceOffset) {
-  assert(IsObject(sourceTypeRepr) && ObjectIsTypeRepresentation(sourceTypeRepr),
-         "Reify: not type repr");
-  assert(IsObject(sourceTypeObj) && ObjectIsTypeDescr(sourceTypeObj),
+  assert(IsObject(sourceDescr) && ObjectIsTypeDescr(sourceDescr),
          "Reify: not type obj");
   assert(IsObject(sourceDatum) && ObjectIsTypedDatum(sourceDatum),
          "Reify: not type datum");
 
   if (!ObjectIsAttached(sourceDatum))
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
 
-  var ptr = new TypedObjectPointer(sourceTypeRepr, sourceTypeObj,
-                                   sourceDatum, sourceOffset);
+  var ptr = new TypedObjectPointer(sourceDescr, sourceDatum, sourceOffset);
 
   return ptr.get();
 }
 
 function FillTypedArrayWithValue(destArray, fromValue) {
-  var typeRepr = DATUM_TYPE_REPR(destArray);
-  var length = REPR_LENGTH(typeRepr);
+  assert(IsObject(handle) && ObjectIsTypedDatum(destArray),
+         "FillTypedArrayWithValue: not typed handle");
+
+  var descr = DATUM_TYPE_DESCR(destArray);
+  var length = DESCR_LENGTH(descr);
   if (length === 0)
     return;
 
   // Use convert and copy to to produce the first element:
   var ptr = TypedObjectPointer.fromTypedDatum(destArray);
   ptr.moveToElem(0);
   ptr.set(fromValue);
 
   // Stamp out the remaining copies:
-  var elementSize = REPR_SIZE(ptr.typeRepr);
+  var elementSize = DESCR_SIZE(ptr.descr);
   var totalSize = length * elementSize;
   for (var offset = elementSize; offset < totalSize; offset += elementSize)
     Memcpy(destArray, offset, destArray, 0, elementSize);
 }
 
 // Warning: user exposed!
-function TypeDescrEquivalent(otherTypeObj) {
+function TypeDescrEquivalent(otherDescr) {
   if (!IsObject(this) || !ObjectIsTypeDescr(this))
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "type object");
-  if (!IsObject(otherTypeObj) || !ObjectIsTypeDescr(otherTypeObj))
+  if (!IsObject(otherDescr) || !ObjectIsTypeDescr(otherDescr))
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "1", "type object");
-  return TYPE_TYPE_REPR(this) === TYPE_TYPE_REPR(otherTypeObj);
+  return DESCR_TYPE_REPR(this) === DESCR_TYPE_REPR(otherDescr);
 }
 
 // TypedArray.redimension(newArrayType)
 //
 // Method that "repackages" the data from this array into a new typed
 // object whose type is `newArrayType`. Once you strip away all the
 // outer array dimensions, the type of `this` array and `newArrayType`
 // must share the same innermost element type. Moreover, those
@@ -557,60 +632,59 @@ function TypedArrayRedimension(newArrayT
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
 
   if (!IsObject(newArrayType) || !ObjectIsTypeDescr(newArrayType))
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1, "type object");
 
   // 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 = DATUM_TYPE_DESCR(this);
-  var oldArrayReprKind = REPR_KIND(TYPE_TYPE_REPR(oldArrayType));
+  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;
 
   case JS_TYPEREPR_SIZED_ARRAY_KIND:
     break;
 
   default:
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
   }
-  while (REPR_KIND(TYPE_TYPE_REPR(oldElementType)) === JS_TYPEREPR_SIZED_ARRAY_KIND) {
+  while (DESCR_KIND(oldElementType) === JS_TYPEREPR_SIZED_ARRAY_KIND) {
     oldElementCount *= oldElementType.length;
     oldElementType = oldElementType.elementType;
   }
 
   // Peel away the outermost array layers from `newArrayType`. In the
   // process, count the number of elements.
   var newElementType = newArrayType;
   var newElementCount = 1;
-  while (REPR_KIND(TYPE_TYPE_REPR(newElementType)) == JS_TYPEREPR_SIZED_ARRAY_KIND) {
+  while (DESCR_KIND(newElementType) == JS_TYPEREPR_SIZED_ARRAY_KIND) {
     newElementCount *= newElementType.length;
     newElementType = newElementType.elementType;
   }
 
   // Check that the total number of elements does not change.
   if (oldElementCount !== newElementCount) {
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1,
                "New number of elements does not match old number of elements");
   }
 
   // Check that the element types are equivalent.
-  if (TYPE_TYPE_REPR(oldElementType) !== TYPE_TYPE_REPR(newElementType)) {
+  if (DESCR_TYPE_REPR(oldElementType) !== DESCR_TYPE_REPR(newElementType)) {
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1,
                "New element type is not equivalent to old element type");
   }
 
   // Together, this should imply that the sizes are unchanged.
-  assert(REPR_SIZE(TYPE_TYPE_REPR(oldArrayType)) ==
-         REPR_SIZE(TYPE_TYPE_REPR(newArrayType)),
+  assert(DESCR_SIZE(oldArrayType) == DESCR_SIZE(newArrayType),
          "Byte sizes should be equal");
 
   // Rewrap the data from `this` in a new type.
   return NewDerivedTypedDatum(newArrayType, this, 0);
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Handles
@@ -621,17 +695,17 @@ function TypedArrayRedimension(newArrayT
 // This is the `handle([obj, [...path]])` method on type objects.
 // User exposed!
 //
 // FIXME bug 929656 -- label algorithms with steps from the spec
 function HandleCreate(obj, ...path) {
   if (!IsObject(this) || !ObjectIsTypeDescr(this))
     ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Type", "handle", "value");
 
-  switch (REPR_KIND(TYPE_TYPE_REPR(this))) {
+  switch (DESCR_KIND(this)) {
   case JS_TYPEREPR_SCALAR_KIND:
   case JS_TYPEREPR_REFERENCE_KIND:
   case JS_TYPEREPR_X4_KIND:
   case JS_TYPEREPR_SIZED_ARRAY_KIND:
   case JS_TYPEREPR_STRUCT_KIND:
     break;
 
   case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
@@ -662,17 +736,17 @@ function HandleMoveInternal(handle, obj,
   if (!IsObject(obj) || !ObjectIsTypedDatum(obj))
     ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Handle", "set", "value");
 
   var ptr = TypedObjectPointer.fromTypedDatum(obj);
   for (var i = 0; i < path.length; i++)
     ptr.moveTo(path[i]);
 
   // Check that the new destination is equivalent to the handle type.
-  if (ptr.typeRepr !== DATUM_TYPE_REPR(handle))
+  if (DESCR_TYPE_REPR(ptr.descr) !== DATUM_TYPE_REPR(handle))
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_TYPE);
 
   AttachHandle(handle, ptr.datum, ptr.offset)
 }
 
 // Handle.get: user exposed!
 // FIXME bug 929656 -- label algorithms with steps from the spec
 function HandleGet(handle) {
@@ -719,21 +793,21 @@ function X4ProtoString(type) {
   assert(false, "Unhandled type constant");
   return undefined;
 }
 
 function X4ToSource() {
   if (!IsObject(this) || !ObjectIsTypedDatum(this))
     ThrowError(JSMSG_INCOMPATIBLE_PROTO, "X4", "toSource", typeof this);
 
-  var repr = DATUM_TYPE_REPR(this);
-  if (REPR_KIND(repr) != JS_TYPEREPR_X4_KIND)
+  if (DESCR_KIND(this) != JS_TYPEREPR_X4_KIND)
     ThrowError(JSMSG_INCOMPATIBLE_PROTO, "X4", "toSource", typeof this);
 
-  var type = REPR_TYPE(repr);
+  var descr = DATUM_TYPE_DESCR(this);
+  var type = DESCR_TYPE(descr);
   return X4ProtoString(type)+"("+this.x+", "+this.y+", "+this.z+", "+this.w+")";
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Miscellaneous
 
 // Warning: user exposed!
 function ArrayShorthand(...dims) {
@@ -794,17 +868,17 @@ function ObjectIsAttached(obj) {
 
 // Warning: user exposed!
 function TypedObjectArrayTypeBuild(a,b,c) {
   // Arguments (this sized) : [depth], func
   // Arguments (this unsized) : length, [depth], func
 
   if (!IsObject(this) || !ObjectIsTypeDescr(this))
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "type object");
-  var kind = REPR_KIND(TYPE_TYPE_REPR(this));
+  var kind = DESCR_KIND(this);
   switch (kind) {
   case JS_TYPEREPR_SIZED_ARRAY_KIND:
     if (typeof a === "function") // XXX here and elsewhere: these type dispatches are fragile at best.
       return BuildTypedSeqImpl(this, this.length, 1, a);
     else if (typeof a === "number" && typeof b === "function")
       return BuildTypedSeqImpl(this, this.length, a, b);
     else if (typeof a === "number")
       return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "2", "function");
@@ -974,17 +1048,17 @@ function GET_BIT(data, index) {
   var word = index >> 3;
   var mask = 1 << (index & 0x7);
   return (data[word] & mask) != 0;
 }
 
 function TypeDescrIsArrayType(t) {
   assert(IsObject(t) && ObjectIsTypeDescr(t), "TypeDescrIsArrayType called on non-type-object");
 
-  var kind = REPR_KIND(TYPE_TYPE_REPR(t));
+  var kind = DESCR_KIND(t);
   switch (kind) {
   case JS_TYPEREPR_SIZED_ARRAY_KIND:
   case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
     return true;
   case JS_TYPEREPR_SCALAR_KIND:
   case JS_TYPEREPR_REFERENCE_KIND:
   case JS_TYPEREPR_X4_KIND:
   case JS_TYPEREPR_STRUCT_KIND:
@@ -992,17 +1066,17 @@ function TypeDescrIsArrayType(t) {
   default:
     return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1, "unknown kind of typed object");
   }
 }
 
 function TypeDescrIsSizedArrayType(t) {
   assert(IsObject(t) && ObjectIsTypeDescr(t), "TypeDescrIsSizedArrayType called on non-type-object");
 
-  var kind = REPR_KIND(TYPE_TYPE_REPR(t));
+  var kind = DESCR_KIND(t);
   switch (kind) {
   case JS_TYPEREPR_SIZED_ARRAY_KIND:
     return true;
   case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
   case JS_TYPEREPR_SCALAR_KIND:
   case JS_TYPEREPR_REFERENCE_KIND:
   case JS_TYPEREPR_X4_KIND:
   case JS_TYPEREPR_STRUCT_KIND:
@@ -1010,17 +1084,17 @@ function TypeDescrIsSizedArrayType(t) {
   default:
     return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1, "unknown kind of typed object");
   }
 }
 
 function TypeDescrIsSimpleType(t) {
   assert(IsObject(t) && ObjectIsTypeDescr(t), "TypeDescrIsSimpleType called on non-type-object");
 
-  var kind = REPR_KIND(TYPE_TYPE_REPR(t));
+  var kind = DESCR_KIND(t);
   switch (kind) {
   case JS_TYPEREPR_SCALAR_KIND:
   case JS_TYPEREPR_REFERENCE_KIND:
   case JS_TYPEREPR_X4_KIND:
     return true;
   case JS_TYPEREPR_SIZED_ARRAY_KIND:
   case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
   case JS_TYPEREPR_STRUCT_KIND:
@@ -1066,17 +1140,17 @@ function BuildTypedSeqImpl(arrayType, le
     callFunction(std_Array_pop, indices);
 
     if (r !== undefined) {
       // result[...indices] = r;
       AttachHandle(handle, result, offset); // (func might have moved handle)
       HandleSet(handle, r);                 // *handle = r
     }
     // Increment indices.
-    offset += REPR_SIZE(TYPE_TYPE_REPR(grainType));
+    offset += DESCR_SIZE(grainType);
     IncrementIterationSpace(indices, iterationSpace);
   }
 
   return result;
 }
 
 function ComputeIterationSpace(arrayType, depth, len) {
   assert(IsObject(arrayType) && ObjectIsTypeDescr(arrayType), "ComputeIterationSpace called on non-type-object");
@@ -1143,17 +1217,17 @@ function MapUntypedSeqImpl(inArray, outp
 
   var outLength = outputType.variable ? inArray.length : outputType.length;
   var outGrainType = outputType.elementType;
 
   // Create a zeroed instance with no data
   var result = outputType.variable ? new outputType(inArray.length) : new outputType();
 
   var outHandle = callFunction(HandleCreate, outGrainType);
-  var outUnitSize = REPR_SIZE(TYPE_TYPE_REPR(outGrainType));
+  var outUnitSize = DESCR_SIZE(outGrainType);
 
   // Core of map computation starts here (comparable to
   // DoMapTypedSeqDepth1 and DoMapTypedSeqDepthN below).
 
   var offset = 0;
   for (var i = 0; i < outLength; i++) {
     // In this loop, since depth is 1, "indices" denotes singleton array [i].
 
@@ -1203,18 +1277,18 @@ function MapTypedSeqImpl(inArray, depth,
       // TypeError("Incompatible iteration space in input and output type");
       ThrowError(JSMSG_TYPEDOBJECT_ARRAYTYPE_BAD_ARGS);
 
   // Create a zeroed instance with no data
   var result = outputType.variable ? new outputType(inArray.length) : new outputType();
 
   var inHandle = callFunction(HandleCreate, inGrainType);
   var outHandle = callFunction(HandleCreate, outGrainType);
-  var inUnitSize = REPR_SIZE(TYPE_TYPE_REPR(inGrainType));
-  var outUnitSize = REPR_SIZE(TYPE_TYPE_REPR(outGrainType));
+  var inUnitSize = DESCR_SIZE(inGrainType);
+  var outUnitSize = DESCR_SIZE(outGrainType);
 
   var inGrainTypeIsSimple = TypeDescrIsSimpleType(inGrainType);
 
   // Bug 956914: add additional variants for depth = 2, 3, etc.
 
   function DoMapTypedSeqDepth1() {
     var inOffset = 0;
     var outOffset = 0;
--- a/js/src/tests/ecma_6/TypedObject/structtypereflection.js
+++ b/js/src/tests/ecma_6/TypedObject/structtypereflection.js
@@ -15,17 +15,17 @@ 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.toSource(), "new StructType({x: int32, y: uint8, z: float64})");
     assertEq(S.variable, false);
     assertEq(S.byteLength, 16);
     assertEq(S.byteAlignment, 8);
     assertEq(S.fieldNames[0], "x");
     assertEq(S.fieldNames[1], "y");
     assertEq(S.fieldNames[2], "z");
     assertEq(S.fieldNames.length, 3);
     assertEq(S.fieldTypes.x, int32);
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -41,16 +41,17 @@
     macro(ConvertAndCopyTo, ConvertAndCopyTo, "ConvertAndCopyTo") \
     macro(currency, currency, "currency") \
     macro(currencyDisplay, currencyDisplay, "currencyDisplay") \
     macro(std_iterator, std_iterator, "@@iterator") \
     macro(DateTimeFormat, DateTimeFormat, "DateTimeFormat") \
     macro(DateTimeFormatFormatGet, DateTimeFormatFormatGet, "Intl_DateTimeFormat_format_get") \
     macro(decodeURI, decodeURI, "decodeURI") \
     macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \
+    macro(DescrToSource, DescrToSource, "DescrToSource") \
     macro(default_, default_, "default") \
     macro(defineProperty, defineProperty, "defineProperty") \
     macro(defineGetter, defineGetter, "__defineGetter__") \
     macro(defineSetter, defineSetter, "__defineSetter__") \
     macro(delete, delete_, "delete") \
     macro(deleteProperty, deleteProperty, "deleteProperty") \
     macro(displayURL, displayURL, "displayURL") \
     macro(done, done, "done") \