Bug 1468524 - Fix instanceof for TypedObject 'struct' instances. r=till
authorLars T Hansen <lhansen@mozilla.com>
Tue, 31 Jul 2018 10:48:26 +0200
changeset 430046 3858eb122b9fb0868140e7c553ec99a49cc82611
parent 430045 61310ac63cfd3f5fdd04420311c8273e20b2b27d
child 430047 3e4eec1a2feee53119135913a33a2fa62c7b4ceb
push id34381
push userdluca@mozilla.com
push dateFri, 03 Aug 2018 22:01:59 +0000
treeherdermozilla-central@ff0d31843793 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1468524
milestone63.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 1468524 - Fix instanceof for TypedObject 'struct' instances. r=till Struct types need to appear to be callable, or some paths through the engine will not think that they are constructors (since constructors are callable). They are not *actually* callable however; the call implementation always throws.
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/js.msg
js/src/tests/non262/TypedObject/structtypereflection.js
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -678,17 +678,17 @@ js::IsTypedObjectArray(JSObject& obj)
 static const ClassOps StructTypeDescrClassOps = {
     nullptr, /* addProperty */
     nullptr, /* delProperty */
     nullptr, /* enumerate */
     nullptr, /* newEnumerate */
     nullptr, /* resolve */
     nullptr, /* mayResolve */
     TypeDescr::finalize,
-    nullptr, /* call */
+    StructTypeDescr::call,
     nullptr, /* hasInstance */
     TypedObject::construct
 };
 
 const Class StructTypeDescr::class_ = {
     "StructType",
     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE,
     &StructTypeDescrClassOps
@@ -1044,16 +1044,25 @@ StructTypeDescr::fieldOffset(size_t inde
 TypeDescr&
 StructTypeDescr::fieldDescr(size_t index) const
 {
     ArrayObject& fieldDescrs = fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_TYPES);
     MOZ_ASSERT(index < fieldDescrs.getDenseInitializedLength());
     return fieldDescrs.getDenseElement(index).toObject().as<TypeDescr>();
 }
 
+bool
+StructTypeDescr::call(JSContext* cx, unsigned argc, Value* vp)
+{
+    // A structure type is a constructor and hence callable, but at present the
+    // call always throws.
+    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_STRUCTTYPE_NOT_CALLABLE);
+    return false;
+}
+
 /******************************************************************************
  * Creating the TypedObject "module"
  *
  * We create one global, `TypedObject`, which contains the following
  * members:
  *
  * 1. uint8, uint16, etc
  * 2. ArrayType
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -471,16 +471,18 @@ class StructTypeDescr : public ComplexTy
     JSAtom& fieldName(size_t index) const;
 
     // Return the type descr of the field at index `index`.
     TypeDescr& fieldDescr(size_t index) const;
 
     // Return the offset of the field at index `index`.
     size_t fieldOffset(size_t index) const;
 
+    static bool call(JSContext* cx, unsigned argc, Value* vp);
+
   private:
     ArrayObject& fieldInfoObject(size_t slot) const {
         return getReservedSlot(slot).toObject().as<ArrayObject>();
     }
 };
 
 typedef Handle<StructTypeDescr*> HandleStructTypeDescr;
 
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -536,16 +536,17 @@ MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR,    0
 MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP,1, JSEXN_ERR, "No such property on self-hosted object: {0}")
 
 // Typed object
 MSG_DEF(JSMSG_INVALID_PROTOTYPE,       0, JSEXN_TYPEERR, "prototype field is not an object")
 MSG_DEF(JSMSG_TYPEDOBJECT_BAD_ARGS,    0, JSEXN_TYPEERR, "invalid arguments")
 MSG_DEF(JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index")
 MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 0, JSEXN_TYPEERR, "handle unattached")
 MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS, 0, JSEXN_RANGEERR, "invalid field descriptor")
+MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_NOT_CALLABLE, 0, JSEXN_TYPEERR, "not callable")
 MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG,     0, JSEXN_ERR, "Type is too large to allocate")
 
 // Array
 MSG_DEF(JSMSG_TOO_LONG_ARRAY,         0, JSEXN_TYPEERR, "Too long array")
 
 // Typed array
 MSG_DEF(JSMSG_BAD_INDEX,               0, JSEXN_RANGEERR, "invalid or out-of-range index")
 MSG_DEF(JSMSG_NON_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected ArrayBuffer, but species constructor returned non-ArrayBuffer")
--- a/js/src/tests/non262/TypedObject/structtypereflection.js
+++ b/js/src/tests/non262/TypedObject/structtypereflection.js
@@ -13,32 +13,35 @@ var int16 = TypedObject.int16;
 var int32 = TypedObject.int32;
 var float32 = TypedObject.float32;
 var float64 = TypedObject.float64;
 
 function runTests() {
     print(BUGNUMBER + ": " + summary);
 
     var S = new StructType({x: int32, y: uint8, z: float64});
+    var T = 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.byteLength, 16);
     assertEq(S.byteAlignment, 8);
     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);
+    assertEq((new S({x:10, y:20, z:30})) instanceof S, true);
+    assertEq((new S({x:10, y:20, z:30})) instanceof T, false);
 
     // fieldTypes and fieldOffsets should be frozen
     assertEq(Object.isFrozen(S.fieldTypes), true);
     assertEq(Object.isFrozen(S.fieldOffsets), true);
 
     if (typeof reportCompare === "function")
         reportCompare(true, true);
     print("Tests complete");