diff options
Diffstat (limited to 'src/wasm/wasm-binary.cpp')
-rw-r--r-- | src/wasm/wasm-binary.cpp | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 263f905fb..16950f88f 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -54,6 +54,9 @@ void WasmBinaryWriter::write() { writeTableDeclarations(); writeMemory(); writeTags(); + if (wasm->features.hasStrings()) { + writeStrings(); + } writeGlobals(); writeExports(); writeStart(); @@ -451,6 +454,69 @@ void WasmBinaryWriter::writeFunctions() { finishSection(sectionStart); } +void WasmBinaryWriter::writeStrings() { + assert(wasm->features.hasStrings()); + + // Scan the entire wasm to find the relevant strings. + // To find all the string literals we must scan all the code. + using StringSet = std::unordered_set<Name>; + + struct StringWalker : public PostWalker<StringWalker> { + StringSet& strings; + + StringWalker(StringSet& strings) : strings(strings) {} + + void visitStringConst(StringConst* curr) { strings.insert(curr->string); } + }; + + ModuleUtils::ParallelFunctionAnalysis<StringSet> analysis( + *wasm, [&](Function* func, StringSet& strings) { + if (!func->imported()) { + StringWalker(strings).walk(func->body); + } + }); + + // Also walk the global module code (for simplicity, also add it to the + // function map, using a "function" key of nullptr). + auto& globalStrings = analysis.map[nullptr]; + StringWalker(globalStrings).walkModuleCode(wasm); + + // Generate the indexes from the combined set of necessary strings, + // which we sort for determinism. + StringSet allStrings; + for (auto& [func, strings] : analysis.map) { + for (auto& string : strings) { + allStrings.insert(string); + } + } + std::vector<Name> sorted; + for (auto& string : allStrings) { + sorted.push_back(string); + } + std::sort(sorted.begin(), sorted.end()); + for (Index i = 0; i < sorted.size(); i++) { + stringIndexes[sorted[i]] = i; + } + + auto num = sorted.size(); + if (num == 0) { + return; + } + + auto start = startSection(BinaryConsts::Section::Strings); + + // Placeholder for future use in the spec. + o << U32LEB(0); + + // The number of strings and then their contents. + o << U32LEB(num); + for (auto& string : sorted) { + writeInlineString(string.str); + } + + finishSection(start); +} + void WasmBinaryWriter::writeGlobals() { if (importInfo->getNumDefinedGlobals() == 0) { return; @@ -586,6 +652,12 @@ uint32_t WasmBinaryWriter::getTypeIndex(HeapType type) const { return it->second; } +uint32_t WasmBinaryWriter::getStringIndex(Name string) const { + auto it = stringIndexes.find(string); + assert(it != stringIndexes.end()); + return it->second; +} + void WasmBinaryWriter::writeTableDeclarations() { if (importInfo->getNumDefinedTables() == 0) { // std::cerr << std::endl << "(WasmBinaryWriter::writeTableDeclarations) No @@ -1489,6 +1561,9 @@ void WasmBinaryBuilder::read() { case BinaryConsts::Section::Element: readElementSegments(); break; + case BinaryConsts::Section::Strings: + readStrings(); + break; case BinaryConsts::Section::Global: readGlobals(); break; @@ -2612,6 +2687,18 @@ Expression* WasmBinaryBuilder::readExpression() { return ret; } +void WasmBinaryBuilder::readStrings() { + auto reserved = getU32LEB(); + if (reserved != 0) { + throwError("unexpected reserved value in strings"); + } + size_t num = getU32LEB(); + for (size_t i = 0; i < num; i++) { + auto string = getInlineString(); + strings.push_back(string); + } +} + void WasmBinaryBuilder::readGlobals() { BYN_TRACE("== readGlobals\n"); size_t num = getU32LEB(); @@ -3834,6 +3921,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { if (maybeVisitStringNew(curr, opcode)) { break; } + if (maybeVisitStringConst(curr, opcode)) { + break; + } if (opcode == BinaryConsts::RefIsFunc || opcode == BinaryConsts::RefIsData || opcode == BinaryConsts::RefIsI31) { @@ -7060,6 +7150,18 @@ bool WasmBinaryBuilder::maybeVisitStringNew(Expression*& out, uint32_t code) { return true; } +bool WasmBinaryBuilder::maybeVisitStringConst(Expression*& out, uint32_t code) { + if (code != BinaryConsts::StringConst) { + return false; + } + auto index = getU32LEB(); + if (index >= strings.size()) { + throwError("bad string index"); + } + out = Builder(wasm).makeStringConst(strings[index]); + return true; +} + void WasmBinaryBuilder::visitRefAs(RefAs* curr, uint8_t code) { BYN_TRACE("zz node: RefAs\n"); switch (code) { |