diff options
author | Thomas Lively <7121787+tlively@users.noreply.github.com> | 2022-02-07 11:58:53 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-07 11:58:53 -0800 |
commit | ca4c474432b053febfc184e6c27f15419ef6f601 (patch) | |
tree | 039ec11c5625efd0d1d5d14d30db136e7668682e /src | |
parent | ab6469865af5e639e1ba3baaa64f519f42b9032e (diff) | |
download | binaryen-ca4c474432b053febfc184e6c27f15419ef6f601.tar.gz binaryen-ca4c474432b053febfc184e6c27f15419ef6f601.tar.bz2 binaryen-ca4c474432b053febfc184e6c27f15419ef6f601.zip |
Validate supertypes after isorecursive canonicalization (#4506)
Validating nominally declared supertypes depends on being able to test type
equality, which in turn depends on the compared types having already been
canonicalized. Previously we validated supertypes before canonicalization, so
validation would fail in cases where it should have succeeded. Fix the bug by
canonicalizing first. This means that the global type store can now end up
holding invalid types, but those types will never be exposed to the user, so
that's not a huge problem.
Also fix an unrelated bug that was preventing the test from passing, which is
that supertypes were being hashed and compared without the special logic for
detecting self-references. This bug preventing the equivalent recursion groups
in the test from being deduplicated.
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm/wasm-type.cpp | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index 9e9a9603d..27480ce68 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -2444,7 +2444,10 @@ size_t RecGroupHasher::hash(const TypeInfo& info) const { size_t RecGroupHasher::hash(const HeapTypeInfo& info) const { assert(info.isFinalized); - size_t digest = wasm::hash(uintptr_t(info.supertype)); + size_t digest = wasm::hash(bool(info.supertype)); + if (info.supertype) { + hash_combine(digest, hash(HeapType(uintptr_t(info.supertype)))); + } wasm::rehash(digest, info.kind); switch (info.kind) { case HeapTypeInfo::BasicKind: @@ -2568,9 +2571,16 @@ bool RecGroupEquator::eq(const TypeInfo& a, const TypeInfo& b) const { } bool RecGroupEquator::eq(const HeapTypeInfo& a, const HeapTypeInfo& b) const { - if (a.supertype != b.supertype) { + if (bool(a.supertype) != bool(b.supertype)) { return false; } + if (a.supertype) { + HeapType superA(uintptr_t(a.supertype)); + HeapType superB(uintptr_t(b.supertype)); + if (!eq(superA, superB)) { + return false; + } + } if (a.kind != b.kind) { return false; } @@ -3550,7 +3560,11 @@ void canonicalizeEquirecursive(CanonicalizationState& state) { } std::optional<TypeBuilder::Error> -validateStructuralSubtyping(const std::vector<HeapType>& types) { +validateSubtyping(const std::vector<HeapType>& types) { + if (getTypeSystem() == TypeSystem::Equirecursive) { + // Subtyping is not explicitly declared, so nothing to check. + return {}; + } for (size_t i = 0; i < types.size(); ++i) { HeapType type = types[i]; if (type.isBasic()) { @@ -3623,11 +3637,6 @@ canonicalizeNominal(CanonicalizationState& state) { checked.insert(path.begin(), path.end()); } - // Check that the declared supertypes are valid. - if (auto error = validateStructuralSubtyping(state.results)) { - return {*error}; - } - return {}; } @@ -3700,11 +3709,6 @@ std::optional<TypeBuilder::Error> canonicalizeIsorecursive( return *error; } - // Check that the declared supertypes are structurally valid. - if (auto error = validateStructuralSubtyping(state.results)) { - return {*error}; - } - // Now that we know everything is valid, start canonicalizing recursion // groups. Before canonicalizing each group, update all the HeapType use sites // within it to make sure it only refers to other canonical groups or to @@ -3839,6 +3843,11 @@ TypeBuilder::BuildResult TypeBuilder::build() { << getMillis(afterStructureCanonicalization, end) << " ms\n"; #endif + // Check that the declared supertypes are structurally valid. + if (auto error = validateSubtyping(state.results)) { + return {*error}; + } + // Note built signature types. See comment in `HeapType::HeapType(Signature)`. for (auto type : state.results) { if (type.isSignature() && (getTypeSystem() == TypeSystem::Nominal)) { |