Bug 969578 -- Remove public facing Handle API r=till
authorNicholas D. Matsakis <nmatsakis@mozilla.com>
Mon, 10 Feb 2014 10:03:49 -0500
changeset 168372 2bb66930e064824285b33933e5ecc331e0fea047
parent 168371 33f464080abc6cff0cf315c0fe0535fb7e6d3189
child 168373 0a13fa6115e9dd0b8613b1a551205c77f144e448
push id26203
push userryanvm@gmail.com
push dateWed, 12 Feb 2014 20:48:00 +0000
treeherdermozilla-central@18e7634d4094 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs969578
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 969578 -- Remove public facing Handle API r=till
js/src/builtin/SIMD.cpp
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.js
js/src/jit-test/tests/TypedObject/gcunattachedhandle.js
js/src/tests/ecma_6/TypedObject/handle.js
js/src/tests/ecma_6/TypedObject/handle_get_set.js
js/src/tests/ecma_6/TypedObject/handle_move.js
js/src/tests/ecma_6/TypedObject/handle_unattached.js
js/src/tests/ecma_6/TypedObject/method_build.js
js/src/tests/ecma_6/TypedObject/method_from.js
js/src/tests/ecma_6/TypedObject/method_map.js
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -133,17 +133,16 @@ class Float32x4Defn {
     static const JSFunctionSpec TypeDescriptorMethods[];
     static const JSPropertySpec TypedDatumProperties[];
     static const JSFunctionSpec TypedDatumMethods[];
 };
 } // namespace js
 
 const JSFunctionSpec js::Float32x4Defn::TypeDescriptorMethods[] = {
     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),
     JS_PSG("y", Float32x4Lane1, JSPROP_PERMANENT),
@@ -155,17 +154,16 @@ 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_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),
     JS_PSG("y", Int32x4Lane1, JSPROP_PERMANENT),
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -211,17 +211,16 @@ const Class js::ScalarTypeDescr::class_ 
     ScalarTypeDescr::call,
     nullptr,
     nullptr,
     nullptr
 };
 
 const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
     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
 };
 
 static size_t ScalarSizes[] = {
 #define SCALAR_SIZE(_kind, _type, _name)                        \
     sizeof(_type),
@@ -312,17 +311,16 @@ const Class js::ReferenceTypeDescr::clas
     ReferenceTypeDescr::call,
     nullptr,
     nullptr,
     nullptr
 };
 
 const JSFunctionSpec js::ReferenceTypeDescr::typeObjectMethods[] = {
     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
 };
 
 /*static*/ const char *
 ReferenceTypeDescr::typeName(Type type)
 {
@@ -462,17 +460,16 @@ const Class SizedArrayTypeDescr::class_ 
     nullptr
 };
 
 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_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),
