diff options
author | Alon Zakai <azakai@google.com> | 2021-08-11 07:53:15 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-11 07:53:15 -0700 |
commit | 344bfe98b3d4cdb9dac223e9b6b8be7f96332d59 (patch) | |
tree | f48f84a1e1454447d621efcc626ed2bcdfbff0f5 /src/passes/LocalSubtyping.cpp | |
parent | 52a90ac33416322c1be103fba6ab32764d3d1c9e (diff) | |
download | binaryen-344bfe98b3d4cdb9dac223e9b6b8be7f96332d59.tar.gz binaryen-344bfe98b3d4cdb9dac223e9b6b8be7f96332d59.tar.bz2 binaryen-344bfe98b3d4cdb9dac223e9b6b8be7f96332d59.zip |
[Wasm GC] Fix LocalSubtyping on unreachable sets with incompatible values (#4051)
We ignore sets in unreachable code, but their values may not be
compatible with a new type we specialize a local for. That is, the
validator cares about unreachable sets, while logically we don't need
to, and this pass doesn't. Fix up such unreachable sets at the end.
Diffstat (limited to 'src/passes/LocalSubtyping.cpp')
-rw-r--r-- | src/passes/LocalSubtyping.cpp | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/src/passes/LocalSubtyping.cpp b/src/passes/LocalSubtyping.cpp index 19ce2f275..24a2e48e4 100644 --- a/src/passes/LocalSubtyping.cpp +++ b/src/passes/LocalSubtyping.cpp @@ -27,6 +27,7 @@ #include <ir/local-graph.h> #include <ir/utils.h> #include <pass.h> +#include <wasm-builder.h> #include <wasm.h> namespace wasm { @@ -178,10 +179,36 @@ struct LocalSubtyping : public WalkerPass<PostWalker<LocalSubtyping>> { get->type = func->getLocalType(get->index); } for (auto* set : FindAll<LocalSet>(func->body).list) { + auto newType = func->getLocalType(set->index); if (set->isTee()) { - set->type = func->getLocalType(set->index); + set->type = newType; set->finalize(); } + + // If this set was not processed earlier - that is, if it is in + // unreachable code - then it may have an incompatible type. That is, + // If we saw a reachable set that writes type A, and this set writes + // type B, we may have specialized the local type to A, but the value + // of type B in this unreachable set is no longer valid to write to + // that local. In such a case we must do additional work. + if (!Type::isSubType(set->value->type, newType)) { + // The type is incompatible. To fix this, replace + // + // (set (bad-value)) + // + // with + // + // (set (block + // (drop (bad-value)) + // (unreachable) + // )) + // + // (We cannot just ignore the bad value, as it may contain a break to + // a target that is necessary for validation.) + Builder builder(*getModule()); + set->value = builder.makeSequence(builder.makeDrop(set->value), + builder.makeUnreachable()); + } } // Also update their parents. |