summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tools/fuzzing/fuzzing.cpp5
-rw-r--r--src/tools/fuzzing/heap-types.cpp227
-rw-r--r--src/tools/wasm-fuzz-types.cpp3
-rw-r--r--src/wasm-features.h5
-rw-r--r--test/lit/fuzz-types.test86
5 files changed, 182 insertions, 144 deletions
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index 6b54ac56d..555de5db1 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -246,8 +246,11 @@ void TranslateToFuzzReader::setupHeapTypes() {
// For GC, also generate random types.
if (wasm.features.hasGC()) {
+ // Do not generate shared types until the fuzzer can be updated to handle
+ // them.
+ auto features = wasm.features - FeatureSet::SharedEverything;
auto generator =
- HeapTypeGenerator::create(random, wasm.features, upTo(MAX_NEW_GC_TYPES));
+ HeapTypeGenerator::create(random, features, upTo(MAX_NEW_GC_TYPES));
auto result = generator.builder.build();
if (auto* err = result.getError()) {
Fatal() << "Failed to build heap types: " << err->reason << " at index "
diff --git a/src/tools/fuzzing/heap-types.cpp b/src/tools/fuzzing/heap-types.cpp
index 127d4f5ba..a1c879b42 100644
--- a/src/tools/fuzzing/heap-types.cpp
+++ b/src/tools/fuzzing/heap-types.cpp
@@ -62,8 +62,8 @@ struct HeapTypeGeneratorImpl {
supertypeIndices(n), rand(rand), features(features) {
// Set up the subtype relationships. Start with some number of root types,
// then after that start creating subtypes of existing types. Determine the
- // top-level kind of each type in advance so that we can appropriately use
- // types we haven't constructed yet.
+ // top-level kind and shareability of each type in advance so that we can
+ // appropriately use types we haven't constructed yet.
typeKinds.reserve(builder.size());
supertypeIndices.reserve(builder.size());
Index numRoots = 1 + rand.upTo(builder.size());
@@ -74,11 +74,14 @@ struct HeapTypeGeneratorImpl {
if (i < numRoots || rand.oneIn(2)) {
// This is a root type with no supertype. Choose a kind for this type.
typeKinds.emplace_back(generateHeapTypeKind());
+ builder[i].setShared(
+ !features.hasSharedEverything() || rand.oneIn(2) ? Unshared : Shared);
} else {
// This is a subtype. Choose one of the previous types to be the
// supertype.
Index super = rand.upTo(i);
builder[i].subTypeOf(builder[super]);
+ builder[i].setShared(HeapType(builder[super]).getShared());
supertypeIndices[i] = super;
subtypeIndices[super].push_back(i);
typeKinds.push_back(typeKinds[super]);
@@ -113,14 +116,15 @@ struct HeapTypeGeneratorImpl {
// Create the heap types.
for (; index < builder.size(); ++index) {
auto kind = typeKinds[index];
+ auto share = HeapType(builder[index]).getShared();
if (!supertypeIndices[index]) {
// No nontrivial supertype, so create a root type.
if (std::get_if<SignatureKind>(&kind)) {
builder[index] = generateSignature();
} else if (std::get_if<StructKind>(&kind)) {
- builder[index] = generateStruct();
+ builder[index] = generateStruct(share);
} else if (std::get_if<ArrayKind>(&kind)) {
- builder[index] = generateArray();
+ builder[index] = generateArray(share);
} else {
WASM_UNREACHABLE("unexpected kind");
}
@@ -130,7 +134,7 @@ struct HeapTypeGeneratorImpl {
if (supertype.isSignature()) {
builder[index] = generateSubSignature(supertype.getSignature());
} else if (supertype.isStruct()) {
- builder[index] = generateSubStruct(supertype.getStruct());
+ builder[index] = generateSubStruct(supertype.getStruct(), share);
} else if (supertype.isArray()) {
builder[index] = generateSubArray(supertype.getArray());
} else {
@@ -140,19 +144,25 @@ struct HeapTypeGeneratorImpl {
}
}
- HeapType::BasicHeapType generateBasicHeapType() {
+ HeapType::BasicHeapType generateBasicHeapType(Shareability share) {
// Choose bottom types more rarely.
+ // TODO: string, exn, and cont types
if (rand.oneIn(16)) {
- return rand.pick(HeapType::noext, HeapType::nofunc, HeapType::none);
+ HeapType ht =
+ rand.pick(HeapType::noext, HeapType::nofunc, HeapType::none);
+ return ht.getBasic(share);
}
- // TODO: string types
- return rand.pick(HeapType::func,
- HeapType::ext,
- HeapType::any,
- HeapType::eq,
- HeapType::i31,
- HeapType::struct_,
- HeapType::array);
+ HeapType ht = rand.pick(HeapType::func,
+ HeapType::ext,
+ HeapType::any,
+ HeapType::eq,
+ HeapType::i31,
+ HeapType::struct_,
+ HeapType::array);
+ if (share == Unshared && features.hasSharedEverything() && rand.oneIn(2)) {
+ share = Shared;
+ }
+ return ht.getBasic(share);
}
Type::BasicType generateBasicType() {
@@ -162,35 +172,47 @@ struct HeapTypeGeneratorImpl {
.add(FeatureSet::SIMD, Type::v128));
}
- HeapType generateHeapType() {
+ HeapType generateHeapType(Shareability share) {
if (rand.oneIn(4)) {
- return generateBasicHeapType();
- } else {
- Index i = rand.upTo(recGroupEnds[index]);
- return builder[i];
+ return generateBasicHeapType(share);
+ }
+ if (share == Shared) {
+ // We can only reference other shared types.
+ std::vector<Index> eligible;
+ for (Index i = 0, n = recGroupEnds[index]; i < n; ++i) {
+ if (HeapType(builder[i]).getShared() == Shared) {
+ eligible.push_back(i);
+ }
+ }
+ if (eligible.empty()) {
+ return generateBasicHeapType(share);
+ }
+ return builder[rand.pick(eligible)];
}
+ // Any heap type can be referenced in an unshared context.
+ return builder[rand.upTo(recGroupEnds[index])];
}
- Type generateRefType() {
- auto heapType = generateHeapType();
+ Type generateRefType(Shareability share) {
+ auto heapType = generateHeapType(share);
auto nullability = rand.oneIn(2) ? Nullable : NonNullable;
return builder.getTempRefType(heapType, nullability);
}
- Type generateSingleType() {
+ Type generateSingleType(Shareability share) {
switch (rand.upTo(2)) {
case 0:
return generateBasicType();
case 1:
- return generateRefType();
+ return generateRefType(share);
}
WASM_UNREACHABLE("unexpected");
}
- Type generateTupleType() {
+ Type generateTupleType(Shareability share) {
std::vector<Type> types(2 + rand.upTo(MAX_TUPLE_SIZE - 1));
for (auto& type : types) {
- type = generateSingleType();
+ type = generateSingleType(share);
}
return builder.getTempTupleType(Tuple(types));
}
@@ -199,55 +221,57 @@ struct HeapTypeGeneratorImpl {
if (rand.oneIn(6)) {
return Type::none;
} else if (features.hasMultivalue() && rand.oneIn(5)) {
- return generateTupleType();
+ return generateTupleType(Unshared);
} else {
- return generateSingleType();
+ return generateSingleType(Unshared);
}
}
Signature generateSignature() {
std::vector<Type> types(rand.upToSquared(MAX_PARAMS));
for (auto& type : types) {
- type = generateSingleType();
+ type = generateSingleType(Unshared);
}
auto params = builder.getTempTupleType(types);
return {params, generateReturnType()};
}
- Field generateField() {
+ Field generateField(Shareability share) {
auto mutability = rand.oneIn(2) ? Mutable : Immutable;
if (rand.oneIn(6)) {
return {rand.oneIn(2) ? Field::i8 : Field::i16, mutability};
} else {
- return {generateSingleType(), mutability};
+ return {generateSingleType(share), mutability};
}
}
- Struct generateStruct() {
+ Struct generateStruct(Shareability share) {
std::vector<Field> fields(rand.upTo(MAX_STRUCT_SIZE + 1));
for (auto& field : fields) {
- field = generateField();
+ field = generateField(share);
}
return {fields};
}
- Array generateArray() { return {generateField()}; }
+ Array generateArray(Shareability share) { return {generateField(share)}; }
- template<typename Kind> std::vector<HeapType> getKindCandidates() {
+ template<typename Kind>
+ std::vector<HeapType> getKindCandidates(Shareability share) {
std::vector<HeapType> candidates;
// Iterate through the top level kinds, finding matches for `Kind`. Since we
// are constructing a child, we can only look through the end of the current
// recursion group.
for (Index i = 0, end = recGroupEnds[index]; i < end; ++i) {
- if (std::get_if<Kind>(&typeKinds[i])) {
+ if (std::get_if<Kind>(&typeKinds[i]) &&
+ share == HeapType(builder[i]).getShared()) {
candidates.push_back(builder[i]);
}
}
return candidates;
}
- template<typename Kind> std::optional<HeapType> pickKind() {
- auto candidates = getKindCandidates<Kind>();
+ template<typename Kind> std::optional<HeapType> pickKind(Shareability share) {
+ auto candidates = getKindCandidates<Kind>(share);
if (candidates.size()) {
return rand.pick(candidates);
} else {
@@ -255,65 +279,71 @@ struct HeapTypeGeneratorImpl {
}
}
- HeapType pickSubFunc() {
+ HeapType pickSubFunc(Shareability share) {
auto choice = rand.upTo(8);
switch (choice) {
case 0:
- return HeapType::func;
+ return HeapTypes::func.getBasic(share);
case 1:
- return HeapType::nofunc;
- default:
- if (auto type = pickKind<SignatureKind>()) {
+ return HeapTypes::nofunc.getBasic(share);
+ default: {
+ if (auto type = pickKind<SignatureKind>(share)) {
return *type;
}
- return (choice % 2) ? HeapType::func : HeapType::nofunc;
+ HeapType ht = (choice % 2) ? HeapType::func : HeapType::nofunc;
+ return ht.getBasic(share);
+ }
}
}
- HeapType pickSubStruct() {
+ HeapType pickSubStruct(Shareability share) {
auto choice = rand.upTo(8);
switch (choice) {
case 0:
- return HeapType::struct_;
+ return HeapTypes::struct_.getBasic(share);
case 1:
- return HeapType::none;
- default:
- if (auto type = pickKind<StructKind>()) {
+ return HeapTypes::none.getBasic(share);
+ default: {
+ if (auto type = pickKind<StructKind>(share)) {
return *type;
}
- return (choice % 2) ? HeapType::struct_ : HeapType::none;
+ HeapType ht = (choice % 2) ? HeapType::struct_ : HeapType::none;
+ return ht.getBasic(share);
+ }
}
}
- HeapType pickSubArray() {
+ HeapType pickSubArray(Shareability share) {
auto choice = rand.upTo(8);
switch (choice) {
case 0:
- return HeapType::array;
+ return HeapTypes::array.getBasic(share);
case 1:
- return HeapType::none;
- default:
- if (auto type = pickKind<ArrayKind>()) {
+ return HeapTypes::none.getBasic(share);
+ default: {
+ if (auto type = pickKind<ArrayKind>(share)) {
return *type;
}
- return (choice % 2) ? HeapType::array : HeapType::none;
+ HeapType ht = (choice % 2) ? HeapType::array : HeapType::none;
+ return ht.getBasic(share);
+ }
}
}
- HeapType pickSubEq() {
+ HeapType pickSubEq(Shareability share) {
auto choice = rand.upTo(16);
switch (choice) {
case 0:
- return HeapType::eq;
+ return HeapTypes::eq.getBasic(share);
case 1:
- return HeapType::array;
+ return HeapTypes::array.getBasic(share);
case 2:
- return HeapType::struct_;
+ return HeapTypes::struct_.getBasic(share);
case 3:
- return HeapType::none;
+ return HeapTypes::none.getBasic(share);
default: {
- auto candidates = getKindCandidates<StructKind>();
- auto arrayCandidates = getKindCandidates<ArrayKind>();
+ auto candidates = getKindCandidates<StructKind>(share);
+ auto arrayCandidates = getKindCandidates<ArrayKind>(share);
candidates.insert(
candidates.end(), arrayCandidates.begin(), arrayCandidates.end());
if (candidates.size()) {
@@ -321,13 +351,13 @@ struct HeapTypeGeneratorImpl {
}
switch (choice >> 2) {
case 0:
- return HeapType::eq;
+ return HeapTypes::eq.getBasic(share);
case 1:
- return HeapType::array;
+ return HeapTypes::array.getBasic(share);
case 2:
- return HeapType::struct_;
+ return HeapTypes::struct_.getBasic(share);
case 3:
- return HeapType::none;
+ return HeapTypes::none.getBasic(share);
default:
WASM_UNREACHABLE("unexpected index");
}
@@ -335,19 +365,20 @@ struct HeapTypeGeneratorImpl {
}
}
- HeapType pickSubAny() {
+ HeapType pickSubAny(Shareability share) {
switch (rand.upTo(8)) {
case 0:
- return HeapType::any;
+ return HeapTypes::any.getBasic(share);
case 1:
- return HeapType::none;
+ return HeapTypes::none.getBasic(share);
default:
- return pickSubEq();
+ return pickSubEq(share);
}
WASM_UNREACHABLE("unexpected index");
}
HeapType pickSubHeapType(HeapType type) {
+ auto share = type.getShared();
auto it = typeIndices.find(type);
if (it != typeIndices.end()) {
// This is a constructed type, so we know where its subtypes are, but we
@@ -365,9 +396,9 @@ struct HeapTypeGeneratorImpl {
if (rand.oneIn(candidates.size() * 8)) {
auto* kind = &typeKinds[it->second];
if (std::get_if<SignatureKind>(kind)) {
- return HeapType::nofunc;
+ return HeapTypes::nofunc.getBasic(share);
} else {
- return HeapType::none;
+ return HeapTypes::none.getBasic(share);
}
}
return rand.pick(candidates);
@@ -377,22 +408,21 @@ struct HeapTypeGeneratorImpl {
if (rand.oneIn(8)) {
return type.getBottom();
}
- assert(!type.isShared() && "TODO: handle shared types");
switch (type.getBasic(Unshared)) {
case HeapType::func:
- return pickSubFunc();
+ return pickSubFunc(share);
case HeapType::cont:
WASM_UNREACHABLE("not implemented");
case HeapType::any:
- return pickSubAny();
+ return pickSubAny(share);
case HeapType::eq:
- return pickSubEq();
+ return pickSubEq(share);
case HeapType::i31:
- return HeapType::i31;
+ return HeapTypes::i31.getBasic(share);
case HeapType::struct_:
- return pickSubStruct();
+ return pickSubStruct(share);
case HeapType::array:
- return pickSubArray();
+ return pickSubArray(share);
case HeapType::ext:
case HeapType::exn:
case HeapType::string:
@@ -408,6 +438,7 @@ struct HeapTypeGeneratorImpl {
}
HeapType pickSuperHeapType(HeapType type) {
+ auto share = type.getShared();
std::vector<HeapType> candidates;
auto it = typeIndices.find(type);
if (it != typeIndices.end()) {
@@ -420,17 +451,17 @@ struct HeapTypeGeneratorImpl {
}
auto* kind = &typeKinds[it->second];
if (std::get_if<StructKind>(kind)) {
- candidates.push_back(HeapType::struct_);
- candidates.push_back(HeapType::eq);
- candidates.push_back(HeapType::any);
+ candidates.push_back(HeapTypes::struct_.getBasic(share));
+ candidates.push_back(HeapTypes::eq.getBasic(share));
+ candidates.push_back(HeapTypes::any.getBasic(share));
return rand.pick(candidates);
} else if (std::get_if<ArrayKind>(kind)) {
- candidates.push_back(HeapType::array);
- candidates.push_back(HeapType::eq);
- candidates.push_back(HeapType::any);
+ candidates.push_back(HeapTypes::array.getBasic(share));
+ candidates.push_back(HeapTypes::eq.getBasic(share));
+ candidates.push_back(HeapTypes::any.getBasic(share));
return rand.pick(candidates);
} else if (std::get_if<SignatureKind>(kind)) {
- candidates.push_back(HeapType::func);
+ candidates.push_back(HeapTypes::func.getBasic(share));
return rand.pick(candidates);
} else {
WASM_UNREACHABLE("unexpected kind");
@@ -439,7 +470,6 @@ struct HeapTypeGeneratorImpl {
// This is not a constructed type, so it must be a basic type.
assert(type.isBasic());
candidates.push_back(type);
- assert(!type.isShared() && "TODO: handle shared types");
switch (type.getBasic(Unshared)) {
case HeapType::ext:
case HeapType::func:
@@ -448,28 +478,28 @@ struct HeapTypeGeneratorImpl {
case HeapType::any:
break;
case HeapType::eq:
- candidates.push_back(HeapType::any);
+ candidates.push_back(HeapTypes::any.getBasic(share));
break;
case HeapType::i31:
case HeapType::struct_:
case HeapType::array:
- candidates.push_back(HeapType::eq);
- candidates.push_back(HeapType::any);
+ candidates.push_back(HeapTypes::eq.getBasic(share));
+ candidates.push_back(HeapTypes::any.getBasic(share));
break;
case HeapType::string:
- candidates.push_back(HeapType::any);
+ candidates.push_back(HeapTypes::any.getBasic(share));
break;
case HeapType::none:
- return pickSubAny();
+ return pickSubAny(share);
case HeapType::nofunc:
- return pickSubFunc();
+ return pickSubFunc(share);
case HeapType::nocont:
WASM_UNREACHABLE("not implemented");
case HeapType::noext:
- candidates.push_back(HeapType::ext);
+ candidates.push_back(HeapTypes::ext.getBasic(share));
break;
case HeapType::noexn:
- candidates.push_back(HeapType::exn);
+ candidates.push_back(HeapTypes::exn.getBasic(share));
break;
}
assert(!candidates.empty());
@@ -552,7 +582,7 @@ struct HeapTypeGeneratorImpl {
return {generateSubtype(super.type), Immutable};
}
- Struct generateSubStruct(const Struct& super) {
+ Struct generateSubStruct(const Struct& super, Shareability share) {
std::vector<Field> fields;
// Depth subtyping
for (auto field : super.fields) {
@@ -561,7 +591,7 @@ struct HeapTypeGeneratorImpl {
// Width subtyping
Index extra = rand.upTo(MAX_STRUCT_SIZE + 1 - fields.size());
for (Index i = 0; i < extra; ++i) {
- fields.push_back(generateField());
+ fields.push_back(generateField(share));
}
return {fields};
}
@@ -900,6 +930,7 @@ std::vector<HeapType> Inhabitator::build() {
}
}
builder[i].setOpen(types[i].isOpen());
+ builder[i].setShared(types[i].getShared());
}
auto built = builder.build();
diff --git a/src/tools/wasm-fuzz-types.cpp b/src/tools/wasm-fuzz-types.cpp
index 2be8aa5e7..ecd8883b1 100644
--- a/src/tools/wasm-fuzz-types.cpp
+++ b/src/tools/wasm-fuzz-types.cpp
@@ -262,9 +262,10 @@ void Fuzzer::checkCanonicalization() {
}
}
- // Set finality
+ // Set finality and shareability
for (size_t i = 0; i < types.size(); ++i) {
builder[i].setOpen(types[i].isOpen());
+ builder[i].setShared(types[i].getShared());
}
// Set up recursion groups and record group ends to ensure we only select
diff --git a/src/wasm-features.h b/src/wasm-features.h
index cda3ce447..366b75200 100644
--- a/src/wasm-features.h
+++ b/src/wasm-features.h
@@ -193,9 +193,12 @@ struct FeatureSet {
return *this;
}
- FeatureSet operator-(FeatureSet& other) const {
+ FeatureSet operator-(const FeatureSet& other) const {
return features & ~other.features;
}
+ FeatureSet operator-(Feature other) const {
+ return *this - FeatureSet(other);
+ }
uint32_t features;
};
diff --git a/test/lit/fuzz-types.test b/test/lit/fuzz-types.test
index ae5c00019..10d8fe3bc 100644
--- a/test/lit/fuzz-types.test
+++ b/test/lit/fuzz-types.test
@@ -1,60 +1,60 @@
-;; RUN: wasm-fuzz-types -v --seed=0 | filecheck %s
+;; RUN: wasm-fuzz-types -v --seed=1 | filecheck %s
-;; CHECK: Running with seed 0
+;; CHECK: Running with seed 1
;; CHECK-NEXT: Built 20 types:
;; CHECK-NEXT: (rec
-;; CHECK-NEXT: (type $0 (sub (struct (field i32))))
-;; CHECK-NEXT: (type $1 (sub (func (param (ref $2)) (result externref))))
-;; CHECK-NEXT: (type $2 (sub (struct )))
+;; CHECK-NEXT: (type $0 (sub (struct (field (mut i16)) (field (mut (ref $2))) (field (mut (ref null $2))))))
+;; CHECK-NEXT: (type $1 (sub (func (param (ref $1)) (result f64 (ref $0) f32 (ref null (shared eq))))))
+;; CHECK-NEXT: (type $2 (sub (shared (struct (field (mut (ref null (shared extern)))) (field (mut (ref null $2)))))))
+;; CHECK-NEXT: (type $3 (sub (shared (struct ))))
;; CHECK-NEXT: )
;; CHECK-NEXT: (rec
-;; CHECK-NEXT: (type $3 (sub $0 (struct (field i32) (field (ref $5)) (field (ref $5)))))
-;; CHECK-NEXT: (type $4 (sub $3 (struct (field i32) (field (ref $5)) (field (ref $5)) (field i8) (field (ref null $13)) (field (mut i64)))))
-;; CHECK-NEXT: (type $5 (sub (array (mut f64))))
-;; CHECK-NEXT: (type $6 (sub $1 (func (param anyref) (result externref))))
-;; CHECK-NEXT: (type $7 (sub final $2 (struct (field (mut (ref null $14))) (field (ref $3)))))
-;; CHECK-NEXT: (type $8 (sub $1 (func (param (ref struct)) (result (ref extern)))))
-;; CHECK-NEXT: (type $9 (sub $5 (array (mut f64))))
-;; CHECK-NEXT: (type $10 (sub final $8 (func (param (ref any)) (result (ref noextern)))))
-;; CHECK-NEXT: (type $11 (sub (array (mut anyref))))
-;; CHECK-NEXT: (type $12 (sub $2 (struct (field (mut f64)))))
-;; CHECK-NEXT: (type $13 (sub final $1 (func (param (ref $2)) (result (ref extern)))))
-;; CHECK-NEXT: (type $14 (array (mut (ref null $14))))
+;; CHECK-NEXT: (type $4 (sub (array i32)))
+;; CHECK-NEXT: (type $5 (sub $4 (array i32)))
+;; CHECK-NEXT: (type $6 (shared (func (param (ref null $3)) (result i32))))
+;; CHECK-NEXT: (type $7 (sub $2 (shared (struct (field (mut (ref null (shared extern)))) (field (mut (ref null $2))) (field (mut (ref null $3))) (field (mut i16)) (field (mut (ref null $7))) (field (mut (ref null $7)))))))
+;; CHECK-NEXT: (type $8 (sub $0 (struct (field (mut i16)) (field (mut (ref $2))) (field (mut (ref null $2))))))
;; CHECK-NEXT: )
;; CHECK-NEXT: (rec
-;; CHECK-NEXT: (type $15 (sub final $11 (array (mut anyref))))
-;; CHECK-NEXT: (type $16 (sub final $12 (struct (field (mut f64)))))
-;; CHECK-NEXT: (type $17 (sub (struct (field f32) (field (mut i32)) (field i8) (field (ref array)))))
-;; CHECK-NEXT: (type $18 (sub $11 (array (mut anyref))))
-;; CHECK-NEXT: (type $19 (sub final $9 (array (mut f64))))
+;; CHECK-NEXT: (type $9 (shared (array i32)))
+;; CHECK-NEXT: (type $10 (sub $5 (array i32)))
+;; CHECK-NEXT: (type $11 (func (result i32)))
+;; CHECK-NEXT: (type $12 (sub (shared (array (ref $3)))))
+;; CHECK-NEXT: (type $13 (sub (shared (func (param (ref null $19) v128) (result (ref null $12))))))
+;; CHECK-NEXT: (type $14 (sub final $12 (shared (array (ref $3)))))
+;; CHECK-NEXT: (type $15 (sub (shared (func (param (ref null (shared struct)) i31ref) (result nullfuncref)))))
+;; CHECK-NEXT: (type $16 (sub $5 (array i32)))
+;; CHECK-NEXT: (type $17 (sub (func (param v128) (result f64))))
+;; CHECK-NEXT: (type $18 (sub (array (ref $11))))
+;; CHECK-NEXT: (type $19 (shared (array i8)))
;; CHECK-NEXT: )
;; CHECK-NEXT:
;; CHECK-NEXT: Inhabitable types:
;; CHECK-NEXT:
;; CHECK-NEXT: Built 20 types:
;; CHECK-NEXT: (rec
-;; CHECK-NEXT: (type $0 (sub (struct (field i32))))
-;; CHECK-NEXT: (type $1 (sub (func (param (ref $2)) (result externref))))
-;; CHECK-NEXT: (type $2 (sub (struct )))
+;; CHECK-NEXT: (type $0 (sub (struct (field (mut i16)) (field (mut (ref $2))) (field (mut (ref null $2))))))
+;; CHECK-NEXT: (type $1 (sub (func (param (ref $1)) (result f64 (ref $0) f32 (ref null (shared eq))))))
+;; CHECK-NEXT: (type $2 (sub (shared (struct (field (mut (ref null (shared extern)))) (field (mut (ref null $2)))))))
+;; CHECK-NEXT: (type $3 (sub (shared (struct ))))
;; CHECK-NEXT: )
;; CHECK-NEXT: (rec
-;; CHECK-NEXT: (type $3 (sub $0 (struct (field i32) (field (ref $5)) (field (ref $5)))))
-;; CHECK-NEXT: (type $4 (sub $3 (struct (field i32) (field (ref $5)) (field (ref $5)) (field i8) (field (ref null $13)) (field (mut i64)))))
-;; CHECK-NEXT: (type $5 (sub (array (mut f64))))
-;; CHECK-NEXT: (type $6 (sub $1 (func (param anyref) (result externref))))
-;; CHECK-NEXT: (type $7 (sub final $2 (struct (field (mut (ref null $14))) (field (ref $3)))))
-;; CHECK-NEXT: (type $8 (sub $1 (func (param (ref struct)) (result (ref extern)))))
-;; CHECK-NEXT: (type $9 (sub $5 (array (mut f64))))
-;; CHECK-NEXT: (type $10 (sub final $8 (func (param (ref any)) (result (ref noextern)))))
-;; CHECK-NEXT: (type $11 (sub (array (mut anyref))))
-;; CHECK-NEXT: (type $12 (sub $2 (struct (field (mut f64)))))
-;; CHECK-NEXT: (type $13 (sub final $1 (func (param (ref $2)) (result (ref extern)))))
-;; CHECK-NEXT: (type $14 (array (mut (ref null $14))))
+;; CHECK-NEXT: (type $4 (sub (array i32)))
+;; CHECK-NEXT: (type $5 (sub $4 (array i32)))
+;; CHECK-NEXT: (type $6 (shared (func (param (ref null $3)) (result i32))))
+;; CHECK-NEXT: (type $7 (sub $2 (shared (struct (field (mut (ref null (shared extern)))) (field (mut (ref null $2))) (field (mut (ref null $3))) (field (mut i16)) (field (mut (ref null $7))) (field (mut (ref null $7)))))))
+;; CHECK-NEXT: (type $8 (sub $0 (struct (field (mut i16)) (field (mut (ref $2))) (field (mut (ref null $2))))))
;; CHECK-NEXT: )
;; CHECK-NEXT: (rec
-;; CHECK-NEXT: (type $15 (sub final $11 (array (mut anyref))))
-;; CHECK-NEXT: (type $16 (sub final $12 (struct (field (mut f64)))))
-;; CHECK-NEXT: (type $17 (sub (struct (field f32) (field (mut i32)) (field i8) (field (ref array)))))
-;; CHECK-NEXT: (type $18 (sub $11 (array (mut anyref))))
-;; CHECK-NEXT: (type $19 (sub final $9 (array (mut f64))))
-)
+;; CHECK-NEXT: (type $9 (shared (array i32)))
+;; CHECK-NEXT: (type $10 (sub $5 (array i32)))
+;; CHECK-NEXT: (type $11 (func (result i32)))
+;; CHECK-NEXT: (type $12 (sub (shared (array (ref $3)))))
+;; CHECK-NEXT: (type $13 (sub (shared (func (param (ref null $19) v128) (result (ref null $12))))))
+;; CHECK-NEXT: (type $14 (sub final $12 (shared (array (ref $3)))))
+;; CHECK-NEXT: (type $15 (sub (shared (func (param (ref null (shared struct)) i31ref) (result nullfuncref)))))
+;; CHECK-NEXT: (type $16 (sub $5 (array i32)))
+;; CHECK-NEXT: (type $17 (sub (func (param v128) (result f64))))
+;; CHECK-NEXT: (type $18 (sub (array (ref $11))))
+;; CHECK-NEXT: (type $19 (shared (array i8)))
+;; CHECK-NEXT: )