diff options
author | Thomas Lively <tlively@google.com> | 2023-04-04 11:33:15 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-04 11:33:15 -0700 |
commit | a802fbe07c270f510c87dfa93577bd4731c075f3 (patch) | |
tree | 4c67b39ced46258593f6904bba4a5ac20292886c /src | |
parent | 05e1183954e49f8b3a1669cc7973af590afe9fc3 (diff) | |
download | binaryen-a802fbe07c270f510c87dfa93577bd4731c075f3.tar.gz binaryen-a802fbe07c270f510c87dfa93577bd4731c075f3.tar.bz2 binaryen-a802fbe07c270f510c87dfa93577bd4731c075f3.zip |
Use Names instead of indices to identify segments (#5618)
All top-level Module elements are identified and referred to by Name, but for
historical reasons element and data segments were referred to by index instead.
Fix this inconsistency by using Names to refer to segments from expressions that
use them. Also parse and print segment names like we do for other elements.
The C API is partially converted to use names instead of indices, but there are
still many functions that refer to data segments by index. Finishing the
conversion can be done in the future once it becomes necessary.
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 25 | ||||
-rw-r--r-- | src/binaryen-c.h | 13 | ||||
-rw-r--r-- | src/ir/possible-contents.cpp | 2 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 20 | ||||
-rw-r--r-- | src/passes/MemoryPacking.cpp | 87 | ||||
-rw-r--r-- | src/passes/MultiMemoryLowering.cpp | 2 | ||||
-rw-r--r-- | src/passes/PostEmscripten.cpp | 28 | ||||
-rw-r--r-- | src/passes/Print.cpp | 21 | ||||
-rw-r--r-- | src/passes/RemoveUnusedModuleElements.cpp | 3 | ||||
-rw-r--r-- | src/tools/fuzzing/fuzzing.cpp | 14 | ||||
-rw-r--r-- | src/wasm-binary.h | 10 | ||||
-rw-r--r-- | src/wasm-builder.h | 6 | ||||
-rw-r--r-- | src/wasm-delegations-fields.def | 6 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 15 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 4 | ||||
-rw-r--r-- | src/wasm.h | 6 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 55 | ||||
-rw-r--r-- | src/wasm/wasm-emscripten.cpp | 8 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 42 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 17 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 18 | ||||
-rw-r--r-- | src/wasm/wat-parser.cpp | 22 | ||||
-rw-r--r-- | src/wasm2js.h | 30 |
23 files changed, 272 insertions, 182 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index fe067587a..01f14f924 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -1553,14 +1553,14 @@ BinaryenExpressionRef BinaryenSIMDLoadStoreLane(BinaryenModuleRef module, getMemoryName(module, memoryName))); } BinaryenExpressionRef BinaryenMemoryInit(BinaryenModuleRef module, - uint32_t segment, + const char* segment, BinaryenExpressionRef dest, BinaryenExpressionRef offset, BinaryenExpressionRef size, const char* memoryName) { return static_cast<Expression*>( Builder(*(Module*)module) - .makeMemoryInit(segment, + .makeMemoryInit(Name(segment), (Expression*)dest, (Expression*)offset, (Expression*)size, @@ -1568,9 +1568,9 @@ BinaryenExpressionRef BinaryenMemoryInit(BinaryenModuleRef module, } BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module, - uint32_t segment) { + const char* segment) { return static_cast<Expression*>( - Builder(*(Module*)module).makeDataDrop(segment)); + Builder(*(Module*)module).makeDataDrop(Name(segment))); } BinaryenExpressionRef BinaryenMemoryCopy(BinaryenModuleRef module, @@ -3483,16 +3483,16 @@ bool BinaryenSIMDLoadStoreLaneIsStore(BinaryenExpressionRef expr) { return static_cast<SIMDLoadStoreLane*>(expression)->isStore(); } // MemoryInit -uint32_t BinaryenMemoryInitGetSegment(BinaryenExpressionRef expr) { +const char* BinaryenMemoryInitGetSegment(BinaryenExpressionRef expr) { auto* expression = (Expression*)expr; assert(expression->is<MemoryInit>()); - return static_cast<MemoryInit*>(expression)->segment; + return static_cast<MemoryInit*>(expression)->segment.str.data(); } void BinaryenMemoryInitSetSegment(BinaryenExpressionRef expr, - uint32_t segment) { + const char* segment) { auto* expression = (Expression*)expr; assert(expression->is<MemoryInit>()); - static_cast<MemoryInit*>(expression)->segment = segment; + static_cast<MemoryInit*>(expression)->segment = Name(segment); } BinaryenExpressionRef BinaryenMemoryInitGetDest(BinaryenExpressionRef expr) { auto* expression = (Expression*)expr; @@ -3531,15 +3531,16 @@ void BinaryenMemoryInitSetSize(BinaryenExpressionRef expr, static_cast<MemoryInit*>(expression)->size = (Expression*)sizeExpr; } // DataDrop -uint32_t BinaryenDataDropGetSegment(BinaryenExpressionRef expr) { +const char* BinaryenDataDropGetSegment(BinaryenExpressionRef expr) { auto* expression = (Expression*)expr; assert(expression->is<DataDrop>()); - return static_cast<DataDrop*>(expression)->segment; + return static_cast<DataDrop*>(expression)->segment.str.data(); } -void BinaryenDataDropSetSegment(BinaryenExpressionRef expr, uint32_t segment) { +void BinaryenDataDropSetSegment(BinaryenExpressionRef expr, + const char* segment) { auto* expression = (Expression*)expr; assert(expression->is<DataDrop>()); - static_cast<DataDrop*>(expression)->segment = segment; + static_cast<DataDrop*>(expression)->segment = Name(segment); } // MemoryCopy BinaryenExpressionRef BinaryenMemoryCopyGetDest(BinaryenExpressionRef expr) { diff --git a/src/binaryen-c.h b/src/binaryen-c.h index 1a54e311c..afbc13782 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -961,13 +961,13 @@ BinaryenSIMDLoadStoreLane(BinaryenModuleRef module, const char* memoryName); BINARYEN_API BinaryenExpressionRef BinaryenMemoryInit(BinaryenModuleRef module, - uint32_t segment, + const char* segment, BinaryenExpressionRef dest, BinaryenExpressionRef offset, BinaryenExpressionRef size, const char* memoryName); BINARYEN_API BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module, - uint32_t segment); + const char* segment); BINARYEN_API BinaryenExpressionRef BinaryenMemoryCopy(BinaryenModuleRef module, BinaryenExpressionRef dest, @@ -2031,11 +2031,12 @@ BINARYEN_API bool BinaryenSIMDLoadStoreLaneIsStore(BinaryenExpressionRef expr); // Gets the index of the segment being initialized by a `memory.init` // expression. -BINARYEN_API uint32_t BinaryenMemoryInitGetSegment(BinaryenExpressionRef expr); +BINARYEN_API const char* +BinaryenMemoryInitGetSegment(BinaryenExpressionRef expr); // Sets the index of the segment being initialized by a `memory.init` // expression. BINARYEN_API void BinaryenMemoryInitSetSegment(BinaryenExpressionRef expr, - uint32_t segmentIndex); + const char* segment); // Gets the destination expression of a `memory.init` expression. BINARYEN_API BinaryenExpressionRef BinaryenMemoryInitGetDest(BinaryenExpressionRef expr); @@ -2058,10 +2059,10 @@ BINARYEN_API void BinaryenMemoryInitSetSize(BinaryenExpressionRef expr, // DataDrop // Gets the index of the segment being dropped by a `data.drop` expression. -BINARYEN_API uint32_t BinaryenDataDropGetSegment(BinaryenExpressionRef expr); +BINARYEN_API const char* BinaryenDataDropGetSegment(BinaryenExpressionRef expr); // Sets the index of the segment being dropped by a `data.drop` expression. BINARYEN_API void BinaryenDataDropSetSegment(BinaryenExpressionRef expr, - uint32_t segmentIndex); + const char* segment); // MemoryCopy diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index d292529dc..05faf7b1e 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -903,7 +903,7 @@ struct InfoCollector return; } case NewElem: { - Type segType = getModule()->elementSegments[curr->segment]->type; + Type segType = getModule()->getElementSegment(curr->segment)->type; addRoot(DataLocation{heapType, 0}, PossibleContents::fromType(segType)); return; } diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index 50cac2a1c..35f5d9a5c 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -758,7 +758,7 @@ function wrapModule(module, self = {}) { return Module['_BinaryenMemoryGrow'](module, value, strToStack(name), memory64); }, 'init'(segment, dest, offset, size, name) { - return Module['_BinaryenMemoryInit'](module, segment, dest, offset, size, strToStack(name)); + return preserveStack(() => Module['_BinaryenMemoryInit'](module, strToStack(segment), dest, offset, size, strToStack(name))); }, 'copy'(dest, source, size, destMemory, sourceMemory) { return Module['_BinaryenMemoryCopy'](module, dest, source, size, strToStack(destMemory), strToStack(sourceMemory)); @@ -781,7 +781,7 @@ function wrapModule(module, self = {}) { self['data'] = { 'drop'(segment) { - return Module['_BinaryenDataDrop'](module, segment); + return preserveStack(() => Module['_BinaryenDataDrop'](module, strToStack(segment))); } } @@ -3172,7 +3172,7 @@ Module['getExpressionInfo'] = function(expr) { case Module['MemoryInitId']: return { 'id': id, - 'segment': Module['_BinaryenMemoryInitGetSegment'](expr), + 'segment': UTF8ToString(Module['_BinaryenMemoryInitGetSegment'](expr)), 'dest': Module['_BinaryenMemoryInitGetDest'](expr), 'offset': Module['_BinaryenMemoryInitGetOffset'](expr), 'size': Module['_BinaryenMemoryInitGetSize'](expr) @@ -3180,7 +3180,7 @@ Module['getExpressionInfo'] = function(expr) { case Module['DataDropId']: return { 'id': id, - 'segment': Module['_BinaryenDataDropGetSegment'](expr), + 'segment': UTF8ToString(Module['_BinaryenDataDropGetSegment'](expr)), }; case Module['MemoryCopyId']: return { @@ -4543,10 +4543,10 @@ Module['SIMDLoadStoreLane'] = makeExpressionWrapper({ Module['MemoryInit'] = makeExpressionWrapper({ 'getSegment'(expr) { - return Module['_BinaryenMemoryInitGetSegment'](expr); + return UTF8ToString(Module['_BinaryenMemoryInitGetSegment'](expr)); }, - 'setSegment'(expr, segmentIndex) { - Module['_BinaryenMemoryInitSetSegment'](expr, segmentIndex); + 'setSegment'(expr, segment) { + preserveStack(() => Module['_BinaryenMemoryInitSetSegment'](expr, strToStack(segment))); }, 'getDest'(expr) { return Module['_BinaryenMemoryInitGetDest'](expr); @@ -4570,10 +4570,10 @@ Module['MemoryInit'] = makeExpressionWrapper({ Module['DataDrop'] = makeExpressionWrapper({ 'getSegment'(expr) { - return Module['_BinaryenDataDropGetSegment'](expr); + return UTF8ToString(Module['_BinaryenDataDropGetSegment'](expr)); }, - 'setSegment'(expr, segmentIndex) { - Module['_BinaryenDataDropSetSegment'](expr, segmentIndex); + 'setSegment'(expr, segment) { + preserveStack(() => Module['_BinaryenDataDropSetSegment'](expr, strToStack(segment))); } }); diff --git a/src/passes/MemoryPacking.cpp b/src/passes/MemoryPacking.cpp index 7beed9a16..608bc1af2 100644 --- a/src/passes/MemoryPacking.cpp +++ b/src/passes/MemoryPacking.cpp @@ -69,7 +69,7 @@ using Replacements = std::unordered_map<Expression*, Replacement>; using Referrers = std::vector<Expression*>; // Map segment indices to referrers. -using ReferrersMap = std::unordered_map<Index, Referrers>; +using ReferrersMap = std::unordered_map<Name, Referrers>; // memory.init: 2 byte opcode + 1 byte segment index + 1 byte memory index + // 3 x 2 byte operands @@ -119,9 +119,9 @@ struct MemoryPacking : public Pass { size_t segmentsRemaining); void createReplacements(Module* module, const std::vector<Range>& ranges, + const std::vector<Name>& segments, const Referrers& referrers, - Replacements& replacements, - const Index segmentIndex); + Replacements& replacements); void replaceSegmentOps(Module* module, Replacements& replacements); }; @@ -155,9 +155,9 @@ void MemoryPacking::run(Module* module) { Replacements replacements; Builder builder(*module); - for (size_t origIndex = 0; origIndex < segments.size(); ++origIndex) { - auto& segment = segments[origIndex]; - auto& currReferrers = referrers[origIndex]; + for (size_t index = 0; index < segments.size(); ++index) { + auto& segment = segments[index]; + auto& currReferrers = referrers[segment->name]; std::vector<Range> ranges; @@ -169,12 +169,16 @@ void MemoryPacking::run(Module* module) { ranges.push_back({false, 0, segment->data.size()}); } - Index firstNewIndex = packed.size(); - size_t segmentsRemaining = segments.size() - origIndex; + size_t segmentsRemaining = segments.size() - index; + size_t currSegmentsStart = packed.size(); createSplitSegments( builder, segment.get(), ranges, packed, segmentsRemaining); + std::vector<Name> currSegmentNames; + for (size_t i = currSegmentsStart; i < packed.size(); ++i) { + currSegmentNames.push_back(packed[i]->name); + } createReplacements( - module, ranges, currReferrers, replacements, firstNewIndex); + module, ranges, currSegmentNames, currReferrers, replacements); } segments.swap(packed); @@ -394,7 +398,7 @@ void MemoryPacking::optimizeSegmentOps(Module* module) { void visitMemoryInit(MemoryInit* curr) { Builder builder(*getModule()); - auto& segment = getModule()->dataSegments[curr->segment]; + auto* segment = getModule()->getDataSegment(curr->segment); size_t maxRuntimeSize = segment->isPassive ? segment->data.size() : 0; bool mustNop = false; bool mustTrap = false; @@ -439,7 +443,7 @@ void MemoryPacking::optimizeSegmentOps(Module* module) { } } void visitDataDrop(DataDrop* curr) { - if (!getModule()->dataSegments[curr->segment]->isPassive) { + if (!getModule()->getDataSegment(curr->segment)->isPassive) { ExpressionManipulator::nop(curr); } } @@ -496,12 +500,11 @@ void MemoryPacking::dropUnusedSegments( std::vector<std::unique_ptr<DataSegment>>& segments, ReferrersMap& referrers) { std::vector<std::unique_ptr<DataSegment>> usedSegments; - ReferrersMap usedReferrers; // Remove segments that are never used // TODO: remove unused portions of partially used segments as well for (size_t i = 0; i < segments.size(); ++i) { bool used = false; - auto referrersIt = referrers.find(i); + auto referrersIt = referrers.find(segments[i]->name); bool hasReferrers = referrersIt != referrers.end(); if (segments[i]->isPassive) { if (hasReferrers) { @@ -518,9 +521,6 @@ void MemoryPacking::dropUnusedSegments( } if (used) { usedSegments.push_back(std::move(segments[i])); - if (hasReferrers) { - usedReferrers[usedSegments.size() - 1] = std::move(referrersIt->second); - } } else if (hasReferrers) { // All referrers are data.drops. Make them nops. for (auto* referrer : referrersIt->second) { @@ -530,7 +530,6 @@ void MemoryPacking::dropUnusedSegments( } std::swap(segments, usedSegments); module->updateDataSegmentsMap(); - std::swap(referrers, usedReferrers); } void MemoryPacking::createSplitSegments( @@ -596,25 +595,11 @@ void MemoryPacking::createSplitSegments( void MemoryPacking::createReplacements(Module* module, const std::vector<Range>& ranges, + const std::vector<Name>& segments, const Referrers& referrers, - Replacements& replacements, - const Index segmentIndex) { - // If there was no transformation, only update the indices + Replacements& replacements) { + // If there was no transformation, we do not need to do anything. if (ranges.size() == 1 && !ranges.front().isZero) { - for (auto referrer : referrers) { - replacements[referrer] = [referrer, segmentIndex](Function*) { - if (auto* curr = referrer->dynCast<MemoryInit>()) { - curr->segment = segmentIndex; - } else if (auto* curr = referrer->dynCast<DataDrop>()) { - curr->segment = segmentIndex; - } else if (auto* curr = referrer->dynCast<ArrayNewSeg>()) { - curr->segment = segmentIndex; - } else { - WASM_UNREACHABLE("Unexpected segment operation"); - } - return referrer; - }; - } return; } @@ -649,8 +634,9 @@ void MemoryPacking::createReplacements(Module* module, size_t start = init->offset->cast<Const>()->value.geti32(); size_t end = start + init->size->cast<Const>()->value.geti32(); - // Segment index used in emitted memory.init instructions - size_t initIndex = segmentIndex; + // Index in `segments` of the segment used in emitted memory.init + // instructions + size_t initIndex = 0; // Index of the range from which this memory.init starts reading size_t firstRangeIdx = 0; @@ -742,8 +728,8 @@ void MemoryPacking::createReplacements(Module* module, size_t offsetBytes = std::max(start, range.start) - range.start; Expression* offset = builder.makeConst(int32_t(offsetBytes)); Expression* size = builder.makeConst(int32_t(bytes)); - appendResult( - builder.makeMemoryInit(initIndex, dest, offset, size, init->memory)); + appendResult(builder.makeMemoryInit( + segments[initIndex], dest, offset, size, init->memory)); initIndex++; } } @@ -779,10 +765,10 @@ void MemoryPacking::createReplacements(Module* module, appendResult( builder.makeGlobalSet(dropStateGlobal, builder.makeConst(int32_t(1)))); } - size_t dropIndex = segmentIndex; + size_t dropIndex = 0; for (auto range : ranges) { if (!range.isZero) { - appendResult(builder.makeDataDrop(dropIndex++)); + appendResult(builder.makeDataDrop(segments[dropIndex++])); } } replacements[drop] = [result, module](Function*) { @@ -807,22 +793,25 @@ void MemoryPacking::replaceSegmentOps(Module* module, } void visitMemoryInit(MemoryInit* curr) { - auto replacement = replacements.find(curr); - assert(replacement != replacements.end()); - replaceCurrent(replacement->second(getFunction())); + if (auto replacement = replacements.find(curr); + replacement != replacements.end()) { + replaceCurrent(replacement->second(getFunction())); + } } void visitDataDrop(DataDrop* curr) { - auto replacement = replacements.find(curr); - assert(replacement != replacements.end()); - replaceCurrent(replacement->second(getFunction())); + if (auto replacement = replacements.find(curr); + replacement != replacements.end()) { + replaceCurrent(replacement->second(getFunction())); + } } void visitArrayNewSeg(ArrayNewSeg* curr) { if (curr->op == NewData) { - auto replacement = replacements.find(curr); - assert(replacement != replacements.end()); - replaceCurrent(replacement->second(getFunction())); + if (auto replacement = replacements.find(curr); + replacement != replacements.end()) { + replaceCurrent(replacement->second(getFunction())); + } } } } replacer(replacements); diff --git a/src/passes/MultiMemoryLowering.cpp b/src/passes/MultiMemoryLowering.cpp index 08e1622d5..f0a4be112 100644 --- a/src/passes/MultiMemoryLowering.cpp +++ b/src/passes/MultiMemoryLowering.cpp @@ -181,7 +181,7 @@ struct MultiMemoryLowering : public Pass { Expression* makeDataSegmentBoundsCheck(MemoryInit* curr, Index sizeIdx, Index offsetIdx) { - auto& segment = parent.wasm->dataSegments[curr->segment]; + auto* segment = parent.wasm->getDataSegment(curr->segment); Expression* addGtuTrap = makeAddGtuTrap( builder.makeLocalGet(offsetIdx, parent.pointerType), builder.makeLocalGet(sizeIdx, parent.pointerType), diff --git a/src/passes/PostEmscripten.cpp b/src/passes/PostEmscripten.cpp index ea4922e3a..b569cd0e0 100644 --- a/src/passes/PostEmscripten.cpp +++ b/src/passes/PostEmscripten.cpp @@ -42,7 +42,7 @@ static bool isInvoke(Function* F) { } struct SegmentRemover : WalkerPass<PostWalker<SegmentRemover>> { - SegmentRemover(Index segment) : segment(segment) {} + SegmentRemover(Name segment) : segment(segment) {} bool isFunctionParallel() override { return true; } @@ -66,19 +66,19 @@ struct SegmentRemover : WalkerPass<PostWalker<SegmentRemover>> { } } - Index segment; + Name segment; }; static void calcSegmentOffsets(Module& wasm, std::vector<Address>& segmentOffsets) { const Address UNKNOWN_OFFSET(uint32_t(-1)); - std::unordered_map<Index, Address> passiveOffsets; + std::unordered_map<Name, Address> passiveOffsets; if (wasm.features.hasBulkMemory()) { // Fetch passive segment offsets out of memory.init instructions struct OffsetSearcher : PostWalker<OffsetSearcher> { - std::unordered_map<Index, Address>& offsets; - OffsetSearcher(std::unordered_map<unsigned, Address>& offsets) + std::unordered_map<Name, Address>& offsets; + OffsetSearcher(std::unordered_map<Name, Address>& offsets) : offsets(offsets) {} void visitMemoryInit(MemoryInit* curr) { // The desitination of the memory.init is either a constant @@ -108,7 +108,7 @@ static void calcSegmentOffsets(Module& wasm, for (unsigned i = 0; i < wasm.dataSegments.size(); ++i) { auto& segment = wasm.dataSegments[i]; if (segment->isPassive) { - auto it = passiveOffsets.find(i); + auto it = passiveOffsets.find(segment->name); if (it != passiveOffsets.end()) { segmentOffsets.push_back(it->second); } else { @@ -126,13 +126,11 @@ static void calcSegmentOffsets(Module& wasm, } } -static void removeSegment(Module& wasm, Index segment) { +static void removeSegment(Module& wasm, Name segment) { PassRunner runner(&wasm); SegmentRemover(segment).run(&runner, &wasm); - // Resize the segment to zero. In theory we should completely remove it - // but that would mean re-numbering the segments that follow which is - // non-trivial. - wasm.dataSegments[segment]->data.resize(0); + // Resize the segment to zero. TODO: Remove it entirely instead. + wasm.getDataSegment(segment)->data.resize(0); } static Address getExportedAddress(Module& wasm, Export* export_) { @@ -160,21 +158,21 @@ static void removeData(Module& wasm, Address startAddress = getExportedAddress(wasm, start); Address endAddress = getExportedAddress(wasm, end); for (Index i = 0; i < wasm.dataSegments.size(); i++) { + auto& segment = wasm.dataSegments[i]; Address segmentStart = segmentOffsets[i]; - size_t segmentSize = wasm.dataSegments[i]->data.size(); + size_t segmentSize = segment->data.size(); if (segmentStart <= startAddress && segmentStart + segmentSize >= endAddress) { - if (segmentStart == startAddress && segmentStart + segmentSize == endAddress) { BYN_TRACE("removeData: removing whole segment\n"); - removeSegment(wasm, i); + removeSegment(wasm, segment->name); } else { // If we can't remove the whole segment then just set the string // data to zero. BYN_TRACE("removeData: removing part of segment\n"); size_t segmentOffset = startAddress - segmentStart; - char* startElem = &wasm.dataSegments[i]->data[segmentOffset]; + char* startElem = &segment->data[segmentOffset]; memset(startElem, 0, endAddress - startAddress); } return; diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index c9a717058..9f765bb79 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -929,13 +929,13 @@ struct PrintExpressionContents o << "memory.init"; restoreNormalColor(o); printMemoryName(curr->memory, o, wasm); - o << ' ' << curr->segment; + o << " $" << curr->segment; } void visitDataDrop(DataDrop* curr) { prepareColor(o); o << "data.drop"; restoreNormalColor(o); - o << ' ' << curr->segment; + o << " $" << curr->segment; } void visitMemoryCopy(MemoryCopy* curr) { prepareColor(o); @@ -2283,7 +2283,7 @@ struct PrintExpressionContents } o << ' '; TypeNamePrinter(o, wasm).print(curr->type.getHeapType()); - o << ' ' << curr->segment; + o << " $" << curr->segment; } void visitArrayNewFixed(ArrayNewFixed* curr) { if (printUnreachableReplacement(curr)) { @@ -3246,13 +3246,8 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { doIndent(o, indent); o << '('; - printMedium(o, "elem"); - // If there is no explicit name, and there are multiple segments, use our - // internal names to differentiate them. - if (curr->hasExplicitName || currModule->elementSegments.size() > 1) { - o << ' '; - printName(curr->name, o); - } + printMedium(o, "elem "); + printName(curr->name, o); if (curr->table.is()) { if (usesExpressions || currModule->tables.size() > 1) { @@ -3325,10 +3320,8 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { doIndent(o, indent); o << '('; printMajor(o, "data "); - if (curr->hasExplicitName) { - printName(curr->name, o); - o << ' '; - } + printName(curr->name, o); + o << ' '; if (!curr->isPassive) { assert(!currModule || currModule->memories.size() > 0); if (!currModule || curr->memory != currModule->memories[0]->name) { diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp index 103be5e4a..8b9ed2a78 100644 --- a/src/passes/RemoveUnusedModuleElements.cpp +++ b/src/passes/RemoveUnusedModuleElements.cpp @@ -180,8 +180,7 @@ struct ReferenceFinder : public PostWalker<ReferenceFinder> { usesMemory = true; return; case NewElem: - auto segment = getModule()->elementSegments[curr->segment]->name; - note({ModuleElementKind::ElementSegment, segment}); + note({ModuleElementKind::ElementSegment, curr->segment}); return; } WASM_UNREACHABLE("unexpected op"); diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 0a4f8e581..4a611345d 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -202,7 +202,8 @@ void TranslateToFuzzReader::setupMemory() { size_t numSegments = upTo(8) + 1; for (size_t i = 0; i < numSegments; i++) { auto segment = builder.makeDataSegment(); - segment->setName(Name::fromInt(i), false); + segment->setName(Names::getValidDataSegmentName(wasm, Name::fromInt(i)), + false); segment->isPassive = bool(upTo(2)); size_t segSize = upTo(USABLE_MEMORY * 2); segment->data.resize(segSize); @@ -214,7 +215,7 @@ void TranslateToFuzzReader::setupMemory() { memCovered += segSize; segment->memory = wasm.memories[0]->name; } - wasm.dataSegments.push_back(std::move(segment)); + wasm.addDataSegment(std::move(segment)); } } else { // init some data @@ -3196,8 +3197,9 @@ Expression* TranslateToFuzzReader::makeMemoryInit() { if (!allowMemory) { return makeTrivial(Type::none); } - uint32_t segment = upTo(wasm.dataSegments.size()); - size_t totalSize = wasm.dataSegments[segment]->data.size(); + Index segIdx = upTo(wasm.dataSegments.size()); + Name segment = wasm.dataSegments[segIdx]->name; + size_t totalSize = wasm.dataSegments[segIdx]->data.size(); size_t offsetVal = upTo(totalSize); size_t sizeVal = upTo(totalSize - offsetVal); Expression* dest = makePointer(); @@ -3211,7 +3213,9 @@ Expression* TranslateToFuzzReader::makeDataDrop() { if (!allowMemory) { return makeTrivial(Type::none); } - return builder.makeDataDrop(upTo(wasm.dataSegments.size())); + Index segIdx = upTo(wasm.dataSegments.size()); + Name segment = wasm.dataSegments[segIdx]->name; + return builder.makeDataDrop(segment); } Expression* TranslateToFuzzReader::makeMemoryCopy() { diff --git a/src/wasm-binary.h b/src/wasm-binary.h index e6092fbc9..4f224e1dd 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1325,6 +1325,8 @@ public: uint32_t getMemoryIndex(Name name) const; uint32_t getGlobalIndex(Name name) const; uint32_t getTagIndex(Name name) const; + uint32_t getDataSegmentIndex(Name name) const; + uint32_t getElementSegmentIndex(Name name) const; uint32_t getTypeIndex(HeapType type) const; uint32_t getStringIndex(Name string) const; @@ -1506,6 +1508,8 @@ public: Name getMemoryName(Index index); Name getGlobalName(Index index); Name getTagName(Index index); + Name getDataName(Index index); + Name getElemName(Index index); // gets a memory in the combined import+defined space Memory* getMemory(Index index); @@ -1556,6 +1560,12 @@ public: // at index i we have all refs to the tag i std::map<Index, std::vector<Name*>> tagRefs; + // at index i we have all refs to the data segment i + std::map<Index, std::vector<Name*>> dataRefs; + + // at index i we have all refs to the element segment i + std::map<Index, std::vector<Name*>> elemRefs; + // Throws a parsing error if we are not in a function context void requireFunctionContext(const char* error); diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 73803e37d..dbddb248b 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -569,7 +569,7 @@ public: ret->memory = memory; return ret; } - MemoryInit* makeMemoryInit(uint32_t segment, + MemoryInit* makeMemoryInit(Name segment, Expression* dest, Expression* offset, Expression* size, @@ -583,7 +583,7 @@ public: ret->finalize(); return ret; } - DataDrop* makeDataDrop(uint32_t segment) { + DataDrop* makeDataDrop(Name segment) { auto* ret = wasm.allocator.alloc<DataDrop>(); ret->segment = segment; ret->finalize(); @@ -930,7 +930,7 @@ public: } ArrayNewSeg* makeArrayNewSeg(ArrayNewSegOp op, HeapType type, - Index seg, + Name seg, Expression* offset, Expression* size) { auto* ret = wasm.allocator.alloc<ArrayNewSeg>(); diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index 92ab4c9d3..480789ca3 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -400,14 +400,14 @@ switch (DELEGATE_ID) { DELEGATE_FIELD_CHILD(MemoryInit, size); DELEGATE_FIELD_CHILD(MemoryInit, offset); DELEGATE_FIELD_CHILD(MemoryInit, dest); - DELEGATE_FIELD_INT(MemoryInit, segment); + DELEGATE_FIELD_NAME(MemoryInit, segment); DELEGATE_FIELD_NAME(MemoryInit, memory); DELEGATE_END(MemoryInit); break; } case Expression::Id::DataDropId: { DELEGATE_START(DataDrop); - DELEGATE_FIELD_INT(DataDrop, segment); + DELEGATE_FIELD_NAME(DataDrop, segment); DELEGATE_END(DataDrop); break; } @@ -666,7 +666,7 @@ switch (DELEGATE_ID) { case Expression::Id::ArrayNewSegId: { DELEGATE_START(ArrayNewSeg); DELEGATE_FIELD_INT(ArrayNewSeg, op); - DELEGATE_FIELD_INT(ArrayNewSeg, segment); + DELEGATE_FIELD_NAME(ArrayNewSeg, segment); DELEGATE_FIELD_CHILD(ArrayNewSeg, size); DELEGATE_FIELD_CHILD(ArrayNewSeg, offset); DELEGATE_END(ArrayNewSeg); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 75f2a8338..4b7d652b4 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2552,7 +2552,7 @@ private: // stack traces. std::vector<Name> functionStack; - std::unordered_set<size_t> droppedSegments; + std::unordered_set<Name> droppedSegments; struct TableInterfaceInfo { // The external interface in which the table is defined. @@ -2642,14 +2642,14 @@ private: MemoryInit init; init.memory = segment->memory; - init.segment = i; + init.segment = segment->name; init.dest = segment->offset; init.offset = &offset; init.size = &size; init.finalize(); DataDrop drop; - drop.segment = i; + drop.segment = segment->name; drop.finalize(); self()->visit(&init); @@ -3397,8 +3397,7 @@ public: NOTE_EVAL1(offset); NOTE_EVAL1(size); - assert(curr->segment < wasm.dataSegments.size()); - auto& segment = wasm.dataSegments[curr->segment]; + auto* segment = wasm.getDataSegment(curr->segment); Address destVal(dest.getSingleValue().getUnsigned()); Address offsetVal(uint32_t(offset.getSingleValue().geti32())); @@ -3543,9 +3542,8 @@ public: switch (curr->op) { case NewData: { - assert(curr->segment < wasm.dataSegments.size()); assert(elemType.isNumber()); - const auto& seg = *wasm.dataSegments[curr->segment]; + const auto& seg = *wasm.getDataSegment(curr->segment); auto elemBytes = element.getByteSize(); auto end = offset + size * elemBytes; if ((size != 0ull && droppedSegments.count(curr->segment)) || @@ -3560,8 +3558,7 @@ public: break; } case NewElem: { - assert(curr->segment < wasm.elementSegments.size()); - const auto& seg = *wasm.elementSegments[curr->segment]; + const auto& seg = *wasm.getElementSegment(curr->segment); auto end = offset + size; // TODO: Handle dropped element segments once we support those. if (end > seg.data.size()) { diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index 5692df03d..c684ae58a 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -124,7 +124,9 @@ class SExpressionWasmBuilder { std::vector<Name> functionNames; std::vector<Name> tableNames; + std::vector<Name> elemSegmentNames; std::vector<Name> memoryNames; + std::vector<Name> dataSegmentNames; std::vector<Name> globalNames; std::vector<Name> tagNames; int functionCounter = 0; @@ -170,7 +172,9 @@ private: Name getFunctionName(Element& s); Name getTableName(Element& s); + Name getElemSegmentName(Element& s); Name getMemoryName(Element& s); + Name getDataSegmentName(Element& s); Name getGlobalName(Element& s); Name getTagName(Element& s); void parseStart(Element& s) { wasm.addStart(getFunctionName(*s[1])); } diff --git a/src/wasm.h b/src/wasm.h index 0f188f7b0..d776ec9aa 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1176,7 +1176,7 @@ public: MemoryInit() = default; MemoryInit(MixedArena& allocator) : MemoryInit() {} - Index segment; + Name segment; Expression* dest; Expression* offset; Expression* size; @@ -1190,7 +1190,7 @@ public: DataDrop() = default; DataDrop(MixedArena& allocator) : DataDrop() {} - Index segment; + Name segment; void finalize(); }; @@ -1608,7 +1608,7 @@ public: ArrayNewSeg(MixedArena& allocator) {} ArrayNewSegOp op; - Index segment; + Name segment; Expression* offset; Expression* size; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 7de97eb64..f92f1ae26 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -651,6 +651,18 @@ uint32_t WasmBinaryWriter::getTagIndex(Name name) const { return it->second; } +uint32_t WasmBinaryWriter::getDataSegmentIndex(Name name) const { + auto it = indexes.dataIndexes.find(name); + assert(it != indexes.dataIndexes.end()); + return it->second; +} + +uint32_t WasmBinaryWriter::getElementSegmentIndex(Name name) const { + auto it = indexes.elemIndexes.find(name); + assert(it != indexes.elemIndexes.end()); + return it->second; +} + uint32_t WasmBinaryWriter::getTypeIndex(HeapType type) const { auto it = indexedTypes.indices.find(type); #ifndef NDEBUG @@ -2304,6 +2316,20 @@ Name WasmBinaryBuilder::getTagName(Index index) { return wasm.tags[index]->name; } +Name WasmBinaryBuilder::getDataName(Index index) { + if (index >= wasm.dataSegments.size()) { + throwError("invalid data segment index"); + } + return wasm.dataSegments[index]->name; +} + +Name WasmBinaryBuilder::getElemName(Index index) { + if (index >= wasm.elementSegments.size()) { + throwError("invalid element segment index"); + } + return wasm.elementSegments[index]->name; +} + Memory* WasmBinaryBuilder::getMemory(Index index) { if (index < wasm.memories.size()) { return wasm.memories[index].get(); @@ -3115,6 +3141,16 @@ void WasmBinaryBuilder::processNames() { *ref = getTagName(index); } } + for (auto& [index, refs] : dataRefs) { + for (auto* ref : refs) { + *ref = getDataName(index); + } + } + for (auto& [index, refs] : elemRefs) { + for (auto* ref : refs) { + *ref = getElemName(index); + } + } // Everything now has its proper name. @@ -5190,10 +5226,11 @@ bool WasmBinaryBuilder::maybeVisitMemoryInit(Expression*& out, uint32_t code) { curr->size = popNonVoidExpression(); curr->offset = popNonVoidExpression(); curr->dest = popNonVoidExpression(); - curr->segment = getU32LEB(); + Index segIdx = getU32LEB(); + dataRefs[segIdx].push_back(&curr->segment); Index memIdx = getU32LEB(); - curr->finalize(); memoryRefs[memIdx].push_back(&curr->memory); + curr->finalize(); out = curr; return true; } @@ -5203,7 +5240,8 @@ bool WasmBinaryBuilder::maybeVisitDataDrop(Expression*& out, uint32_t code) { return false; } auto* curr = allocator.alloc<DataDrop>(); - curr->segment = getU32LEB(); + Index segIdx = getU32LEB(); + dataRefs[segIdx].push_back(&curr->segment); curr->finalize(); out = curr; return true; @@ -7080,10 +7118,17 @@ bool WasmBinaryBuilder::maybeVisitArrayNewSeg(Expression*& out, uint32_t code) { code == BinaryConsts::ArrayNewElem) { auto op = code == BinaryConsts::ArrayNewData ? NewData : NewElem; auto heapType = getIndexedHeapType(); - auto seg = getU32LEB(); + auto segIdx = getU32LEB(); auto* size = popNonVoidExpression(); auto* offset = popNonVoidExpression(); - out = Builder(wasm).makeArrayNewSeg(op, heapType, seg, offset, size); + auto* built = + Builder(wasm).makeArrayNewSeg(op, heapType, Name(), offset, size); + if (op == NewData) { + dataRefs[segIdx].push_back(&built->segment); + } else { + elemRefs[segIdx].push_back(&built->segment); + } + out = built; return true; } return false; diff --git a/src/wasm/wasm-emscripten.cpp b/src/wasm/wasm-emscripten.cpp index 9cc8b29f0..aef36d181 100644 --- a/src/wasm/wasm-emscripten.cpp +++ b/src/wasm/wasm-emscripten.cpp @@ -125,12 +125,12 @@ public: private: void calcSegmentOffsets() { - std::unordered_map<Index, Address> passiveOffsets; + std::unordered_map<Name, Address> passiveOffsets; if (wasm.features.hasBulkMemory()) { // Fetch passive segment offsets out of memory.init instructions struct OffsetSearcher : PostWalker<OffsetSearcher> { - std::unordered_map<Index, Address>& offsets; - OffsetSearcher(std::unordered_map<unsigned, Address>& offsets) + std::unordered_map<Name, Address>& offsets; + OffsetSearcher(std::unordered_map<Name, Address>& offsets) : offsets(offsets) {} void visitMemoryInit(MemoryInit* curr) { // The desitination of the memory.init is either a constant @@ -160,7 +160,7 @@ private: for (unsigned i = 0; i < wasm.dataSegments.size(); ++i) { auto& segment = wasm.dataSegments[i]; if (segment->isPassive) { - auto it = passiveOffsets.find(i); + auto it = passiveOffsets.find(segment->name); if (it != passiveOffsets.end()) { segmentOffsets.push_back(it->second); } else { diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 1afdefe87..51df46544 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -510,6 +510,19 @@ Name SExpressionWasmBuilder::getTableName(Element& s) { } } +Name SExpressionWasmBuilder::getElemSegmentName(Element& s) { + if (s.dollared()) { + return s.str(); + } else { + // index + size_t offset = parseIndex(s); + if (offset >= elemSegmentNames.size()) { + throw ParseException("unknown elem segment", s.line, s.col); + } + return elemSegmentNames[offset]; + } +} + bool SExpressionWasmBuilder::isMemory64(Name memoryName) { auto* memory = wasm.getMemoryOrNull(memoryName); if (!memory) { @@ -535,6 +548,19 @@ Name SExpressionWasmBuilder::getMemoryName(Element& s) { } } +Name SExpressionWasmBuilder::getDataSegmentName(Element& s) { + if (s.dollared()) { + return s.str(); + } else { + // index + size_t offset = parseIndex(s); + if (offset >= dataSegmentNames.size()) { + throw ParseException("unknown data segment", s.line, s.col); + } + return dataSegmentNames[offset]; + } +} + Name SExpressionWasmBuilder::getGlobalName(Element& s) { if (s.dollared()) { return s.str(); @@ -2289,7 +2315,7 @@ Expression* SExpressionWasmBuilder::makeMemoryInit(Element& s) { memory = getMemoryNameAtIdx(0); } ret->memory = memory; - ret->segment = parseIndex(*s[i++]); + ret->segment = getDataSegmentName(*s[i++]); ret->dest = parseExpression(s[i++]); ret->offset = parseExpression(s[i++]); ret->size = parseExpression(s[i]); @@ -2299,7 +2325,7 @@ Expression* SExpressionWasmBuilder::makeMemoryInit(Element& s) { Expression* SExpressionWasmBuilder::makeDataDrop(Element& s) { auto ret = allocator.alloc<DataDrop>(); - ret->segment = parseIndex(*s[1]); + ret->segment = getDataSegmentName(*s[1]); ret->finalize(); return ret; } @@ -2951,7 +2977,8 @@ Expression* SExpressionWasmBuilder::makeArrayNew(Element& s, bool default_) { Expression* SExpressionWasmBuilder::makeArrayNewSeg(Element& s, ArrayNewSegOp op) { auto heapType = parseHeapType(*s[1]); - Index seg = parseIndex(*s[2]); + Name seg = + op == NewData ? getDataSegmentName(*s[2]) : getElemSegmentName(*s[2]); Expression* offset = parseExpression(*s[3]); Expression* size = parseExpression(*s[4]); return Builder(wasm).makeArrayNewSeg(op, heapType, seg, offset, size); @@ -3312,8 +3339,9 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) { } else { offset->set(Literal(int32_t(0))); } - auto seg = Builder::makeDataSegment( - Name::fromInt(dataCounter++), memory->name, false, offset); + auto segName = Name::fromInt(dataCounter++); + auto seg = Builder::makeDataSegment(segName, memory->name, false, offset); + dataSegmentNames.push_back(segName); parseInnerData(inner, j, seg); memory->initial = seg->data.size(); wasm.addDataSegment(std::move(seg)); @@ -3358,6 +3386,7 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) { data.data(), data.size()); segment->hasExplicitName = false; + dataSegmentNames.push_back(segment->name); wasm.addDataSegment(std::move(segment)); } else { auto segment = Builder::makeDataSegment( @@ -3382,6 +3411,7 @@ void SExpressionWasmBuilder::parseData(Element& s) { name = s[i++]->str(); hasExplicitName = true; } + dataSegmentNames.push_back(name); if (s[i]->isList()) { // Optional (memory <memoryidx>) @@ -3764,6 +3794,7 @@ void SExpressionWasmBuilder::parseElem(Element& s, Table* table) { Expression* offset = allocator.alloc<Const>()->set(Literal(int32_t(0))); auto segment = std::make_unique<ElementSegment>(table->name, offset); segment->setName(name, hasExplicitName); + elemSegmentNames.push_back(name); parseElemFinish(s, segment, i, s[i]->isList()); return; } @@ -3772,6 +3803,7 @@ void SExpressionWasmBuilder::parseElem(Element& s, Table* table) { name = s[i++]->str(); hasExplicitName = true; } + elemSegmentNames.push_back(name); if (s[i]->isStr() && s[i]->str() == DECLARE) { // We don't store declared segments in the IR return; diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 1d4e28116..9e22efc0c 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -687,26 +687,27 @@ void BinaryInstWriter::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) { void BinaryInstWriter::visitMemoryInit(MemoryInit* curr) { o << int8_t(BinaryConsts::MiscPrefix); o << U32LEB(BinaryConsts::MemoryInit); - o << U32LEB(curr->segment) << int8_t(parent.getMemoryIndex(curr->memory)); + o << U32LEB(parent.getDataSegmentIndex(curr->segment)); + o << U32LEB(parent.getMemoryIndex(curr->memory)); } void BinaryInstWriter::visitDataDrop(DataDrop* curr) { o << int8_t(BinaryConsts::MiscPrefix); o << U32LEB(BinaryConsts::DataDrop); - o << U32LEB(curr->segment); + o << U32LEB(parent.getDataSegmentIndex(curr->segment)); } void BinaryInstWriter::visitMemoryCopy(MemoryCopy* curr) { o << int8_t(BinaryConsts::MiscPrefix); o << U32LEB(BinaryConsts::MemoryCopy); - o << int8_t(parent.getMemoryIndex(curr->destMemory)) - << int8_t(parent.getMemoryIndex(curr->sourceMemory)); + o << U32LEB(parent.getMemoryIndex(curr->destMemory)); + o << U32LEB(parent.getMemoryIndex(curr->sourceMemory)); } void BinaryInstWriter::visitMemoryFill(MemoryFill* curr) { o << int8_t(BinaryConsts::MiscPrefix); o << U32LEB(BinaryConsts::MemoryFill); - o << int8_t(parent.getMemoryIndex(curr->memory)); + o << U32LEB(parent.getMemoryIndex(curr->memory)); } void BinaryInstWriter::visitConst(Const* curr) { @@ -2122,15 +2123,17 @@ void BinaryInstWriter::visitArrayNewSeg(ArrayNewSeg* curr) { switch (curr->op) { case NewData: o << U32LEB(BinaryConsts::ArrayNewData); + parent.writeIndexedHeapType(curr->type.getHeapType()); + o << U32LEB(parent.getDataSegmentIndex(curr->segment)); break; case NewElem: o << U32LEB(BinaryConsts::ArrayNewElem); + parent.writeIndexedHeapType(curr->type.getHeapType()); + o << U32LEB(parent.getElementSegmentIndex(curr->segment)); break; default: WASM_UNREACHABLE("unexpected op"); } - parent.writeIndexedHeapType(curr->type.getHeapType()); - o << U32LEB(curr->segment); } void BinaryInstWriter::visitArrayNewFixed(ArrayNewFixed* curr) { diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 274e1fd1c..d8dba953f 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -1425,9 +1425,9 @@ void FunctionValidator::visitMemoryInit(MemoryInit* curr) { if (!shouldBeTrue(!!memory, curr, "memory.init memory must exist")) { return; } - shouldBeTrue(curr->segment < getModule()->dataSegments.size(), + shouldBeTrue(getModule()->getDataSegmentOrNull(curr->segment), curr, - "memory.init segment index out of bounds"); + "memory.init segment should exist"); } void FunctionValidator::visitDataDrop(DataDrop* curr) { @@ -1442,9 +1442,9 @@ void FunctionValidator::visitDataDrop(DataDrop* curr) { "Memory operations require a memory")) { return; } - shouldBeTrue(curr->segment < getModule()->dataSegments.size(), + shouldBeTrue(getModule()->getDataSegment(curr->segment), curr, - "data.drop segment index out of bounds"); + "data.drop segment should exist"); } void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) { @@ -2722,16 +2722,16 @@ void FunctionValidator::visitArrayNewSeg(ArrayNewSeg* curr) { "array.new_{data, elem} size must be an i32"); switch (curr->op) { case NewData: - if (!shouldBeTrue(curr->segment < getModule()->dataSegments.size(), + if (!shouldBeTrue(getModule()->getDataSegment(curr->segment), curr, - "array.new_data segment index out of bounds")) { + "array.new_data segment should exist")) { return; } break; case NewElem: - if (!shouldBeTrue(curr->segment < getModule()->elementSegments.size(), + if (!shouldBeTrue(getModule()->getElementSegment(curr->segment), curr, - "array.new_elem segment index out of bounds")) { + "array.new_elem segment should exist")) { return; } break; @@ -2762,7 +2762,7 @@ void FunctionValidator::visitArrayNewSeg(ArrayNewSeg* curr) { "array.new_data result element type should be numeric"); break; case NewElem: - shouldBeSubType(getModule()->elementSegments[curr->segment]->type, + shouldBeSubType(getModule()->getElementSegment(curr->segment)->type, elemType, curr, "array.new_elem segment type should be a subtype of the " diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp index 89e913ab5..567502c93 100644 --- a/src/wasm/wat-parser.cpp +++ b/src/wasm/wat-parser.cpp @@ -1284,7 +1284,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { using LocalIdxT = Index; using GlobalIdxT = Name; using MemoryIdxT = Name; - using DataIdxT = uint32_t; + using DataIdxT = Name; using MemargT = Memarg; @@ -1550,20 +1550,18 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { return name; } - Result<uint32_t> getDataFromIdx(uint32_t idx) { + Result<Name> getDataFromIdx(uint32_t idx) { if (idx >= wasm.dataSegments.size()) { return in.err("data index out of bounds"); } - return idx; + return wasm.dataSegments[idx]->name; } - Result<uint32_t> getDataFromName(Name name) { - for (uint32_t i = 0; i < wasm.dataSegments.size(); ++i) { - if (wasm.dataSegments[i]->name == name) { - return i; - } + Result<Name> getDataFromName(Name name) { + if (!wasm.getDataSegmentOrNull(name)) { + return in.err("data $" + name.toString() + " does not exist"); } - return in.err("data $" + name.toString() + " does not exist"); + return name; } Result<TypeUseT> makeTypeUse(Index pos, @@ -1984,7 +1982,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { op, memarg.offset, memarg.align, lane, *ptr, *vec, *m)); } - Result<> makeMemoryInit(Index pos, Name* mem, uint32_t data) { + Result<> makeMemoryInit(Index pos, Name* mem, Name data) { auto m = getMemory(pos, mem); CHECK_ERR(m); auto size = pop(pos); @@ -1996,7 +1994,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { return push(pos, builder.makeMemoryInit(data, *dest, *offset, *size, *m)); } - Result<> makeDataDrop(Index pos, uint32_t data) { + Result<> makeDataDrop(Index pos, Name data) { return push(pos, builder.makeDataDrop(data)); } @@ -2147,7 +2145,7 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { return push(pos, builder.makeArrayNew(type, *size)); } - Result<> makeArrayNewData(Index pos, HeapType type, uint32_t data) { + Result<> makeArrayNewData(Index pos, HeapType type, Name data) { if (!type.isArray()) { return in.err(pos, "expected array type annotation"); } diff --git a/src/wasm2js.h b/src/wasm2js.h index 054f442dc..c86788e5a 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -168,6 +168,9 @@ public: std::string symbolsFile; }; + // Map data segment names to indices. + std::unordered_map<Name, Index> dataIndices; + Wasm2JSBuilder(Flags f, PassOptions options_) : flags(f), options(options_) { // We don't try to model wasm's trapping precisely - if we did, each load // and store would need to do a check. Given that, we can just ignore @@ -191,6 +194,12 @@ public: // JS Ref processFunctionBody(Module* m, Function* func, bool standalone); + Index getDataIndex(Name segment) { + auto it = dataIndices.find(segment); + assert(it != dataIndices.end()); + return it->second; + } + // Get a temp var. IString getTemp(Type type, Function* func) { IString ret; @@ -333,6 +342,11 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) { ElementUtils::iterAllElementFunctionNames( wasm, [&](Name name) { functionsCallableFromOutside.insert(name); }); + // Collect passive data segment indices. + for (Index i = 0; i < wasm->dataSegments.size(); ++i) { + dataIndices[wasm->dataSegments[i]->name] = i; + } + // Ensure the scratch memory helpers. // If later on they aren't needed, we'll clean them up. ABI::wasm2js::ensureHelpers(wasm); @@ -2178,16 +2192,18 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, } Ref visitMemoryInit(MemoryInit* curr) { ABI::wasm2js::ensureHelpers(module, ABI::wasm2js::MEMORY_INIT); - return ValueBuilder::makeCall(ABI::wasm2js::MEMORY_INIT, - ValueBuilder::makeNum(curr->segment), - visit(curr->dest, EXPRESSION_RESULT), - visit(curr->offset, EXPRESSION_RESULT), - visit(curr->size, EXPRESSION_RESULT)); + return ValueBuilder::makeCall( + ABI::wasm2js::MEMORY_INIT, + ValueBuilder::makeNum(parent->getDataIndex(curr->segment)), + visit(curr->dest, EXPRESSION_RESULT), + visit(curr->offset, EXPRESSION_RESULT), + visit(curr->size, EXPRESSION_RESULT)); } Ref visitDataDrop(DataDrop* curr) { ABI::wasm2js::ensureHelpers(module, ABI::wasm2js::DATA_DROP); - return ValueBuilder::makeCall(ABI::wasm2js::DATA_DROP, - ValueBuilder::makeNum(curr->segment)); + return ValueBuilder::makeCall( + ABI::wasm2js::DATA_DROP, + ValueBuilder::makeNum(parent->getDataIndex(curr->segment))); } Ref visitMemoryCopy(MemoryCopy* curr) { ABI::wasm2js::ensureHelpers(module, ABI::wasm2js::MEMORY_COPY); |