summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/wasm/wasm-validator.cpp100
1 files changed, 60 insertions, 40 deletions
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index c9024b343..3688587be 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -3305,11 +3305,6 @@ void FunctionValidator::visitResume(Resume* curr) {
}
void FunctionValidator::visitFunction(Function* curr) {
- if (curr->getResults().isTuple()) {
- shouldBeTrue(getModule()->features.hasMultivalue(),
- curr->body,
- "Multivalue function results (multivalue is not enabled)");
- }
FeatureSet features;
// Check for things like having a rec group with GC enabled. The type we're
// checking is a reference type even if this an MVP function type, so ignore
@@ -3330,28 +3325,7 @@ void FunctionValidator::visitFunction(Function* curr) {
shouldBeTrue(features <= getModule()->features,
curr->name,
"all used types should be allowed");
- if (curr->profile == IRProfile::Poppy) {
- shouldBeTrue(
- curr->body->is<Block>(), curr->body, "Function body must be a block");
- }
- // if function has no result, it is ignored
- // if body is unreachable, it might be e.g. a return
- shouldBeSubType(curr->body->type,
- curr->getResults(),
- curr->body,
- "function body type must match, if function returns");
- for (Type returnType : returnTypes) {
- shouldBeSubType(returnType,
- curr->getResults(),
- curr->body,
- "function result must match, if function has returns");
- }
- assert(breakTypes.empty());
- assert(delegateTargetNames.empty());
- assert(rethrowTargetNames.empty());
- returnTypes.clear();
- labelNames.clear();
// validate optional local names
std::unordered_set<Name> seen;
for (auto& pair : curr->localNames) {
@@ -3359,17 +3333,50 @@ void FunctionValidator::visitFunction(Function* curr) {
shouldBeTrue(seen.insert(name).second, name, "local names must be unique");
}
- if (getModule()->features.hasGC()) {
- // If we have non-nullable locals, verify that local.get are valid.
- LocalStructuralDominance info(curr, *getModule());
- for (auto index : info.nonDominatingIndices) {
- auto localType = curr->getLocalType(index);
- for (auto type : localType) {
- shouldBeTrue(!type.isNonNullable(),
- index,
- "non-nullable local's sets must dominate gets");
+ if (curr->body) {
+ if (curr->getResults().isTuple()) {
+ shouldBeTrue(getModule()->features.hasMultivalue(),
+ curr->body,
+ "Multivalue function results (multivalue is not enabled)");
+ }
+ if (curr->profile == IRProfile::Poppy) {
+ shouldBeTrue(
+ curr->body->is<Block>(), curr->body, "Function body must be a block");
+ }
+ // if function has no result, it is ignored
+ // if body is unreachable, it might be e.g. a return
+ shouldBeSubType(curr->body->type,
+ curr->getResults(),
+ curr->body,
+ "function body type must match, if function returns");
+ for (Type returnType : returnTypes) {
+ shouldBeSubType(returnType,
+ curr->getResults(),
+ curr->body,
+ "function result must match, if function has returns");
+ }
+
+ if (getModule()->features.hasGC()) {
+ // If we have non-nullable locals, verify that local.get are valid.
+ LocalStructuralDominance info(curr, *getModule());
+ for (auto index : info.nonDominatingIndices) {
+ auto localType = curr->getLocalType(index);
+ for (auto type : localType) {
+ shouldBeTrue(!type.isNonNullable(),
+ index,
+ "non-nullable local's sets must dominate gets");
+ }
}
}
+
+ // Assert that we finished with a clean state after processing the body's
+ // expressions, and reset the state for next time. Note that we use some of
+ // this state in the above validations, so this must appear last.
+ assert(breakTypes.empty());
+ assert(delegateTargetNames.empty());
+ assert(rethrowTargetNames.empty());
+ returnTypes.clear();
+ labelNames.clear();
}
}
@@ -3904,10 +3911,21 @@ bool WasmValidator::validate(Module& module, Flags flags) {
info.validateGlobally = (flags & Globally) != 0;
info.quiet = (flags & Quiet) != 0;
info.closedWorld = (flags & ClosedWorld) != 0;
- // parallel wasm logic validation
+
+ // Parallel function validation.
PassRunner runner(&module);
- FunctionValidator(module, &info).validate(&runner);
- // validate globally
+ FunctionValidator functionValidator(module, &info);
+ functionValidator.validate(&runner);
+
+ // Also validate imports, which were not covered in the parallel traversal
+ // since it is a function-parallel operation.
+ for (auto& func : module.functions) {
+ if (func->imported()) {
+ functionValidator.visitFunction(func.get());
+ }
+ }
+
+ // Validate globally.
if (info.validateGlobally) {
validateImports(module, info);
validateExports(module, info);
@@ -3922,11 +3940,13 @@ bool WasmValidator::validate(Module& module, Flags flags) {
validateClosedWorldInterface(module, info);
}
}
- // validate additional internal IR details when in pass-debug mode
+
+ // Validate additional internal IR details when in pass-debug mode.
if (PassRunner::getPassDebug()) {
validateBinaryenIR(module, info);
}
- // print all the data
+
+ // Print all the data.
if (!info.valid.load() && !info.quiet) {
for (auto& func : module.functions) {
std::cerr << info.getStream(func.get()).str();