@@ -751,17 +748,16 @@ const Class StructTypeDescr::class_ = {
     nullptr  /* trace */
 };
 
 const JSPropertySpec StructMetaTypeDescr::typeObjectProperties[] = {
     JS_PS_END
 };
 
 const JSFunctionSpec StructMetaTypeDescr::typeObjectMethods[] = {
-    {"handle", {nullptr, nullptr}, 2, 0, "HandleCreate"},
     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
     JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     JS_FS_END
 };
 
 const JSPropertySpec StructMetaTypeDescr::typedObjectProperties[] = {
     JS_PS_END
@@ -1245,34 +1241,16 @@ GlobalObject::initTypedObjectModule(JSCo
 
     RootedValue structTypeValue(cx, ObjectValue(*structType));
     if (!JSObject::defineProperty(cx, module, cx->names().StructType,
                                   structTypeValue,
                                   nullptr, nullptr,
                                   JSPROP_READONLY | JSPROP_PERMANENT))
         return nullptr;
 
-    //  Handle
-
-    RootedObject handle(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
-    if (!module)
-        return nullptr;
-
-    if (!JS_DefineFunctions(cx, handle, TypedHandle::handleStaticMethods))
-        return nullptr;
-
-    RootedValue handleValue(cx, ObjectValue(*handle));
-    if (!JSObject::defineProperty(cx, module, cx->names().Handle,
-                                  handleValue,
-                                  nullptr, nullptr,
-                                  JSPROP_READONLY | JSPROP_PERMANENT))
-    {
-        return nullptr;
-    }
-
     // Everything is setup, install module on the global object:
     RootedValue moduleValue(cx, ObjectValue(*module));
     global->setConstructor(JSProto_TypedObject, moduleValue);
     if (!JSObject::defineProperty(cx, global, cx->names().TypedObject,
                                   moduleValue,
                                   nullptr, nullptr,
                                   0))
     {
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -176,16 +176,22 @@ TypedObjectPointer.prototype.copy = func
 
 TypedObjectPointer.prototype.reset = function(inPtr) {
   this.descr = inPtr.descr;
   this.datum = inPtr.datum;
   this.offset = inPtr.offset;
   return this;
 };
 
+TypedObjectPointer.prototype.bump = function(size) {
+  assert(TO_INT32(this.offset) === this.offset, "current offset not int");
+  assert(TO_INT32(size) === size, "size not int");
+  this.offset += size;
+}
+
 TypedObjectPointer.prototype.kind = function() {
   return DESCR_KIND(this.descr);
 }
 
 // Extract the length. This does a switch on kind, so it's
 // best if we can avoid it.
 TypedObjectPointer.prototype.length = function() {
   switch (this.kind()) {
@@ -307,45 +313,48 @@ TypedObjectPointer.prototype.moveToField
 //
 // 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
 // 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.
+// result will be a datum of the same class as the ptr's datum.
 TypedObjectPointer.prototype.get = function() {
   assert(ObjectIsAttached(this.datum), "get() called with unattached datum");
 
   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);
+    return this.getDerived();
 
   case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
     assert(false, "Unhandled repr kind: " + this.kind());
   }
 
   assert(false, "Unhandled kind: " + this.kind());
   return undefined;
 }
 
+TypedObjectPointer.prototype.getDerived = function() {
+  assert(!TypeDescrIsSimpleType(this.descr),
+         "getDerived() used with simple type");
+  return NewDerivedTypedDatum(this.descr, this.datum, this.offset);
+}
+
 TypedObjectPointer.prototype.getScalar = function() {
   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:
@@ -722,109 +731,16 @@ function TypedArrayRedimension(newArrayT
   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
-//
-// Note: these methods are directly invokable by users and so must be
-// defensive.
-
-// 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 (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:
-    ThrowError(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED);
-  }
-
-  var handle = NewTypedHandle(this);
-
-  if (obj !== undefined)
-    HandleMoveInternal(handle, obj, path);
-
-  return handle;
-}
-
-// Handle.move: user exposed!
-// FIXME bug 929656 -- label algorithms with steps from the spec
-function HandleMove(handle, obj, ...path) {
-  if (!IsObject(handle) || !ObjectIsTypedHandle(handle))
-    ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Handle", "set", typeof value);
-
-  HandleMoveInternal(handle, obj, path);
-}
-
-function HandleMoveInternal(handle, obj, path) {
-  assert(IsObject(handle) && ObjectIsTypedHandle(handle),
-         "HandleMoveInternal: not typed handle");
-
-  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 (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) {
-  if (!IsObject(handle) || !ObjectIsTypedHandle(handle))
-    ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Handle", "set", typeof value);
-
-  if (!ObjectIsAttached(handle))
-    ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
-
-  var ptr = TypedObjectPointer.fromTypedDatum(handle);
-  return ptr.get();
-}
-
-// Handle.set: user exposed!
-// FIXME bug 929656 -- label algorithms with steps from the spec
-function HandleSet(handle, value) {
-  if (!IsObject(handle) || !ObjectIsTypedHandle(handle))
-    ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Handle", "set", typeof value);
-
-  if (!ObjectIsAttached(handle))
-    ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
-
-  var ptr = TypedObjectPointer.fromTypedDatum(handle);
-  ptr.set(value);
-}
-
-// Handle.isHandle: user exposed!
-// FIXME bug 929656 -- label algorithms with steps from the spec
-function HandleTest(obj) {
-  return IsObject(obj) && ObjectIsTypedHandle(obj);
-}
-
-///////////////////////////////////////////////////////////////////////////
 // X4
 
 function X4ProtoString(type) {
   switch (type) {
   case JS_X4TYPEREPR_INT32:
     return "int32x4";
   case JS_X4TYPEREPR_FLOAT32:
     return "float32x4";
@@ -948,17 +864,16 @@ function TypedObjectArrayTypeFrom(a, b, 
 
   var untypedInput = !IsObject(a) || !ObjectIsTypedDatum(a);
 
   // for untyped input array, the expectation (in terms of error
   // reporting for invalid parameters) is no-depth, despite
   // supporting an explicit depth of 1; while for typed input array,
   // the expectation is explicit depth.
 
-
   if (untypedInput) {
     var explicitDepth = (b === 1);
     if (explicitDepth && IsCallable(c))
       return MapUntypedSeqImpl(a, this, c);
     else if (IsCallable(b))
       return MapUntypedSeqImpl(a, this, b);
     else
       return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "2", "function");
@@ -1163,35 +1078,35 @@ function BuildTypedSeqImpl(arrayType, le
   // Create a zeroed instance with no data
   var result = arrayType.variable ? new arrayType(len) : new arrayType();
 
   var indices = NewDenseArray(depth);
   for (var i = 0; i < depth; i++) {
     indices[i] = 0;
   }
 
-  var handle = callFunction(HandleCreate, grainType);
-  var offset = 0;
+  var grainTypeIsSimple = TypeDescrIsSimpleType(grainType);
+  var size = DESCR_SIZE(grainType);
+  var outPointer = new TypedObjectPointer(grainType, result, 0);
   for (i = 0; i < totalLength; i++) {
-    // Position handle to point at &result[...indices]
-    AttachHandle(handle, result, offset);
+    // Position out-pointer to point at &result[...indices], if appropriate.
+    var userOutPointer = (grainTypeIsSimple
+                          ? undefined
+                          : outPointer.getDerived());
 
-    // Invoke func(...indices, out)
-    callFunction(std_Array_push, indices, handle);
-    var r = callFunction(std_Function_apply, func, void 0, indices);
+    // Invoke func(...indices, userOutPointer) and store the result
+    callFunction(std_Array_push, indices, userOutPointer);
+    var r = callFunction(std_Function_apply, func, undefined, indices);
     callFunction(std_Array_pop, indices);
+    if (r !== undefined)
+      outPointer.set(r); // result[...indices] = r;
 
-    if (r !== undefined) {
-      // result[...indices] = r;
-      AttachHandle(handle, result, offset); // (func might have moved handle)
-      HandleSet(handle, r);                 // *handle = r
-    }
     // Increment indices.
-    offset += DESCR_SIZE(grainType);
     IncrementIterationSpace(indices, iterationSpace);
+    outPointer.bump(size);
   }
 
   return result;
 }
 
 function ComputeIterationSpace(arrayType, depth, len) {
   assert(IsObject(arrayType) && ObjectIsTypeDescr(arrayType), "ComputeIterationSpace called on non-type-object");
   assert(TypeDescrIsArrayType(arrayType), "ComputeIterationSpace called on non-array-type");
@@ -1256,45 +1171,42 @@ function MapUntypedSeqImpl(inArray, outp
   // is trivially compatible with any iteration space of depth 1.
 
   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 = DESCR_SIZE(outGrainType);
+  var outGrainTypeIsSimple = TypeDescrIsSimpleType(outGrainType);
+  var outPointer = new TypedObjectPointer(outGrainType, result, 0);
 
   // 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].
 
-    // Adjust handle to point at &array[...indices] for result array.
-    AttachHandle(outHandle, result, offset);
-
     if (i in inArray) { // Check for holes (only needed for untyped case).
-
-      // Extract element value (no input handles for untyped case).
+      // Extract element value.
       var element = inArray[i];
 
-      // Invoke: var r = func(element, ...indices, collection, out);
-      var r = func(element, i, inArray, outHandle);
+      // Create out pointer to point at &array[...indices] for result array.
+      var out = (outGrainTypeIsSimple ? undefined : outPointer.getDerived());
 
-      if (r !== undefined) {
-        AttachHandle(outHandle, result, offset); // (func could move handle)
-        HandleSet(outHandle, r); // *handle = r; (i.e. result[i] = r).
-      }
+      // Invoke: var r = func(element, ...indices, collection, out);
+      var r = func(element, i, inArray, out);
+
+      if (r !== undefined)
+        outPointer.set(r); // result[i] = r
     }
 
     // Update offset and (implicitly) increment indices.
-    offset += outUnitSize;
+    outPointer.bump(outUnitSize);
   }
 
   return result;
 }
 
 // Implements |map| and |from| methods for typed |inArray|.
 function MapTypedSeqImpl(inArray, depth, outputType, func) {
   assert(IsObject(outputType) && ObjectIsTypeDescr(outputType), "2. Map/From called on non-type-object outputType");
@@ -1315,82 +1227,67 @@ function MapTypedSeqImpl(inArray, depth,
   for (var i = 0; i < depth; i++)
     if (inIterationSpace[i] !== iterationSpace[i])
       // 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 inGrainTypeIsSimple = TypeDescrIsSimpleType(inGrainType);
+  var outGrainTypeIsSimple = TypeDescrIsSimpleType(outGrainType);
+
+  var inPointer = new TypedObjectPointer(inGrainType, inArray, 0);
+  var outPointer = new TypedObjectPointer(outGrainType, result, 0);
+
   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;
-
     for (var i = 0; i < totalLength; i++) {
       // In this loop, since depth is 1, "indices" denotes singleton array [i].
 
-      // Adjust handles to point at &array[...indices] for in and out array.
-      AttachHandle(inHandle, inArray, inOffset);
-      AttachHandle(outHandle, result, outOffset);
-
-      // Extract element value if simple; if not, handle acts as array element.
-      var element = (inGrainTypeIsSimple ? HandleGet(inHandle) : inHandle);
+      // Prepare input element/handle and out pointer
+      var element = inPointer.get();
+      var out = (outGrainTypeIsSimple ? undefined : outPointer.getDerived());
 
       // Invoke: var r = func(element, ...indices, collection, out);
-      var r = func(element, i, inArray, outHandle);
-
-      if (r !== undefined) {
-        AttachHandle(outHandle, result, outOffset); // (func could move handle)
-        HandleSet(outHandle, r); // *handle = r; (i.e. result[i] = r).
-      }
+      var r = func(element, i, inArray, out);
+      if (r !== undefined)
+        outPointer.set(r); // result[i] = r
 
       // Update offsets and (implicitly) increment indices.
-      inOffset += inUnitSize;
-      outOffset += outUnitSize;
+      inPointer.bump(inUnitSize);
+      outPointer.bump(outUnitSize);
     }
 
     return result;
   }
 
   function DoMapTypedSeqDepthN() {
     var indices = new Uint32Array(depth);
 
-    var inOffset = 0;
-    var outOffset = 0;
     for (var i = 0; i < totalLength; i++) {
-      // Adjust handles to point at &array[...indices] for in and out array.
-      AttachHandle(inHandle, inArray, inOffset);
-      AttachHandle(outHandle, result, outOffset);
-
-      // Extract element value if simple; if not, handle acts as array element.
-      var element = (inGrainTypeIsSimple ? HandleGet(inHandle) : inHandle);
+      // Prepare input element and out pointer
+      var element = inPointer.get();
+      var out = (outGrainTypeIsSimple ? undefined : outPointer.getDerived());
 
       // Invoke: var r = func(element, ...indices, collection, out);
       var args = [element];
       callFunction(std_Function_apply, std_Array_push, args, indices);
-      callFunction(std_Array_push, args, inArray, outHandle);
+      callFunction(std_Array_push, args, inArray, out);
       var r = callFunction(std_Function_apply, func, void 0, args);
-
-      if (r !== undefined) {
-        AttachHandle(outHandle, result, outOffset); // (func could move handle)
-        HandleSet(outHandle, r);                    // *handle = r
-      }
+      if (r !== undefined)
+        outPointer.set(r); // result[...indices] = r
 
       // Update offsets and explicitly increment indices.
-      inOffset += inUnitSize;
-      outOffset += outUnitSize;
+      inPointer.bump(inUnitSize);
+      outPointer.bump(outUnitSize);
       IncrementIterationSpace(indices, iterationSpace);
     }
 
     return result;
   }
 
   if  (depth == 1) {
     return DoMapTypedSeqDepth1();
@@ -1476,24 +1373,25 @@ function FilterTypedSeqImpl(array, func)
   assert(typeof func === "function", "Filter called with non-function predicate");
 
   var arrayType = TypeOfTypedDatum(array);
   if (!TypeDescrIsArrayType(arrayType))
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
 
   var elementType = arrayType.elementType;
   var flags = new Uint8Array(NUM_BYTES(array.length));
-  var handle = callFunction(HandleCreate, elementType);
   var count = 0;
+  var size = DESCR_SIZE(elementType);
+  var inPointer = new TypedObjectPointer(elementType, array, 0);
   for (var i = 0; i < array.length; i++) {
-    HandleMove(handle, array, i);
-    if (func(HandleGet(handle), i, array)) {
+    if (func(inPointer.get(), i, array)) {
       SET_BIT(flags, i);
       count++;
     }
+    inPointer.bump(size);
   }
 
   var resultType = (arrayType.variable ? arrayType : arrayType.unsized);
   var result = new resultType(count);
   for (var i = 0, j = 0; i < array.length; i++) {
     if (GET_BIT(flags, i))
       result[j++] = array[i];
   }
deleted file mode 100644
--- a/js/src/jit-test/tests/TypedObject/gcunattachedhandle.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Test that we can trace a unattached handle.
-
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-if (!this.hasOwnProperty("TypedObject"))
-  quit();
-
-var Object = TypedObject.Object;
-var handle0 = Object.handle();
-gc();
deleted file mode 100644
--- a/js/src/tests/ecma_6/TypedObject/handle.js
+++ /dev/null
@@ -1,60 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
-
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-var BUGNUMBER = 898342;
-var summary = 'Handles';
-
-var T = TypedObject;
-
-function runTests() {
-  var Point = T.float32.array(3);
-  var Line = new T.StructType({from: Point, to: Point});
-  var Lines = Line.array(3);
-
-  var lines = new Lines([
-    {from: [1, 2, 3], to: [4, 5, 6]},
-    {from: [7, 8, 9], to: [10, 11, 12]},
-    {from: [13, 14, 15], to: [16, 17, 18]}
-  ]);
-
-  var handle = Lines.handle(lines);
-  var handle0 = Line.handle(lines, 0);
-  var handle2 = Line.handle(lines, 2);
-
-  // Reads from handles should see the correct data:
-  assertEq(handle[0].from[0], 1);
-  assertEq(handle0.from[0], 1);
-  assertEq(handle2.from[0], 13);
-
-  // Writes to handles should modify the original:
-  handle2.from[0] = 22;
-  assertEq(lines[2].from[0], 22);
-
-  // Reads from handles should see the updated data:
-  assertEq(handle[0].from[0], 1);
-  assertEq(handle0.from[0], 1);
-  assertEq(handle2.from[0], 22);
-
-  // isHandle, when called on nonsense, returns false:
-  assertEq(T.Handle.isHandle(22), false);
-  assertEq(T.Handle.isHandle({}), false);
-
-  // Derived handles should remain handles:
-  assertEq(T.Handle.isHandle(lines), false);
-  assertEq(T.Handle.isHandle(lines[0]), false);
-  assertEq(T.Handle.isHandle(lines[0].from), false);
-  assertEq(T.Handle.isHandle(handle), true);
-  assertEq(T.Handle.isHandle(handle[0]), true);
-  assertEq(T.Handle.isHandle(handle[0].from), true);
-
-  reportCompare(true, true);
-  print("Tests complete");
-}
-
-runTests();
-
-
deleted file mode 100644
--- a/js/src/tests/ecma_6/TypedObject/handle_get_set.js
+++ /dev/null
@@ -1,79 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
-
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-var BUGNUMBER = 898342;
-var summary = 'Handle Move';
-
-var T = TypedObject;
-
-var Point = T.float32.array(3);
-var Line = new T.StructType({from: Point, to: Point});
-var Lines = Line.array(3);
-
-var Objects = T.Object.array(3);
-
-function runTests() {
-  function testHandleGetSetWithScalarType() {
-    var lines = new Lines([
-      {from: [1, 2, 3], to: [4, 5, 6]},
-      {from: [7, 8, 9], to: [10, 11, 12]},
-      {from: [13, 14, 15], to: [16, 17, 18]}
-    ]);
-
-    var handle = T.float32.handle(lines, 0, "to", 1);
-    assertEq(T.Handle.get(handle), 5);
-    T.Handle.set(handle, 22);
-    assertEq(T.Handle.get(handle), 22);
-    assertEq(lines[0].to[1], 22);
-  }
-  testHandleGetSetWithScalarType();
-
-  function testHandleGetSetWithObjectType() {
-    var one = {x: 1};
-    var two = {x: 2};
-    var three = {x: 3};
-    var objects = new Objects([one, two, three]);
-
-    var handle = T.Object.handle(objects, 0);
-    assertEq(T.Handle.get(handle), one);
-    T.Handle.set(handle, three);
-    assertEq(T.Handle.get(handle), three);
-    assertEq(objects[0], three);
-
-    T.Handle.move(handle, objects, 1);
-    assertEq(T.Handle.get(handle), two);
-  }
-  testHandleGetSetWithScalarType();
-
-  function testHandleGetSetWithComplexType() {
-    var lines = new Lines([
-      {from: [1, 2, 3], to: [4, 5, 6]},
-      {from: [7, 8, 9], to: [10, 11, 12]},
-      {from: [13, 14, 15], to: [16, 17, 18]}
-    ]);
-
-    var handle = Point.handle(lines, 0, "to");
-
-    T.Handle.set(handle, [22, 23, 24]);
-
-    assertEq(handle[0], 22);
-    assertEq(handle[1], 23);
-    assertEq(handle[2], 24);
-
-    assertEq(T.Handle.get(handle)[0], 22);
-    assertEq(T.Handle.get(handle)[1], 23);
-    assertEq(T.Handle.get(handle)[2], 24);
-  }
-  testHandleGetSetWithComplexType();
-
-  reportCompare(true, true);
-  print("Tests complete");
-}
-
-runTests();
-
-
deleted file mode 100644
--- a/js/src/tests/ecma_6/TypedObject/handle_move.js
+++ /dev/null
@@ -1,162 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
-
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-var BUGNUMBER = 898342;
-var summary = 'Handle Move';
-
-var T = TypedObject;
-
-var Point = T.float32.array(3);
-var Line = new T.StructType({from: Point, to: Point});
-var Lines = Line.array(3);
-
-function runTests() {
-  function testHandleToPoint() {
-    var lines = new Lines([
-      {from: [1, 2, 3], to: [4, 5, 6]},
-      {from: [7, 8, 9], to: [10, 11, 12]},
-      {from: [13, 14, 15], to: [16, 17, 18]}
-    ]);
-
-    function allPoints(lines, func) {
-      var handle = Point.handle();
-      for (var i = 0; i < lines.length; i++) {
-        T.Handle.move(handle, lines, i, "from");
-        func(handle);
-
-        T.Handle.move(handle, lines, i, "to");
-        func(handle);
-      }
-    }
-
-    // Iterate over all ponts and mutate them in place:
-    allPoints(lines, function(p) {
-      p[0] += 100;
-      p[1] += 200;
-      p[2] += 300;
-    });
-
-    // Spot check the results
-    assertEq(lines[0].from[0], 101);
-    assertEq(lines[1].to[1], 211);
-    assertEq(lines[2].to[2], 318);
-  }
-  testHandleToPoint();
-
-  function testHandleToFloat() {
-    var lines = new Lines([
-      {from: [1, 2, 3], to: [4, 5, 6]},
-      {from: [7, 8, 9], to: [10, 11, 12]},
-      {from: [13, 14, 15], to: [16, 17, 18]}
-    ]);
-
-    function allPoints(lines, func) {
-      var handle = T.float32.handle();
-      for (var i = 0; i < lines.length; i++) {
-        T.Handle.move(handle, lines, i, "from", 0);
-        func(handle);
-
-        T.Handle.move(handle, lines, i, "from", 1);
-        func(handle);
-
-        T.Handle.move(handle, lines, i, "from", 2);
-        func(handle);
-
-        T.Handle.move(handle, lines, i, "to", 0);
-        func(handle);
-
-        T.Handle.move(handle, lines, i, "to", 1);
-        func(handle);
-
-        T.Handle.move(handle, lines, i, "to", 2);
-        func(handle);
-      }
-    }
-
-    // Iterate over all ponts and mutate them in place:
-    allPoints(lines, function(p) {
-      T.Handle.set(p, T.Handle.get(p) + 100);
-    });
-
-    // Spot check the results
-    assertEq(lines[0].from[0], 101);
-    assertEq(lines[1].to[1], 111);
-    assertEq(lines[2].to[2], 118);
-  }
-  testHandleToFloat();
-
-  function testHandleToEquivalentType() {
-    var Point2 = T.float32.array(3);
-
-    assertEq(Point.equivalent(Point2), true);
-
-    var lines = new Lines([
-      {from: [1, 2, 3], to: [4, 5, 6]},
-      {from: [7, 8, 9], to: [10, 11, 12]},
-      {from: [13, 14, 15], to: [16, 17, 18]}
-    ]);
-
-    var handle = Point2.handle(lines, 0, "to");
-    assertEq(handle[0], 4);
-    assertEq(handle[1], 5);
-    assertEq(handle[2], 6);
-  }
-  testHandleToEquivalentType();
-
-  function testHandleMoveToIllegalType() {
-    var lines = new Lines([
-      {from: [1, 2, 3], to: [4, 5, 6]},
-      {from: [7, 8, 9], to: [10, 11, 12]},
-      {from: [13, 14, 15], to: [16, 17, 18]}
-    ]);
-
-    // Moving a handle to a value of incorrect type should report an error:
-    assertThrowsInstanceOf(function() {
-      Line.handle(lines);
-    }, TypeError, "handle moved to destination of incorrect type");
-    assertThrowsInstanceOf(function() {
-      var h = Line.handle();
-      T.Handle.move(h, lines);
-    }, TypeError, "handle moved to destination of incorrect type");
-    assertThrowsInstanceOf(function() {
-      var h = T.float32.handle();
-      T.Handle.move(h, lines, 0);
-    }, TypeError, "handle moved to destination of incorrect type");
-  }
-  testHandleMoveToIllegalType();
-
-  function testHandleMoveToIllegalProperty() {
-    var lines = new Lines([
-      {from: [1, 2, 3], to: [4, 5, 6]},
-      {from: [7, 8, 9], to: [10, 11, 12]},
-      {from: [13, 14, 15], to: [16, 17, 18]}
-    ]);
-
-    assertThrowsInstanceOf(function() {
-      var h = Point.handle();
-      T.Handle.move(h, lines, 0, "foo");
-    }, TypeError, "No such property: foo");
-
-    assertThrowsInstanceOf(function() {
-      var h = Point.handle();
-      T.Handle.move(h, lines, 22, "to");
-    }, TypeError, "No such property: 22");
-
-    assertThrowsInstanceOf(function() {
-      var h = Point.handle();
-      T.Handle.move(h, lines, -100, "to");
-    }, TypeError, "No such property: -100");
-  }
-  testHandleMoveToIllegalProperty();
-
-  reportCompare(true, true);
-  print("Tests complete");
-}
-
-runTests();
-
-
deleted file mode 100644
--- a/js/src/tests/ecma_6/TypedObject/handle_unattached.js
+++ /dev/null
@@ -1,49 +0,0 @@
-// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
-
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/licenses/publicdomain/
- */
-
-var BUGNUMBER = 898342;
-var summary = 'Unattached handles';
-
-var T = TypedObject;
-
-function runTests() {
-  var Line = new T.StructType({from: T.uint8, to: T.uint8});
-  var Lines = Line.array(3);
-
-  // Create unattached handle to array, struct:
-  var handle = Lines.handle();
-  var handle0 = Line.handle();
-
-  // Accessing length throws:
-  assertThrowsInstanceOf(function() handle.length, TypeError,
-                         "handle.length did not yield error");
-
-  // Accessing properties throws:
-  assertThrowsInstanceOf(function() handle[0], TypeError,
-                         "Unattached handle did not yield error");
-  assertThrowsInstanceOf(function() handle0.from, TypeError,
-                         "Unattached handle did not yield error");
-
-  // Handle.get() throws:
-  assertThrowsInstanceOf(function() T.Handle.get(handle), TypeError,
-                         "Unattached handle did not yield error");
-  assertThrowsInstanceOf(function() T.Handle.get(handle0), TypeError,
-                         "Unattached handle did not yield error");
-
-  // Handle.set() throws:
-  assertThrowsInstanceOf(function() T.Handle.set(handle, [{},{},{}]), TypeError,
-                         "Unattached handle did not yield error");
-  assertThrowsInstanceOf(function() T.Handle.set(handle0, {}), TypeError,
-                         "Unattached handle did not yield error");
-
-  reportCompare(true, true);
-  print("Tests complete");
-}
-
-runTests();
-
-
--- a/js/src/tests/ecma_6/TypedObject/method_build.js
+++ b/js/src/tests/ecma_6/TypedObject/method_build.js
@@ -14,25 +14,21 @@ var uint16 = TypedObject.uint16;
 var uint32 = TypedObject.uint32;
 var uint8Clamped = TypedObject.uint8Clamped;
 var int8 = TypedObject.int8;
 var int16 = TypedObject.int16;
 var int32 = TypedObject.int32;
 var float32 = TypedObject.float32;
 var float64 = TypedObject.float64;
 
-var Handle = TypedObject.Handle;
-
 function oneDimensionalArrayOfUints() {
   var grain = uint32;
   var type = grain.array(4);
   var r1 = type.build(x => x * 2);
-  var r2 = type.build((x, out) => Handle.set(out, x * 2));
   assertTypedEqual(type, r1, new type([0, 2, 4, 6]));
-  assertTypedEqual(type, r1, r2);
 }
 
 function oneDimensionalArrayOfStructs() {
   var grain = new StructType({f: uint32});
   var type = grain.array(4);
   var r1 = type.build(x => new grain({f: x * 2}));
   var r2 = type.build((x, out) => { out.f = x * 2; });
   assertTypedEqual(type, r1, new type([{f:0}, {f:2},
@@ -82,20 +78,18 @@ function twoDimensionalArrayOfStructsWit
                                        [{f:10}, {f:11}]]));
   assertTypedEqual(type, r1, r2);
 }
 
 function threeDimensionalArrayOfUintsWithDepth3() {
   var grain = uint32;
   var type = grain.array(2).array(2).array(2);
   var r1 = type.build(3, (x,y,z) => x * 100 + y * 10 + z);
-  var r2 = type.build(3, (x,y,z, out) => Handle.set(out, x * 100 + y * 10 + z));
   assertTypedEqual(type, r1, new type([[[  0,   1], [ 10,  11]],
                                        [[100, 101], [110, 111]]]));
-  assertTypedEqual(type, r1, r2);
 }
 
 function threeDimensionalArrayOfUintsWithDepth2() {
   var grain = uint32.array(2);
   var type = grain.array(2).array(2);
   var r1 = type.build(2, (x,y) => [x * 100 + y * 10 + 0, x * 100 + y * 10 + 1]);
   var r1b = type.build(2, (x,y) => grain.build(z => x * 100 + y * 10 + z));
   var r1c = type.build(2, (x,y) => grain.build(1, z => x * 100 + y * 10 + z));
--- a/js/src/tests/ecma_6/TypedObject/method_from.js
+++ b/js/src/tests/ecma_6/TypedObject/method_from.js
@@ -14,18 +14,16 @@ var uint16 = TypedObject.uint16;
 var uint32 = TypedObject.uint32;
 var uint8Clamped = TypedObject.uint8Clamped;
 var int8 = TypedObject.int8;
 var int16 = TypedObject.int16;
 var int32 = TypedObject.int32;
 var float32 = TypedObject.float32;
 var float64 = TypedObject.float64;
 
-var Handle = TypedObject.Handle;
-
 // Test name format:
 
 // from<N>DimArrayOf<G1>sTo<G2>s where <N> is a positive integer (or its
 // equivalent word in English) and <G1> and <G2> are both grain types
 // (potentially an array themselves.)
 
 function fromOneDimArrayOfUint8ToUint32s() {
   var intype = uint8.array(4);
@@ -53,75 +51,66 @@ function fromTwoDimArrayOfUint8ToUint32s
   var type = rowtype.array(4);
   var i1 = new type([[10, 11, 12, 13],
                      [20, 21, 22, 23],
                      [30, 31, 32, 33],
                      [40, 41, 42, 43]]);
 
   var r1 = type.from(i1, 2, x => x*2);
   var r2 = type.from(i1, 1, a => rowtype.from(a, 1, x => x*2));
-  var r3 = type.from(i1, 1,
-    a => rowtype.from(a, 1, (x, j, c, out) => Handle.set(out, x*2)));
-  var r4 = type.from(i1, 1, (a, j, c, out) => { out[0] = a[0]*2;
+  var r3 = type.from(i1, 1, (a, j, c, out) => { out[0] = a[0]*2;
                                                 out[1] = a[1]*2;
                                                 out[2] = a[2]*2;
                                                 out[3] = a[3]*2; });
   assertTypedEqual(type, r1, new type([[20, 22, 24, 26],
                                        [40, 42, 44, 46],
                                        [60, 62, 64, 66],
                                        [80, 82, 84, 86]]));
   assertTypedEqual(type, r1, r2);
   assertTypedEqual(type, r1, r3);
-  assertTypedEqual(type, r1, r4);
 }
 
 function fromTwoDimArrayOfUint32ToUint8s() {
   var intype = uint32.array(4).array(4);
   var rowtype = uint8.array(4);
   var type = rowtype.array(4);
   var i1 = new type([[10, 11, 12, 13],
                      [20, 21, 22, 23],
                      [30, 31, 32, 33],
                      [40, 41, 42, 43]]);
 
   var r1 = type.from(i1, 2, x => x*2);
   var r2 = type.from(i1, 1, a => rowtype.from(a, 1, x => x*2));
-  var r3 = type.from(i1, 1,
-    a => rowtype.from(a, 1, (x, j, c, out) => Handle.set(out, x*2)));
-  var r4 = type.from(i1, 1, (a, j, c, out) => { out[0] = a[0]*2;
+  var r3 = type.from(i1, 1, (a, j, c, out) => { out[0] = a[0]*2;
                                                 out[1] = a[1]*2;
                                                 out[2] = a[2]*2;
                                                 out[3] = a[3]*2; });
   assertTypedEqual(type, r1, new type([[20, 22, 24, 26],
                                        [40, 42, 44, 46],
                                        [60, 62, 64, 66],
                                        [80, 82, 84, 86]]));
   assertTypedEqual(type, r1, r2);
   assertTypedEqual(type, r1, r3);
-  assertTypedEqual(type, r1, r4);
 }
 
 function fromOneDimArrayOfArrayOfUint8ToUint32s() {
   var intype = uint8.array(4).array(4);
   var type = uint32.array(4);
   var i1 = new intype([[0xdd, 0xcc, 0xbb, 0xaa],
                        [0x09, 0x08, 0x07, 0x06],
                        [0x15, 0x14, 0x13, 0x12],
                        [0x23, 0x32, 0x41, 0x50]]);
 
   function combine(a,b,c,d) { return a << 24 | b << 16 | c << 8 | d; }
 
   var r1 = type.from(i1, x => combine(x[0], x[1], x[2], x[3]));
-  var r2 = type.from(i1, 1,
-    (x, i, c, out) => Handle.set(out, combine(x[0], x[1], x[2], x[3])));
   assertTypedEqual(type, r1, new type([0xddccbbaa,
                                        0x09080706,
                                        0x15141312,
                                        0x23324150]));
-  assertTypedEqual(type, r1, r2);
 }
 
 function fromOneDimArrayOfUint32ToArrayOfUint8s() {
   var intype = uint32.array(4);
   var type = uint8.array(4).array(4);
   var i1 = new intype([0xddccbbaa,
                        0x09080706,
                        0x15141312,
--- a/js/src/tests/ecma_6/TypedObject/method_map.js
+++ b/js/src/tests/ecma_6/TypedObject/method_map.js
@@ -14,18 +14,16 @@ var uint16 = TypedObject.uint16;
 var uint32 = TypedObject.uint32;
 var uint8Clamped = TypedObject.uint8Clamped;
 var int8 = TypedObject.int8;
 var int16 = TypedObject.int16;
 var int32 = TypedObject.int32;
 var float32 = TypedObject.float32;
 var float64 = TypedObject.float64;
 
-var Handle = TypedObject.Handle;
-
 // Test name format:
 
 // map<N>DimArrayOf<G1>sTo<G2>s where <N> is a positive integer (or its
 // equivalent word in English) and <G1> and <G2> are both grain types
 // (potentially an array themselves.)
 
 function mapOneDimArrayOfUint8() {
   var type = uint8.array(4);
@@ -49,51 +47,47 @@ function mapTwoDimArrayOfUint8() {
   var type = uint8.array(4).array(4);
   var i1 = new type([[10, 11, 12, 13],
                      [20, 21, 22, 23],
                      [30, 31, 32, 33],
                      [40, 41, 42, 43]]);
 
   var r1 = i1.map(2, x => x*2);
   var r2 = i1.map(1, a => a.map(1, x => x*2));
-  var r3 = i1.map(1, a => a.map(1, (x, j, c, out) => Handle.set(out, x*2)));
-  var r4 = i1.map(1, (a, j, c, out) => { out[0] = a[0]*2;
+  var r3 = i1.map(1, (a, j, c, out) => { out[0] = a[0]*2;
                                          out[1] = a[1]*2;
                                          out[2] = a[2]*2;
                                          out[3] = a[3]*2; });
   assertTypedEqual(type, r1, new type([[20, 22, 24, 26],
                                        [40, 42, 44, 46],
                                        [60, 62, 64, 66],
                                        [80, 82, 84, 86]]));
   assertTypedEqual(type, r1, r2);
   assertTypedEqual(type, r1, r3);
-  assertTypedEqual(type, r1, r4);
 }
 
 function mapTwoDimArrayOfUint32() {
   var type = uint32.array(4).array(4);
   var i1 = new type([[10, 11, 12, 13],
                      [20, 21, 22, 23],
                      [30, 31, 32, 33],
                      [40, 41, 42, 43]]);
 
   var r1 = i1.map(2, x => x*2);
   var r2 = i1.map(1, a => a.map(1, x => x*2));
-  var r3 = i1.map(1, a => a.map(1, (x, j, c, out) => Handle.set(out, x*2)));
-  var r4 = i1.map(1, (a, j, c, out) => { out[0] = a[0]*2;
+  var r3 = i1.map(1, (a, j, c, out) => { out[0] = a[0]*2;
                                          out[1] = a[1]*2;
                                          out[2] = a[2]*2;
                                          out[3] = a[3]*2; });
   assertTypedEqual(type, r1, new type([[20, 22, 24, 26],
                                        [40, 42, 44, 46],
                                        [60, 62, 64, 66],
                                        [80, 82, 84, 86]]));
   assertTypedEqual(type, r1, r2);
   assertTypedEqual(type, r1, r3);
-  assertTypedEqual(type, r1, r4);
 }
 
 var Grain = new StructType({f: uint32});
 function wrapG(v) { return new Grain({f: v}); }
 function doubleG(g) { return new Grain({f: g.f * 2}); }
 function tenG(x, y) { return new Grain({f: x * 10 + y}); }
 
 function mapOneDimArrayOfStructs() {