summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-binary.cpp
diff options
context:
space:
mode:
authorDaniel Wirtz <dcode@dcode.io>2020-09-14 11:51:59 +0200
committerGitHub <noreply@github.com>2020-09-14 11:51:59 +0200
commit18716065cc470c3bc29a4fecf3889891a9bf604b (patch)
treef106abf584fcc2ab1e14320682962326357479e8 /src/wasm/wasm-binary.cpp
parent0ade3f2761b0661ab4d1290ab704c594c1d90df9 (diff)
downloadbinaryen-18716065cc470c3bc29a4fecf3889891a9bf604b.tar.gz
binaryen-18716065cc470c3bc29a4fecf3889891a9bf604b.tar.bz2
binaryen-18716065cc470c3bc29a4fecf3889891a9bf604b.zip
Implement module and local names in name section (#3115)
Adds support for the module and local subsections of the name section plus the respective C and JS APIs to populate and obtain local names. C API: * BinaryenFunctionGetNumLocals(func) * BinaryenFunctionHasLocalName(func, index) * BinaryenFunctionGetLocalName(func, index) * BinaryenFunctionSetLocalName(func, index, name) JS API: * Function.getNumLocals(func) * Function.hasLocalName(func, index) * Function.getLocalName(func, index) * Function.setLocalName(func, index, name)
Diffstat (limited to 'src/wasm/wasm-binary.cpp')
-rw-r--r--src/wasm/wasm-binary.cpp174
1 files changed, 136 insertions, 38 deletions
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");