Bug 966575 part06 -- Move field info into reserved slots, remove non-standard fieldName r=sfink
authorNicholas D. Matsakis <nmatsakis@mozilla.com>
Wed, 29 Jan 2014 14:04:05 -0500
changeset 168103 7ff5470b1d28d35d607646cfd4ab0c402d6535a2
parent 168102 639a7d0a840413c4bf1638518294c83c2090dfd8
child 168104 f1ad2702b533bab7473e86d5e202b12f0eb18dd6
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 part06 -- Move field info into reserved slots, remove non-standard fieldName r=sfink
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/builtin/TypedObject.js
js/src/builtin/TypedObjectConstants.h
js/src/tests/ecma_6/TypedObject/shell.js
js/src/tests/ecma_6/TypedObject/structtypereflection.js
js/src/vm/CommonPropertyNames.h
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -125,17 +125,16 @@ ConvertAndCopyTo(JSContext *cx, HandleTy
 }
 
 /*
  * Overwrites the contents of `datum` at offset `offset` with `val`
  * converted to the type `typeObj`
  */
 static bool
 Reify(JSContext *cx,
-      TypeRepresentation *typeRepr,
       HandleTypeDescr type,
       HandleTypedDatum datum,
       size_t offset,
       MutableHandleValue to)
 {
     RootedFunction func(cx, SelfHostedFunction(cx, cx->names().Reify));
     if (!func)
         return false;
@@ -777,46 +776,62 @@ StructMetaTypeDescr::layout(JSContext *c
     typeReprObj = StructTypeRepresentation::Create(cx, fieldNames, fieldTypeReprObjs);
     if (!typeReprObj)
         return false;
     StructTypeRepresentation *typeRepr =
         TypeRepresentation::fromOwnerObject(*typeReprObj)->asStruct();
     structType->initReservedSlot(JS_DESCR_SLOT_TYPE_REPR,
                                  ObjectValue(*typeReprObj));
 
+    // Construct for internal use an array with names of each field
+    {
+        AutoValueVector fieldNameValues(cx);
+        for (unsigned int i = 0; i < ids.length(); i++) {
+            RootedValue value(cx, IdToValue(ids[i]));
+            if (!fieldNameValues.append(value))
+                return false;
+        }
+        RootedObject fieldNamesVec(
+            cx, NewDenseCopiedArray(cx, fieldNameValues.length(),
+                                    fieldNameValues.begin()));
+        if (!fieldNamesVec)
+            return false;
+        structType->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_NAMES,
+                                     ObjectValue(*fieldNamesVec));
+    }
+
     // Construct for internal use an array with the type object for each field.
-    RootedObject fieldTypeVec(
-        cx, NewDenseCopiedArray(cx, fieldTypeObjs.length(),
-                                fieldTypeObjs.begin()));
-    if (!fieldTypeVec)
-        return false;
-
-    structType->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES,
-                                 ObjectValue(*fieldTypeVec));
-
-    // Construct the fieldNames vector
-    AutoValueVector fieldNameValues(cx);
-    for (unsigned int i = 0; i < ids.length(); i++) {
-        RootedValue value(cx, IdToValue(ids[i]));
-        if (!fieldNameValues.append(value))
+    {
+        RootedObject fieldTypeVec(cx);
+        fieldTypeVec = NewDenseCopiedArray(cx, fieldTypeObjs.length(),
+                                           fieldTypeObjs.begin());
+        if (!fieldTypeVec)
             return false;
+        structType->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES,
+                                     ObjectValue(*fieldTypeVec));
     }
