diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm-binary.h | 22 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 186 |
2 files changed, 182 insertions, 26 deletions
diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 9ac5664d3..c869adf06 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -393,6 +393,14 @@ enum Subsection { NameModule = 0, NameFunction = 1, NameLocal = 2, + // see: https://github.com/WebAssembly/extended-name-section + NameLabel = 3, + NameType = 4, + NameTable = 5, + NameMemory = 6, + NameGlobal = 7, + NameElem = 8, + NameData = 9 }; } // namespace UserSections @@ -1299,8 +1307,8 @@ public: Name getNextLabel(); - // We read functions before we know their names, so we need to backpatch the - // names later + // We read functions and globals before we know their names, so we need to + // backpatch the names later // we store functions here before wasm.addFunction after we know their names std::vector<Function*> functions; @@ -1314,6 +1322,14 @@ public: // function to check Index endOfFunction = -1; + // we store globals here before wasm.addGlobal after we know their names + std::vector<Global*> globals; + // we store global imports here before wasm.addGlobalImport after we know + // their names + std::vector<Global*> globalImports; + // at index i we have all refs to the global i + std::map<Index, std::vector<Expression*>> globalRefs; + // Throws a parsing error if we are not in a function context void requireFunctionContext(const char* error); @@ -1382,7 +1398,7 @@ public: Expression* popTypedExpression(Type type); void validateBinary(); // validations that cannot be performed on the Module - void processFunctions(); + void processNames(); size_t dataCount = 0; bool hasDataCount = false; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 85880a988..48564a897 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -551,10 +551,6 @@ void WasmBinaryWriter::writeEvents() { } void WasmBinaryWriter::writeNames() { - if (wasm->functions.empty()) { - return; - } - BYN_TRACE("== writeNames\n"); auto start = startSection(BinaryConsts::Section::User); writeInlineString(BinaryConsts::UserSections::Name); @@ -631,6 +627,52 @@ void WasmBinaryWriter::writeNames() { } } + // table names + if (wasm->table.exists && wasm->table.name.is()) { + auto substart = + startSubsection(BinaryConsts::UserSections::Subsection::NameTable); + o << U32LEB(1) << U32LEB(0); // currently exactly 1 table at index 0 + writeEscapedName(wasm->table.name.str); + finishSubsection(substart); + } + + // memory names + if (wasm->memory.exists && wasm->memory.name.is()) { + auto substart = + startSubsection(BinaryConsts::UserSections::Subsection::NameMemory); + o << U32LEB(1) << U32LEB(0); // currently exactly 1 memory at index 0 + writeEscapedName(wasm->memory.name.str); + finishSubsection(substart); + } + + // global names + { + std::vector<std::pair<Index, Global*>> globalsWithNames; + Index checked = 0; + auto check = [&](Global* curr) { + if (curr->name.is()) { + globalsWithNames.push_back({checked, curr}); + } + checked++; + }; + ModuleUtils::iterImportedGlobals(*wasm, check); + ModuleUtils::iterDefinedGlobals(*wasm, check); + assert(checked == indexes.globalIndexes.size()); + if (globalsWithNames.size() > 0) { + auto substart = + startSubsection(BinaryConsts::UserSections::Subsection::NameGlobal); + o << U32LEB(globalsWithNames.size()); + for (auto& indexedGlobal : globalsWithNames) { + o << U32LEB(indexedGlobal.first); + writeEscapedName(indexedGlobal.second->name.str); + } + finishSubsection(substart); + } + } + + // TODO: label, type, element and data names + // see: https://github.com/WebAssembly/extended-name-section + finishSection(start); } @@ -1035,7 +1077,7 @@ void WasmBinaryBuilder::read() { } validateBinary(); - processFunctions(); + processNames(); } void WasmBinaryBuilder::readUserSection(size_t payloadLen) { @@ -1459,7 +1501,7 @@ void WasmBinaryBuilder::readImports() { case ExternalKind::Memory: { wasm.memory.module = module; wasm.memory.base = base; - wasm.memory.name = Name(std::to_string(i)); + wasm.memory.name = Name(std::string("mimport$") + std::to_string(i)); wasm.memory.exists = true; getResizableLimits(wasm.memory.initial, wasm.memory.max, @@ -1480,6 +1522,7 @@ void WasmBinaryBuilder::readImports() { curr->module = module; curr->base = base; wasm.addGlobal(curr); + globalImports.push_back(curr); break; } case ExternalKind::Event: { @@ -1819,7 +1862,7 @@ void WasmBinaryBuilder::readGlobals() { throwError("Global mutability must be 0 or 1"); } auto* init = readExpression(); - wasm.addGlobal( + globals.push_back( Builder::makeGlobal("global$" + std::to_string(i), type, init, @@ -2008,12 +2051,15 @@ void WasmBinaryBuilder::validateBinary() { } } -void WasmBinaryBuilder::processFunctions() { +void WasmBinaryBuilder::processNames() { for (auto* func : functions) { wasm.addFunction(func); } + for (auto* global : globals) { + wasm.addGlobal(global); + } - // now that we have names for each function, apply things + // now that we have names, apply things if (startIndex != static_cast<Index>(-1)) { wasm.start = getFunctionName(startIndex); @@ -2027,10 +2073,10 @@ void WasmBinaryBuilder::processFunctions() { break; } case ExternalKind::Table: - curr->value = Name::fromInt(0); + curr->value = wasm.table.name; break; case ExternalKind::Memory: - curr->value = Name::fromInt(0); + curr->value = wasm.memory.name; break; case ExternalKind::Global: curr->value = getGlobalName(index); @@ -2066,6 +2112,20 @@ void WasmBinaryBuilder::processFunctions() { } } + for (auto& iter : globalRefs) { + size_t index = iter.first; + auto& refs = iter.second; + for (auto* ref : refs) { + if (auto* get = ref->dynCast<GlobalGet>()) { + get->name = getGlobalName(index); + } else if (auto* set = ref->dynCast<GlobalSet>()) { + set->name = getGlobalName(index); + } else { + WASM_UNREACHABLE("Invalid type in global references"); + } + } + } + // Everything now has its proper name. wasm.updateMaps(); @@ -2226,14 +2286,12 @@ void WasmBinaryBuilder::readNames(size_t payloadLen) { for (size_t i = 0; i < num; i++) { auto index = getU32LEB(); auto rawName = getInlineString(); - rawName = escape(rawName); - auto name = rawName; + auto name = escape(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); + name = std::string(escape(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; @@ -2242,7 +2300,7 @@ void WasmBinaryBuilder::readNames(size_t payloadLen) { } else { std::cerr << "warning: function index out of bounds in name section, " "function subsection: " - << std::string(name.str) << " at index " + << std::string(rawName.str) << " at index " << std::to_string(index) << std::endl; } } @@ -2263,25 +2321,85 @@ void WasmBinaryBuilder::readNames(size_t payloadLen) { << std::to_string(funcIndex) << std::endl; } auto numLocals = getU32LEB(); + std::set<Name> usedNames; for (size_t j = 0; j < numLocals; j++) { auto localIndex = getU32LEB(); - auto localName = getInlineString(); + auto rawLocalName = getInlineString(); if (!func) { continue; // read and discard in case of prior error } + auto localName = escape(rawLocalName); + // De-duplicate names by appending .1, .2, etc. + for (int i = 1; !usedNames.insert(localName).second; ++i) { + localName = std::string(escape(rawLocalName).str) + + std::string(".") + std::to_string(i); + } 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::string(rawLocalName.str) << " at index " << std::to_string(localIndex) << " in function " << std::string(func->name.str) << std::endl; } } } + } else if (nameType == BinaryConsts::UserSections::Subsection::NameTable) { + auto num = getU32LEB(); + for (size_t i = 0; i < num; i++) { + auto index = getU32LEB(); + auto rawName = getInlineString(); + if (index == 0) { + wasm.table.name = escape(rawName); + } else { + std::cerr << "warning: table index out of bounds in name section, " + "table subsection: " + << std::string(rawName.str) << " at index " + << std::to_string(index) << std::endl; + } + } + } else if (nameType == BinaryConsts::UserSections::Subsection::NameMemory) { + auto num = getU32LEB(); + for (size_t i = 0; i < num; i++) { + auto index = getU32LEB(); + auto rawName = getInlineString(); + if (index == 0) { + wasm.memory.name = escape(rawName); + } else { + std::cerr << "warning: memory index out of bounds in name section, " + "memory subsection: " + << std::string(rawName.str) << " at index " + << std::to_string(index) << std::endl; + } + } + } else if (nameType == BinaryConsts::UserSections::Subsection::NameGlobal) { + auto num = getU32LEB(); + std::set<Name> usedNames; + for (size_t i = 0; i < num; i++) { + auto index = getU32LEB(); + auto rawName = getInlineString(); + auto name = escape(rawName); + // De-duplicate names by appending .1, .2, etc. + for (int i = 1; !usedNames.insert(name).second; ++i) { + name = std::string(escape(rawName).str) + std::string(".") + + std::to_string(i); + } + auto numGlobalImports = globalImports.size(); + if (index < numGlobalImports) { + globalImports[index]->name = name; + } else if (index - numGlobalImports < globals.size()) { + globals[index - numGlobalImports]->name = name; + } else { + std::cerr << "warning: global index out of bounds in name section, " + "global subsection: " + << std::string(rawName.str) << " at index " + << std::to_string(index) << std::endl; + } + } } else { - std::cerr << "warning: unknown name subsection at " << pos << std::endl; + std::cerr << "warning: unknown name subsection with id " + << std::to_string(nameType) << " at " << pos << std::endl; pos = subsectionPos + subsectionSize; } if (pos != subsectionPos + subsectionSize) { @@ -2952,15 +3070,37 @@ void WasmBinaryBuilder::visitLocalSet(LocalSet* curr, uint8_t code) { void WasmBinaryBuilder::visitGlobalGet(GlobalGet* curr) { BYN_TRACE("zz node: GlobalGet " << pos << std::endl); auto index = getU32LEB(); - curr->name = getGlobalName(index); - curr->type = wasm.getGlobal(curr->name)->type; + if (index < globalImports.size()) { + auto* import = globalImports[index]; + curr->name = import->name; + curr->type = import->type; + } else { + Index adjustedIndex = index - globalImports.size(); + if (adjustedIndex >= globals.size()) { + throwError("invalid global index"); + } + auto* glob = globals[adjustedIndex]; + curr->name = glob->name; + curr->type = glob->type; + } + globalRefs[index].push_back(curr); // we don't know the final name yet } void WasmBinaryBuilder::visitGlobalSet(GlobalSet* curr) { BYN_TRACE("zz node: GlobalSet\n"); auto index = getU32LEB(); - curr->name = getGlobalName(index); + if (index < globalImports.size()) { + auto* import = globalImports[index]; + curr->name = import->name; + } else { + Index adjustedIndex = index - globalImports.size(); + if (adjustedIndex >= globals.size()) { + throwError("invalid global index"); + } + curr->name = globals[adjustedIndex]->name; + } curr->value = popNonVoidExpression(); + globalRefs[index].push_back(curr); // we don't know the final name yet curr->finalize(); } |