diff options
author | Thomas Lively <7121787+tlively@users.noreply.github.com> | 2021-07-01 01:56:23 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-30 18:56:23 -0700 |
commit | ca27f40a2f1070a16ee7c0efc18ff35d342d8027 (patch) | |
tree | ab0f2b1b731737bc409db21f677b97be16f67c0f /src | |
parent | 10ef52d62468aec5762742930630e882dc5e5c0b (diff) | |
download | binaryen-ca27f40a2f1070a16ee7c0efc18ff35d342d8027.tar.gz binaryen-ca27f40a2f1070a16ee7c0efc18ff35d342d8027.tar.bz2 binaryen-ca27f40a2f1070a16ee7c0efc18ff35d342d8027.zip |
Preserve Function HeapTypes (#3952)
When using nominal types, func.ref of two functions with identical signatures
but different HeapTypes will yield different types. To preserve these semantics,
Functions need to track their HeapTypes, not just their Signatures.
This PR replaces the Signature field in Function with a HeapType field and adds
new utility methods to make it almost as simple to update and query the function
HeapType as it was to update and query the Function Signature.
Diffstat (limited to 'src')
48 files changed, 278 insertions, 285 deletions
diff --git a/src/abi/js.h b/src/abi/js.h index 118a2c981..970f7ffa7 100644 --- a/src/abi/js.h +++ b/src/abi/js.h @@ -18,6 +18,7 @@ #define wasm_abi_abi_h #include "asmjs/shared-constants.h" +#include "wasm-builder.h" #include "wasm.h" namespace wasm { @@ -64,9 +65,7 @@ inline void ensureHelpers(Module* wasm, if (specific.is() && name != specific) { return; } - auto func = make_unique<Function>(); - func->name = name; - func->sig = Signature(params, results); + auto func = Builder::makeFunction(name, Signature(params, results), {}); func->module = ENV; func->base = name; wasm->addFunction(std::move(func)); diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 66c4341e3..d7f23e259 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -3280,7 +3280,8 @@ BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, BinaryenExpressionRef body) { auto* ret = new Function; ret->setExplicitName(name); - ret->sig = Signature(Type(params), Type(results)); + // TODO: Take a HeapType rather than params and results. + ret->type = Signature(Type(params), Type(results)); for (BinaryenIndex i = 0; i < numVarTypes; i++) { ret->vars.push_back(Type(varTypes[i])); } @@ -3380,7 +3381,8 @@ void BinaryenAddFunctionImport(BinaryenModuleRef module, ret->name = internalName; ret->module = externalModuleName; ret->base = externalBaseName; - ret->sig = Signature(Type(params), Type(results)); + // TODO: Take a HeapType rather than params and results. + ret->type = Signature(Type(params), Type(results)); ((Module*)module)->addFunction(ret); } void BinaryenAddTableImport(BinaryenModuleRef module, @@ -3547,7 +3549,7 @@ BinaryenAddActiveElementSegment(BinaryenModuleRef module, Fatal() << "invalid function '" << funcNames[i] << "'."; } segment->data.push_back( - Builder(*(Module*)module).makeRefFunc(funcNames[i], func->sig)); + Builder(*(Module*)module).makeRefFunc(funcNames[i], func->type)); } return ((Module*)module)->addElementSegment(std::move(segment)); } @@ -3564,7 +3566,7 @@ BinaryenAddPassiveElementSegment(BinaryenModuleRef module, Fatal() << "invalid function '" << funcNames[i] << "'."; } segment->data.push_back( - Builder(*(Module*)module).makeRefFunc(funcNames[i], func->sig)); + Builder(*(Module*)module).makeRefFunc(funcNames[i], func->type)); } return ((Module*)module)->addElementSegment(std::move(segment)); } @@ -4006,14 +4008,16 @@ const char* BinaryenModuleGetDebugInfoFileName(BinaryenModuleRef module, // ========== Function Operations ========== // +// TODO: add BinaryenFunctionGetType + const char* BinaryenFunctionGetName(BinaryenFunctionRef func) { return ((Function*)func)->name.c_str(); } BinaryenType BinaryenFunctionGetParams(BinaryenFunctionRef func) { - return ((Function*)func)->sig.params.getID(); + return ((Function*)func)->getParams().getID(); } BinaryenType BinaryenFunctionGetResults(BinaryenFunctionRef func) { - return ((Function*)func)->sig.results.getID(); + return ((Function*)func)->getResults().getID(); } BinaryenIndex BinaryenFunctionGetNumVars(BinaryenFunctionRef func) { return ((Function*)func)->vars.size(); diff --git a/src/ir/ExpressionAnalyzer.cpp b/src/ir/ExpressionAnalyzer.cpp index 0c6081b03..260a9a6c4 100644 --- a/src/ir/ExpressionAnalyzer.cpp +++ b/src/ir/ExpressionAnalyzer.cpp @@ -60,7 +60,7 @@ bool ExpressionAnalyzer::isResultUsed(ExpressionStack& stack, Function* func) { } } // The value might be used, so it depends on if the function returns - return func->sig.results != Type::none; + return func->getResults() != Type::none; } // Checks if a value is dropped. diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp index 6f1a22095..419b83cc2 100644 --- a/src/ir/ReFinalize.cpp +++ b/src/ir/ReFinalize.cpp @@ -171,7 +171,7 @@ void ReFinalize::visitRefAs(RefAs* curr) { curr->finalize(); } void ReFinalize::visitFunction(Function* curr) { // we may have changed the body from unreachable to none, which might be bad // if the function has a return value - if (curr->sig.results != Type::none && curr->body->type == Type::none) { + if (curr->getResults() != Type::none && curr->body->type == Type::none) { Builder builder(*getModule()); curr->body = builder.blockify(curr->body, builder.makeUnreachable()); } diff --git a/src/ir/function-utils.h b/src/ir/function-utils.h index f172240e2..b1654d965 100644 --- a/src/ir/function-utils.h +++ b/src/ir/function-utils.h @@ -28,13 +28,13 @@ namespace FunctionUtils { // everything but their name (which can't be the same, in the same // module!) - same params, vars, body, result, etc. inline bool equal(Function* left, Function* right) { - if (left->sig != right->sig) { + if (left->type != right->type) { return false; } if (left->getNumVars() != right->getNumVars()) { return false; } - for (Index i = left->sig.params.size(); i < left->getNumLocals(); i++) { + for (Index i = left->getParams().size(); i < left->getNumLocals(); i++) { if (left->getLocalType(i) != right->getLocalType(i)) { return false; } diff --git a/src/ir/hashed.h b/src/ir/hashed.h index fe959936a..4a6e1647e 100644 --- a/src/ir/hashed.h +++ b/src/ir/hashed.h @@ -64,8 +64,7 @@ struct FunctionHasher : public WalkerPass<PostWalker<FunctionHasher>> { void doWalkFunction(Function* func) { output->at(func) = hashFunction(func); } static size_t hashFunction(Function* func) { - auto digest = hash(func->sig.params.getID()); - rehash(digest, func->sig.results.getID()); + auto digest = hash(func->type); for (auto type : func->vars) { rehash(digest, type.getID()); } diff --git a/src/ir/module-splitting.cpp b/src/ir/module-splitting.cpp index 62c10222a..2ef9f505d 100644 --- a/src/ir/module-splitting.cpp +++ b/src/ir/module-splitting.cpp @@ -122,7 +122,7 @@ struct TableSlotManager { ElementSegment* makeElementSegment(); // Returns the table index for `func`, allocating a new index if necessary. - Slot getSlot(Name func, Signature sig); + Slot getSlot(Name func, HeapType type); void addSlot(Name func, Slot slot); }; @@ -209,7 +209,7 @@ ElementSegment* TableSlotManager::makeElementSegment() { Builder(module).makeConst(int32_t(0)))); } -TableSlotManager::Slot TableSlotManager::getSlot(Name func, Signature sig) { +TableSlotManager::Slot TableSlotManager::getSlot(Name func, HeapType type) { auto slotIt = funcIndices.find(func); if (slotIt != funcIndices.end()) { return slotIt->second; @@ -237,7 +237,7 @@ TableSlotManager::Slot TableSlotManager::getSlot(Name func, Signature sig) { activeBase.index + Index(activeSegment->data.size())}; Builder builder(module); - activeSegment->data.push_back(builder.makeRefFunc(func, sig)); + activeSegment->data.push_back(builder.makeRefFunc(func, type)); addSlot(func, newSlot); if (activeTable->initial <= newSlot.index) { @@ -365,7 +365,7 @@ void ModuleSplitter::exportImportFunction(Name funcName) { // module. if (secondary.getFunctionOrNull(funcName) == nullptr) { auto func = - Builder::makeFunction(funcName, primary.getFunction(funcName)->sig, {}); + Builder::makeFunction(funcName, primary.getFunction(funcName)->type, {}); func->module = config.importNamespace; func->base = exportName; secondary.addFunction(std::move(func)); @@ -399,14 +399,15 @@ void ModuleSplitter::thunkExportedSecondaryFunctions() { continue; } auto* func = primary.addFunction(Builder::makeFunction( - secondaryFunc, secondary.getFunction(secondaryFunc)->sig, {})); + secondaryFunc, secondary.getFunction(secondaryFunc)->type, {})); std::vector<Expression*> args; - for (size_t i = 0, size = func->sig.params.size(); i < size; ++i) { - args.push_back(builder.makeLocalGet(i, func->sig.params[i])); + Type params = func->getParams(); + for (size_t i = 0, size = params.size(); i < size; ++i) { + args.push_back(builder.makeLocalGet(i, params[i])); } - auto tableSlot = tableManager.getSlot(secondaryFunc, func->sig); + auto tableSlot = tableManager.getSlot(secondaryFunc, func->type); func->body = builder.makeCallIndirect( - tableSlot.tableName, tableSlot.makeExpr(primary), args, func->sig); + tableSlot.tableName, tableSlot.makeExpr(primary), args, func->getSig()); } } @@ -425,12 +426,12 @@ void ModuleSplitter::indirectCallsToSecondaryFunctions() { return; } auto* func = parent.secondary.getFunction(curr->target); - auto tableSlot = parent.tableManager.getSlot(curr->target, func->sig); + auto tableSlot = parent.tableManager.getSlot(curr->target, func->type); replaceCurrent( builder.makeCallIndirect(tableSlot.tableName, tableSlot.makeExpr(parent.primary), curr->operands, - func->sig, + func->getSig(), curr->isReturn)); } void visitRefFunc(RefFunc* curr) { @@ -496,7 +497,7 @@ void ModuleSplitter::setupTablePatching() { primary, std::string("placeholder_") + std::string(placeholder->base.c_str())); placeholder->hasExplicitName = false; - placeholder->sig = secondaryFunc->sig; + placeholder->type = secondaryFunc->type; elem = placeholder->name; primary.addFunction(std::move(placeholder)); } @@ -535,7 +536,7 @@ void ModuleSplitter::setupTablePatching() { if (replacement->first == i) { // primarySeg->data[i] is a placeholder, so use the secondary function. auto* func = replacement->second; - auto* ref = Builder(secondary).makeRefFunc(func->name, func->sig); + auto* ref = Builder(secondary).makeRefFunc(func->name, func->type); secondaryElems.push_back(ref); ++replacement; } else if (auto* get = primarySeg->data[i]->dynCast<RefFunc>()) { @@ -574,7 +575,7 @@ void ModuleSplitter::setupTablePatching() { currData.clear(); } auto* func = curr->second; - currData.push_back(Builder(secondary).makeRefFunc(func->name, func->sig)); + currData.push_back(Builder(secondary).makeRefFunc(func->name, func->type)); } if (currData.size()) { finishSegment(); diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h index 9c9f5cbfb..2cbab414b 100644 --- a/src/ir/module-utils.h +++ b/src/ir/module-utils.h @@ -33,7 +33,7 @@ namespace ModuleUtils { inline Function* copyFunction(Function* func, Module& out) { auto* ret = new Function(); ret->name = func->name; - ret->sig = func->sig; + ret->type = func->type; ret->vars = func->vars; ret->localNames = func->localNames; ret->localIndices = func->localIndices; @@ -526,7 +526,7 @@ inline void collectHeapTypes(Module& wasm, // Collect info from functions in parallel. ModuleUtils::ParallelFunctionAnalysis<Counts, InsertOrderedMap> analysis( wasm, [&](Function* func, Counts& counts) { - counts.note(func->sig); + counts.note(func->type); for (auto type : func->vars) { counts.note(type); } diff --git a/src/ir/table-utils.h b/src/ir/table-utils.h index 59d7cc3df..99a5bbf5b 100644 --- a/src/ir/table-utils.h +++ b/src/ir/table-utils.h @@ -87,7 +87,7 @@ inline Index append(Table& table, Name name, Module& wasm) { auto* func = wasm.getFunctionOrNull(name); assert(func != nullptr && "Cannot append non-existing function to a table."); - segment->data.push_back(Builder(wasm).makeRefFunc(name, func->sig)); + segment->data.push_back(Builder(wasm).makeRefFunc(name, func->type)); table.initial++; return tableIndex; } diff --git a/src/ir/utils.h b/src/ir/utils.h index 78b546962..157293e31 100644 --- a/src/ir/utils.h +++ b/src/ir/utils.h @@ -237,7 +237,7 @@ struct AutoDrop : public WalkerPass<ExpressionStackWalker<AutoDrop>> { void doWalkFunction(Function* curr) { ReFinalize().walkFunctionInModule(curr, getModule()); walk(curr->body); - if (curr->sig.results == Type::none && curr->body->type.isConcrete()) { + if (curr->getResults() == Type::none && curr->body->type.isConcrete()) { curr->body = Builder(*getModule()).makeDrop(curr->body); } ReFinalize().walkFunctionInModule(curr, getModule()); diff --git a/src/passes/Asyncify.cpp b/src/passes/Asyncify.cpp index 4bd9dee61..d0d03c9d1 100644 --- a/src/passes/Asyncify.cpp +++ b/src/passes/Asyncify.cpp @@ -862,7 +862,7 @@ struct AsyncifyFlow : public Pass { State::Rewinding), // TODO: such checks can be !normal makeCallIndexPop()), process(func->body)}); - if (func->sig.results != Type::none) { + if (func->getResults() != Type::none) { // Rewriting control flow may alter things; make sure the function ends in // something valid (which the optimizer can remove later). block->list.push_back(builder->makeUnreachable()); @@ -1204,7 +1204,7 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> { walk(func->body); // After the normal function body, emit a barrier before the postamble. Expression* barrier; - if (func->sig.results == Type::none) { + if (func->getResults() == Type::none) { // The function may have ended without a return; ensure one. barrier = builder->makeReturn(); } else { @@ -1222,12 +1222,12 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> { builder->makeSequence(func->body, barrier))), makeCallIndexPush(unwindIndex), makeLocalSaving()}); - if (func->sig.results != Type::none) { + if (func->getResults() != Type::none) { // If we unwind, we must still "return" a value, even if it will be // ignored on the outside. newBody->list.push_back( - LiteralUtils::makeZero(func->sig.results, *getModule())); - newBody->finalize(func->sig.results); + LiteralUtils::makeZero(func->getResults(), *getModule())); + newBody->finalize(func->getResults()); } func->body = newBody; // Making things like returns conditional may alter types. diff --git a/src/passes/CodeFolding.cpp b/src/passes/CodeFolding.cpp index 5362e310d..5b7c88024 100644 --- a/src/passes/CodeFolding.cpp +++ b/src/passes/CodeFolding.cpp @@ -742,7 +742,7 @@ private: mergeable.pop_back(); } // ensure the replacement has the same type, so the outside is not surprised - outer->finalize(getFunction()->sig.results); + outer->finalize(getFunction()->getResults()); getFunction()->body = outer; return true; } diff --git a/src/passes/DeNaN.cpp b/src/passes/DeNaN.cpp index 8dadb90de..44dd0bf15 100644 --- a/src/passes/DeNaN.cpp +++ b/src/passes/DeNaN.cpp @@ -120,9 +120,7 @@ struct DeNaN : public WalkerPass< // Add helper functions after the walk, so they are not instrumented. Builder builder(*module); auto add = [&](Name name, Type type, Literal literal, BinaryOp op) { - auto* func = new Function; - func->name = name; - func->sig = Signature(type, type); + auto func = Builder::makeFunction(name, Signature(type, type), {}); // Compare the value to itself to check if it is a NaN, and return 0 if // so: // @@ -139,7 +137,7 @@ struct DeNaN : public WalkerPass< op, builder.makeLocalGet(0, type), builder.makeLocalGet(0, type)), builder.makeLocalGet(0, type), builder.makeConst(literal)); - module->addFunction(func); + module->addFunction(std::move(func)); }; add(deNan32, Type::f32, Literal(float(0)), EqFloat32); add(deNan64, Type::f64, Literal(double(0)), EqFloat64); diff --git a/src/passes/DeadArgumentElimination.cpp b/src/passes/DeadArgumentElimination.cpp index 33ca81dc7..a95d4f91a 100644 --- a/src/passes/DeadArgumentElimination.cpp +++ b/src/passes/DeadArgumentElimination.cpp @@ -405,7 +405,7 @@ struct DAE : public Pass { // once to remove a param, once to drop the return value). if (changed.empty()) { for (auto& func : module->functions) { - if (func->sig.results == Type::none) { + if (func->getResults() == Type::none) { continue; } auto name = func->name; @@ -451,10 +451,11 @@ private: // Remove the parameter from the function. We must add a new local // for uses of the parameter, but cannot make it use the same index // (in general). - std::vector<Type> params(func->sig.params.begin(), func->sig.params.end()); + auto paramsType = func->getParams(); + std::vector<Type> params(paramsType.begin(), paramsType.end()); auto type = params[i]; params.erase(params.begin() + i); - func->sig.params = Type(params); + func->setParams(Type(params)); Index newIndex = Builder::addVar(func, type); // Update local operations. struct LocalUpdater : public PostWalker<LocalUpdater> { @@ -482,7 +483,7 @@ private: void removeReturnValue(Function* func, std::vector<Call*>& calls, Module* module) { - func->sig.results = Type::none; + func->setResults(Type::none); Builder builder(*module); // Remove any return values. struct ReturnUpdater : public PostWalker<ReturnUpdater> { diff --git a/src/passes/Directize.cpp b/src/passes/Directize.cpp index 3a7ef1024..086cc88a5 100644 --- a/src/passes/Directize.cpp +++ b/src/passes/Directize.cpp @@ -66,7 +66,7 @@ struct FunctionDirectizer : public WalkerPass<PostWalker<FunctionDirectizer>> { return; } auto* func = getModule()->getFunction(name); - if (curr->sig != func->sig) { + if (curr->sig != func->getSig()) { replaceWithUnreachable(curr); return; } diff --git a/src/passes/DuplicateImportElimination.cpp b/src/passes/DuplicateImportElimination.cpp index b917c5fe8..a4d9065c5 100644 --- a/src/passes/DuplicateImportElimination.cpp +++ b/src/passes/DuplicateImportElimination.cpp @@ -41,7 +41,7 @@ struct DuplicateImportElimination : public Pass { auto previousFunc = module->getFunction(previousName); // It is ok to import the same thing with multiple types; we can only // merge if the types match, of course. - if (previousFunc->sig == func->sig) { + if (previousFunc->type == func->type) { replacements[func->name] = previousName; toRemove.push_back(func->name); continue; diff --git a/src/passes/FuncCastEmulation.cpp b/src/passes/FuncCastEmulation.cpp index e63375f2b..d8b9f9b1d 100644 --- a/src/passes/FuncCastEmulation.cpp +++ b/src/passes/FuncCastEmulation.cpp @@ -199,11 +199,11 @@ private: } // The item in the table may be a function or a function import. auto* func = module->getFunction(name); - Type type = func->sig.results; + Type type = func->getResults(); Builder builder(*module); std::vector<Expression*> callOperands; Index i = 0; - for (const auto& param : func->sig.params) { + for (const auto& param : func->getParams()) { callOperands.push_back( fromABI(builder.makeLocalGet(i++, Type::i64), param, module)); } diff --git a/src/passes/GenerateDynCalls.cpp b/src/passes/GenerateDynCalls.cpp index 0f4934c06..2487085c0 100644 --- a/src/passes/GenerateDynCalls.cpp +++ b/src/passes/GenerateDynCalls.cpp @@ -40,8 +40,8 @@ struct GenerateDynCalls : public WalkerPass<PostWalker<GenerateDynCalls>> { void doWalkModule(Module* wasm) { PostWalker<GenerateDynCalls>::doWalkModule(wasm); - for (auto& sig : invokeSigs) { - generateDynCallThunk(sig); + for (auto& type : invokeTypes) { + generateDynCallThunk(type); } } @@ -61,7 +61,7 @@ struct GenerateDynCalls : public WalkerPass<PostWalker<GenerateDynCalls>> { std::vector<Name> tableSegmentData; ElementUtils::iterElementSegmentFunctionNames( it->get(), [&](Name name, Index) { - generateDynCallThunk(wasm->getFunction(name)->sig); + generateDynCallThunk(wasm->getFunction(name)->type); }); } } @@ -70,19 +70,19 @@ struct GenerateDynCalls : public WalkerPass<PostWalker<GenerateDynCalls>> { // Generate dynCalls for invokes if (func->imported() && func->module == ENV && func->base.startsWith("invoke_")) { - Signature sig = func->sig; + Signature sig = func->type.getSignature(); // The first parameter is a pointer to the original function that's called // by the invoke, so skip it std::vector<Type> newParams(sig.params.begin() + 1, sig.params.end()); - invokeSigs.insert(Signature(Type(newParams), sig.results)); + invokeTypes.insert(Signature(Type(newParams), sig.results)); } } - void generateDynCallThunk(Signature sig); + void generateDynCallThunk(HeapType funcType); bool onlyI64; - // The set of all invokes' signatures - InsertOrderedSet<Signature> invokeSigs; + // The set of all invokes' signature types. + InsertOrderedSet<HeapType> invokeTypes; }; static bool hasI64(Signature sig) { @@ -116,7 +116,8 @@ static void exportFunction(Module& wasm, Name name, bool must_export) { wasm.addExport(exp); } -void GenerateDynCalls::generateDynCallThunk(Signature sig) { +void GenerateDynCalls::generateDynCallThunk(HeapType funcType) { + Signature sig = funcType.getSignature(); if (onlyI64 && !hasI64(sig)) { return; } @@ -127,13 +128,17 @@ void GenerateDynCalls::generateDynCallThunk(Signature sig) { if (wasm->getFunctionOrNull(name) || wasm->getExportOrNull(name)) { return; // module already contains this dyncall } - std::vector<NameType> params; - params.emplace_back("fptr", Type::i32); // function pointer param + std::vector<NameType> namedParams; + std::vector<Type> params; + namedParams.emplace_back("fptr", Type::i32); // function pointer param + params.push_back(Type::i32); int p = 0; for (const auto& param : sig.params) { - params.emplace_back(std::to_string(p++), param); + namedParams.emplace_back(std::to_string(p++), param); + params.push_back(param); } - auto f = builder.makeFunction(name, std::move(params), sig.results, {}); + auto f = builder.makeFunction( + name, std::move(namedParams), Signature(Type(params), sig.results), {}); Expression* fptr = builder.makeLocalGet(0, Type::i32); std::vector<Expression*> args; Index i = 0; diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp index 36d0ce8f9..9b516342d 100644 --- a/src/passes/I64ToI32Lowering.cpp +++ b/src/passes/I64ToI32Lowering.cpp @@ -158,7 +158,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { freeTemps.clear(); Module temp; auto* oldFunc = ModuleUtils::copyFunction(func, temp); - func->sig.params = Type::none; + func->setParams(Type::none); func->vars.clear(); func->localNames.clear(); func->localIndices.clear(); @@ -191,8 +191,8 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { if (func->imported()) { return; } - if (func->sig.results == Type::i64) { - func->sig.results = Type::i32; + if (func->getResults() == Type::i64) { + func->setResults(Type::i32); // body may not have out param if it ends with control flow if (hasOutParam(func->body)) { TempVar highBits = fetchOutParam(func->body); @@ -250,7 +250,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> { } void visitCall(Call* curr) { if (curr->isReturn && - getModule()->getFunction(curr->target)->sig.results == Type::i64) { + getModule()->getFunction(curr->target)->getResults() == Type::i64) { Fatal() << "i64 to i32 lowering of return_call values not yet implemented"; } diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp index 8601b3409..1a84918bb 100644 --- a/src/passes/Inlining.cpp +++ b/src/passes/Inlining.cpp @@ -143,7 +143,7 @@ struct FunctionInfoScanner // We cannot inline a function if we cannot handle placing it in a local, as // all params become locals. - for (auto param : curr->sig.params) { + for (auto param : curr->getParams()) { if (!TypeUpdating::canHandleAsLocal(param)) { info.uninlineable = true; } @@ -233,7 +233,7 @@ struct Updater : public PostWalker<Updater> { } void visitCall(Call* curr) { if (curr->isReturn) { - handleReturnCall(curr, module->getFunction(curr->target)->sig.results); + handleReturnCall(curr, module->getFunction(curr->target)->getResults()); } } void visitCallIndirect(CallIndirect* curr) { @@ -262,7 +262,7 @@ doInlining(Module* module, Function* into, const InliningAction& action) { Function* from = action.contents; auto* call = (*action.callSite)->cast<Call>(); // Works for return_call, too - Type retType = module->getFunction(call->target)->sig.results; + Type retType = module->getFunction(call->target)->getResults(); Builder builder(*module); auto* block = builder.makeBlock(); block->name = Name(std::string("__inlined_func$") + from->name.str); @@ -285,7 +285,7 @@ doInlining(Module* module, Function* into, const InliningAction& action) { updater.localMapping[i] = builder.addVar(into, from->getLocalType(i)); } // Assign the operands into the params - for (Index i = 0; i < from->sig.params.size(); i++) { + for (Index i = 0; i < from->getParams().size(); i++) { block->list.push_back( builder.makeLocalSet(updater.localMapping[i], call->operands[i])); } diff --git a/src/passes/InstrumentLocals.cpp b/src/passes/InstrumentLocals.cpp index 85da3bd9b..aab0ee3fe 100644 --- a/src/passes/InstrumentLocals.cpp +++ b/src/passes/InstrumentLocals.cpp @@ -245,12 +245,10 @@ private: Index id = 0; void addImport(Module* wasm, Name name, Type params, Type results) { - auto import = new Function; - import->name = name; + auto import = Builder::makeFunction(name, Signature(params, results), {}); import->module = ENV; import->base = name; - import->sig = Signature(params, results); - wasm->addFunction(import); + wasm->addFunction(std::move(import)); } }; diff --git a/src/passes/InstrumentMemory.cpp b/src/passes/InstrumentMemory.cpp index 6c81f8588..38a23a658 100644 --- a/src/passes/InstrumentMemory.cpp +++ b/src/passes/InstrumentMemory.cpp @@ -158,12 +158,10 @@ private: Index id; void addImport(Module* curr, Name name, Type params, Type results) { - auto import = new Function; - import->name = name; + auto import = Builder::makeFunction(name, Signature(params, results), {}); import->module = ENV; import->base = name; - import->sig = Signature(params, results); - curr->addFunction(import); + curr->addFunction(std::move(import)); } }; diff --git a/src/passes/LegalizeJSInterface.cpp b/src/passes/LegalizeJSInterface.cpp index 10e751701..e7a5f9220 100644 --- a/src/passes/LegalizeJSInterface.cpp +++ b/src/passes/LegalizeJSInterface.cpp @@ -157,12 +157,12 @@ private: std::map<Name, Name> illegalImportsToLegal; template<typename T> bool isIllegal(T* t) { - for (const auto& param : t->sig.params) { + for (const auto& param : t->getParams()) { if (param == Type::i64) { return true; } } - return t->sig.results == Type::i64; + return t->getResults() == Type::i64; } bool isDynCall(Name name) { return name.startsWith("dynCall_"); } @@ -201,10 +201,10 @@ private: auto* call = module->allocator.alloc<Call>(); call->target = func->name; - call->type = func->sig.results; + call->type = func->getResults(); std::vector<Type> legalParams; - for (const auto& param : func->sig.params) { + for (const auto& param : func->getParams()) { if (param == Type::i64) { call->operands.push_back(I64Utilities::recreateI64( builder, legalParams.size(), legalParams.size() + 1)); @@ -216,12 +216,12 @@ private: legalParams.push_back(param); } } - legal->sig.params = Type(legalParams); - - if (func->sig.results == Type::i64) { + Type resultsType = + func->getResults() == Type::i64 ? Type::i32 : func->getResults(); + legal->type = Signature(Type(legalParams), resultsType); + if (func->getResults() == Type::i64) { Function* f = getFunctionOrImport(module, SET_TEMP_RET0, Type::i32, Type::none); - legal->sig.results = Type::i32; auto index = Builder::addVar(legal, Name(), Type::i64); auto* block = builder.makeBlock(); block->list.push_back(builder.makeLocalSet(index, call)); @@ -231,10 +231,8 @@ private: block->finalize(); legal->body = block; } else { - legal->sig.results = func->sig.results; legal->body = call; } - return module->addFunction(legal)->name; } @@ -248,14 +246,14 @@ private: legalIm->base = im->base; auto stub = make_unique<Function>(); stub->name = Name(std::string("legalfunc$") + im->name.str); - stub->sig = im->sig; + stub->type = im->type; auto* call = module->allocator.alloc<Call>(); call->target = legalIm->name; std::vector<Type> params; Index i = 0; - for (const auto& param : im->sig.params) { + for (const auto& param : im->getParams()) { if (param == Type::i64) { call->operands.push_back(I64Utilities::getI64Low(builder, i)); call->operands.push_back(I64Utilities::getI64High(builder, i)); @@ -268,17 +266,17 @@ private: ++i; } - if (im->sig.results == Type::i64) { + if (im->getResults() == Type::i64) { Function* f = getFunctionOrImport(module, GET_TEMP_RET0, Type::none, Type::i32); call->type = Type::i32; Expression* get = builder.makeCall(f->name, {}, call->type); stub->body = I64Utilities::recreateI64(builder, call, get); } else { - call->type = im->sig.results; + call->type = im->getResults(); stub->body = call; } - legalIm->sig = Signature(Type(params), call->type); + legalIm->type = Signature(Type(params), call->type); const auto& stubName = stub->name; if (!module->getFunctionOrNull(stubName)) { @@ -302,13 +300,12 @@ private: return f; } // Failing that create a new function import. - auto import = new Function; - import->name = name; + auto import = Builder::makeFunction(name, Signature(params, results), {}); import->module = ENV; import->base = name; - import->sig = Signature(params, results); - module->addFunction(import); - return import; + auto* ret = import.get(); + module->addFunction(std::move(import)); + return ret; } }; diff --git a/src/passes/LogExecution.cpp b/src/passes/LogExecution.cpp index b9b203d0b..5978ecc72 100644 --- a/src/passes/LogExecution.cpp +++ b/src/passes/LogExecution.cpp @@ -57,12 +57,11 @@ struct LogExecution : public WalkerPass<PostWalker<LogExecution>> { void visitModule(Module* curr) { // Add the import - auto import = new Function; - import->name = LOGGER; + auto import = + Builder::makeFunction(LOGGER, Signature(Type::i32, Type::none), {}); import->module = ENV; import->base = LOGGER; - import->sig = Signature(Type::i32, Type::none); - curr->addFunction(import); + curr->addFunction(std::move(import)); } private: diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index c6bf13f42..491e44ca2 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2596,7 +2596,7 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { lastPrintedLocation = {0, 0, 0}; o << '('; emitImportHeader(curr); - handleSignature(curr->sig, curr->name); + handleSignature(curr->getSig(), curr->name); o << ')'; o << maybeNewLine; } @@ -2613,9 +2613,9 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { if (!stackIR && curr->stackIR && !minify) { o << " (; has Stack IR ;)"; } - if (curr->sig.params.size() > 0) { + if (curr->getParams().size() > 0) { Index i = 0; - for (const auto& param : curr->sig.params) { + for (const auto& param : curr->getParams()) { o << maybeSpace; o << '('; printMinor(o, "param "); @@ -2625,9 +2625,9 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { ++i; } } - if (curr->sig.results != Type::none) { + if (curr->getResults() != Type::none) { o << maybeSpace; - printResultType(o, curr->sig.results, currModule); + printResultType(o, curr->getResults(), currModule); } incIndent(); for (size_t i = curr->getVarIndexBase(); i < curr->getNumLocals(); i++) { diff --git a/src/passes/ReReloop.cpp b/src/passes/ReReloop.cpp index 9a82d8b44..0559343d4 100644 --- a/src/passes/ReReloop.cpp +++ b/src/passes/ReReloop.cpp @@ -318,7 +318,7 @@ struct ReReloop final : public Pass { for (auto& cfgBlock : relooper->Blocks) { auto* block = cfgBlock->Code->cast<Block>(); if (cfgBlock->BranchesOut.empty() && block->type != Type::unreachable) { - block->list.push_back(function->sig.results == Type::none + block->list.push_back(function->getResults() == Type::none ? (Expression*)builder->makeReturn() : (Expression*)builder->makeUnreachable()); block->finalize(); @@ -351,7 +351,7 @@ struct ReReloop final : public Pass { // because of the relooper's boilerplate switch-handling // code, for example, which could be optimized out later // but isn't yet), then make sure it has a proper type - if (function->sig.results != Type::none && + if (function->getResults() != Type::none && function->body->type == Type::none) { function->body = builder.makeSequence(function->body, builder.makeUnreachable()); diff --git a/src/passes/RemoveImports.cpp b/src/passes/RemoveImports.cpp index 2a1c119fd..af216ecbd 100644 --- a/src/passes/RemoveImports.cpp +++ b/src/passes/RemoveImports.cpp @@ -35,7 +35,7 @@ struct RemoveImports : public WalkerPass<PostWalker<RemoveImports>> { if (!func->imported()) { return; } - Type type = func->sig.results; + Type type = func->getResults(); if (type == Type::none) { replaceCurrent(getModule()->allocator.alloc<Nop>()); } else { diff --git a/src/passes/ReorderLocals.cpp b/src/passes/ReorderLocals.cpp index 8d7c0f1d9..b34eeb3bf 100644 --- a/src/passes/ReorderLocals.cpp +++ b/src/passes/ReorderLocals.cpp @@ -82,7 +82,7 @@ struct ReorderLocals : public WalkerPass<PostWalker<ReorderLocals>> { return counts[a] > counts[b]; }); // sorting left params in front, perhaps slightly reordered. verify and fix. - size_t numParams = curr->sig.params.size(); + size_t numParams = curr->getParams().size(); for (size_t i = 0; i < numParams; i++) { assert(newToOld[i] < numParams); newToOld[i] = i; diff --git a/src/passes/SafeHeap.cpp b/src/passes/SafeHeap.cpp index 2eed23256..a3416afaf 100644 --- a/src/passes/SafeHeap.cpp +++ b/src/passes/SafeHeap.cpp @@ -134,32 +134,33 @@ struct SafeHeap : public Pass { } else if (auto* existing = info.getImportedFunction(ENV, SBRK)) { sbrk = existing->name; } else { - auto* import = new Function; - import->name = getSbrkPtr = GET_SBRK_PTR; + auto import = Builder::makeFunction( + GET_SBRK_PTR, Signature(Type::none, indexType), {}); + getSbrkPtr = GET_SBRK_PTR; import->module = ENV; import->base = GET_SBRK_PTR; - import->sig = Signature(Type::none, indexType); - module->addFunction(import); + module->addFunction(std::move(import)); } if (auto* existing = info.getImportedFunction(ENV, SEGFAULT_IMPORT)) { segfault = existing->name; } else { - auto* import = new Function; - import->name = segfault = SEGFAULT_IMPORT; + auto import = Builder::makeFunction( + SEGFAULT_IMPORT, Signature(Type::none, Type::none), {}); + segfault = SEGFAULT_IMPORT; import->module = ENV; import->base = SEGFAULT_IMPORT; - import->sig = Signature(Type::none, Type::none); - module->addFunction(import); + module->addFunction(std::move(import)); } if (auto* existing = info.getImportedFunction(ENV, ALIGNFAULT_IMPORT)) { alignfault = existing->name; } else { - auto* import = new Function; - import->name = alignfault = ALIGNFAULT_IMPORT; + auto import = Builder::makeFunction( + ALIGNFAULT_IMPORT, Signature(Type::none, Type::none), {}); + + alignfault = ALIGNFAULT_IMPORT; import->module = ENV; import->base = ALIGNFAULT_IMPORT; - import->sig = Signature(Type::none, Type::none); - module->addFunction(import); + module->addFunction(std::move(import)); } } @@ -246,12 +247,10 @@ struct SafeHeap : public Pass { if (module->getFunctionOrNull(name)) { return; } - auto* func = new Function; - func->name = name; // pointer, offset auto indexType = module->memory.indexType; - func->sig = Signature({indexType, indexType}, style.type); - func->vars.push_back(indexType); // pointer + offset + auto funcSig = Signature({indexType, indexType}, style.type); + auto func = Builder::makeFunction(name, funcSig, {indexType}); Builder builder(*module); auto* block = builder.makeBlock(); block->list.push_back(builder.makeLocalSet( @@ -279,7 +278,7 @@ struct SafeHeap : public Pass { block->list.push_back(last); block->finalize(style.type); func->body = block; - module->addFunction(func); + module->addFunction(std::move(func)); } // creates a function for a particular type of store @@ -288,12 +287,11 @@ struct SafeHeap : public Pass { if (module->getFunctionOrNull(name)) { return; } - auto* func = new Function; - func->name = name; - // pointer, offset, value auto indexType = module->memory.indexType; - func->sig = Signature({indexType, indexType, style.valueType}, Type::none); - func->vars.push_back(indexType); // pointer + offset + // pointer, offset, value + auto funcSig = + Signature({indexType, indexType, style.valueType}, Type::none); + auto func = Builder::makeFunction(name, funcSig, {indexType}); Builder builder(*module); auto* block = builder.makeBlock(); block->list.push_back(builder.makeLocalSet( @@ -316,7 +314,7 @@ struct SafeHeap : public Pass { block->list.push_back(store); block->finalize(Type::none); func->body = block; - module->addFunction(func); + module->addFunction(std::move(func)); } Expression* diff --git a/src/passes/StackCheck.cpp b/src/passes/StackCheck.cpp index 23fd5be3d..e7fc3c6b3 100644 --- a/src/passes/StackCheck.cpp +++ b/src/passes/StackCheck.cpp @@ -39,12 +39,10 @@ static void importStackOverflowHandler(Module& module, Name name) { ImportInfo info(module); if (!info.getImportedFunction(ENV, name)) { - auto* import = new Function; - import->name = name; + auto import = Builder::makeFunction(name, Signature(), {}); import->module = ENV; import->base = name; - import->sig = Signature(Type::none, Type::none); - module.addFunction(import); + module.addFunction(std::move(import)); } } diff --git a/src/passes/TrapMode.cpp b/src/passes/TrapMode.cpp index 9c9dee9ca..ee245af88 100644 --- a/src/passes/TrapMode.cpp +++ b/src/passes/TrapMode.cpp @@ -132,14 +132,14 @@ Function* generateBinaryFunc(Module& wasm, Binary* curr) { builder.makeConst(zeroLit), result); } - auto func = new Function; - func->name = getBinaryFuncName(curr); - func->sig = Signature({type, type}, type); + auto funcSig = Signature({type, type}, type); + auto func = Builder::makeFunction(getBinaryFuncName(curr), funcSig, {}); func->body = builder.makeIf(builder.makeUnary(eqZOp, builder.makeLocalGet(1, type)), builder.makeConst(zeroLit), result); - return func; + // TODO: use unique_ptr properly and do not release ownership. + return func.release(); } template<typename IntType, typename FloatType> @@ -193,9 +193,8 @@ Function* generateUnaryFunc(Module& wasm, Unary* curr) { WASM_UNREACHABLE("unexpected op"); } - auto func = new Function; - func->name = getUnaryFuncName(curr); - func->sig = Signature(type, retType); + auto func = + Builder::makeFunction(getUnaryFuncName(curr), Signature(type, retType), {}); func->body = builder.makeUnary(truncOp, builder.makeLocalGet(0, type)); // too small XXX this is different than asm.js, which does frem. here we // clamp, which is much simpler/faster, and similar to native builds @@ -218,7 +217,8 @@ Function* generateUnaryFunc(Module& wasm, Unary* curr) { // NB: min here as well. anything invalid => to the min builder.makeConst(iMin), func->body); - return func; + // TODO: use unique_ptr properly and do not release ownership. + return func.release(); } void ensureBinaryFunc(Binary* curr, @@ -251,7 +251,7 @@ void ensureF64ToI64JSImport(TrappingFunctionContainer& trappingFunctions) { import->name = F64_TO_INT; import->module = ASM2WASM; import->base = F64_TO_INT; - import->sig = Signature(Type::f64, Type::i32); + import->type = Signature(Type::f64, Type::i32); trappingFunctions.addImport(import); } diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp index 506eee5e6..25b0116b3 100644 --- a/src/passes/Vacuum.cpp +++ b/src/passes/Vacuum.cpp @@ -355,13 +355,13 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> { void visitFunction(Function* curr) { auto* optimized = - optimize(curr->body, curr->sig.results != Type::none, true); + optimize(curr->body, curr->getResults() != Type::none, true); if (optimized) { curr->body = optimized; } else { ExpressionManipulator::nop(curr->body); } - if (curr->sig.results == Type::none && + if (curr->getResults() == Type::none && !EffectAnalyzer(getPassOptions(), getModule()->features, curr->body) .hasSideEffects()) { ExpressionManipulator::nop(curr->body); diff --git a/src/shell-interface.h b/src/shell-interface.h index 494722ab1..96b96cf15 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -174,19 +174,19 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { if (!func) { trap("uninitialized table element"); } - if (sig != func->sig) { + if (sig != func->getSig()) { trap("callIndirect: function signatures don't match"); } - if (func->sig.params.size() != arguments.size()) { + if (func->getParams().size() != arguments.size()) { trap("callIndirect: bad # of arguments"); } size_t i = 0; - for (const auto& param : func->sig.params) { + for (const auto& param : func->getParams()) { if (!Type::isSubType(arguments[i++].type, param)) { trap("callIndirect: bad argument type"); } } - if (func->sig.results != results) { + if (func->getResults() != results) { trap("callIndirect: bad result type"); } if (func->imported()) { diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 50f627baf..aabbb4819 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -106,14 +106,14 @@ struct ExecutionResults { } std::cout << "[fuzz-exec] calling " << exp->name << "\n"; auto* func = wasm.getFunction(exp->value); - if (func->sig.results != Type::none) { + if (func->getResults() != Type::none) { // this has a result Literals ret = run(func, wasm, instance); results[exp->name] = ret; // ignore the result if we hit an unreachable and returned no value if (ret.size() > 0) { std::cout << "[fuzz-exec] note result: " << exp->name << " => "; - auto resultType = func->sig.results; + auto resultType = func->getResults(); if (resultType.isRef()) { // Don't print reference values, as funcref(N) contains an index // for example, which is not guaranteed to remain identical after @@ -227,7 +227,7 @@ struct ExecutionResults { instance.callFunction(ex->value, arguments); } // call the method - for (const auto& param : func->sig.params) { + for (const auto& param : func->getParams()) { // zeros in arguments TODO: more? if (!param.isDefaultable()) { std::cout << "[trap fuzzer can only send defaultable parameters to " diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h index 03efd8134..dcdfd391f 100644 --- a/src/tools/fuzzing.h +++ b/src/tools/fuzzing.h @@ -592,7 +592,7 @@ private: auto funcName = Names::getValidFunctionName(wasm, exportName); auto* func = new Function; func->name = funcName; - func->sig = Signature(Type::none, Type::none); + func->type = Signature(Type::none, Type::none); func->body = builder.makeGlobalSet(HANG_LIMIT_GLOBAL, builder.makeConst(int32_t(HANG_LIMIT))); wasm.addFunction(func); @@ -616,7 +616,7 @@ private: func->name = name; func->module = "fuzzing-support"; func->base = name; - func->sig = Signature(type, Type::none); + func->type = Signature(type, Type::none); wasm.addFunction(func); } } @@ -684,7 +684,7 @@ private: funcContext->typeLocals[type].push_back(params.size()); params.push_back(type); } - func->sig = Signature(Type(params), getControlFlowType()); + func->type = Signature(Type(params), getControlFlowType()); Index numVars = upToSquared(MAX_VARS); for (Index i = 0; i < numVars; i++) { auto type = getConcreteType(); @@ -698,7 +698,7 @@ private: func->vars.push_back(type); } // with small chance, make the body unreachable - auto bodyType = func->sig.results; + auto bodyType = func->getResults(); if (oneIn(10)) { bodyType = Type::unreachable; } @@ -737,7 +737,7 @@ private: } // add some to an elem segment while (oneIn(3) && !finishedInput) { - auto type = Type(HeapType(func->sig), NonNullable); + auto type = Type(func->type, NonNullable); std::vector<ElementSegment*> compatibleSegments; ModuleUtils::iterActiveElementSegments( wasm, [&](ElementSegment* segment) { @@ -746,7 +746,7 @@ private: } }); auto& randomElem = compatibleSegments[upTo(compatibleSegments.size())]; - randomElem->data.push_back(builder.makeRefFunc(func->name, func->sig)); + randomElem->data.push_back(builder.makeRefFunc(func->name, func->type)); } numAddedFunctions++; return func; @@ -760,8 +760,8 @@ private: builder.makeSequence(makeHangLimitCheck(), loop->body, loop->type); } // recursion limit - func->body = - builder.makeSequence(makeHangLimitCheck(), func->body, func->sig.results); + func->body = builder.makeSequence( + makeHangLimitCheck(), func->body, func->getResults()); } // Recombination and mutation can replace a node with another node of the same @@ -967,7 +967,7 @@ private: // We can't allow extra imports, as the fuzzing infrastructure wouldn't // know what to provide. func->module = func->base = Name(); - func->body = make(func->sig.results); + func->body = make(func->getResults()); } // Optionally, fuzz the function contents. if (upTo(RESOLUTION) >= chance) { @@ -1033,12 +1033,12 @@ private: std::vector<Expression*> invocations; while (oneIn(2) && !finishedInput) { std::vector<Expression*> args; - for (const auto& type : func->sig.params) { + for (const auto& type : func->getParams()) { args.push_back(makeConst(type)); } Expression* invoke = - builder.makeCall(func->name, args, func->sig.results); - if (func->sig.results.isConcrete()) { + builder.makeCall(func->name, args, func->getResults()); + if (func->getResults().isConcrete()) { invoke = builder.makeDrop(invoke); } invocations.push_back(invoke); @@ -1052,7 +1052,7 @@ private: } auto* invoker = new Function; invoker->name = name; - invoker->sig = Signature(Type::none, Type::none); + invoker->type = Signature(Type::none, Type::none); invoker->body = builder.makeBlock(invocations); wasm.addFunction(invoker); auto* export_ = new Export; @@ -1236,8 +1236,8 @@ private: } assert(type == Type::unreachable); Expression* ret = nullptr; - if (funcContext->func->sig.results.isConcrete()) { - ret = makeTrivial(funcContext->func->sig.results); + if (funcContext->func->getResults().isConcrete()) { + ret = makeTrivial(funcContext->func->getResults()); } return builder.makeReturn(ret); } @@ -1437,13 +1437,13 @@ private: target = pick(wasm.functions).get(); } isReturn = type == Type::unreachable && wasm.features.hasTailCall() && - funcContext->func->sig.results == target->sig.results; - if (target->sig.results != type && !isReturn) { + funcContext->func->getResults() == target->getResults(); + if (target->getResults() != type && !isReturn) { continue; } // we found one! std::vector<Expression*> args; - for (const auto& argType : target->sig.params) { + for (const auto& argType : target->getParams()) { args.push_back(make(argType)); } return builder.makeCall(target->name, args, type, isReturn); @@ -1468,8 +1468,8 @@ private: if (auto* get = data[i]->dynCast<RefFunc>()) { targetFn = wasm.getFunction(get->func); isReturn = type == Type::unreachable && wasm.features.hasTailCall() && - funcContext->func->sig.results == targetFn->sig.results; - if (targetFn->sig.results == type || isReturn) { + funcContext->func->getResults() == targetFn->getResults(); + if (targetFn->getResults() == type || isReturn) { break; } } @@ -1490,12 +1490,12 @@ private: target = make(Type::i32); } std::vector<Expression*> args; - for (const auto& type : targetFn->sig.params) { + for (const auto& type : targetFn->getParams()) { args.push_back(make(type)); } // TODO: use a random table return builder.makeCallIndirect( - funcrefTableName, target, args, targetFn->sig, isReturn); + funcrefTableName, target, args, targetFn->getSig(), isReturn); } Expression* makeCallRef(Type type) { @@ -1511,19 +1511,19 @@ private: // TODO: handle unreachable target = wasm.functions[upTo(wasm.functions.size())].get(); isReturn = type == Type::unreachable && wasm.features.hasTailCall() && - funcContext->func->sig.results == target->sig.results; - if (target->sig.results == type || isReturn) { + funcContext->func->getResults() == target->getResults(); + if (target->getResults() == type || isReturn) { break; } i++; } std::vector<Expression*> args; - for (const auto& type : target->sig.params) { + for (const auto& type : target->getParams()) { args.push_back(make(type)); } // TODO: half the time make a completely random item with that type. return builder.makeCallRef( - builder.makeRefFunc(target->name, target->sig), args, type, isReturn); + builder.makeRefFunc(target->name, target->type), args, type, isReturn); } Expression* makeLocalGet(Type type) { @@ -2112,7 +2112,7 @@ private: if (!wasm.functions.empty() && !oneIn(wasm.functions.size())) { target = pick(wasm.functions).get(); } - return builder.makeRefFunc(target->name, target->sig); + return builder.makeRefFunc(target->name, target->type); } if (type == Type::i31ref) { return builder.makeI31New(makeConst(Type::i32)); @@ -2133,8 +2133,8 @@ private: } // TODO: randomize the order for (auto& func : wasm.functions) { - if (type == Type(HeapType(func->sig), NonNullable)) { - return builder.makeRefFunc(func->name, func->sig); + if (type == Type(func->type, NonNullable)) { + return builder.makeRefFunc(func->name, func->type); } } // We failed to find a function, so create a null reference if we can. @@ -2143,17 +2143,13 @@ private: } // Last resort: create a function. auto heapType = type.getHeapType(); - Signature sig; - if (heapType.isSignature()) { - sig = heapType.getSignature(); - } else { - assert(heapType == HeapType::func); + if (heapType == HeapType::func) { // The specific signature does not matter. - sig = Signature(Type::none, Type::none); + heapType = Signature(Type::none, Type::none); } auto* func = wasm.addFunction(builder.makeFunction( Names::getValidFunctionName(wasm, "ref_func_target"), - sig, + heapType, {}, builder.makeUnreachable())); return builder.makeRefFunc(func->name, heapType); @@ -2681,8 +2677,8 @@ private: } Expression* makeReturn(Type type) { - return builder.makeReturn(funcContext->func->sig.results.isConcrete() - ? make(funcContext->func->sig.results) + return builder.makeReturn(funcContext->func->getResults().isConcrete() + ? make(funcContext->func->getResults()) : nullptr); } diff --git a/src/tools/js-wrapper.h b/src/tools/js-wrapper.h index e6f553124..b93948e74 100644 --- a/src/tools/js-wrapper.h +++ b/src/tools/js-wrapper.h @@ -25,7 +25,7 @@ namespace wasm { -static std::string generateJSWrapper(Module& wasm) { +inline std::string generateJSWrapper(Module& wasm) { std::string ret; ret += "if (typeof console === 'undefined') {\n" " console = { log: print };\n" @@ -96,7 +96,7 @@ static std::string generateJSWrapper(Module& wasm) { ret += "try {\n"; ret += std::string(" console.log('[fuzz-exec] calling ") + exp->name.str + "');\n"; - if (func->sig.results != Type::none) { + if (func->getResults() != Type::none) { ret += std::string(" console.log('[fuzz-exec] note result: ") + exp->name.str + " => ' + literal("; } else { @@ -104,7 +104,7 @@ static std::string generateJSWrapper(Module& wasm) { } ret += std::string("instance.exports.") + exp->name.str + "("; bool first = true; - for (auto param : func->sig.params) { + for (auto param : func->getParams()) { // zeros in arguments TODO more? if (first) { first = false; @@ -121,8 +121,8 @@ static std::string generateJSWrapper(Module& wasm) { } } ret += ")"; - if (func->sig.results != Type::none) { - ret += ", '" + func->sig.results.toString() + "'))"; + if (func->getResults() != Type::none) { + ret += ", '" + func->getResults().toString() + "'))"; // TODO: getTempRet } ret += ";\n"; diff --git a/src/tools/spec-wrapper.h b/src/tools/spec-wrapper.h index 32e547f1b..3a490c954 100644 --- a/src/tools/spec-wrapper.h +++ b/src/tools/spec-wrapper.h @@ -24,7 +24,7 @@ namespace wasm { -static std::string generateSpecWrapper(Module& wasm) { +inline std::string generateSpecWrapper(Module& wasm) { std::string ret; for (auto& exp : wasm.exports) { auto* func = wasm.getFunctionOrNull(exp->value); @@ -33,7 +33,7 @@ static std::string generateSpecWrapper(Module& wasm) { } ret += std::string("(invoke \"hangLimitInitializer\") (invoke \"") + exp->name.str + "\" "; - for (const auto& param : func->sig.params) { + for (const auto& param : func->getParams()) { // zeros in arguments TODO more? TODO_SINGLE_COMPOUND(param); switch (param.getBasic()) { diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 5bede4444..bd370a58a 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -322,7 +322,7 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface { // if this is one of our functions, we can call it; if it was // imported, fail auto* func = wasm->getFunction(name); - if (func->sig != sig) { + if (func->getSig() != sig) { throw FailToEvalException( std::string("callTable signature mismatch: ") + name.str); } diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp index 48435fac0..ed2b9b564 100644 --- a/src/tools/wasm-reduce.cpp +++ b/src/tools/wasm-reduce.cpp @@ -483,7 +483,7 @@ struct Reducer auto* save = curr; Unreachable un; Nop nop; - bool useUnreachable = getFunction()->sig.results != Type::none; + bool useUnreachable = getFunction()->getResults() != Type::none; if (useUnreachable) { replaceCurrent(&un); } else { @@ -977,7 +977,7 @@ struct Reducer auto* func = module->functions[0].get(); // We can't remove something that might have breaks to it. if (!func->imported() && !Properties::isNamedControlFlow(func->body)) { - auto funcSig = func->sig; + auto funcType = func->type; auto* funcBody = func->body; for (auto* child : ChildIterator(func->body)) { if (!(child->type.isConcrete() || child->type == Type::none)) { @@ -985,7 +985,7 @@ struct Reducer } // Try to replace the body with the child, fixing up the function // to accept it. - func->sig.results = child->type; + func->type = Signature(funcType.getSignature().params, child->type); func->body = child; if (writeAndTestReduction()) { // great, we succeeded! @@ -994,7 +994,7 @@ struct Reducer break; } // Undo. - func->sig = funcSig; + func->type = funcType; func->body = funcBody; } } diff --git a/src/tools/wasm2c-wrapper.h b/src/tools/wasm2c-wrapper.h index de235c35e..ae32ec744 100644 --- a/src/tools/wasm2c-wrapper.h +++ b/src/tools/wasm2c-wrapper.h @@ -27,7 +27,7 @@ namespace wasm { // Mangle a name in (hopefully) exactly the same way wasm2c does. -static std::string wasm2cMangle(Name name, Signature sig) { +inline std::string wasm2cMangle(Name name, Signature sig) { const char escapePrefix = 'Z'; std::string mangled = "Z_"; const char* original = name.str; @@ -78,7 +78,7 @@ static std::string wasm2cMangle(Name name, Signature sig) { return mangled; } -static std::string generateWasm2CWrapper(Module& wasm) { +inline std::string generateWasm2CWrapper(Module& wasm) { // First, emit implementations of the wasm's imports so that the wasm2c code // can call them. The names use wasm2c's name mangling. std::string ret = R"( @@ -169,7 +169,7 @@ int main(int argc, char** argv) { ret += std::string(" puts(\"[fuzz-exec] calling ") + exp->name.str + "\");\n"; - auto result = func->sig.results; + auto result = func->getResults(); // Emit the call itself. ret += " "; @@ -199,13 +199,13 @@ int main(int argc, char** argv) { ret += "(*"; // Emit the callee's name with wasm2c name mangling. - ret += wasm2cMangle(exp->name, func->sig); + ret += wasm2cMangle(exp->name, func->getSig()); ret += ")("; // Emit the parameters (all 0s, like the other wrappers). bool first = true; - for (const auto& param : func->sig.params) { + for (const auto& param : func->getParams()) { WASM_UNUSED(param); if (!first) { ret += ", "; diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp index 06b24ea26..4736dee08 100644 --- a/src/tools/wasm2js.cpp +++ b/src/tools/wasm2js.cpp @@ -604,7 +604,7 @@ Expression* AssertionEmitter::parseInvoke(Builder& wasmBuilder, for (size_t i = 2; i < e.size(); ++i) { args.push_back(sexpBuilder.parseExpression(e[i])); } - Type type = module.getFunction(module.getExport(target)->value)->sig.results; + Type type = module.getFunction(module.getExport(target)->value)->getResults(); return wasmBuilder.makeCall(target, args, type); } @@ -658,7 +658,7 @@ Ref AssertionEmitter::emitAssertReturnFunc(Builder& wasmBuilder, std::unique_ptr<Function> testFunc( wasmBuilder.makeFunction(testFuncName, std::vector<NameType>{}, - body->type, + Signature(Type::none, body->type), std::vector<NameType>{}, body)); Ref jsFunc = processFunction(testFunc.get()); @@ -676,7 +676,7 @@ Ref AssertionEmitter::emitAssertReturnNanFunc(Builder& wasmBuilder, std::unique_ptr<Function> testFunc( wasmBuilder.makeFunction(testFuncName, std::vector<NameType>{}, - body->type, + Signature(Type::none, body->type), std::vector<NameType>{}, body)); Ref jsFunc = processFunction(testFunc.get()); @@ -695,7 +695,7 @@ Ref AssertionEmitter::emitAssertTrapFunc(Builder& wasmBuilder, std::unique_ptr<Function> exprFunc( wasmBuilder.makeFunction(innerFuncName, std::vector<NameType>{}, - expr->type, + Signature(Type::none, expr->type), std::vector<NameType>{}, expr)); IString expectedErr = e[2]->str(); @@ -729,7 +729,7 @@ Ref AssertionEmitter::emitInvokeFunc(Builder& wasmBuilder, std::unique_ptr<Function> testFunc( wasmBuilder.makeFunction(testFuncName, std::vector<NameType>{}, - body->type, + Signature(Type::none, body->type), std::vector<NameType>{}, body)); Ref jsFunc = processFunction(testFunc.get()); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index a3b0febaa..876474223 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -43,12 +43,13 @@ public: // make* functions create an expression instance. static std::unique_ptr<Function> makeFunction(Name name, - Signature sig, + HeapType type, std::vector<Type>&& vars, Expression* body = nullptr) { + assert(type.isSignature()); auto func = std::make_unique<Function>(); func->name = name; - func->sig = sig; + func->type = type; func->body = body; func->vars.swap(vars); return func; @@ -56,20 +57,21 @@ public: static std::unique_ptr<Function> makeFunction(Name name, std::vector<NameType>&& params, - Type resultType, + HeapType type, std::vector<NameType>&& vars, Expression* body = nullptr) { + assert(type.isSignature()); auto func = std::make_unique<Function>(); func->name = name; + func->type = type; func->body = body; - std::vector<Type> paramVec; - for (auto& param : params) { - paramVec.push_back(param.type); + for (size_t i = 0; i < params.size(); ++i) { + NameType& param = params[i]; + assert(func->getParams()[i] == param.type); Index index = func->localNames.size(); func->localIndices[param.name] = index; func->localNames[index] = param.name; } - func->sig = Signature(Type(paramVec), resultType); for (auto& var : vars) { func->vars.push_back(var.type); Index index = func->localNames.size(); @@ -948,11 +950,12 @@ public: static Index addParam(Function* func, Name name, Type type) { // only ok to add a param if no vars, otherwise indices are invalidated - assert(func->localIndices.size() == func->sig.params.size()); + assert(func->localIndices.size() == func->getParams().size()); assert(name.is()); - std::vector<Type> params(func->sig.params.begin(), func->sig.params.end()); + Signature sig = func->getSig(); + std::vector<Type> params(sig.params.begin(), sig.params.end()); params.push_back(type); - func->sig.params = Type(params); + func->type = Signature(Type(params), sig.results); Index index = func->localNames.size(); func->localIndices[name] = index; func->localNames[index] = name; @@ -980,12 +983,6 @@ public: func->localIndices.clear(); } - static void clearLocals(Function* func) { - func->sig.params = Type::none; - func->vars.clear(); - clearLocalNames(func); - } - // ensure a node is a block, if it isn't already, and optionally append to the // block Block* blockify(Expression* any, Expression* append = nullptr) { diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 2ffb542c7..77b055fd1 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1452,7 +1452,7 @@ public: cast.breaking = NONCONSTANT_FLOW; return cast; } - seenRtt = Literal(Type(Rtt(0, func->sig))); + seenRtt = Literal(Type(Rtt(0, func->type))); if (!seenRtt.isSubRtt(intendedRtt)) { cast.outcome = cast.Failure; return cast; @@ -2019,7 +2019,7 @@ public: if ((flags & FlagValues::TRAVERSE_CALLS) != 0 && this->module != nullptr) { auto* func = this->module->getFunction(curr->target); if (!func->imported()) { - if (func->sig.results.isConcrete()) { + if (func->getResults().isConcrete()) { auto numOperands = curr->operands.size(); assert(numOperands == func->getNumParams()); auto prevLocalValues = localValues; @@ -2425,6 +2425,7 @@ private: void initializeTableContents() { ModuleUtils::iterActiveElementSegments(wasm, [&](ElementSegment* segment) { Function dummyFunc; + dummyFunc.type = Signature(Type::none, Type::none); FunctionScope dummyScope(&dummyFunc, {}); RuntimeExpressionRunner runner(*this, dummyScope, maxDepth); @@ -2476,6 +2477,7 @@ private: // we don't actually have a function, but we need one in order to visit // the memory.init and data.drop instructions. Function dummyFunc; + dummyFunc.type = Signature(Type::none, Type::none); FunctionScope dummyScope(&dummyFunc, {}); RuntimeExpressionRunner runner(*this, dummyScope, maxDepth); runner.visit(&init); @@ -2490,19 +2492,20 @@ private: FunctionScope(Function* function, const LiteralList& arguments) : function(function) { - if (function->sig.params.size() != arguments.size()) { + if (function->getParams().size() != arguments.size()) { std::cerr << "Function `" << function->name << "` expects " - << function->sig.params.size() << " parameters, got " + << function->getParams().size() << " parameters, got " << arguments.size() << " arguments." << std::endl; WASM_UNREACHABLE("invalid param count"); } locals.resize(function->getNumLocals()); + Type params = function->getParams(); for (size_t i = 0; i < function->getNumLocals(); i++) { if (i < arguments.size()) { - if (!Type::isSubType(arguments[i].type, function->sig.params[i])) { + if (!Type::isSubType(arguments[i].type, params[i])) { std::cerr << "Function `" << function->name << "` expects type " - << function->sig.params[i] << " for parameter " << i - << ", got " << arguments[i].type << "." << std::endl; + << params[i] << " for parameter " << i << ", got " + << arguments[i].type << "." << std::endl; WASM_UNREACHABLE("invalid param count"); } locals[i] = {arguments[i]}; @@ -2590,7 +2593,7 @@ private: } Index index = target.getSingleValue().geti32(); - Type type = curr->isReturn ? scope.function->sig.results : curr->type; + Type type = curr->isReturn ? scope.function->getResults() : curr->type; Flow ret; auto* table = instance.wasm.getTable(curr->table); @@ -3345,9 +3348,9 @@ public: // cannot still be breaking, it means we missed our stop assert(!flow.breaking() || flow.breakTo == RETURN_FLOW); auto type = flow.getType(); - if (!Type::isSubType(type, function->sig.results)) { + if (!Type::isSubType(type, function->getResults())) { std::cerr << "calling " << function->name << " resulted in " << type - << " but the function type is " << function->sig.results + << " but the function type is " << function->getResults() << '\n'; WASM_UNREACHABLE("unexpected result type"); } diff --git a/src/wasm.h b/src/wasm.h index d02d9a1a7..268611f34 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1609,7 +1609,7 @@ using StackIR = std::vector<StackInst*>; class Function : public Importable { public: - Signature sig; // parameters and return value + HeapType type = HeapType(Signature()); // parameters and return value IRProfile profile = IRProfile::Normal; std::vector<Type> vars; // non-param locals @@ -1658,6 +1658,12 @@ public: delimiterLocations; BinaryLocations::FunctionLocations funcLocation; + Signature getSig() { return type.getSignature(); } + Type getParams() { return getSig().params; } + Type getResults() { return getSig().results; } + void setParams(Type params) { type = Signature(params, getResults()); } + void setResults(Type results) { type = Signature(getParams(), results); } + size_t getNumParams(); size_t getNumVars(); size_t getNumLocals(); diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 779df5c65..31fe1bc6e 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -269,7 +269,7 @@ void WasmBinaryWriter::writeImports() { BYN_TRACE("write one function\n"); writeImportHeader(func); o << U32LEB(int32_t(ExternalKind::Function)); - o << U32LEB(getTypeIndex(func->sig)); + o << U32LEB(getTypeIndex(func->type)); }); ModuleUtils::iterImportedGlobals(*wasm, [&](Global* global) { BYN_TRACE("write one global\n"); @@ -318,7 +318,7 @@ void WasmBinaryWriter::writeFunctionSignatures() { o << U32LEB(importInfo->getNumDefinedFunctions()); ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) { BYN_TRACE("write one\n"); - o << U32LEB(getTypeIndex(func->sig)); + o << U32LEB(getTypeIndex(func->type)); }); finishSection(start); } @@ -2008,8 +2008,7 @@ void WasmBinaryBuilder::readImports() { Name name(std::string("fimport$") + std::to_string(functionCounter++)); auto index = getU32LEB(); functionTypes.push_back(getTypeByIndex(index)); - auto curr = - builder.makeFunction(name, getSignatureByTypeIndex(index), {}); + auto curr = builder.makeFunction(name, getTypeByIndex(index), {}); curr->module = module; curr->base = base; functionImports.push_back(curr.get()); @@ -2158,7 +2157,7 @@ void WasmBinaryBuilder::readFunctions() { auto* func = new Function; func->name = Name::fromInt(i); - func->sig = getSignatureByFunctionIndex(functionImports.size() + i); + func->type = getTypeByFunctionIndex(functionImports.size() + i); currFunction = func; if (DWARF) { @@ -2197,7 +2196,7 @@ void WasmBinaryBuilder::readFunctions() { auto currFunctionIndex = functionImports.size() + functions.size(); bool isStart = startIndex == currFunctionIndex; if (!skipFunctionBodies || isStart) { - func->body = getBlockOrSingleton(func->sig.results); + func->body = getBlockOrSingleton(func->getResults()); } else { // When skipping the function body we need to put something valid in // their place so we validate. An unreachable is always acceptable @@ -6004,8 +6003,9 @@ void WasmBinaryBuilder::visitSelect(Select* curr, uint8_t code) { void WasmBinaryBuilder::visitReturn(Return* curr) { BYN_TRACE("zz node: Return\n"); requireFunctionContext("return"); - if (currFunction->sig.results.isConcrete()) { - curr->value = popTypedExpression(currFunction->sig.results); + Type type = currFunction->getResults(); + if (type.isConcrete()) { + curr->value = popTypedExpression(type); } curr->finalize(); } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index bda94dec5..25be13f58 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -914,9 +914,7 @@ void SExpressionWasmBuilder::preParseFunctionType(Element& s) { } functionNames.push_back(name); functionCounter++; - HeapType type; - parseTypeUse(s, i, type); - functionTypes[name] = type; + parseTypeUse(s, i, functionTypes[name]); } size_t SExpressionWasmBuilder::parseFunctionNames(Element& s, @@ -1007,12 +1005,12 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) { im->setName(name, hasExplicitName); im->module = importModule; im->base = importBase; - im->sig = type.getSignature(); + im->type = type; functionTypes[name] = type; if (wasm.getFunctionOrNull(im->name)) { throw ParseException("duplicate import", s.line, s.col); } - wasm.addFunction(im.release()); + wasm.addFunction(std::move(im)); if (currFunction) { throw ParseException("import module inside function dec", s.line, s.col); } @@ -1034,8 +1032,8 @@ void SExpressionWasmBuilder::parseFunction(Element& s, bool preParseImport) { } // make a new function - currFunction = std::unique_ptr<Function>(Builder(wasm).makeFunction( - name, std::move(params), type.getSignature().results, std::move(vars))); + currFunction = std::unique_ptr<Function>( + Builder(wasm).makeFunction(name, std::move(params), type, std::move(vars))); currFunction->profile = profile; // parse body @@ -3045,13 +3043,11 @@ void SExpressionWasmBuilder::parseImport(Element& s) { if (kind == ExternalKind::Function) { auto func = make_unique<Function>(); - HeapType funcType; - j = parseTypeUse(inner, j, funcType); - func->sig = funcType.getSignature(); + j = parseTypeUse(inner, j, func->type); func->setName(name, hasExplicitName); func->module = module; func->base = base; - functionTypes[name] = funcType; + functionTypes[name] = func->type; wasm.addFunction(func.release()); } else if (kind == ExternalKind::Global) { Type type; @@ -3403,7 +3399,7 @@ ElementSegment* SExpressionWasmBuilder::parseElemFinish( for (; i < s.size(); i++) { auto func = getFunctionName(*s[i]); segment->data.push_back( - Builder(wasm).makeRefFunc(func, functionTypes[func].getSignature())); + Builder(wasm).makeRefFunc(func, functionTypes[func])); } } return wasm.addElementSegment(std::move(segment)); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index bed04b92b..f492c7110 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -461,7 +461,7 @@ private: curr, "return_call* should have unreachable type"); shouldBeEqual( - getFunction()->sig.results, + getFunction()->getResults(), sig.results, curr, "return_call* callee return type must match caller return type"); @@ -785,7 +785,7 @@ void FunctionValidator::visitCall(Call* curr) { if (!shouldBeTrue(!!target, curr, "call target must exist")) { return; } - validateCallParamsAndResult(curr, target->sig); + validateCallParamsAndResult(curr, target->getSig()); } void FunctionValidator::visitCallIndirect(CallIndirect* curr) { @@ -2481,17 +2481,17 @@ void FunctionValidator::visitArrayCopy(ArrayCopy* curr) { } void FunctionValidator::visitFunction(Function* curr) { - if (curr->sig.results.isTuple()) { + if (curr->getResults().isTuple()) { shouldBeTrue(getModule()->features.hasMultivalue(), curr->body, "Multivalue function results (multivalue is not enabled)"); } FeatureSet features; - for (const auto& param : curr->sig.params) { + for (const auto& param : curr->getParams()) { features |= param.getFeatures(); shouldBeTrue(param.isConcrete(), curr, "params must be concretely typed"); } - for (const auto& result : curr->sig.results) { + for (const auto& result : curr->getResults()) { features |= result.getFeatures(); shouldBeTrue(result.isConcrete(), curr, "results must be concretely typed"); } @@ -2512,12 +2512,12 @@ void FunctionValidator::visitFunction(Function* curr) { // if function has no result, it is ignored // if body is unreachable, it might be e.g. a return shouldBeSubType(curr->body->type, - curr->sig.results, + curr->getResults(), curr->body, "function body type must match, if function returns"); for (Type returnType : returnTypes) { shouldBeSubType(returnType, - curr->sig.results, + curr->getResults(), curr->body, "function result must match, if function has returns"); } @@ -2657,20 +2657,20 @@ static void validateBinaryenIR(Module& wasm, ValidationInfo& info) { static void validateImports(Module& module, ValidationInfo& info) { ModuleUtils::iterImportedFunctions(module, [&](Function* curr) { - if (curr->sig.results.isTuple()) { + if (curr->getResults().isTuple()) { info.shouldBeTrue(module.features.hasMultivalue(), curr->name, "Imported multivalue function " "(multivalue is not enabled)"); } if (info.validateWeb) { - for (const auto& param : curr->sig.params) { + for (const auto& param : curr->getParams()) { info.shouldBeUnequal(param, Type(Type::i64), curr->name, "Imported function must not have i64 parameters"); } - for (const auto& result : curr->sig.results) { + for (const auto& result : curr->getResults()) { info.shouldBeUnequal(result, Type(Type::i64), curr->name, @@ -2693,14 +2693,14 @@ static void validateExports(Module& module, ValidationInfo& info) { if (curr->kind == ExternalKind::Function) { if (info.validateWeb) { Function* f = module.getFunction(curr->value); - for (const auto& param : f->sig.params) { + for (const auto& param : f->getParams()) { info.shouldBeUnequal( param, Type(Type::i64), f->name, "Exported function must not have i64 parameters"); } - for (const auto& result : f->sig.results) { + for (const auto& result : f->getResults()) { info.shouldBeUnequal(result, Type(Type::i64), f->name, @@ -3007,10 +3007,10 @@ 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->sig.params == Type::none, + info.shouldBeTrue(func->getParams() == Type::none, module.start, "start must have 0 params"); - info.shouldBeTrue(func->sig.results == Type::none, + info.shouldBeTrue(func->getResults() == Type::none, module.start, "start must not return a value"); } diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 54c82159f..5b1163ae0 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -1087,14 +1087,14 @@ void RefAs::finalize() { } } -size_t Function::getNumParams() { return sig.params.size(); } +size_t Function::getNumParams() { return getParams().size(); } size_t Function::getNumVars() { return vars.size(); } -size_t Function::getNumLocals() { return sig.params.size() + vars.size(); } +size_t Function::getNumLocals() { return getParams().size() + vars.size(); } bool Function::isParam(Index index) { - size_t size = sig.params.size(); + size_t size = getParams().size(); assert(index < size + vars.size()); return index < size; } @@ -1141,12 +1141,12 @@ Index Function::getLocalIndex(Name name) { return iter->second; } -Index Function::getVarIndexBase() { return sig.params.size(); } +Index Function::getVarIndexBase() { return getParams().size(); } Type Function::getLocalType(Index index) { - auto numParams = sig.params.size(); + auto numParams = getParams().size(); if (index < numParams) { - return sig.params[index]; + return getParams()[index]; } else if (isVar(index)) { return vars[index - numParams]; } else { |