diff options
author | Alon Zakai <azakai@google.com> | 2021-02-01 22:44:40 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-01 14:44:40 -0800 |
commit | eafb0a4ef25cd82317ac8fa84a9d7e58f9382fcc (patch) | |
tree | 7284b2c93d1416dd898f297792fc00a11dac0ed7 /src | |
parent | 02f8c56aad18a2715904d1d5e0951b25bf7749c3 (diff) | |
download | binaryen-eafb0a4ef25cd82317ac8fa84a9d7e58f9382fcc.tar.gz binaryen-eafb0a4ef25cd82317ac8fa84a9d7e58f9382fcc.tar.bz2 binaryen-eafb0a4ef25cd82317ac8fa84a9d7e58f9382fcc.zip |
[GC] br_on_null (#3528)
This is only partial support, as br_on_null also has an extra optional
value in the spec. Implementing that is cumbersome in binaryen, and
there is ongoing spec discussions about it (see
https://github.com/WebAssembly/function-references/issues/45 ), so
for now we only support the simple case without the default value.
Also fix prefixed opcodes to be LEBs in RefAs, which was noticed here
as the change here made it noticeable whether the values were int8 or
LEBs.
Diffstat (limited to 'src')
-rw-r--r-- | src/gen-s-parser.inc | 3 | ||||
-rw-r--r-- | src/passes/Print.cpp | 3 | ||||
-rw-r--r-- | src/wasm-binary.h | 1 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 9 | ||||
-rw-r--r-- | src/wasm.h | 7 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 6 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 18 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 13 |
8 files changed, 51 insertions, 9 deletions
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 3930a0318..281a2cfca 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -85,6 +85,9 @@ switch (op[0]) { case 'i': if (strcmp(op, "br_on_i31") == 0) { return makeBrOn(s, BrOnI31); } goto parse_error; + case 'n': + if (strcmp(op, "br_on_null") == 0) { return makeBrOn(s, BrOnNull); } + goto parse_error; default: goto parse_error; } } diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 9e1afffd4..39c66cc57 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -1785,6 +1785,9 @@ struct PrintExpressionContents } void visitBrOn(BrOn* curr) { switch (curr->op) { + case BrOnNull: + printMedium(o, "br_on_null "); + break; case BrOnCast: printMedium(o, "br_on_cast "); break; diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 3536afaf8..0213baffe 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -997,6 +997,7 @@ enum ASTNodes { RefIsNull = 0xd1, RefFunc = 0xd2, RefAsNonNull = 0xd3, + BrOnNull = 0xd4, // exception handling opcodes diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 26c86efe6..ac64a30c0 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1490,6 +1490,15 @@ public: } const auto& value = flow.getSingleValue(); NOTE_EVAL1(value); + if (curr->op == BrOnNull) { + // Unlike the others, BrOnNull does not propagate the value if it takes + // the branch. + if (value.isNull()) { + return Flow(curr->name); + } + // If the branch is not taken, we return the non-null value. + return {value}; + } if (value.isNull()) { return {value}; } diff --git a/src/wasm.h b/src/wasm.h index d681f3f4b..bd2e31814 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -557,6 +557,7 @@ enum RefAsOp { }; enum BrOnOp { + BrOnNull, BrOnCast, BrOnFunc, BrOnData, @@ -1400,6 +1401,12 @@ public: // BrOnCast has an rtt that is used in the cast. Expression* rtt; + // TODO: BrOnNull also has an optional extra value in the spec, which we do + // not support. See also the discussion on + // https://github.com/WebAssembly/function-references/issues/45 + // - depending on the decision there, we may want to move BrOnNull into + // Break or a new class of its own. + void finalize(); Type getCastType(); diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 4a90dd698..b7ffcd8d7 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2879,6 +2879,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { case BinaryConsts::RefAsNonNull: visitRefAs((curr = allocator.alloc<RefAs>())->cast<RefAs>(), code); break; + case BinaryConsts::BrOnNull: + maybeVisitBrOn(curr, code); + break; case BinaryConsts::Try: visitTryOrTryInBlock(curr); break; @@ -5831,6 +5834,9 @@ bool WasmBinaryBuilder::maybeVisitRefCast(Expression*& out, uint32_t code) { bool WasmBinaryBuilder::maybeVisitBrOn(Expression*& out, uint32_t code) { BrOnOp op; switch (code) { + case BinaryConsts::BrOnNull: + op = BrOnNull; + break; case BinaryConsts::BrOnCast: op = BrOnCast; break; diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 003d2b7af..d42080bac 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -1982,19 +1982,21 @@ void BinaryInstWriter::visitRefCast(RefCast* curr) { } void BinaryInstWriter::visitBrOn(BrOn* curr) { - o << int8_t(BinaryConsts::GCPrefix); switch (curr->op) { + case BrOnNull: + o << int8_t(BinaryConsts::BrOnNull); + break; case BrOnCast: - o << U32LEB(BinaryConsts::BrOnCast); + o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnCast); break; case BrOnFunc: - o << U32LEB(BinaryConsts::BrOnFunc); + o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnFunc); break; case BrOnData: - o << U32LEB(BinaryConsts::BrOnData); + o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnData); break; case BrOnI31: - o << U32LEB(BinaryConsts::BrOnI31); + o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnI31); break; default: WASM_UNREACHABLE("invalid br_on_*"); @@ -2085,13 +2087,13 @@ void BinaryInstWriter::visitRefAs(RefAs* curr) { o << int8_t(BinaryConsts::RefAsNonNull); break; case RefAsFunc: - o << int8_t(BinaryConsts::GCPrefix) << int8_t(BinaryConsts::RefAsFunc); + o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefAsFunc); break; case RefAsData: - o << int8_t(BinaryConsts::GCPrefix) << int8_t(BinaryConsts::RefAsData); + o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefAsData); break; case RefAsI31: - o << int8_t(BinaryConsts::GCPrefix) << int8_t(BinaryConsts::RefAsI31); + o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::RefAsI31); break; default: WASM_UNREACHABLE("invalid ref.as_*"); diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index a94bda066..f8d8890ec 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -936,13 +936,24 @@ void BrOn::finalize() { (rtt && rtt->type == Type::unreachable)) { type = Type::unreachable; } else { - type = ref->type; + if (op == BrOnNull) { + // If BrOnNull does not branch, it flows out the existing value as + // non-null. + // FIXME: When we support non-nullable types, this should be non-nullable. + type = Type(ref->type.getHeapType(), Nullable); + } else { + type = ref->type; + } } } Type BrOn::getCastType() { switch (op) { + case BrOnNull: + // BrOnNull does not send a value on the branch. + return Type::none; case BrOnCast: + // FIXME: When we support non-nullable types, this should be non-nullable. return Type(rtt->type.getHeapType(), Nullable); case BrOnFunc: return Type::funcref; |