diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 16 | ||||
-rw-r--r-- | src/binaryen-c.h | 13 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 48 | ||||
-rw-r--r-- | src/passes/Print.cpp | 4 | ||||
-rw-r--r-- | src/tools/wasm-shell.cpp | 4 | ||||
-rw-r--r-- | src/wasm-binary.h | 1 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 5 | ||||
-rw-r--r-- | src/wasm.h | 6 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 174 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 7 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 5 |
11 files changed, 227 insertions, 56 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index e11b762dd..3582c99ca 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -3709,6 +3709,22 @@ BinaryenType BinaryenFunctionGetVar(BinaryenFunctionRef func, assert(index < vars.size()); return vars[index].getID(); } +BinaryenIndex BinaryenFunctionGetNumLocals(BinaryenFunctionRef func) { + return ((Function*)func)->getNumLocals(); +} +int BinaryenFunctionHasLocalName(BinaryenFunctionRef func, + BinaryenIndex index) { + return ((Function*)func)->hasLocalName(index); +} +const char* BinaryenFunctionGetLocalName(BinaryenFunctionRef func, + BinaryenIndex index) { + return ((Function*)func)->getLocalName(index).str; +} +void BinaryenFunctionSetLocalName(BinaryenFunctionRef func, + BinaryenIndex index, + const char* name) { + ((Function*)func)->setLocalName(index, name); +} BinaryenExpressionRef BinaryenFunctionGetBody(BinaryenFunctionRef func) { return ((Function*)func)->body; } diff --git a/src/binaryen-c.h b/src/binaryen-c.h index e622419ac..1adc73b8e 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -2236,6 +2236,19 @@ BINARYEN_API BinaryenIndex BinaryenFunctionGetNumVars(BinaryenFunctionRef func); // specified `Function`. BINARYEN_API BinaryenType BinaryenFunctionGetVar(BinaryenFunctionRef func, BinaryenIndex index); +// Gets the number of locals within the specified function. Includes parameters. +BINARYEN_API BinaryenIndex +BinaryenFunctionGetNumLocals(BinaryenFunctionRef func); +// Tests if the local at the specified index has a name. +BINARYEN_API int BinaryenFunctionHasLocalName(BinaryenFunctionRef func, + BinaryenIndex index); +// Gets the name of the local at the specified index. +BINARYEN_API const char* BinaryenFunctionGetLocalName(BinaryenFunctionRef func, + BinaryenIndex index); +// Sets the name of the local at the specified index. +BINARYEN_API void BinaryenFunctionSetLocalName(BinaryenFunctionRef func, + BinaryenIndex index, + const char* name); // Gets the body of the specified `Function`. BINARYEN_API BinaryenExpressionRef BinaryenFunctionGetBody(BinaryenFunctionRef func); diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index fd121b8af..d7c1878fd 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -3061,18 +3061,18 @@ function makeExpressionWrapper(ownStaticMembers) { // inherit from Expression (SpecificExpression.prototype = Object.create(Expression.prototype)).constructor = SpecificExpression; // make own instance members - makeExpressionWrapperInstanceMembers(SpecificExpression.prototype, ownStaticMembers); + makeWrapperInstanceMembers(SpecificExpression.prototype, ownStaticMembers); return SpecificExpression; } // Makes instance members from the given static members -function makeExpressionWrapperInstanceMembers(prototype, staticMembers) { +function makeWrapperInstanceMembers(prototype, staticMembers, ref = 'expr') { Object.keys(staticMembers).forEach(memberName => { const member = staticMembers[memberName]; if (typeof member === "function") { // Instance method calls the respective static method prototype[memberName] = function(...args) { - return this.constructor[memberName](this['expr'], ...args); + return this.constructor[memberName](this[ref], ...args); }; // Instance accessor calls the respective static methods let match; @@ -3082,10 +3082,10 @@ function makeExpressionWrapperInstanceMembers(prototype, staticMembers) { const setterIfAny = staticMembers["set" + memberName.substring(index)]; Object.defineProperty(prototype, propertyName, { get() { - return member(this['expr']); + return member(this[ref]); }, set(value) { - if (setterIfAny) setterIfAny(this['expr'], value); + if (setterIfAny) setterIfAny(this[ref], value); else throw Error("property '" + propertyName + "' has no setter"); } }); @@ -3114,7 +3114,7 @@ Expression['finalize'] = function(expr) { Expression['toText'] = function(expr) { return Module['emitText'](expr); }; -makeExpressionWrapperInstanceMembers(Expression.prototype, Expression); +makeWrapperInstanceMembers(Expression.prototype, Expression); Expression.prototype['valueOf'] = function() { return this['expr']; }; @@ -4281,6 +4281,42 @@ Module['TupleExtract'] = makeExpressionWrapper({ } }); +// Function wrapper + +Module['Function'] = (() => { + function Function(func) { + if (!(this instanceof Function)) { + if (!func) return null; + return new Function(func); + } + if (!func) throw Error("function reference must not be null"); + this['func'] = func; + } + Function['getName'] = function(func) { + return Module['_BinaryenFunctionGetName'](func); + }; + Function['getNumLocals'] = function(func) { + return Module['_BinaryenFunctionGetNumLocals'](func); + }; + Function['hasLocalName'] = function(func, index) { + return Boolean(Module['_BinaryenFunctionHasLocalName'](func, index)); + }; + Function['getLocalName'] = function(func, index) { + return UTF8ToString(Module['_BinaryenFunctionGetLocalName'](func, index)); + }; + Function['setLocalName'] = function(func, index, name) { + preserveStack(() => { + Module['_BinaryenFunctionSetLocalName'](func, index, strToStack(name)); + }); + }; + // TODO: add more methods + makeWrapperInstanceMembers(Function.prototype, Function, 'func'); + Function.prototype['valueOf'] = function() { + return this['func']; + }; + return Function; +})(); + // Additional customizations Module['exit'] = function(status) { diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index f4131db37..15ab97098 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2398,6 +2398,10 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> { currModule = curr; o << '('; printMajor(o, "module"); + if (curr->name.is()) { + o << ' '; + printName(curr->name, o); + } incIndent(); std::vector<Signature> signatures; std::unordered_map<Signature, Index> indices; diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index 80229554b..8ba6a4142 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -304,9 +304,9 @@ int main(int argc, const char* argv[]) { std::cerr << "BUILDING MODULE [line: " << curr.line << "]\n"; Colors::normal(std::cerr); auto module = wasm::make_unique<Module>(); - Name moduleName; auto builder = wasm::make_unique<SExpressionWasmBuilder>( - *module, *root[i], IRProfile::Normal, &moduleName); + *module, *root[i], IRProfile::Normal); + auto moduleName = module->name; builders[moduleName].swap(builder); modules[moduleName].swap(module); i++; diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 33f78ce7f..8a067e3fd 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -386,6 +386,7 @@ extern const char* MultivalueFeature; extern const char* AnyrefFeature; enum Subsection { + NameModule = 0, NameFunction = 1, NameLocal = 2, }; diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index a4559012d..85ca217e7 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -126,10 +126,7 @@ class SExpressionWasmBuilder { public: // Assumes control of and modifies the input. - SExpressionWasmBuilder(Module& wasm, - Element& module, - IRProfile profile, - Name* moduleName = nullptr); + SExpressionWasmBuilder(Module& wasm, Element& module, IRProfile profile); private: // pre-parse types and function definitions, so we know function return types diff --git a/src/wasm.h b/src/wasm.h index 63a6fe79c..c5db2fbd3 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1263,7 +1263,7 @@ using StackIR = std::vector<StackInst*>; class Function : public Importable { public: Name name; - Signature sig; // parameters and return value + Signature sig; // parameters and return value IRProfile profile = IRProfile::Normal; std::vector<Type> vars; // non-param locals @@ -1328,6 +1328,7 @@ public: Name getLocalNameOrGeneric(Index index); bool hasLocalName(Index index) const; + void setLocalName(Index index, Name name); void clearNames(); void clearDebugInfo(); @@ -1502,6 +1503,9 @@ public: FeatureSet features = FeatureSet::MVP; bool hasFeaturesSection = false; + // Module name, if specified. Serves a documentary role only. + Name name; + MixedArena allocator; private: diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index de82f0656..fb8d97cb5 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -555,20 +555,79 @@ void WasmBinaryWriter::writeNames() { BYN_TRACE("== writeNames\n"); auto start = startSection(BinaryConsts::Section::User); writeInlineString(BinaryConsts::UserSections::Name); - auto substart = - startSubsection(BinaryConsts::UserSections::Subsection::NameFunction); - o << U32LEB(indexes.functionIndexes.size()); - Index emitted = 0; - auto add = [&](Function* curr) { - o << U32LEB(emitted); - writeEscapedName(curr->name.str); - emitted++; - }; - ModuleUtils::iterImportedFunctions(*wasm, add); - ModuleUtils::iterDefinedFunctions(*wasm, add); - assert(emitted == indexes.functionIndexes.size()); - finishSubsection(substart); - /* TODO: locals */ + + // module name + if (wasm->name.is()) { + auto substart = + startSubsection(BinaryConsts::UserSections::Subsection::NameModule); + writeEscapedName(wasm->name.str); + finishSubsection(substart); + } + + // function names + { + auto substart = + startSubsection(BinaryConsts::UserSections::Subsection::NameFunction); + o << U32LEB(indexes.functionIndexes.size()); + Index emitted = 0; + auto add = [&](Function* curr) { + o << U32LEB(emitted); + writeEscapedName(curr->name.str); + emitted++; + }; + ModuleUtils::iterImportedFunctions(*wasm, add); + ModuleUtils::iterDefinedFunctions(*wasm, add); + assert(emitted == indexes.functionIndexes.size()); + finishSubsection(substart); + } + + // local names + { + // Find all functions with at least one local name and only emit the + // subsection if there is at least one. + std::vector<std::pair<Index, Function*>> functionsWithLocalNames; + Index checked = 0; + auto check = [&](Function* curr) { + auto numLocals = curr->getNumLocals(); + for (Index i = 0; i < numLocals; ++i) { + if (curr->hasLocalName(i)) { + functionsWithLocalNames.push_back({checked, curr}); + break; + } + } + checked++; + }; + ModuleUtils::iterImportedFunctions(*wasm, check); + ModuleUtils::iterDefinedFunctions(*wasm, check); + assert(checked == indexes.functionIndexes.size()); + if (functionsWithLocalNames.size() > 0) { + // Otherwise emit those functions but only include locals with a name. + auto substart = + startSubsection(BinaryConsts::UserSections::Subsection::NameLocal); + o << U32LEB(functionsWithLocalNames.size()); + Index emitted = 0; + for (auto& indexedFunc : functionsWithLocalNames) { + std::vector<std::pair<Index, Name>> localsWithNames; + auto numLocals = indexedFunc.second->getNumLocals(); + for (Index i = 0; i < numLocals; ++i) { + if (indexedFunc.second->hasLocalName(i)) { + localsWithNames.push_back({i, indexedFunc.second->getLocalName(i)}); + } + } + assert(localsWithNames.size()); + o << U32LEB(indexedFunc.first); + o << U32LEB(localsWithNames.size()); + for (auto& indexedLocal : localsWithNames) { + o << U32LEB(indexedLocal.first); + writeEscapedName(indexedLocal.second.str); + } + emitted++; + } + assert(emitted == functionsWithLocalNames.size()); + finishSubsection(substart); + } + } + finishSection(start); } @@ -2126,33 +2185,72 @@ void WasmBinaryBuilder::readNames(size_t payloadLen) { auto nameType = getU32LEB(); auto subsectionSize = getU32LEB(); auto subsectionPos = pos; - if (nameType != BinaryConsts::UserSections::Subsection::NameFunction) { - // TODO: locals - std::cerr << "warning: unknown name subsection at " << pos << std::endl; - pos = subsectionPos + subsectionSize; - continue; - } - auto num = getU32LEB(); - std::set<Name> usedNames; - for (size_t i = 0; i < num; i++) { - auto index = getU32LEB(); - auto rawName = getInlineString(); - rawName = escape(rawName); - auto name = rawName; - // De-duplicate names by appending .1, .2, etc. - for (int i = 1; !usedNames.insert(name).second; ++i) { - name = rawName.str + std::string(".") + std::to_string(i); + if (nameType == BinaryConsts::UserSections::Subsection::NameModule) { + wasm.name = getInlineString(); + } else if (nameType == + BinaryConsts::UserSections::Subsection::NameFunction) { + auto num = getU32LEB(); + std::set<Name> usedNames; + for (size_t i = 0; i < num; i++) { + auto index = getU32LEB(); + auto rawName = getInlineString(); + rawName = escape(rawName); + auto name = rawName; + // De-duplicate names by appending .1, .2, etc. + for (int i = 1; !usedNames.insert(name).second; ++i) { + name = rawName.str + std::string(".") + std::to_string(i); + } + // note: we silently ignore errors here, as name section errors + // are not fatal. should we warn? + auto numFunctionImports = functionImports.size(); + if (index < numFunctionImports) { + functionImports[index]->name = name; + } else if (index - numFunctionImports < functions.size()) { + functions[index - numFunctionImports]->name = name; + } else { + std::cerr << "warning: function index out of bounds in name section, " + "function subsection: " + << std::string(name.str) << " at index " + << std::to_string(index) << std::endl; + } } - // note: we silently ignore errors here, as name section errors - // are not fatal. should we warn? + } else if (nameType == BinaryConsts::UserSections::Subsection::NameLocal) { + auto numFuncs = getU32LEB(); auto numFunctionImports = functionImports.size(); - if (index < numFunctionImports) { - functionImports[index]->name = name; - } else if (index - numFunctionImports < functions.size()) { - functions[index - numFunctionImports]->name = name; - } else { - throwError("index out of bounds: " + std::string(name.str)); + for (size_t i = 0; i < numFuncs; i++) { + auto funcIndex = getU32LEB(); + Function* func = nullptr; + if (funcIndex < numFunctionImports) { + func = functionImports[funcIndex]; + } else if (funcIndex - numFunctionImports < functions.size()) { + func = functions[funcIndex - numFunctionImports]; + } else { + std::cerr + << "warning: function index out of bounds in name section, local " + "subsection: " + << std::to_string(funcIndex) << std::endl; + } + auto numLocals = getU32LEB(); + for (size_t j = 0; j < numLocals; j++) { + auto localIndex = getU32LEB(); + auto localName = getInlineString(); + if (!func) { + continue; // read and discard in case of prior error + } + if (localIndex < func->getNumLocals()) { + func->localNames[localIndex] = localName; + } else { + std::cerr << "warning: local index out of bounds in name " + "section, local subsection: " + << std::string(localName.str) << " at index " + << std::to_string(localIndex) << " in function " + << std::string(func->name.str) << std::endl; + } + } } + } else { + std::cerr << "warning: unknown name subsection at " << pos << std::endl; + pos = subsectionPos + subsectionSize; } if (pos != subsectionPos + subsectionSize) { throwError("bad names subsection position change"); diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 97bfe55f9..97da80fea 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -314,8 +314,7 @@ Element* SExpressionParser::parseString() { SExpressionWasmBuilder::SExpressionWasmBuilder(Module& wasm, Element& module, - IRProfile profile, - Name* moduleName) + IRProfile profile) : wasm(wasm), allocator(wasm.allocator), profile(profile) { if (module.size() == 0) { throw ParseException("empty toplevel, expected module"); @@ -328,9 +327,7 @@ SExpressionWasmBuilder::SExpressionWasmBuilder(Module& wasm, } Index i = 1; if (module[i]->dollared()) { - if (moduleName) { - *moduleName = module[i]->str(); - } + wasm.name = module[i]->str(); i++; } if (i < module.size() && module[i]->isStr()) { diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 31e05f42e..5931b56aa 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -986,6 +986,11 @@ bool Function::hasLocalName(Index index) const { Name Function::getLocalName(Index index) { return localNames.at(index); } +void Function::setLocalName(Index index, Name name) { + assert(index < getNumLocals()); + localNames[index] = name; +} + Name Function::getLocalNameOrDefault(Index index) { auto nameIt = localNames.find(index); if (nameIt != localNames.end()) { |