summaryrefslogtreecommitdiff
path: root/src/passes/LocalSubtyping.cpp
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2021-08-11 07:53:15 -0700
committerGitHub <noreply@github.com>2021-08-11 07:53:15 -0700
commit344bfe98b3d4cdb9dac223e9b6b8be7f96332d59 (patch)
treef48f84a1e1454447d621efcc626ed2bcdfbff0f5 /src/passes/LocalSubtyping.cpp
parent52a90ac33416322c1be103fba6ab32764d3d1c9e (diff)
downloadbinaryen-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.cpp29
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.