summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-08-21 11:45:24 -0700
committerGitHub <noreply@github.com>2023-08-21 11:45:24 -0700
commit4672c533985e8f2c9a88dec616aa3d9b95deb63e (patch)
tree2a78580977dec80e3f56b54debc67b48e064aa28 /src
parentb41ec7cb488481e5b1a57fc7203e9c0bc7331bbd (diff)
downloadbinaryen-4672c533985e8f2c9a88dec616aa3d9b95deb63e.tar.gz
binaryen-4672c533985e8f2c9a88dec616aa3d9b95deb63e.tar.bz2
binaryen-4672c533985e8f2c9a88dec616aa3d9b95deb63e.zip
Fix finalization of call_ref to handle refined target types (#5883)
Previously CallRef::finalize() would never update the type of the CallRef, even if the type of the call target had been refined to give a more precise result type. Besides unnecessarily losing type information, this could also lead to validation errors, since the validator checks that the type of CallRef matches the result type of the target signature. Fix the bug by updating CallRef's type based on its target signature in CallRef::finalize() and add a test that depends on this refinalization.
Diffstat (limited to 'src')
-rw-r--r--src/wasm.h1
-rw-r--r--src/wasm/wasm-binary.cpp5
-rw-r--r--src/wasm/wasm-s-parser.cpp7
-rw-r--r--src/wasm/wasm.cpp17
4 files changed, 22 insertions, 8 deletions
diff --git a/src/wasm.h b/src/wasm.h
index 39cc9fb54..90628c5bf 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -1503,7 +1503,6 @@ public:
bool isReturn = false;
void finalize();
- void finalize(Type type_);
};
class RefTest : public SpecificExpression<Expression::RefTestId> {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 0d405251e..684afe80c 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -6936,7 +6936,10 @@ void WasmBinaryReader::visitCallRef(CallRef* curr) {
for (size_t i = 0; i < num; i++) {
curr->operands[num - i - 1] = popNonVoidExpression();
}
- curr->finalize(sig.results);
+ // If the target has bottom type, we won't be able to infer the correct type
+ // from it, so set the type manually to be safe.
+ curr->type = sig.results;
+ curr->finalize();
}
bool WasmBinaryReader::maybeVisitI31New(Expression*& out, uint32_t code) {
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 0519afd83..4fa4981e4 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2822,6 +2822,13 @@ Expression* SExpressionWasmBuilder::makeCallRef(Element& s, bool isReturn) {
s.line,
s.col);
}
+ if (!Type::isSubType(target->type, Type(sigType, Nullable))) {
+ throw ParseException(
+ std::string(isReturn ? "return_call_ref" : "call_ref") +
+ " target should match expected type",
+ s.line,
+ s.col);
+ }
return Builder(wasm).makeCallRef(
target, operands, sigType.getSignature().results, isReturn);
}
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 74b944bb6..188cd2d6f 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -920,18 +920,23 @@ void I31Get::finalize() {
}
void CallRef::finalize() {
- handleUnreachableOperands(this);
+ if (handleUnreachableOperands(this)) {
+ return;
+ }
if (isReturn) {
type = Type::unreachable;
+ return;
}
if (target->type == Type::unreachable) {
type = Type::unreachable;
+ return;
}
-}
-
-void CallRef::finalize(Type type_) {
- type = type_;
- finalize();
+ assert(target->type.isRef());
+ if (target->type.getHeapType().isBottom()) {
+ return;
+ }
+ assert(target->type.getHeapType().isSignature());
+ type = target->type.getHeapType().getSignature().results;
}
void RefTest::finalize() {