diff options
author | Thomas Lively <7121787+tlively@users.noreply.github.com> | 2022-02-08 10:55:23 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-08 18:55:23 +0000 |
commit | ac6c450b38b2fe4d049eef8aaa2acd56e3be9ae2 (patch) | |
tree | 0cdd0611d86cd27e6e3ab6cd75a7ef4f7d86c405 | |
parent | 419b7e23696c7dbd7e7c5464433cfd23da4157df (diff) | |
download | binaryen-ac6c450b38b2fe4d049eef8aaa2acd56e3be9ae2.tar.gz binaryen-ac6c450b38b2fe4d049eef8aaa2acd56e3be9ae2.tar.bz2 binaryen-ac6c450b38b2fe4d049eef8aaa2acd56e3be9ae2.zip |
Eagerly canonicalize basic types (#4507)
We were already eagerly canonicalizing basic HeapTypes when building types so
the more complicated canonicalization algorithms would not have to handle
noncanonical heap types, but we were not doing the same for Types. Equirecursive
canonicalization was properly handling noncanonical Types everywhere, but
isorecursive canonicalization was not. Rather than update isorecursive
canonicalization in multiple places, remove the special handling from
equirecursive canonicalization and canonicalize types in a single location.
-rw-r--r-- | src/wasm/wasm-type.cpp | 29 | ||||
-rw-r--r-- | test/gtest/type-builder.cpp | 27 |
2 files changed, 48 insertions, 8 deletions
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 04b1122b6..d7ba224c8 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -2194,7 +2194,6 @@ std::ostream& TypePrinter::print(const Rtt& rtt) { } size_t FiniteShapeHasher::hash(Type type) { - type = asCanonical(type); size_t digest = wasm::hash(type.isBasic()); if (type.isBasic()) { rehash(digest, type.getID()); @@ -2205,7 +2204,6 @@ size_t FiniteShapeHasher::hash(Type type) { } size_t FiniteShapeHasher::hash(HeapType heapType) { - heapType = asCanonical(heapType); size_t digest = wasm::hash(heapType.isBasic()); if (heapType.isBasic()) { rehash(digest, heapType.getID()); @@ -2314,8 +2312,6 @@ size_t FiniteShapeHasher::hash(const Rtt& rtt) { } bool FiniteShapeEquator::eq(Type a, Type b) { - a = asCanonical(a); - b = asCanonical(b); if (a.isBasic() != b.isBasic()) { return false; } else if (a.isBasic()) { @@ -2326,8 +2322,6 @@ bool FiniteShapeEquator::eq(Type a, Type b) { } bool FiniteShapeEquator::eq(HeapType a, HeapType b) { - a = asCanonical(a); - b = asCanonical(b); if (a.isBasic() != b.isBasic()) { return false; } else if (a.isBasic()) { @@ -3798,7 +3792,7 @@ std::optional<TypeBuilder::Error> canonicalizeIsorecursive( return {}; } -void canonicalizeBasicHeapTypes(CanonicalizationState& state) { +void canonicalizeBasicTypes(CanonicalizationState& state) { // Replace heap types backed by BasicKind HeapTypeInfos with their // corresponding BasicHeapTypes. The heap types backed by BasicKind // HeapTypeInfos exist only to support building basic types in a TypeBuilder @@ -3814,6 +3808,25 @@ void canonicalizeBasicHeapTypes(CanonicalizationState& state) { } } state.update(replacements); + + if (replacements.size()) { + // Canonicalizing basic heap types may cause their parent types to become + // canonicalizable as well, for example after creating `(ref null extern)` + // we can futher canonicalize to `externref`. + struct TypeCanonicalizer : TypeGraphWalkerBase<TypeCanonicalizer> { + void scanType(Type* type) { + if (type->isTuple()) { + TypeGraphWalkerBase<TypeCanonicalizer>::scanType(type); + } else { + *type = asCanonical(*type); + } + } + }; + for (auto& info : state.newInfos) { + auto root = asHeapType(info); + TypeCanonicalizer{}.walkRoot(&root); + } + } } } // anonymous namespace @@ -3842,7 +3855,7 @@ TypeBuilder::BuildResult TypeBuilder::build() { // Eagerly replace references to built basic heap types so the more // complicated canonicalization algorithms don't need to consider them. - canonicalizeBasicHeapTypes(state); + canonicalizeBasicTypes(state); #if TRACE_CANONICALIZATION std::cerr << "After replacing basic heap types:\n"; diff --git a/test/gtest/type-builder.cpp b/test/gtest/type-builder.cpp index 2a29d11b0..4ae9e0e63 100644 --- a/test/gtest/type-builder.cpp +++ b/test/gtest/type-builder.cpp @@ -457,3 +457,30 @@ TEST_F(IsorecursiveTest, CanonicalizeTypesBeforeSubtyping) { auto result = builder.build(); EXPECT_TRUE(result); } + +static void testCanonicalizeBasicTypes() { + TypeBuilder builder(5); + + Type externref = builder.getTempRefType(builder[0], Nullable); + Type externrefs = builder.getTempTupleType({externref, externref}); + + builder[0] = HeapType::ext; + builder[1] = Struct({Field(externref, Immutable)}); + builder[2] = Struct({Field(Type::externref, Immutable)}); + builder[3] = Signature(externrefs, Type::none); + builder[4] = Signature({Type::externref, Type::externref}, Type::none); + + auto result = builder.build(); + ASSERT_TRUE(result); + auto built = *result; + + EXPECT_EQ(built[1], built[2]); + EXPECT_EQ(built[3], built[4]); +} + +TEST_F(EquirecursiveTest, CanonicalizeBasicTypes) { + testCanonicalizeBasicTypes(); +} +TEST_F(IsorecursiveTest, CanonicalizeBasicTypes) { + testCanonicalizeBasicTypes(); +} |