summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-validator.cpp
diff options
context:
space:
mode:
authorThomas Lively <7121787+tlively@users.noreply.github.com>2019-12-11 17:12:37 -0800
committerAlon Zakai <azakai@google.com>2019-12-11 17:12:37 -0800
commit759c485a9f35bd859d43b86b02e1397a669fa469 (patch)
treea5c7475002b406e35c6d1e5c2d843000947ef192 /src/wasm/wasm-validator.cpp
parentacd786dbd1e59f9d105c4ec8603c2ff46f233649 (diff)
downloadbinaryen-759c485a9f35bd859d43b86b02e1397a669fa469.tar.gz
binaryen-759c485a9f35bd859d43b86b02e1397a669fa469.tar.bz2
binaryen-759c485a9f35bd859d43b86b02e1397a669fa469.zip
Remove FunctionType (#2510)
Function signatures were previously redundantly stored on Function objects as well as on FunctionType objects. These two signature representations had to always be kept in sync, which was error-prone and needlessly complex. This PR takes advantage of the new ability of Type to represent multiple value types by consolidating function signatures as a pair of Types (params and results) stored on the Function object. Since there are no longer module-global named function types, significant changes had to be made to the printing and emitting of function types, as well as their parsing and manipulation in various passes. The C and JS APIs and their tests also had to be updated to remove named function types.
Diffstat (limited to 'src/wasm/wasm-validator.cpp')
-rw-r--r--src/wasm/wasm-validator.cpp136
1 files changed, 67 insertions, 69 deletions
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 75121d4f4..c6de444c1 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -593,14 +593,15 @@ void FunctionValidator::visitCall(Call* curr) {
if (!shouldBeTrue(!!target, curr, "call target must exist")) {
return;
}
- if (!shouldBeTrue(curr->operands.size() == target->params.size(),
+ const std::vector<Type> params = target->sig.params.expand();
+ if (!shouldBeTrue(curr->operands.size() == params.size(),
curr,
"call param number must match")) {
return;
}
for (size_t i = 0; i < curr->operands.size(); i++) {
if (!shouldBeEqualOrFirstIsUnreachable(curr->operands[i]->type,
- target->params[i],
+ params[i],
curr,
"call param types must match") &&
!info.quiet) {
@@ -613,8 +614,8 @@ void FunctionValidator::visitCall(Call* curr) {
curr,
"return_call should have unreachable type");
shouldBeEqual(
- getFunction()->result,
- target->result,
+ getFunction()->sig.results,
+ target->sig.results,
curr,
"return_call callee return type must match caller return type");
} else {
@@ -629,7 +630,7 @@ void FunctionValidator::visitCall(Call* curr) {
"calls may only be unreachable if they have unreachable operands");
} else {
shouldBeEqual(curr->type,
- target->result,
+ target->sig.results,
curr,
"call type must match callee return type");
}
@@ -643,20 +644,17 @@ void FunctionValidator::visitCallIndirect(CallIndirect* curr) {
if (!info.validateGlobally) {
return;
}
- auto* type = getModule()->getFunctionTypeOrNull(curr->fullType);
- if (!shouldBeTrue(!!type, curr, "call_indirect type must exist")) {
- return;
- }
+ const std::vector<Type>& params = curr->sig.params.expand();
shouldBeEqualOrFirstIsUnreachable(
curr->target->type, i32, curr, "indirect call target must be an i32");
- if (!shouldBeTrue(curr->operands.size() == type->params.size(),
+ if (!shouldBeTrue(curr->operands.size() == params.size(),
curr,
"call param number must match")) {
return;
}
for (size_t i = 0; i < curr->operands.size(); i++) {
if (!shouldBeEqualOrFirstIsUnreachable(curr->operands[i]->type,
- type->params[i],
+ params[i],
curr,
"call param types must match") &&
!info.quiet) {
@@ -669,8 +667,8 @@ void FunctionValidator::visitCallIndirect(CallIndirect* curr) {
curr,
"return_call_indirect should have unreachable type");
shouldBeEqual(
- getFunction()->result,
- type->result,
+ getFunction()->sig.results,
+ curr->sig.results,
curr,
"return_call_indirect callee return type must match caller return type");
} else {
@@ -687,7 +685,7 @@ void FunctionValidator::visitCallIndirect(CallIndirect* curr) {
}
} else {
shouldBeEqual(curr->type,
- type->result,
+ curr->sig.results,
curr,
"call_indirect type must match callee return type");
}
@@ -701,31 +699,35 @@ void FunctionValidator::visitConst(Const* curr) {
}
void FunctionValidator::visitLocalGet(LocalGet* curr) {
- shouldBeTrue(curr->index < getFunction()->getNumLocals(),
- curr,
- "local.get index must be small enough");
shouldBeTrue(curr->type.isConcrete(),
curr,
"local.get must have a valid type - check what you provided "
"when you constructed the node");
- shouldBeTrue(curr->type == getFunction()->getLocalType(curr->index),
- curr,
- "local.get must have proper type");
+ if (shouldBeTrue(curr->index < getFunction()->getNumLocals(),
+ curr,
+ "local.get index must be small enough")) {
+ shouldBeTrue(curr->type == getFunction()->getLocalType(curr->index),
+ curr,
+ "local.get must have proper type");
+ }
}
void FunctionValidator::visitLocalSet(LocalSet* curr) {
- shouldBeTrue(curr->index < getFunction()->getNumLocals(),
- curr,
- "local.set index must be small enough");
- if (curr->value->type != unreachable) {
- if (curr->type != none) { // tee is ok anyhow
- shouldBeEqualOrFirstIsUnreachable(
- curr->value->type, curr->type, curr, "local.set type must be correct");
+ if (shouldBeTrue(curr->index < getFunction()->getNumLocals(),
+ curr,
+ "local.set index must be small enough")) {
+ if (curr->value->type != unreachable) {
+ if (curr->type != none) { // tee is ok anyhow
+ shouldBeEqualOrFirstIsUnreachable(curr->value->type,
+ curr->type,
+ curr,
+ "local.set type must be correct");
+ }
+ shouldBeEqual(getFunction()->getLocalType(curr->index),
+ curr->value->type,
+ curr,
+ "local.set type must match function");
}
- shouldBeEqual(getFunction()->getLocalType(curr->index),
- curr->value->type,
- curr,
- "local.set type must match function");
}
}
@@ -1754,28 +1756,35 @@ void FunctionValidator::visitBrOnExn(BrOnExn* curr) {
}
void FunctionValidator::visitFunction(Function* curr) {
- FeatureSet typeFeatures = getFeatures(curr->result);
- for (auto type : curr->params) {
- typeFeatures |= getFeatures(type);
+ shouldBeTrue(!curr->sig.results.isMulti(),
+ curr->body,
+ "Multivalue functions not allowed yet");
+ FeatureSet features;
+ for (auto type : curr->sig.params.expand()) {
+ features |= getFeatures(type);
shouldBeTrue(type.isConcrete(), curr, "params must be concretely typed");
}
+ for (auto type : curr->sig.results.expand()) {
+ features |= getFeatures(type);
+ shouldBeTrue(type.isConcrete(), curr, "results must be concretely typed");
+ }
for (auto type : curr->vars) {
- typeFeatures |= getFeatures(type);
+ features |= getFeatures(type);
shouldBeTrue(type.isConcrete(), curr, "vars must be concretely typed");
}
- shouldBeTrue(typeFeatures <= getModule()->features,
+ shouldBeTrue(features <= getModule()->features,
curr,
"all used types should be allowed");
// if function has no result, it is ignored
// if body is unreachable, it might be e.g. a return
if (curr->body->type != unreachable) {
- shouldBeEqual(curr->result,
+ shouldBeEqual(curr->sig.results,
curr->body->type,
curr->body,
"function body type must match, if function returns");
}
if (returnType != unreachable) {
- shouldBeEqual(curr->result,
+ shouldBeEqual(curr->sig.results,
returnType,
curr->body,
"function result must match, if function has returns");
@@ -1784,22 +1793,6 @@ void FunctionValidator::visitFunction(Function* curr) {
breakInfos.empty(), curr->body, "all named break targets must exist");
returnType = unreachable;
labelNames.clear();
- // if function has a named type, it must match up with the function's params
- // and result
- if (info.validateGlobally && curr->type.is()) {
- auto* ft = getModule()->getFunctionType(curr->type);
- shouldBeTrue(ft->params == curr->params,
- curr->name,
- "function params must match its declared type");
- shouldBeTrue(ft->result == curr->result,
- curr->name,
- "function result must match its declared type");
- }
- if (curr->imported()) {
- shouldBeTrue(curr->type.is(),
- curr->name,
- "imported functions must have a function type");
- }
// validate optional local names
std::set<Name> seen;
for (auto& pair : curr->localNames) {
@@ -1925,17 +1918,18 @@ static void validateBinaryenIR(Module& wasm, ValidationInfo& info) {
static void validateImports(Module& module, ValidationInfo& info) {
ModuleUtils::iterImportedFunctions(module, [&](Function* curr) {
if (info.validateWeb) {
- auto* functionType = module.getFunctionType(curr->type);
- info.shouldBeUnequal(functionType->result,
- i64,
- curr->name,
- "Imported function must not have i64 return type");
- for (Type param : functionType->params) {
+ for (Type param : curr->sig.params.expand()) {
info.shouldBeUnequal(param,
i64,
curr->name,
"Imported function must not have i64 parameters");
}
+ for (Type result : curr->sig.results.expand()) {
+ info.shouldBeUnequal(result,
+ i64,
+ curr->name,
+ "Imported function must not have i64 results");
+ }
}
});
if (!module.features.hasMutableGlobals()) {
@@ -1951,17 +1945,19 @@ static void validateExports(Module& module, ValidationInfo& info) {
if (curr->kind == ExternalKind::Function) {
if (info.validateWeb) {
Function* f = module.getFunction(curr->value);
- info.shouldBeUnequal(f->result,
- i64,
- f->name,
- "Exported function must not have i64 return type");
- for (auto param : f->params) {
+ for (auto param : f->sig.params.expand()) {
info.shouldBeUnequal(
param,
i64,
f->name,
"Exported function must not have i64 parameters");
}
+ for (auto result : f->sig.results.expand()) {
+ info.shouldBeUnequal(result,
+ i64,
+ f->name,
+ "Exported function must not have i64 results");
+ }
}
} else if (curr->kind == ExternalKind::Global &&
!module.features.hasMutableGlobals()) {
@@ -2133,10 +2129,12 @@ static void validateModule(Module& module, ValidationInfo& info) {
auto func = module.getFunctionOrNull(module.start);
if (info.shouldBeTrue(
func != nullptr, module.start, "start must be found")) {
- info.shouldBeTrue(
- func->params.size() == 0, module.start, "start must have 0 params");
- info.shouldBeTrue(
- func->result == none, module.start, "start must not return a value");
+ info.shouldBeTrue(func->sig.params == Type::none,
+ module.start,
+ "start must have 0 params");
+ info.shouldBeTrue(func->sig.results == Type::none,
+ module.start,
+ "start must not return a value");
}
}
}