summaryrefslogtreecommitdiff
path: root/src/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm')
-rw-r--r--src/wasm/wasm-binary.cpp273
-rw-r--r--src/wasm/wasm-debug.cpp3
-rw-r--r--src/wasm/wasm-s-parser.cpp356
-rw-r--r--src/wasm/wasm-stack.cpp46
-rw-r--r--src/wasm/wasm-validator.cpp140
-rw-r--r--src/wasm/wasm.cpp32
6 files changed, 576 insertions, 274 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index e4b942203..7008d185c 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -52,7 +52,7 @@ void WasmBinaryWriter::write() {
writeImports();
writeFunctionSignatures();
writeTableDeclarations();
- writeMemory();
+ writeMemories();
writeTags();
if (wasm->features.hasStrings()) {
writeStrings();
@@ -203,18 +203,21 @@ void WasmBinaryWriter::writeStart() {
finishSection(start);
}
-void WasmBinaryWriter::writeMemory() {
- if (!wasm->memory.exists || wasm->memory.imported()) {
+void WasmBinaryWriter::writeMemories() {
+ if (wasm->memories.empty()) {
return;
}
- BYN_TRACE("== writeMemory\n");
+ BYN_TRACE("== writeMemories\n");
auto start = startSection(BinaryConsts::Section::Memory);
- o << U32LEB(1); // Define 1 memory
- writeResizableLimits(wasm->memory.initial,
- wasm->memory.max,
- wasm->memory.hasMax(),
- wasm->memory.shared,
- wasm->memory.is64());
+ auto num = importInfo->getNumDefinedMemories();
+ o << U32LEB(num);
+ ModuleUtils::iterDefinedMemories(*wasm, [&](Memory* memory) {
+ writeResizableLimits(memory->initial,
+ memory->max,
+ memory->hasMax(),
+ memory->shared,
+ memory->is64());
+ });
finishSection(start);
}
@@ -333,16 +336,16 @@ void WasmBinaryWriter::writeImports() {
o << uint8_t(0); // Reserved 'attribute' field. Always 0.
o << U32LEB(getTypeIndex(tag->sig));
});
- if (wasm->memory.imported()) {
+ ModuleUtils::iterImportedMemories(*wasm, [&](Memory* memory) {
BYN_TRACE("write one memory\n");
- writeImportHeader(&wasm->memory);
+ writeImportHeader(memory);
o << U32LEB(int32_t(ExternalKind::Memory));
- writeResizableLimits(wasm->memory.initial,
- wasm->memory.max,
- wasm->memory.hasMax(),
- wasm->memory.shared,
- wasm->memory.is64());
- }
+ writeResizableLimits(memory->initial,
+ memory->max,
+ memory->hasMax(),
+ memory->shared,
+ memory->is64());
+ });
ModuleUtils::iterImportedTables(*wasm, [&](Table* table) {
BYN_TRACE("write one table\n");
writeImportHeader(table);
@@ -566,8 +569,7 @@ void WasmBinaryWriter::writeExports() {
o << U32LEB(getTableIndex(curr->value));
break;
case ExternalKind::Memory:
- // TODO: fix with multi-memory
- o << U32LEB(0);
+ o << U32LEB(getMemoryIndex(curr->value));
break;
case ExternalKind::Global:
o << U32LEB(getGlobalIndex(curr->value));
@@ -629,6 +631,12 @@ uint32_t WasmBinaryWriter::getTableIndex(Name name) const {
return it->second;
}
+uint32_t WasmBinaryWriter::getMemoryIndex(Name name) const {
+ auto it = indexes.memoryIndexes.find(name);
+ assert(it != indexes.memoryIndexes.end());
+ return it->second;
+}
+
uint32_t WasmBinaryWriter::getGlobalIndex(Name name) const {
auto it = indexes.globalIndexes.find(name);
assert(it != indexes.globalIndexes.end());
@@ -930,12 +938,28 @@ void WasmBinaryWriter::writeNames() {
}
// memory names
- if (wasm->memory.exists && wasm->memory.hasExplicitName) {
- auto substart =
- startSubsection(BinaryConsts::UserSections::Subsection::NameMemory);
- o << U32LEB(1) << U32LEB(0); // currently exactly 1 memory at index 0
- writeEscapedName(wasm->memory.name.str);
- finishSubsection(substart);
+ {
+ std::vector<std::pair<Index, Memory*>> memoriesWithNames;
+ Index checked = 0;
+ auto check = [&](Memory* curr) {
+ if (curr->hasExplicitName) {
+ memoriesWithNames.push_back({checked, curr});
+ }
+ checked++;
+ };
+ ModuleUtils::iterImportedMemories(*wasm, check);
+ ModuleUtils::iterDefinedMemories(*wasm, check);
+ assert(checked == indexes.memoryIndexes.size());
+ if (memoriesWithNames.size() > 0) {
+ auto substart =
+ startSubsection(BinaryConsts::UserSections::Subsection::NameMemory);
+ o << U32LEB(memoriesWithNames.size());
+ for (auto& [index, memory] : memoriesWithNames) {
+ o << U32LEB(index);
+ writeEscapedName(memory->name.str);
+ }
+ finishSubsection(substart);
+ }
}
// global names
@@ -990,7 +1014,7 @@ void WasmBinaryWriter::writeNames() {
}
// data segment names
- if (wasm->memory.exists) {
+ if (!wasm->memories.empty()) {
Index count = 0;
for (auto& seg : wasm->dataSegments) {
if (seg->hasExplicitName) {
@@ -1547,7 +1571,7 @@ void WasmBinaryBuilder::read() {
readStart();
break;
case BinaryConsts::Section::Memory:
- readMemory();
+ readMemories();
break;
case BinaryConsts::Section::Type:
readTypes();
@@ -1761,10 +1785,6 @@ int64_t WasmBinaryBuilder::getS64LEB() {
return ret.value;
}
-uint64_t WasmBinaryBuilder::getUPtrLEB() {
- return wasm.memory.is64() ? getU64LEB() : getU32LEB();
-}
-
bool WasmBinaryBuilder::getBasicType(int32_t code, Type& out) {
switch (code) {
case BinaryConsts::EncodedType::i32:
@@ -1963,24 +1983,20 @@ void WasmBinaryBuilder::readStart() {
startIndex = getU32LEB();
}
-void WasmBinaryBuilder::readMemory() {
- BYN_TRACE("== readMemory\n");
- auto numMemories = getU32LEB();
- if (!numMemories) {
- return;
- }
- if (numMemories != 1) {
- throwError("Must be exactly 1 memory");
- }
- if (wasm.memory.exists) {
- throwError("Memory cannot be both imported and defined");
+void WasmBinaryBuilder::readMemories() {
+ BYN_TRACE("== readMemories\n");
+ auto num = getU32LEB();
+ BYN_TRACE("num: " << num << std::endl);
+ for (size_t i = 0; i < num; i++) {
+ BYN_TRACE("read one\n");
+ auto memory = Builder::makeMemory(Name::fromInt(i));
+ getResizableLimits(memory->initial,
+ memory->max,
+ memory->shared,
+ memory->indexType,
+ Memory::kUnlimitedSize);
+ memories.push_back(std::move(memory));
}
- wasm.memory.exists = true;
- getResizableLimits(wasm.memory.initial,
- wasm.memory.max,
- wasm.memory.shared,
- wasm.memory.indexType,
- Memory::kUnlimitedSize);
}
void WasmBinaryBuilder::readTypes() {
@@ -2171,6 +2187,13 @@ Name WasmBinaryBuilder::getTableName(Index index) {
return wasm.tables[index]->name;
}
+Name WasmBinaryBuilder::getMemoryName(Index index) {
+ if (index >= wasm.memories.size()) {
+ throwError("invalid memory index");
+ }
+ return wasm.memories[index]->name;
+}
+
Name WasmBinaryBuilder::getGlobalName(Index index) {
if (index >= wasm.globals.size()) {
throwError("invalid global index");
@@ -2270,15 +2293,16 @@ void WasmBinaryBuilder::readImports() {
}
case ExternalKind::Memory: {
Name name(std::string("mimport$") + std::to_string(memoryCounter++));
- wasm.memory.module = module;
- wasm.memory.base = base;
- wasm.memory.name = name;
- wasm.memory.exists = true;
- getResizableLimits(wasm.memory.initial,
- wasm.memory.max,
- wasm.memory.shared,
- wasm.memory.indexType,
+ auto memory = builder.makeMemory(name);
+ memory->module = module;
+ memory->base = base;
+ getResizableLimits(memory->initial,
+ memory->max,
+ memory->shared,
+ memory->indexType,
Memory::kUnlimitedSize);
+ memoryImports.push_back(memory.get());
+ wasm.addMemory(std::move(memory));
break;
}
case ExternalKind::Global: {
@@ -2923,6 +2947,9 @@ void WasmBinaryBuilder::processNames() {
for (auto& segment : elementSegments) {
wasm.addElementSegment(std::move(segment));
}
+ for (auto& memory : memories) {
+ wasm.addMemory(std::move(memory));
+ }
for (auto& segment : dataSegments) {
wasm.addDataSegment(std::move(segment));
}
@@ -2943,7 +2970,7 @@ void WasmBinaryBuilder::processNames() {
curr->value = getTableName(index);
break;
case ExternalKind::Memory:
- curr->value = wasm.memory.name;
+ curr->value = getMemoryName(index);
break;
case ExternalKind::Global:
curr->value = getGlobalName(index);
@@ -2969,6 +2996,12 @@ void WasmBinaryBuilder::processNames() {
}
}
+ for (auto& [index, refs] : memoryRefs) {
+ for (auto ref : refs) {
+ *ref = getMemoryName(index);
+ }
+ }
+
for (auto& [index, refs] : globalRefs) {
for (auto* ref : refs) {
*ref = getGlobalName(index);
@@ -2998,12 +3031,21 @@ void WasmBinaryBuilder::readDataSegments() {
}
curr->setName(Name::fromInt(i), false);
curr->isPassive = flags & BinaryConsts::IsPassive;
+ Index memIdx = 0;
if (flags & BinaryConsts::HasIndex) {
- auto memIndex = getU32LEB();
- if (memIndex != 0) {
- throwError("nonzero memory index");
- }
+ memIdx = getU32LEB();
+ }
+ Memory* memory = nullptr;
+ Index numMemoryImports = memoryImports.size();
+ if (memIdx < numMemoryImports) {
+ memory = memoryImports[memIdx];
+ } else if (memIdx - numMemoryImports < memories.size()) {
+ memory = memories[memIdx - numMemoryImports].get();
}
+ if (!memory) {
+ throwError("Memory index out of range while reading data segments.");
+ }
+ curr->memory = memory->name;
if (!curr->isPassive) {
curr->offset = readExpression();
}
@@ -3333,11 +3375,16 @@ void WasmBinaryBuilder::readNames(size_t payloadLen) {
}
} else if (nameType == BinaryConsts::UserSections::Subsection::NameMemory) {
auto num = getU32LEB();
+ NameProcessor processor;
for (size_t i = 0; i < num; i++) {
auto index = getU32LEB();
auto rawName = getInlineString();
- if (index == 0) {
- wasm.memory.setExplicitName(escape(rawName));
+ auto name = processor.process(rawName);
+ auto numMemoryImports = memoryImports.size();
+ if (index < numMemoryImports) {
+ memoryImports[index]->setExplicitName(name);
+ } else if (index - numMemoryImports < memories.size()) {
+ memories[index - numMemoryImports]->setExplicitName(name);
} else {
std::cerr << "warning: memory index out of bounds in name section, "
"memory subsection: "
@@ -3713,18 +3760,12 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
break;
case BinaryConsts::MemorySize: {
auto size = allocator.alloc<MemorySize>();
- if (wasm.memory.is64()) {
- size->make64();
- }
curr = size;
visitMemorySize(size);
break;
}
case BinaryConsts::MemoryGrow: {
auto grow = allocator.alloc<MemoryGrow>();
- if (wasm.memory.is64()) {
- grow->make64();
- }
curr = grow;
visitMemoryGrow(grow);
break;
@@ -4304,13 +4345,39 @@ void WasmBinaryBuilder::visitGlobalSet(GlobalSet* curr) {
curr->finalize();
}
-void WasmBinaryBuilder::readMemoryAccess(Address& alignment, Address& offset) {
+Index WasmBinaryBuilder::readMemoryAccess(Address& alignment, Address& offset) {
auto rawAlignment = getU32LEB();
- if (rawAlignment > 4) {
+ bool hasMemIdx = false;
+ Index memIdx = 0;
+ // Check bit 6 in the alignment to know whether a memory index is present per:
+ // https://github.com/WebAssembly/multi-memory/blob/main/proposals/multi-memory/Overview.md
+ if (rawAlignment & (1 << (6))) {
+ hasMemIdx = true;
+ // Clear the bit before we parse alignment
+ rawAlignment = rawAlignment & ~(1 << 6);
+ }
+
+ if (rawAlignment > 8) {
throwError("Alignment must be of a reasonable size");
}
+
alignment = Bits::pow2(rawAlignment);
- offset = getUPtrLEB();
+ if (hasMemIdx) {
+ memIdx = getU32LEB();
+ }
+ Memory* memory = nullptr;
+ auto numMemoryImports = memoryImports.size();
+ if (memIdx < numMemoryImports) {
+ memory = memoryImports[memIdx];
+ } else if (memIdx - numMemoryImports < memories.size()) {
+ memory = memories[memIdx - numMemoryImports].get();
+ }
+ if (!memory) {
+ throwError("Memory index out of range while reading memory alignment.");
+ }
+ offset = memory->indexType == Type::i32 ? getU32LEB() : getU64LEB();
+
+ return memIdx;
}
bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out,
@@ -4445,7 +4512,8 @@ bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out,
}
curr->isAtomic = isAtomic;
- readMemoryAccess(curr->align, curr->offset);
+ Index memIdx = readMemoryAccess(curr->align, curr->offset);
+ memoryRefs[memIdx].push_back(&curr->memory);
curr->ptr = popNonVoidExpression();
curr->finalize();
out = curr;
@@ -4550,7 +4618,8 @@ bool WasmBinaryBuilder::maybeVisitStore(Expression*& out,
curr->isAtomic = isAtomic;
BYN_TRACE("zz node: Store\n");
- readMemoryAccess(curr->align, curr->offset);
+ Index memIdx = readMemoryAccess(curr->align, curr->offset);
+ memoryRefs[memIdx].push_back(&curr->memory);
curr->value = popNonVoidExpression();
curr->ptr = popNonVoidExpression();
curr->finalize();
@@ -4610,7 +4679,8 @@ bool WasmBinaryBuilder::maybeVisitAtomicRMW(Expression*& out, uint8_t code) {
BYN_TRACE("zz node: AtomicRMW\n");
Address readAlign;
- readMemoryAccess(readAlign, curr->offset);
+ Index memIdx = readMemoryAccess(readAlign, curr->offset);
+ memoryRefs[memIdx].push_back(&curr->memory);
if (readAlign != curr->bytes) {
throwError("Align of AtomicRMW must match size");
}
@@ -4662,7 +4732,8 @@ bool WasmBinaryBuilder::maybeVisitAtomicCmpxchg(Expression*& out,
BYN_TRACE("zz node: AtomicCmpxchg\n");
Address readAlign;
- readMemoryAccess(readAlign, curr->offset);
+ Index memIdx = readMemoryAccess(readAlign, curr->offset);
+ memoryRefs[memIdx].push_back(&curr->memory);
if (readAlign != curr->bytes) {
throwError("Align of AtomicCpxchg must match size");
}
@@ -4697,7 +4768,8 @@ bool WasmBinaryBuilder::maybeVisitAtomicWait(Expression*& out, uint8_t code) {
curr->expected = popNonVoidExpression();
curr->ptr = popNonVoidExpression();
Address readAlign;
- readMemoryAccess(readAlign, curr->offset);
+ Index memIdx = readMemoryAccess(readAlign, curr->offset);
+ memoryRefs[memIdx].push_back(&curr->memory);
if (readAlign != curr->expectedType.getByteSize()) {
throwError("Align of AtomicWait must match size");
}
@@ -4717,7 +4789,8 @@ bool WasmBinaryBuilder::maybeVisitAtomicNotify(Expression*& out, uint8_t code) {
curr->notifyCount = popNonVoidExpression();
curr->ptr = popNonVoidExpression();
Address readAlign;
- readMemoryAccess(readAlign, curr->offset);
+ Index memIdx = readMemoryAccess(readAlign, curr->offset);
+ memoryRefs[memIdx].push_back(&curr->memory);
if (readAlign != curr->type.getByteSize()) {
throwError("Align of AtomicNotify must match size");
}
@@ -5048,10 +5121,9 @@ bool WasmBinaryBuilder::maybeVisitMemoryInit(Expression*& out, uint32_t code) {
curr->offset = popNonVoidExpression();
curr->dest = popNonVoidExpression();
curr->segment = getU32LEB();
- if (getInt8() != 0) {
- throwError("Unexpected nonzero memory index");
- }
+ Index memIdx = getU32LEB();
curr->finalize();
+ memoryRefs[memIdx].push_back(&curr->memory);
out = curr;
return true;
}
@@ -5075,10 +5147,11 @@ bool WasmBinaryBuilder::maybeVisitMemoryCopy(Expression*& out, uint32_t code) {
curr->size = popNonVoidExpression();
curr->source = popNonVoidExpression();
curr->dest = popNonVoidExpression();
- if (getInt8() != 0 || getInt8() != 0) {
- throwError("Unexpected nonzero memory index");
- }
+ Index destIdx = getU32LEB();
+ Index sourceIdx = getU32LEB();
curr->finalize();
+ memoryRefs[destIdx].push_back(&curr->destMemory);
+ memoryRefs[sourceIdx].push_back(&curr->sourceMemory);
out = curr;
return true;
}
@@ -5091,10 +5164,9 @@ bool WasmBinaryBuilder::maybeVisitMemoryFill(Expression*& out, uint32_t code) {
curr->size = popNonVoidExpression();
curr->value = popNonVoidExpression();
curr->dest = popNonVoidExpression();
- if (getInt8() != 0) {
- throwError("Unexpected nonzero memory index");
- }
+ Index memIdx = getU32LEB();
curr->finalize();
+ memoryRefs[memIdx].push_back(&curr->memory);
out = curr;
return true;
}
@@ -6038,7 +6110,8 @@ bool WasmBinaryBuilder::maybeVisitSIMDStore(Expression*& out, uint32_t code) {
auto* curr = allocator.alloc<Store>();
curr->bytes = 16;
curr->valueType = Type::v128;
- readMemoryAccess(curr->align, curr->offset);
+ Index memIdx = readMemoryAccess(curr->align, curr->offset);
+ memoryRefs[memIdx].push_back(&curr->memory);
curr->isAtomic = false;
curr->value = popNonVoidExpression();
curr->ptr = popNonVoidExpression();
@@ -6277,7 +6350,8 @@ bool WasmBinaryBuilder::maybeVisitSIMDLoad(Expression*& out, uint32_t code) {
auto* curr = allocator.alloc<Load>();
curr->type = Type::v128;
curr->bytes = 16;
- readMemoryAccess(curr->align, curr->offset);
+ Index memIdx = readMemoryAccess(curr->align, curr->offset);
+ memoryRefs[memIdx].push_back(&curr->memory);
curr->isAtomic = false;
curr->ptr = popNonVoidExpression();
curr->finalize();
@@ -6337,7 +6411,8 @@ bool WasmBinaryBuilder::maybeVisitSIMDLoad(Expression*& out, uint32_t code) {
default:
return false;
}
- readMemoryAccess(curr->align, curr->offset);
+ Index memIdx = readMemoryAccess(curr->align, curr->offset);
+ memoryRefs[memIdx].push_back(&curr->memory);
curr->ptr = popNonVoidExpression();
curr->finalize();
out = curr;
@@ -6386,7 +6461,8 @@ bool WasmBinaryBuilder::maybeVisitSIMDLoadStoreLane(Expression*& out,
}
auto* curr = allocator.alloc<SIMDLoadStoreLane>();
curr->op = op;
- readMemoryAccess(curr->align, curr->offset);
+ Index memIdx = readMemoryAccess(curr->align, curr->offset);
+ memoryRefs[memIdx].push_back(&curr->memory);
curr->index = getLaneIndex(lanes);
curr->vec = popNonVoidExpression();
curr->ptr = popNonVoidExpression();
@@ -6427,21 +6503,17 @@ void WasmBinaryBuilder::visitReturn(Return* curr) {
void WasmBinaryBuilder::visitMemorySize(MemorySize* curr) {
BYN_TRACE("zz node: MemorySize\n");
- auto reserved = getU32LEB();
- if (reserved != 0) {
- throwError("Invalid reserved field on memory.size");
- }
+ Index memIdx = getU32LEB();
curr->finalize();
+ memoryRefs[memIdx].push_back(&curr->memory);
}
void WasmBinaryBuilder::visitMemoryGrow(MemoryGrow* curr) {
BYN_TRACE("zz node: MemoryGrow\n");
curr->delta = popNonVoidExpression();
- auto reserved = getU32LEB();
- if (reserved != 0) {
- throwError("Invalid reserved field on memory.grow");
- }
+ Index memIdx = getU32LEB();
curr->finalize();
+ memoryRefs[memIdx].push_back(&curr->memory);
}
void WasmBinaryBuilder::visitNop(Nop* curr) { BYN_TRACE("zz node: Nop\n"); }
@@ -7270,7 +7342,6 @@ void WasmBinaryBuilder::visitRefAs(RefAs* curr, uint8_t code) {
}
curr->finalize();
}
-
void WasmBinaryBuilder::throwError(std::string text) {
throw ParseException(text, 0, pos);
}
diff --git a/src/wasm/wasm-debug.cpp b/src/wasm/wasm-debug.cpp
index 23c2dc938..8de691272 100644
--- a/src/wasm/wasm-debug.cpp
+++ b/src/wasm/wasm-debug.cpp
@@ -1065,7 +1065,8 @@ void writeDWARFSections(Module& wasm, const BinaryLocations& newLocations) {
updateDebugLines(data, locationUpdater);
- updateCompileUnits(info, data, locationUpdater, wasm.memory.is64());
+ bool is64 = wasm.memories.size() > 0 ? wasm.memories[0]->is64() : false;
+ updateCompileUnits(info, data, locationUpdater, is64);
updateRanges(data, locationUpdater);
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 382ca741d..55551ef58 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -378,6 +378,7 @@ SExpressionWasmBuilder::SExpressionWasmBuilder(Module& wasm,
auto& s = *module[j];
preParseFunctionType(s);
preParseImports(s);
+ preParseMemory(s);
if (elementStartsWith(s, FUNC) && !isImport(s)) {
implementedFunctions++;
}
@@ -423,20 +424,27 @@ void SExpressionWasmBuilder::preParseImports(Element& curr) {
}
}
+void SExpressionWasmBuilder::preParseMemory(Element& curr) {
+ IString id = curr[0]->str();
+ if (id == MEMORY && !isImport(curr)) {
+ parseMemory(curr);
+ }
+}
+
void SExpressionWasmBuilder::parseModuleElement(Element& curr) {
if (isImport(curr)) {
return; // already done
}
IString id = curr[0]->str();
+ if (id == MEMORY) {
+ return; // already done
+ }
if (id == START) {
return parseStart(curr);
}
if (id == FUNC) {
return parseFunction(curr);
}
- if (id == MEMORY) {
- return parseMemory(curr);
- }
if (id == DATA) {
return parseData(curr);
}
@@ -495,6 +503,31 @@ Name SExpressionWasmBuilder::getTableName(Element& s) {
}
}
+bool SExpressionWasmBuilder::isMemory64(Name memoryName) {
+ auto* memory = wasm.getMemoryOrNull(memoryName);
+ if (!memory) {
+ throw ParseException("invalid memory name in isMemory64");
+ }
+ return memory->is64();
+}
+
+Name SExpressionWasmBuilder::getMemoryNameAtIdx(Index i) {
+ if (i >= memoryNames.size()) {
+ throw ParseException("unknown memory in getMemoryName");
+ }
+ return memoryNames[i];
+}
+
+Name SExpressionWasmBuilder::getMemoryName(Element& s) {
+ if (s.dollared()) {
+ return s.str();
+ } else {
+ // index
+ size_t offset = atoi(s.str().c_str());
+ return getMemoryNameAtIdx(offset);
+ }
+}
+
Name SExpressionWasmBuilder::getGlobalName(Element& s) {
if (s.dollared()) {
return s.str();
@@ -1359,7 +1392,15 @@ Expression* SExpressionWasmBuilder::makeDrop(Element& s) {
Expression* SExpressionWasmBuilder::makeMemorySize(Element& s) {
auto ret = allocator.alloc<MemorySize>();
- if (wasm.memory.is64()) {
+ Index i = 1;
+ Name memory;
+ if (s.size() > 1) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
+ if (isMemory64(memory)) {
ret->make64();
}
ret->finalize();
@@ -1368,10 +1409,18 @@ Expression* SExpressionWasmBuilder::makeMemorySize(Element& s) {
Expression* SExpressionWasmBuilder::makeMemoryGrow(Element& s) {
auto ret = allocator.alloc<MemoryGrow>();
- if (wasm.memory.is64()) {
+ Index i = 1;
+ Name memory;
+ if (s.size() > 2) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
+ if (isMemory64(memory)) {
ret->make64();
}
- ret->delta = parseExpression(s[1]);
+ ret->delta = parseExpression(s[i]);
ret->finalize();
return ret;
}
@@ -1820,11 +1869,11 @@ static uint8_t parseMemBytes(const char*& s, uint8_t fallback) {
return ret;
}
-static size_t parseMemAttributes(Element& s,
+static size_t parseMemAttributes(size_t i,
+ Element& s,
Address& offset,
Address& align,
Address fallbackAlign) {
- size_t i = 1;
offset = 0;
align = fallbackAlign;
// Parse "align=X" and "offset=X" arguments, bailing out on anything else.
@@ -1884,6 +1933,17 @@ static const char* findMemExtra(const Element& s, size_t skip, bool isAtomic) {
return ret;
}
+bool SExpressionWasmBuilder::hasMemoryIdx(Element& s,
+ Index defaultSize,
+ Index i) {
+ if (s.size() > defaultSize && !s[i]->isList() &&
+ strncmp(s[i]->c_str(), "align", 5) != 0 &&
+ strncmp(s[i]->c_str(), "offset", 6) != 0) {
+ return true;
+ }
+ return false;
+}
+
Expression*
SExpressionWasmBuilder::makeLoad(Element& s, Type type, bool isAtomic) {
const char* extra = findMemExtra(*s[0], 5 /* after "type.load" */, isAtomic);
@@ -1892,7 +1952,17 @@ SExpressionWasmBuilder::makeLoad(Element& s, Type type, bool isAtomic) {
ret->type = type;
ret->bytes = parseMemBytes(extra, type.getByteSize());
ret->signed_ = extra[0] && extra[1] == 's';
- size_t i = parseMemAttributes(s, ret->offset, ret->align, ret->bytes);
+ Index i = 1;
+ Name memory;
+ // Check to make sure there are more than the default args & this str isn't
+ // the mem attributes
+ if (hasMemoryIdx(s, 2, i)) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
+ i = parseMemAttributes(i, s, ret->offset, ret->align, ret->bytes);
ret->ptr = parseExpression(s[i]);
ret->finalize();
return ret;
@@ -1905,7 +1975,17 @@ SExpressionWasmBuilder::makeStore(Element& s, Type type, bool isAtomic) {
ret->isAtomic = isAtomic;
ret->valueType = type;
ret->bytes = parseMemBytes(extra, type.getByteSize());
- size_t i = parseMemAttributes(s, ret->offset, ret->align, ret->bytes);
+ Index i = 1;
+ Name memory;
+ // Check to make sure there are more than the default args & this str isn't
+ // the mem attributes
+ if (hasMemoryIdx(s, 3, i)) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
+ i = parseMemAttributes(i, s, ret->offset, ret->align, ret->bytes);
ret->ptr = parseExpression(s[i]);
ret->value = parseExpression(s[i + 1]);
ret->finalize();
@@ -1927,7 +2007,6 @@ Expression* SExpressionWasmBuilder::makeAtomicRMWOrCmpxchg(Element& s,
}
return makeAtomicRMW(s, type, bytes, extra);
}
-
Expression* SExpressionWasmBuilder::makeAtomicRMW(Element& s,
Type type,
uint8_t bytes,
@@ -1950,8 +2029,18 @@ Expression* SExpressionWasmBuilder::makeAtomicRMW(Element& s,
} else {
throw ParseException("bad atomic rmw operator", s.line, s.col);
}
+ Index i = 1;
+ Name memory;
+ // Check to make sure there are more than the default args & this str isn't
+ // the mem attributes
+ if (hasMemoryIdx(s, 3, i)) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
Address align;
- size_t i = parseMemAttributes(s, ret->offset, align, ret->bytes);
+ i = parseMemAttributes(i, s, ret->offset, align, ret->bytes);
if (align != ret->bytes) {
throw ParseException("Align of Atomic RMW must match size", s.line, s.col);
}
@@ -1968,8 +2057,18 @@ Expression* SExpressionWasmBuilder::makeAtomicCmpxchg(Element& s,
auto ret = allocator.alloc<AtomicCmpxchg>();
ret->type = type;
ret->bytes = bytes;
+ Index i = 1;
Address align;
- size_t i = parseMemAttributes(s, ret->offset, align, ret->bytes);
+ Name memory;
+ // Check to make sure there are more than the default args & this str isn't
+ // the mem attributes
+ if (hasMemoryIdx(s, 4, i)) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
+ i = parseMemAttributes(i, s, ret->offset, align, ret->bytes);
if (align != ret->bytes) {
throw ParseException(
"Align of Atomic Cmpxchg must match size", s.line, s.col);
@@ -1994,7 +2093,17 @@ Expression* SExpressionWasmBuilder::makeAtomicWait(Element& s, Type type) {
} else {
WASM_UNREACHABLE("Invalid prefix for memory.atomic.wait");
}
- size_t i = parseMemAttributes(s, ret->offset, align, expectedAlign);
+ Index i = 1;
+ Name memory;
+ // Check to make sure there are more than the default args & this str isn't
+ // the mem attributes
+ if (hasMemoryIdx(s, 4, i)) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
+ i = parseMemAttributes(i, s, ret->offset, align, expectedAlign);
if (align != expectedAlign) {
throw ParseException(
"Align of memory.atomic.wait must match size", s.line, s.col);
@@ -2009,8 +2118,18 @@ Expression* SExpressionWasmBuilder::makeAtomicWait(Element& s, Type type) {
Expression* SExpressionWasmBuilder::makeAtomicNotify(Element& s) {
auto ret = allocator.alloc<AtomicNotify>();
ret->type = Type::i32;
+ Index i = 1;
+ Name memory;
+ // Check to make sure there are more than the default args & this str isn't
+ // the mem attributes
+ if (hasMemoryIdx(s, 3, i)) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
Address align;
- size_t i = parseMemAttributes(s, ret->offset, align, 4);
+ i = parseMemAttributes(i, s, ret->offset, align, 4);
if (align != 4) {
throw ParseException(
"Align of memory.atomic.notify must be 4", s.line, s.col);
@@ -2119,7 +2238,17 @@ Expression* SExpressionWasmBuilder::makeSIMDLoad(Element& s, SIMDLoadOp op) {
defaultAlign = 8;
break;
}
- size_t i = parseMemAttributes(s, ret->offset, ret->align, defaultAlign);
+ Index i = 1;
+ Name memory;
+ // Check to make sure there are more than the default args & this str isn't
+ // the mem attributes
+ if (hasMemoryIdx(s, 2, i)) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
+ i = parseMemAttributes(i, s, ret->offset, ret->align, defaultAlign);
ret->ptr = parseExpression(s[i]);
ret->finalize();
return ret;
@@ -2156,7 +2285,17 @@ SExpressionWasmBuilder::makeSIMDLoadStoreLane(Element& s,
default:
WASM_UNREACHABLE("Unexpected SIMDLoadStoreLane op");
}
- size_t i = parseMemAttributes(s, ret->offset, ret->align, defaultAlign);
+ Index i = 1;
+ Name memory;
+ // Check to make sure there are more than the default args & this str isn't
+ // the mem attributes
+ if (hasMemoryIdx(s, 4, i)) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
+ i = parseMemAttributes(i, s, ret->offset, ret->align, defaultAlign);
ret->index = parseLaneIndex(s[i++], lanes);
ret->ptr = parseExpression(s[i++]);
ret->vec = parseExpression(s[i]);
@@ -2166,10 +2305,18 @@ SExpressionWasmBuilder::makeSIMDLoadStoreLane(Element& s,
Expression* SExpressionWasmBuilder::makeMemoryInit(Element& s) {
auto ret = allocator.alloc<MemoryInit>();
- ret->segment = atoi(s[1]->str().c_str());
- ret->dest = parseExpression(s[2]);
- ret->offset = parseExpression(s[3]);
- ret->size = parseExpression(s[4]);
+ Index i = 1;
+ Name memory;
+ if (s.size() > 5) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
+ ret->segment = atoi(s[i++]->str().c_str());
+ ret->dest = parseExpression(s[i++]);
+ ret->offset = parseExpression(s[i++]);
+ ret->size = parseExpression(s[i]);
ret->finalize();
return ret;
}
@@ -2183,18 +2330,38 @@ Expression* SExpressionWasmBuilder::makeDataDrop(Element& s) {
Expression* SExpressionWasmBuilder::makeMemoryCopy(Element& s) {
auto ret = allocator.alloc<MemoryCopy>();
- ret->dest = parseExpression(s[1]);
- ret->source = parseExpression(s[2]);
- ret->size = parseExpression(s[3]);
+ Index i = 1;
+ Name destMemory;
+ Name sourceMemory;
+ if (s.size() > 4) {
+ destMemory = getMemoryName(*s[i++]);
+ sourceMemory = getMemoryName(*s[i++]);
+ } else {
+ destMemory = getMemoryNameAtIdx(0);
+ sourceMemory = getMemoryNameAtIdx(0);
+ }
+ ret->destMemory = destMemory;
+ ret->sourceMemory = sourceMemory;
+ ret->dest = parseExpression(s[i++]);
+ ret->source = parseExpression(s[i++]);
+ ret->size = parseExpression(s[i]);
ret->finalize();
return ret;
}
Expression* SExpressionWasmBuilder::makeMemoryFill(Element& s) {
auto ret = allocator.alloc<MemoryFill>();
- ret->dest = parseExpression(s[1]);
- ret->value = parseExpression(s[2]);
- ret->size = parseExpression(s[3]);
+ Index i = 1;
+ Name memory;
+ if (s.size() > 4) {
+ memory = getMemoryName(*s[i++]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
+ }
+ ret->memory = memory;
+ ret->dest = parseExpression(s[i++]);
+ ret->value = parseExpression(s[i++]);
+ ret->size = parseExpression(s[i]);
ret->finalize();
return ret;
}
@@ -2995,35 +3162,37 @@ void SExpressionWasmBuilder::stringToBinary(const char* input,
data.resize(actual);
}
-Index SExpressionWasmBuilder::parseMemoryIndex(Element& s, Index i) {
+Index SExpressionWasmBuilder::parseMemoryIndex(
+ Element& s, Index i, std::unique_ptr<Memory>& memory) {
if (i < s.size() && s[i]->isStr()) {
if (s[i]->str() == "i64") {
i++;
- wasm.memory.indexType = Type::i64;
+ memory->indexType = Type::i64;
} else if (s[i]->str() == "i32") {
i++;
- wasm.memory.indexType = Type::i32;
+ memory->indexType = Type::i32;
}
}
return i;
}
-Index SExpressionWasmBuilder::parseMemoryLimits(Element& s, Index i) {
- i = parseMemoryIndex(s, i);
+Index SExpressionWasmBuilder::parseMemoryLimits(
+ Element& s, Index i, std::unique_ptr<Memory>& memory) {
+ i = parseMemoryIndex(s, i, memory);
if (i == s.size()) {
throw ParseException("missing memory limits", s.line, s.col);
}
auto initElem = s[i++];
- wasm.memory.initial = getAddress(initElem);
- if (!wasm.memory.is64()) {
- checkAddress(wasm.memory.initial, "excessive memory init", initElem);
+ memory->initial = getAddress(initElem);
+ if (!memory->is64()) {
+ checkAddress(memory->initial, "excessive memory init", initElem);
}
if (i == s.size()) {
- wasm.memory.max = Memory::kUnlimitedSize;
+ memory->max = Memory::kUnlimitedSize;
} else {
auto maxElem = s[i++];
- wasm.memory.max = getAddress(maxElem);
- if (!wasm.memory.is64() && wasm.memory.max > Memory::kMaxSize32) {
+ memory->max = getAddress(maxElem);
+ if (!memory->is64() && memory->max > Memory::kMaxSize32) {
throw ParseException(
"total memory must be <= 4GB", maxElem->line, maxElem->col);
}
@@ -3032,23 +3201,24 @@ Index SExpressionWasmBuilder::parseMemoryLimits(Element& s, Index i) {
}
void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
- if (wasm.memory.exists) {
- throw ParseException("too many memories", s.line, s.col);
- }
- wasm.memory.exists = true;
- wasm.memory.shared = false;
+ auto memory = make_unique<Memory>();
+ memory->shared = false;
Index i = 1;
if (s[i]->dollared()) {
- wasm.memory.setExplicitName(s[i++]->str());
+ memory->setExplicitName(s[i++]->str());
+ } else {
+ memory->name = Name::fromInt(memoryCounter++);
}
- i = parseMemoryIndex(s, i);
+ memoryNames.push_back(memory->name);
+
+ i = parseMemoryIndex(s, i, memory);
Name importModule, importBase;
if (s[i]->isList()) {
auto& inner = *s[i];
if (elementStartsWith(inner, EXPORT)) {
auto ex = make_unique<Export>();
ex->name = inner[1]->str();
- ex->value = wasm.memory.name;
+ ex->value = memory->name;
ex->kind = ExternalKind::Memory;
if (wasm.getExportOrNull(ex->name)) {
throw ParseException("duplicate export", inner.line, inner.col);
@@ -3056,33 +3226,36 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
wasm.addExport(ex.release());
i++;
} else if (elementStartsWith(inner, IMPORT)) {
- wasm.memory.module = inner[1]->str();
- wasm.memory.base = inner[2]->str();
+ memory->module = inner[1]->str();
+ memory->base = inner[2]->str();
i++;
} else if (elementStartsWith(inner, SHARED)) {
- wasm.memory.shared = true;
- parseMemoryLimits(inner, 1);
+ memory->shared = true;
+ parseMemoryLimits(inner, 1, memory);
i++;
} else {
if (!(inner.size() > 0 ? inner[0]->str() != IMPORT : true)) {
throw ParseException("bad import ending", inner.line, inner.col);
}
// (memory (data ..)) format
- auto j = parseMemoryIndex(inner, 1);
+ auto j = parseMemoryIndex(inner, 1, memory);
auto offset = allocator.alloc<Const>();
- if (wasm.memory.is64()) {
+ if (memory->is64()) {
offset->set(Literal(int64_t(0)));
} else {
offset->set(Literal(int32_t(0)));
}
- parseInnerData(
- inner, j, Name::fromInt(dataCounter++), false, offset, false);
- wasm.memory.initial = wasm.dataSegments[0]->data.size();
+ auto seg = Builder::makeDataSegment(
+ Name::fromInt(dataCounter++), memory->name, false, offset);
+ parseInnerData(inner, j, seg);
+ memory->initial = seg->data.size();
+ wasm.addDataSegment(std::move(seg));
+ wasm.addMemory(std::move(memory));
return;
}
}
- if (!wasm.memory.shared) {
- i = parseMemoryLimits(s, i);
+ if (!memory->shared) {
+ i = parseMemoryLimits(s, i, memory);
}
// Parse memory initializers.
@@ -3095,13 +3268,13 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
} else {
auto offsetElem = curr[j++];
offsetValue = getAddress(offsetElem);
- if (!wasm.memory.is64()) {
+ if (!memory->is64()) {
checkAddress(offsetValue, "excessive memory offset", offsetElem);
}
}
const char* input = curr[j]->c_str();
auto* offset = allocator.alloc<Const>();
- if (wasm.memory.is64()) {
+ if (memory->is64()) {
offset->type = Type::i64;
offset->value = Literal(offsetValue);
} else {
@@ -3111,27 +3284,33 @@ void SExpressionWasmBuilder::parseMemory(Element& s, bool preParseImport) {
if (auto size = strlen(input)) {
std::vector<char> data;
stringToBinary(input, size, data);
- auto segment = Builder::makeDataSegment(
- Name::fromInt(dataCounter++), false, offset, data.data(), data.size());
+ auto segment = Builder::makeDataSegment(Name::fromInt(dataCounter++),
+ memory->name,
+ false,
+ offset,
+ data.data(),
+ data.size());
segment->hasExplicitName = false;
- wasm.dataSegments.push_back(std::move(segment));
+ wasm.addDataSegment(std::move(segment));
} else {
- auto segment =
- Builder::makeDataSegment(Name::fromInt(dataCounter++), false, offset);
+ auto segment = Builder::makeDataSegment(
+ Name::fromInt(dataCounter++), memory->name, false, offset);
segment->hasExplicitName = false;
- wasm.dataSegments.push_back(std::move(segment));
+ wasm.addDataSegment(std::move(segment));
}
i++;
}
+ wasm.addMemory(std::move(memory));
}
void SExpressionWasmBuilder::parseData(Element& s) {
- if (!wasm.memory.exists) {
+ if (wasm.memories.empty()) {
throw ParseException("data but no memory", s.line, s.col);
}
Index i = 1;
Name name = Name::fromInt(dataCounter++);
bool hasExplicitName = false;
+ Name memory;
bool isPassive = true;
Expression* offset = nullptr;
@@ -3143,11 +3322,11 @@ void SExpressionWasmBuilder::parseData(Element& s) {
if (s[i]->isList()) {
// Optional (memory <memoryidx>)
if (elementStartsWith(s[i], MEMORY)) {
- // TODO: we're just skipping memory since we have only one. Assign the
- // memory name to the segment when we support multiple memories.
- i += 1;
+ auto& inner = *s[i++];
+ memory = getMemoryName(*inner[1]);
+ } else {
+ memory = getMemoryNameAtIdx(0);
}
-
// Offset expression (offset (<expr>)) | (<expr>)
auto& inner = *s[i++];
if (elementStartsWith(inner, OFFSET)) {
@@ -3158,15 +3337,15 @@ void SExpressionWasmBuilder::parseData(Element& s) {
isPassive = false;
}
- parseInnerData(s, i, name, hasExplicitName, offset, isPassive);
+ auto seg = Builder::makeDataSegment(name, memory, isPassive, offset);
+ seg->hasExplicitName = hasExplicitName;
+ parseInnerData(s, i, seg);
+ wasm.addDataSegment(std::move(seg));
}
void SExpressionWasmBuilder::parseInnerData(Element& s,
Index i,
- Name name,
- bool hasExplicitName,
- Expression* offset,
- bool isPassive) {
+ std::unique_ptr<DataSegment>& seg) {
std::vector<char> data;
while (i < s.size()) {
const char* input = s[i++]->c_str();
@@ -3174,10 +3353,8 @@ void SExpressionWasmBuilder::parseInnerData(Element& s,
stringToBinary(input, size, data);
}
}
- auto curr =
- Builder::makeDataSegment(name, isPassive, offset, data.data(), data.size());
- curr->hasExplicitName = hasExplicitName;
- wasm.dataSegments.push_back(std::move(curr));
+ seg->data.resize(data.size());
+ std::copy_n(data.data(), data.size(), seg->data.begin());
}
void SExpressionWasmBuilder::parseExport(Element& s) {
@@ -3224,10 +3401,6 @@ void SExpressionWasmBuilder::parseImport(Element& s) {
kind = ExternalKind::Function;
} else if (elementStartsWith(*s[3], MEMORY)) {
kind = ExternalKind::Memory;
- if (wasm.memory.exists) {
- throw ParseException("more than one memory", s[3]->line, s[3]->col);
- }
- wasm.memory.exists = true;
} else if (elementStartsWith(*s[3], TABLE)) {
kind = ExternalKind::Table;
} else if (elementStartsWith(*s[3], GLOBAL)) {
@@ -3320,20 +3493,25 @@ void SExpressionWasmBuilder::parseImport(Element& s) {
j++; // funcref
// ends with the table element type
} else if (kind == ExternalKind::Memory) {
- wasm.memory.setName(name, hasExplicitName);
- wasm.memory.module = module;
- wasm.memory.base = base;
+ auto memory = make_unique<Memory>();
+ memory->setName(name, hasExplicitName);
+ memory->module = module;
+ memory->base = base;
+ memoryNames.push_back(name);
+
if (inner[j]->isList()) {
auto& limits = *inner[j];
if (!elementStartsWith(limits, SHARED)) {
throw ParseException(
"bad memory limit declaration", inner[j]->line, inner[j]->col);
}
- wasm.memory.shared = true;
- j = parseMemoryLimits(limits, 1);
+ memory->shared = true;
+ j = parseMemoryLimits(limits, 1, memory);
} else {
- j = parseMemoryLimits(inner, j);
+ j = parseMemoryLimits(inner, j, memory);
}
+
+ wasm.addMemory(std::move(memory));
} else if (kind == ExternalKind::Tag) {
auto tag = make_unique<Tag>();
HeapType tagType;
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index b887f6ec5..13bd09927 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -234,7 +234,7 @@ void BinaryInstWriter::visitLoad(Load* curr) {
WASM_UNREACHABLE("unexpected type");
}
}
- emitMemoryAccess(curr->align, curr->bytes, curr->offset);
+ emitMemoryAccess(curr->align, curr->bytes, curr->offset, curr->memory);
}
void BinaryInstWriter::visitStore(Store* curr) {
@@ -331,7 +331,7 @@ void BinaryInstWriter::visitStore(Store* curr) {
WASM_UNREACHABLE("unexpected type");
}
}
- emitMemoryAccess(curr->align, curr->bytes, curr->offset);
+ emitMemoryAccess(curr->align, curr->bytes, curr->offset, curr->memory);
}
void BinaryInstWriter::visitAtomicRMW(AtomicRMW* curr) {
@@ -390,7 +390,7 @@ void BinaryInstWriter::visitAtomicRMW(AtomicRMW* curr) {
}
#undef CASE_FOR_OP
- emitMemoryAccess(curr->bytes, curr->bytes, curr->offset);
+ emitMemoryAccess(curr->bytes, curr->bytes, curr->offset, curr->memory);
}
void BinaryInstWriter::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
@@ -432,7 +432,7 @@ void BinaryInstWriter::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
default:
WASM_UNREACHABLE("unexpected type");
}
- emitMemoryAccess(curr->bytes, curr->bytes, curr->offset);
+ emitMemoryAccess(curr->bytes, curr->bytes, curr->offset, curr->memory);
}
void BinaryInstWriter::visitAtomicWait(AtomicWait* curr) {
@@ -440,12 +440,12 @@ void BinaryInstWriter::visitAtomicWait(AtomicWait* curr) {
switch (curr->expectedType.getBasic()) {
case Type::i32: {
o << int8_t(BinaryConsts::I32AtomicWait);
- emitMemoryAccess(4, 4, curr->offset);
+ emitMemoryAccess(4, 4, curr->offset, curr->memory);
break;
}
case Type::i64: {
o << int8_t(BinaryConsts::I64AtomicWait);
- emitMemoryAccess(8, 8, curr->offset);
+ emitMemoryAccess(8, 8, curr->offset, curr->memory);
break;
}
default:
@@ -455,7 +455,7 @@ void BinaryInstWriter::visitAtomicWait(AtomicWait* curr) {
void BinaryInstWriter::visitAtomicNotify(AtomicNotify* curr) {
o << int8_t(BinaryConsts::AtomicPrefix) << int8_t(BinaryConsts::AtomicNotify);
- emitMemoryAccess(4, 4, curr->offset);
+ emitMemoryAccess(4, 4, curr->offset, curr->memory);
}
void BinaryInstWriter::visitAtomicFence(AtomicFence* curr) {
@@ -646,7 +646,8 @@ void BinaryInstWriter::visitSIMDLoad(SIMDLoad* curr) {
break;
}
assert(curr->align);
- emitMemoryAccess(curr->align, /*(unused) bytes=*/0, curr->offset);
+ emitMemoryAccess(
+ curr->align, /*(unused) bytes=*/0, curr->offset, curr->memory);
}
void BinaryInstWriter::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
@@ -678,14 +679,15 @@ void BinaryInstWriter::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
break;
}
assert(curr->align);
- emitMemoryAccess(curr->align, /*(unused) bytes=*/0, curr->offset);
+ emitMemoryAccess(
+ curr->align, /*(unused) bytes=*/0, curr->offset, curr->memory);
o << curr->index;
}
void BinaryInstWriter::visitMemoryInit(MemoryInit* curr) {
o << int8_t(BinaryConsts::MiscPrefix);
o << U32LEB(BinaryConsts::MemoryInit);
- o << U32LEB(curr->segment) << int8_t(0);
+ o << U32LEB(curr->segment) << int8_t(parent.getMemoryIndex(curr->memory));
}
void BinaryInstWriter::visitDataDrop(DataDrop* curr) {
@@ -697,13 +699,14 @@ void BinaryInstWriter::visitDataDrop(DataDrop* curr) {
void BinaryInstWriter::visitMemoryCopy(MemoryCopy* curr) {
o << int8_t(BinaryConsts::MiscPrefix);
o << U32LEB(BinaryConsts::MemoryCopy);
- o << int8_t(0) << int8_t(0);
+ o << int8_t(parent.getMemoryIndex(curr->destMemory))
+ << int8_t(parent.getMemoryIndex(curr->sourceMemory));
}
void BinaryInstWriter::visitMemoryFill(MemoryFill* curr) {
o << int8_t(BinaryConsts::MiscPrefix);
o << U32LEB(BinaryConsts::MemoryFill);
- o << int8_t(0);
+ o << int8_t(parent.getMemoryIndex(curr->memory));
}
void BinaryInstWriter::visitConst(Const* curr) {
@@ -1859,12 +1862,12 @@ void BinaryInstWriter::visitReturn(Return* curr) {
void BinaryInstWriter::visitMemorySize(MemorySize* curr) {
o << int8_t(BinaryConsts::MemorySize);
- o << U32LEB(0); // Reserved flags field
+ o << U32LEB(parent.getMemoryIndex(curr->memory));
}
void BinaryInstWriter::visitMemoryGrow(MemoryGrow* curr) {
o << int8_t(BinaryConsts::MemoryGrow);
- o << U32LEB(0); // Reserved flags field
+ o << U32LEB(parent.getMemoryIndex(curr->memory));
}
void BinaryInstWriter::visitRefNull(RefNull* curr) {
@@ -2476,8 +2479,19 @@ void BinaryInstWriter::setScratchLocals() {
void BinaryInstWriter::emitMemoryAccess(size_t alignment,
size_t bytes,
- uint32_t offset) {
- o << U32LEB(Bits::log2(alignment ? alignment : bytes));
+ uint32_t offset,
+ Name memory) {
+ uint32_t alignmentBits = Bits::log2(alignment ? alignment : bytes);
+ uint32_t memoryIdx = parent.getMemoryIndex(memory);
+ if (memoryIdx > 0) {
+ // Set bit 6 in the alignment to indicate a memory index is present per:
+ // https://github.com/WebAssembly/multi-memory/blob/main/proposals/multi-memory/Overview.md
+ alignmentBits = alignmentBits | 1 << 6;
+ }
+ o << U32LEB(alignmentBits);
+ if (memoryIdx > 0) {
+ o << U32LEB(memoryIdx);
+ }
o << U32LEB(offset);
}
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index b7354ff3f..92f6c76bf 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -499,7 +499,10 @@ private:
validateCallParamsAndResult(curr, sigType, curr);
}
- Type indexType() { return getModule()->memory.indexType; }
+ Type indexType(Name memoryName) {
+ auto memory = getModule()->getMemory(memoryName);
+ return memory->indexType;
+ }
};
void FunctionValidator::noteLabelName(Name name) {
@@ -934,8 +937,8 @@ void FunctionValidator::visitGlobalSet(GlobalSet* curr) {
}
void FunctionValidator::visitLoad(Load* curr) {
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ shouldBeTrue(!!memory, curr, "memory.load memory must exist");
if (curr->isAtomic) {
shouldBeTrue(getModule()->features.hasAtomics(),
curr,
@@ -954,7 +957,7 @@ void FunctionValidator::visitLoad(Load* curr) {
validateAlignment(curr->align, curr->type, curr->bytes, curr->isAtomic, curr);
shouldBeEqualOrFirstIsUnreachable(
curr->ptr->type,
- indexType(),
+ indexType(curr->memory),
curr,
"load pointer type must match memory index type");
if (curr->isAtomic) {
@@ -965,8 +968,8 @@ void FunctionValidator::visitLoad(Load* curr) {
}
void FunctionValidator::visitStore(Store* curr) {
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ shouldBeTrue(!!memory, curr, "memory.store memory must exist");
if (curr->isAtomic) {
shouldBeTrue(getModule()->features.hasAtomics(),
curr,
@@ -986,7 +989,7 @@ void FunctionValidator::visitStore(Store* curr) {
curr->align, curr->valueType, curr->bytes, curr->isAtomic, curr);
shouldBeEqualOrFirstIsUnreachable(
curr->ptr->type,
- indexType(),
+ indexType(curr->memory),
curr,
"store pointer must match memory index type");
shouldBeUnequal(curr->value->type,
@@ -1002,15 +1005,15 @@ void FunctionValidator::visitStore(Store* curr) {
}
void FunctionValidator::visitAtomicRMW(AtomicRMW* curr) {
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ shouldBeTrue(!!memory, curr, "memory.atomicRMW memory must exist");
shouldBeTrue(getModule()->features.hasAtomics(),
curr,
"Atomic operation (atomics are disabled)");
validateMemBytes(curr->bytes, curr->type, curr);
shouldBeEqualOrFirstIsUnreachable(
curr->ptr->type,
- indexType(),
+ indexType(curr->memory),
curr,
"AtomicRMW pointer type must match memory index type");
shouldBeEqualOrFirstIsUnreachable(curr->type,
@@ -1022,15 +1025,15 @@ void FunctionValidator::visitAtomicRMW(AtomicRMW* curr) {
}
void FunctionValidator::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ shouldBeTrue(!!memory, curr, "memory.atomicCmpxchg memory must exist");
shouldBeTrue(getModule()->features.hasAtomics(),
curr,
"Atomic operation (atomics are disabled)");
validateMemBytes(curr->bytes, curr->type, curr);
shouldBeEqualOrFirstIsUnreachable(
curr->ptr->type,
- indexType(),
+ indexType(curr->memory),
curr,
"cmpxchg pointer must match memory index type");
if (curr->expected->type != Type::unreachable &&
@@ -1055,8 +1058,8 @@ void FunctionValidator::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
}
void FunctionValidator::visitAtomicWait(AtomicWait* curr) {
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ shouldBeTrue(!!memory, curr, "memory.atomicWait memory must exist");
shouldBeTrue(getModule()->features.hasAtomics(),
curr,
"Atomic operation (atomics are disabled)");
@@ -1064,7 +1067,7 @@ void FunctionValidator::visitAtomicWait(AtomicWait* curr) {
curr->type, Type(Type::i32), curr, "AtomicWait must have type i32");
shouldBeEqualOrFirstIsUnreachable(
curr->ptr->type,
- indexType(),
+ indexType(curr->memory),
curr,
"AtomicWait pointer must match memory index type");
shouldBeIntOrUnreachable(
@@ -1081,8 +1084,8 @@ void FunctionValidator::visitAtomicWait(AtomicWait* curr) {
}
void FunctionValidator::visitAtomicNotify(AtomicNotify* curr) {
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ shouldBeTrue(!!memory, curr, "memory.atomicNotify memory must exist");
shouldBeTrue(getModule()->features.hasAtomics(),
curr,
"Atomic operation (atomics are disabled)");
@@ -1090,7 +1093,7 @@ void FunctionValidator::visitAtomicNotify(AtomicNotify* curr) {
curr->type, Type(Type::i32), curr, "AtomicNotify must have type i32");
shouldBeEqualOrFirstIsUnreachable(
curr->ptr->type,
- indexType(),
+ indexType(curr->memory),
curr,
"AtomicNotify pointer must match memory index type");
shouldBeEqualOrFirstIsUnreachable(
@@ -1101,8 +1104,8 @@ void FunctionValidator::visitAtomicNotify(AtomicNotify* curr) {
}
void FunctionValidator::visitAtomicFence(AtomicFence* curr) {
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ shouldBeFalse(
+ getModule()->memories.empty(), curr, "Memory operations require a memory");
shouldBeTrue(getModule()->features.hasAtomics(),
curr,
"Atomic operation (atomics are disabled)");
@@ -1240,15 +1243,15 @@ void FunctionValidator::visitSIMDShift(SIMDShift* curr) {
}
void FunctionValidator::visitSIMDLoad(SIMDLoad* curr) {
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ shouldBeTrue(!!memory, curr, "memory.SIMDLoad memory must exist");
shouldBeTrue(
getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
shouldBeEqualOrFirstIsUnreachable(
curr->type, Type(Type::v128), curr, "load_splat must have type v128");
shouldBeEqualOrFirstIsUnreachable(
curr->ptr->type,
- indexType(),
+ indexType(curr->memory),
curr,
"load_splat address must match memory index type");
Type memAlignType = Type::none;
@@ -1275,8 +1278,8 @@ void FunctionValidator::visitSIMDLoad(SIMDLoad* curr) {
}
void FunctionValidator::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ shouldBeTrue(!!memory, curr, "memory.SIMDLoadStoreLane memory must exist");
shouldBeTrue(
getModule()->features.hasSIMD(), curr, "SIMD operation (SIMD is disabled)");
if (curr->isLoad()) {
@@ -1288,7 +1291,7 @@ void FunctionValidator::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
}
shouldBeEqualOrFirstIsUnreachable(
curr->ptr->type,
- indexType(),
+ indexType(curr->memory),
curr,
"loadX_lane or storeX_lane address must match memory index type");
shouldBeEqualOrFirstIsUnreachable(
@@ -1335,7 +1338,7 @@ void FunctionValidator::visitMemoryInit(MemoryInit* curr) {
curr->type, Type(Type::none), curr, "memory.init must have type none");
shouldBeEqualOrFirstIsUnreachable(
curr->dest->type,
- indexType(),
+ indexType(curr->memory),
curr,
"memory.init dest must match memory index type");
shouldBeEqualOrFirstIsUnreachable(curr->offset->type,
@@ -1344,9 +1347,8 @@ void FunctionValidator::visitMemoryInit(MemoryInit* curr) {
"memory.init offset must be an i32");
shouldBeEqualOrFirstIsUnreachable(
curr->size->type, Type(Type::i32), curr, "memory.init size must be an i32");
- if (!shouldBeTrue(getModule()->memory.exists,
- curr,
- "Memory operations require a memory")) {
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ if (!shouldBeTrue(!!memory, curr, "memory.init memory must exist")) {
return;
}
shouldBeTrue(curr->segment < getModule()->dataSegments.size(),
@@ -1360,9 +1362,9 @@ void FunctionValidator::visitDataDrop(DataDrop* curr) {
"Bulk memory operation (bulk memory is disabled)");
shouldBeEqualOrFirstIsUnreachable(
curr->type, Type(Type::none), curr, "data.drop must have type none");
- if (!shouldBeTrue(getModule()->memory.exists,
- curr,
- "Memory operations require a memory")) {
+ if (!shouldBeFalse(getModule()->memories.empty(),
+ curr,
+ "Memory operations require a memory")) {
return;
}
shouldBeTrue(curr->segment < getModule()->dataSegments.size(),
@@ -1376,23 +1378,30 @@ void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) {
"Bulk memory operation (bulk memory is disabled)");
shouldBeEqualOrFirstIsUnreachable(
curr->type, Type(Type::none), curr, "memory.copy must have type none");
+ auto* destMemory = getModule()->getMemoryOrNull(curr->destMemory);
+ shouldBeTrue(!!destMemory, curr, "memory.copy destMemory must exist");
+ auto* sourceMemory = getModule()->getMemoryOrNull(curr->sourceMemory);
+ shouldBeTrue(!!sourceMemory, curr, "memory.copy sourceMemory must exist");
shouldBeEqualOrFirstIsUnreachable(
curr->dest->type,
- indexType(),
+ indexType(curr->destMemory),
curr,
- "memory.copy dest must match memory index type");
+ "memory.copy dest must match destMemory index type");
shouldBeEqualOrFirstIsUnreachable(
curr->source->type,
- indexType(),
+ indexType(curr->sourceMemory),
curr,
- "memory.copy source must match memory index type");
+ "memory.copy source must match sourceMemory index type");
shouldBeEqualOrFirstIsUnreachable(
curr->size->type,
- indexType(),
+ indexType(curr->destMemory),
curr,
- "memory.copy size must match memory index type");
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ "memory.copy size must match destMemory index type");
+ shouldBeEqualOrFirstIsUnreachable(
+ curr->size->type,
+ indexType(curr->sourceMemory),
+ curr,
+ "memory.copy size must match destMemory index type");
}
void FunctionValidator::visitMemoryFill(MemoryFill* curr) {
@@ -1403,7 +1412,7 @@ void FunctionValidator::visitMemoryFill(MemoryFill* curr) {
curr->type, Type(Type::none), curr, "memory.fill must have type none");
shouldBeEqualOrFirstIsUnreachable(
curr->dest->type,
- indexType(),
+ indexType(curr->memory),
curr,
"memory.fill dest must match memory index type");
shouldBeEqualOrFirstIsUnreachable(curr->value->type,
@@ -1412,11 +1421,11 @@ void FunctionValidator::visitMemoryFill(MemoryFill* curr) {
"memory.fill value must be an i32");
shouldBeEqualOrFirstIsUnreachable(
curr->size->type,
- indexType(),
+ indexType(curr->memory),
curr,
"memory.fill size must match memory index type");
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ shouldBeTrue(!!memory, curr, "memory.fill memory must exist");
}
void FunctionValidator::validateMemBytes(uint8_t bytes,
@@ -2020,15 +2029,15 @@ void FunctionValidator::visitReturn(Return* curr) {
}
void FunctionValidator::visitMemorySize(MemorySize* curr) {
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ shouldBeTrue(!!memory, curr, "memory.size memory must exist");
}
void FunctionValidator::visitMemoryGrow(MemoryGrow* curr) {
- shouldBeTrue(
- getModule()->memory.exists, curr, "Memory operations require a memory");
+ auto* memory = getModule()->getMemoryOrNull(curr->memory);
+ shouldBeTrue(!!memory, curr, "memory.grow memory must exist");
shouldBeEqualOrFirstIsUnreachable(curr->delta->type,
- indexType(),
+ indexType(curr->memory),
curr,
"memory.grow must match memory index type");
}
@@ -2940,7 +2949,7 @@ static void validateExports(Module& module, ValidationInfo& info) {
name,
"module table exports must be found");
} else if (exp->kind == ExternalKind::Memory) {
- info.shouldBeTrue(name == Name("0") || name == module.memory.name,
+ info.shouldBeTrue(module.getMemoryOrNull(name),
name,
"module memory exports must be found");
} else if (exp->kind == ExternalKind::Tag) {
@@ -2982,25 +2991,28 @@ static void validateGlobals(Module& module, ValidationInfo& info) {
}
static void validateMemory(Module& module, ValidationInfo& info) {
- auto& curr = module.memory;
+ if (module.memories.empty()) {
+ return;
+ }
+ auto& curr = module.memories[0];
info.shouldBeFalse(
- curr.initial > curr.max, "memory", "memory max >= initial");
- if (curr.is64()) {
+ curr->initial > curr->max, "memory", "memory max >= initial");
+ if (curr->is64()) {
info.shouldBeTrue(module.features.hasMemory64(),
"memory",
"memory is 64-bit, but memory64 is disabled");
} else {
- info.shouldBeTrue(curr.initial <= Memory::kMaxSize32,
+ info.shouldBeTrue(curr->initial <= Memory::kMaxSize32,
"memory",
"initial memory must be <= 4GB");
- info.shouldBeTrue(!curr.hasMax() || curr.max <= Memory::kMaxSize32,
+ info.shouldBeTrue(!curr->hasMax() || curr->max <= Memory::kMaxSize32,
"memory",
"max memory must be <= 4GB, or unlimited");
}
- info.shouldBeTrue(!curr.shared || curr.hasMax(),
+ info.shouldBeTrue(!curr->shared || curr->hasMax(),
"memory",
"shared memory must have max size");
- if (curr.shared) {
+ if (curr->shared) {
info.shouldBeTrue(module.features.hasAtomics(),
"memory",
"memory is shared, but atomics are disabled");
@@ -3016,7 +3028,7 @@ static void validateMemory(Module& module, ValidationInfo& info) {
segment->offset,
"passive segment should not have an offset");
} else {
- if (curr.is64()) {
+ if (curr->is64()) {
if (!info.shouldBeEqual(segment->offset->type,
Type(Type::i64),
segment->offset,
@@ -3033,14 +3045,14 @@ static void validateMemory(Module& module, ValidationInfo& info) {
}
info.shouldBeTrue(checkSegmentOffset(segment->offset,
segment->data.size(),
- curr.initial * Memory::kPageSize,
+ curr->initial * Memory::kPageSize,
module.features),
segment->offset,
"memory segment offset should be reasonable");
if (segment->offset->is<Const>()) {
auto start = segment->offset->cast<Const>()->value.getUnsigned();
auto end = start + size;
- info.shouldBeTrue(end <= curr.initial * Memory::kPageSize,
+ info.shouldBeTrue(end <= curr->initial * Memory::kPageSize,
segment->data.size(),
"segment size should fit in memory (end)");
}
@@ -3049,8 +3061,8 @@ static void validateMemory(Module& module, ValidationInfo& info) {
// If the memory is imported we don't actually know its initial size.
// Specifically wasm dll's import a zero sized memory which is perfectly
// valid.
- if (!curr.imported()) {
- info.shouldBeTrue(size <= curr.initial * Memory::kPageSize,
+ if (!curr->imported()) {
+ info.shouldBeTrue(size <= curr->initial * Memory::kPageSize,
segment->data.size(),
"segment size should fit in memory (initial)");
}
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 1c9c1389d..574eb5c47 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -1336,6 +1336,10 @@ ElementSegment* Module::getElementSegment(Name name) {
return getModuleElement(elementSegmentsMap, name, "getElementSegment");
}
+Memory* Module::getMemory(Name name) {
+ return getModuleElement(memoriesMap, name, "getMemory");
+}
+
DataSegment* Module::getDataSegment(Name name) {
return getModuleElement(dataSegmentsMap, name, "getDataSegment");
}
@@ -1373,6 +1377,10 @@ ElementSegment* Module::getElementSegmentOrNull(Name name) {
return getModuleElementOrNull(elementSegmentsMap, name);
}
+Memory* Module::getMemoryOrNull(Name name) {
+ return getModuleElementOrNull(memoriesMap, name);
+}
+
DataSegment* Module::getDataSegmentOrNull(Name name) {
return getModuleElementOrNull(dataSegmentsMap, name);
}
@@ -1452,6 +1460,10 @@ Module::addElementSegment(std::unique_ptr<ElementSegment>&& curr) {
elementSegments, elementSegmentsMap, std::move(curr), "addElementSegment");
}
+Memory* Module::addMemory(std::unique_ptr<Memory>&& curr) {
+ return addModuleElement(memories, memoriesMap, std::move(curr), "addMemory");
+}
+
DataSegment* Module::addDataSegment(std::unique_ptr<DataSegment>&& curr) {
return addModuleElement(
dataSegments, dataSegmentsMap, std::move(curr), "addDataSegment");
@@ -1490,6 +1502,9 @@ void Module::removeTable(Name name) {
void Module::removeElementSegment(Name name) {
removeModuleElement(elementSegments, elementSegmentsMap, name);
}
+void Module::removeMemory(Name name) {
+ removeModuleElement(memories, memoriesMap, name);
+}
void Module::removeDataSegment(Name name) {
removeModuleElement(dataSegments, dataSegmentsMap, name);
}
@@ -1526,6 +1541,9 @@ void Module::removeTables(std::function<bool(Table*)> pred) {
void Module::removeElementSegments(std::function<bool(ElementSegment*)> pred) {
removeModuleElements(elementSegments, elementSegmentsMap, pred);
}
+void Module::removeMemories(std::function<bool(Memory*)> pred) {
+ removeModuleElements(memories, memoriesMap, pred);
+}
void Module::removeDataSegments(std::function<bool(DataSegment*)> pred) {
removeModuleElements(dataSegments, dataSegmentsMap, pred);
}
@@ -1536,6 +1554,13 @@ void Module::removeTags(std::function<bool(Tag*)> pred) {
removeModuleElements(tags, tagsMap, pred);
}
+void Module::updateDataSegmentsMap() {
+ dataSegmentsMap.clear();
+ for (auto& curr : dataSegments) {
+ dataSegmentsMap[curr->name] = curr.get();
+ }
+}
+
void Module::updateMaps() {
functionsMap.clear();
for (auto& curr : functions) {
@@ -1553,10 +1578,11 @@ void Module::updateMaps() {
for (auto& curr : elementSegments) {
elementSegmentsMap[curr->name] = curr.get();
}
- dataSegmentsMap.clear();
- for (auto& curr : dataSegments) {
- dataSegmentsMap[curr->name] = curr.get();
+ memoriesMap.clear();
+ for (auto& curr : memories) {
+ memoriesMap[curr->name] = curr.get();
}
+ updateDataSegmentsMap();
globalsMap.clear();
for (auto& curr : globals) {
globalsMap[curr->name] = curr.get();