tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WasmTypeDef.h (52524B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 *
      4 * Copyright 2021 Mozilla Foundation
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *     http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 #ifndef wasm_type_def_h
     20 #define wasm_type_def_h
     21 
     22 #include "mozilla/Assertions.h"
     23 #include "mozilla/HashTable.h"
     24 
     25 #include "js/RefCounted.h"
     26 
     27 #include "wasm/WasmCodegenConstants.h"
     28 #include "wasm/WasmCompileArgs.h"
     29 #include "wasm/WasmConstants.h"
     30 #include "wasm/WasmSerialize.h"
     31 #include "wasm/WasmStructLayout.h"
     32 #include "wasm/WasmUtility.h"
     33 #include "wasm/WasmValType.h"
     34 
     35 namespace js {
     36 namespace wasm {
     37 
     38 class RecGroup;
     39 
     40 //=========================================================================
     41 // Function types
     42 
     43 // The FuncType class represents a WebAssembly function signature which takes a
     44 // list of value types and returns an expression type. The engine uses two
     45 // in-memory representations of the argument Vector's memory (when elements do
     46 // not fit inline): normal malloc allocation (via SystemAllocPolicy) and
     47 // allocation in a LifoAlloc (via LifoAllocPolicy). The former FuncType objects
     48 // can have any lifetime since they own the memory. The latter FuncType objects
     49 // must not outlive the associated LifoAlloc mark/release interval (which is
     50 // currently the duration of module validation+compilation). Thus, long-lived
     51 // objects like WasmModule must use malloced allocation.
     52 
     53 class FuncType {
     54  ValTypeVector args_;
     55  ValTypeVector results_;
     56  // A packed structural type identifier for use in the call_indirect type
     57  // check in the prologue of functions. If this function type cannot fit in
     58  // this immediate, it will be NO_IMMEDIATE_TYPE_ID.
     59  //
     60  // This is initialized in DecodeTypeSection once we have the full recursion
     61  // group around.
     62  uint32_t immediateTypeId_ = NO_IMMEDIATE_TYPE_ID;
     63 
     64  // This function type cannot be packed into an immediate for call_indirect
     65  // signature checks.
     66  static const uint32_t NO_IMMEDIATE_TYPE_ID = UINT32_MAX;
     67 
     68  // Entry from JS to wasm via the JIT is currently unimplemented for
     69  // functions that return multiple values.
     70  bool temporarilyUnsupportedResultCountForJitEntry() const {
     71    return results().length() > MaxResultsForJitEntry;
     72  }
     73  // Calls out from wasm to JS that return multiple values is currently
     74  // unsupported.
     75  bool temporarilyUnsupportedResultCountForJitExit() const {
     76    return results().length() > MaxResultsForJitExit;
     77  }
     78  // For JS->wasm jit entries, temporarily disallow certain types until the
     79  // stubs generator is improved.
     80  //   * ref params may be nullable externrefs
     81  //   * ref results may not be type indices
     82  // V128 types are excluded per spec but are guarded against separately.
     83  bool temporarilyUnsupportedReftypeForEntry() const {
     84    for (ValType arg : args()) {
     85      if (arg.isRefType() && (!arg.isExternRef() || !arg.isNullable())) {
     86        return true;
     87      }
     88    }
     89    for (ValType result : results()) {
     90      if (result.isTypeRef()) {
     91        return true;
     92      }
     93    }
     94    return false;
     95  }
     96  // For wasm->JS jit exits, temporarily disallow certain types until
     97  // the stubs generator is improved.
     98  //   * ref results may be nullable externrefs
     99  // Unexposable types must be guarded against separately.
    100  bool temporarilyUnsupportedReftypeForExit() const {
    101    for (ValType result : results()) {
    102      if (result.isRefType() &&
    103          (!result.isExternRef() || !result.isNullable())) {
    104        return true;
    105      }
    106    }
    107    return false;
    108  }
    109 
    110 public:
    111  FuncType() = default;
    112  FuncType(ValTypeVector&& args, ValTypeVector&& results)
    113      : args_(std::move(args)), results_(std::move(results)) {
    114    MOZ_ASSERT(args_.length() <= MaxParams);
    115    MOZ_ASSERT(results_.length() <= MaxResults);
    116  }
    117 
    118  FuncType(FuncType&&) = default;
    119  FuncType& operator=(FuncType&&) = default;
    120 
    121  [[nodiscard]] bool clone(const FuncType& src) {
    122    MOZ_ASSERT(args_.empty());
    123    MOZ_ASSERT(results_.empty());
    124    immediateTypeId_ = src.immediateTypeId_;
    125    return args_.appendAll(src.args_) && results_.appendAll(src.results_);
    126  }
    127 
    128  ValType arg(unsigned i) const { return args_[i]; }
    129  const ValTypeVector& args() const { return args_; }
    130  ValType result(unsigned i) const { return results_[i]; }
    131  const ValTypeVector& results() const { return results_; }
    132 
    133  void initImmediateTypeId(bool isFinal, const TypeDef* superTypeDef,
    134                           uint32_t recGroupLength);
    135  bool hasImmediateTypeId() const {
    136    return immediateTypeId_ != NO_IMMEDIATE_TYPE_ID;
    137  }
    138  uint32_t immediateTypeId() const {
    139    MOZ_ASSERT(hasImmediateTypeId());
    140    return immediateTypeId_;
    141  }
    142 
    143  // The lsb for every immediate type id is set to distinguish an immediate type
    144  // id from a type id represented by a pointer to the global hash type set.
    145  static const uint32_t ImmediateBit = 0x1;
    146 
    147  HashNumber hash(const RecGroup* recGroup) const {
    148    HashNumber hn = 0;
    149    for (const ValType& vt : args_) {
    150      hn = mozilla::AddToHash(hn, vt.forIsoEquals(recGroup).hash());
    151    }
    152    for (const ValType& vt : results_) {
    153      hn = mozilla::AddToHash(hn, vt.forIsoEquals(recGroup).hash());
    154    }
    155    return hn;
    156  }
    157 
    158  // Compares two function types for isorecursive equality. See
    159  // "Comparing type definitions" in WasmValType.h for more background.
    160  static bool isoEquals(const RecGroup* lhsRecGroup, const FuncType& lhs,
    161                        const RecGroup* rhsRecGroup, const FuncType& rhs) {
    162    if (lhs.args_.length() != rhs.args_.length() ||
    163        lhs.results_.length() != rhs.results_.length()) {
    164      return false;
    165    }
    166    for (uint32_t i = 0; i < lhs.args_.length(); i++) {
    167      if (lhs.args_[i].forIsoEquals(lhsRecGroup) !=
    168          rhs.args_[i].forIsoEquals(rhsRecGroup)) {
    169        return false;
    170      }
    171    }
    172    for (uint32_t i = 0; i < lhs.results_.length(); i++) {
    173      if (lhs.results_[i].forIsoEquals(lhsRecGroup) !=
    174          rhs.results_[i].forIsoEquals(rhsRecGroup)) {
    175        return false;
    176      }
    177    }
    178    return true;
    179  }
    180 
    181  // Checks if every arg and result of the specified function types are bitwise
    182  // equal. Type references must therefore point to exactly the same type
    183  // definition instance.
    184  static bool strictlyEquals(const FuncType& lhs, const FuncType& rhs) {
    185    return EqualContainers(lhs.args(), rhs.args()) &&
    186           EqualContainers(lhs.results(), rhs.results());
    187  }
    188 
    189  // Checks if two function types are compatible in a given subtyping
    190  // relationship.
    191  static bool canBeSubTypeOf(const FuncType& subType,
    192                             const FuncType& superType) {
    193    // A subtype must have exactly as many arguments as its supertype
    194    if (subType.args().length() != superType.args().length()) {
    195      return false;
    196    }
    197 
    198    // A subtype must have exactly as many returns as its supertype
    199    if (subType.results().length() != superType.results().length()) {
    200      return false;
    201    }
    202 
    203    // Function result types are covariant
    204    for (uint32_t i = 0; i < superType.results().length(); i++) {
    205      if (!ValType::isSubTypeOf(subType.results()[i], superType.results()[i])) {
    206        return false;
    207      }
    208    }
    209 
    210    // Function argument types are contravariant
    211    for (uint32_t i = 0; i < superType.args().length(); i++) {
    212      if (!ValType::isSubTypeOf(superType.args()[i], subType.args()[i])) {
    213        return false;
    214      }
    215    }
    216 
    217    return true;
    218  }
    219 
    220  bool canHaveJitEntry() const;
    221  bool canHaveJitExit() const;
    222 
    223  bool hasInt64Arg() const {
    224    for (ValType arg : args()) {
    225      if (arg.kind() == ValType::Kind::I64) {
    226        return true;
    227      }
    228    }
    229    return false;
    230  }
    231 
    232  bool hasUnexposableArgOrRet() const {
    233    for (ValType arg : args()) {
    234      if (!arg.isExposable()) {
    235        return true;
    236      }
    237    }
    238    for (ValType result : results()) {
    239      if (!result.isExposable()) {
    240        return true;
    241      }
    242    }
    243    return false;
    244  }
    245 
    246  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    247  WASM_DECLARE_FRIEND_SERIALIZE(FuncType);
    248 };
    249 
    250 //=========================================================================
    251 // Structure types
    252 
    253 // The Module owns a dense array of StructType values that represent the
    254 // structure types that the module knows about.  It is created from the sparse
    255 // array of types in the ModuleMetadata when the Module is created.
    256 
    257 struct FieldType {
    258  StorageType type;
    259  bool isMutable;
    260 
    261  FieldType() : isMutable(false) {}
    262  FieldType(StorageType type, bool isMutable)
    263      : type(type), isMutable(isMutable) {}
    264 
    265  HashNumber hash(const RecGroup* recGroup) const {
    266    HashNumber hn = 0;
    267    hn = mozilla::AddToHash(hn, type.forIsoEquals(recGroup).hash());
    268    hn = mozilla::AddToHash(hn, HashNumber(isMutable));
    269    return hn;
    270  }
    271 
    272  // Compares two field types for isorecursive equality. See
    273  // "Comparing type definitions" in WasmValType.h for more background.
    274  static bool isoEquals(const RecGroup* lhsRecGroup, const FieldType& lhs,
    275                        const RecGroup* rhsRecGroup, const FieldType& rhs) {
    276    return lhs.isMutable == rhs.isMutable &&
    277           lhs.type.forIsoEquals(lhsRecGroup) ==
    278               rhs.type.forIsoEquals(rhsRecGroup);
    279  }
    280 
    281  // Checks if two struct fields are compatible in a given subtyping
    282  // relationship.
    283  static bool canBeSubTypeOf(const FieldType& subType,
    284                             const FieldType& superType) {
    285    // Mutable fields are invariant w.r.t. field types
    286    if (subType.isMutable && superType.isMutable) {
    287      return subType.type == superType.type;
    288    }
    289 
    290    // Immutable fields are covariant w.r.t. field types
    291    if (!subType.isMutable && !superType.isMutable) {
    292      return StorageType::isSubTypeOf(subType.type, superType.type);
    293    }
    294 
    295    return false;
    296  }
    297 };
    298 
    299 using FieldTypeVector = Vector<FieldType, 0, SystemAllocPolicy>;
    300 
    301 using FieldAccessPathVector = Vector<FieldAccessPath, 2, SystemAllocPolicy>;
    302 using InlineTraceOffsetVector = Vector<uint32_t, 2, SystemAllocPolicy>;
    303 using OutlineTraceOffsetVector = Vector<uint32_t, 0, SystemAllocPolicy>;
    304 
    305 class StructType {
    306 public:
    307  // Vector of the fields in this struct
    308  FieldTypeVector fields_;
    309  // The access path for every struct field.  Same length as `fields_`.
    310  FieldAccessPathVector fieldAccessPaths_;
    311 
    312  // The offsets of fields that must be traced in the inline portion of wasm
    313  // struct object.  Offsets are from the base of the WasmStructObject.
    314  InlineTraceOffsetVector inlineTraceOffsets_;
    315  // The offsets of fields that must be traced in the outline portion of wasm
    316  // struct object.
    317  OutlineTraceOffsetVector outlineTraceOffsets_;
    318 
    319  // The total block size for the WasmStructObject's OOL data area, or zero if
    320  // no OOL data is required.
    321  uint32_t totalSizeOOL_;
    322  // The offset from the start of the WasmStructObject to the OOL pointer
    323  // field, or InvalidOffset if no OOL data is required.
    324  uint32_t oolPointerOffset_;
    325 
    326  // The total object size for the WasmStructObject, including fixed overheads
    327  // (its header words).
    328  uint32_t totalSizeIL_;
    329  // The offset from the start of the WasmStructObject to the first payload
    330  // byte.
    331  uint8_t payloadOffsetIL_;
    332 
    333  // The AllocKind for the object, computed directly from `totalSizeIL_`.  Note
    334  // this requires further processing with GetFinalizedAllocKindForClass before
    335  // use.
    336  gc::AllocKind allocKind_;
    337 
    338  // Whether this struct only contains defaultable fields.
    339  bool isDefaultable_;
    340 
    341  static const uint32_t InvalidOffset = 0xFFFFFFFF;
    342 
    343  StructType()
    344      : totalSizeOOL_(0),
    345        oolPointerOffset_(InvalidOffset),
    346        totalSizeIL_(0),
    347        payloadOffsetIL_(0),
    348        allocKind_(gc::AllocKind::INVALID),
    349        isDefaultable_(false) {}
    350 
    351  explicit StructType(FieldTypeVector&& fields)
    352      : fields_(std::move(fields)),
    353        totalSizeOOL_(0),
    354        oolPointerOffset_(InvalidOffset),
    355        totalSizeIL_(0),
    356        payloadOffsetIL_(0),
    357        allocKind_(gc::AllocKind::INVALID),
    358        isDefaultable_(false) {
    359    MOZ_ASSERT(fields_.length() <= MaxStructFields);
    360  }
    361 
    362  StructType(StructType&&) = default;
    363  StructType& operator=(StructType&&) = default;
    364 
    365  [[nodiscard]] bool init();
    366 
    367  bool isDefaultable() const { return isDefaultable_; }
    368 
    369  bool hasOOL() const { return totalSizeOOL_ > 0; }
    370 
    371  HashNumber hash(const RecGroup* recGroup) const {
    372    HashNumber hn = 0;
    373    for (const FieldType& field : fields_) {
    374      hn = mozilla::AddToHash(hn, field.hash(recGroup));
    375    }
    376    return hn;
    377  }
    378 
    379  // Compares two struct types for isorecursive equality. See
    380  // "Comparing type definitions" in WasmValType.h for more background.
    381  static bool isoEquals(const RecGroup* lhsRecGroup, const StructType& lhs,
    382                        const RecGroup* rhsRecGroup, const StructType& rhs) {
    383    if (lhs.fields_.length() != rhs.fields_.length()) {
    384      return false;
    385    }
    386    for (uint32_t i = 0; i < lhs.fields_.length(); i++) {
    387      const FieldType& lhsField = lhs.fields_[i];
    388      const FieldType& rhsField = rhs.fields_[i];
    389      if (!FieldType::isoEquals(lhsRecGroup, lhsField, rhsRecGroup, rhsField)) {
    390        return false;
    391      }
    392    }
    393    return true;
    394  }
    395 
    396  // Checks if two struct types are compatible in a given subtyping
    397  // relationship.
    398  static bool canBeSubTypeOf(const StructType& subType,
    399                             const StructType& superType) {
    400    // A subtype must have at least as many fields as its supertype
    401    if (subType.fields_.length() < superType.fields_.length()) {
    402      return false;
    403    }
    404 
    405    // Every field that is in both superType and subType must be compatible
    406    for (uint32_t i = 0; i < superType.fields_.length(); i++) {
    407      if (!FieldType::canBeSubTypeOf(subType.fields_[i],
    408                                     superType.fields_[i])) {
    409        return false;
    410      }
    411    }
    412    return true;
    413  }
    414 
    415  static bool createImmutable(const ValTypeVector& types, StructType* struct_);
    416 
    417  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    418  WASM_DECLARE_FRIEND_SERIALIZE(StructType);
    419 };
    420 
    421 using StructTypeVector = Vector<StructType, 0, SystemAllocPolicy>;
    422 
    423 //=========================================================================
    424 // Array types
    425 
    426 class ArrayType {
    427 public:
    428  // The kind of value stored in this array
    429  FieldType fieldType_;
    430 
    431 public:
    432  ArrayType() = default;
    433  ArrayType(StorageType elementType, bool isMutable)
    434      : fieldType_(FieldType(elementType, isMutable)) {}
    435 
    436  ArrayType(const ArrayType&) = default;
    437  ArrayType& operator=(const ArrayType&) = default;
    438 
    439  ArrayType(ArrayType&&) = default;
    440  ArrayType& operator=(ArrayType&&) = default;
    441 
    442  StorageType elementType() const { return fieldType_.type; }
    443  bool isMutable() const { return fieldType_.isMutable; }
    444  bool isDefaultable() const { return elementType().isDefaultable(); }
    445 
    446  HashNumber hash(const RecGroup* recGroup) const {
    447    return fieldType_.hash(recGroup);
    448  }
    449 
    450  // Compares two array types for isorecursive equality. See
    451  // "Comparing type definitions" in WasmValType.h for more background.
    452  static bool isoEquals(const RecGroup* lhsRecGroup, const ArrayType& lhs,
    453                        const RecGroup* rhsRecGroup, const ArrayType& rhs) {
    454    return FieldType::isoEquals(lhsRecGroup, lhs.fieldType_, rhsRecGroup,
    455                                rhs.fieldType_);
    456  }
    457 
    458  // Checks if two arrays are compatible in a given subtyping relationship.
    459  static bool canBeSubTypeOf(const ArrayType& subType,
    460                             const ArrayType& superType) {
    461    return FieldType::canBeSubTypeOf(subType.fieldType_, superType.fieldType_);
    462  }
    463 
    464  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    465 };
    466 
    467 WASM_DECLARE_CACHEABLE_POD(ArrayType);
    468 
    469 using ArrayTypeVector = Vector<ArrayType, 0, SystemAllocPolicy>;
    470 
    471 //=========================================================================
    472 // SuperTypeVector
    473 
    474 // [SMDOC] Super type vector
    475 //
    476 // A super type vector is a vector representation of the linked list of super
    477 // types that a type definition has. Every element is a raw pointer to another
    478 // super type vector - they are one-to-one with type definitions, so they are
    479 // functionally equivalent. It is possible to form a vector here because
    480 // subtypes in wasm form trees, not DAGs, with every type having at most one
    481 // super type.
    482 //
    483 // The first element in the vector is the 'root' type definition without a
    484 // super type. The last element is to the type definition itself.
    485 //
    486 // ## Subtype checking
    487 //
    488 // The only purpose of a super type vector is to support constant time
    489 // subtyping checks. This is not free, it comes at the cost of worst case N^2
    490 // metadata size growth. We limit the max subtyping depth to counter this.
    491 //
    492 // To perform a subtype check we rely on the following:
    493 //  (1) a type A is a subtype (<:) of type B iff:
    494 //        type A == type B OR
    495 //        type B is reachable by following declared super types of type A
    496 //  (2) we order super type vectors from least to most derived types
    497 //  (3) the 'subtyping depth' of all type definitions is statically known
    498 //
    499 // With the above, we know that if type B is a super type of type A, that it
    500 // must be in A's super type vector at type B's subtyping depth. We can
    501 // therefore just do an index and comparison to determine if that's the case.
    502 //
    503 // ## Example
    504 //
    505 // For the following type section:
    506 //   ..
    507 //   12: (type (struct))
    508 //   ..
    509 //   34: (type (sub 12 (struct)))
    510 //   ..
    511 //   56: (type (sub 34 (struct)))
    512 //   ..
    513 //   78: (type (sub 56 (struct)))
    514 //   ..
    515 //
    516 // (type 12) would have the following super type vector:
    517 //   [(type 12)]
    518 //
    519 // (type 78) would have the following super type vector:
    520 //   [(type 12), (type 34), (type 56), (type 78)]
    521 //
    522 // Checking that (type 78) <: (type 12) can use the fact that (type 12) will
    523 // always be present at depth 0 of any super type vector it is in, and
    524 // therefore check the vector at that index.
    525 //
    526 // ## Minimum sizing
    527 //
    528 // As a further optimization to avoid bounds checking, we guarantee that all
    529 // super type vectors are at least `MinSuperTypeVectorLength`. All checks
    530 // against indices that we know statically are at/below that can skip bounds
    531 // checking. Extra entries added to reach the minimum size are initialized to
    532 // null.
    533 class SuperTypeVector {
    534  SuperTypeVector() : typeDef_(nullptr), length_(0) {}
    535 
    536  // The TypeDef for which this is the supertype vector.  That TypeDef should
    537  // point back to this SuperTypeVector.
    538  const TypeDef* typeDef_;
    539 
    540  // A cached copy of subTypingDepth from TypeDef.
    541  uint32_t subTypingDepth_;
    542 
    543  // The length of types stored inline below.
    544  uint32_t length_;
    545 
    546 public:
    547  // Raw pointers to the super types of this type definition. Ordered from
    548  // least-derived to most-derived.  Do not add any fields after this point.
    549  const SuperTypeVector* types_[0];
    550 
    551  // Batch allocate super type vectors for all the types in a recursion group.
    552  // Returns a pointer to the first super type vector, which can be used to
    553  // free all vectors.
    554  [[nodiscard]] static const SuperTypeVector* createMultipleForRecGroup(
    555      RecGroup* recGroup);
    556 
    557  const TypeDef* typeDef() const { return typeDef_; }
    558 
    559  uint32_t length() const { return length_; }
    560 
    561  const SuperTypeVector* type(size_t index) const {
    562    MOZ_ASSERT(index < length_);
    563    return types_[index];
    564  }
    565 
    566  // The length of a super type vector for a specific type def.
    567  static size_t lengthForTypeDef(const TypeDef& typeDef);
    568  // The byte size of a super type vector for a specific type def.
    569  static size_t byteSizeForTypeDef(const TypeDef& typeDef);
    570 
    571  static size_t offsetOfSubTypingDepth() {
    572    return offsetof(SuperTypeVector, subTypingDepth_);
    573  }
    574  static size_t offsetOfLength() { return offsetof(SuperTypeVector, length_); }
    575  static size_t offsetOfSelfTypeDef() {
    576    return offsetof(SuperTypeVector, typeDef_);
    577  };
    578  static size_t offsetOfSTVInVector(uint32_t subTypingDepth);
    579 };
    580 
    581 // Ensure it is safe to use `sizeof(SuperTypeVector)` to find the offset of
    582 // `types_[0]`.
    583 static_assert(offsetof(SuperTypeVector, types_) == sizeof(SuperTypeVector));
    584 
    585 //=========================================================================
    586 // TypeDef and supporting types
    587 
    588 // A tagged container for the various types that can be present in a wasm
    589 // module's type section.
    590 
    591 enum class TypeDefKind : uint8_t {
    592  None = 0,
    593  Func,
    594  Struct,
    595  Array,
    596 };
    597 
    598 class TypeDef {
    599  uint32_t offsetToRecGroup_;
    600 
    601  // The supertype vector for this TypeDef.  That SuperTypeVector should point
    602  // back to this TypeDef.
    603  const SuperTypeVector* superTypeVector_;
    604 
    605  const TypeDef* superTypeDef_;
    606  uint16_t subTypingDepth_;
    607  bool isFinal_;
    608  TypeDefKind kind_;
    609  union {
    610    FuncType funcType_;
    611    StructType structType_;
    612    ArrayType arrayType_;
    613  };
    614 
    615  void setRecGroup(RecGroup* recGroup) {
    616    uintptr_t recGroupAddr = (uintptr_t)recGroup;
    617    uintptr_t typeDefAddr = (uintptr_t)this;
    618    MOZ_ASSERT(typeDefAddr > recGroupAddr);
    619    MOZ_ASSERT(typeDefAddr - recGroupAddr <= UINT32_MAX);
    620    offsetToRecGroup_ = typeDefAddr - recGroupAddr;
    621  }
    622 
    623 public:
    624  explicit TypeDef(RecGroup* recGroup)
    625      : offsetToRecGroup_(0),
    626        superTypeVector_(nullptr),
    627        superTypeDef_(nullptr),
    628        subTypingDepth_(0),
    629        isFinal_(true),
    630        kind_(TypeDefKind::None) {
    631    setRecGroup(recGroup);
    632  }
    633 
    634  ~TypeDef() {
    635    switch (kind_) {
    636      case TypeDefKind::Func:
    637        funcType_.~FuncType();
    638        break;
    639      case TypeDefKind::Struct:
    640        structType_.~StructType();
    641        break;
    642      case TypeDefKind::Array:
    643        arrayType_.~ArrayType();
    644        break;
    645      case TypeDefKind::None:
    646        break;
    647    }
    648  }
    649 
    650  TypeDef& operator=(FuncType&& that) noexcept {
    651    MOZ_ASSERT(isNone());
    652    kind_ = TypeDefKind::Func;
    653    new (&funcType_) FuncType(std::move(that));
    654    return *this;
    655  }
    656 
    657  TypeDef& operator=(StructType&& that) noexcept {
    658    MOZ_ASSERT(isNone());
    659    kind_ = TypeDefKind::Struct;
    660    new (&structType_) StructType(std::move(that));
    661    return *this;
    662  }
    663 
    664  TypeDef& operator=(ArrayType&& that) noexcept {
    665    MOZ_ASSERT(isNone());
    666    kind_ = TypeDefKind::Array;
    667    new (&arrayType_) ArrayType(std::move(that));
    668    return *this;
    669  }
    670 
    671  const SuperTypeVector* superTypeVector() const { return superTypeVector_; }
    672 
    673  void setSuperTypeVector(const SuperTypeVector* superTypeVector) {
    674    superTypeVector_ = superTypeVector;
    675  }
    676 
    677  static size_t offsetOfKind() { return offsetof(TypeDef, kind_); }
    678 
    679  static size_t offsetOfSuperTypeVector() {
    680    return offsetof(TypeDef, superTypeVector_);
    681  }
    682 
    683  static size_t offsetOfSubTypingDepth() {
    684    return offsetof(TypeDef, subTypingDepth_);
    685  }
    686 
    687  const TypeDef* superTypeDef() const { return superTypeDef_; }
    688 
    689  bool isFinal() const { return isFinal_; }
    690 
    691  uint16_t subTypingDepth() const { return subTypingDepth_; }
    692 
    693  const RecGroup& recGroup() const {
    694    uintptr_t typeDefAddr = (uintptr_t)this;
    695    uintptr_t recGroupAddr = typeDefAddr - offsetToRecGroup_;
    696    return *(const RecGroup*)recGroupAddr;
    697  }
    698 
    699  TypeDefKind kind() const { return kind_; }
    700 
    701  bool isNone() const { return kind_ == TypeDefKind::None; }
    702 
    703  bool isFuncType() const { return kind_ == TypeDefKind::Func; }
    704 
    705  bool isStructType() const { return kind_ == TypeDefKind::Struct; }
    706 
    707  bool isArrayType() const { return kind_ == TypeDefKind::Array; }
    708 
    709  bool isGcType() const { return isStructType() || isArrayType(); }
    710 
    711  const FuncType& funcType() const {
    712    MOZ_ASSERT(isFuncType());
    713    return funcType_;
    714  }
    715 
    716  FuncType& funcType() {
    717    MOZ_ASSERT(isFuncType());
    718    return funcType_;
    719  }
    720 
    721  const StructType& structType() const {
    722    MOZ_ASSERT(isStructType());
    723    return structType_;
    724  }
    725 
    726  StructType& structType() {
    727    MOZ_ASSERT(isStructType());
    728    return structType_;
    729  }
    730 
    731  const ArrayType& arrayType() const {
    732    MOZ_ASSERT(isArrayType());
    733    return arrayType_;
    734  }
    735 
    736  ArrayType& arrayType() {
    737    MOZ_ASSERT(isArrayType());
    738    return arrayType_;
    739  }
    740 
    741  // Get a value that can be used for comparing type definitions across
    742  // different recursion groups.
    743  static inline uintptr_t forIsoEquals(const TypeDef* typeDef,
    744                                       const RecGroup* recGroup);
    745 
    746  HashNumber hash() const {
    747    HashNumber hn = HashNumber(kind_);
    748    hn = mozilla::AddToHash(hn,
    749                            TypeDef::forIsoEquals(superTypeDef_, &recGroup()));
    750    hn = mozilla::AddToHash(hn, isFinal_);
    751    switch (kind_) {
    752      case TypeDefKind::Func:
    753        hn = mozilla::AddToHash(hn, funcType_.hash(&recGroup()));
    754        break;
    755      case TypeDefKind::Struct:
    756        hn = mozilla::AddToHash(hn, structType_.hash(&recGroup()));
    757        break;
    758      case TypeDefKind::Array:
    759        hn = mozilla::AddToHash(hn, arrayType_.hash(&recGroup()));
    760        break;
    761      case TypeDefKind::None:
    762        break;
    763    }
    764    return hn;
    765  }
    766 
    767  // Compares two type definitions for isorecursive equality. See
    768  // "Comparing type definitions" in WasmValType.h for more background.
    769  static bool isoEquals(const TypeDef& lhs, const TypeDef& rhs) {
    770    if (lhs.kind_ != rhs.kind_) {
    771      return false;
    772    }
    773    if (lhs.isFinal_ != rhs.isFinal_) {
    774      return false;
    775    }
    776    if (TypeDef::forIsoEquals(lhs.superTypeDef_, &lhs.recGroup()) !=
    777        TypeDef::forIsoEquals(rhs.superTypeDef_, &rhs.recGroup())) {
    778      return false;
    779    }
    780    switch (lhs.kind_) {
    781      case TypeDefKind::Func:
    782        return FuncType::isoEquals(&lhs.recGroup(), lhs.funcType_,
    783                                   &rhs.recGroup(), rhs.funcType_);
    784      case TypeDefKind::Struct:
    785        return StructType::isoEquals(&lhs.recGroup(), lhs.structType_,
    786                                     &rhs.recGroup(), rhs.structType_);
    787      case TypeDefKind::Array:
    788        return ArrayType::isoEquals(&lhs.recGroup(), lhs.arrayType_,
    789                                    &rhs.recGroup(), rhs.arrayType_);
    790      case TypeDefKind::None:
    791        MOZ_CRASH("can't match TypeDefKind::None");
    792    }
    793    return false;
    794  }
    795 
    796  // Checks if two type definitions are compatible in a given subtyping
    797  // relationship.
    798  static bool canBeSubTypeOf(const TypeDef* subType, const TypeDef* superType) {
    799    if (subType->kind() != superType->kind()) {
    800      return false;
    801    }
    802 
    803    // A subtype can't declare a final super type.
    804    if (superType->isFinal()) {
    805      return false;
    806    }
    807 
    808    switch (subType->kind_) {
    809      case TypeDefKind::Func:
    810        return FuncType::canBeSubTypeOf(subType->funcType_,
    811                                        superType->funcType_);
    812      case TypeDefKind::Struct:
    813        return StructType::canBeSubTypeOf(subType->structType_,
    814                                          superType->structType_);
    815      case TypeDefKind::Array:
    816        return ArrayType::canBeSubTypeOf(subType->arrayType_,
    817                                         superType->arrayType_);
    818      case TypeDefKind::None:
    819        MOZ_CRASH();
    820    }
    821    return false;
    822  }
    823 
    824  void setSuperTypeDef(const TypeDef* superTypeDef) {
    825    superTypeDef_ = superTypeDef;
    826    subTypingDepth_ = superTypeDef_->subTypingDepth_ + 1;
    827  }
    828 
    829  void setFinal(const bool value) { isFinal_ = value; }
    830 
    831  // Checks if `subTypeDef` is a declared sub type of `superTypeDef`.
    832  static bool isSubTypeOf(const TypeDef* subTypeDef,
    833                          const TypeDef* superTypeDef) {
    834    // Fast path for when the types are equal
    835    if (MOZ_LIKELY(subTypeDef == superTypeDef)) {
    836      return true;
    837    }
    838    const SuperTypeVector* subSTV = subTypeDef->superTypeVector();
    839    const SuperTypeVector* superSTV = superTypeDef->superTypeVector();
    840 
    841    // During construction of a recursion group, the super type vectors may not
    842    // have been computed yet, in which case we need to fall back to a linear
    843    // search.
    844    if (!subSTV || !superSTV) {
    845      while (subTypeDef) {
    846        if (subTypeDef == superTypeDef) {
    847          return true;
    848        }
    849        subTypeDef = subTypeDef->superTypeDef();
    850      }
    851      return false;
    852    }
    853 
    854    // The supertype vectors do exist. Check that they point to the right
    855    // places.
    856    MOZ_ASSERT(subSTV);
    857    MOZ_ASSERT(superSTV);
    858    MOZ_ASSERT(subSTV->typeDef() == subTypeDef);
    859    MOZ_ASSERT(superSTV->typeDef() == superTypeDef);
    860 
    861    // We need to check if `superTypeDef` is one of `subTypeDef`s super types
    862    // by checking in `subTypeDef`s super type vector. We can use the static
    863    // information of the depth of `superTypeDef` to index directly into the
    864    // vector.
    865    uint32_t subTypingDepth = superTypeDef->subTypingDepth();
    866    if (subTypingDepth >= subSTV->length()) {
    867      return false;
    868    }
    869 
    870    return subSTV->type(subTypingDepth) == superSTV;
    871  }
    872 
    873  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
    874  WASM_DECLARE_FRIEND_SERIALIZE(TypeDef);
    875 
    876  inline void AddRef() const;
    877  inline void Release() const;
    878 };
    879 
    880 using SharedTypeDef = RefPtr<const TypeDef>;
    881 using MutableTypeDef = RefPtr<TypeDef>;
    882 
    883 using TypeDefVector = Vector<TypeDef, 0, SystemAllocPolicy>;
    884 using TypeDefPtrVector = Vector<const TypeDef*, 0, SystemAllocPolicy>;
    885 
    886 using TypeDefPtrToIndexMap =
    887    HashMap<const TypeDef*, uint32_t, PointerHasher<const TypeDef*>,
    888            SystemAllocPolicy>;
    889 
    890 //=========================================================================
    891 // RecGroup
    892 
    893 // A recursion group is a set of type definitions that may refer to each other
    894 // or to type definitions in another recursion group. There is an ordering
    895 // restriction on type references such that references across recursion groups
    896 // must be acyclic.
    897 //
    898 // Type definitions are stored inline in their containing recursion group, and
    899 // have an offset to their containing recursion group. Recursion groups are
    900 // atomically refcounted and hold strong references to other recursion groups
    901 // they depend on.
    902 //
    903 // Type equality is structural in WebAssembly, and we canonicalize recursion
    904 // groups while building them so that pointer equality of types implies
    905 // equality of types. There is a global hash set of weak pointers to recursion
    906 // groups that holds the current canonical instance of a recursion group.
    907 class RecGroup : public AtomicRefCounted<RecGroup> {
    908  // Whether this recursion group has been finished and acquired strong
    909  // references to external recursion groups.
    910  bool finalizedTypes_;
    911  // The number of types stored in this recursion group.
    912  uint32_t numTypes_;
    913  // The batch allocated super type vectors for all type definitions in this
    914  // recursion group.
    915  const SuperTypeVector* vectors_;
    916  // The first type definition stored inline in this recursion group.
    917  TypeDef types_[0];
    918 
    919  friend class TypeContext;
    920 
    921  explicit RecGroup(uint32_t numTypes)
    922      : finalizedTypes_(false), numTypes_(numTypes), vectors_(nullptr) {}
    923 
    924  // Compute the size in bytes of a recursion group with the specified amount
    925  // of types.
    926  static constexpr size_t sizeOfRecGroup(uint32_t numTypes) {
    927    // TypeDef can find containing RecGroup using only a 32-bit offset
    928    static_assert(offsetof(RecGroup, types_) + sizeof(TypeDef) * MaxTypes <=
    929                  UINT32_MAX);
    930    // We will not overflow in our calculation here
    931    static_assert(MaxTypes <= SIZE_MAX / sizeof(TypeDef));
    932    return sizeof(RecGroup) + sizeof(TypeDef) * numTypes;
    933  }
    934 
    935  // Allocate a recursion group with the specified amount of types. The type
    936  // definitions will be ready to be filled in. Users must call `finish` once
    937  // type definitions are initialized so that strong references to external
    938  // recursion groups are taken.
    939  static RefPtr<RecGroup> allocate(uint32_t numTypes) {
    940    // Validation must ensure this
    941    MOZ_RELEASE_ASSERT(numTypes <= MaxTypes);
    942 
    943    // Allocate the recursion group with the correct size
    944    RecGroup* recGroup = (RecGroup*)js_malloc(sizeOfRecGroup(numTypes));
    945    if (!recGroup) {
    946      return nullptr;
    947    }
    948 
    949    // Construct the recursion group and types that are stored inline
    950    new (recGroup) RecGroup(numTypes);
    951    for (uint32_t i = 0; i < numTypes; i++) {
    952      new (recGroup->types_ + i) TypeDef(recGroup);
    953    }
    954    return recGroup;
    955  }
    956 
    957  // Finish initialization by acquiring strong references to groups referenced
    958  // by type definitions.
    959  [[nodiscard]] bool finalizeDefinitions() {
    960    MOZ_ASSERT(!finalizedTypes_);
    961    // Super type vectors are only needed for GC and have a size/time impact
    962    // that we don't want to encur until we're ready for it. Only use them when
    963    // GC is built into the binary.
    964    vectors_ = SuperTypeVector::createMultipleForRecGroup(this);
    965    if (!vectors_) {
    966      return false;
    967    }
    968    visitReferencedGroups([](const RecGroup* recGroup) { recGroup->AddRef(); });
    969    finalizedTypes_ = true;
    970    return true;
    971  }
    972 
    973  // Visit every external recursion group that is referenced by the types in
    974  // this recursion group.
    975  template <typename Visitor>
    976  void visitReferencedGroups(Visitor visitor) const {
    977    auto visitValType = [this, visitor](ValType type) {
    978      if (type.isTypeRef() && &type.typeDef()->recGroup() != this) {
    979        visitor(&type.typeDef()->recGroup());
    980      }
    981    };
    982    auto visitStorageType = [this, visitor](StorageType type) {
    983      if (type.isTypeRef() && &type.typeDef()->recGroup() != this) {
    984        visitor(&type.typeDef()->recGroup());
    985      }
    986    };
    987 
    988    for (uint32_t i = 0; i < numTypes_; i++) {
    989      const TypeDef& typeDef = types_[i];
    990 
    991      if (typeDef.superTypeDef() &&
    992          &typeDef.superTypeDef()->recGroup() != this) {
    993        visitor(&typeDef.superTypeDef()->recGroup());
    994      }
    995 
    996      switch (typeDef.kind()) {
    997        case TypeDefKind::Func: {
    998          const FuncType& funcType = typeDef.funcType();
    999          MOZ_RELEASE_ASSERT(funcType.args().length() <= MaxParams);
   1000          MOZ_RELEASE_ASSERT(funcType.results().length() <= MaxResults);
   1001          for (auto type : funcType.args()) {
   1002            visitValType(type);
   1003          }
   1004          for (auto type : funcType.results()) {
   1005            visitValType(type);
   1006          }
   1007          break;
   1008        }
   1009        case TypeDefKind::Struct: {
   1010          const StructType& structType = typeDef.structType();
   1011          MOZ_RELEASE_ASSERT(structType.fields_.length() <= MaxStructFields);
   1012          for (const auto& field : structType.fields_) {
   1013            visitStorageType(field.type);
   1014          }
   1015          break;
   1016        }
   1017        case TypeDefKind::Array: {
   1018          const ArrayType& arrayType = typeDef.arrayType();
   1019          visitStorageType(arrayType.elementType());
   1020          break;
   1021        }
   1022        case TypeDefKind::None: {
   1023          MOZ_CRASH();
   1024        }
   1025      }
   1026    }
   1027  }
   1028 
   1029 public:
   1030  ~RecGroup() {
   1031    // Release the referenced recursion groups if we acquired references to
   1032    // them. Do this before the type definitions are destroyed below.
   1033    if (finalizedTypes_) {
   1034      finalizedTypes_ = false;
   1035      visitReferencedGroups(
   1036          [](const RecGroup* recGroup) { recGroup->Release(); });
   1037    }
   1038 
   1039    if (vectors_) {
   1040      js_free((void*)vectors_);
   1041      vectors_ = nullptr;
   1042    }
   1043 
   1044    // Call destructors on all the type definitions.
   1045    for (uint32_t i = 0; i < numTypes_; i++) {
   1046      type(i).~TypeDef();
   1047    }
   1048  }
   1049 
   1050  // Recursion groups cannot be copied or moved
   1051  RecGroup& operator=(const RecGroup&) = delete;
   1052  RecGroup& operator=(RecGroup&&) = delete;
   1053 
   1054  // Get the type definition at the group type index (not module type index).
   1055  TypeDef& type(uint32_t groupTypeIndex) {
   1056    // We cannot mutate type definitions after we've finalized them
   1057    MOZ_ASSERT(!finalizedTypes_);
   1058    return types_[groupTypeIndex];
   1059  }
   1060  const TypeDef& type(uint32_t groupTypeIndex) const {
   1061    return types_[groupTypeIndex];
   1062  }
   1063 
   1064  // The number of types stored in this recursion group.
   1065  uint32_t numTypes() const { return numTypes_; }
   1066 
   1067  // Get the index of a type definition that's in this recursion group.
   1068  uint32_t indexOf(const TypeDef* typeDef) const {
   1069    MOZ_ASSERT(typeDef >= types_);
   1070    size_t groupTypeIndex = (size_t)(typeDef - types_);
   1071    MOZ_ASSERT(groupTypeIndex < numTypes());
   1072    return (uint32_t)groupTypeIndex;
   1073  }
   1074 
   1075  bool hasGcType() const {
   1076    for (uint32_t groupTypeIndex = 0; groupTypeIndex < numTypes();
   1077         groupTypeIndex++) {
   1078      if (type(groupTypeIndex).isGcType()) {
   1079        return true;
   1080      }
   1081    }
   1082    return false;
   1083  }
   1084 
   1085  HashNumber hash() const {
   1086    HashNumber hn = 0;
   1087    for (uint32_t i = 0; i < numTypes(); i++) {
   1088      hn = mozilla::AddToHash(hn, types_[i].hash());
   1089    }
   1090    return hn;
   1091  }
   1092 
   1093  // Compares two recursion groups for isorecursive equality. See
   1094  // "Comparing type definitions" in WasmValType.h for more background.
   1095  static bool isoEquals(const RecGroup& lhs, const RecGroup& rhs) {
   1096    if (lhs.numTypes() != rhs.numTypes()) {
   1097      return false;
   1098    }
   1099    for (uint32_t i = 0; i < lhs.numTypes(); i++) {
   1100      if (!TypeDef::isoEquals(lhs.type(i), rhs.type(i))) {
   1101        return false;
   1102      }
   1103    }
   1104    return true;
   1105  }
   1106 };
   1107 
   1108 // Remove all types from the canonical type set that are not referenced from
   1109 // outside the type set.
   1110 extern void PurgeCanonicalTypes();
   1111 
   1112 using SharedRecGroup = RefPtr<const RecGroup>;
   1113 using MutableRecGroup = RefPtr<RecGroup>;
   1114 using SharedRecGroupVector = Vector<SharedRecGroup, 0, SystemAllocPolicy>;
   1115 
   1116 //=========================================================================
   1117 // TypeContext
   1118 
   1119 // A type context holds the recursion groups and corresponding type definitions
   1120 // defined in a module.
   1121 class TypeContext : public AtomicRefCounted<TypeContext> {
   1122  // The pending recursion group that is currently being constructed
   1123  MutableRecGroup pendingRecGroup_;
   1124  // An in-order list of all the recursion groups defined in this module
   1125  SharedRecGroupVector recGroups_;
   1126  // An in-order list of the type definitions in the module. Each type is
   1127  // stored in a recursion group.
   1128  TypeDefPtrVector types_;
   1129  // A map from type definition to the original module index.
   1130  TypeDefPtrToIndexMap moduleIndices_;
   1131 
   1132  static SharedRecGroup canonicalizeGroup(SharedRecGroup recGroup);
   1133 
   1134 public:
   1135  TypeContext() = default;
   1136  ~TypeContext();
   1137 
   1138  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   1139    return types_.sizeOfExcludingThis(mallocSizeOf) +
   1140           moduleIndices_.shallowSizeOfExcludingThis(mallocSizeOf);
   1141  }
   1142 
   1143  // Disallow copy, allow move initialization
   1144  TypeContext(const TypeContext&) = delete;
   1145  TypeContext& operator=(const TypeContext&) = delete;
   1146  TypeContext(TypeContext&&) = delete;
   1147  TypeContext& operator=(TypeContext&&) = delete;
   1148 
   1149  // Begin creating a recursion group with the specified number of types.
   1150  // Returns a recursion group to be filled in with type definitions. This must
   1151  // be paired with `endGroup`.
   1152  [[nodiscard]] MutableRecGroup startRecGroup(uint32_t numTypes) {
   1153    // We must not have a pending group
   1154    MOZ_ASSERT(!pendingRecGroup_);
   1155 
   1156    // Create the group and add it to the list of groups
   1157    MutableRecGroup recGroup = RecGroup::allocate(numTypes);
   1158    if (!recGroup || !addRecGroup(recGroup)) {
   1159      return nullptr;
   1160    }
   1161 
   1162    // Store this group for later use in endRecGroup
   1163    pendingRecGroup_ = recGroup;
   1164    return recGroup;
   1165  }
   1166 
   1167  // Finish creation of a recursion group after type definitions have been
   1168  // initialized. This must be paired with `startGroup`.
   1169  [[nodiscard]] bool endRecGroup() {
   1170    // We must have started a recursion group
   1171    MOZ_ASSERT(pendingRecGroup_);
   1172    MutableRecGroup recGroup = pendingRecGroup_;
   1173    pendingRecGroup_ = nullptr;
   1174 
   1175    // Finalize the type definitions in the recursion group
   1176    if (!recGroup->finalizeDefinitions()) {
   1177      return false;
   1178    }
   1179 
   1180    // Canonicalize the recursion group
   1181    SharedRecGroup canonicalRecGroup = canonicalizeGroup(recGroup);
   1182    if (!canonicalRecGroup) {
   1183      return false;
   1184    }
   1185 
   1186    // Nothing left to do if this group became the canonical group
   1187    if (canonicalRecGroup == recGroup) {
   1188      return true;
   1189    }
   1190 
   1191    // Store the canonical group into the list
   1192    recGroups_.back() = canonicalRecGroup;
   1193 
   1194    // Overwrite all the entries we stored into the index space maps when we
   1195    // started this group.
   1196    MOZ_ASSERT(recGroup->numTypes() == canonicalRecGroup->numTypes());
   1197    for (uint32_t groupTypeIndex = 0; groupTypeIndex < recGroup->numTypes();
   1198         groupTypeIndex++) {
   1199      uint32_t typeIndex = length() - recGroup->numTypes() + groupTypeIndex;
   1200      const TypeDef* oldTypeDef = types_[typeIndex];
   1201      const TypeDef* canonTypeDef = &canonicalRecGroup->type(groupTypeIndex);
   1202 
   1203      types_[typeIndex] = canonTypeDef;
   1204      moduleIndices_.remove(oldTypeDef);
   1205 
   1206      // Ensure there is an module index entry pointing to the canonical type
   1207      // definition. Don't overwrite it if it already exists, serialization
   1208      // relies on the module index map pointing to the first occurrence of a
   1209      // type definition to avoid creating forward references that didn't exist
   1210      // in the original module.
   1211      auto canonTypeIndexEntry = moduleIndices_.lookupForAdd(canonTypeDef);
   1212      if (!canonTypeIndexEntry &&
   1213          !moduleIndices_.add(canonTypeIndexEntry, canonTypeDef, typeIndex)) {
   1214        return false;
   1215      }
   1216    }
   1217 
   1218    return true;
   1219  }
   1220 
   1221  // Add a pre-existing recursion group to this type context.
   1222  [[nodiscard]] bool addRecGroup(SharedRecGroup recGroup) {
   1223    // We must not have a pending group
   1224    MOZ_ASSERT(!pendingRecGroup_);
   1225 
   1226    // Add it to the list of groups
   1227    if (!recGroups_.append(recGroup)) {
   1228      return false;
   1229    }
   1230 
   1231    // Store the types of the group into our index space maps. These may get
   1232    // overwritten if this group is being added by `startRecGroup` and we
   1233    // overwrite it with a canonical group in `endRecGroup`. We need to do
   1234    // this before finishing though, because these entries will be used by
   1235    // decoding and error printing.
   1236    for (uint32_t groupTypeIndex = 0; groupTypeIndex < recGroup->numTypes();
   1237         groupTypeIndex++) {
   1238      const TypeDef* typeDef = &recGroup->type(groupTypeIndex);
   1239      uint32_t typeIndex = types_.length();
   1240      if (!types_.append(typeDef) || !moduleIndices_.put(typeDef, typeIndex)) {
   1241        return false;
   1242      }
   1243    }
   1244    return true;
   1245  }
   1246 
   1247  template <typename T>
   1248  [[nodiscard]] const TypeDef* addType(T&& type) {
   1249    MutableRecGroup recGroup = startRecGroup(1);
   1250    if (!recGroup) {
   1251      return nullptr;
   1252    }
   1253    recGroup->type(0) = std::move(type);
   1254    if (!endRecGroup()) {
   1255      return nullptr;
   1256    }
   1257    return &this->type(length() - 1);
   1258  }
   1259 
   1260  const TypeDef& type(uint32_t index) const { return *types_[index]; }
   1261  const TypeDef& operator[](uint32_t index) const { return *types_[index]; }
   1262 
   1263  bool empty() const { return types_.empty(); }
   1264  uint32_t length() const { return types_.length(); }
   1265 
   1266  const SharedRecGroupVector& groups() const { return recGroups_; }
   1267 
   1268  bool hasGcType() const {
   1269    for (const SharedRecGroup& recGroup : groups()) {
   1270      if (recGroup->hasGcType()) {
   1271        return true;
   1272      }
   1273    }
   1274    return false;
   1275  }
   1276 
   1277  // Map from type definition to index
   1278 
   1279  uint32_t indexOf(const TypeDef& typeDef) const {
   1280    auto moduleIndex = moduleIndices_.readonlyThreadsafeLookup(&typeDef);
   1281    MOZ_RELEASE_ASSERT(moduleIndex.found());
   1282    return moduleIndex->value();
   1283  }
   1284 };
   1285 
   1286 using SharedTypeContext = RefPtr<const TypeContext>;
   1287 using MutableTypeContext = RefPtr<TypeContext>;
   1288 
   1289 //=========================================================================
   1290 // misc
   1291 
   1292 /* static */
   1293 inline uintptr_t TypeDef::forIsoEquals(const TypeDef* typeDef,
   1294                                       const RecGroup* recGroup) {
   1295  // TypeDef is aligned sufficiently to allow a tag to distinguish a local type
   1296  // reference (index) from a non-local type reference (pointer).
   1297  static_assert(alignof(TypeDef) > 1);
   1298  MOZ_ASSERT((uintptr_t(typeDef) & 0x1) == 0);
   1299 
   1300  // Return a tagged index for local type references
   1301  if (typeDef && &typeDef->recGroup() == recGroup) {
   1302    // recGroup->indexOf result is expected to be not greater than MaxTypes,
   1303    // and shall fit in 32-bit pointer without loss.
   1304    static_assert(MaxTypes <= 0x7FFFFFFF);
   1305    return (uintptr_t(recGroup->indexOf(typeDef)) << 1) | 0x1;
   1306  }
   1307 
   1308  // Return an untagged pointer for non-local type references
   1309  return uintptr_t(typeDef);
   1310 }
   1311 
   1312 /* static */
   1313 inline IsoEqualsTypeCode IsoEqualsTypeCode::forIsoEquals(
   1314    PackedTypeCode ptc, const RecGroup* recGroup) {
   1315  IsoEqualsTypeCode mtc = {};
   1316  mtc.typeCode = PackedRepr(ptc.typeCode());
   1317  mtc.typeRef = TypeDef::forIsoEquals(ptc.typeDef(), recGroup);
   1318  mtc.nullable = ptc.isNullable();
   1319  return mtc;
   1320 }
   1321 
   1322 template <class T>
   1323 void PackedType<T>::AddRef() const {
   1324  if (!isRefType()) {
   1325    return;
   1326  }
   1327  refType().AddRef();
   1328 }
   1329 template <class T>
   1330 void PackedType<T>::Release() const {
   1331  if (!isRefType()) {
   1332    return;
   1333  }
   1334  refType().Release();
   1335 }
   1336 
   1337 void RefType::AddRef() const {
   1338  if (!isTypeRef()) {
   1339    return;
   1340  }
   1341  typeDef()->AddRef();
   1342 }
   1343 void RefType::Release() const {
   1344  if (!isTypeRef()) {
   1345    return;
   1346  }
   1347  typeDef()->Release();
   1348 }
   1349 
   1350 void TypeDef::AddRef() const { recGroup().AddRef(); }
   1351 void TypeDef::Release() const { recGroup().Release(); }
   1352 
   1353 inline RefTypeHierarchy RefType::hierarchy() const {
   1354  switch (kind()) {
   1355    case RefType::Func:
   1356    case RefType::NoFunc:
   1357      return RefTypeHierarchy::Func;
   1358    case RefType::Extern:
   1359    case RefType::NoExtern:
   1360      return RefTypeHierarchy::Extern;
   1361    case RefType::Exn:
   1362    case RefType::NoExn:
   1363      return RefTypeHierarchy::Exn;
   1364    case RefType::Any:
   1365    case RefType::None:
   1366    case RefType::I31:
   1367    case RefType::Eq:
   1368    case RefType::Struct:
   1369    case RefType::Array:
   1370      return RefTypeHierarchy::Any;
   1371    case RefType::TypeRef:
   1372      switch (typeDef()->kind()) {
   1373        case TypeDefKind::Struct:
   1374        case TypeDefKind::Array:
   1375          return RefTypeHierarchy::Any;
   1376        case TypeDefKind::Func:
   1377          return RefTypeHierarchy::Func;
   1378        case TypeDefKind::None:
   1379          MOZ_CRASH();
   1380      }
   1381  }
   1382  MOZ_CRASH("switch is exhaustive");
   1383 }
   1384 
   1385 inline TableRepr RefType::tableRepr() const {
   1386  switch (hierarchy()) {
   1387    case RefTypeHierarchy::Any:
   1388    case RefTypeHierarchy::Extern:
   1389    case RefTypeHierarchy::Exn:
   1390      return TableRepr::Ref;
   1391    case RefTypeHierarchy::Func:
   1392      return TableRepr::Func;
   1393  }
   1394  MOZ_CRASH("switch is exhaustive");
   1395 }
   1396 
   1397 inline bool RefType::isFuncHierarchy() const {
   1398  return hierarchy() == RefTypeHierarchy::Func;
   1399 }
   1400 inline bool RefType::isExternHierarchy() const {
   1401  return hierarchy() == RefTypeHierarchy::Extern;
   1402 }
   1403 inline bool RefType::isAnyHierarchy() const {
   1404  return hierarchy() == RefTypeHierarchy::Any;
   1405 }
   1406 inline bool RefType::isExnHierarchy() const {
   1407  return hierarchy() == RefTypeHierarchy::Exn;
   1408 }
   1409 
   1410 /* static */
   1411 inline bool RefType::isSubTypeOf(RefType subType, RefType superType) {
   1412  // Anything is a subtype of itself.
   1413  if (subType == superType) {
   1414    return true;
   1415  }
   1416 
   1417  // A subtype must have the same nullability as the supertype or the
   1418  // supertype must be nullable.
   1419  if (subType.isNullable() && !superType.isNullable()) {
   1420    return false;
   1421  }
   1422 
   1423  // Non type-index references are subtypes if they have the same kind
   1424  if (!subType.isTypeRef() && !superType.isTypeRef() &&
   1425      subType.kind() == superType.kind()) {
   1426    return true;
   1427  }
   1428 
   1429  // eq is a subtype of any
   1430  if (subType.isEq() && superType.isAny()) {
   1431    return true;
   1432  }
   1433 
   1434  // i31 is a subtype of eq and any
   1435  if (subType.isI31() && (superType.isAny() || superType.isEq())) {
   1436    return true;
   1437  }
   1438 
   1439  // Abstract struct/array are subtypes of eq and any
   1440  if ((subType.isStruct() || subType.isArray()) &&
   1441      (superType.isAny() || superType.isEq())) {
   1442    return true;
   1443  }
   1444 
   1445  // Concrete struct types are subtypes of struct, eq, and any
   1446  if (subType.isTypeRef() && subType.typeDef()->isStructType() &&
   1447      (superType.isAny() || superType.isEq() || superType.isStruct())) {
   1448    return true;
   1449  }
   1450 
   1451  // Concrete array types are subtypes of array, eq, and any
   1452  if (subType.isTypeRef() && subType.typeDef()->isArrayType() &&
   1453      (superType.isAny() || superType.isEq() || superType.isArray())) {
   1454    return true;
   1455  }
   1456 
   1457  // Concrete func types are subtypes of func
   1458  if (subType.isTypeRef() && subType.typeDef()->isFuncType() &&
   1459      superType.isFunc()) {
   1460    return true;
   1461  }
   1462 
   1463  // Type references can be subtypes
   1464  if (subType.isTypeRef() && superType.isTypeRef()) {
   1465    return TypeDef::isSubTypeOf(subType.typeDef(), superType.typeDef());
   1466  }
   1467 
   1468  // nofunc is the bottom type of the func hierarchy
   1469  if (subType.isNoFunc() && superType.hierarchy() == RefTypeHierarchy::Func) {
   1470    return true;
   1471  }
   1472 
   1473  // noextern is the bottom type of the extern hierarchy
   1474  if (subType.isNoExtern() &&
   1475      superType.hierarchy() == RefTypeHierarchy::Extern) {
   1476    return true;
   1477  }
   1478 
   1479  // none is the bottom type of the any hierarchy
   1480  if (subType.isNone() && superType.hierarchy() == RefTypeHierarchy::Any) {
   1481    return true;
   1482  }
   1483 
   1484  // noexn is the bottom type of the exn hierarchy
   1485  if (subType.isNoExn() && superType.hierarchy() == RefTypeHierarchy::Exn) {
   1486    return true;
   1487  }
   1488 
   1489  return false;
   1490 }
   1491 
   1492 /* static */
   1493 inline bool RefType::castPossible(RefType sourceType, RefType destType) {
   1494  // Nullable types always have null in common.
   1495  if (sourceType.isNullable() && destType.isNullable()) {
   1496    return true;
   1497  }
   1498 
   1499  // At least one of the types is non-nullable, so the only common values can be
   1500  // non-null. Therefore, if either type is a bottom type, common values are
   1501  // impossible.
   1502  if (sourceType.isRefBottom() || destType.isRefBottom()) {
   1503    return false;
   1504  }
   1505 
   1506  // After excluding bottom types, our type hierarchy is a tree, and after
   1507  // excluding nulls, subtype relationships are sufficient to tell if the types
   1508  // share any values. If neither type is a subtype of the other, then they are
   1509  // on different branches of the tree and completely disjoint.
   1510  RefType sourceNonNull = sourceType.withIsNullable(false);
   1511  RefType destNonNull = destType.withIsNullable(false);
   1512  return RefType::isSubTypeOf(sourceNonNull, destNonNull) ||
   1513         RefType::isSubTypeOf(destNonNull, sourceNonNull);
   1514 }
   1515 
   1516 //=========================================================================
   1517 // [SMDOC] Signatures and runtime types
   1518 //
   1519 // TypeIdDesc describes the runtime representation of a TypeDef suitable for
   1520 // type equality checks. The kind of representation depends on whether the type
   1521 // is a function or a GC type. This design is in flux and will evolve.
   1522 //
   1523 // # Function types
   1524 //
   1525 // For functions in the general case, a FuncType is allocated and stored in a
   1526 // process-wide hash table, so that pointer equality implies structural
   1527 // equality. This process does not correctly handle type references (which would
   1528 // require hash-consing of infinite-trees), but that's okay while
   1529 // function-references and gc-types are experimental.
   1530 //
   1531 // A pointer to the hash table entry is stored in the global data
   1532 // area for each instance, and TypeIdDesc gives the offset to this entry.
   1533 //
   1534 // ## Immediate function types
   1535 //
   1536 // As an optimization for the 99% case where the FuncType has a small number of
   1537 // parameters, the FuncType is bit-packed into a uint32 immediate value so that
   1538 // integer equality implies structural equality. Both cases can be handled with
   1539 // a single comparison by always setting the LSB for the immediates
   1540 // (the LSB is necessarily 0 for allocated FuncType pointers due to alignment).
   1541 //
   1542 // # GC types
   1543 //
   1544 // For GC types, an entry is always created in the global data area and a
   1545 // unique RttValue (see wasm/WasmGcObject.h) is stored there. This RttValue
   1546 // is the value given by 'rtt.canon $t' for each type definition. As each entry
   1547 // is given a unique value and no canonicalization is done (which would require
   1548 // hash-consing of infinite-trees), this is not yet spec compliant.
   1549 //
   1550 // # wasm::Instance and the global type context
   1551 //
   1552 // As GC objects may outlive the module they are created in, types are
   1553 // additionally transferred to a wasm::Context (which is part of JSContext) upon
   1554 // instantiation. This wasm::Context contains the 'global type context' that
   1555 // RTTValues refer to by type index. Types are never freed from the global type
   1556 // context as that would shift the index space. In the future, this will be
   1557 // fixed.
   1558 
   1559 }  // namespace wasm
   1560 }  // namespace js
   1561 
   1562 #endif  // wasm_type_def_h