-    RootedObject fieldNamesVec(
-        cx, NewDenseCopiedArray(cx, fieldNameValues.length(),
-                                fieldNameValues.begin()));
-    if (!fieldNamesVec)
-        return false;
-    RootedValue fieldNamesVecValue(cx, ObjectValue(*fieldNamesVec));
-    if (!JSObject::defineProperty(cx, structType, cx->names().fieldNames,
-                                  fieldNamesVecValue, nullptr, nullptr,
-                                  JSPROP_READONLY | JSPROP_PERMANENT))
-        return false;
-
-    // Construct the fieldNames, fieldOffsets and fieldTypes objects:
-    // fieldNames : [ string ]
+
+    // Construct for internal use an array with the offset for each field.
+    {
+        AutoValueVector fieldOffsets(cx);
+        for (size_t i = 0; i < typeRepr->fieldCount(); i++) {
+            const StructField &field = typeRepr->field(i);
+            if (!fieldOffsets.append(Int32Value(field.offset)))
+                return false;
+        }
+        RootedObject fieldOffsetsVec(cx);
+        fieldOffsetsVec = NewDenseCopiedArray(cx, fieldOffsets.length(),
+                                              fieldOffsets.begin());
+        if (!fieldOffsetsVec)
+            return false;
+        structType->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS,
+                                     ObjectValue(*fieldOffsetsVec));
+    }
+
+    // Construct the fieldOffsets and fieldTypes objects:
     // fieldOffsets : { string: integer, ... }
     // fieldTypes : { string: Type, ... }
     RootedObject fieldOffsets(cx);
     fieldOffsets = NewObjectWithProto<JSObject>(cx, nullptr, nullptr, TenuredObject);
     RootedObject fieldTypes(cx);
     fieldTypes = NewObjectWithProto<JSObject>(cx, nullptr, nullptr, TenuredObject);
     for (size_t i = 0; i < typeRepr->fieldCount(); i++) {
         const StructField &field = typeRepr->field(i);
@@ -909,16 +924,50 @@ StructMetaTypeDescr::construct(JSContext
         return true;
     }
 
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
                          JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS);
     return false;
 }
 
