diff options
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); |