LCOV - code coverage report
Current view: top level - js/src/builtin - TypedObject.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 129 1261 10.2 %
Date: 2017-07-14 16:53:18 Functions: 17 135 12.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "builtin/TypedObject.h"
       8             : 
       9             : #include "mozilla/Casting.h"
      10             : #include "mozilla/CheckedInt.h"
      11             : 
      12             : #include "jscompartment.h"
      13             : #include "jsfun.h"
      14             : #include "jsutil.h"
      15             : 
      16             : #include "builtin/SIMD.h"
      17             : #include "gc/Marking.h"
      18             : #include "js/Vector.h"
      19             : #include "vm/GlobalObject.h"
      20             : #include "vm/String.h"
      21             : #include "vm/StringBuffer.h"
      22             : #include "vm/TypedArrayObject.h"
      23             : 
      24             : #include "jsatominlines.h"
      25             : #include "jsobjinlines.h"
      26             : 
      27             : #include "gc/StoreBuffer-inl.h"
      28             : #include "vm/NativeObject-inl.h"
      29             : #include "vm/Shape-inl.h"
      30             : 
      31             : using mozilla::AssertedCast;
      32             : using mozilla::CheckedInt32;
      33             : using mozilla::DebugOnly;
      34             : using mozilla::IsPowerOfTwo;
      35             : using mozilla::PodCopy;
      36             : using mozilla::PointerRangeSize;
      37             : 
      38             : using namespace js;
      39             : 
      40             : const Class js::TypedObjectModuleObject::class_ = {
      41             :     "TypedObject",
      42             :     JSCLASS_HAS_RESERVED_SLOTS(SlotCount) |
      43             :     JSCLASS_HAS_CACHED_PROTO(JSProto_TypedObject)
      44             : };
      45             : 
      46             : static const JSFunctionSpec TypedObjectMethods[] = {
      47             :     JS_SELF_HOSTED_FN("objectType", "TypeOfTypedObject", 1, 0),
      48             :     JS_SELF_HOSTED_FN("storage", "StorageOfTypedObject", 1, 0),
      49             :     JS_FS_END
      50             : };
      51             : 
      52             : static void
      53           0 : ReportCannotConvertTo(JSContext* cx, HandleValue fromValue, const char* toType)
      54             : {
      55           0 :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
      56           0 :                               InformalValueTypeName(fromValue), toType);
      57           0 : }
      58             : 
      59             : template<class T>
      60             : static inline T*
      61           0 : ToObjectIf(HandleValue value)
      62             : {
      63           0 :     if (!value.isObject())
      64           0 :         return nullptr;
      65             : 
      66           0 :     if (!value.toObject().is<T>())
      67           0 :         return nullptr;
      68             : 
      69           0 :     return &value.toObject().as<T>();
      70             : }
      71             : 
      72             : static inline CheckedInt32
      73           0 : RoundUpToAlignment(CheckedInt32 address, uint32_t align)
      74             : {
      75           0 :     MOZ_ASSERT(IsPowerOfTwo(align));
      76             : 
      77             :     // Note: Be careful to order operators such that we first make the
      78             :     // value smaller and then larger, so that we don't get false
      79             :     // overflow errors due to (e.g.) adding `align` and then
      80             :     // subtracting `1` afterwards when merely adding `align-1` would
      81             :     // not have overflowed. Note that due to the nature of two's
      82             :     // complement representation, if `address` is already aligned,
      83             :     // then adding `align-1` cannot itself cause an overflow.
      84             : 
      85           0 :     return ((address + (align - 1)) / align) * align;
      86             : }
      87             : 
      88             : /*
      89             :  * Overwrites the contents of `typedObj` at offset `offset` with `val`
      90             :  * converted to the type `typeObj`. This is done by delegating to
      91             :  * self-hosted code. This is used for assignments and initializations.
      92             :  *
      93             :  * For example, consider the final assignment in this snippet:
      94             :  *
      95             :  *    var Point = new StructType({x: float32, y: float32});
      96             :  *    var Line = new StructType({from: Point, to: Point});
      97             :  *    var line = new Line();
      98             :  *    line.to = {x: 22, y: 44};
      99             :  *
     100             :  * This would result in a call to `ConvertAndCopyTo`
     101             :  * where:
     102             :  * - typeObj = Point
     103             :  * - typedObj = line
     104             :  * - offset = sizeof(Point) == 8
     105             :  * - val = {x: 22, y: 44}
     106             :  * This would result in loading the value of `x`, converting
     107             :  * it to a float32, and hen storing it at the appropriate offset,
     108             :  * and then doing the same for `y`.
     109             :  *
     110             :  * Note that the type of `typeObj` may not be the
     111             :  * type of `typedObj` but rather some subcomponent of `typedObj`.
     112             :  */
     113             : static bool
     114           0 : ConvertAndCopyTo(JSContext* cx,
     115             :                  HandleTypeDescr typeObj,
     116             :                  HandleTypedObject typedObj,
     117             :                  int32_t offset,
     118             :                  HandleAtom name,
     119             :                  HandleValue val)
     120             : {
     121           0 :     RootedFunction func(cx, SelfHostedFunction(cx, cx->names().ConvertAndCopyTo));
     122           0 :     if (!func)
     123           0 :         return false;
     124             : 
     125           0 :     FixedInvokeArgs<5> args(cx);
     126             : 
     127           0 :     args[0].setObject(*typeObj);
     128           0 :     args[1].setObject(*typedObj);
     129           0 :     args[2].setInt32(offset);
     130           0 :     if (name)
     131           0 :         args[3].setString(name);
     132             :     else
     133           0 :         args[3].setNull();
     134           0 :     args[4].set(val);
     135             : 
     136           0 :     RootedValue fval(cx, ObjectValue(*func));
     137           0 :     RootedValue dummy(cx); // ignored by ConvertAndCopyTo
     138           0 :     return js::Call(cx, fval, dummy, args, &dummy);
     139             : }
     140             : 
     141             : static bool
     142           0 : ConvertAndCopyTo(JSContext* cx, HandleTypedObject typedObj, HandleValue val)
     143             : {
     144           0 :     Rooted<TypeDescr*> type(cx, &typedObj->typeDescr());
     145           0 :     return ConvertAndCopyTo(cx, type, typedObj, 0, nullptr, val);
     146             : }
     147             : 
     148             : /*
     149             :  * Overwrites the contents of `typedObj` at offset `offset` with `val`
     150             :  * converted to the type `typeObj`
     151             :  */
     152             : static bool
     153           0 : Reify(JSContext* cx,
     154             :       HandleTypeDescr type,
     155             :       HandleTypedObject typedObj,
     156             :       size_t offset,
     157             :       MutableHandleValue to)
     158             : {
     159           0 :     RootedFunction func(cx, SelfHostedFunction(cx, cx->names().Reify));
     160           0 :     if (!func)
     161           0 :         return false;
     162             : 
     163           0 :     FixedInvokeArgs<3> args(cx);
     164             : 
     165           0 :     args[0].setObject(*type);
     166           0 :     args[1].setObject(*typedObj);
     167           0 :     args[2].setInt32(offset);
     168             : 
     169           0 :     RootedValue fval(cx, ObjectValue(*func));
     170           0 :     return js::Call(cx, fval, UndefinedHandleValue, args, to);
     171             : }
     172             : 
     173             : // Extracts the `prototype` property from `obj`, throwing if it is
     174             : // missing or not an object.
     175             : static JSObject*
     176           0 : GetPrototype(JSContext* cx, HandleObject obj)
     177             : {
     178           0 :     RootedValue prototypeVal(cx);
     179           0 :     if (!GetProperty(cx, obj, obj, cx->names().prototype,
     180             :                                &prototypeVal))
     181             :     {
     182           0 :         return nullptr;
     183             :     }
     184           0 :     if (!prototypeVal.isObject()) {
     185           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INVALID_PROTOTYPE);
     186           0 :         return nullptr;
     187             :     }
     188           0 :     return &prototypeVal.toObject();
     189             : }
     190             : 
     191             : /***************************************************************************
     192             :  * Typed Prototypes
     193             :  *
     194             :  * Every type descriptor has an associated prototype. Instances of
     195             :  * that type descriptor use this as their prototype. Per the spec,
     196             :  * typed object prototypes cannot be mutated.
     197             :  */
     198             : 
     199             : const Class js::TypedProto::class_ = {
     200             :     "TypedProto",
     201             :     JSCLASS_HAS_RESERVED_SLOTS(JS_TYPROTO_SLOTS)
     202             : };
     203             : 
     204             : /***************************************************************************
     205             :  * Scalar type objects
     206             :  *
     207             :  * Scalar type objects like `uint8`, `uint16`, are all instances of
     208             :  * the ScalarTypeDescr class. Like all type objects, they have a reserved
     209             :  * slot pointing to a TypeRepresentation object, which is used to
     210             :  * distinguish which scalar type object this actually is.
     211             :  */
     212             : 
     213             : static const ClassOps ScalarTypeDescrClassOps = {
     214             :     nullptr, /* addProperty */
     215             :     nullptr, /* delProperty */
     216             :     nullptr, /* getProperty */
     217             :     nullptr, /* setProperty */
     218             :     nullptr, /* enumerate */
     219             :     nullptr, /* newEnumerate */
     220             :     nullptr, /* resolve */
     221             :     nullptr, /* mayResolve */
     222             :     TypeDescr::finalize,
     223             :     ScalarTypeDescr::call
     224             : };
     225             : 
     226             : const Class js::ScalarTypeDescr::class_ = {
     227             :     "Scalar",
     228             :     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE,
     229             :     &ScalarTypeDescrClassOps
     230             : };
     231             : 
     232             : const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
     233             :     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
     234             :     JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
     235             :     JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
     236             :     JS_FS_END
     237             : };
     238             : 
     239             : uint32_t
     240          54 : ScalarTypeDescr::size(Type t)
     241             : {
     242          54 :     return AssertedCast<uint32_t>(Scalar::byteSize(t));
     243             : }
     244             : 
     245             : uint32_t
     246          54 : ScalarTypeDescr::alignment(Type t)
     247             : {
     248          54 :     return AssertedCast<uint32_t>(Scalar::byteSize(t));
     249             : }
     250             : 
     251             : /*static*/ const char*
     252           0 : ScalarTypeDescr::typeName(Type type)
     253             : {
     254           0 :     switch (type) {
     255             : #define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
     256             :         case constant_: return #name_;
     257           0 :         JS_FOR_EACH_SCALAR_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
     258             : #undef NUMERIC_TYPE_TO_STRING
     259             :       case Scalar::Int64:
     260             :       case Scalar::Float32x4:
     261             :       case Scalar::Int8x16:
     262             :       case Scalar::Int16x8:
     263             :       case Scalar::Int32x4:
     264             :       case Scalar::MaxTypedArrayViewType:
     265           0 :         break;
     266             :     }
     267           0 :     MOZ_CRASH("Invalid type");
     268             : }
     269             : 
     270             : bool
     271           0 : ScalarTypeDescr::call(JSContext* cx, unsigned argc, Value* vp)
     272             : {
     273           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     274           0 :     if (args.length() < 1) {
     275             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
     276           0 :                                   args.callee().getClass()->name, "0", "s");
     277           0 :         return false;
     278             :     }
     279             : 
     280           0 :     Rooted<ScalarTypeDescr*> descr(cx, &args.callee().as<ScalarTypeDescr>());
     281           0 :     ScalarTypeDescr::Type type = descr->type();
     282             : 
     283             :     double number;
     284           0 :     if (!ToNumber(cx, args[0], &number))
     285           0 :         return false;
     286             : 
     287           0 :     if (type == Scalar::Uint8Clamped)
     288           0 :         number = ClampDoubleToUint8(number);
     289             : 
     290           0 :     switch (type) {
     291             : #define SCALARTYPE_CALL(constant_, type_, name_)                             \
     292             :       case constant_: {                                                       \
     293             :           type_ converted = ConvertScalar<type_>(number);                     \
     294             :           args.rval().setNumber((double) converted);                          \
     295             :           return true;                                                        \
     296             :       }
     297             : 
     298           0 :         JS_FOR_EACH_SCALAR_TYPE_REPR(SCALARTYPE_CALL)
     299             : #undef SCALARTYPE_CALL
     300             :       case Scalar::Int64:
     301             :       case Scalar::Float32x4:
     302             :       case Scalar::Int8x16:
     303             :       case Scalar::Int16x8:
     304             :       case Scalar::Int32x4:
     305             :       case Scalar::MaxTypedArrayViewType:
     306           0 :         MOZ_CRASH();
     307             :     }
     308           0 :     return true;
     309             : }
     310             : 
     311             : /***************************************************************************
     312             :  * Reference type objects
     313             :  *
     314             :  * Reference type objects like `Any` or `Object` basically work the
     315             :  * same way that the scalar type objects do. There is one class with
     316             :  * many instances, and each instance has a reserved slot with a
     317             :  * TypeRepresentation object, which is used to distinguish which
     318             :  * reference type object this actually is.
     319             :  */
     320             : 
     321             : static const ClassOps ReferenceTypeDescrClassOps = {
     322             :     nullptr, /* addProperty */
     323             :     nullptr, /* delProperty */
     324             :     nullptr, /* getProperty */
     325             :     nullptr, /* setProperty */
     326             :     nullptr, /* enumerate */
     327             :     nullptr, /* newEnumerate */
     328             :     nullptr, /* resolve */
     329             :     nullptr, /* mayResolve */
     330             :     TypeDescr::finalize,
     331             :     ReferenceTypeDescr::call
     332             : };
     333             : 
     334             : const Class js::ReferenceTypeDescr::class_ = {
     335             :     "Reference",
     336             :     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE,
     337             :     &ReferenceTypeDescrClassOps
     338             : };
     339             : 
     340             : const JSFunctionSpec js::ReferenceTypeDescr::typeObjectMethods[] = {
     341             :     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
     342             :     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
     343             :     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     344             :     JS_FS_END
     345             : };
     346             : 
     347             : static const uint32_t ReferenceSizes[] = {
     348             : #define REFERENCE_SIZE(_kind, _type, _name)                        \
     349             :     sizeof(_type),
     350             :     JS_FOR_EACH_REFERENCE_TYPE_REPR(REFERENCE_SIZE) 0
     351             : #undef REFERENCE_SIZE
     352             : };
     353             : 
     354             : uint32_t
     355          18 : ReferenceTypeDescr::size(Type t)
     356             : {
     357          18 :     return ReferenceSizes[t];
     358             : }
     359             : 
     360             : uint32_t
     361          18 : ReferenceTypeDescr::alignment(Type t)
     362             : {
     363          18 :     return ReferenceSizes[t];
     364             : }
     365             : 
     366             : /*static*/ const char*
     367           0 : ReferenceTypeDescr::typeName(Type type)
     368             : {
     369           0 :     switch (type) {
     370             : #define NUMERIC_TYPE_TO_STRING(constant_, type_, name_) \
     371             :         case constant_: return #name_;
     372           0 :         JS_FOR_EACH_REFERENCE_TYPE_REPR(NUMERIC_TYPE_TO_STRING)
     373             : #undef NUMERIC_TYPE_TO_STRING
     374             :     }
     375           0 :     MOZ_CRASH("Invalid type");
     376             : }
     377             : 
     378             : bool
     379           0 : js::ReferenceTypeDescr::call(JSContext* cx, unsigned argc, Value* vp)
     380             : {
     381           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     382             : 
     383           0 :     MOZ_ASSERT(args.callee().is<ReferenceTypeDescr>());
     384           0 :     Rooted<ReferenceTypeDescr*> descr(cx, &args.callee().as<ReferenceTypeDescr>());
     385             : 
     386           0 :     if (args.length() < 1) {
     387           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
     388           0 :                                   descr->typeName(), "0", "s");
     389           0 :         return false;
     390             :     }
     391             : 
     392           0 :     switch (descr->type()) {
     393             :       case ReferenceTypeDescr::TYPE_ANY:
     394           0 :         args.rval().set(args[0]);
     395           0 :         return true;
     396             : 
     397             :       case ReferenceTypeDescr::TYPE_OBJECT:
     398             :       {
     399           0 :         RootedObject obj(cx, ToObject(cx, args[0]));
     400           0 :         if (!obj)
     401           0 :             return false;
     402           0 :         args.rval().setObject(*obj);
     403           0 :         return true;
     404             :       }
     405             : 
     406             :       case ReferenceTypeDescr::TYPE_STRING:
     407             :       {
     408           0 :         RootedString obj(cx, ToString<CanGC>(cx, args[0]));
     409           0 :         if (!obj)
     410           0 :             return false;
     411           0 :         args.rval().setString(&*obj);
     412           0 :         return true;
     413             :       }
     414             :     }
     415             : 
     416           0 :     MOZ_CRASH("Unhandled Reference type");
     417             : }
     418             : 
     419             : /***************************************************************************
     420             :  * SIMD type objects
     421             :  *
     422             :  * Note: these are partially defined in SIMD.cpp
     423             :  */
     424             : 
     425             : SimdType
     426           0 : SimdTypeDescr::type() const {
     427           0 :     uint32_t t = uint32_t(getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32());
     428           0 :     MOZ_ASSERT(t < uint32_t(SimdType::Count));
     429           0 :     return SimdType(t);
     430             : }
     431             : 
     432             : uint32_t
     433           0 : SimdTypeDescr::size(SimdType t)
     434             : {
     435           0 :     MOZ_ASSERT(unsigned(t) < unsigned(SimdType::Count));
     436           0 :     switch (t) {
     437             :       case SimdType::Int8x16:
     438             :       case SimdType::Int16x8:
     439             :       case SimdType::Int32x4:
     440             :       case SimdType::Uint8x16:
     441             :       case SimdType::Uint16x8:
     442             :       case SimdType::Uint32x4:
     443             :       case SimdType::Float32x4:
     444             :       case SimdType::Float64x2:
     445             :       case SimdType::Bool8x16:
     446             :       case SimdType::Bool16x8:
     447             :       case SimdType::Bool32x4:
     448             :       case SimdType::Bool64x2:
     449           0 :         return 16;
     450             :       case SimdType::Count:
     451           0 :         break;
     452             :     }
     453           0 :     MOZ_CRASH("unexpected SIMD type");
     454             : }
     455             : 
     456             : uint32_t
     457           0 : SimdTypeDescr::alignment(SimdType t)
     458             : {
     459           0 :     MOZ_ASSERT(unsigned(t) < unsigned(SimdType::Count));
     460           0 :     return size(t);
     461             : }
     462             : 
     463             : /***************************************************************************
     464             :  * ArrayMetaTypeDescr class
     465             :  */
     466             : 
     467             : /*
     468             :  * For code like:
     469             :  *
     470             :  *   var A = new TypedObject.ArrayType(uint8, 10);
     471             :  *   var S = new TypedObject.StructType({...});
     472             :  *
     473             :  * As usual, the [[Prototype]] of A is
     474             :  * TypedObject.ArrayType.prototype.  This permits adding methods to
     475             :  * all ArrayType types, by setting
     476             :  * TypedObject.ArrayType.prototype.methodName = function() { ... }.
     477             :  * The same holds for S with respect to TypedObject.StructType.
     478             :  *
     479             :  * We may also want to add methods to *instances* of an ArrayType:
     480             :  *
     481             :  *   var a = new A();
     482             :  *   var s = new S();
     483             :  *
     484             :  * As usual, the [[Prototype]] of a is A.prototype.  What's
     485             :  * A.prototype?  It's an empty object, and you can set
     486             :  * A.prototype.methodName = function() { ... } to add a method to all
     487             :  * A instances.  (And the same with respect to s and S.)
     488             :  *
     489             :  * But what if you want to add a method to all ArrayType instances,
     490             :  * not just all A instances?  (Or to all StructType instances.)  The
     491             :  * [[Prototype]] of the A.prototype empty object is
     492             :  * TypedObject.ArrayType.prototype.prototype (two .prototype levels!).
     493             :  * So just set TypedObject.ArrayType.prototype.prototype.methodName =
     494             :  * function() { ... } to add a method to all ArrayType instances.
     495             :  * (And, again, same with respect to s and S.)
     496             :  *
     497             :  * This function creates the A.prototype/S.prototype object. It returns an
     498             :  * empty object with the .prototype.prototype object as its [[Prototype]].
     499             :  */
     500             : static TypedProto*
     501           0 : CreatePrototypeObjectForComplexTypeInstance(JSContext* cx, HandleObject ctorPrototype)
     502             : {
     503           0 :     RootedObject ctorPrototypePrototype(cx, GetPrototype(cx, ctorPrototype));
     504           0 :     if (!ctorPrototypePrototype)
     505           0 :         return nullptr;
     506             : 
     507           0 :     return NewObjectWithGivenProto<TypedProto>(cx, ctorPrototypePrototype, SingletonObject);
     508             : }
     509             : 
     510             : static const ClassOps ArrayTypeDescrClassOps = {
     511             :     nullptr, /* addProperty */
     512             :     nullptr, /* delProperty */
     513             :     nullptr, /* getProperty */
     514             :     nullptr, /* setProperty */
     515             :     nullptr, /* enumerate */
     516             :     nullptr, /* newEnumerate */
     517             :     nullptr, /* resolve */
     518             :     nullptr, /* mayResolve */
     519             :     TypeDescr::finalize,
     520             :     nullptr, /* call */
     521             :     nullptr, /* hasInstance */
     522             :     TypedObject::construct
     523             : };
     524             : 
     525             : const Class ArrayTypeDescr::class_ = {
     526             :     "ArrayType",
     527             :     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE,
     528             :     &ArrayTypeDescrClassOps
     529             : };
     530             : 
     531             : const JSPropertySpec ArrayMetaTypeDescr::typeObjectProperties[] = {
     532             :     JS_PS_END
     533             : };
     534             : 
     535             : const JSFunctionSpec ArrayMetaTypeDescr::typeObjectMethods[] = {
     536             :     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
     537             :     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
     538             :     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     539             :     JS_SELF_HOSTED_FN("build",    "TypedObjectArrayTypeBuild", 3, 0),
     540             :     JS_SELF_HOSTED_FN("from",     "TypedObjectArrayTypeFrom", 3, 0),
     541             :     JS_FS_END
     542             : };
     543             : 
     544             : const JSPropertySpec ArrayMetaTypeDescr::typedObjectProperties[] = {
     545             :     JS_PS_END
     546             : };
     547             : 
     548             : const JSFunctionSpec ArrayMetaTypeDescr::typedObjectMethods[] = {
     549             :     {"forEach", {nullptr, nullptr}, 1, 0, "ArrayForEach"},
     550             :     {"redimension", {nullptr, nullptr}, 1, 0, "TypedObjectArrayRedimension"},
     551             :     JS_SELF_HOSTED_FN("map",        "TypedObjectArrayMap",        2, 0),
     552             :     JS_SELF_HOSTED_FN("reduce",     "TypedObjectArrayReduce",     2, 0),
     553             :     JS_SELF_HOSTED_FN("filter",     "TypedObjectArrayFilter",     1, 0),
     554             :     JS_FS_END
     555             : };
     556             : 
     557             : bool
     558          72 : js::CreateUserSizeAndAlignmentProperties(JSContext* cx, HandleTypeDescr descr)
     559             : {
     560             :     // If data is transparent, also store the public slots.
     561          72 :     if (descr->transparent()) {
     562             :         // byteLength
     563         108 :         RootedValue typeByteLength(cx, Int32Value(AssertedCast<int32_t>(descr->size())));
     564          54 :         if (!DefineProperty(cx, descr, cx->names().byteLength, typeByteLength,
     565             :                             nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
     566             :         {
     567           0 :             return false;
     568             :         }
     569             : 
     570             :         // byteAlignment
     571         108 :         RootedValue typeByteAlignment(cx, Int32Value(descr->alignment()));
     572          54 :         if (!DefineProperty(cx, descr, cx->names().byteAlignment, typeByteAlignment,
     573             :                             nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
     574             :         {
     575           0 :             return false;
     576             :         }
     577             :     } else {
     578             :         // byteLength
     579          18 :         if (!DefineProperty(cx, descr, cx->names().byteLength, UndefinedHandleValue,
     580             :                             nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
     581             :         {
     582           0 :             return false;
     583             :         }
     584             : 
     585             :         // byteAlignment
     586          18 :         if (!DefineProperty(cx, descr, cx->names().byteAlignment, UndefinedHandleValue,
     587             :                             nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
     588             :         {
     589           0 :             return false;
     590             :         }
     591             :     }
     592             : 
     593          72 :     return true;
     594             : }
     595             : 
     596             : static bool
     597             : CreateTraceList(JSContext* cx, HandleTypeDescr descr);
     598             : 
     599             : ArrayTypeDescr*
     600           0 : ArrayMetaTypeDescr::create(JSContext* cx,
     601             :                            HandleObject arrayTypePrototype,
     602             :                            HandleTypeDescr elementType,
     603             :                            HandleAtom stringRepr,
     604             :                            int32_t size,
     605             :                            int32_t length)
     606             : {
     607           0 :     MOZ_ASSERT(arrayTypePrototype);
     608           0 :     Rooted<ArrayTypeDescr*> obj(cx);
     609           0 :     obj = NewObjectWithGivenProto<ArrayTypeDescr>(cx, arrayTypePrototype, SingletonObject);
     610           0 :     if (!obj)
     611           0 :         return nullptr;
     612             : 
     613           0 :     obj->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(ArrayTypeDescr::Kind));
     614           0 :     obj->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
     615           0 :     obj->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(elementType->alignment()));
     616           0 :     obj->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(size));
     617           0 :     obj->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(elementType->opaque()));
     618           0 :     obj->initReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE, ObjectValue(*elementType));
     619           0 :     obj->initReservedSlot(JS_DESCR_SLOT_ARRAY_LENGTH, Int32Value(length));
     620             : 
     621           0 :     RootedValue elementTypeVal(cx, ObjectValue(*elementType));
     622           0 :     if (!DefineProperty(cx, obj, cx->names().elementType, elementTypeVal,
     623             :                         nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
     624             :     {
     625           0 :         return nullptr;
     626             :     }
     627             : 
     628           0 :     RootedValue lengthValue(cx, NumberValue(length));
     629           0 :     if (!DefineProperty(cx, obj, cx->names().length, lengthValue,
     630             :                         nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
     631             :     {
     632           0 :         return nullptr;
     633             :     }
     634             : 
     635           0 :     if (!CreateUserSizeAndAlignmentProperties(cx, obj))
     636           0 :         return nullptr;
     637             : 
     638             :     // All arrays with the same element type have the same prototype. This
     639             :     // prototype is created lazily and stored in the element type descriptor.
     640           0 :     Rooted<TypedProto*> prototypeObj(cx);
     641           0 :     if (elementType->getReservedSlot(JS_DESCR_SLOT_ARRAYPROTO).isObject()) {
     642           0 :         prototypeObj = &elementType->getReservedSlot(JS_DESCR_SLOT_ARRAYPROTO).toObject().as<TypedProto>();
     643             :     } else {
     644           0 :         prototypeObj = CreatePrototypeObjectForComplexTypeInstance(cx, arrayTypePrototype);
     645           0 :         if (!prototypeObj)
     646           0 :             return nullptr;
     647           0 :         elementType->setReservedSlot(JS_DESCR_SLOT_ARRAYPROTO, ObjectValue(*prototypeObj));
     648             :     }
     649             : 
     650           0 :     obj->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*prototypeObj));
     651             : 
     652           0 :     if (!LinkConstructorAndPrototype(cx, obj, prototypeObj))
     653           0 :         return nullptr;
     654             : 
     655           0 :     if (!CreateTraceList(cx, obj))
     656           0 :         return nullptr;
     657             : 
     658           0 :     if (!cx->zone()->addTypeDescrObject(cx, obj)) {
     659           0 :         ReportOutOfMemory(cx);
     660           0 :         return nullptr;
     661             :     }
     662             : 
     663           0 :     return obj;
     664             : }
     665             : 
     666             : bool
     667           0 : ArrayMetaTypeDescr::construct(JSContext* cx, unsigned argc, Value* vp)
     668             : {
     669           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     670             : 
     671           0 :     if (!ThrowIfNotConstructing(cx, args, "ArrayType"))
     672           0 :         return false;
     673             : 
     674           0 :     RootedObject arrayTypeGlobal(cx, &args.callee());
     675             : 
     676             :     // Expect two arguments. The first is a type object, the second is a length.
     677           0 :     if (args.length() < 2) {
     678             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
     679           0 :                                   "ArrayType", "1", "");
     680           0 :         return false;
     681             :     }
     682             : 
     683           0 :     if (!args[0].isObject() || !args[0].toObject().is<TypeDescr>()) {
     684           0 :         ReportCannotConvertTo(cx, args[0], "ArrayType element specifier");
     685           0 :         return false;
     686             :     }
     687             : 
     688           0 :     if (!args[1].isInt32() || args[1].toInt32() < 0) {
     689           0 :         ReportCannotConvertTo(cx, args[1], "ArrayType length specifier");
     690           0 :         return false;
     691             :     }
     692             : 
     693           0 :     Rooted<TypeDescr*> elementType(cx, &args[0].toObject().as<TypeDescr>());
     694             : 
     695           0 :     int32_t length = args[1].toInt32();
     696             : 
     697             :     // Compute the byte size.
     698           0 :     CheckedInt32 size = CheckedInt32(elementType->size()) * length;
     699           0 :     if (!size.isValid()) {
     700           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_TOO_BIG);
     701           0 :         return false;
     702             :     }
     703             : 
     704             :     // Construct a canonical string `new ArrayType(<elementType>, N)`:
     705           0 :     StringBuffer contents(cx);
     706           0 :     if (!contents.append("new ArrayType("))
     707           0 :         return false;
     708           0 :     if (!contents.append(&elementType->stringRepr()))
     709           0 :         return false;
     710           0 :     if (!contents.append(", "))
     711           0 :         return false;
     712           0 :     if (!NumberValueToStringBuffer(cx, NumberValue(length), contents))
     713           0 :         return false;
     714           0 :     if (!contents.append(")"))
     715           0 :         return false;
     716           0 :     RootedAtom stringRepr(cx, contents.finishAtom());
     717           0 :     if (!stringRepr)
     718           0 :         return false;
     719             : 
     720             :     // Extract ArrayType.prototype
     721           0 :     RootedObject arrayTypePrototype(cx, GetPrototype(cx, arrayTypeGlobal));
     722           0 :     if (!arrayTypePrototype)
     723           0 :         return false;
     724             : 
     725             :     // Create the instance of ArrayType
     726           0 :     Rooted<ArrayTypeDescr*> obj(cx);
     727           0 :     obj = create(cx, arrayTypePrototype, elementType, stringRepr, size.value(), length);
     728           0 :     if (!obj)
     729           0 :         return false;
     730             : 
     731           0 :     args.rval().setObject(*obj);
     732           0 :     return true;
     733             : }
     734             : 
     735             : bool
     736           0 : js::IsTypedObjectArray(JSObject& obj)
     737             : {
     738           0 :     if (!obj.is<TypedObject>())
     739           0 :         return false;
     740           0 :     TypeDescr& d = obj.as<TypedObject>().typeDescr();
     741           0 :     return d.is<ArrayTypeDescr>();
     742             : }
     743             : 
     744             : /*********************************
     745             :  * StructType class
     746             :  */
     747             : 
     748             : static const ClassOps StructTypeDescrClassOps = {
     749             :     nullptr, /* addProperty */
     750             :     nullptr, /* delProperty */
     751             :     nullptr, /* getProperty */
     752             :     nullptr, /* setProperty */
     753             :     nullptr, /* enumerate */
     754             :     nullptr, /* newEnumerate */
     755             :     nullptr, /* resolve */
     756             :     nullptr, /* mayResolve */
     757             :     TypeDescr::finalize,
     758             :     nullptr, /* call */
     759             :     nullptr, /* hasInstance */
     760             :     TypedObject::construct
     761             : };
     762             : 
     763             : const Class StructTypeDescr::class_ = {
     764             :     "StructType",
     765             :     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE,
     766             :     &StructTypeDescrClassOps
     767             : };
     768             : 
     769             : const JSPropertySpec StructMetaTypeDescr::typeObjectProperties[] = {
     770             :     JS_PS_END
     771             : };
     772             : 
     773             : const JSFunctionSpec StructMetaTypeDescr::typeObjectMethods[] = {
     774             :     {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"},
     775             :     JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
     776             :     {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"},
     777             :     JS_FS_END
     778             : };
     779             : 
     780             : const JSPropertySpec StructMetaTypeDescr::typedObjectProperties[] = {
     781             :     JS_PS_END
     782             : };
     783             : 
     784             : const JSFunctionSpec StructMetaTypeDescr::typedObjectMethods[] = {
     785             :     JS_FS_END
     786             : };
     787             : 
     788             : JSObject*
     789           0 : StructMetaTypeDescr::create(JSContext* cx,
     790             :                             HandleObject metaTypeDescr,
     791             :                             HandleObject fields)
     792             : {
     793             :     // Obtain names of fields, which are the own properties of `fields`
     794           0 :     AutoIdVector ids(cx);
     795           0 :     if (!GetPropertyKeys(cx, fields, JSITER_OWNONLY | JSITER_SYMBOLS, &ids))
     796           0 :         return nullptr;
     797             : 
     798             :     // Iterate through each field. Collect values for the various
     799             :     // vectors below and also track total size and alignment. Be wary
     800             :     // of overflow!
     801           0 :     StringBuffer stringBuffer(cx);     // Canonical string repr
     802           0 :     AutoValueVector fieldNames(cx);    // Name of each field.
     803           0 :     AutoValueVector fieldTypeObjs(cx); // Type descriptor of each field.
     804           0 :     AutoValueVector fieldOffsets(cx);  // Offset of each field field.
     805           0 :     RootedObject userFieldOffsets(cx); // User-exposed {f:offset} object
     806           0 :     RootedObject userFieldTypes(cx);   // User-exposed {f:descr} object.
     807           0 :     CheckedInt32 sizeSoFar(0);         // Size of struct thus far.
     808           0 :     uint32_t alignment = 1;            // Alignment of struct.
     809           0 :     bool opaque = false;               // Opacity of struct.
     810             : 
     811           0 :     userFieldOffsets = NewBuiltinClassInstance<PlainObject>(cx, TenuredObject);
     812           0 :     if (!userFieldOffsets)
     813           0 :         return nullptr;
     814             : 
     815           0 :     userFieldTypes = NewBuiltinClassInstance<PlainObject>(cx, TenuredObject);
     816           0 :     if (!userFieldTypes)
     817           0 :         return nullptr;
     818             : 
     819           0 :     if (!stringBuffer.append("new StructType({"))
     820           0 :         return nullptr;
     821             : 
     822           0 :     RootedValue fieldTypeVal(cx);
     823           0 :     RootedId id(cx);
     824           0 :     Rooted<TypeDescr*> fieldType(cx);
     825           0 :     for (unsigned int i = 0; i < ids.length(); i++) {
     826           0 :         id = ids[i];
     827             : 
     828             :         // Check that all the property names are non-numeric strings.
     829             :         uint32_t unused;
     830           0 :         if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&unused)) {
     831           0 :             RootedValue idValue(cx, IdToValue(id));
     832           0 :             ReportCannotConvertTo(cx, idValue, "StructType field name");
     833           0 :             return nullptr;
     834             :         }
     835             : 
     836             :         // Load the value for the current field from the `fields` object.
     837             :         // The value should be a type descriptor.
     838           0 :         if (!GetProperty(cx, fields, fields, id, &fieldTypeVal))
     839           0 :             return nullptr;
     840           0 :         fieldType = ToObjectIf<TypeDescr>(fieldTypeVal);
     841           0 :         if (!fieldType) {
     842           0 :             ReportCannotConvertTo(cx, fieldTypeVal, "StructType field specifier");
     843           0 :             return nullptr;
     844             :         }
     845             : 
     846             :         // Collect field name and type object
     847           0 :         RootedValue fieldName(cx, IdToValue(id));
     848           0 :         if (!fieldNames.append(fieldName))
     849           0 :             return nullptr;
     850           0 :         if (!fieldTypeObjs.append(ObjectValue(*fieldType)))
     851           0 :             return nullptr;
     852             : 
     853             :         // userFieldTypes[id] = typeObj
     854           0 :         if (!DefineProperty(cx, userFieldTypes, id, fieldTypeObjs[i], nullptr, nullptr,
     855             :                             JSPROP_READONLY | JSPROP_PERMANENT))
     856             :         {
     857           0 :             return nullptr;
     858             :         }
     859             : 
     860             :         // Append "f:Type" to the string repr
     861           0 :         if (i > 0 && !stringBuffer.append(", "))
     862           0 :             return nullptr;
     863           0 :         if (!stringBuffer.append(JSID_TO_ATOM(id)))
     864           0 :             return nullptr;
     865           0 :         if (!stringBuffer.append(": "))
     866           0 :             return nullptr;
     867           0 :         if (!stringBuffer.append(&fieldType->stringRepr()))
     868           0 :             return nullptr;
     869             : 
     870             :         // Offset of this field is the current total size adjusted for
     871             :         // the field's alignment.
     872           0 :         CheckedInt32 offset = RoundUpToAlignment(sizeSoFar, fieldType->alignment());
     873           0 :         if (!offset.isValid()) {
     874           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_TOO_BIG);
     875           0 :             return nullptr;
     876             :         }
     877           0 :         MOZ_ASSERT(offset.value() >= 0);
     878           0 :         if (!fieldOffsets.append(Int32Value(offset.value())))
     879           0 :             return nullptr;
     880             : 
     881             :         // userFieldOffsets[id] = offset
     882           0 :         RootedValue offsetValue(cx, Int32Value(offset.value()));
     883           0 :         if (!DefineProperty(cx, userFieldOffsets, id, offsetValue, nullptr, nullptr,
     884             :                             JSPROP_READONLY | JSPROP_PERMANENT))
     885             :         {
     886           0 :             return nullptr;
     887             :         }
     888             : 
     889             :         // Add space for this field to the total struct size.
     890           0 :         sizeSoFar = offset + fieldType->size();
     891           0 :         if (!sizeSoFar.isValid()) {
     892           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_TOO_BIG);
     893           0 :             return nullptr;
     894             :         }
     895             : 
     896             :         // Struct is opaque if any field is opaque
     897           0 :         if (fieldType->opaque())
     898           0 :             opaque = true;
     899             : 
     900             :         // Alignment of the struct is the max of the alignment of its fields.
     901           0 :         alignment = js::Max(alignment, fieldType->alignment());
     902             :     }
     903             : 
     904             :     // Complete string representation.
     905           0 :     if (!stringBuffer.append("})"))
     906           0 :         return nullptr;
     907             : 
     908           0 :     RootedAtom stringRepr(cx, stringBuffer.finishAtom());
     909           0 :     if (!stringRepr)
     910           0 :         return nullptr;
     911             : 
     912             :     // Adjust the total size to be a multiple of the final alignment.
     913           0 :     CheckedInt32 totalSize = RoundUpToAlignment(sizeSoFar, alignment);
     914           0 :     if (!totalSize.isValid()) {
     915           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_TOO_BIG);
     916           0 :         return nullptr;
     917             :     }
     918             : 
     919             :     // Now create the resulting type descriptor.
     920           0 :     RootedObject structTypePrototype(cx, GetPrototype(cx, metaTypeDescr));
     921           0 :     if (!structTypePrototype)
     922           0 :         return nullptr;
     923             : 
     924           0 :     Rooted<StructTypeDescr*> descr(cx);
     925           0 :     descr = NewObjectWithGivenProto<StructTypeDescr>(cx, structTypePrototype, SingletonObject);
     926           0 :     if (!descr)
     927           0 :         return nullptr;
     928             : 
     929           0 :     descr->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(type::Struct));
     930           0 :     descr->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr));
     931           0 :     descr->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(AssertedCast<int32_t>(alignment)));
     932           0 :     descr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(totalSize.value()));
     933           0 :     descr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(opaque));
     934             : 
     935             :     // Construct for internal use an array with the name for each field.
     936             :     {
     937           0 :         RootedObject fieldNamesVec(cx);
     938           0 :         fieldNamesVec = NewDenseCopiedArray(cx, fieldNames.length(),
     939           0 :                                             fieldNames.begin(), nullptr,
     940           0 :                                             TenuredObject);
     941           0 :         if (!fieldNamesVec)
     942           0 :             return nullptr;
     943           0 :         descr->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_NAMES, ObjectValue(*fieldNamesVec));
     944             :     }
     945             : 
     946             :     // Construct for internal use an array with the type object for each field.
     947           0 :     RootedObject fieldTypeVec(cx);
     948           0 :     fieldTypeVec = NewDenseCopiedArray(cx, fieldTypeObjs.length(),
     949           0 :                                        fieldTypeObjs.begin(), nullptr,
     950           0 :                                        TenuredObject);
     951           0 :     if (!fieldTypeVec)
     952           0 :         return nullptr;
     953           0 :     descr->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_TYPES, ObjectValue(*fieldTypeVec));
     954             : 
     955             :     // Construct for internal use an array with the offset for each field.
     956             :     {
     957           0 :         RootedObject fieldOffsetsVec(cx);
     958           0 :         fieldOffsetsVec = NewDenseCopiedArray(cx, fieldOffsets.length(),
     959           0 :                                               fieldOffsets.begin(), nullptr,
     960           0 :                                               TenuredObject);
     961           0 :         if (!fieldOffsetsVec)
     962           0 :             return nullptr;
     963           0 :         descr->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS, ObjectValue(*fieldOffsetsVec));
     964             :     }
     965             : 
     966             :     // Create data properties fieldOffsets and fieldTypes
     967           0 :     if (!FreezeObject(cx, userFieldOffsets))
     968           0 :         return nullptr;
     969           0 :     if (!FreezeObject(cx, userFieldTypes))
     970           0 :         return nullptr;
     971           0 :     RootedValue userFieldOffsetsValue(cx, ObjectValue(*userFieldOffsets));
     972           0 :     if (!DefineProperty(cx, descr, cx->names().fieldOffsets, userFieldOffsetsValue,
     973             :                         nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
     974             :     {
     975           0 :         return nullptr;
     976             :     }
     977           0 :     RootedValue userFieldTypesValue(cx, ObjectValue(*userFieldTypes));
     978           0 :     if (!DefineProperty(cx, descr, cx->names().fieldTypes, userFieldTypesValue,
     979             :                         nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
     980             :     {
     981           0 :         return nullptr;
     982             :     }
     983             : 
     984           0 :     if (!CreateUserSizeAndAlignmentProperties(cx, descr))
     985           0 :         return nullptr;
     986             : 
     987           0 :     Rooted<TypedProto*> prototypeObj(cx);
     988           0 :     prototypeObj = CreatePrototypeObjectForComplexTypeInstance(cx, structTypePrototype);
     989           0 :     if (!prototypeObj)
     990           0 :         return nullptr;
     991             : 
     992           0 :     descr->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*prototypeObj));
     993             : 
     994           0 :     if (!LinkConstructorAndPrototype(cx, descr, prototypeObj))
     995           0 :         return nullptr;
     996             : 
     997           0 :     if (!CreateTraceList(cx, descr))
     998           0 :         return nullptr;
     999             : 
    1000           0 :     if (!cx->zone()->addTypeDescrObject(cx, descr) ||
    1001           0 :         !cx->zone()->addTypeDescrObject(cx, fieldTypeVec))
    1002             :     {
    1003           0 :         ReportOutOfMemory(cx);
    1004           0 :         return nullptr;
    1005             :     }
    1006             : 
    1007           0 :     return descr;
    1008             : }
    1009             : 
    1010             : bool
    1011           0 : StructMetaTypeDescr::construct(JSContext* cx, unsigned int argc, Value* vp)
    1012             : {
    1013           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1014             : 
    1015           0 :     if (!ThrowIfNotConstructing(cx, args, "StructType"))
    1016           0 :         return false;
    1017             : 
    1018           0 :     if (args.length() >= 1 && args[0].isObject()) {
    1019           0 :         RootedObject metaTypeDescr(cx, &args.callee());
    1020           0 :         RootedObject fields(cx, &args[0].toObject());
    1021           0 :         RootedObject obj(cx, create(cx, metaTypeDescr, fields));
    1022           0 :         if (!obj)
    1023           0 :             return false;
    1024           0 :         args.rval().setObject(*obj);
    1025           0 :         return true;
    1026             :     }
    1027             : 
    1028           0 :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD_ARGS);
    1029           0 :     return false;
    1030             : }
    1031             : 
    1032             : size_t
    1033           0 : StructTypeDescr::fieldCount() const
    1034             : {
    1035           0 :     return fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_NAMES).getDenseInitializedLength();
    1036             : }
    1037             : 
    1038             : bool
    1039           0 : StructTypeDescr::fieldIndex(jsid id, size_t* out) const
    1040             : {
    1041           0 :     ArrayObject& fieldNames = fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_NAMES);
    1042           0 :     size_t l = fieldNames.getDenseInitializedLength();
    1043           0 :     for (size_t i = 0; i < l; i++) {
    1044           0 :         JSAtom& a = fieldNames.getDenseElement(i).toString()->asAtom();
    1045           0 :         if (JSID_IS_ATOM(id, &a)) {
    1046           0 :             *out = i;
    1047           0 :             return true;
    1048             :         }
    1049             :     }
    1050           0 :     return false;
    1051             : }
    1052             : 
    1053             : JSAtom&
    1054           0 : StructTypeDescr::fieldName(size_t index) const
    1055             : {
    1056           0 :     return fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_NAMES).getDenseElement(index).toString()->asAtom();
    1057             : }
    1058             : 
    1059             : size_t
    1060           0 : StructTypeDescr::fieldOffset(size_t index) const
    1061             : {
    1062           0 :     ArrayObject& fieldOffsets = fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS);
    1063           0 :     MOZ_ASSERT(index < fieldOffsets.getDenseInitializedLength());
    1064           0 :     return AssertedCast<size_t>(fieldOffsets.getDenseElement(index).toInt32());
    1065             : }
    1066             : 
    1067             : TypeDescr&
    1068           0 : StructTypeDescr::fieldDescr(size_t index) const
    1069             : {
    1070           0 :     ArrayObject& fieldDescrs = fieldInfoObject(JS_DESCR_SLOT_STRUCT_FIELD_TYPES);
    1071           0 :     MOZ_ASSERT(index < fieldDescrs.getDenseInitializedLength());
    1072           0 :     return fieldDescrs.getDenseElement(index).toObject().as<TypeDescr>();
    1073             : }
    1074             : 
    1075             : /******************************************************************************
    1076             :  * Creating the TypedObject "module"
    1077             :  *
    1078             :  * We create one global, `TypedObject`, which contains the following
    1079             :  * members:
    1080             :  *
    1081             :  * 1. uint8, uint16, etc
    1082             :  * 2. ArrayType
    1083             :  * 3. StructType
    1084             :  *
    1085             :  * Each of these is a function and hence their prototype is
    1086             :  * `Function.__proto__` (in terms of the JS Engine, they are not
    1087             :  * JSFunctions but rather instances of their own respective JSClasses
    1088             :  * which override the call and construct operations).
    1089             :  *
    1090             :  * Each type object also has its own `prototype` field. Therefore,
    1091             :  * using `StructType` as an example, the basic setup is:
    1092             :  *
    1093             :  *   StructType --__proto__--> Function.__proto__
    1094             :  *        |
    1095             :  *    prototype -- prototype --> { }
    1096             :  *        |
    1097             :  *        v
    1098             :  *       { } -----__proto__--> Function.__proto__
    1099             :  *
    1100             :  * When a new type object (e.g., an instance of StructType) is created,
    1101             :  * it will look as follows:
    1102             :  *
    1103             :  *   MyStruct -__proto__-> StructType.prototype -__proto__-> Function.__proto__
    1104             :  *        |                          |
    1105             :  *        |                     prototype
    1106             :  *        |                          |
    1107             :  *        |                          v
    1108             :  *    prototype -----__proto__----> { }
    1109             :  *        |
    1110             :  *        v
    1111             :  *       { } --__proto__-> Object.prototype
    1112             :  *
    1113             :  * Finally, when an instance of `MyStruct` is created, its
    1114             :  * structure is as follows:
    1115             :  *
    1116             :  *    object -__proto__->
    1117             :  *      MyStruct.prototype -__proto__->
    1118             :  *        StructType.prototype.prototype -__proto__->
    1119             :  *          Object.prototype
    1120             :  */
    1121             : 
    1122             : // Here `T` is either `ScalarTypeDescr` or `ReferenceTypeDescr`
    1123             : template<typename T>
    1124             : static bool
    1125          72 : DefineSimpleTypeDescr(JSContext* cx,
    1126             :                       Handle<GlobalObject*> global,
    1127             :                       HandleObject module,
    1128             :                       typename T::Type type,
    1129             :                       HandlePropertyName className)
    1130             : {
    1131         144 :     RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
    1132          72 :     if (!objProto)
    1133           0 :         return false;
    1134             : 
    1135         144 :     RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global));
    1136          72 :     if (!funcProto)
    1137           0 :         return false;
    1138             : 
    1139         144 :     Rooted<T*> descr(cx);
    1140          72 :     descr = NewObjectWithGivenProto<T>(cx, funcProto, SingletonObject);
    1141          72 :     if (!descr)
    1142           0 :         return false;
    1143             : 
    1144          72 :     descr->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(T::Kind));
    1145          72 :     descr->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(className));
    1146          72 :     descr->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(T::alignment(type)));
    1147          72 :     descr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(AssertedCast<int32_t>(T::size(type))));
    1148          72 :     descr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(T::Opaque));
    1149          72 :     descr->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(type));
    1150             : 
    1151          72 :     if (!CreateUserSizeAndAlignmentProperties(cx, descr))
    1152           0 :         return false;
    1153             : 
    1154          72 :     if (!JS_DefineFunctions(cx, descr, T::typeObjectMethods))
    1155           0 :         return false;
    1156             : 
    1157             :     // Create the typed prototype for the scalar type. This winds up
    1158             :     // not being user accessible, but we still create one for consistency.
    1159         144 :     Rooted<TypedProto*> proto(cx);
    1160          72 :     proto = NewObjectWithGivenProto<TypedProto>(cx, objProto, TenuredObject);
    1161          72 :     if (!proto)
    1162           0 :         return false;
    1163          72 :     descr->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto));
    1164             : 
    1165         144 :     RootedValue descrValue(cx, ObjectValue(*descr));
    1166          72 :     if (!DefineProperty(cx, module, className, descrValue, nullptr, nullptr, 0))
    1167           0 :         return false;
    1168             : 
    1169          72 :     if (!CreateTraceList(cx, descr))
    1170           0 :         return false;
    1171             : 
    1172          72 :     if (!cx->zone()->addTypeDescrObject(cx, descr))
    1173           0 :         return false;
    1174             : 
    1175          72 :     return true;
    1176             : }
    1177             : 
    1178             : ///////////////////////////////////////////////////////////////////////////
    1179             : 
    1180             : template<typename T>
    1181             : static JSObject*
    1182          12 : DefineMetaTypeDescr(JSContext* cx,
    1183             :                     const char* name,
    1184             :                     Handle<GlobalObject*> global,
    1185             :                     Handle<TypedObjectModuleObject*> module,
    1186             :                     TypedObjectModuleObject::Slot protoSlot)
    1187             : {
    1188          24 :     RootedAtom className(cx, Atomize(cx, name, strlen(name)));
    1189          12 :     if (!className)
    1190           0 :         return nullptr;
    1191             : 
    1192          24 :     RootedObject funcProto(cx, GlobalObject::getOrCreateFunctionPrototype(cx, global));
    1193          12 :     if (!funcProto)
    1194           0 :         return nullptr;
    1195             : 
    1196             :     // Create ctor.prototype, which inherits from Function.__proto__
    1197             : 
    1198          24 :     RootedObject proto(cx, NewObjectWithGivenProto<PlainObject>(cx, funcProto, SingletonObject));
    1199          12 :     if (!proto)
    1200           0 :         return nullptr;
    1201             : 
    1202             :     // Create ctor.prototype.prototype, which inherits from Object.__proto__
    1203             : 
    1204          24 :     RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
    1205          12 :     if (!objProto)
    1206           0 :         return nullptr;
    1207          24 :     RootedObject protoProto(cx);
    1208          12 :     protoProto = NewObjectWithGivenProto<PlainObject>(cx, objProto, SingletonObject);
    1209          12 :     if (!protoProto)
    1210           0 :         return nullptr;
    1211             : 
    1212          24 :     RootedValue protoProtoValue(cx, ObjectValue(*protoProto));
    1213          12 :     if (!DefineProperty(cx, proto, cx->names().prototype, protoProtoValue,
    1214             :                         nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
    1215             :     {
    1216           0 :         return nullptr;
    1217             :     }
    1218             : 
    1219             :     // Create ctor itself
    1220             : 
    1221          12 :     const int constructorLength = 2;
    1222          24 :     RootedFunction ctor(cx);
    1223          12 :     ctor = GlobalObject::createConstructor(cx, T::construct, className, constructorLength);
    1224          48 :     if (!ctor ||
    1225          36 :         !LinkConstructorAndPrototype(cx, ctor, proto) ||
    1226          48 :         !DefinePropertiesAndFunctions(cx, proto,
    1227             :                                       T::typeObjectProperties,
    1228          48 :                                       T::typeObjectMethods) ||
    1229          36 :         !DefinePropertiesAndFunctions(cx, protoProto,
    1230             :                                       T::typedObjectProperties,
    1231             :                                       T::typedObjectMethods))
    1232             :     {
    1233           0 :         return nullptr;
    1234             :     }
    1235             : 
    1236          12 :     module->initReservedSlot(protoSlot, ObjectValue(*proto));
    1237             : 
    1238          12 :     return ctor;
    1239             : }
    1240             : 
    1241             : /*  The initialization strategy for TypedObjects is mildly unusual
    1242             :  * compared to other classes. Because all of the types are members
    1243             :  * of a single global, `TypedObject`, we basically make the
    1244             :  * initializer for the `TypedObject` class populate the
    1245             :  * `TypedObject` global (which is referred to as "module" herein).
    1246             :  */
    1247             : /* static */ bool
    1248           6 : GlobalObject::initTypedObjectModule(JSContext* cx, Handle<GlobalObject*> global)
    1249             : {
    1250          12 :     RootedObject objProto(cx, GlobalObject::getOrCreateObjectPrototype(cx, global));
    1251           6 :     if (!objProto)
    1252           0 :         return false;
    1253             : 
    1254          12 :     Rooted<TypedObjectModuleObject*> module(cx);
    1255           6 :     module = NewObjectWithGivenProto<TypedObjectModuleObject>(cx, objProto);
    1256           6 :     if (!module)
    1257           0 :         return false;
    1258             : 
    1259           6 :     if (!JS_DefineFunctions(cx, module, TypedObjectMethods))
    1260           0 :         return false;
    1261             : 
    1262             :     // uint8, uint16, any, etc
    1263             : 
    1264             : #define BINARYDATA_SCALAR_DEFINE(constant_, type_, name_)                       \
    1265             :     if (!DefineSimpleTypeDescr<ScalarTypeDescr>(cx, global, module, constant_,      \
    1266             :                                             cx->names().name_))                 \
    1267             :         return false;
    1268           6 :     JS_FOR_EACH_SCALAR_TYPE_REPR(BINARYDATA_SCALAR_DEFINE)
    1269             : #undef BINARYDATA_SCALAR_DEFINE
    1270             : 
    1271             : #define BINARYDATA_REFERENCE_DEFINE(constant_, type_, name_)                    \
    1272             :     if (!DefineSimpleTypeDescr<ReferenceTypeDescr>(cx, global, module, constant_,   \
    1273             :                                                cx->names().name_))              \
    1274             :         return false;
    1275           6 :     JS_FOR_EACH_REFERENCE_TYPE_REPR(BINARYDATA_REFERENCE_DEFINE)
    1276             : #undef BINARYDATA_REFERENCE_DEFINE
    1277             : 
    1278             :     // ArrayType.
    1279             : 
    1280          12 :     RootedObject arrayType(cx);
    1281          12 :     arrayType = DefineMetaTypeDescr<ArrayMetaTypeDescr>(
    1282           6 :         cx, "ArrayType", global, module, TypedObjectModuleObject::ArrayTypePrototype);
    1283           6 :     if (!arrayType)
    1284           0 :         return false;
    1285             : 
    1286          12 :     RootedValue arrayTypeValue(cx, ObjectValue(*arrayType));
    1287           6 :     if (!DefineProperty(cx, module, cx->names().ArrayType, arrayTypeValue,
    1288             :                         nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
    1289             :     {
    1290           0 :         return false;
    1291             :     }
    1292             : 
    1293             :     // StructType.
    1294             : 
    1295          12 :     RootedObject structType(cx);
    1296          12 :     structType = DefineMetaTypeDescr<StructMetaTypeDescr>(
    1297           6 :         cx, "StructType", global, module, TypedObjectModuleObject::StructTypePrototype);
    1298           6 :     if (!structType)
    1299           0 :         return false;
    1300             : 
    1301          12 :     RootedValue structTypeValue(cx, ObjectValue(*structType));
    1302           6 :     if (!DefineProperty(cx, module, cx->names().StructType, structTypeValue,
    1303             :                         nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
    1304             :     {
    1305           0 :         return false;
    1306             :     }
    1307             : 
    1308             :     // Everything is setup, install module on the global object:
    1309          12 :     RootedValue moduleValue(cx, ObjectValue(*module));
    1310           6 :     if (!DefineProperty(cx, global, cx->names().TypedObject, moduleValue, nullptr, nullptr,
    1311             :                         JSPROP_RESOLVING))
    1312             :     {
    1313           0 :         return false;
    1314             :     }
    1315             : 
    1316           6 :     global->setConstructor(JSProto_TypedObject, moduleValue);
    1317             : 
    1318           6 :     return module;
    1319             : }
    1320             : 
    1321             : JSObject*
    1322           6 : js::InitTypedObjectModuleObject(JSContext* cx, HandleObject obj)
    1323             : {
    1324           6 :     Handle<GlobalObject*> global = obj.as<GlobalObject>();
    1325           6 :     return GlobalObject::getOrCreateTypedObjectModule(cx, global);
    1326             : }
    1327             : 
    1328             : /******************************************************************************
    1329             :  * Typed objects
    1330             :  */
    1331             : 
    1332             : uint32_t
    1333           0 : TypedObject::offset() const
    1334             : {
    1335           0 :     if (is<InlineTypedObject>())
    1336           0 :         return 0;
    1337           0 :     return PointerRangeSize(typedMemBase(), typedMem());
    1338             : }
    1339             : 
    1340             : uint32_t
    1341           0 : TypedObject::length() const
    1342             : {
    1343           0 :     return typeDescr().as<ArrayTypeDescr>().length();
    1344             : }
    1345             : 
    1346             : uint8_t*
    1347           0 : TypedObject::typedMem() const
    1348             : {
    1349           0 :     MOZ_ASSERT(isAttached());
    1350             : 
    1351           0 :     if (is<InlineTypedObject>())
    1352           0 :         return as<InlineTypedObject>().inlineTypedMem();
    1353           0 :     return as<OutlineTypedObject>().outOfLineTypedMem();
    1354             : }
    1355             : 
    1356             : uint8_t*
    1357           0 : TypedObject::typedMemBase() const
    1358             : {
    1359           0 :     MOZ_ASSERT(isAttached());
    1360           0 :     MOZ_ASSERT(is<OutlineTypedObject>());
    1361             : 
    1362           0 :     JSObject& owner = as<OutlineTypedObject>().owner();
    1363           0 :     if (owner.is<ArrayBufferObject>())
    1364           0 :         return owner.as<ArrayBufferObject>().dataPointer();
    1365           0 :     return owner.as<InlineTypedObject>().inlineTypedMem();
    1366             : }
    1367             : 
    1368             : bool
    1369           0 : TypedObject::isAttached() const
    1370             : {
    1371           0 :     if (is<InlineTransparentTypedObject>()) {
    1372           0 :         ObjectWeakMap* table = compartment()->lazyArrayBuffers;
    1373           0 :         if (table) {
    1374           0 :             JSObject* buffer = table->lookup(this);
    1375           0 :             if (buffer)
    1376           0 :                 return !buffer->as<ArrayBufferObject>().isDetached();
    1377             :         }
    1378           0 :         return true;
    1379             :     }
    1380           0 :     if (is<InlineOpaqueTypedObject>())
    1381           0 :         return true;
    1382           0 :     if (!as<OutlineTypedObject>().outOfLineTypedMem())
    1383           0 :         return false;
    1384           0 :     JSObject& owner = as<OutlineTypedObject>().owner();
    1385           0 :     if (owner.is<ArrayBufferObject>() && owner.as<ArrayBufferObject>().isDetached())
    1386           0 :         return false;
    1387           0 :     return true;
    1388             : }
    1389             : 
    1390             : /* static */ bool
    1391           0 : TypedObject::GetBuffer(JSContext* cx, unsigned argc, Value* vp)
    1392             : {
    1393           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1394           0 :     JSObject& obj = args[0].toObject();
    1395             :     ArrayBufferObject* buffer;
    1396           0 :     if (obj.is<OutlineTransparentTypedObject>())
    1397           0 :         buffer = obj.as<OutlineTransparentTypedObject>().getOrCreateBuffer(cx);
    1398             :     else
    1399           0 :         buffer = obj.as<InlineTransparentTypedObject>().getOrCreateBuffer(cx);
    1400           0 :     if (!buffer)
    1401           0 :         return false;
    1402           0 :     args.rval().setObject(*buffer);
    1403           0 :     return true;
    1404             : }
    1405             : 
    1406             : /* static */ bool
    1407           0 : TypedObject::GetByteOffset(JSContext* cx, unsigned argc, Value* vp)
    1408             : {
    1409           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1410           0 :     args.rval().setInt32(AssertedCast<int32_t>(args[0].toObject().as<TypedObject>().offset()));
    1411           0 :     return true;
    1412             : }
    1413             : 
    1414             : /******************************************************************************
    1415             :  * Outline typed objects
    1416             :  */
    1417             : 
    1418             : /*static*/ OutlineTypedObject*
    1419           0 : OutlineTypedObject::createUnattached(JSContext* cx,
    1420             :                                      HandleTypeDescr descr,
    1421             :                                      int32_t length,
    1422             :                                      gc::InitialHeap heap)
    1423             : {
    1424           0 :     if (descr->opaque())
    1425           0 :         return createUnattachedWithClass(cx, &OutlineOpaqueTypedObject::class_, descr, length, heap);
    1426             :     else
    1427           0 :         return createUnattachedWithClass(cx, &OutlineTransparentTypedObject::class_, descr, length, heap);
    1428             : }
    1429             : 
    1430             : void
    1431           0 : OutlineTypedObject::setOwnerAndData(JSObject* owner, uint8_t* data)
    1432             : {
    1433             :     // Make sure we don't associate with array buffers whose data is from an
    1434             :     // inline typed object, see obj_trace.
    1435           0 :     MOZ_ASSERT_IF(owner && owner->is<ArrayBufferObject>(),
    1436             :                   !owner->as<ArrayBufferObject>().forInlineTypedObject());
    1437             : 
    1438             :     // Typed objects cannot move from one owner to another, so don't worry
    1439             :     // about pre barriers during this initialization.
    1440           0 :     owner_ = owner;
    1441           0 :     data_ = data;
    1442             : 
    1443             :     // Trigger a post barrier when attaching an object outside the nursery to
    1444             :     // one that is inside it.
    1445           0 :     if (owner && !IsInsideNursery(this) && IsInsideNursery(owner))
    1446           0 :         zone()->group()->storeBuffer().putWholeCell(this);
    1447           0 : }
    1448             : 
    1449             : /*static*/ OutlineTypedObject*
    1450           0 : OutlineTypedObject::createUnattachedWithClass(JSContext* cx,
    1451             :                                               const Class* clasp,
    1452             :                                               HandleTypeDescr descr,
    1453             :                                               int32_t length,
    1454             :                                               gc::InitialHeap heap)
    1455             : {
    1456           0 :     MOZ_ASSERT(clasp == &OutlineTransparentTypedObject::class_ ||
    1457             :                clasp == &OutlineOpaqueTypedObject::class_);
    1458             : 
    1459           0 :     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp,
    1460           0 :                                                              TaggedProto(&descr->typedProto()),
    1461           0 :                                                              descr));
    1462           0 :     if (!group)
    1463           0 :         return nullptr;
    1464             : 
    1465           0 :     NewObjectKind newKind = (heap == gc::TenuredHeap) ? TenuredObject : GenericObject;
    1466           0 :     OutlineTypedObject* obj = NewObjectWithGroup<OutlineTypedObject>(cx, group,
    1467             :                                                                      gc::AllocKind::OBJECT0,
    1468           0 :                                                                      newKind);
    1469           0 :     if (!obj)
    1470           0 :         return nullptr;
    1471             : 
    1472           0 :     obj->setOwnerAndData(nullptr, nullptr);
    1473           0 :     return obj;
    1474             : }
    1475             : 
    1476             : void
    1477           0 : OutlineTypedObject::attach(JSContext* cx, ArrayBufferObject& buffer, uint32_t offset)
    1478             : {
    1479           0 :     MOZ_ASSERT(!isAttached());
    1480           0 :     MOZ_ASSERT(offset <= buffer.byteLength());
    1481           0 :     MOZ_ASSERT(size() <= buffer.byteLength() - offset);
    1482             : 
    1483             :     // If the owner's data is from an inline typed object, associate this with
    1484             :     // the inline typed object instead, to simplify tracing.
    1485           0 :     if (buffer.forInlineTypedObject()) {
    1486           0 :         InlineTypedObject& realOwner = buffer.firstView()->as<InlineTypedObject>();
    1487           0 :         attach(cx, realOwner, offset);
    1488           0 :         return;
    1489             :     }
    1490             : 
    1491           0 :     buffer.setHasTypedObjectViews();
    1492             : 
    1493             :     {
    1494           0 :         AutoEnterOOMUnsafeRegion oomUnsafe;
    1495           0 :         if (!buffer.addView(cx, this))
    1496           0 :             oomUnsafe.crash("TypedObject::attach");
    1497             :     }
    1498             : 
    1499           0 :     setOwnerAndData(&buffer, buffer.dataPointer() + offset);
    1500             : }
    1501             : 
    1502             : void
    1503           0 : OutlineTypedObject::attach(JSContext* cx, TypedObject& typedObj, uint32_t offset)
    1504             : {
    1505           0 :     MOZ_ASSERT(!isAttached());
    1506           0 :     MOZ_ASSERT(typedObj.isAttached());
    1507             : 
    1508           0 :     JSObject* owner = &typedObj;
    1509           0 :     if (typedObj.is<OutlineTypedObject>()) {
    1510           0 :         owner = &typedObj.as<OutlineTypedObject>().owner();
    1511           0 :         MOZ_ASSERT(typedObj.offset() <= UINT32_MAX - offset);
    1512           0 :         offset += typedObj.offset();
    1513             :     }
    1514             : 
    1515           0 :     if (owner->is<ArrayBufferObject>()) {
    1516           0 :         attach(cx, owner->as<ArrayBufferObject>(), offset);
    1517             :     } else {
    1518           0 :         MOZ_ASSERT(owner->is<InlineTypedObject>());
    1519           0 :         JS::AutoCheckCannotGC nogc(cx);
    1520           0 :         setOwnerAndData(owner, owner->as<InlineTypedObject>().inlineTypedMem(nogc) + offset);
    1521             :     }
    1522           0 : }
    1523             : 
    1524             : // Returns a suitable JS_TYPEDOBJ_SLOT_LENGTH value for an instance of
    1525             : // the type `type`.
    1526             : static uint32_t
    1527           0 : TypedObjLengthFromType(TypeDescr& descr)
    1528             : {
    1529           0 :     switch (descr.kind()) {
    1530             :       case type::Scalar:
    1531             :       case type::Reference:
    1532             :       case type::Struct:
    1533             :       case type::Simd:
    1534           0 :         return 0;
    1535             : 
    1536             :       case type::Array:
    1537           0 :         return descr.as<ArrayTypeDescr>().length();
    1538             :     }
    1539           0 :     MOZ_CRASH("Invalid kind");
    1540             : }
    1541             : 
    1542             : /*static*/ OutlineTypedObject*
    1543           0 : OutlineTypedObject::createDerived(JSContext* cx, HandleTypeDescr type,
    1544             :                                   HandleTypedObject typedObj, uint32_t offset)
    1545             : {
    1546           0 :     MOZ_ASSERT(offset <= typedObj->size());
    1547           0 :     MOZ_ASSERT(offset + type->size() <= typedObj->size());
    1548             : 
    1549           0 :     int32_t length = TypedObjLengthFromType(*type);
    1550             : 
    1551           0 :     const js::Class* clasp = typedObj->opaque()
    1552           0 :                              ? &OutlineOpaqueTypedObject::class_
    1553           0 :                              : &OutlineTransparentTypedObject::class_;
    1554           0 :     Rooted<OutlineTypedObject*> obj(cx);
    1555           0 :     obj = createUnattachedWithClass(cx, clasp, type, length);
    1556           0 :     if (!obj)
    1557           0 :         return nullptr;
    1558             : 
    1559           0 :     obj->attach(cx, *typedObj, offset);
    1560           0 :     return obj;
    1561             : }
    1562             : 
    1563             : /*static*/ TypedObject*
    1564           0 : TypedObject::createZeroed(JSContext* cx, HandleTypeDescr descr, int32_t length, gc::InitialHeap heap)
    1565             : {
    1566             :     // If possible, create an object with inline data.
    1567           0 :     if (descr->size() <= InlineTypedObject::MaximumSize) {
    1568           0 :         AutoSetNewObjectMetadata metadata(cx);
    1569             : 
    1570           0 :         InlineTypedObject* obj = InlineTypedObject::create(cx, descr, heap);
    1571           0 :         if (!obj)
    1572           0 :             return nullptr;
    1573           0 :         JS::AutoCheckCannotGC nogc(cx);
    1574           0 :         descr->initInstances(cx->runtime(), obj->inlineTypedMem(nogc), 1);
    1575           0 :         return obj;
    1576             :     }
    1577             : 
    1578             :     // Create unattached wrapper object.
    1579           0 :     Rooted<OutlineTypedObject*> obj(cx, OutlineTypedObject::createUnattached(cx, descr, length, heap));
    1580           0 :     if (!obj)
    1581           0 :         return nullptr;
    1582             : 
    1583             :     // Allocate and initialize the memory for this instance.
    1584           0 :     size_t totalSize = descr->size();
    1585           0 :     Rooted<ArrayBufferObject*> buffer(cx);
    1586           0 :     buffer = ArrayBufferObject::create(cx, totalSize);
    1587           0 :     if (!buffer)
    1588           0 :         return nullptr;
    1589           0 :     descr->initInstances(cx->runtime(), buffer->dataPointer(), 1);
    1590           0 :     obj->attach(cx, *buffer, 0);
    1591           0 :     return obj;
    1592             : }
    1593             : 
    1594             : static bool
    1595           0 : ReportTypedObjTypeError(JSContext* cx,
    1596             :                         const unsigned errorNumber,
    1597             :                         HandleTypedObject obj)
    1598             : {
    1599             :     // Serialize type string of obj
    1600           0 :     RootedAtom typeReprAtom(cx, &obj->typeDescr().stringRepr());
    1601           0 :     UniqueChars typeReprStr(JS_EncodeStringToUTF8(cx, typeReprAtom));
    1602           0 :     if (!typeReprStr)
    1603           0 :         return false;
    1604             : 
    1605           0 :     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber, typeReprStr.get());
    1606           0 :     return false;
    1607             : }
    1608             : 
    1609             : /* static */ void
    1610           0 : OutlineTypedObject::obj_trace(JSTracer* trc, JSObject* object)
    1611             : {
    1612           0 :     OutlineTypedObject& typedObj = object->as<OutlineTypedObject>();
    1613             : 
    1614           0 :     TraceEdge(trc, &typedObj.shape_, "OutlineTypedObject_shape");
    1615             : 
    1616           0 :     if (!typedObj.owner_)
    1617           0 :         return;
    1618             : 
    1619           0 :     TypeDescr& descr = typedObj.typeDescr();
    1620             : 
    1621             :     // Mark the owner, watching in case it is moved by the tracer.
    1622           0 :     JSObject* oldOwner = typedObj.owner_;
    1623           0 :     TraceManuallyBarrieredEdge(trc, &typedObj.owner_, "typed object owner");
    1624           0 :     JSObject* owner = typedObj.owner_;
    1625             : 
    1626           0 :     uint8_t* oldData = typedObj.outOfLineTypedMem();
    1627           0 :     uint8_t* newData = oldData;
    1628             : 
    1629             :     // Update the data pointer if the owner moved and the owner's data is
    1630             :     // inline with it. Note that an array buffer pointing to data in an inline
    1631             :     // typed object will never be used as an owner for another outline typed
    1632             :     // object. In such cases, the owner will be the inline typed object itself.
    1633           0 :     MakeAccessibleAfterMovingGC(owner);
    1634           0 :     MOZ_ASSERT_IF(owner->is<ArrayBufferObject>(),
    1635             :                   !owner->as<ArrayBufferObject>().forInlineTypedObject());
    1636           0 :     if (owner != oldOwner &&
    1637           0 :         (owner->is<InlineTypedObject>() ||
    1638           0 :          owner->as<ArrayBufferObject>().hasInlineData()))
    1639             :     {
    1640           0 :         newData += reinterpret_cast<uint8_t*>(owner) - reinterpret_cast<uint8_t*>(oldOwner);
    1641           0 :         typedObj.setData(newData);
    1642             : 
    1643           0 :         if (trc->isTenuringTracer()) {
    1644           0 :             Nursery& nursery = typedObj.zoneFromAnyThread()->group()->nursery();
    1645           0 :             nursery.maybeSetForwardingPointer(trc, oldData, newData, /* direct = */ false);
    1646             :         }
    1647             :     }
    1648             : 
    1649           0 :     if (!descr.opaque() || !typedObj.isAttached())
    1650           0 :         return;
    1651             : 
    1652           0 :     descr.traceInstances(trc, newData, 1);
    1653             : }
    1654             : 
    1655             : bool
    1656           0 : TypeDescr::hasProperty(const JSAtomState& names, jsid id)
    1657             : {
    1658           0 :     switch (kind()) {
    1659             :       case type::Scalar:
    1660             :       case type::Reference:
    1661             :       case type::Simd:
    1662           0 :         return false;
    1663             : 
    1664             :       case type::Array:
    1665             :       {
    1666             :         uint32_t index;
    1667           0 :         return IdIsIndex(id, &index) || JSID_IS_ATOM(id, names.length);
    1668             :       }
    1669             : 
    1670             :       case type::Struct:
    1671             :       {
    1672             :         size_t index;
    1673           0 :         return as<StructTypeDescr>().fieldIndex(id, &index);
    1674             :       }
    1675             :     }
    1676             : 
    1677           0 :     MOZ_CRASH("Unexpected kind");
    1678             : }
    1679             : 
    1680             : /* static */ bool
    1681           0 : TypedObject::obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
    1682             :                                 MutableHandleObject objp, MutableHandle<PropertyResult> propp)
    1683             : {
    1684           0 :     if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) {
    1685           0 :         propp.setNonNativeProperty();
    1686           0 :         objp.set(obj);
    1687           0 :         return true;
    1688             :     }
    1689             : 
    1690           0 :     RootedObject proto(cx, obj->staticPrototype());
    1691           0 :     if (!proto) {
    1692           0 :         objp.set(nullptr);
    1693           0 :         propp.setNotFound();
    1694           0 :         return true;
    1695             :     }
    1696             : 
    1697           0 :     return LookupProperty(cx, proto, id, objp, propp);
    1698             : }
    1699             : 
    1700             : static bool
    1701           0 : ReportPropertyError(JSContext* cx,
    1702             :                     const unsigned errorNumber,
    1703             :                     HandleId id)
    1704             : {
    1705           0 :     RootedValue idVal(cx, IdToValue(id));
    1706           0 :     RootedString str(cx, ValueToSource(cx, idVal));
    1707           0 :     if (!str)
    1708           0 :         return false;
    1709             : 
    1710           0 :     UniqueChars propName(JS_EncodeStringToUTF8(cx, str));
    1711           0 :     if (!propName)
    1712           0 :         return false;
    1713             : 
    1714           0 :     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber, propName.get());
    1715           0 :     return false;
    1716             : }
    1717             : 
    1718             : bool
    1719           0 : TypedObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
    1720             :                                 Handle<PropertyDescriptor> desc,
    1721             :                                 ObjectOpResult& result)
    1722             : {
    1723           0 :     Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
    1724           0 :     return ReportTypedObjTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, typedObj);
    1725             : }
    1726             : 
    1727             : bool
    1728           0 : TypedObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
    1729             : {
    1730           0 :     Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
    1731           0 :     switch (typedObj->typeDescr().kind()) {
    1732             :       case type::Scalar:
    1733             :       case type::Reference:
    1734             :       case type::Simd:
    1735           0 :         break;
    1736             : 
    1737             :       case type::Array: {
    1738           0 :         if (JSID_IS_ATOM(id, cx->names().length)) {
    1739           0 :             *foundp = true;
    1740           0 :             return true;
    1741             :         }
    1742             :         uint32_t index;
    1743             :         // Elements are not inherited from the prototype.
    1744           0 :         if (IdIsIndex(id, &index)) {
    1745           0 :             *foundp = (index < uint32_t(typedObj->length()));
    1746           0 :             return true;
    1747             :         }
    1748           0 :         break;
    1749             :       }
    1750             : 
    1751             :       case type::Struct:
    1752             :         size_t index;
    1753           0 :         if (typedObj->typeDescr().as<StructTypeDescr>().fieldIndex(id, &index)) {
    1754           0 :             *foundp = true;
    1755           0 :             return true;
    1756             :         }
    1757             :     }
    1758             : 
    1759           0 :     RootedObject proto(cx, obj->staticPrototype());
    1760           0 :     if (!proto) {
    1761           0 :         *foundp = false;
    1762           0 :         return true;
    1763             :     }
    1764             : 
    1765           0 :     return HasProperty(cx, proto, id, foundp);
    1766             : }
    1767             : 
    1768             : bool
    1769           0 : TypedObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
    1770             :                              HandleId id, MutableHandleValue vp)
    1771             : {
    1772           0 :     Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
    1773             : 
    1774             :     // Dispatch elements to obj_getElement:
    1775             :     uint32_t index;
    1776           0 :     if (IdIsIndex(id, &index))
    1777           0 :         return obj_getElement(cx, obj, receiver, index, vp);
    1778             : 
    1779             :     // Handle everything else here:
    1780             : 
    1781           0 :     switch (typedObj->typeDescr().kind()) {
    1782             :       case type::Scalar:
    1783             :       case type::Reference:
    1784           0 :         break;
    1785             : 
    1786             :       case type::Simd:
    1787           0 :         break;
    1788             : 
    1789             :       case type::Array:
    1790           0 :         if (JSID_IS_ATOM(id, cx->names().length)) {
    1791           0 :             if (!typedObj->isAttached()) {
    1792             :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1793           0 :                                           JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
    1794           0 :                 return false;
    1795             :             }
    1796             : 
    1797           0 :             vp.setInt32(typedObj->length());
    1798           0 :             return true;
    1799             :         }
    1800           0 :         break;
    1801             : 
    1802             :       case type::Struct: {
    1803           0 :         Rooted<StructTypeDescr*> descr(cx, &typedObj->typeDescr().as<StructTypeDescr>());
    1804             : 
    1805             :         size_t fieldIndex;
    1806           0 :         if (!descr->fieldIndex(id, &fieldIndex))
    1807           0 :             break;
    1808             : 
    1809           0 :         size_t offset = descr->fieldOffset(fieldIndex);
    1810           0 :         Rooted<TypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
    1811           0 :         return Reify(cx, fieldType, typedObj, offset, vp);
    1812             :       }
    1813             :     }
    1814             : 
    1815           0 :     RootedObject proto(cx, obj->staticPrototype());
    1816           0 :     if (!proto) {
    1817           0 :         vp.setUndefined();
    1818           0 :         return true;
    1819             :     }
    1820             : 
    1821           0 :     return GetProperty(cx, proto, receiver, id, vp);
    1822             : }
    1823             : 
    1824             : bool
    1825           0 : TypedObject::obj_getElement(JSContext* cx, HandleObject obj, HandleValue receiver,
    1826             :                             uint32_t index, MutableHandleValue vp)
    1827             : {
    1828           0 :     MOZ_ASSERT(obj->is<TypedObject>());
    1829           0 :     Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
    1830           0 :     Rooted<TypeDescr*> descr(cx, &typedObj->typeDescr());
    1831             : 
    1832           0 :     switch (descr->kind()) {
    1833             :       case type::Scalar:
    1834             :       case type::Reference:
    1835             :       case type::Simd:
    1836             :       case type::Struct:
    1837           0 :         break;
    1838             : 
    1839             :       case type::Array:
    1840           0 :         return obj_getArrayElement(cx, typedObj, descr, index, vp);
    1841             :     }
    1842             : 
    1843           0 :     RootedObject proto(cx, obj->staticPrototype());
    1844           0 :     if (!proto) {
    1845           0 :         vp.setUndefined();
    1846           0 :         return true;
    1847             :     }
    1848             : 
    1849           0 :     return GetElement(cx, proto, receiver, index, vp);
    1850             : }
    1851             : 
    1852             : /*static*/ bool
    1853           0 : TypedObject::obj_getArrayElement(JSContext* cx,
    1854             :                                  Handle<TypedObject*> typedObj,
    1855             :                                  Handle<TypeDescr*> typeDescr,
    1856             :                                  uint32_t index,
    1857             :                                  MutableHandleValue vp)
    1858             : {
    1859             :     // Elements are not inherited from the prototype.
    1860           0 :     if (index >= (size_t) typedObj->length()) {
    1861           0 :         vp.setUndefined();
    1862           0 :         return true;
    1863             :     }
    1864             : 
    1865           0 :     Rooted<TypeDescr*> elementType(cx, &typeDescr->as<ArrayTypeDescr>().elementType());
    1866           0 :     size_t offset = elementType->size() * index;
    1867           0 :     return Reify(cx, elementType, typedObj, offset, vp);
    1868             : }
    1869             : 
    1870             : bool
    1871           0 : TypedObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
    1872             :                              HandleValue receiver, ObjectOpResult& result)
    1873             : {
    1874           0 :     Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
    1875             : 
    1876           0 :     switch (typedObj->typeDescr().kind()) {
    1877             :       case type::Scalar:
    1878             :       case type::Reference:
    1879           0 :         break;
    1880             : 
    1881             :       case type::Simd:
    1882           0 :         break;
    1883             : 
    1884             :       case type::Array: {
    1885           0 :         if (JSID_IS_ATOM(id, cx->names().length)) {
    1886           0 :             if (receiver.isObject() && obj == &receiver.toObject()) {
    1887             :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1888           0 :                                           JSMSG_CANT_REDEFINE_ARRAY_LENGTH);
    1889           0 :                 return false;
    1890             :             }
    1891           0 :             return result.failReadOnly();
    1892             :         }
    1893             : 
    1894             :         uint32_t index;
    1895           0 :         if (IdIsIndex(id, &index)) {
    1896           0 :             if (!receiver.isObject() || obj != &receiver.toObject())
    1897           0 :                 return SetPropertyByDefining(cx, id, v, receiver, result);
    1898             : 
    1899           0 :             if (index >= uint32_t(typedObj->length())) {
    1900             :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1901           0 :                                           JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX);
    1902           0 :                 return false;
    1903             :             }
    1904             : 
    1905           0 :             Rooted<TypeDescr*> elementType(cx);
    1906           0 :             elementType = &typedObj->typeDescr().as<ArrayTypeDescr>().elementType();
    1907           0 :             size_t offset = elementType->size() * index;
    1908           0 :             if (!ConvertAndCopyTo(cx, elementType, typedObj, offset, nullptr, v))
    1909           0 :                 return false;
    1910           0 :             return result.succeed();
    1911             :         }
    1912           0 :         break;
    1913             :       }
    1914             : 
    1915             :       case type::Struct: {
    1916           0 :         Rooted<StructTypeDescr*> descr(cx, &typedObj->typeDescr().as<StructTypeDescr>());
    1917             : 
    1918             :         size_t fieldIndex;
    1919           0 :         if (!descr->fieldIndex(id, &fieldIndex))
    1920           0 :             break;
    1921             : 
    1922           0 :         if (!receiver.isObject() || obj != &receiver.toObject())
    1923           0 :             return SetPropertyByDefining(cx, id, v, receiver, result);
    1924             : 
    1925           0 :         size_t offset = descr->fieldOffset(fieldIndex);
    1926           0 :         Rooted<TypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
    1927           0 :         RootedAtom fieldName(cx, &descr->fieldName(fieldIndex));
    1928           0 :         if (!ConvertAndCopyTo(cx, fieldType, typedObj, offset, fieldName, v))
    1929           0 :             return false;
    1930           0 :         return result.succeed();
    1931             :       }
    1932             :     }
    1933             : 
    1934           0 :     return SetPropertyOnProto(cx, obj, id, v, receiver, result);
    1935             : }
    1936             : 
    1937             : bool
    1938           0 : TypedObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
    1939             :                                           MutableHandle<PropertyDescriptor> desc)
    1940             : {
    1941           0 :     Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
    1942           0 :     if (!typedObj->isAttached()) {
    1943           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
    1944           0 :         return false;
    1945             :     }
    1946             : 
    1947           0 :     Rooted<TypeDescr*> descr(cx, &typedObj->typeDescr());
    1948           0 :     switch (descr->kind()) {
    1949             :       case type::Scalar:
    1950             :       case type::Reference:
    1951             :       case type::Simd:
    1952           0 :         break;
    1953             : 
    1954             :       case type::Array:
    1955             :       {
    1956             :         uint32_t index;
    1957           0 :         if (IdIsIndex(id, &index)) {
    1958           0 :             if (!obj_getArrayElement(cx, typedObj, descr, index, desc.value()))
    1959           0 :                 return false;
    1960           0 :             desc.setAttributes(JSPROP_ENUMERATE | JSPROP_PERMANENT);
    1961           0 :             desc.object().set(obj);
    1962           0 :             return true;
    1963             :         }
    1964             : 
    1965           0 :         if (JSID_IS_ATOM(id, cx->names().length)) {
    1966           0 :             desc.value().setInt32(typedObj->length());
    1967           0 :             desc.setAttributes(JSPROP_READONLY | JSPROP_PERMANENT);
    1968           0 :             desc.object().set(obj);
    1969           0 :             return true;
    1970             :         }
    1971           0 :         break;
    1972             :       }
    1973             : 
    1974             :       case type::Struct:
    1975             :       {
    1976           0 :         Rooted<StructTypeDescr*> descr(cx, &typedObj->typeDescr().as<StructTypeDescr>());
    1977             : 
    1978             :         size_t fieldIndex;
    1979           0 :         if (!descr->fieldIndex(id, &fieldIndex))
    1980           0 :             break;
    1981             : 
    1982           0 :         size_t offset = descr->fieldOffset(fieldIndex);
    1983           0 :         Rooted<TypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
    1984           0 :         if (!Reify(cx, fieldType, typedObj, offset, desc.value()))
    1985           0 :             return false;
    1986             : 
    1987           0 :         desc.setAttributes(JSPROP_ENUMERATE | JSPROP_PERMANENT);
    1988           0 :         desc.object().set(obj);
    1989           0 :         return true;
    1990             :       }
    1991             :     }
    1992             : 
    1993           0 :     desc.object().set(nullptr);
    1994           0 :     return true;
    1995             : }
    1996             : 
    1997             : static bool
    1998           0 : IsOwnId(JSContext* cx, HandleObject obj, HandleId id)
    1999             : {
    2000             :     uint32_t index;
    2001           0 :     Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
    2002           0 :     switch (typedObj->typeDescr().kind()) {
    2003             :       case type::Scalar:
    2004             :       case type::Reference:
    2005             :       case type::Simd:
    2006           0 :         return false;
    2007             : 
    2008             :       case type::Array:
    2009           0 :         return IdIsIndex(id, &index) || JSID_IS_ATOM(id, cx->names().length);
    2010             : 
    2011             :       case type::Struct:
    2012             :         size_t index;
    2013           0 :         if (typedObj->typeDescr().as<StructTypeDescr>().fieldIndex(id, &index))
    2014           0 :             return true;
    2015             :     }
    2016             : 
    2017           0 :     return false;
    2018             : }
    2019             : 
    2020             : bool
    2021           0 : TypedObject::obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
    2022             : {
    2023           0 :     if (IsOwnId(cx, obj, id))
    2024           0 :         return ReportPropertyError(cx, JSMSG_CANT_DELETE, id);
    2025             : 
    2026           0 :     RootedObject proto(cx, obj->staticPrototype());
    2027           0 :     if (!proto)
    2028           0 :         return result.succeed();
    2029             : 
    2030           0 :     return DeleteProperty(cx, proto, id, result);
    2031             : }
    2032             : 
    2033             : bool
    2034           0 : TypedObject::obj_newEnumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
    2035             :                               bool enumerableOnly)
    2036             : {
    2037           0 :     MOZ_ASSERT(obj->is<TypedObject>());
    2038           0 :     Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
    2039           0 :     Rooted<TypeDescr*> descr(cx, &typedObj->typeDescr());
    2040             : 
    2041           0 :     RootedId id(cx);
    2042           0 :     switch (descr->kind()) {
    2043             :       case type::Scalar:
    2044             :       case type::Reference:
    2045             :       case type::Simd: {
    2046             :         // Nothing to enumerate.
    2047           0 :         break;
    2048             :       }
    2049             : 
    2050             :       case type::Array: {
    2051           0 :         if (!properties.reserve(typedObj->length()))
    2052           0 :             return false;
    2053             : 
    2054           0 :         for (uint32_t index = 0; index < typedObj->length(); index++) {
    2055           0 :             id = INT_TO_JSID(index);
    2056           0 :             properties.infallibleAppend(id);
    2057             :         }
    2058           0 :         break;
    2059             :       }
    2060             : 
    2061             :       case type::Struct: {
    2062           0 :         size_t fieldCount = descr->as<StructTypeDescr>().fieldCount();
    2063           0 :         if (!properties.reserve(fieldCount))
    2064           0 :             return false;
    2065             : 
    2066           0 :         for (size_t index = 0; index < fieldCount; index++) {
    2067           0 :             id = AtomToId(&descr->as<StructTypeDescr>().fieldName(index));
    2068           0 :             properties.infallibleAppend(id);
    2069             :         }
    2070           0 :         break;
    2071             :       }
    2072             :     }
    2073             : 
    2074           0 :     return true;
    2075             : }
    2076             : 
    2077             : void
    2078           0 : OutlineTypedObject::notifyBufferDetached(void* newData)
    2079             : {
    2080           0 :     setData(reinterpret_cast<uint8_t*>(newData));
    2081           0 : }
    2082             : 
    2083             : /******************************************************************************
    2084             :  * Inline typed objects
    2085             :  */
    2086             : 
    2087             : /* static */ InlineTypedObject*
    2088           0 : InlineTypedObject::create(JSContext* cx, HandleTypeDescr descr, gc::InitialHeap heap)
    2089             : {
    2090           0 :     gc::AllocKind allocKind = allocKindForTypeDescriptor(descr);
    2091             : 
    2092           0 :     const Class* clasp = descr->opaque()
    2093           0 :                          ? &InlineOpaqueTypedObject::class_
    2094           0 :                          : &InlineTransparentTypedObject::class_;
    2095             : 
    2096           0 :     RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp,
    2097           0 :                                                              TaggedProto(&descr->typedProto()),
    2098           0 :                                                              descr));
    2099           0 :     if (!group)
    2100           0 :         return nullptr;
    2101             : 
    2102           0 :     NewObjectKind newKind = (heap == gc::TenuredHeap) ? TenuredObject : GenericObject;
    2103           0 :     return NewObjectWithGroup<InlineTypedObject>(cx, group, allocKind, newKind);
    2104             : }
    2105             : 
    2106             : /* static */ InlineTypedObject*
    2107           0 : InlineTypedObject::createCopy(JSContext* cx, Handle<InlineTypedObject*> templateObject,
    2108             :                               gc::InitialHeap heap)
    2109             : {
    2110           0 :     AutoSetNewObjectMetadata metadata(cx);
    2111             : 
    2112           0 :     Rooted<TypeDescr*> descr(cx, &templateObject->typeDescr());
    2113           0 :     InlineTypedObject* res = create(cx, descr, heap);
    2114           0 :     if (!res)
    2115           0 :         return nullptr;
    2116             : 
    2117           0 :     memcpy(res->inlineTypedMem(), templateObject->inlineTypedMem(), templateObject->size());
    2118           0 :     return res;
    2119             : }
    2120             : 
    2121             : /* static */ void
    2122           0 : InlineTypedObject::obj_trace(JSTracer* trc, JSObject* object)
    2123             : {
    2124           0 :     InlineTypedObject& typedObj = object->as<InlineTypedObject>();
    2125             : 
    2126           0 :     TraceEdge(trc, &typedObj.shape_, "InlineTypedObject_shape");
    2127             : 
    2128             :     // Inline transparent objects do not have references and do not need more
    2129             :     // tracing. If there is an entry in the compartment's LazyArrayBufferTable,
    2130             :     // tracing that reference will be taken care of by the table itself.
    2131           0 :     if (typedObj.is<InlineTransparentTypedObject>())
    2132           0 :         return;
    2133             : 
    2134           0 :     typedObj.typeDescr().traceInstances(trc, typedObj.inlineTypedMem(), 1);
    2135             : }
    2136             : 
    2137             : /* static */ void
    2138           0 : InlineTypedObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src)
    2139             : {
    2140             :     // Inline typed object element arrays can be preserved on the stack by Ion
    2141             :     // and need forwarding pointers created during a minor GC. We can't do this
    2142             :     // in the trace hook because we don't have any stale data to determine
    2143             :     // whether this object moved and where it was moved from.
    2144           0 :     TypeDescr& descr = dst->as<InlineTypedObject>().typeDescr();
    2145           0 :     if (descr.kind() == type::Array) {
    2146             :         // The forwarding pointer can be direct as long as there is enough
    2147             :         // space for it. Other objects might point into the object's buffer,
    2148             :         // but they will not set any direct forwarding pointers.
    2149           0 :         uint8_t* oldData = reinterpret_cast<uint8_t*>(src) + offsetOfDataStart();
    2150           0 :         uint8_t* newData = dst->as<InlineTypedObject>().inlineTypedMem();
    2151           0 :         dst->zone()->group()->nursery().maybeSetForwardingPointer(trc, oldData, newData,
    2152           0 :                                                                   descr.size() >= sizeof(uintptr_t));
    2153             :     }
    2154           0 : }
    2155             : 
    2156             : ArrayBufferObject*
    2157           0 : InlineTransparentTypedObject::getOrCreateBuffer(JSContext* cx)
    2158             : {
    2159           0 :     ObjectWeakMap*& table = cx->compartment()->lazyArrayBuffers;
    2160           0 :     if (!table) {
    2161           0 :         table = cx->new_<ObjectWeakMap>(cx);
    2162           0 :         if (!table || !table->init())
    2163           0 :             return nullptr;
    2164             :     }
    2165             : 
    2166           0 :     JSObject* obj = table->lookup(this);
    2167           0 :     if (obj)
    2168           0 :         return &obj->as<ArrayBufferObject>();
    2169             : 
    2170             :     ArrayBufferObject::BufferContents contents =
    2171           0 :         ArrayBufferObject::BufferContents::createPlain(inlineTypedMem());
    2172           0 :     size_t nbytes = typeDescr().size();
    2173             : 
    2174             :     // Prevent GC under ArrayBufferObject::create, which might move this object
    2175             :     // and its contents.
    2176           0 :     gc::AutoSuppressGC suppress(cx);
    2177             : 
    2178             :     ArrayBufferObject* buffer =
    2179           0 :         ArrayBufferObject::create(cx, nbytes, contents, ArrayBufferObject::DoesntOwnData);
    2180           0 :     if (!buffer)
    2181           0 :         return nullptr;
    2182             : 
    2183             :     // The owning object must always be the array buffer's first view. This
    2184             :     // both prevents the memory from disappearing out from under the buffer
    2185             :     // (the first view is held strongly by the buffer) and is used by the
    2186             :     // buffer marking code to detect whether its data pointer needs to be
    2187             :     // relocated.
    2188           0 :     JS_ALWAYS_TRUE(buffer->addView(cx, this));
    2189             : 
    2190           0 :     buffer->setForInlineTypedObject();
    2191           0 :     buffer->setHasTypedObjectViews();
    2192             : 
    2193           0 :     if (!table->add(cx, this, buffer))
    2194           0 :         return nullptr;
    2195             : 
    2196           0 :     if (IsInsideNursery(this)) {
    2197             :         // Make sure the buffer is traced by the next generational collection,
    2198             :         // so that its data pointer is updated after this typed object moves.
    2199           0 :         zone()->group()->storeBuffer().putWholeCell(buffer);
    2200             :     }
    2201             : 
    2202           0 :     return buffer;
    2203             : }
    2204             : 
    2205             : ArrayBufferObject*
    2206           0 : OutlineTransparentTypedObject::getOrCreateBuffer(JSContext* cx)
    2207             : {
    2208           0 :     if (owner().is<ArrayBufferObject>())
    2209           0 :         return &owner().as<ArrayBufferObject>();
    2210           0 :     return owner().as<InlineTransparentTypedObject>().getOrCreateBuffer(cx);
    2211             : }
    2212             : 
    2213             : /******************************************************************************
    2214             :  * Typed object classes
    2215             :  */
    2216             : 
    2217             : const ObjectOps TypedObject::objectOps_ = {
    2218             :     TypedObject::obj_lookupProperty,
    2219             :     TypedObject::obj_defineProperty,
    2220             :     TypedObject::obj_hasProperty,
    2221             :     TypedObject::obj_getProperty,
    2222             :     TypedObject::obj_setProperty,
    2223             :     TypedObject::obj_getOwnPropertyDescriptor,
    2224             :     TypedObject::obj_deleteProperty,
    2225             :     nullptr, nullptr, /* watch/unwatch */
    2226             :     nullptr,   /* getElements */
    2227             :     nullptr, /* thisValue */
    2228             : };
    2229             : 
    2230             : #define DEFINE_TYPEDOBJ_CLASS(Name, Trace, flag)         \
    2231             :     static const ClassOps Name##ClassOps = {             \
    2232             :         nullptr,        /* addProperty */                \
    2233             :         nullptr,        /* delProperty */                \
    2234             :         nullptr,        /* getProperty */                \
    2235             :         nullptr,        /* setProperty */                \
    2236             :         nullptr,        /* enumerate   */                \
    2237             :         TypedObject::obj_newEnumerate,                   \
    2238             :         nullptr,        /* resolve     */                \
    2239             :         nullptr,        /* mayResolve  */                \
    2240             :         nullptr,        /* finalize    */                \
    2241             :         nullptr,        /* call        */                \
    2242             :         nullptr,        /* hasInstance */                \
    2243             :         nullptr,        /* construct   */                \
    2244             :         Trace,                                           \
    2245             :     };                                                   \
    2246             :     const Class Name::class_ = {                         \
    2247             :         # Name,                                          \
    2248             :         Class::NON_NATIVE | flag,                        \
    2249             :         &Name##ClassOps,                                 \
    2250             :         JS_NULL_CLASS_SPEC,                              \
    2251             :         JS_NULL_CLASS_EXT,                               \
    2252             :         &TypedObject::objectOps_                         \
    2253             :     }
    2254             : 
    2255             : DEFINE_TYPEDOBJ_CLASS(OutlineTransparentTypedObject, OutlineTypedObject::obj_trace, 0);
    2256             : DEFINE_TYPEDOBJ_CLASS(OutlineOpaqueTypedObject,      OutlineTypedObject::obj_trace, 0);
    2257             : DEFINE_TYPEDOBJ_CLASS(InlineTransparentTypedObject,  InlineTypedObject::obj_trace,
    2258             :                       JSCLASS_DELAY_METADATA_BUILDER);
    2259             : DEFINE_TYPEDOBJ_CLASS(InlineOpaqueTypedObject,       InlineTypedObject::obj_trace,
    2260             :                       JSCLASS_DELAY_METADATA_BUILDER);
    2261             : 
    2262             : static int32_t
    2263           0 : LengthForType(TypeDescr& descr)
    2264             : {
    2265           0 :     switch (descr.kind()) {
    2266             :       case type::Scalar:
    2267             :       case type::Reference:
    2268             :       case type::Struct:
    2269             :       case type::Simd:
    2270           0 :         return 0;
    2271             : 
    2272             :       case type::Array:
    2273           0 :         return descr.as<ArrayTypeDescr>().length();
    2274             :     }
    2275             : 
    2276           0 :     MOZ_CRASH("Invalid kind");
    2277             : }
    2278             : 
    2279             : static bool
    2280           0 : CheckOffset(uint32_t offset, uint32_t size, uint32_t alignment, uint32_t bufferLength)
    2281             : {
    2282             :     // Offset (plus size) must be fully contained within the buffer.
    2283           0 :     if (offset > bufferLength)
    2284           0 :         return false;
    2285           0 :     if (offset + size < offset)
    2286           0 :         return false;
    2287           0 :     if (offset + size > bufferLength)
    2288           0 :         return false;
    2289             : 
    2290             :     // Offset must be aligned.
    2291           0 :     if ((offset % alignment) != 0)
    2292           0 :         return false;
    2293             : 
    2294           0 :     return true;
    2295             : }
    2296             : 
    2297             : template<typename T, typename U, typename V, typename W>
    2298             : inline bool CheckOffset(T, U, V, W) = delete;
    2299             : 
    2300             : /*static*/ bool
    2301           0 : TypedObject::construct(JSContext* cx, unsigned int argc, Value* vp)
    2302             : {
    2303           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2304             : 
    2305           0 :     MOZ_ASSERT(args.callee().is<TypeDescr>());
    2306           0 :     Rooted<TypeDescr*> callee(cx, &args.callee().as<TypeDescr>());
    2307             : 
    2308             :     // Typed object constructors are overloaded in three ways, in order of
    2309             :     // precedence:
    2310             :     //
    2311             :     //   new TypeObj()
    2312             :     //   new TypeObj(buffer, [offset])
    2313             :     //   new TypeObj(data)
    2314             : 
    2315             :     // Zero argument constructor:
    2316           0 :     if (args.length() == 0) {
    2317           0 :         int32_t length = LengthForType(*callee);
    2318           0 :         Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
    2319           0 :         if (!obj)
    2320           0 :             return false;
    2321           0 :         args.rval().setObject(*obj);
    2322           0 :         return true;
    2323             :     }
    2324             : 
    2325             :     // Buffer constructor.
    2326           0 :     if (args[0].isObject() && args[0].toObject().is<ArrayBufferObject>()) {
    2327           0 :         Rooted<ArrayBufferObject*> buffer(cx);
    2328           0 :         buffer = &args[0].toObject().as<ArrayBufferObject>();
    2329             : 
    2330           0 :         if (callee->opaque() || buffer->isDetached()) {
    2331           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
    2332           0 :             return false;
    2333             :         }
    2334             : 
    2335             :         uint32_t offset;
    2336           0 :         if (args.length() >= 2 && !args[1].isUndefined()) {
    2337           0 :             if (!args[1].isInt32() || args[1].toInt32() < 0) {
    2338           0 :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
    2339           0 :                 return false;
    2340             :             }
    2341             : 
    2342           0 :             offset = args[1].toInt32();
    2343             :         } else {
    2344           0 :             offset = 0;
    2345             :         }
    2346             : 
    2347           0 :         if (args.length() >= 3 && !args[2].isUndefined()) {
    2348           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
    2349           0 :             return false;
    2350             :         }
    2351             : 
    2352           0 :         if (!CheckOffset(offset, callee->size(), callee->alignment(),
    2353           0 :                          buffer->byteLength()))
    2354             :         {
    2355           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
    2356           0 :             return false;
    2357             :         }
    2358             : 
    2359           0 :         Rooted<OutlineTypedObject*> obj(cx);
    2360           0 :         obj = OutlineTypedObject::createUnattached(cx, callee, LengthForType(*callee));
    2361           0 :         if (!obj)
    2362           0 :             return false;
    2363             : 
    2364           0 :         obj->attach(cx, *buffer, offset);
    2365           0 :         args.rval().setObject(*obj);
    2366           0 :         return true;
    2367             :     }
    2368             : 
    2369             :     // Data constructor.
    2370           0 :     if (args[0].isObject()) {
    2371             :         // Create the typed object.
    2372           0 :         int32_t length = LengthForType(*callee);
    2373           0 :         Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
    2374           0 :         if (!obj)
    2375           0 :             return false;
    2376             : 
    2377             :         // Initialize from `arg`.
    2378           0 :         if (!ConvertAndCopyTo(cx, obj, args[0]))
    2379           0 :             return false;
    2380           0 :         args.rval().setObject(*obj);
    2381           0 :         return true;
    2382             :     }
    2383             : 
    2384             :     // Something bogus.
    2385           0 :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
    2386           0 :     return false;
    2387             : }
    2388             : 
    2389             : /* static */ JS::Result<TypedObject*, JS::OOM&>
    2390           0 : TypedObject::create(JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
    2391             :                     js::HandleShape shape, js::HandleObjectGroup group)
    2392             : {
    2393           0 :     debugCheckNewObject(group, shape, kind, heap);
    2394             : 
    2395           0 :     const js::Class* clasp = group->clasp();
    2396           0 :     MOZ_ASSERT(::IsTypedObjectClass(clasp));
    2397             : 
    2398           0 :     JSObject* obj = js::Allocate<JSObject>(cx, kind, /* nDynamicSlots = */ 0, heap, clasp);
    2399           0 :     if (!obj)
    2400           0 :         return cx->alreadyReportedOOM();
    2401             : 
    2402           0 :     TypedObject* tobj = static_cast<TypedObject*>(obj);
    2403           0 :     tobj->group_.init(group);
    2404           0 :     tobj->initShape(shape);
    2405             : 
    2406           0 :     tobj->setInitialElementsMaybeNonNative(js::emptyObjectElements);
    2407             : 
    2408           0 :     if (clasp->shouldDelayMetadataBuilder())
    2409           0 :         cx->compartment()->setObjectPendingMetadata(cx, tobj);
    2410             :     else
    2411           0 :         tobj = SetNewObjectMetadata(cx, tobj);
    2412             : 
    2413           0 :     js::gc::TraceCreateObject(tobj);
    2414             : 
    2415           0 :     return tobj;
    2416             : }
    2417             : 
    2418             : /******************************************************************************
    2419             :  * Intrinsics
    2420             :  */
    2421             : 
    2422             : bool
    2423           0 : js::NewOpaqueTypedObject(JSContext* cx, unsigned argc, Value* vp)
    2424             : {
    2425           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2426           0 :     MOZ_ASSERT(args.length() == 1);
    2427           0 :     MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypeDescr>());
    2428             : 
    2429           0 :     Rooted<TypeDescr*> descr(cx, &args[0].toObject().as<TypeDescr>());
    2430           0 :     int32_t length = TypedObjLengthFromType(*descr);
    2431           0 :     Rooted<OutlineTypedObject*> obj(cx);
    2432           0 :     obj = OutlineTypedObject::createUnattachedWithClass(cx, &OutlineOpaqueTypedObject::class_, descr, length);
    2433           0 :     if (!obj)
    2434           0 :         return false;
    2435           0 :     args.rval().setObject(*obj);
    2436           0 :     return true;
    2437             : }
    2438             : 
    2439             : bool
    2440           0 : js::NewDerivedTypedObject(JSContext* cx, unsigned argc, Value* vp)
    2441             : {
    2442           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2443           0 :     MOZ_ASSERT(args.length() == 3);
    2444           0 :     MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypeDescr>());
    2445           0 :     MOZ_ASSERT(args[1].isObject() && args[1].toObject().is<TypedObject>());
    2446           0 :     MOZ_ASSERT(args[2].isInt32());
    2447             : 
    2448           0 :     Rooted<TypeDescr*> descr(cx, &args[0].toObject().as<TypeDescr>());
    2449           0 :     Rooted<TypedObject*> typedObj(cx, &args[1].toObject().as<TypedObject>());
    2450           0 :     uint32_t offset = AssertedCast<uint32_t>(args[2].toInt32());
    2451             : 
    2452           0 :     Rooted<TypedObject*> obj(cx);
    2453           0 :     obj = OutlineTypedObject::createDerived(cx, descr, typedObj, offset);
    2454           0 :     if (!obj)
    2455           0 :         return false;
    2456             : 
    2457           0 :     args.rval().setObject(*obj);
    2458           0 :     return true;
    2459             : }
    2460             : 
    2461             : bool
    2462           0 : js::AttachTypedObject(JSContext* cx, unsigned argc, Value* vp)
    2463             : {
    2464           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2465           0 :     MOZ_ASSERT(args.length() == 3);
    2466           0 :     MOZ_ASSERT(args[2].isInt32());
    2467             : 
    2468           0 :     OutlineTypedObject& handle = args[0].toObject().as<OutlineTypedObject>();
    2469           0 :     TypedObject& target = args[1].toObject().as<TypedObject>();
    2470           0 :     MOZ_ASSERT(!handle.isAttached());
    2471           0 :     uint32_t offset = AssertedCast<uint32_t>(args[2].toInt32());
    2472             : 
    2473           0 :     handle.attach(cx, target, offset);
    2474             : 
    2475           0 :     return true;
    2476             : }
    2477             : 
    2478             : bool
    2479           0 : js::SetTypedObjectOffset(JSContext*, unsigned argc, Value* vp)
    2480             : {
    2481           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2482           0 :     MOZ_ASSERT(args.length() == 2);
    2483           0 :     MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>());
    2484           0 :     MOZ_ASSERT(args[1].isInt32());
    2485             : 
    2486           0 :     OutlineTypedObject& typedObj = args[0].toObject().as<OutlineTypedObject>();
    2487           0 :     int32_t offset = args[1].toInt32();
    2488             : 
    2489           0 :     MOZ_ASSERT(typedObj.isAttached());
    2490           0 :     typedObj.resetOffset(offset);
    2491           0 :     args.rval().setUndefined();
    2492           0 :     return true;
    2493             : }
    2494             : 
    2495             : bool
    2496           0 : js::ObjectIsTypeDescr(JSContext*, unsigned argc, Value* vp)
    2497             : {
    2498           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2499           0 :     MOZ_ASSERT(args.length() == 1);
    2500           0 :     MOZ_ASSERT(args[0].isObject());
    2501           0 :     args.rval().setBoolean(args[0].toObject().is<TypeDescr>());
    2502           0 :     return true;
    2503             : }
    2504             : 
    2505             : bool
    2506           0 : js::ObjectIsTypedObject(JSContext*, unsigned argc, Value* vp)
    2507             : {
    2508           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2509           0 :     MOZ_ASSERT(args.length() == 1);
    2510           0 :     MOZ_ASSERT(args[0].isObject());
    2511           0 :     args.rval().setBoolean(args[0].toObject().is<TypedObject>());
    2512           0 :     return true;
    2513             : }
    2514             : 
    2515             : bool
    2516           0 : js::ObjectIsOpaqueTypedObject(JSContext*, unsigned argc, Value* vp)
    2517             : {
    2518           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2519           0 :     MOZ_ASSERT(args.length() == 1);
    2520           0 :     JSObject& obj = args[0].toObject();
    2521           0 :     args.rval().setBoolean(obj.is<TypedObject>() && obj.as<TypedObject>().opaque());
    2522           0 :     return true;
    2523             : }
    2524             : 
    2525             : bool
    2526           0 : js::ObjectIsTransparentTypedObject(JSContext*, unsigned argc, Value* vp)
    2527             : {
    2528           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2529           0 :     MOZ_ASSERT(args.length() == 1);
    2530           0 :     JSObject& obj = args[0].toObject();
    2531           0 :     args.rval().setBoolean(obj.is<TypedObject>() && !obj.as<TypedObject>().opaque());
    2532           0 :     return true;
    2533             : }
    2534             : 
    2535             : bool
    2536           0 : js::TypeDescrIsSimpleType(JSContext*, unsigned argc, Value* vp)
    2537             : {
    2538           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2539           0 :     MOZ_ASSERT(args.length() == 1);
    2540           0 :     MOZ_ASSERT(args[0].isObject());
    2541           0 :     MOZ_ASSERT(args[0].toObject().is<js::TypeDescr>());
    2542           0 :     args.rval().setBoolean(args[0].toObject().is<js::SimpleTypeDescr>());
    2543           0 :     return true;
    2544             : }
    2545             : 
    2546             : bool
    2547           0 : js::TypeDescrIsArrayType(JSContext*, unsigned argc, Value* vp)
    2548             : {
    2549           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2550           0 :     MOZ_ASSERT(args.length() == 1);
    2551           0 :     MOZ_ASSERT(args[0].isObject());
    2552           0 :     MOZ_ASSERT(args[0].toObject().is<js::TypeDescr>());
    2553           0 :     JSObject& obj = args[0].toObject();
    2554           0 :     args.rval().setBoolean(obj.is<js::ArrayTypeDescr>());
    2555           0 :     return true;
    2556             : }
    2557             : 
    2558             : bool
    2559           0 : js::TypedObjectIsAttached(JSContext* cx, unsigned argc, Value* vp)
    2560             : {
    2561           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2562           0 :     TypedObject& typedObj = args[0].toObject().as<TypedObject>();
    2563           0 :     args.rval().setBoolean(typedObj.isAttached());
    2564           0 :     return true;
    2565             : }
    2566             : 
    2567             : bool
    2568           0 : js::TypedObjectTypeDescr(JSContext* cx, unsigned argc, Value* vp)
    2569             : {
    2570           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2571           0 :     TypedObject& typedObj = args[0].toObject().as<TypedObject>();
    2572           0 :     args.rval().setObject(typedObj.typeDescr());
    2573           0 :     return true;
    2574             : }
    2575             : 
    2576             : bool
    2577           0 : js::ClampToUint8(JSContext*, unsigned argc, Value* vp)
    2578             : {
    2579           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2580           0 :     MOZ_ASSERT(args.length() == 1);
    2581           0 :     MOZ_ASSERT(args[0].isNumber());
    2582           0 :     args.rval().setNumber(ClampDoubleToUint8(args[0].toNumber()));
    2583           0 :     return true;
    2584             : }
    2585             : 
    2586             : bool
    2587           0 : js::GetTypedObjectModule(JSContext* cx, unsigned argc, Value* vp)
    2588             : {
    2589           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2590           0 :     Rooted<GlobalObject*> global(cx, cx->global());
    2591           0 :     MOZ_ASSERT(global);
    2592           0 :     args.rval().setObject(global->getTypedObjectModule());
    2593           0 :     return true;
    2594             : }
    2595             : 
    2596             : bool
    2597           0 : js::GetSimdTypeDescr(JSContext* cx, unsigned argc, Value* vp)
    2598             : {
    2599           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    2600           0 :     MOZ_ASSERT(args.length() == 1);
    2601           0 :     MOZ_ASSERT(args[0].isInt32());
    2602             :     // One of the JS_SIMDTYPEREPR_* constants / a SimdType enum value.
    2603             :     // getOrCreateSimdTypeDescr() will do the range check.
    2604           0 :     int32_t simdTypeRepr = args[0].toInt32();
    2605           0 :     Rooted<GlobalObject*> global(cx, cx->global());
    2606           0 :     MOZ_ASSERT(global);
    2607           0 :     auto* obj = GlobalObject::getOrCreateSimdTypeDescr(cx, global, SimdType(simdTypeRepr));
    2608           0 :     args.rval().setObject(*obj);
    2609           0 :     return true;
    2610             : }
    2611             : 
    2612             : #define JS_STORE_SCALAR_CLASS_IMPL(_constant, T, _name)                         \
    2613             : bool                                                                            \
    2614             : js::StoreScalar##T::Func(JSContext* cx, unsigned argc, Value* vp)               \
    2615             : {                                                                               \
    2616             :     CallArgs args = CallArgsFromVp(argc, vp);                                   \
    2617             :     MOZ_ASSERT(args.length() == 3);                                             \
    2618             :     MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>());     \
    2619             :     MOZ_ASSERT(args[1].isInt32());                                              \
    2620             :     MOZ_ASSERT(args[2].isNumber());                                             \
    2621             :                                                                                 \
    2622             :     TypedObject& typedObj = args[0].toObject().as<TypedObject>();               \
    2623             :     int32_t offset = args[1].toInt32();                                         \
    2624             :                                                                                 \
    2625             :     /* Should be guaranteed by the typed objects API: */                        \
    2626             :     MOZ_ASSERT(offset % MOZ_ALIGNOF(T) == 0);                                   \
    2627             :                                                                                 \
    2628             :     JS::AutoCheckCannotGC nogc(cx);                                             \
    2629             :     T* target = reinterpret_cast<T*>(typedObj.typedMem(offset, nogc));          \
    2630             :     double d = args[2].toNumber();                                              \
    2631             :     *target = ConvertScalar<T>(d);                                              \
    2632             :     args.rval().setUndefined();                                                 \
    2633             :     return true;                                                                \
    2634             : }
    2635             : 
    2636             : #define JS_STORE_REFERENCE_CLASS_IMPL(_constant, T, _name)                      \
    2637             : bool                                                                            \
    2638             : js::StoreReference##_name::Func(JSContext* cx, unsigned argc, Value* vp)        \
    2639             : {                                                                               \
    2640             :     CallArgs args = CallArgsFromVp(argc, vp);                                   \
    2641             :     MOZ_ASSERT(args.length() == 4);                                             \
    2642             :     MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>());     \
    2643             :     MOZ_ASSERT(args[1].isInt32());                                              \
    2644             :     MOZ_ASSERT(args[2].isString() || args[2].isNull());                         \
    2645             :                                                                                 \
    2646             :     TypedObject& typedObj = args[0].toObject().as<TypedObject>();               \
    2647             :     int32_t offset = args[1].toInt32();                                         \
    2648             :                                                                                 \
    2649             :     jsid id = args[2].isString()                                                \
    2650             :               ? IdToTypeId(AtomToId(&args[2].toString()->asAtom()))             \
    2651             :               : JSID_VOID;                                                      \
    2652             :                                                                                 \
    2653             :     /* Should be guaranteed by the typed objects API: */                        \
    2654             :     MOZ_ASSERT(offset % MOZ_ALIGNOF(T) == 0);                                   \
    2655             :                                                                                 \
    2656             :     JS::AutoCheckCannotGC nogc(cx);                                             \
    2657             :     T* target = reinterpret_cast<T*>(typedObj.typedMem(offset, nogc));          \
    2658             :     if (!store(cx, target, args[3], &typedObj, id))                             \
    2659             :         return false;                                                           \
    2660             :     args.rval().setUndefined();                                                 \
    2661             :     return true;                                                                \
    2662             : }
    2663             : 
    2664             : #define JS_LOAD_SCALAR_CLASS_IMPL(_constant, T, _name)                                  \
    2665             : bool                                                                                    \
    2666             : js::LoadScalar##T::Func(JSContext* cx, unsigned argc, Value* vp)                        \
    2667             : {                                                                                       \
    2668             :     CallArgs args = CallArgsFromVp(argc, vp);                                           \
    2669             :     MOZ_ASSERT(args.length() == 2);                                                     \
    2670             :     MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>());             \
    2671             :     MOZ_ASSERT(args[1].isInt32());                                                      \
    2672             :                                                                                         \
    2673             :     TypedObject& typedObj = args[0].toObject().as<TypedObject>();                       \
    2674             :     int32_t offset = args[1].toInt32();                                                 \
    2675             :                                                                                         \
    2676             :     /* Should be guaranteed by the typed objects API: */                                \
    2677             :     MOZ_ASSERT(offset % MOZ_ALIGNOF(T) == 0);                                           \
    2678             :                                                                                         \
    2679             :     JS::AutoCheckCannotGC nogc(cx);                                                     \
    2680             :     T* target = reinterpret_cast<T*>(typedObj.typedMem(offset, nogc));                  \
    2681             :     args.rval().setNumber((double) *target);                                            \
    2682             :     return true;                                                                        \
    2683             : }
    2684             : 
    2685             : #define JS_LOAD_REFERENCE_CLASS_IMPL(_constant, T, _name)                       \
    2686             : bool                                                                            \
    2687             : js::LoadReference##_name::Func(JSContext* cx, unsigned argc, Value* vp)         \
    2688             : {                                                                               \
    2689             :     CallArgs args = CallArgsFromVp(argc, vp);                                   \
    2690             :     MOZ_ASSERT(args.length() == 2);                                             \
    2691             :     MOZ_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>());     \
    2692             :     MOZ_ASSERT(args[1].isInt32());                                              \
    2693             :                                                                                 \
    2694             :     TypedObject& typedObj = args[0].toObject().as<TypedObject>();               \
    2695             :     int32_t offset = args[1].toInt32();                                         \
    2696             :                                                                                 \
    2697             :     /* Should be guaranteed by the typed objects API: */                        \
    2698             :     MOZ_ASSERT(offset % MOZ_ALIGNOF(T) == 0);                                   \
    2699             :                                                                                 \
    2700             :     JS::AutoCheckCannotGC nogc(cx);                                             \
    2701             :     T* target = reinterpret_cast<T*>(typedObj.typedMem(offset, nogc));          \
    2702             :     load(target, args.rval());                                                  \
    2703             :     return true;                                                                \
    2704             : }
    2705             : 
    2706             : // Because the precise syntax for storing values/objects/strings
    2707             : // differs, we abstract it away using specialized variants of the
    2708             : // private methods `store()` and `load()`.
    2709             : 
    2710             : bool
    2711           0 : StoreReferenceAny::store(JSContext* cx, GCPtrValue* heap, const Value& v,
    2712             :                          TypedObject* obj, jsid id)
    2713             : {
    2714             :     // Undefined values are not included in type inference information for
    2715             :     // value properties of typed objects, as these properties are always
    2716             :     // considered to contain undefined.
    2717           0 :     if (!v.isUndefined()) {
    2718           0 :         if (!cx->helperThread())
    2719           0 :             AddTypePropertyId(cx, obj, id, v);
    2720           0 :         else if (!HasTypePropertyId(obj, id, v))
    2721           0 :             return false;
    2722             :     }
    2723             : 
    2724           0 :     *heap = v;
    2725           0 :     return true;
    2726             : }
    2727             : 
    2728             : bool
    2729           0 : StoreReferenceObject::store(JSContext* cx, GCPtrObject* heap, const Value& v,
    2730             :                             TypedObject* obj, jsid id)
    2731             : {
    2732           0 :     MOZ_ASSERT(v.isObjectOrNull()); // or else Store_object is being misused
    2733             : 
    2734             :     // Null pointers are not included in type inference information for
    2735             :     // object properties of typed objects, as these properties are always
    2736             :     // considered to contain null.
    2737           0 :     if (v.isObject()) {
    2738           0 :         if (!cx->helperThread())
    2739           0 :             AddTypePropertyId(cx, obj, id, v);
    2740           0 :         else if (!HasTypePropertyId(obj, id, v))
    2741           0 :             return false;
    2742             :     }
    2743             : 
    2744           0 :     *heap = v.toObjectOrNull();
    2745           0 :     return true;
    2746             : }
    2747             : 
    2748             : bool
    2749           0 : StoreReferencestring::store(JSContext* cx, GCPtrString* heap, const Value& v,
    2750             :                             TypedObject* obj, jsid id)
    2751             : {
    2752           0 :     MOZ_ASSERT(v.isString()); // or else Store_string is being misused
    2753             : 
    2754             :     // Note: string references are not reflected in type information for the object.
    2755           0 :     *heap = v.toString();
    2756             : 
    2757           0 :     return true;
    2758             : }
    2759             : 
    2760             : void
    2761           0 : LoadReferenceAny::load(GCPtrValue* heap, MutableHandleValue v)
    2762             : {
    2763           0 :     v.set(*heap);
    2764           0 : }
    2765             : 
    2766             : void
    2767           0 : LoadReferenceObject::load(GCPtrObject* heap, MutableHandleValue v)
    2768             : {
    2769           0 :     if (*heap)
    2770           0 :         v.setObject(**heap);
    2771             :     else
    2772           0 :         v.setNull();
    2773           0 : }
    2774             : 
    2775             : void
    2776           0 : LoadReferencestring::load(GCPtrString* heap, MutableHandleValue v)
    2777             : {
    2778           0 :     v.setString(*heap);
    2779           0 : }
    2780             : 
    2781             : // I was using templates for this stuff instead of macros, but ran
    2782             : // into problems with the Unagi compiler.
    2783           0 : JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(JS_STORE_SCALAR_CLASS_IMPL)
    2784           0 : JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(JS_LOAD_SCALAR_CLASS_IMPL)
    2785           0 : JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_STORE_REFERENCE_CLASS_IMPL)
    2786           0 : JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_LOAD_REFERENCE_CLASS_IMPL)
    2787             : 
    2788             : ///////////////////////////////////////////////////////////////////////////
    2789             : // Walking memory
    2790             : 
    2791             : template<typename V>
    2792             : static void
    2793          18 : visitReferences(TypeDescr& descr,
    2794             :                 uint8_t* mem,
    2795             :                 V& visitor)
    2796             : {
    2797          18 :     if (descr.transparent())
    2798           0 :         return;
    2799             : 
    2800          18 :     switch (descr.kind()) {
    2801             :       case type::Scalar:
    2802             :       case type::Simd:
    2803           0 :         return;
    2804             : 
    2805             :       case type::Reference:
    2806          18 :         visitor.visitReference(descr.as<ReferenceTypeDescr>(), mem);
    2807          18 :         return;
    2808             : 
    2809             :       case type::Array:
    2810             :       {
    2811           0 :         ArrayTypeDescr& arrayDescr = descr.as<ArrayTypeDescr>();
    2812           0 :         TypeDescr& elementDescr = arrayDescr.elementType();
    2813           0 :         for (uint32_t i = 0; i < arrayDescr.length(); i++) {
    2814           0 :             visitReferences(elementDescr, mem, visitor);
    2815           0 :             mem += elementDescr.size();
    2816             :         }
    2817           0 :         return;
    2818             :       }
    2819             : 
    2820             :       case type::Struct:
    2821             :       {
    2822           0 :         StructTypeDescr& structDescr = descr.as<StructTypeDescr>();
    2823           0 :         for (size_t i = 0; i < structDescr.fieldCount(); i++) {
    2824           0 :             TypeDescr& descr = structDescr.fieldDescr(i);
    2825           0 :             size_t offset = structDescr.fieldOffset(i);
    2826           0 :             visitReferences(descr, mem + offset, visitor);
    2827             :         }
    2828           0 :         return;
    2829             :       }
    2830             :     }
    2831             : 
    2832           0 :     MOZ_CRASH("Invalid type repr kind");
    2833             : }
    2834             : 
    2835             : ///////////////////////////////////////////////////////////////////////////
    2836             : // Initializing instances
    2837             : 
    2838             : namespace {
    2839             : 
    2840             : class MemoryInitVisitor {
    2841             :     const JSRuntime* rt_;
    2842             : 
    2843             :   public:
    2844           0 :     explicit MemoryInitVisitor(const JSRuntime* rt)
    2845           0 :       : rt_(rt)
    2846           0 :     {}
    2847             : 
    2848             :     void visitReference(ReferenceTypeDescr& descr, uint8_t* mem);
    2849             : };
    2850             : 
    2851             : } // namespace
    2852             : 
    2853             : void
    2854           0 : MemoryInitVisitor::visitReference(ReferenceTypeDescr& descr, uint8_t* mem)
    2855             : {
    2856           0 :     switch (descr.type()) {
    2857             :       case ReferenceTypeDescr::TYPE_ANY:
    2858             :       {
    2859           0 :         js::GCPtrValue* heapValue = reinterpret_cast<js::GCPtrValue*>(mem);
    2860           0 :         heapValue->init(UndefinedValue());
    2861           0 :         return;
    2862             :       }
    2863             : 
    2864             :       case ReferenceTypeDescr::TYPE_OBJECT:
    2865             :       {
    2866             :         js::GCPtrObject* objectPtr =
    2867           0 :             reinterpret_cast<js::GCPtrObject*>(mem);
    2868           0 :         objectPtr->init(nullptr);
    2869           0 :         return;
    2870             :       }
    2871             : 
    2872             :       case ReferenceTypeDescr::TYPE_STRING:
    2873             :       {
    2874             :         js::GCPtrString* stringPtr =
    2875           0 :             reinterpret_cast<js::GCPtrString*>(mem);
    2876           0 :         stringPtr->init(rt_->emptyString);
    2877           0 :         return;
    2878             :       }
    2879             :     }
    2880             : 
    2881           0 :     MOZ_CRASH("Invalid kind");
    2882             : }
    2883             : 
    2884             : void
    2885           0 : TypeDescr::initInstances(const JSRuntime* rt, uint8_t* mem, size_t length)
    2886             : {
    2887           0 :     MOZ_ASSERT(length >= 1);
    2888             : 
    2889           0 :     MemoryInitVisitor visitor(rt);
    2890             : 
    2891             :     // Initialize the 0th instance
    2892           0 :     memset(mem, 0, size());
    2893           0 :     if (opaque())
    2894           0 :         visitReferences(*this, mem, visitor);
    2895             : 
    2896             :     // Stamp out N copies of later instances
    2897           0 :     uint8_t* target = mem;
    2898           0 :     for (size_t i = 1; i < length; i++) {
    2899           0 :         target += size();
    2900           0 :         memcpy(target, mem, size());
    2901             :     }
    2902           0 : }
    2903             : 
    2904             : ///////////////////////////////////////////////////////////////////////////
    2905             : // Tracing instances
    2906             : 
    2907             : namespace {
    2908             : 
    2909             : class MemoryTracingVisitor {
    2910             :     JSTracer* trace_;
    2911             : 
    2912             :   public:
    2913             : 
    2914           0 :     explicit MemoryTracingVisitor(JSTracer* trace)
    2915           0 :       : trace_(trace)
    2916           0 :     {}
    2917             : 
    2918             :     void visitReference(ReferenceTypeDescr& descr, uint8_t* mem);
    2919             : };
    2920             : 
    2921             : } // namespace
    2922             : 
    2923             : void
    2924           0 : MemoryTracingVisitor::visitReference(ReferenceTypeDescr& descr, uint8_t* mem)
    2925             : {
    2926           0 :     switch (descr.type()) {
    2927             :       case ReferenceTypeDescr::TYPE_ANY:
    2928             :       {
    2929           0 :         GCPtrValue* heapValue = reinterpret_cast<js::GCPtrValue*>(mem);
    2930           0 :         TraceEdge(trace_, heapValue, "reference-val");
    2931           0 :         return;
    2932             :       }
    2933             : 
    2934             :       case ReferenceTypeDescr::TYPE_OBJECT:
    2935             :       {
    2936           0 :         GCPtrObject* objectPtr = reinterpret_cast<js::GCPtrObject*>(mem);
    2937           0 :         TraceNullableEdge(trace_, objectPtr, "reference-obj");
    2938           0 :         return;
    2939             :       }
    2940             : 
    2941             :       case ReferenceTypeDescr::TYPE_STRING:
    2942             :       {
    2943           0 :         GCPtrString* stringPtr = reinterpret_cast<js::GCPtrString*>(mem);
    2944           0 :         TraceNullableEdge(trace_, stringPtr, "reference-str");
    2945           0 :         return;
    2946             :       }
    2947             :     }
    2948             : 
    2949           0 :     MOZ_CRASH("Invalid kind");
    2950             : }
    2951             : 
    2952             : void
    2953           0 : TypeDescr::traceInstances(JSTracer* trace, uint8_t* mem, size_t length)
    2954             : {
    2955           0 :     MemoryTracingVisitor visitor(trace);
    2956             : 
    2957           0 :     for (size_t i = 0; i < length; i++) {
    2958           0 :         visitReferences(*this, mem, visitor);
    2959           0 :         mem += size();
    2960             :     }
    2961           0 : }
    2962             : 
    2963             : namespace {
    2964             : 
    2965          36 : struct TraceListVisitor {
    2966             :     typedef Vector<int32_t, 0, SystemAllocPolicy> VectorType;
    2967             :     VectorType stringOffsets, objectOffsets, valueOffsets;
    2968             : 
    2969             :     void visitReference(ReferenceTypeDescr& descr, uint8_t* mem);
    2970             : 
    2971             :     bool fillList(Vector<int32_t>& entries);
    2972             : };
    2973             : 
    2974             : } // namespace
    2975             : 
    2976             : void
    2977          18 : TraceListVisitor::visitReference(ReferenceTypeDescr& descr, uint8_t* mem)
    2978             : {
    2979             :     VectorType* offsets;
    2980          18 :     switch (descr.type()) {
    2981           6 :       case ReferenceTypeDescr::TYPE_ANY: offsets = &valueOffsets; break;
    2982           6 :       case ReferenceTypeDescr::TYPE_OBJECT: offsets = &objectOffsets; break;
    2983           6 :       case ReferenceTypeDescr::TYPE_STRING: offsets = &stringOffsets; break;
    2984           0 :       default: MOZ_CRASH("Invalid kind");
    2985             :     }
    2986             : 
    2987          36 :     AutoEnterOOMUnsafeRegion oomUnsafe;
    2988          18 :     if (!offsets->append((uintptr_t) mem))
    2989           0 :         oomUnsafe.crash("TraceListVisitor::visitReference");
    2990          18 : }
    2991             : 
    2992             : bool
    2993          18 : TraceListVisitor::fillList(Vector<int32_t>& entries)
    2994             : {
    2995          54 :     return entries.appendAll(stringOffsets) &&
    2996          90 :            entries.append(-1) &&
    2997          54 :            entries.appendAll(objectOffsets) &&
    2998          72 :            entries.append(-1) &&
    2999          90 :            entries.appendAll(valueOffsets) &&
    3000          72 :            entries.append(-1);
    3001             : }
    3002             : 
    3003             : static bool
    3004          72 : CreateTraceList(JSContext* cx, HandleTypeDescr descr)
    3005             : {
    3006             :     // Trace lists are only used for inline typed objects. We don't use them
    3007             :     // for larger objects, both to limit the size of the trace lists and
    3008             :     // because tracing outline typed objects is considerably more complicated
    3009             :     // than inline ones.
    3010          72 :     if (descr->size() > InlineTypedObject::MaximumSize || descr->transparent())
    3011          54 :         return true;
    3012             : 
    3013          36 :     TraceListVisitor visitor;
    3014          18 :     visitReferences(*descr, nullptr, visitor);
    3015             : 
    3016          36 :     Vector<int32_t> entries(cx);
    3017          18 :     if (!visitor.fillList(entries))
    3018           0 :         return false;
    3019             : 
    3020             :     // Trace lists aren't necessary for descriptors with no references.
    3021          18 :     MOZ_ASSERT(entries.length() >= 3);
    3022          18 :     if (entries.length() == 3)
    3023           0 :         return true;
    3024             : 
    3025          18 :     int32_t* list = cx->pod_malloc<int32_t>(entries.length());
    3026          18 :     if (!list)
    3027           0 :         return false;
    3028             : 
    3029          18 :     PodCopy(list, entries.begin(), entries.length());
    3030             : 
    3031          18 :     descr->initReservedSlot(JS_DESCR_SLOT_TRACE_LIST, PrivateValue(list));
    3032          18 :     return true;
    3033             : }
    3034             : 
    3035             : /* static */ void
    3036           0 : TypeDescr::finalize(FreeOp* fop, JSObject* obj)
    3037             : {
    3038           0 :     TypeDescr& descr = obj->as<TypeDescr>();
    3039           0 :     if (descr.hasTraceList())
    3040           0 :         js_free(const_cast<int32_t*>(descr.traceList()));
    3041           0 : }

Generated by: LCOV version 1.13