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 "wasm/WasmCompileArgs.h"
23 #include "wasm/WasmSerialize.h"
24 #include "wasm/WasmUtility.h"
25 #include "wasm/WasmValType.h"
26 
27 namespace js {
28 namespace wasm {
29 
30 using mozilla::MallocSizeOf;
31 
32 // The FuncType class represents a WebAssembly function signature which takes a
33 // list of value types and returns an expression type. The engine uses two
34 // in-memory representations of the argument Vector's memory (when elements do
35 // not fit inline): normal malloc allocation (via SystemAllocPolicy) and
36 // allocation in a LifoAlloc (via LifoAllocPolicy). The former FuncType objects
37 // can have any lifetime since they own the memory. The latter FuncType objects
38 // must not outlive the associated LifoAlloc mark/release interval (which is
39 // currently the duration of module validation+compilation). Thus, long-lived
40 // objects like WasmModule must use malloced allocation.
41 
42 class FuncType {
43   ValTypeVector args_;
44   ValTypeVector results_;
45 
46   // Entry from JS to wasm via the JIT is currently unimplemented for
47   // functions that return multiple values.
temporarilyUnsupportedResultCountForJitEntry()48   bool temporarilyUnsupportedResultCountForJitEntry() const {
49     return results().length() > MaxResultsForJitEntry;
50   }
51   // Calls out from wasm to JS that return multiple values is currently
52   // unsupported.
temporarilyUnsupportedResultCountForJitExit()53   bool temporarilyUnsupportedResultCountForJitExit() const {
54     return results().length() > MaxResultsForJitExit;
55   }
56   // For JS->wasm jit entries, temporarily disallow certain types until the
57   // stubs generator is improved.
58   //   * ref params may be nullable externrefs
59   //   * ref results may not be type indices
60   // V128 types are excluded per spec but are guarded against separately.
temporarilyUnsupportedReftypeForEntry()61   bool temporarilyUnsupportedReftypeForEntry() const {
62     for (ValType arg : args()) {
63       if (arg.isReference() && (!arg.isExternRef() || !arg.isNullable())) {
64         return true;
65       }
66     }
67     for (ValType result : results()) {
68       if (result.isTypeIndex()) {
69         return true;
70       }
71     }
72     return false;
73   }
74   // For wasm->JS jit exits, temporarily disallow certain types until
75   // the stubs generator is improved.
76   //   * ref results may be nullable externrefs
77   // Unexposable types must be guarded against separately.
temporarilyUnsupportedReftypeForExit()78   bool temporarilyUnsupportedReftypeForExit() const {
79     for (ValType result : results()) {
80       if (result.isReference() &&
81           (!result.isExternRef() || !result.isNullable())) {
82         return true;
83       }
84     }
85     return false;
86   }
87 
88  public:
FuncType()89   FuncType() : args_(), results_() {}
FuncType(ValTypeVector && args,ValTypeVector && results)90   FuncType(ValTypeVector&& args, ValTypeVector&& results)
91       : args_(std::move(args)), results_(std::move(results)) {}
92 
clone(const FuncType & src)93   [[nodiscard]] bool clone(const FuncType& src) {
94     MOZ_ASSERT(args_.empty());
95     MOZ_ASSERT(results_.empty());
96     return args_.appendAll(src.args_) && results_.appendAll(src.results_);
97   }
98 
renumber(const RenumberMap & map)99   void renumber(const RenumberMap& map) {
100     for (auto& arg : args_) {
101       arg.renumber(map);
102     }
103     for (auto& result : results_) {
104       result.renumber(map);
105     }
106   }
offsetTypeIndex(uint32_t offsetBy)107   void offsetTypeIndex(uint32_t offsetBy) {
108     for (auto& arg : args_) {
109       arg.offsetTypeIndex(offsetBy);
110     }
111     for (auto& result : results_) {
112       result.offsetTypeIndex(offsetBy);
113     }
114   }
115 
arg(unsigned i)116   ValType arg(unsigned i) const { return args_[i]; }
args()117   const ValTypeVector& args() const { return args_; }
result(unsigned i)118   ValType result(unsigned i) const { return results_[i]; }
results()119   const ValTypeVector& results() const { return results_; }
120 
hash()121   HashNumber hash() const {
122     HashNumber hn = 0;
123     for (const ValType& vt : args_) {
124       hn = mozilla::AddToHash(hn, HashNumber(vt.packed().bits()));
125     }
126     for (const ValType& vt : results_) {
127       hn = mozilla::AddToHash(hn, HashNumber(vt.packed().bits()));
128     }
129     return hn;
130   }
131   bool operator==(const FuncType& rhs) const {
132     return EqualContainers(args(), rhs.args()) &&
133            EqualContainers(results(), rhs.results());
134   }
135   bool operator!=(const FuncType& rhs) const { return !(*this == rhs); }
136 
137   bool canHaveJitEntry() const;
138   bool canHaveJitExit() const;
139 
hasUnexposableArgOrRet()140   bool hasUnexposableArgOrRet() const {
141     for (ValType arg : args()) {
142       if (!arg.isExposable()) {
143         return true;
144       }
145     }
146     for (ValType result : results()) {
147       if (!result.isExposable()) {
148         return true;
149       }
150     }
151     return false;
152   }
153 
154 #ifdef WASM_PRIVATE_REFTYPES
exposesTypeIndex()155   bool exposesTypeIndex() const {
156     for (const ValType& arg : args()) {
157       if (arg.isTypeIndex()) {
158         return true;
159       }
160     }
161     for (const ValType& result : results()) {
162       if (result.isTypeIndex()) {
163         return true;
164       }
165     }
166     return false;
167   }
168 #endif
169 
170   WASM_DECLARE_SERIALIZABLE(FuncType)
171 };
172 
173 struct FuncTypeHashPolicy {
174   using Lookup = const FuncType&;
hashFuncTypeHashPolicy175   static HashNumber hash(Lookup ft) { return ft.hash(); }
matchFuncTypeHashPolicy176   static bool match(const FuncType* lhs, Lookup rhs) { return *lhs == rhs; }
177 };
178 
179 // Structure type.
180 //
181 // The Module owns a dense array of StructType values that represent the
182 // structure types that the module knows about.  It is created from the sparse
183 // array of types in the ModuleEnvironment when the Module is created.
184 
185 struct StructField {
186   FieldType type;
187   uint32_t offset;
188   bool isMutable;
189 };
190 
191 using StructFieldVector = Vector<StructField, 0, SystemAllocPolicy>;
192 
193 class StructType {
194  public:
195   StructFieldVector fields_;  // Field type, offset, and mutability
196   uint32_t size_;             // The size of the type in bytes.
197 
198  public:
StructType()199   StructType() : fields_(), size_(0) {}
200 
StructType(StructFieldVector && fields)201   explicit StructType(StructFieldVector&& fields)
202       : fields_(std::move(fields)), size_(0) {}
203 
204   StructType(StructType&&) = default;
205   StructType& operator=(StructType&&) = default;
206 
clone(const StructType & src)207   [[nodiscard]] bool clone(const StructType& src) {
208     if (!fields_.appendAll(src.fields_)) {
209       return false;
210     }
211     size_ = src.size_;
212     return true;
213   }
214 
renumber(const RenumberMap & map)215   void renumber(const RenumberMap& map) {
216     for (auto& field : fields_) {
217       field.type.renumber(map);
218     }
219   }
offsetTypeIndex(uint32_t offsetBy)220   void offsetTypeIndex(uint32_t offsetBy) {
221     for (auto& field : fields_) {
222       field.type.offsetTypeIndex(offsetBy);
223     }
224   }
225 
isDefaultable()226   bool isDefaultable() const {
227     for (auto& field : fields_) {
228       if (!field.type.isDefaultable()) {
229         return false;
230       }
231     }
232     return true;
233   }
234   [[nodiscard]] bool computeLayout();
235 
236   WASM_DECLARE_SERIALIZABLE(StructType)
237 };
238 
239 using StructTypeVector = Vector<StructType, 0, SystemAllocPolicy>;
240 using StructTypePtrVector = Vector<const StructType*, 0, SystemAllocPolicy>;
241 
242 // Array type
243 
244 class ArrayType {
245  public:
246   FieldType elementType_;  // field type
247   bool isMutable_;         // mutability
248 
249  public:
ArrayType(FieldType elementType,bool isMutable)250   ArrayType(FieldType elementType, bool isMutable)
251       : elementType_(elementType), isMutable_(isMutable) {}
252 
253   ArrayType(const ArrayType&) = default;
254   ArrayType& operator=(const ArrayType&) = default;
255 
256   ArrayType(ArrayType&&) = default;
257   ArrayType& operator=(ArrayType&&) = default;
258 
clone(const ArrayType & src)259   [[nodiscard]] bool clone(const ArrayType& src) {
260     elementType_ = src.elementType_;
261     isMutable_ = src.isMutable_;
262     return true;
263   }
264 
renumber(const RenumberMap & map)265   void renumber(const RenumberMap& map) { elementType_.renumber(map); }
offsetTypeIndex(uint32_t offsetBy)266   void offsetTypeIndex(uint32_t offsetBy) {
267     elementType_.offsetTypeIndex(offsetBy);
268   }
269 
isDefaultable()270   bool isDefaultable() const { return elementType_.isDefaultable(); }
271 
272   WASM_DECLARE_SERIALIZABLE(ArrayType)
273 };
274 
275 using ArrayTypeVector = Vector<ArrayType, 0, SystemAllocPolicy>;
276 using ArrayTypePtrVector = Vector<const ArrayType*, 0, SystemAllocPolicy>;
277 
278 // A tagged container for the various types that can be present in a wasm
279 // module's type section.
280 
281 enum class TypeDefKind : uint8_t {
282   None = 0,
283   Func,
284   Struct,
285   Array,
286 };
287 
288 class TypeDef {
289   TypeDefKind kind_;
290   union {
291     FuncType funcType_;
292     StructType structType_;
293     ArrayType arrayType_;
294   };
295 
296  public:
TypeDef()297   TypeDef() : kind_(TypeDefKind::None) {}
298 
TypeDef(FuncType && funcType)299   explicit TypeDef(FuncType&& funcType)
300       : kind_(TypeDefKind::Func), funcType_(std::move(funcType)) {}
301 
TypeDef(StructType && structType)302   explicit TypeDef(StructType&& structType)
303       : kind_(TypeDefKind::Struct), structType_(std::move(structType)) {}
304 
TypeDef(ArrayType && arrayType)305   explicit TypeDef(ArrayType&& arrayType)
306       : kind_(TypeDefKind::Array), arrayType_(std::move(arrayType)) {}
307 
TypeDef(TypeDef && td)308   TypeDef(TypeDef&& td) noexcept : kind_(td.kind_) {
309     switch (kind_) {
310       case TypeDefKind::Func:
311         new (&funcType_) FuncType(std::move(td.funcType_));
312         break;
313       case TypeDefKind::Struct:
314         new (&structType_) StructType(std::move(td.structType_));
315         break;
316       case TypeDefKind::Array:
317         new (&arrayType_) ArrayType(std::move(td.arrayType_));
318         break;
319       case TypeDefKind::None:
320         break;
321     }
322   }
323 
~TypeDef()324   ~TypeDef() {
325     switch (kind_) {
326       case TypeDefKind::Func:
327         funcType_.~FuncType();
328         break;
329       case TypeDefKind::Struct:
330         structType_.~StructType();
331         break;
332       case TypeDefKind::Array:
333         arrayType_.~ArrayType();
334         break;
335       case TypeDefKind::None:
336         break;
337     }
338   }
339 
340   TypeDef& operator=(TypeDef&& that) noexcept {
341     MOZ_ASSERT(isNone());
342     switch (that.kind_) {
343       case TypeDefKind::Func:
344         new (&funcType_) FuncType(std::move(that.funcType_));
345         break;
346       case TypeDefKind::Struct:
347         new (&structType_) StructType(std::move(that.structType_));
348         break;
349       case TypeDefKind::Array:
350         new (&arrayType_) ArrayType(std::move(that.arrayType_));
351         break;
352       case TypeDefKind::None:
353         break;
354     }
355     kind_ = that.kind_;
356     return *this;
357   }
358 
clone(const TypeDef & src)359   [[nodiscard]] bool clone(const TypeDef& src) {
360     MOZ_ASSERT(isNone());
361     kind_ = src.kind_;
362     switch (src.kind_) {
363       case TypeDefKind::Func:
364         new (&funcType_) FuncType();
365         return funcType_.clone(src.funcType());
366       case TypeDefKind::Struct:
367         new (&structType_) StructType();
368         return structType_.clone(src.structType());
369       case TypeDefKind::Array:
370         new (&arrayType_) ArrayType(src.arrayType());
371         return true;
372       case TypeDefKind::None:
373         break;
374     }
375     MOZ_ASSERT_UNREACHABLE();
376     return false;
377   }
378 
kind()379   TypeDefKind kind() const { return kind_; }
380 
isNone()381   bool isNone() const { return kind_ == TypeDefKind::None; }
382 
isFuncType()383   bool isFuncType() const { return kind_ == TypeDefKind::Func; }
384 
isStructType()385   bool isStructType() const { return kind_ == TypeDefKind::Struct; }
386 
isArrayType()387   bool isArrayType() const { return kind_ == TypeDefKind::Array; }
388 
funcType()389   const FuncType& funcType() const {
390     MOZ_ASSERT(isFuncType());
391     return funcType_;
392   }
393 
funcType()394   FuncType& funcType() {
395     MOZ_ASSERT(isFuncType());
396     return funcType_;
397   }
398 
structType()399   const StructType& structType() const {
400     MOZ_ASSERT(isStructType());
401     return structType_;
402   }
403 
structType()404   StructType& structType() {
405     MOZ_ASSERT(isStructType());
406     return structType_;
407   }
408 
arrayType()409   const ArrayType& arrayType() const {
410     MOZ_ASSERT(isArrayType());
411     return arrayType_;
412   }
413 
arrayType()414   ArrayType& arrayType() {
415     MOZ_ASSERT(isArrayType());
416     return arrayType_;
417   }
418 
renumber(const RenumberMap & map)419   void renumber(const RenumberMap& map) {
420     switch (kind_) {
421       case TypeDefKind::Func:
422         funcType_.renumber(map);
423         break;
424       case TypeDefKind::Struct:
425         structType_.renumber(map);
426         break;
427       case TypeDefKind::Array:
428         arrayType_.renumber(map);
429         break;
430       case TypeDefKind::None:
431         break;
432     }
433   }
offsetTypeIndex(uint32_t offsetBy)434   void offsetTypeIndex(uint32_t offsetBy) {
435     switch (kind_) {
436       case TypeDefKind::Func:
437         funcType_.offsetTypeIndex(offsetBy);
438         break;
439       case TypeDefKind::Struct:
440         structType_.offsetTypeIndex(offsetBy);
441         break;
442       case TypeDefKind::Array:
443         arrayType_.offsetTypeIndex(offsetBy);
444         break;
445       case TypeDefKind::None:
446         break;
447     }
448   }
449 
450   WASM_DECLARE_SERIALIZABLE(TypeDef)
451 };
452 
453 using TypeDefVector = Vector<TypeDef, 0, SystemAllocPolicy>;
454 
455 template <typename T>
456 using DerivedTypeDefVector = Vector<T, 0, SystemAllocPolicy>;
457 
458 // A type cache maintains a cache of equivalence and subtype relations between
459 // wasm types. This is required for the computation of equivalence and subtyping
460 // on recursive types.
461 //
462 // This class is not thread-safe and so must exist separately from TypeContext,
463 // which may be shared between multiple threads.
464 
465 class TypeCache {
466   using TypeIndex = uint32_t;
467   using TypePair = uint64_t;
468   using TypeSet = HashSet<TypePair, DefaultHasher<TypePair>, SystemAllocPolicy>;
469 
470   // Generates a hash key for the ordered pair (a, b).
makeOrderedPair(TypeIndex a,TypeIndex b)471   static constexpr TypePair makeOrderedPair(TypeIndex a, TypeIndex b) {
472     return (TypePair(a) << 32) | TypePair(b);
473   }
474 
475   // Generates a hash key for the unordered pair (a, b).
makeUnorderedPair(TypeIndex a,TypeIndex b)476   static constexpr TypePair makeUnorderedPair(TypeIndex a, TypeIndex b) {
477     if (a < b) {
478       return (TypePair(a) << 32) | TypePair(b);
479     }
480     return (TypePair(b) << 32) | TypePair(a);
481   }
482 
483   TypeSet equivalence_;
484   TypeSet subtype_;
485 
486  public:
487   TypeCache() = default;
488 
489   // Mark `a` as equivalent to `b` in the equivalence cache.
markEquivalent(TypeIndex a,TypeIndex b)490   [[nodiscard]] bool markEquivalent(TypeIndex a, TypeIndex b) {
491     return equivalence_.put(makeUnorderedPair(a, b));
492   }
493   // Unmark `a` as equivalent to `b` in the equivalence cache
unmarkEquivalent(TypeIndex a,TypeIndex b)494   void unmarkEquivalent(TypeIndex a, TypeIndex b) {
495     equivalence_.remove(makeUnorderedPair(a, b));
496   }
497 
498   // Check if `a` is equivalent to `b` in the equivalence cache
isEquivalent(TypeIndex a,TypeIndex b)499   bool isEquivalent(TypeIndex a, TypeIndex b) {
500     return equivalence_.has(makeUnorderedPair(a, b));
501   }
502 
503   // Mark `a` as a subtype of `b` in the subtype cache
markSubtypeOf(TypeIndex a,TypeIndex b)504   [[nodiscard]] bool markSubtypeOf(TypeIndex a, TypeIndex b) {
505     return subtype_.put(makeOrderedPair(a, b));
506   }
507   // Unmark `a` as a subtype of `b` in the subtype cache
unmarkSubtypeOf(TypeIndex a,TypeIndex b)508   void unmarkSubtypeOf(TypeIndex a, TypeIndex b) {
509     subtype_.remove(makeOrderedPair(a, b));
510   }
511   // Check if `a` is a subtype of `b` in the subtype cache
isSubtypeOf(TypeIndex a,TypeIndex b)512   bool isSubtypeOf(TypeIndex a, TypeIndex b) {
513     return subtype_.has(makeOrderedPair(a, b));
514   }
515 };
516 
517 // The result of an equivalence or subtyping check between types.
518 enum class TypeResult {
519   True,
520   False,
521   OOM,
522 };
523 
524 // A type context maintains an index space for TypeDef's that can be used to
525 // give ValType's meaning. It is used during compilation for modules, and
526 // during runtime for all instances.
527 
528 class TypeContext {
529   FeatureArgs features_;
530   TypeDefVector types_;
531 
532  public:
TypeContext(const FeatureArgs & features,TypeDefVector && types)533   TypeContext(const FeatureArgs& features, TypeDefVector&& types)
534       : features_(features), types_(std::move(types)) {}
535 
sizeOfExcludingThis(MallocSizeOf mallocSizeOf)536   size_t sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const {
537     return types_.sizeOfExcludingThis(mallocSizeOf);
538   }
539 
540   // Disallow copy, allow move initialization
541   TypeContext(const TypeContext&) = delete;
542   TypeContext& operator=(const TypeContext&) = delete;
543   TypeContext(TypeContext&&) = default;
544   TypeContext& operator=(TypeContext&&) = default;
545 
type(uint32_t index)546   TypeDef& type(uint32_t index) { return types_[index]; }
type(uint32_t index)547   const TypeDef& type(uint32_t index) const { return types_[index]; }
548 
549   TypeDef& operator[](uint32_t index) { return types_[index]; }
550   const TypeDef& operator[](uint32_t index) const { return types_[index]; }
551 
length()552   uint32_t length() const { return types_.length(); }
553 
554   template <typename U>
append(U && typeDef)555   [[nodiscard]] bool append(U&& typeDef) {
556     return types_.append(std::forward<U>(typeDef));
557   }
resize(uint32_t length)558   [[nodiscard]] bool resize(uint32_t length) { return types_.resize(length); }
559 
560   template <typename T>
transferTypes(const DerivedTypeDefVector<T> & types,uint32_t * baseIndex)561   [[nodiscard]] bool transferTypes(const DerivedTypeDefVector<T>& types,
562                                    uint32_t* baseIndex) {
563     *baseIndex = length();
564     if (!resize(*baseIndex + types.length())) {
565       return false;
566     }
567     for (uint32_t i = 0; i < types.length(); i++) {
568       if (!types_[*baseIndex + i].clone(types[i])) {
569         return false;
570       }
571       types_[*baseIndex + i].offsetTypeIndex(*baseIndex);
572     }
573     return true;
574   }
575 
576   // FuncType accessors
577 
isFuncType(uint32_t index)578   bool isFuncType(uint32_t index) const { return types_[index].isFuncType(); }
isFuncType(RefType t)579   bool isFuncType(RefType t) const {
580     return t.isTypeIndex() && isFuncType(t.typeIndex());
581   }
582 
funcType(uint32_t index)583   FuncType& funcType(uint32_t index) { return types_[index].funcType(); }
funcType(uint32_t index)584   const FuncType& funcType(uint32_t index) const {
585     return types_[index].funcType();
586   }
funcType(RefType t)587   FuncType& funcType(RefType t) { return funcType(t.typeIndex()); }
funcType(RefType t)588   const FuncType& funcType(RefType t) const { return funcType(t.typeIndex()); }
589 
590   // StructType accessors
591 
isStructType(uint32_t index)592   bool isStructType(uint32_t index) const {
593     return types_[index].isStructType();
594   }
isStructType(RefType t)595   bool isStructType(RefType t) const {
596     return t.isTypeIndex() && isStructType(t.typeIndex());
597   }
598 
structType(uint32_t index)599   StructType& structType(uint32_t index) { return types_[index].structType(); }
structType(uint32_t index)600   const StructType& structType(uint32_t index) const {
601     return types_[index].structType();
602   }
structType(RefType t)603   StructType& structType(RefType t) { return structType(t.typeIndex()); }
structType(RefType t)604   const StructType& structType(RefType t) const {
605     return structType(t.typeIndex());
606   }
607 
608   // StructType accessors
609 
isArrayType(uint32_t index)610   bool isArrayType(uint32_t index) const { return types_[index].isArrayType(); }
isArrayType(RefType t)611   bool isArrayType(RefType t) const {
612     return t.isTypeIndex() && isArrayType(t.typeIndex());
613   }
614 
arrayType(uint32_t index)615   ArrayType& arrayType(uint32_t index) { return types_[index].arrayType(); }
arrayType(uint32_t index)616   const ArrayType& arrayType(uint32_t index) const {
617     return types_[index].arrayType();
618   }
arrayType(RefType t)619   ArrayType& arrayType(RefType t) { return arrayType(t.typeIndex()); }
arrayType(RefType t)620   const ArrayType& arrayType(RefType t) const {
621     return arrayType(t.typeIndex());
622   }
623 
624   // Type equivalence
625 
626   template <class T>
isEquivalent(T one,T two,TypeCache * cache)627   TypeResult isEquivalent(T one, T two, TypeCache* cache) const {
628     // Anything's equal to itself.
629     if (one == two) {
630       return TypeResult::True;
631     }
632 
633     // A reference may be equal to another reference
634     if (one.isReference() && two.isReference()) {
635       return isRefEquivalent(one.refType(), two.refType(), cache);
636     }
637 
638 #ifdef ENABLE_WASM_GC
639     // An rtt may be a equal to another rtt
640     if (one.isRtt() && two.isRtt()) {
641       return isTypeIndexEquivalent(one.typeIndex(), two.typeIndex(), cache);
642     }
643 #endif
644 
645     return TypeResult::False;
646   }
647 
648   TypeResult isRefEquivalent(RefType one, RefType two, TypeCache* cache) const;
649 #ifdef ENABLE_WASM_FUNCTION_REFERENCES
650   TypeResult isTypeIndexEquivalent(uint32_t one, uint32_t two,
651                                    TypeCache* cache) const;
652 #endif
653 #ifdef ENABLE_WASM_GC
654   TypeResult isStructEquivalent(uint32_t oneIndex, uint32_t twoIndex,
655                                 TypeCache* cache) const;
656   TypeResult isStructFieldEquivalent(const StructField one,
657                                      const StructField two,
658                                      TypeCache* cache) const;
659   TypeResult isArrayEquivalent(uint32_t oneIndex, uint32_t twoIndex,
660                                TypeCache* cache) const;
661   TypeResult isArrayElementEquivalent(const ArrayType& one,
662                                       const ArrayType& two,
663                                       TypeCache* cache) const;
664 #endif
665 
666   // Subtyping
667 
668   template <class T>
isSubtypeOf(T one,T two,TypeCache * cache)669   TypeResult isSubtypeOf(T one, T two, TypeCache* cache) const {
670     // Anything's a subtype of itself.
671     if (one == two) {
672       return TypeResult::True;
673     }
674 
675     // A reference may be a subtype of another reference
676     if (one.isReference() && two.isReference()) {
677       return isRefSubtypeOf(one.refType(), two.refType(), cache);
678     }
679 
680     // An rtt may be a subtype of another rtt
681 #ifdef ENABLE_WASM_GC
682     if (one.isRtt() && two.isRtt()) {
683       return isTypeIndexEquivalent(one.typeIndex(), two.typeIndex(), cache);
684     }
685 #endif
686 
687     return TypeResult::False;
688   }
689 
690   TypeResult isRefSubtypeOf(RefType one, RefType two, TypeCache* cache) const;
691 #ifdef ENABLE_WASM_FUNCTION_REFERENCES
692   TypeResult isTypeIndexSubtypeOf(uint32_t one, uint32_t two,
693                                   TypeCache* cache) const;
694 #endif
695 
696 #ifdef ENABLE_WASM_GC
697   TypeResult isStructSubtypeOf(uint32_t oneIndex, uint32_t twoIndex,
698                                TypeCache* cache) const;
699   TypeResult isStructFieldSubtypeOf(const StructField one,
700                                     const StructField two,
701                                     TypeCache* cache) const;
702   TypeResult isArraySubtypeOf(uint32_t oneIndex, uint32_t twoIndex,
703                               TypeCache* cache) const;
704   TypeResult isArrayElementSubtypeOf(const ArrayType& one, const ArrayType& two,
705                                      TypeCache* cache) const;
706 #endif
707 };
708 
709 class TypeHandle {
710  private:
711   uint32_t index_;
712 
713  public:
TypeHandle(uint32_t index)714   explicit TypeHandle(uint32_t index) : index_(index) {}
715 
716   TypeHandle(const TypeHandle&) = default;
717   TypeHandle& operator=(const TypeHandle&) = default;
718 
get(TypeContext * tycx)719   TypeDef& get(TypeContext* tycx) const { return tycx->type(index_); }
get(const TypeContext * tycx)720   const TypeDef& get(const TypeContext* tycx) const {
721     return tycx->type(index_);
722   }
723 
index()724   uint32_t index() const { return index_; }
725 };
726 
727 }  // namespace wasm
728 }  // namespace js
729 
730 #endif  // wasm_type_def_h
731