+bool
+StructTypeDescr::fieldIndex(jsid id, size_t *out)
+{
+    JSObject &fieldNames =
+        getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_NAMES).toObject();
+    size_t l = fieldNames.getDenseInitializedLength();
+    for (size_t i = 0; i < l; i++) {
+        JSAtom &a = fieldNames.getDenseElement(i).toString()->asAtom();
+        if (JSID_IS_ATOM(id, &a)) {
+            *out = i;
+            return true;
+        }
+    }
+    return false;
+}
+
+size_t
+StructTypeDescr::fieldOffset(size_t index)
+{
+    JSObject &fieldOffsets =
+        getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS).toObject();
+    JS_ASSERT(index < fieldOffsets.getDenseInitializedLength());
+    return fieldOffsets.getDenseElement(index).toInt32();
+}
+
+SizedTypeDescr&
+StructTypeDescr::fieldDescr(size_t index)
+{
+    JSObject &fieldDescrs =
+        getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES).toObject();
+    JS_ASSERT(index < fieldDescrs.getDenseInitializedLength());
+    return fieldDescrs.getDenseElement(index).toObject().as<SizedTypeDescr>();
+}
+
 /******************************************************************************
  * Creating the TypedObject "module"
  *
  * We create one global, `TypedObject`, which contains the following
  * members:
  *
  * 1. uint8, uint16, etc
  * 2. ArrayType
@@ -1592,44 +1641,16 @@ TypedDatum::obj_defineElement(JSContext 
 bool
 TypedDatum::obj_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue v,
                               PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
 }
 
-static SizedTypeDescr *
-StructFieldType(JSContext *cx,
-                HandleStructTypeDescr type,
-                int32_t fieldIndex)
-{
-    // Recover the original type object here (`field` contains
-    // only its canonical form). The difference is observable,
-    // e.g. in a program like:
-    //
-    //     var Point1 = new StructType({x:uint8, y:uint8});
-    //     var Point2 = new StructType({x:uint8, y:uint8});
-    //     var Line1 = new StructType({start:Point1, end: Point1});
-    //     var Line2 = new StructType({start:Point2, end: Point2});
-    //     var line1 = new Line1(...);
-    //     var line2 = new Line2(...);
-    //
-    // In this scenario, line1.start.type() === Point1 and
-    // line2.start.type() === Point2.
-    RootedObject fieldTypes(
-        cx, &type->getReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES).toObject());
-    RootedValue fieldTypeVal(cx);
-    if (!JSObject::getElement(cx, fieldTypes, fieldTypes,
-                              fieldIndex, &fieldTypeVal))
-        return nullptr;
-
-    return &fieldTypeVal.toObject().as<SizedTypeDescr>();
-}
-
 bool
 TypedDatum::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
                            HandleId id, MutableHandleValue vp)
 {
     JS_ASSERT(obj->is<TypedDatum>());
     Rooted<TypedDatum *> datum(cx, &obj->as<TypedDatum>());
 
     // Dispatch elements to obj_getElement:
@@ -1659,30 +1680,25 @@ TypedDatum::obj_getGeneric(JSContext *cx
             }
 
             vp.setInt32(datum->length());
             return true;
         }
         break;
 
       case TypeRepresentation::Struct: {
-        Rooted<StructTypeDescr*> type(cx);
-        type = &datum->typeDescr().as<StructTypeDescr>();
-
-        StructTypeRepresentation *structTypeRepr = typeRepr->asStruct();
-        const StructField *field = structTypeRepr->fieldNamed(id);
-        if (!field)
+        Rooted<StructTypeDescr*> descr(cx, &datum->typeDescr().as<StructTypeDescr>());
+
+        size_t fieldIndex;
+        if (!descr->fieldIndex(id, &fieldIndex))
             break;
 
-        Rooted<SizedTypeDescr*> fieldType(cx);
-        fieldType = StructFieldType(cx, type, field->index);
-        if (!fieldType)
-            return false;
-
-        return Reify(cx, field->typeRepr, fieldType, datum, field->offset, vp);
+        size_t offset = descr->fieldOffset(fieldIndex);
+        Rooted<SizedTypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
+        return Reify(cx, fieldType, datum, offset, vp);
       }
     }
 
     RootedObject proto(cx, obj->getProto());
     if (!proto) {
         vp.setUndefined();
         return true;
     }
@@ -1746,17 +1762,17 @@ TypedDatum::obj_getArrayElement(JSContex
         vp.setUndefined();
         return true;
     }
 
     Rooted<SizedTypeDescr*> elementType(cx);
     elementType = &typeDescr->as<T>().elementType();
     SizedTypeRepresentation *elementTypeRepr = elementType->typeRepresentation();
     size_t offset = elementTypeRepr->size() * index;
-    return Reify(cx, elementTypeRepr, elementType, datum, offset, vp);
+    return Reify(cx, elementType, datum, offset, vp);
 }
 
 bool
 TypedDatum::obj_getSpecial(JSContext *cx, HandleObject obj,
                             HandleObject receiver, HandleSpecialId sid,
                             MutableHandleValue vp)
 {
     RootedId id(cx, SPECIALID_TO_JSID(sid));
@@ -1788,27 +1804,25 @@ TypedDatum::obj_setGeneric(JSContext *cx
         if (JSID_IS_ATOM(id, cx->names().length)) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage,
                                  nullptr, JSMSG_CANT_REDEFINE_ARRAY_LENGTH);
             return false;
         }
         break;
 
       case ScalarTypeRepresentation::Struct: {
-        const StructField *field = typeRepr->asStruct()->fieldNamed(id);
-        if (!field)
+        Rooted<StructTypeDescr*> descr(cx, &datum->typeDescr().as<StructTypeDescr>());
+
+        size_t fieldIndex;
+        if (!descr->fieldIndex(id, &fieldIndex))
             break;
 
-        Rooted<StructTypeDescr *> descr(cx, &datum->typeDescr().as<StructTypeDescr>());
-        Rooted<SizedTypeDescr*> fieldType(cx);
-        fieldType = StructFieldType(cx, descr, field->index);
-        if (!fieldType)
-            return false;
-
-        return ConvertAndCopyTo(cx, fieldType, datum, field->offset, vp);
+        size_t offset = descr->fieldOffset(fieldIndex);
+        Rooted<SizedTypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
+        return ConvertAndCopyTo(cx, fieldType, datum, offset, vp);
       }
     }
 
     return ReportDatumTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, datum);
 }
 
 bool
 TypedDatum::obj_setProperty(JSContext *cx, HandleObject obj,
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -332,16 +332,26 @@ class StructMetaTypeDescr : public JSObj
     static bool convertAndCopyTo(JSContext *cx,
                                  StructTypeRepresentation *typeRepr,
                                  HandleValue from, uint8_t *mem);
 };
 
 class StructTypeDescr : public SizedTypeDescr {
   public:
     static const Class class_;
+
+    // Set `*out` to the index of the field named `id` and returns true,
+    // or return false if no such field exists.
+    bool fieldIndex(jsid id, size_t *out);
+
+    // Return the type descr of the field at index `index`.
+    SizedTypeDescr &fieldDescr(size_t index);
+
+    // Return the offset of the field at index `index`.
+    size_t fieldOffset(size_t index);
 };
 
 typedef Handle<StructTypeDescr*> HandleStructTypeDescr;
 
 /*
  * Base type for typed objects and handles. Basically any type whose
  * contents consist of typed memory.
  */
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -21,16 +21,22 @@
 #define DESCR_KIND(obj) \
     REPR_KIND(DESCR_TYPE_REPR(obj))
 #define DESCR_SIZE(obj) \
     UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_SIZE)
 #define DESCR_SIZED_ARRAY_LENGTH(obj) \
     TO_INT32(UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_SIZED_ARRAY_LENGTH))
 #define DESCR_TYPE(obj)   \
     UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_TYPE)
