@@ -96,26 +96,27 @@ class HeapType {
9696 uintptr_t id;
9797
9898public:
99- // Bit zero indicates whether the type is `shared` , so we need to leave it
100- // free .
99+ // Bits 0 and 1 are used by the Type representation , so need to be left free.
100+ // Bit 2 determines whether the basic heap type is shared (1) or unshared (0) .
101101 enum BasicHeapType : uint32_t {
102- ext = 0 << 1 ,
103- func = 1 << 1 ,
104- cont = 2 << 1 ,
105- any = 3 << 1 ,
106- eq = 4 << 1 ,
107- i31 = 5 << 1 ,
108- struct_ = 6 << 1 ,
109- array = 7 << 1 ,
110- exn = 8 << 1 ,
111- string = 9 << 1 ,
112- none = 10 << 1 ,
113- noext = 11 << 1 ,
114- nofunc = 12 << 1 ,
115- nocont = 13 << 1 ,
116- noexn = 14 << 1 ,
102+ ext = 1 << 3 ,
103+ func = 2 << 3 ,
104+ cont = 3 << 3 ,
105+ any = 4 << 3 ,
106+ eq = 5 << 3 ,
107+ i31 = 6 << 3 ,
108+ struct_ = 7 << 3 ,
109+ array = 8 << 3 ,
110+ exn = 9 << 3 ,
111+ string = 10 << 3 ,
112+ none = 11 << 3 ,
113+ noext = 12 << 3 ,
114+ nofunc = 13 << 3 ,
115+ nocont = 14 << 3 ,
116+ noexn = 15 << 3 ,
117117 };
118- static constexpr BasicHeapType _last_basic_type = BasicHeapType(noexn + 1 );
118+ static constexpr BasicHeapType _last_basic_type =
119+ BasicHeapType (noexn + (1 << 2 ));
119120
120121 // BasicHeapType can be implicitly upgraded to HeapType
121122 constexpr HeapType (BasicHeapType id) : id(id) {}
@@ -213,7 +214,7 @@ class HeapType {
213214 // Get the shared or unshared version of this basic heap type.
214215 constexpr BasicHeapType getBasic (Shareability share) const {
215216 assert (isBasic ());
216- return BasicHeapType (share == Shared ? (id | 1 ) : (id & ~1 ));
217+ return BasicHeapType (share == Shared ? (id | 4 ) : (id & ~4 ));
217218 }
218219
219220 // (In)equality must be defined for both HeapType and BasicHeapType because it
@@ -261,63 +262,29 @@ class HeapType {
261262 std::string toString () const ;
262263};
263264
264- // Internal only.
265- struct TypeInfo {
266- using type_t = Type;
267- // Used in assertions to ensure that temporary types don't leak into the
268- // global store.
269- bool isTemp = false ;
270- enum Kind {
271- TupleKind,
272- RefKind,
273- } kind;
274- struct Ref {
275- HeapType heapType;
276- Nullability nullability;
277- };
278- union {
279- Tuple tuple;
280- Ref ref;
281- };
282-
283- TypeInfo (const Tuple& tuple);
284- TypeInfo (Tuple&& tuple) : kind(TupleKind), tuple(std::move(tuple)) {}
285- TypeInfo (HeapType heapType, Nullability nullable)
286- : kind(RefKind), ref{heapType, nullable} {}
287- TypeInfo (const TypeInfo& other);
288- ~TypeInfo ();
289-
290- constexpr bool isTuple () const { return kind == TupleKind; }
291- constexpr bool isRef () const { return kind == RefKind; }
292-
293- // If this TypeInfo represents a Type that can be represented more simply,
294- // return that simpler Type. For example, this handles eliminating singleton
295- // tuple types.
296- std::optional<Type> getCanonical () const ;
297-
298- bool operator ==(const TypeInfo& other) const ;
299- bool operator !=(const TypeInfo& other) const { return !(*this == other); }
300- };
301-
302265class Type {
303266 // The `id` uniquely represents each type, so type equality is just a
304- // comparison of the ids. For basic types the `id` is just the `BasicType`
305- // enum value below, and for constructed types the `id` is the address of the
306- // canonical representation of the type, making lookups cheap for all types.
267+ // comparison of the ids. The basic types are packed at the bottom of the
268+ // expressible range, and after that tuple types are distinguished by having
269+ // bit 0 set. When that bit is masked off, they are pointers to the underlying
270+ // vectors of types. Otherwise, the type is a reference type, and is
271+ // represented as a heap type with bit 1 set iff the reference type is
272+ // nullable.
273+ //
307274 // Since `Type` is really just a single integer, it should be passed by value.
308275 // This is a uintptr_t rather than a TypeID (uint64_t) to save memory on
309276 // 32-bit platforms.
310277 uintptr_t id;
311278
312279public:
313280 enum BasicType : uint32_t {
314- none,
315- unreachable,
316- i32 ,
317- i64 ,
318- f32 ,
319- f64 ,
320- v128,
281+ none = 0 ,
282+ unreachable = 1 ,
283+ i32 = 2 ,
284+ i64 = 3 ,
285+ f32 = 4 ,
286+ f64 = 5 ,
287+ v128 = 6 ,
321288 };
322289 static constexpr BasicType _last_basic_type = v128;
323290
@@ -338,7 +305,8 @@ class Type {
338305
339306 // Construct from a heap type description. Also covers construction from
340307 // Signature, Struct or Array via implicit conversion to HeapType.
341- Type (HeapType, Nullability nullable);
308+ Type (HeapType heapType, Nullability nullable)
309+ : Type(heapType.getID() | (nullable == Nullable ? 2 : 0 )) {}
342310
343311 // Predicates
344312 // Compound Concrete
@@ -376,74 +344,37 @@ class Type {
376344 // Tuples, refs, etc. are quickly handled using isBasic(), leaving the non-
377345 // basic case for the underlying implementation.
378346
379- bool isTuple () const {
380- if (isBasic ()) {
381- return false ;
382- } else {
383- return getTypeInfo (*this )->isTuple ();
384- }
385- }
386-
387- bool isRef () const {
388- if (isBasic ()) {
389- return false ;
390- } else {
391- return getTypeInfo (*this )->isRef ();
392- }
393- }
394-
395- bool isFunction () const {
396- if (isBasic ()) {
397- return false ;
398- } else {
399- auto * info = getTypeInfo (*this );
400- return info->isRef () && info->ref .heapType .isFunction ();
401- }
402- }
403-
404- bool isData () const {
405- if (isBasic ()) {
406- return false ;
407- } else {
408- auto * info = getTypeInfo (*this );
409- return info->isRef () && info->ref .heapType .isData ();
410- }
411- }
412-
413- // Checks whether a type is a reference and is nullable. This returns false
414- // for a value that is not a reference, that is, for which nullability is
415- // irrelevant.
416- bool isNullable () const {
417- if (isRef ()) {
418- return getTypeInfo (*this )->ref .nullability == Nullable;
419- } else {
420- return false ;
421- }
347+ // TODO: Experiment with leaving bit 0 free in basic types.
348+ bool isTuple () const { return !isBasic () && (id & 1 ); }
349+ const Tuple& getTuple () const {
350+ assert (isTuple ());
351+ return *(Tuple*)(id & ~1 );
422352 }
423353
424- // Checks whether a type is a reference and is non-nullable. This returns
425- // false for a value that is not a reference, that is, for which nullability
426- // is irrelevant. (For that reason, this is only the negation of isNullable()
427- // on references, but both return false on non-references.)
428- bool isNonNullable () const {
429- if (isRef ()) {
430- return getTypeInfo (*this )->ref .nullability == NonNullable;
431- } else {
432- return false ;
433- }
354+ bool isRef () const { return !isBasic () && !(id & 1 ); }
355+ bool isNullable () const { return isRef () && (id & 2 ); }
356+ bool isNonNullable () const { return isRef () && !(id & 2 ); }
357+ HeapType getHeapType () const {
358+ assert (isRef ());
359+ return HeapType (id & ~2 );
434360 }
435361
362+ bool isFunction () const { return isRef () && getHeapType ().isFunction (); }
436363 bool isSignature () const { return isRef () && getHeapType ().isSignature (); }
364+ bool isData () const { return isRef () && getHeapType ().isData (); }
437365
438366 // Whether this type is only inhabited by null values.
439- bool isNull () const ;
440- bool isStruct () const ;
441- bool isArray () const ;
442- bool isExn () const ;
443- bool isString () const ;
367+ bool isNull () const { return isRef () && getHeapType (). isBottom (); }
368+ bool isStruct () const { return isRef () && getHeapType (). isStruct (); }
369+ bool isArray () const { return isRef () && getHeapType (). isArray (); }
370+ bool isExn () const { return isRef () && getHeapType (). isExn (); }
371+ bool isString () const { return isRef () && getHeapType (). isString (); }
444372 bool isDefaultable () const ;
445373
446- Nullability getNullability () const ;
374+ // TODO: Allow this only for reference types.
375+ Nullability getNullability () const {
376+ return isNullable () ? Nullable : NonNullable;
377+ }
447378
448379private:
449380 template <bool (Type::*pred)() const > bool hasPredicate () {
@@ -489,20 +420,6 @@ class Type {
489420 // Returns the feature set required to use this type.
490421 FeatureSet getFeatures () const ;
491422
492- // Returns the tuple, assuming that this is a tuple type. Note that it is
493- // normally simpler to use operator[] and size() on the Type directly.
494- HeapType getHeapType () const {
495- assert (isRef ());
496- return getTypeInfo (*this )->ref .heapType ;
497- }
498-
499- // Gets the heap type corresponding to this type, assuming that it is a
500- // reference type.
501- const Tuple& getTuple () const {
502- assert (isTuple ());
503- return getTypeInfo (*this )->tuple ;
504- }
505-
506423 // Returns a number type based on its size in bytes and whether it is a float
507424 // type.
508425 static Type get (unsigned byteSize, bool float_);
@@ -565,7 +482,9 @@ class Type {
565482
566483 std::string toString () const ;
567484
568- size_t size () const ;
485+ size_t size () const {
486+ return isTuple () ? getTuple ().size () : size_t (id != Type::none);
487+ }
569488
570489 struct Iterator : ParentIndexIterator<const Type*, Iterator> {
571490 using value_type = Type;
@@ -583,15 +502,8 @@ class Type {
583502 return std::make_reverse_iterator (begin ());
584503 }
585504 const Type& operator [](size_t i) const { return *Iterator{{this , i}}; }
586-
587- static TypeInfo* getTypeInfo (Type type) {
588- assert (!type.isBasic ());
589- return (TypeInfo*)type.getID ();
590- }
591505};
592506
593- inline bool Type::isNull () const { return isRef () && getHeapType ().isBottom (); }
594-
595507namespace HeapTypes {
596508
597509constexpr HeapType ext = HeapType::ext;
0 commit comments