summaryrefslogtreecommitdiff
path: root/src/wasm-interpreter.h
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2021-01-28 22:09:31 +0000
committerGitHub <noreply@github.com>2021-01-28 14:09:31 -0800
commit6299471584ce74d365526e33ed0a662bd2ee3490 (patch)
treed3aa2132d0897ea84bacab31c4e424780009efad /src/wasm-interpreter.h
parent53c471a445ef26eac7befc3f3a5e0a53870df8cb (diff)
downloadbinaryen-6299471584ce74d365526e33ed0a662bd2ee3490.tar.gz
binaryen-6299471584ce74d365526e33ed0a662bd2ee3490.tar.bz2
binaryen-6299471584ce74d365526e33ed0a662bd2ee3490.zip
[GC] Add br_on_func/data/i31 (#3525)
This expands the existing BrOnCast into BrOn that can also handle the func/data/i31 variants. This is not as elegant as RefIs / RefAs in that BrOnCast has an extra rtt field, but I think it is still the best option. We already have optional fields on Break (the value and condition), so making rtt optional is not odd. And it allows us to share all the behavior of br_on_* which aside from the cast or the check itself, is identical - returning the value if the branch is not taken, etc.
Diffstat (limited to 'src/wasm-interpreter.h')
-rw-r--r--src/wasm-interpreter.h52
1 files changed, 43 insertions, 9 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index ab5644bf4..fb7a3fcea 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1469,17 +1469,51 @@ public:
assert(cast.outcome == cast.Success);
return cast.castRef;
}
- Flow visitBrOnCast(BrOnCast* curr) {
- NOTE_ENTER("BrOnCast");
- auto cast = doCast(curr);
- if (cast.outcome == cast.Break) {
- return cast.breaking;
+ Flow visitBrOn(BrOn* curr) {
+ NOTE_ENTER("BrOn");
+ // BrOnCast uses the casting infrastructure, so handle it first.
+ if (curr->op == BrOnCast) {
+ auto cast = doCast(curr);
+ if (cast.outcome == cast.Break) {
+ return cast.breaking;
+ }
+ if (cast.outcome == cast.Null || cast.outcome == cast.Failure) {
+ return cast.originalRef;
+ }
+ assert(cast.outcome == cast.Success);
+ return Flow(curr->name, cast.castRef);
+ }
+ // The others do a simpler check for the type.
+ Flow flow = visit(curr->ref);
+ if (flow.breaking()) {
+ return flow;
}
- if (cast.outcome == cast.Null || cast.outcome == cast.Failure) {
- return cast.originalRef;
+ const auto& value = flow.getSingleValue();
+ NOTE_EVAL1(value);
+ if (value.isNull()) {
+ return {value};
}
- assert(cast.outcome == cast.Success);
- return Flow(curr->name, cast.castRef);
+ switch (curr->op) {
+ case BrOnFunc:
+ if (!value.type.isFunction()) {
+ return {value};
+ }
+ break;
+ case BrOnData:
+ if (!value.isGCData()) {
+ return {value};
+ }
+ break;
+ case BrOnI31:
+ if (value.type.getHeapType() != HeapType::i31) {
+ return {value};
+ }
+ break;
+ default:
+ WASM_UNREACHABLE("invalid br_on_*");
+ }
+ // No problems: take the branch.
+ return Flow(curr->name, value);
}
Flow visitRttCanon(RttCanon* curr) { return Literal(curr->type); }
Flow visitRttSub(RttSub* curr) {