+#define DESCR_STRUCT_FIELD_NAMES(obj) \
+    UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_NAMES)
+#define DESCR_STRUCT_FIELD_TYPES(obj) \
+    UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_TYPES)
+#define DESCR_STRUCT_FIELD_OFFSETS(obj) \
+    UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS)
 
 // Typed 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) \
@@ -93,25 +99,25 @@ function DescrToSource(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++) {
+    var fieldNames = DESCR_STRUCT_FIELD_NAMES(descr);
+    var fieldTypes = DESCR_STRUCT_FIELD_TYPES(descr);
+    for (var i = 0; i < fieldNames.length; i++) {
       if (i != 0)
         result += ", ";
 
-      var fieldName = descr.fieldNames[i];
-      var fieldDescr = descr.fieldTypes[fieldName];
-      result += fieldName;
+      result += fieldNames[i];
       result += ": ";
-      result += DescrToSource(fieldDescr);
+      result += DescrToSource(fieldTypes[i]);
     }
     result += "})";
     return result;
 
   case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
     return "new ArrayType(" + DescrToSource(descr.elementType) + ")";
 
   case JS_TYPEREPR_SIZED_ARRAY_KIND:
@@ -262,31 +268,37 @@ TypedObjectPointer.prototype.moveToElem 
 
   // 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;
 };
 
+TypedObjectPointer.prototype.moveToField = function(propName) {
+  var fieldNames = DESCR_STRUCT_FIELD_NAMES(this.descr);
+  var index = fieldNames.indexOf(propName);
+  if (index != -1)
+    return this.moveToFieldIndex(index);
+
+  ThrowError(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, propName);
+  return undefined;
+}
+
 // Adjust `this` to point at the field `propName`.  `this` must be a
 // struct type and `propName` must be a valid field name. Returns
 // `this`.
-TypedObjectPointer.prototype.moveToField = function(propName) {
+TypedObjectPointer.prototype.moveToFieldIndex = function(index) {
   assert(this.kind() == JS_TYPEREPR_STRUCT_KIND,
-         "moveToField invoked on non-struct");
-  assert(HAS_PROPERTY(this.descr.fieldTypes, propName),
-         "moveToField invoked with undefined field");
+         "moveToFieldIndex invoked on non-struct");
+  assert(index >= 0 && index < DESCR_STRUCT_FIELD_NAMES(this.descr).length,
+         "moveToFieldIndex invoked with invalid field index " + index);
 
-  // FIXME(Bug 966575) -- the fieldOffsets array that we are using
-  // below is only available on transparent types. This is fixed
-  // in part 6 of this patch series.
-
-  var fieldDescr = this.descr.fieldTypes[propName];
-  var fieldOffset = TO_INT32(this.descr.fieldOffsets[propName]);
+  var fieldDescr = DESCR_STRUCT_FIELD_TYPES(this.descr)[index];
+  var fieldOffset = TO_INT32(DESCR_STRUCT_FIELD_OFFSETS(this.descr)[index]);
 
   assert(IsObject(fieldDescr) && ObjectIsTypeDescr(fieldDescr),
          "bad field descr");
   assert(TO_INT32(fieldOffset) === fieldOffset,
          "bad field offset");
   assert(fieldOffset >= 0 && fieldOffset < DESCR_SIZE(this.descr),
          "out of bounds field offset");
 
@@ -457,20 +469,20 @@ TypedObjectPointer.prototype.set = funct
     break;
 
   case JS_TYPEREPR_STRUCT_KIND:
     if (!IsObject(fromValue))
       break;
 
     // Adapt each field.
     var tempPtr = this.copy();
-    var fieldNames = this.descr.fieldNames;
+    var fieldNames = DESCR_STRUCT_FIELD_NAMES(this.descr);
     for (var i = 0; i < fieldNames.length; i++) {
       var fieldName = fieldNames[i];
-      tempPtr.reset(this).moveToField(fieldName).set(fromValue[fieldName]);
+      tempPtr.reset(this).moveToFieldIndex(i).set(fromValue[fieldName]);
     }
     return;
   }
 
   ThrowError(JSMSG_CANT_CONVERT_TO,
              typeof(fromValue),
              DescrToSource(this.descr));
 }
