summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-validator.cpp
diff options
context:
space:
mode:
authorThomas Lively <7121787+tlively@users.noreply.github.com>2021-03-10 16:06:19 -0800
committerGitHub <noreply@github.com>2021-03-11 00:06:19 +0000
commitd369cd6474364e5797e40af94676339af03723a9 (patch)
tree2441fb6aec7ae185a73804fe61298854ee3495d9 /src/wasm/wasm-validator.cpp
parent9202df3864d2d8f09f191f61a964a08c30d10821 (diff)
downloadbinaryen-d369cd6474364e5797e40af94676339af03723a9.tar.gz
binaryen-d369cd6474364e5797e40af94676339af03723a9.tar.bz2
binaryen-d369cd6474364e5797e40af94676339af03723a9.zip
Make unreachable a subtype of everything (#3673)
Since in principle an unreachable expression can be used in any position. An exception to this rule is in OptimizeInstructions, which avoids replacing concrete expressions with unreachable expressions so that it doesn't need to refinalize any expressions. Notably, Type::getLeastUpperBound was already treating unreachable as the bottom type.
Diffstat (limited to 'src/wasm/wasm-validator.cpp')
-rw-r--r--src/wasm/wasm-validator.cpp143
1 files changed, 56 insertions, 87 deletions
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 70a9ad90f..057243fd3 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -196,18 +196,6 @@ struct ValidationInfo {
fail(text, curr, func);
return false;
}
-
- // Type 'left' should be a subtype of 'right', or unreachable.
- bool shouldBeSubTypeOrFirstIsUnreachable(Type left,
- Type right,
- Expression* curr,
- const char* text,
- Function* func = nullptr) {
- if (left == Type::unreachable) {
- return true;
- }
- return shouldBeSubType(left, right, curr, text, func);
- }
};
struct FunctionValidator : public WalkerPass<PostWalker<FunctionValidator>> {
@@ -441,14 +429,6 @@ private:
return info.shouldBeSubType(left, right, curr, text, getFunction());
}
- bool shouldBeSubTypeOrFirstIsUnreachable(Type left,
- Type right,
- Expression* curr,
- const char* text) {
- return info.shouldBeSubTypeOrFirstIsUnreachable(
- left, right, curr, text, getFunction());
- }
-
void validateAlignment(
size_t align, Type type, Index bytes, bool isAtomic, Expression* curr);
void validateMemBytes(uint8_t bytes, Type type, Expression* curr);
@@ -468,10 +448,10 @@ private:
}
size_t i = 0;
for (const auto& param : sig.params) {
- if (!shouldBeSubTypeOrFirstIsUnreachable(curr->operands[i]->type,
- param,
- curr,
- "call param types must match") &&
+ if (!shouldBeSubType(curr->operands[i]->type,
+ param,
+ curr,
+ "call param types must match") &&
!info.quiet) {
getStream() << "(on argument " << i << ")\n";
}
@@ -724,11 +704,10 @@ void FunctionValidator::visitLoop(Loop* curr) {
"if loop is not returning a value, final element should "
"not flow out a value");
} else {
- shouldBeSubTypeOrFirstIsUnreachable(
- curr->body->type,
- curr->type,
- curr,
- "loop with value and body must match types");
+ shouldBeSubType(curr->body->type,
+ curr->type,
+ curr,
+ "loop with value and body must match types");
}
}
}
@@ -750,16 +729,14 @@ void FunctionValidator::visitIf(If* curr) {
}
} else {
if (curr->type != Type::unreachable) {
- shouldBeSubTypeOrFirstIsUnreachable(
- curr->ifTrue->type,
- curr->type,
- curr,
- "returning if-else's true must have right type");
- shouldBeSubTypeOrFirstIsUnreachable(
- curr->ifFalse->type,
- curr->type,
- curr,
- "returning if-else's false must have right type");
+ shouldBeSubType(curr->ifTrue->type,
+ curr->type,
+ curr,
+ "returning if-else's true must have right type");
+ shouldBeSubType(curr->ifFalse->type,
+ curr->type,
+ curr,
+ "returning if-else's false must have right type");
} else {
if (curr->condition->type != Type::unreachable) {
shouldBeEqual(curr->ifTrue->type,
@@ -929,11 +906,10 @@ void FunctionValidator::visitGlobalSet(GlobalSet* curr) {
"global.set name must be valid (and not an import; imports "
"can't be modified)")) {
shouldBeTrue(global->mutable_, curr, "global.set global must be mutable");
- shouldBeSubTypeOrFirstIsUnreachable(
- curr->value->type,
- global->type,
- curr,
- "global.set value must have right type");
+ shouldBeSubType(curr->value->type,
+ global->type,
+ curr,
+ "global.set value must have right type");
}
}
@@ -2068,16 +2044,14 @@ void FunctionValidator::visitRefFunc(RefFunc* curr) {
void FunctionValidator::visitRefEq(RefEq* curr) {
shouldBeTrue(
getModule()->features.hasGC(), curr, "ref.eq requires gc to be enabled");
- shouldBeSubTypeOrFirstIsUnreachable(
- curr->left->type,
- Type::eqref,
- curr->left,
- "ref.eq's left argument should be a subtype of eqref");
- shouldBeSubTypeOrFirstIsUnreachable(
- curr->right->type,
- Type::eqref,
- curr->right,
- "ref.eq's right argument should be a subtype of eqref");
+ shouldBeSubType(curr->left->type,
+ Type::eqref,
+ curr->left,
+ "ref.eq's left argument should be a subtype of eqref");
+ shouldBeSubType(curr->right->type,
+ Type::eqref,
+ curr->right,
+ "ref.eq's right argument should be a subtype of eqref");
}
void FunctionValidator::noteDelegate(Name name, Expression* curr) {
@@ -2102,17 +2076,15 @@ void FunctionValidator::visitTry(Try* curr) {
noteLabelName(curr->name);
}
if (curr->type != Type::unreachable) {
- shouldBeSubTypeOrFirstIsUnreachable(
- curr->body->type,
- curr->type,
- curr->body,
- "try's type does not match try body's type");
+ shouldBeSubType(curr->body->type,
+ curr->type,
+ curr->body,
+ "try's type does not match try body's type");
for (auto catchBody : curr->catchBodies) {
- shouldBeSubTypeOrFirstIsUnreachable(
- catchBody->type,
- curr->type,
- catchBody,
- "try's type does not match catch's body type");
+ shouldBeSubType(catchBody->type,
+ curr->type,
+ catchBody,
+ "try's type does not match catch's body type");
}
} else {
shouldBeEqual(curr->body->type,
@@ -2166,10 +2138,10 @@ void FunctionValidator::visitThrow(Throw* curr) {
}
size_t i = 0;
for (const auto& param : event->sig.params) {
- if (!shouldBeSubTypeOrFirstIsUnreachable(curr->operands[i]->type,
- param,
- curr->operands[i],
- "event param types must match") &&
+ if (!shouldBeSubType(curr->operands[i]->type,
+ param,
+ curr->operands[i],
+ "event param types must match") &&
!info.quiet) {
getStream() << "(on argument " << i << ")\n";
}
@@ -2250,10 +2222,10 @@ void FunctionValidator::visitCallRef(CallRef* curr) {
void FunctionValidator::visitI31New(I31New* curr) {
shouldBeTrue(
getModule()->features.hasGC(), curr, "i31.new requires gc to be enabled");
- shouldBeSubTypeOrFirstIsUnreachable(curr->value->type,
- Type::i32,
- curr->value,
- "i31.new's argument should be i32");
+ shouldBeSubType(curr->value->type,
+ Type::i32,
+ curr->value,
+ "i31.new's argument should be i32");
}
void FunctionValidator::visitI31Get(I31Get* curr) {
@@ -2262,11 +2234,10 @@ void FunctionValidator::visitI31Get(I31Get* curr) {
"i31.get_s/u requires gc to be enabled");
// FIXME: use i31ref here, which is non-nullable, when we support non-
// nullability.
- shouldBeSubTypeOrFirstIsUnreachable(
- curr->i31->type,
- Type(HeapType::i31, Nullable),
- curr->i31,
- "i31.get_s/u's argument should be i31ref");
+ shouldBeSubType(curr->i31->type,
+ Type(HeapType::i31, Nullable),
+ curr->i31,
+ "i31.get_s/u's argument should be i31ref");
}
void FunctionValidator::visitRefTest(RefTest* curr) {
@@ -2536,17 +2507,15 @@ void FunctionValidator::visitFunction(Function* curr) {
}
// if function has no result, it is ignored
// if body is unreachable, it might be e.g. a return
- shouldBeSubTypeOrFirstIsUnreachable(
- curr->body->type,
- curr->sig.results,
- curr->body,
- "function body type must match, if function returns");
+ shouldBeSubType(curr->body->type,
+ curr->sig.results,
+ curr->body,
+ "function body type must match, if function returns");
for (Type returnType : returnTypes) {
- shouldBeSubTypeOrFirstIsUnreachable(
- returnType,
- curr->sig.results,
- curr->body,
- "function result must match, if function has returns");
+ shouldBeSubType(returnType,
+ curr->sig.results,
+ curr->body,
+ "function result must match, if function has returns");
}
assert(breakInfos.empty());