summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gen-s-parser.inc3
-rw-r--r--src/passes/Print.cpp3
-rw-r--r--src/wasm-binary.h1
-rw-r--r--src/wasm-interpreter.h9
-rw-r--r--src/wasm.h7
-rw-r--r--src/wasm/wasm-binary.cpp6
-rw-r--r--src/wasm/wasm-stack.cpp18
-rw-r--r--src/wasm/wasm.cpp13
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;