--- a/js/src/builtin/TypedObjectConstants.h
+++ b/js/src/builtin/TypedObjectConstants.h
@@ -27,20 +27,22 @@
 
 // Slots on all array descriptors
 #define JS_DESCR_SLOT_ARRAY_ELEM_TYPE    3
 
 // Slots on sized array descriptors
 #define JS_DESCR_SLOT_SIZED_ARRAY_LENGTH 4
 
 // Slots on struct type objects
-#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 3
+#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 3
+#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 4
+#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 5
 
 // Maximum number of slots for any descriptor
-#define JS_DESCR_SLOTS                   5
+#define JS_DESCR_SLOTS                   6
 
 ///////////////////////////////////////////////////////////////////////////
 // Slots for type representation objects
 //
 // Some slots apply to all type representations and some are specific
 // to particular kinds of type representations. Because all type
 // representations share the same class, however, they always have the
 // same number of slots, though not all of them will be initialized or
--- a/js/src/tests/ecma_6/TypedObject/shell.js
+++ b/js/src/tests/ecma_6/TypedObject/shell.js
@@ -12,22 +12,18 @@ function assertTypedEqual(type, a_orig, 
 
   function recur(type, a, b) {
     if (type instanceof ArrayType) {
       assertEq(a.length, type.length);
       assertEq(b.length, type.length);
       for (var i = 0; i < type.length; i++)
         recur(type.elementType, a[i], b[i]);
       } else if (type instanceof StructType) {
-        for (var idx in type.fieldNames) {
-          var fieldName = type.fieldNames[idx];
-          if (type.fieldTypes[fieldName] !== undefined) {
-            recur(type.fieldTypes[fieldName], a[fieldName], b[fieldName]);
-          } else {
-            throw new Error("assertTypedEqual no type for "+
-                            "fieldName: "+fieldName+" in type: "+type.toSource());
-          }
+        var fieldNames = Object.getOwnPropertyNames(type.fieldTypes);
+        for (var i = 0; i < fieldNames.length; i++) {
+          var fieldName = fieldNames[i];
+          recur(type.fieldTypes[fieldName], a[fieldName], b[fieldName]);
         }
       } else {
         assertEq(a, b);
       }
   }
 }
--- a/js/src/tests/ecma_6/TypedObject/structtypereflection.js
+++ b/js/src/tests/ecma_6/TypedObject/structtypereflection.js
@@ -19,20 +19,21 @@ function runTests() {
 
     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(), "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);
+    var fieldNames = Object.getOwnPropertyNames(S.fieldTypes);
+    assertEq(fieldNames[0], "x");
+    assertEq(fieldNames[1], "y");
+    assertEq(fieldNames[2], "z");
+    assertEq(fieldNames.length, 3);
     assertEq(S.fieldTypes.x, int32);
     assertEq(S.fieldTypes.y, uint8);
     assertEq(S.fieldTypes.z, float64);
     assertEq(S.fieldOffsets.x, 0);
     assertEq(S.fieldOffsets.y, 4);
     assertEq(S.fieldOffsets.z, 8);
 
     if (typeof reportCompare === "function")
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -60,17 +60,16 @@
     macro(empty, empty, "") \
     macro(encodeURI, encodeURI, "encodeURI") \
     macro(encodeURIComponent, encodeURIComponent, "encodeURIComponent") \
     macro(enumerable, enumerable, "enumerable") \
     macro(enumerate, enumerate, "enumerate") \
     macro(escape, escape, "escape") \
     macro(eval, eval, "eval") \
     macro(false, false_, "false") \
-    macro(fieldNames, fieldNames, "fieldNames") \
     macro(fieldOffsets, fieldOffsets, "fieldOffsets") \
     macro(fieldTypes, fieldTypes, "fieldTypes") \
     macro(fileName, fileName, "fileName") \
     macro(FillTypedArrayWithValue, FillTypedArrayWithValue, "FillTypedArrayWithValue") \
     macro(fix, fix, "fix") \
     macro(float32, float32, "float32") \
     macro(float32x4, float32x4, "float32x4") \
     macro(float64, float64, "float64") \