summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/fuzz_opt.py8
-rw-r--r--src/abi/stack.h3
-rw-r--r--src/binaryen-c.cpp288
-rw-r--r--src/binaryen-c.h84
-rw-r--r--src/ir/import-utils.h14
-rw-r--r--src/ir/memory-utils.cpp5
-rw-r--r--src/ir/memory-utils.h18
-rw-r--r--src/ir/module-splitting.cpp11
-rw-r--r--src/ir/module-utils.h37
-rw-r--r--src/js/binaryen.js-post.js483
-rw-r--r--src/passes/AlignmentLowering.cpp72
-rw-r--r--src/passes/Asyncify.cpp36
-rw-r--r--src/passes/AvoidReinterprets.cpp10
-rw-r--r--src/passes/I64ToI32Lowering.cpp10
-rw-r--r--src/passes/InstrumentMemory.cpp13
-rw-r--r--src/passes/Memory64Lowering.cpp98
-rw-r--r--src/passes/MemoryPacking.cpp36
-rw-r--r--src/passes/Metrics.cpp9
-rw-r--r--src/passes/OptimizeInstructions.cpp100
-rw-r--r--src/passes/Print.cpp37
-rw-r--r--src/passes/RemoveNonJSOps.cpp2
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp12
-rw-r--r--src/passes/SafeHeap.cpp110
-rw-r--r--src/passes/SpillPointers.cpp5
-rw-r--r--src/passes/StackCheck.cpp6
-rw-r--r--src/shell-interface.h140
-rw-r--r--src/tools/fuzzing/fuzzing.cpp171
-rw-r--r--src/tools/wasm-ctor-eval.cpp100
-rw-r--r--src/tools/wasm-shell.cpp13
-rw-r--r--src/tools/wasm-split/instrumenter.cpp55
-rw-r--r--src/wasm-binary.h19
-rw-r--r--src/wasm-builder.h102
-rw-r--r--src/wasm-delegations-fields.def14
-rw-r--r--src/wasm-interpreter.h413
-rw-r--r--src/wasm-s-parser.h22
-rw-r--r--src/wasm-stack.h5
-rw-r--r--src/wasm-traversal.h4
-rw-r--r--src/wasm.h27
-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
-rw-r--r--src/wasm2js.h38
-rw-r--r--test/binaryen.js/expressions.js42
-rw-r--r--test/binaryen.js/expressions.js.txt28
-rw-r--r--test/binaryen.js/kitchen-sink.js29
-rw-r--r--test/binaryen.js/kitchen-sink.js.txt4
-rw-r--r--test/binaryen.js/memory-info.js.txt4
-rw-r--r--test/binaryen.js/sideffects.js1
-rw-r--r--test/example/c-api-kitchen-sink.c92
-rw-r--r--test/example/c-api-relooper-unreachable-if.cpp216
-rw-r--r--test/example/c-api-unused-mem.cpp30
-rw-r--r--test/example/relooper-fuzz.c47
-rw-r--r--test/example/relooper-fuzz1.c47
-rw-r--r--test/example/relooper-fuzz2.c472
-rw-r--r--test/example/relooper-merge1.c44
-rw-r--r--test/example/relooper-merge2.c44
-rw-r--r--test/example/relooper-merge3.c44
-rw-r--r--test/example/relooper-merge4.c44
-rw-r--r--test/example/relooper-merge5.c44
-rw-r--r--test/example/relooper-merge6.c44
-rw-r--r--test/lit/multi-memories-atomics64.wast704
-rw-r--r--test/lit/multi-memories-basics.wast175
-rw-r--r--test/lit/multi-memories-simd.wast635
-rw-r--r--test/lit/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.wast4
-rw-r--r--test/lit/passes/O4_disable-bulk-memory.wast4
-rw-r--r--test/lit/wasm-split/export-name-already-exists.wast1
-rw-r--r--test/lit/wasm-split/instrument-in-memory.wast1
-rw-r--r--test/lit/wasm-split/merge-profiles.wast1
-rw-r--r--test/lit/wasm-split/mismatched-hashes.wast1
-rw-r--r--test/multi-memories-atomics64.wasmbin0 -> 835 bytes
-rw-r--r--test/multi-memories-atomics64.wasm.fromBinary352
-rw-r--r--test/multi-memories-basics.wasmbin0 -> 400 bytes
-rw-r--r--test/multi-memories-basics.wasm.fromBinary117
-rw-r--r--test/multi-memories-simd.wasmbin0 -> 2292 bytes
-rw-r--r--test/multi-memories-simd.wasm.fromBinary320
-rw-r--r--test/passes/O3_low-memory-unused_metrics.txt2
-rw-r--r--test/passes/converge_O3_metrics.bin.txt3
-rw-r--r--test/passes/func-metrics.txt6
-rw-r--r--test/passes/fuzz_metrics_noprint.bin.txt1
-rw-r--r--test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.txt14
-rw-r--r--test/passes/metrics_all-features.txt2
-rw-r--r--test/passes/metrics_strip-debug_metrics.bin.txt2
-rw-r--r--test/passes/metrics_strip-producers_metrics.bin.txt2
-rw-r--r--test/passes/print_g_metrics.bin.txt1
-rw-r--r--test/passes/sparse_matrix_liveness.bin.txt2
-rw-r--r--test/passes/translate-to-fuzz_all-features_metrics_noprint.txt1
-rw-r--r--test/spec/imports.wast13
-rw-r--r--test/spec/memory.wast3
-rw-r--r--test/spec/memory64.wast3
-rw-r--r--test/spec/multi-memories_size.wast35
-rw-r--r--test/spec/old_import.wast13
94 files changed, 5398 insertions, 1776 deletions
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py
index bb73aeb6b..e8c497306 100755
--- a/scripts/fuzz_opt.py
+++ b/scripts/fuzz_opt.py
@@ -283,6 +283,14 @@ INITIAL_CONTENTS_IGNORE = [
'fib2_emptylocspan_dwarf.wasm',
'fannkuch3_dwarf.wasm',
'multi_unit_abbrev_noprint.wasm',
+ # TODO fuzzer support for multi-memories
+ 'multi-memories-atomics64.wast',
+ 'multi-memories-basics.wast',
+ 'multi-memories-simd.wast',
+ 'multi-memories-atomics64.wasm',
+ 'multi-memories-basics.wasm',
+ 'multi-memories-simd.wasm',
+ 'multi-memories_size.wast',
]
diff --git a/src/abi/stack.h b/src/abi/stack.h
index cc678b6e8..93a6e4cc1 100644
--- a/src/abi/stack.h
+++ b/src/abi/stack.h
@@ -50,7 +50,8 @@ getStackSpace(Index local, Function* func, Index size, Module& wasm) {
}
// align the size
size = stackAlign(size);
- auto pointerType = wasm.memory.indexType;
+ auto pointerType =
+ !wasm.memories.empty() ? wasm.memories[0]->indexType : Type::i32;
// TODO: find existing stack usage, and add on top of that - carefully
Builder builder(wasm);
auto* block = builder.makeBlock();
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 1dd9fccd2..869f3a92a 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -1068,14 +1068,20 @@ BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module,
uint32_t offset,
uint32_t align,
BinaryenType type,
- BinaryenExpressionRef ptr) {
+ BinaryenExpressionRef ptr,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
return static_cast<Expression*>(Builder(*(Module*)module)
.makeLoad(bytes,
!!signed_,
offset,
align ? align : bytes,
(Expression*)ptr,
- Type(type)));
+ Type(type),
+ name));
}
BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module,
uint32_t bytes,
@@ -1083,14 +1089,20 @@ BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module,
uint32_t align,
BinaryenExpressionRef ptr,
BinaryenExpressionRef value,
- BinaryenType type) {
+ BinaryenType type,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
return static_cast<Expression*>(Builder(*(Module*)module)
.makeStore(bytes,
offset,
align ? align : bytes,
(Expression*)ptr,
(Expression*)value,
- Type(type)));
+ Type(type),
+ name));
}
BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module,
BinaryenLiteral value) {
@@ -1137,13 +1149,24 @@ BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module,
auto* ret = Builder(*(Module*)module).makeReturn((Expression*)value);
return static_cast<Expression*>(ret);
}
-BinaryenExpressionRef BinaryenMemorySize(BinaryenModuleRef module) {
- auto* ret = Builder(*(Module*)module).makeMemorySize();
+BinaryenExpressionRef BinaryenMemorySize(BinaryenModuleRef module,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
+ auto* ret = Builder(*(Module*)module).makeMemorySize(name);
return static_cast<Expression*>(ret);
}
BinaryenExpressionRef BinaryenMemoryGrow(BinaryenModuleRef module,
- BinaryenExpressionRef delta) {
- auto* ret = Builder(*(Module*)module).makeMemoryGrow((Expression*)delta);
+ BinaryenExpressionRef delta,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
+ auto* ret =
+ Builder(*(Module*)module).makeMemoryGrow((Expression*)delta, name);
return static_cast<Expression*>(ret);
}
BinaryenExpressionRef BinaryenNop(BinaryenModuleRef module) {
@@ -1156,21 +1179,31 @@ BinaryenExpressionRef BinaryenAtomicLoad(BinaryenModuleRef module,
uint32_t bytes,
uint32_t offset,
BinaryenType type,
- BinaryenExpressionRef ptr) {
+ BinaryenExpressionRef ptr,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
return static_cast<Expression*>(
Builder(*(Module*)module)
- .makeAtomicLoad(bytes, offset, (Expression*)ptr, Type(type)));
+ .makeAtomicLoad(bytes, offset, (Expression*)ptr, Type(type), name));
}
BinaryenExpressionRef BinaryenAtomicStore(BinaryenModuleRef module,
uint32_t bytes,
uint32_t offset,
BinaryenExpressionRef ptr,
BinaryenExpressionRef value,
- BinaryenType type) {
+ BinaryenType type,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
return static_cast<Expression*>(
Builder(*(Module*)module)
.makeAtomicStore(
- bytes, offset, (Expression*)ptr, (Expression*)value, Type(type)));
+ bytes, offset, (Expression*)ptr, (Expression*)value, Type(type), name));
}
BinaryenExpressionRef BinaryenAtomicRMW(BinaryenModuleRef module,
BinaryenOp op,
@@ -1178,14 +1211,20 @@ BinaryenExpressionRef BinaryenAtomicRMW(BinaryenModuleRef module,
BinaryenIndex offset,
BinaryenExpressionRef ptr,
BinaryenExpressionRef value,
- BinaryenType type) {
+ BinaryenType type,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
return static_cast<Expression*>(Builder(*(Module*)module)
.makeAtomicRMW(AtomicRMWOp(op),
bytes,
offset,
(Expression*)ptr,
(Expression*)value,
- Type(type)));
+ Type(type),
+ name));
}
BinaryenExpressionRef BinaryenAtomicCmpxchg(BinaryenModuleRef module,
BinaryenIndex bytes,
@@ -1193,33 +1232,50 @@ BinaryenExpressionRef BinaryenAtomicCmpxchg(BinaryenModuleRef module,
BinaryenExpressionRef ptr,
BinaryenExpressionRef expected,
BinaryenExpressionRef replacement,
- BinaryenType type) {
+ BinaryenType type,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
return static_cast<Expression*>(Builder(*(Module*)module)
.makeAtomicCmpxchg(bytes,
offset,
(Expression*)ptr,
(Expression*)expected,
(Expression*)replacement,
- Type(type)));
+ Type(type),
+ name));
}
BinaryenExpressionRef BinaryenAtomicWait(BinaryenModuleRef module,
BinaryenExpressionRef ptr,
BinaryenExpressionRef expected,
BinaryenExpressionRef timeout,
- BinaryenType expectedType) {
+ BinaryenType expectedType,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
return static_cast<Expression*>(Builder(*(Module*)module)
.makeAtomicWait((Expression*)ptr,
(Expression*)expected,
(Expression*)timeout,
Type(expectedType),
- 0));
+ 0,
+ name));
}
BinaryenExpressionRef BinaryenAtomicNotify(BinaryenModuleRef module,
BinaryenExpressionRef ptr,
- BinaryenExpressionRef notifyCount) {
+ BinaryenExpressionRef notifyCount,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
return static_cast<Expression*>(
Builder(*(Module*)module)
- .makeAtomicNotify((Expression*)ptr, (Expression*)notifyCount, 0));
+ .makeAtomicNotify((Expression*)ptr, (Expression*)notifyCount, 0, name));
}
BinaryenExpressionRef BinaryenAtomicFence(BinaryenModuleRef module) {
return static_cast<Expression*>(Builder(*(Module*)module).makeAtomicFence());
@@ -1275,11 +1331,18 @@ BinaryenExpressionRef BinaryenSIMDLoad(BinaryenModuleRef module,
BinaryenOp op,
uint32_t offset,
uint32_t align,
- BinaryenExpressionRef ptr) {
- return static_cast<Expression*>(
- Builder(*(Module*)module)
- .makeSIMDLoad(
- SIMDLoadOp(op), Address(offset), Address(align), (Expression*)ptr));
+ BinaryenExpressionRef ptr,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
+ return static_cast<Expression*>(Builder(*(Module*)module)
+ .makeSIMDLoad(SIMDLoadOp(op),
+ Address(offset),
+ Address(align),
+ (Expression*)ptr,
+ name));
}
BinaryenExpressionRef BinaryenSIMDLoadStoreLane(BinaryenModuleRef module,
BinaryenOp op,
@@ -1287,7 +1350,12 @@ BinaryenExpressionRef BinaryenSIMDLoadStoreLane(BinaryenModuleRef module,
uint32_t align,
uint8_t index,
BinaryenExpressionRef ptr,
- BinaryenExpressionRef vec) {
+ BinaryenExpressionRef vec,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
return static_cast<Expression*>(
Builder(*(Module*)module)
.makeSIMDLoadStoreLane(SIMDLoadStoreLaneOp(op),
@@ -1295,17 +1363,25 @@ BinaryenExpressionRef BinaryenSIMDLoadStoreLane(BinaryenModuleRef module,
Address(align),
index,
(Expression*)ptr,
- (Expression*)vec));
+ (Expression*)vec,
+ name));
}
BinaryenExpressionRef BinaryenMemoryInit(BinaryenModuleRef module,
uint32_t segment,
BinaryenExpressionRef dest,
BinaryenExpressionRef offset,
- BinaryenExpressionRef size) {
- return static_cast<Expression*>(
- Builder(*(Module*)module)
- .makeMemoryInit(
- segment, (Expression*)dest, (Expression*)offset, (Expression*)size));
+ BinaryenExpressionRef size,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
+ return static_cast<Expression*>(Builder(*(Module*)module)
+ .makeMemoryInit(segment,
+ (Expression*)dest,
+ (Expression*)offset,
+ (Expression*)size,
+ name));
}
BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module,
@@ -1317,21 +1393,36 @@ BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module,
BinaryenExpressionRef BinaryenMemoryCopy(BinaryenModuleRef module,
BinaryenExpressionRef dest,
BinaryenExpressionRef source,
- BinaryenExpressionRef size) {
+ BinaryenExpressionRef size,
+ const char* destMemory,
+ const char* sourceMemory) {
+ // Maintaining compatibility for instructions with a single memory
+ if ((destMemory == nullptr || sourceMemory == nullptr) &&
+ module->memories.size() == 1) {
+ destMemory = module->memories[0]->name.c_str();
+ sourceMemory = module->memories[0]->name.c_str();
+ }
return static_cast<Expression*>(Builder(*(Module*)module)
.makeMemoryCopy((Expression*)dest,
(Expression*)source,
- (Expression*)size));
+ (Expression*)size,
+ destMemory,
+ sourceMemory));
}
BinaryenExpressionRef BinaryenMemoryFill(BinaryenModuleRef module,
BinaryenExpressionRef dest,
BinaryenExpressionRef value,
- BinaryenExpressionRef size) {
- return static_cast<Expression*>(Builder(*(Module*)module)
- .makeMemoryFill((Expression*)dest,
- (Expression*)value,
- (Expression*)size));
+ BinaryenExpressionRef size,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
+ return static_cast<Expression*>(
+ Builder(*(Module*)module)
+ .makeMemoryFill(
+ (Expression*)dest, (Expression*)value, (Expression*)size, name));
}
BinaryenExpressionRef BinaryenTupleMake(BinaryenModuleRef module,
@@ -3656,10 +3747,11 @@ void BinaryenAddMemoryImport(BinaryenModuleRef module,
const char* externalModuleName,
const char* externalBaseName,
uint8_t shared) {
- auto& memory = ((Module*)module)->memory;
- memory.module = externalModuleName;
- memory.base = externalBaseName;
- memory.shared = shared;
+ auto memory = Builder::makeMemory(internalName);
+ memory->module = externalModuleName;
+ memory->base = externalBaseName;
+ memory->shared = shared;
+ ((Module*)module)->addMemory(std::move(memory));
}
void BinaryenAddGlobalImport(BinaryenModuleRef module,
const char* internalName,
@@ -3871,7 +3963,7 @@ const char* BinaryenElementSegmentGetData(BinaryenElementSegmentRef elem,
}
}
-// Memory. One per module
+// Memory.
void BinaryenSetMemory(BinaryenModuleRef module,
BinaryenIndex initial,
@@ -3882,28 +3974,35 @@ void BinaryenSetMemory(BinaryenModuleRef module,
BinaryenExpressionRef* segmentOffsets,
BinaryenIndex* segmentSizes,
BinaryenIndex numSegments,
- bool shared) {
- auto* wasm = (Module*)module;
- wasm->memory.initial = initial;
- wasm->memory.max = int32_t(maximum); // Make sure -1 extends.
- wasm->memory.exists = true;
- wasm->memory.shared = shared;
+ bool shared,
+ const char* name) {
+ auto memory = std::make_unique<Memory>();
+ memory->name = name ? name : "0";
+ memory->initial = initial;
+ memory->max = int32_t(maximum); // Make sure -1 extends.
+ memory->shared = shared;
if (exportName) {
auto memoryExport = make_unique<Export>();
memoryExport->name = exportName;
- memoryExport->value = Name::fromInt(0);
+ memoryExport->value = memory->name;
memoryExport->kind = ExternalKind::Memory;
- wasm->addExport(memoryExport.release());
+ ((Module*)module)->addExport(memoryExport.release());
}
+ ((Module*)module)->removeDataSegments([&](DataSegment* curr) {
+ return true;
+ });
for (BinaryenIndex i = 0; i < numSegments; i++) {
auto curr = Builder::makeDataSegment(Name::fromInt(i),
+ memory->name,
segmentPassive[i],
(Expression*)segmentOffsets[i],
segments[i],
segmentSizes[i]);
curr->hasExplicitName = false;
- wasm->dataSegments.push_back(std::move(curr));
+ ((Module*)module)->addDataSegment(std::move(curr));
}
+ ((Module*)module)->removeMemories([&](Memory* curr) { return true; });
+ ((Module*)module)->addMemory(std::move(memory));
}
// Memory segments
@@ -3944,35 +4043,84 @@ uint32_t BinaryenGetMemorySegmentByteOffset(BinaryenModuleRef module,
return 0;
}
bool BinaryenHasMemory(BinaryenModuleRef module) {
- return ((Module*)module)->memory.exists;
+ return !((Module*)module)->memories.empty();
}
-BinaryenIndex BinaryenMemoryGetInitial(BinaryenModuleRef module) {
- return ((Module*)module)->memory.initial;
+BinaryenIndex BinaryenMemoryGetInitial(BinaryenModuleRef module,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
+ auto* memory = ((Module*)module)->getMemoryOrNull(name);
+ if (memory == nullptr) {
+ Fatal() << "invalid memory '" << name << "'.";
+ }
+ return memory->initial;
}
-bool BinaryenMemoryHasMax(BinaryenModuleRef module) {
- return ((Module*)module)->memory.hasMax();
+bool BinaryenMemoryHasMax(BinaryenModuleRef module, const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
+ auto* memory = ((Module*)module)->getMemoryOrNull(name);
+ if (memory == nullptr) {
+ Fatal() << "invalid memory '" << name << "'.";
+ }
+ return memory->hasMax();
}
-BinaryenIndex BinaryenMemoryGetMax(BinaryenModuleRef module) {
- return ((Module*)module)->memory.max;
+BinaryenIndex BinaryenMemoryGetMax(BinaryenModuleRef module, const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
+ auto* memory = ((Module*)module)->getMemoryOrNull(name);
+ if (memory == nullptr) {
+ Fatal() << "invalid memory '" << name << "'.";
+ }
+ return memory->max;
}
-const char* BinaryenMemoryImportGetModule(BinaryenModuleRef module) {
- auto& memory = ((Module*)module)->memory;
- if (memory.imported()) {
- return memory.module.c_str();
+const char* BinaryenMemoryImportGetModule(BinaryenModuleRef module,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
+ auto* memory = ((Module*)module)->getMemoryOrNull(name);
+ if (memory == nullptr) {
+ Fatal() << "invalid memory '" << name << "'.";
+ }
+ if (memory->imported()) {
+ return memory->module.c_str();
} else {
return "";
}
}
-const char* BinaryenMemoryImportGetBase(BinaryenModuleRef module) {
- auto& memory = ((Module*)module)->memory;
- if (memory.imported()) {
- return memory.base.c_str();
+const char* BinaryenMemoryImportGetBase(BinaryenModuleRef module,
+ const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
+ auto* memory = ((Module*)module)->getMemoryOrNull(name);
+ if (memory == nullptr) {
+ Fatal() << "invalid memory '" << name << "'.";
+ }
+ if (memory->imported()) {
+ return memory->base.c_str();
} else {
return "";
}
}
-bool BinaryenMemoryIsShared(BinaryenModuleRef module) {
- return ((Module*)module)->memory.shared;
+bool BinaryenMemoryIsShared(BinaryenModuleRef module, const char* name) {
+ // Maintaining compatibility for instructions with a single memory
+ if (name == nullptr && module->memories.size() == 1) {
+ name = module->memories[0]->name.c_str();
+ }
+ auto* memory = ((Module*)module)->getMemoryOrNull(name);
+ if (memory == nullptr) {
+ Fatal() << "invalid memory '" << name << "'.";
+ }
+ return memory->shared;
}
size_t BinaryenGetMemorySegmentByteLength(BinaryenModuleRef module,
BinaryenIndex id) {
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index f02b2cb19..f5bb71eb9 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -746,7 +746,8 @@ BINARYEN_API BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module,
uint32_t offset,
uint32_t align,
BinaryenType type,
- BinaryenExpressionRef ptr);
+ BinaryenExpressionRef ptr,
+ const char* name);
// Store: align can be 0, in which case it will be the natural alignment (equal
// to bytes)
BINARYEN_API BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module,
@@ -755,7 +756,8 @@ BINARYEN_API BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module,
uint32_t align,
BinaryenExpressionRef ptr,
BinaryenExpressionRef value,
- BinaryenType type);
+ BinaryenType type,
+ const char* name);
BINARYEN_API BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module,
struct BinaryenLiteral value);
BINARYEN_API BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module,
@@ -776,25 +778,27 @@ BINARYEN_API BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module,
// Return: value can be NULL
BINARYEN_API BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module,
BinaryenExpressionRef value);
-BINARYEN_API BinaryenExpressionRef BinaryenMemorySize(BinaryenModuleRef module);
-BINARYEN_API BinaryenExpressionRef
-BinaryenMemoryGrow(BinaryenModuleRef module, BinaryenExpressionRef delta);
+BINARYEN_API BinaryenExpressionRef BinaryenMemorySize(BinaryenModuleRef module,
+ const char* name);
+BINARYEN_API BinaryenExpressionRef BinaryenMemoryGrow(
+ BinaryenModuleRef module, BinaryenExpressionRef delta, const char* name);
BINARYEN_API BinaryenExpressionRef BinaryenNop(BinaryenModuleRef module);
BINARYEN_API BinaryenExpressionRef
BinaryenUnreachable(BinaryenModuleRef module);
-BINARYEN_API BinaryenExpressionRef
-BinaryenAtomicLoad(BinaryenModuleRef module,
- uint32_t bytes,
- uint32_t offset,
- BinaryenType type,
- BinaryenExpressionRef ptr);
+BINARYEN_API BinaryenExpressionRef BinaryenAtomicLoad(BinaryenModuleRef module,
+ uint32_t bytes,
+ uint32_t offset,
+ BinaryenType type,
+ BinaryenExpressionRef ptr,
+ const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicStore(BinaryenModuleRef module,
uint32_t bytes,
uint32_t offset,
BinaryenExpressionRef ptr,
BinaryenExpressionRef value,
- BinaryenType type);
+ BinaryenType type,
+ const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicRMW(BinaryenModuleRef module,
BinaryenOp op,
@@ -802,7 +806,8 @@ BinaryenAtomicRMW(BinaryenModuleRef module,
BinaryenIndex offset,
BinaryenExpressionRef ptr,
BinaryenExpressionRef value,
- BinaryenType type);
+ BinaryenType type,
+ const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicCmpxchg(BinaryenModuleRef module,
BinaryenIndex bytes,
@@ -810,17 +815,20 @@ BinaryenAtomicCmpxchg(BinaryenModuleRef module,
BinaryenExpressionRef ptr,
BinaryenExpressionRef expected,
BinaryenExpressionRef replacement,
- BinaryenType type);
+ BinaryenType type,
+ const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicWait(BinaryenModuleRef module,
BinaryenExpressionRef ptr,
BinaryenExpressionRef expected,
BinaryenExpressionRef timeout,
- BinaryenType type);
+ BinaryenType type,
+ const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicNotify(BinaryenModuleRef module,
BinaryenExpressionRef ptr,
- BinaryenExpressionRef notifyCount);
+ BinaryenExpressionRef notifyCount,
+ const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenAtomicFence(BinaryenModuleRef module);
BINARYEN_API BinaryenExpressionRef
@@ -853,7 +861,8 @@ BINARYEN_API BinaryenExpressionRef BinaryenSIMDLoad(BinaryenModuleRef module,
BinaryenOp op,
uint32_t offset,
uint32_t align,
- BinaryenExpressionRef ptr);
+ BinaryenExpressionRef ptr,
+ const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenSIMDLoadStoreLane(BinaryenModuleRef module,
BinaryenOp op,
@@ -861,25 +870,30 @@ BinaryenSIMDLoadStoreLane(BinaryenModuleRef module,
uint32_t align,
uint8_t index,
BinaryenExpressionRef ptr,
- BinaryenExpressionRef vec);
+ BinaryenExpressionRef vec,
+ const char* name);
BINARYEN_API BinaryenExpressionRef
BinaryenMemoryInit(BinaryenModuleRef module,
uint32_t segment,
BinaryenExpressionRef dest,
BinaryenExpressionRef offset,
- BinaryenExpressionRef size);
+ BinaryenExpressionRef size,
+ const char* name);
BINARYEN_API BinaryenExpressionRef BinaryenDataDrop(BinaryenModuleRef module,
uint32_t segment);
BINARYEN_API BinaryenExpressionRef
BinaryenMemoryCopy(BinaryenModuleRef module,
BinaryenExpressionRef dest,
BinaryenExpressionRef source,
- BinaryenExpressionRef size);
+ BinaryenExpressionRef size,
+ const char* destMemory,
+ const char* sourceMemory);
BINARYEN_API BinaryenExpressionRef
BinaryenMemoryFill(BinaryenModuleRef module,
BinaryenExpressionRef dest,
BinaryenExpressionRef value,
- BinaryenExpressionRef size);
+ BinaryenExpressionRef size,
+ const char* name);
BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module,
BinaryenType type);
BINARYEN_API BinaryenExpressionRef BinaryenRefIs(BinaryenModuleRef module,
@@ -2194,6 +2208,9 @@ BINARYEN_API void BinaryenAddTagImport(BinaryenModuleRef module,
BinaryenType params,
BinaryenType results);
+// Memory
+BINARYEN_REF(Memory);
+
// Exports
BINARYEN_REF(Export);
@@ -2310,8 +2327,7 @@ BinaryenGetElementSegment(BinaryenModuleRef module, const char* name);
BINARYEN_API BinaryenElementSegmentRef
BinaryenGetElementSegmentByIndex(BinaryenModuleRef module, BinaryenIndex index);
-// Memory. One per module
-
+// This will create a memory, overwriting any existing memory
// Each memory has data in segments, a start offset in segmentOffsets, and a
// size in segmentSizes. exportName can be NULL
BINARYEN_API void BinaryenSetMemory(BinaryenModuleRef module,
@@ -2323,16 +2339,22 @@ BINARYEN_API void BinaryenSetMemory(BinaryenModuleRef module,
BinaryenExpressionRef* segmentOffsets,
BinaryenIndex* segmentSizes,
BinaryenIndex numSegments,
- bool shared);
+ bool shared,
+ const char* name);
BINARYEN_API bool BinaryenHasMemory(BinaryenModuleRef module);
-BINARYEN_API BinaryenIndex BinaryenMemoryGetInitial(BinaryenModuleRef module);
-BINARYEN_API bool BinaryenMemoryHasMax(BinaryenModuleRef module);
-BINARYEN_API BinaryenIndex BinaryenMemoryGetMax(BinaryenModuleRef module);
-BINARYEN_API const char*
-BinaryenMemoryImportGetModule(BinaryenModuleRef module);
-BINARYEN_API const char* BinaryenMemoryImportGetBase(BinaryenModuleRef module);
-BINARYEN_API bool BinaryenMemoryIsShared(BinaryenModuleRef module);
+BINARYEN_API BinaryenIndex BinaryenMemoryGetInitial(BinaryenModuleRef module,
+ const char* name);
+BINARYEN_API bool BinaryenMemoryHasMax(BinaryenModuleRef module,
+ const char* name);
+BINARYEN_API BinaryenIndex BinaryenMemoryGetMax(BinaryenModuleRef module,
+ const char* name);
+BINARYEN_API const char* BinaryenMemoryImportGetModule(BinaryenModuleRef module,
+ const char* name);
+BINARYEN_API const char* BinaryenMemoryImportGetBase(BinaryenModuleRef module,
+ const char* name);
+BINARYEN_API bool BinaryenMemoryIsShared(BinaryenModuleRef module,
+ const char* name);
// Memory segments. Query utilities.
diff --git a/src/ir/import-utils.h b/src/ir/import-utils.h
index 2e7a4f44c..d0b5a8042 100644
--- a/src/ir/import-utils.h
+++ b/src/ir/import-utils.h
@@ -30,6 +30,7 @@ struct ImportInfo {
std::vector<Global*> importedGlobals;
std::vector<Function*> importedFunctions;
std::vector<Table*> importedTables;
+ std::vector<Memory*> importedMemories;
std::vector<Tag*> importedTags;
ImportInfo(Module& wasm) : wasm(wasm) {
@@ -48,6 +49,11 @@ struct ImportInfo {
importedTables.push_back(import.get());
}
}
+ for (auto& import : wasm.memories) {
+ if (import->imported()) {
+ importedMemories.push_back(import.get());
+ }
+ }
for (auto& import : wasm.tags) {
if (import->imported()) {
importedTags.push_back(import.get());
@@ -88,11 +94,13 @@ struct ImportInfo {
Index getNumImportedTables() { return importedTables.size(); }
+ Index getNumImportedMemories() { return importedMemories.size(); }
+
Index getNumImportedTags() { return importedTags.size(); }
Index getNumImports() {
return getNumImportedGlobals() + getNumImportedFunctions() +
- getNumImportedTags() + (wasm.memory.imported() ? 1 : 0) +
+ getNumImportedTags() + getNumImportedMemories() +
getNumImportedTables();
}
@@ -108,6 +116,10 @@ struct ImportInfo {
return wasm.tables.size() - getNumImportedTables();
}
+ Index getNumDefinedMemories() {
+ return wasm.memories.size() - getNumImportedMemories();
+ }
+
Index getNumDefinedTags() { return wasm.tags.size() - getNumImportedTags(); }
};
diff --git a/src/ir/memory-utils.cpp b/src/ir/memory-utils.cpp
index 8dc3baeb9..f1471b7a4 100644
--- a/src/ir/memory-utils.cpp
+++ b/src/ir/memory-utils.cpp
@@ -20,6 +20,10 @@
namespace wasm::MemoryUtils {
bool flatten(Module& wasm) {
+ // Flatten does not currently have support for multi-memories
+ if (wasm.memories.size() > 1) {
+ return false;
+ }
// The presence of any MemoryInit instructions is a problem because they care
// about segment identity, which flattening gets rid of ( when it merges them
// all into one big segment).
@@ -62,7 +66,6 @@ bool flatten(Module& wasm) {
}
std::copy(segment->data.begin(), segment->data.end(), data.begin() + start);
}
- dataSegments.resize(1);
dataSegments[0]->offset->cast<Const>()->value = Literal(int32_t(0));
dataSegments[0]->data.swap(data);
wasm.removeDataSegments(
diff --git a/src/ir/memory-utils.h b/src/ir/memory-utils.h
index 5e9086ca4..9bdd00258 100644
--- a/src/ir/memory-utils.h
+++ b/src/ir/memory-utils.h
@@ -30,19 +30,25 @@ namespace wasm::MemoryUtils {
// Flattens memory into a single data segment, or no segment. If there is
// a segment, it starts at 0.
// Returns true if successful (e.g. relocatable segments cannot be flattened).
+// Does not yet support multi-memories
bool flatten(Module& wasm);
-// Ensures that the memory exists (of minimal size).
-inline void ensureExists(Memory& memory) {
- if (!memory.exists) {
- memory.exists = true;
- memory.initial = memory.max = 1;
+// Ensures that a memory exists (of minimal size).
+inline void ensureExists(Module* wasm) {
+ if (wasm->memories.empty()) {
+ auto memory = Builder::makeMemory("0");
+ memory->initial = memory->max = 1;
+ wasm->addMemory(std::move(memory));
}
}
// Try to merge segments until they fit into web limitations.
// Return true if successful.
+// Does not yet support multi-memories
inline bool ensureLimitedSegments(Module& module) {
+ if (module.memories.size() > 1) {
+ return false;
+ }
auto& dataSegments = module.dataSegments;
if (dataSegments.size() <= WebLimitations::MaxDataSegments) {
return true;
@@ -136,6 +142,7 @@ inline bool ensureLimitedSegments(Module& module) {
c->type = Type::i32;
auto combined = Builder::makeDataSegment();
+ combined->memory = module.memories[0]->name;
combined->offset = c;
for (Index j = i; j < dataSegments.size(); j++) {
auto& segment = dataSegments[j];
@@ -156,6 +163,7 @@ inline bool ensureLimitedSegments(Module& module) {
}
dataSegments.swap(mergedSegments);
+ module.updateDataSegmentsMap();
return true;
}
} // namespace wasm::MemoryUtils
diff --git a/src/ir/module-splitting.cpp b/src/ir/module-splitting.cpp
index e24dd6452..8294e1575 100644
--- a/src/ir/module-splitting.cpp
+++ b/src/ir/module-splitting.cpp
@@ -612,14 +612,9 @@ void ModuleSplitter::shareImportableItems() {
// TODO: Be more selective by only sharing global items that are actually used
// in the secondary module, just like we do for functions.
- if (primary.memory.exists) {
- secondary.memory.exists = true;
- secondary.memory.initial = primary.memory.initial;
- secondary.memory.max = primary.memory.max;
- secondary.memory.shared = primary.memory.shared;
- secondary.memory.indexType = primary.memory.indexType;
- makeImportExport(
- primary.memory, secondary.memory, "memory", ExternalKind::Memory);
+ for (auto& memory : primary.memories) {
+ auto secondaryMemory = ModuleUtils::copyMemory(memory.get(), secondary);
+ makeImportExport(*memory, *secondaryMemory, "memory", ExternalKind::Memory);
}
for (auto& table : primary.tables) {
diff --git a/src/ir/module-utils.h b/src/ir/module-utils.h
index 4f731748e..81f832b40 100644
--- a/src/ir/module-utils.h
+++ b/src/ir/module-utils.h
@@ -106,10 +106,22 @@ inline Table* copyTable(const Table* table, Module& out) {
return out.addTable(std::move(ret));
}
+inline Memory* copyMemory(const Memory* memory, Module& out) {
+ auto ret = Builder::makeMemory(memory->name);
+ ret->hasExplicitName = memory->hasExplicitName;
+ ret->initial = memory->initial;
+ ret->max = memory->max;
+ ret->shared = memory->shared;
+ ret->indexType = memory->indexType;
+
+ return out.addMemory(std::move(ret));
+}
+
inline DataSegment* copyDataSegment(const DataSegment* segment, Module& out) {
auto ret = Builder::makeDataSegment();
ret->name = segment->name;
ret->hasExplicitName = segment->hasExplicitName;
+ ret->memory = segment->memory;
ret->isPassive = segment->isPassive;
if (!segment->isPassive) {
auto offset = ExpressionManipulator::copy(segment->offset, out);
@@ -141,10 +153,12 @@ inline void copyModule(const Module& in, Module& out) {
for (auto& curr : in.tables) {
copyTable(curr.get(), out);
}
+ for (auto& curr : in.memories) {
+ copyMemory(curr.get(), out);
+ }
for (auto& curr : in.dataSegments) {
copyDataSegment(curr.get(), out);
}
- out.memory = in.memory;
out.start = in.start;
out.userSections = in.userSections;
out.debugInfoFileNames = in.debugInfoFileNames;
@@ -207,14 +221,27 @@ inline void renameFunction(Module& wasm, Name oldName, Name newName) {
// Convenient iteration over imported/non-imported module elements
template<typename T> inline void iterImportedMemories(Module& wasm, T visitor) {
- if (wasm.memory.exists && wasm.memory.imported()) {
- visitor(&wasm.memory);
+ for (auto& import : wasm.memories) {
+ if (import->imported()) {
+ visitor(import.get());
+ }
}
}
template<typename T> inline void iterDefinedMemories(Module& wasm, T visitor) {
- if (wasm.memory.exists && !wasm.memory.imported()) {
- visitor(&wasm.memory);
+ for (auto& import : wasm.memories) {
+ if (!import->imported()) {
+ visitor(import.get());
+ }
+ }
+}
+
+template<typename T>
+inline void iterMemorySegments(Module& wasm, Name memory, T visitor) {
+ for (auto& segment : wasm.dataSegments) {
+ if (!segment->isPassive && segment->memory == memory) {
+ visitor(segment.get());
+ }
}
}
diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js
index 6ba5454e9..53930e16c 100644
--- a/src/js/binaryen.js-post.js
+++ b/src/js/binaryen.js-post.js
@@ -687,30 +687,30 @@ function wrapModule(module, self = {}) {
}
self['memory'] = {
- 'size'() {
- return Module['_BinaryenMemorySize'](module);
+ 'size'(name) {
+ return Module['_BinaryenMemorySize'](module, strToStack(name));
},
- 'grow'(value) {
- return Module['_BinaryenMemoryGrow'](module, value);
+ 'grow'(value, name) {
+ return Module['_BinaryenMemoryGrow'](module, value, strToStack(name));
},
- 'init'(segment, dest, offset, size) {
- return Module['_BinaryenMemoryInit'](module, segment, dest, offset, size);
+ 'init'(segment, dest, offset, size, name) {
+ return Module['_BinaryenMemoryInit'](module, segment, dest, offset, size, strToStack(name));
},
- 'copy'(dest, source, size) {
- return Module['_BinaryenMemoryCopy'](module, dest, source, size);
+ 'copy'(dest, source, size, destMemory, sourceMemory) {
+ return Module['_BinaryenMemoryCopy'](module, dest, source, size, strToStack(destMemory), strToStack(sourceMemory));
},
- 'fill'(dest, value, size) {
- return Module['_BinaryenMemoryFill'](module, dest, value, size);
+ 'fill'(dest, value, size, name) {
+ return Module['_BinaryenMemoryFill'](module, dest, value, size, strToStack(name));
},
'atomic': {
- 'notify'(ptr, notifyCount) {
- return Module['_BinaryenAtomicNotify'](module, ptr, notifyCount);
+ 'notify'(ptr, notifyCount, name) {
+ return Module['_BinaryenAtomicNotify'](module, ptr, notifyCount, strToStack(name));
},
- 'wait32'(ptr, expected, timeout) {
- return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i32']);
+ 'wait32'(ptr, expected, timeout, name) {
+ return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i32'], strToStack(name));
},
- 'wait64'(ptr, expected, timeout) {
- return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i64']);
+ 'wait64'(ptr, expected, timeout, name) {
+ return Module['_BinaryenAtomicWait'](module, ptr, expected, timeout, Module['i64'], strToStack(name));
}
}
}
@@ -722,29 +722,29 @@ function wrapModule(module, self = {}) {
}
self['i32'] = {
- 'load'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['i32'], ptr);
+ 'load'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['i32'], ptr, strToStack(name));
},
- 'load8_s'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 1, true, offset, align, Module['i32'], ptr);
+ 'load8_s'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 1, true, offset, align, Module['i32'], ptr, strToStack(name));
},
- 'load8_u'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 1, false, offset, align, Module['i32'], ptr);
+ 'load8_u'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 1, false, offset, align, Module['i32'], ptr, strToStack(name));
},
- 'load16_s'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 2, true, offset, align, Module['i32'], ptr);
+ 'load16_s'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 2, true, offset, align, Module['i32'], ptr, strToStack(name));
},
- 'load16_u'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 2, false, offset, align, Module['i32'], ptr);
+ 'load16_u'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 2, false, offset, align, Module['i32'], ptr, strToStack(name));
},
- 'store'(offset, align, ptr, value) {
- return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i32']);
+ 'store'(offset, align, ptr, value, name) {
+ return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i32'], strToStack(name));
},
- 'store8'(offset, align, ptr, value) {
- return Module['_BinaryenStore'](module, 1, offset, align, ptr, value, Module['i32']);
+ 'store8'(offset, align, ptr, value, name) {
+ return Module['_BinaryenStore'](module, 1, offset, align, ptr, value, Module['i32'], strToStack(name));
},
- 'store16'(offset, align, ptr, value) {
- return Module['_BinaryenStore'](module, 2, offset, align, ptr, value, Module['i32']);
+ 'store16'(offset, align, ptr, value, name) {
+ return Module['_BinaryenStore'](module, 2, offset, align, ptr, value, Module['i32'], strToStack(name));
},
'const'(x) {
return preserveStack(() => {
@@ -885,91 +885,91 @@ function wrapModule(module, self = {}) {
return Module['_BinaryenBinary'](module, Module['GeUInt32'], left, right);
},
'atomic': {
- 'load'(offset, ptr) {
- return Module['_BinaryenAtomicLoad'](module, 4, offset, Module['i32'], ptr);
+ 'load'(offset, ptr, name) {
+ return Module['_BinaryenAtomicLoad'](module, 4, offset, Module['i32'], ptr, strToStack(name));
},
- 'load8_u'(offset, ptr) {
- return Module['_BinaryenAtomicLoad'](module, 1, offset, Module['i32'], ptr);
+ 'load8_u'(offset, ptr, name) {
+ return Module['_BinaryenAtomicLoad'](module, 1, offset, Module['i32'], ptr, strToStack(name));
},
- 'load16_u'(offset, ptr) {
- return Module['_BinaryenAtomicLoad'](module, 2, offset, Module['i32'], ptr);
+ 'load16_u'(offset, ptr, name) {
+ return Module['_BinaryenAtomicLoad'](module, 2, offset, Module['i32'], ptr, strToStack(name));
},
- 'store'(offset, ptr, value) {
- return Module['_BinaryenAtomicStore'](module, 4, offset, ptr, value, Module['i32']);
+ 'store'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicStore'](module, 4, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'store8'(offset, ptr, value) {
- return Module['_BinaryenAtomicStore'](module, 1, offset, ptr, value, Module['i32']);
+ 'store8'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicStore'](module, 1, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'store16'(offset, ptr, value) {
- return Module['_BinaryenAtomicStore'](module, 2, offset, ptr, value, Module['i32']);
+ 'store16'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicStore'](module, 2, offset, ptr, value, Module['i32'], strToStack(name));
},
'rmw': {
- 'add'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 4, offset, ptr, value, Module['i32']);
+ 'add'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 4, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'sub'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 4, offset, ptr, value, Module['i32']);
+ 'sub'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 4, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'and'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 4, offset, ptr, value, Module['i32']);
+ 'and'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 4, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'or'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 4, offset, ptr, value, Module['i32']);
+ 'or'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 4, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'xor'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 4, offset, ptr, value, Module['i32']);
+ 'xor'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 4, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'xchg'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 4, offset, ptr, value, Module['i32']);
+ 'xchg'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 4, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'cmpxchg'(offset, ptr, expected, replacement) {
- return Module['_BinaryenAtomicCmpxchg'](module, 4, offset, ptr, expected, replacement, Module['i32'])
+ 'cmpxchg'(offset, ptr, expected, replacement, name) {
+ return Module['_BinaryenAtomicCmpxchg'](module, 4, offset, ptr, expected, replacement, Module['i32'], strToStack(name))
},
},
'rmw8_u': {
- 'add'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 1, offset, ptr, value, Module['i32']);
+ 'add'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 1, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'sub'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 1, offset, ptr, value, Module['i32']);
+ 'sub'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 1, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'and'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 1, offset, ptr, value, Module['i32']);
+ 'and'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 1, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'or'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 1, offset, ptr, value, Module['i32']);
+ 'or'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 1, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'xor'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 1, offset, ptr, value, Module['i32']);
+ 'xor'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 1, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'xchg'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 1, offset, ptr, value, Module['i32']);
+ 'xchg'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 1, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'cmpxchg'(offset, ptr, expected, replacement) {
- return Module['_BinaryenAtomicCmpxchg'](module, 1, offset, ptr, expected, replacement, Module['i32'])
+ 'cmpxchg'(offset, ptr, expected, replacement, name) {
+ return Module['_BinaryenAtomicCmpxchg'](module, 1, offset, ptr, expected, replacement, Module['i32'], strToStack(name))
},
},
'rmw16_u': {
- 'add'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 2, offset, ptr, value, Module['i32']);
+ 'add'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 2, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'sub'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 2, offset, ptr, value, Module['i32']);
+ 'sub'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 2, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'and'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 2, offset, ptr, value, Module['i32']);
+ 'and'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 2, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'or'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 2, offset, ptr, value, Module['i32']);
+ 'or'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 2, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'xor'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 2, offset, ptr, value, Module['i32']);
+ 'xor'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 2, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'xchg'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 2, offset, ptr, value, Module['i32']);
+ 'xchg'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 2, offset, ptr, value, Module['i32'], strToStack(name));
},
- 'cmpxchg'(offset, ptr, expected, replacement) {
- return Module['_BinaryenAtomicCmpxchg'](module, 2, offset, ptr, expected, replacement, Module['i32'])
+ 'cmpxchg'(offset, ptr, expected, replacement, name) {
+ return Module['_BinaryenAtomicCmpxchg'](module, 2, offset, ptr, expected, replacement, Module['i32'], strToStack(name))
},
},
},
@@ -979,38 +979,38 @@ function wrapModule(module, self = {}) {
};
self['i64'] = {
- 'load'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 8, true, offset, align, Module['i64'], ptr);
+ 'load'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 8, true, offset, align, Module['i64'], ptr, strToStack(name));
},
- 'load8_s'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 1, true, offset, align, Module['i64'], ptr);
+ 'load8_s'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 1, true, offset, align, Module['i64'], ptr, strToStack(name));
},
- 'load8_u'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 1, false, offset, align, Module['i64'], ptr);
+ 'load8_u'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 1, false, offset, align, Module['i64'], ptr, strToStack(name));
},
- 'load16_s'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 2, true, offset, align, Module['i64'], ptr);
+ 'load16_s'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 2, true, offset, align, Module['i64'], ptr, strToStack(name));
},
- 'load16_u'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 2, false, offset, align, Module['i64'], ptr);
+ 'load16_u'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 2, false, offset, align, Module['i64'], ptr, strToStack(name));
},
- 'load32_s'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['i64'], ptr);
+ 'load32_s'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['i64'], ptr, strToStack(name));
},
- 'load32_u'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 4, false, offset, align, Module['i64'], ptr);
+ 'load32_u'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 4, false, offset, align, Module['i64'], ptr, strToStack(name));
},
- 'store'(offset, align, ptr, value) {
- return Module['_BinaryenStore'](module, 8, offset, align, ptr, value, Module['i64']);
+ 'store'(offset, align, ptr, value, name) {
+ return Module['_BinaryenStore'](module, 8, offset, align, ptr, value, Module['i64'], strToStack(name));
},
- 'store8'(offset, align, ptr, value) {
- return Module['_BinaryenStore'](module, 1, offset, align, ptr, value, Module['i64']);
+ 'store8'(offset, align, ptr, value, name) {
+ return Module['_BinaryenStore'](module, 1, offset, align, ptr, value, Module['i64'], strToStack(name));
},
- 'store16'(offset, align, ptr, value) {
- return Module['_BinaryenStore'](module, 2, offset, align, ptr, value, Module['i64']);
+ 'store16'(offset, align, ptr, value, name) {
+ return Module['_BinaryenStore'](module, 2, offset, align, ptr, value, Module['i64'], strToStack(name));
},
- 'store32'(offset, align, ptr, value) {
- return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i64']);
+ 'store32'(offset, align, ptr, value, name) {
+ return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['i64'], strToStack(name));
},
'const'(x, y) {
return preserveStack(() => {
@@ -1157,120 +1157,120 @@ function wrapModule(module, self = {}) {
return Module['_BinaryenBinary'](module, Module['GeUInt64'], left, right);
},
'atomic': {
- 'load'(offset, ptr) {
- return Module['_BinaryenAtomicLoad'](module, 8, offset, Module['i64'], ptr);
+ 'load'(offset, ptr, name) {
+ return Module['_BinaryenAtomicLoad'](module, 8, offset, Module['i64'], ptr, strToStack(name));
},
- 'load8_u'(offset, ptr) {
- return Module['_BinaryenAtomicLoad'](module, 1, offset, Module['i64'], ptr);
+ 'load8_u'(offset, ptr, name) {
+ return Module['_BinaryenAtomicLoad'](module, 1, offset, Module['i64'], ptr, strToStack(name));
},
- 'load16_u'(offset, ptr) {
- return Module['_BinaryenAtomicLoad'](module, 2, offset, Module['i64'], ptr);
+ 'load16_u'(offset, ptr, name) {
+ return Module['_BinaryenAtomicLoad'](module, 2, offset, Module['i64'], ptr, strToStack(name));
},
- 'load32_u'(offset, ptr) {
- return Module['_BinaryenAtomicLoad'](module, 4, offset, Module['i64'], ptr);
+ 'load32_u'(offset, ptr, name) {
+ return Module['_BinaryenAtomicLoad'](module, 4, offset, Module['i64'], ptr, strToStack(name));
},
- 'store'(offset, ptr, value) {
- return Module['_BinaryenAtomicStore'](module, 8, offset, ptr, value, Module['i64']);
+ 'store'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicStore'](module, 8, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'store8'(offset, ptr, value) {
- return Module['_BinaryenAtomicStore'](module, 1, offset, ptr, value, Module['i64']);
+ 'store8'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicStore'](module, 1, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'store16'(offset, ptr, value) {
- return Module['_BinaryenAtomicStore'](module, 2, offset, ptr, value, Module['i64']);
+ 'store16'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicStore'](module, 2, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'store32'(offset, ptr, value) {
- return Module['_BinaryenAtomicStore'](module, 4, offset, ptr, value, Module['i64']);
+ 'store32'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicStore'](module, 4, offset, ptr, value, Module['i64'], strToStack(name));
},
'rmw': {
- 'add'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 8, offset, ptr, value, Module['i64']);
+ 'add'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 8, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'sub'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 8, offset, ptr, value, Module['i64']);
+ 'sub'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 8, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'and'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 8, offset, ptr, value, Module['i64']);
+ 'and'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 8, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'or'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 8, offset, ptr, value, Module['i64']);
+ 'or'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 8, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'xor'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 8, offset, ptr, value, Module['i64']);
+ 'xor'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 8, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'xchg'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 8, offset, ptr, value, Module['i64']);
+ 'xchg'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 8, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'cmpxchg'(offset, ptr, expected, replacement) {
- return Module['_BinaryenAtomicCmpxchg'](module, 8, offset, ptr, expected, replacement, Module['i64'])
+ 'cmpxchg'(offset, ptr, expected, replacement, name) {
+ return Module['_BinaryenAtomicCmpxchg'](module, 8, offset, ptr, expected, replacement, Module['i64'], strToStack(name))
},
},
'rmw8_u': {
- 'add'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 1, offset, ptr, value, Module['i64']);
+ 'add'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 1, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'sub'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 1, offset, ptr, value, Module['i64']);
+ 'sub'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 1, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'and'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 1, offset, ptr, value, Module['i64']);
+ 'and'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 1, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'or'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 1, offset, ptr, value, Module['i64']);
+ 'or'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 1, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'xor'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 1, offset, ptr, value, Module['i64']);
+ 'xor'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 1, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'xchg'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 1, offset, ptr, value, Module['i64']);
+ 'xchg'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 1, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'cmpxchg'(offset, ptr, expected, replacement) {
- return Module['_BinaryenAtomicCmpxchg'](module, 1, offset, ptr, expected, replacement, Module['i64'])
+ 'cmpxchg'(offset, ptr, expected, replacement, name) {
+ return Module['_BinaryenAtomicCmpxchg'](module, 1, offset, ptr, expected, replacement, Module['i64'], strToStack(name))
},
},
'rmw16_u': {
- 'add'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 2, offset, ptr, value, Module['i64']);
+ 'add'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 2, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'sub'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 2, offset, ptr, value, Module['i64']);
+ 'sub'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 2, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'and'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 2, offset, ptr, value, Module['i64']);
+ 'and'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 2, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'or'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 2, offset, ptr, value, Module['i64']);
+ 'or'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 2, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'xor'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 2, offset, ptr, value, Module['i64']);
+ 'xor'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 2, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'xchg'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 2, offset, ptr, value, Module['i64']);
+ 'xchg'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 2, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'cmpxchg'(offset, ptr, expected, replacement) {
- return Module['_BinaryenAtomicCmpxchg'](module, 2, offset, ptr, expected, replacement, Module['i64'])
+ 'cmpxchg'(offset, ptr, expected, replacement, name) {
+ return Module['_BinaryenAtomicCmpxchg'](module, 2, offset, ptr, expected, replacement, Module['i64'], strToStack(name))
},
},
'rmw32_u': {
- 'add'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 4, offset, ptr, value, Module['i64']);
+ 'add'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAdd'], 4, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'sub'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 4, offset, ptr, value, Module['i64']);
+ 'sub'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWSub'], 4, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'and'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 4, offset, ptr, value, Module['i64']);
+ 'and'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWAnd'], 4, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'or'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 4, offset, ptr, value, Module['i64']);
+ 'or'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWOr'], 4, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'xor'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 4, offset, ptr, value, Module['i64']);
+ 'xor'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXor'], 4, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'xchg'(offset, ptr, value) {
- return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 4, offset, ptr, value, Module['i64']);
+ 'xchg'(offset, ptr, value, name) {
+ return Module['_BinaryenAtomicRMW'](module, Module['AtomicRMWXchg'], 4, offset, ptr, value, Module['i64'], strToStack(name));
},
- 'cmpxchg'(offset, ptr, expected, replacement) {
- return Module['_BinaryenAtomicCmpxchg'](module, 4, offset, ptr, expected, replacement, Module['i64'])
+ 'cmpxchg'(offset, ptr, expected, replacement, name) {
+ return Module['_BinaryenAtomicCmpxchg'](module, 4, offset, ptr, expected, replacement, Module['i64'], strToStack(name))
},
},
},
@@ -1280,11 +1280,11 @@ function wrapModule(module, self = {}) {
};
self['f32'] = {
- 'load'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['f32'], ptr);
+ 'load'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 4, true, offset, align, Module['f32'], ptr, strToStack(name));
},
- 'store'(offset, align, ptr, value) {
- return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['f32']);
+ 'store'(offset, align, ptr, value, name) {
+ return Module['_BinaryenStore'](module, 4, offset, align, ptr, value, Module['f32'], strToStack(name));
},
'const'(x) {
return preserveStack(() => {
@@ -1388,11 +1388,11 @@ function wrapModule(module, self = {}) {
};
self['f64'] = {
- 'load'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 8, true, offset, align, Module['f64'], ptr);
+ 'load'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 8, true, offset, align, Module['f64'], ptr, strToStack(name));
},
- 'store'(offset, align, ptr, value) {
- return Module['_BinaryenStore'](module, 8, offset, align, ptr, value, Module['f64']);
+ 'store'(offset, align, ptr, value, name) {
+ return Module['_BinaryenStore'](module, 8, offset, align, ptr, value, Module['f64'], strToStack(name));
},
'const'(x) {
return preserveStack(() => {
@@ -1496,71 +1496,71 @@ function wrapModule(module, self = {}) {
};
self['v128'] = {
- 'load'(offset, align, ptr) {
- return Module['_BinaryenLoad'](module, 16, false, offset, align, Module['v128'], ptr);
+ 'load'(offset, align, ptr, name) {
+ return Module['_BinaryenLoad'](module, 16, false, offset, align, Module['v128'], ptr, strToStack(name));
},
- 'load8_splat'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load8SplatVec128'], offset, align, ptr);
+ 'load8_splat'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load8SplatVec128'], offset, align, ptr, strToStack(name));
},
- 'load16_splat'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load16SplatVec128'], offset, align, ptr);
+ 'load16_splat'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load16SplatVec128'], offset, align, ptr, strToStack(name));
},
- 'load32_splat'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load32SplatVec128'], offset, align, ptr);
+ 'load32_splat'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load32SplatVec128'], offset, align, ptr, strToStack(name));
},
- 'load64_splat'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load64SplatVec128'], offset, align, ptr);
+ 'load64_splat'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load64SplatVec128'], offset, align, ptr, strToStack(name));
},
- 'load8x8_s'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load8x8SVec128'], offset, align, ptr);
+ 'load8x8_s'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load8x8SVec128'], offset, align, ptr, strToStack(name));
},
- 'load8x8_u'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load8x8UVec128'], offset, align, ptr);
+ 'load8x8_u'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load8x8UVec128'], offset, align, ptr, strToStack(name));
},
- 'load16x4_s'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load16x4SVec128'], offset, align, ptr);
+ 'load16x4_s'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load16x4SVec128'], offset, align, ptr, strToStack(name));
},
- 'load16x4_u'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load16x4UVec128'], offset, align, ptr);
+ 'load16x4_u'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load16x4UVec128'], offset, align, ptr, strToStack(name));
},
- 'load32x2_s'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load32x2SVec128'], offset, align, ptr);
+ 'load32x2_s'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load32x2SVec128'], offset, align, ptr, strToStack(name));
},
- 'load32x2_u'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load32x2UVec128'], offset, align, ptr);
+ 'load32x2_u'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load32x2UVec128'], offset, align, ptr, strToStack(name));
},
- 'load32_zero'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load32ZeroVec128'], offset, align, ptr);
+ 'load32_zero'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load32ZeroVec128'], offset, align, ptr, strToStack(name));
},
- 'load64_zero'(offset, align, ptr) {
- return Module['_BinaryenSIMDLoad'](module, Module['Load64ZeroVec128'], offset, align, ptr);
+ 'load64_zero'(offset, align, ptr, name) {
+ return Module['_BinaryenSIMDLoad'](module, Module['Load64ZeroVec128'], offset, align, ptr, strToStack(name));
},
- 'load8_lane'(offset, align, index, ptr, vec) {
- return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load8LaneVec128'], offset, align, index, ptr, vec);
+ 'load8_lane'(offset, align, index, ptr, vec, name) {
+ return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load8LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
},
- 'load16_lane'(offset, align, index, ptr, vec) {
- return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load16LaneVec128'], offset, align, index, ptr, vec);
+ 'load16_lane'(offset, align, index, ptr, vec, name) {
+ return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load16LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
},
- 'load32_lane'(offset, align, index, ptr, vec) {
- return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load32LaneVec128'], offset, align, index, ptr, vec);
+ 'load32_lane'(offset, align, index, ptr, vec, name) {
+ return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load32LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
},
- 'load64_lane'(offset, align, index, ptr, vec) {
- return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load64LaneVec128'], offset, align, index, ptr, vec);
+ 'load64_lane'(offset, align, index, ptr, vec, name) {
+ return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Load64LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
},
- 'store8_lane'(offset, align, index, ptr, vec) {
- return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store8LaneVec128'], offset, align, index, ptr, vec);
+ 'store8_lane'(offset, align, index, ptr, vec, name) {
+ return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store8LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
},
- 'store16_lane'(offset, align, index, ptr, vec) {
- return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store16LaneVec128'], offset, align, index, ptr, vec);
+ 'store16_lane'(offset, align, index, ptr, vec, name) {
+ return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store16LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
},
- 'store32_lane'(offset, align, index, ptr, vec) {
- return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store32LaneVec128'], offset, align, index, ptr, vec);
+ 'store32_lane'(offset, align, index, ptr, vec, name) {
+ return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store32LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
},
- 'store64_lane'(offset, align, index, ptr, vec) {
- return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store64LaneVec128'], offset, align, index, ptr, vec);
+ 'store64_lane'(offset, align, index, ptr, vec, name) {
+ return Module['_BinaryenSIMDLoadStoreLane'](module, Module['Store64LaneVec128'], offset, align, index, ptr, vec, strToStack(name));
},
- 'store'(offset, align, ptr, value) {
- return Module['_BinaryenStore'](module, 16, offset, align, ptr, value, Module['v128']);
+ 'store'(offset, align, ptr, value, name) {
+ return Module['_BinaryenStore'](module, 16, offset, align, ptr, value, Module['v128'], strToStack(name));
},
'const'(i8s) {
return preserveStack(() => {
@@ -2501,7 +2501,7 @@ function wrapModule(module, self = {}) {
self['removeExport'] = function(externalName) {
return preserveStack(() => Module['_BinaryenRemoveExport'](module, strToStack(externalName)));
};
- self['setMemory'] = function(initial, maximum, exportName, segments = [], shared = false) {
+ self['setMemory'] = function(initial, maximum, exportName, segments = [], shared = false, internalName) {
// segments are assumed to be { passive: bool, offset: expression ref, data: array of 8-bit data }
return preserveStack(() => {
const segmentsLen = segments.length;
@@ -2524,22 +2524,23 @@ function wrapModule(module, self = {}) {
i32sToStack(segmentOffset),
i32sToStack(segmentDataLen),
segmentsLen,
- shared
+ shared,
+ strToStack(internalName)
);
});
};
self['hasMemory'] = function() {
return Boolean(Module['_BinaryenHasMemory'](module));
};
- self['getMemoryInfo'] = function() {
+ self['getMemoryInfo'] = function(name) {
var memoryInfo = {
- 'module': UTF8ToString(Module['_BinaryenMemoryImportGetModule'](module)),
- 'base': UTF8ToString(Module['_BinaryenMemoryImportGetBase'](module)),
- 'initial': Module['_BinaryenMemoryGetInitial'](module),
- 'shared': Boolean(Module['_BinaryenMemoryIsShared'](module))
+ 'module': UTF8ToString(Module['_BinaryenMemoryImportGetModule'](module, strToStack(name))),
+ 'base': UTF8ToString(Module['_BinaryenMemoryImportGetBase'](module, strToStack(name))),
+ 'initial': Module['_BinaryenMemoryGetInitial'](module, strToStack(name)),
+ 'shared': Boolean(Module['_BinaryenMemoryIsShared'](module, strToStack(name)))
};
- if (Module['_BinaryenMemoryHasMax'](module)) {
- memoryInfo['max'] = Module['_BinaryenMemoryGetMax'](module);
+ if (Module['_BinaryenMemoryHasMax'](module, strToStack(name))) {
+ memoryInfo['max'] = Module['_BinaryenMemoryGetMax'](module, strToStack(name));
}
return memoryInfo;
};
diff --git a/src/passes/AlignmentLowering.cpp b/src/passes/AlignmentLowering.cpp
index 8cab58072..d0ceeb610 100644
--- a/src/passes/AlignmentLowering.cpp
+++ b/src/passes/AlignmentLowering.cpp
@@ -34,7 +34,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
if (curr->align == 0 || curr->align == curr->bytes) {
return curr;
}
- auto indexType = getModule()->memory.indexType;
+ auto mem = getModule()->getMemory(curr->memory);
+ auto indexType = mem->indexType;
Builder builder(*getModule());
assert(curr->type == Type::i32);
auto temp = builder.addVar(getFunction(), indexType);
@@ -47,7 +48,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->offset,
1,
builder.makeLocalGet(temp, indexType),
- Type::i32),
+ Type::i32,
+ curr->memory),
builder.makeBinary(
ShlInt32,
builder.makeLoad(1,
@@ -55,7 +57,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->offset + 1,
1,
builder.makeLocalGet(temp, indexType),
- Type::i32),
+ Type::i32,
+ curr->memory),
builder.makeConst(int32_t(8))));
if (curr->signed_) {
ret = Bits::makeSignExt(ret, 2, *getModule());
@@ -71,7 +74,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->offset,
1,
builder.makeLocalGet(temp, indexType),
- Type::i32),
+ Type::i32,
+ curr->memory),
builder.makeBinary(
ShlInt32,
builder.makeLoad(1,
@@ -79,7 +83,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->offset + 1,
1,
builder.makeLocalGet(temp, indexType),
- Type::i32),
+ Type::i32,
+ curr->memory),
builder.makeConst(int32_t(8)))),
builder.makeBinary(
OrInt32,
@@ -90,7 +95,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->offset + 2,
1,
builder.makeLocalGet(temp, indexType),
- Type::i32),
+ Type::i32,
+ curr->memory),
builder.makeConst(int32_t(16))),
builder.makeBinary(
ShlInt32,
@@ -99,7 +105,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->offset + 3,
1,
builder.makeLocalGet(temp, indexType),
- Type::i32),
+ Type::i32,
+ curr->memory),
builder.makeConst(int32_t(24)))));
} else if (curr->align == 2) {
ret = builder.makeBinary(
@@ -109,7 +116,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->offset,
2,
builder.makeLocalGet(temp, indexType),
- Type::i32),
+ Type::i32,
+ curr->memory),
builder.makeBinary(
ShlInt32,
builder.makeLoad(2,
@@ -117,7 +125,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->offset + 2,
2,
builder.makeLocalGet(temp, indexType),
- Type::i32),
+ Type::i32,
+ curr->memory),
builder.makeConst(int32_t(16))));
} else {
WASM_UNREACHABLE("invalid alignment");
@@ -135,7 +144,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
}
Builder builder(*getModule());
assert(curr->value->type == Type::i32);
- auto indexType = getModule()->memory.indexType;
+ auto mem = getModule()->getMemory(curr->memory);
+ auto indexType = mem->indexType;
auto tempPtr = builder.addVar(getFunction(), indexType);
auto tempValue = builder.addVar(getFunction(), Type::i32);
auto* block =
@@ -148,7 +158,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
1,
builder.makeLocalGet(tempPtr, indexType),
builder.makeLocalGet(tempValue, Type::i32),
- Type::i32));
+ Type::i32,
+ curr->memory));
block->list.push_back(builder.makeStore(
1,
curr->offset + 1,
@@ -157,7 +168,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
builder.makeBinary(ShrUInt32,
builder.makeLocalGet(tempValue, Type::i32),
builder.makeConst(int32_t(8))),
- Type::i32));
+ Type::i32,
+ curr->memory));
} else if (curr->bytes == 4) {
if (curr->align == 1) {
block->list.push_back(
@@ -166,7 +178,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
1,
builder.makeLocalGet(tempPtr, indexType),
builder.makeLocalGet(tempValue, Type::i32),
- Type::i32));
+ Type::i32,
+ curr->memory));
block->list.push_back(builder.makeStore(
1,
curr->offset + 1,
@@ -175,7 +188,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
builder.makeBinary(ShrUInt32,
builder.makeLocalGet(tempValue, Type::i32),
builder.makeConst(int32_t(8))),
- Type::i32));
+ Type::i32,
+ curr->memory));
block->list.push_back(builder.makeStore(
1,
curr->offset + 2,
@@ -184,7 +198,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
builder.makeBinary(ShrUInt32,
builder.makeLocalGet(tempValue, Type::i32),
builder.makeConst(int32_t(16))),
- Type::i32));
+ Type::i32,
+ curr->memory));
block->list.push_back(builder.makeStore(
1,
curr->offset + 3,
@@ -193,7 +208,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
builder.makeBinary(ShrUInt32,
builder.makeLocalGet(tempValue, Type::i32),
builder.makeConst(int32_t(24))),
- Type::i32));
+ Type::i32,
+ curr->memory));
} else if (curr->align == 2) {
block->list.push_back(
builder.makeStore(2,
@@ -201,7 +217,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
2,
builder.makeLocalGet(tempPtr, indexType),
builder.makeLocalGet(tempValue, Type::i32),
- Type::i32));
+ Type::i32,
+ curr->memory));
block->list.push_back(builder.makeStore(
2,
curr->offset + 2,
@@ -210,7 +227,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
builder.makeBinary(ShrUInt32,
builder.makeLocalGet(tempValue, Type::i32),
builder.makeConst(int32_t(16))),
- Type::i32));
+ Type::i32,
+ curr->memory));
} else {
WASM_UNREACHABLE("invalid alignment");
}
@@ -256,7 +274,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
break;
}
// Load two 32-bit pieces, and combine them.
- auto indexType = getModule()->memory.indexType;
+ auto mem = getModule()->getMemory(curr->memory);
+ auto indexType = mem->indexType;
auto temp = builder.addVar(getFunction(), indexType);
auto* set = builder.makeLocalSet(temp, curr->ptr);
Expression* low =
@@ -265,7 +284,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->offset,
curr->align,
builder.makeLocalGet(temp, indexType),
- Type::i32));
+ Type::i32,
+ curr->memory));
low = builder.makeUnary(ExtendUInt32, low);
// Note that the alignment is assumed to be the same here, even though
// we add an offset of 4. That is because this is an unaligned load, so
@@ -277,7 +297,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->offset + 4,
curr->align,
builder.makeLocalGet(temp, indexType),
- Type::i32));
+ Type::i32,
+ curr->memory));
high = builder.makeUnary(ExtendUInt32, high);
high =
builder.makeBinary(ShlInt64, high, builder.makeConst(int64_t(32)));
@@ -335,7 +356,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
value = builder.makeUnary(ReinterpretFloat64, value);
}
// Store as two 32-bit pieces.
- auto indexType = getModule()->memory.indexType;
+ auto mem = getModule()->getMemory(curr->memory);
+ auto indexType = mem->indexType;
auto tempPtr = builder.addVar(getFunction(), indexType);
auto* setPtr = builder.makeLocalSet(tempPtr, curr->ptr);
auto tempValue = builder.addVar(getFunction(), Type::i64);
@@ -348,7 +370,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->align,
builder.makeLocalGet(tempPtr, indexType),
low,
- Type::i32));
+ Type::i32,
+ curr->memory));
Expression* high =
builder.makeBinary(ShrUInt64,
builder.makeLocalGet(tempValue, Type::i64),
@@ -364,7 +387,8 @@ struct AlignmentLowering : public WalkerPass<PostWalker<AlignmentLowering>> {
curr->align,
builder.makeLocalGet(tempPtr, indexType),
high,
- Type::i32));
+ Type::i32,
+ curr->memory));
replacement = builder.makeBlock({setPtr, setValue, low, high});
break;
}
diff --git a/src/passes/Asyncify.cpp b/src/passes/Asyncify.cpp
index 8a50d49e6..b076c77d4 100644
--- a/src/passes/Asyncify.cpp
+++ b/src/passes/Asyncify.cpp
@@ -794,7 +794,9 @@ static bool doesCall(Expression* curr) {
class AsyncifyBuilder : public Builder {
public:
- AsyncifyBuilder(Module& wasm) : Builder(wasm) {}
+ Module& wasm;
+
+ AsyncifyBuilder(Module& wasm) : Builder(wasm), wasm(wasm) {}
Expression* makeGetStackPos() {
return makeLoad(4,
@@ -802,7 +804,8 @@ public:
int32_t(DataOffset::BStackPos),
4,
makeGlobalGet(ASYNCIFY_DATA, Type::i32),
- Type::i32);
+ Type::i32,
+ wasm.memories[0]->name);
}
Expression* makeIncStackPos(int32_t by) {
@@ -815,7 +818,8 @@ public:
4,
makeGlobalGet(ASYNCIFY_DATA, Type::i32),
makeBinary(AddInt32, makeGetStackPos(), makeConst(Literal(by))),
- Type::i32);
+ Type::i32,
+ wasm.memories[0]->name);
}
Expression* makeStateCheck(State value) {
@@ -1222,8 +1226,13 @@ struct AsyncifyLocals : public WalkerPass<PostWalker<AsyncifyLocals>> {
builder->makeIncStackPos(-4),
builder->makeLocalSet(
rewindIndex,
- builder->makeLoad(
- 4, false, 0, 4, builder->makeGetStackPos(), Type::i32))));
+ builder->makeLoad(4,
+ false,
+ 0,
+ 4,
+ builder->makeGetStackPos(),
+ Type::i32,
+ getModule()->memories[0]->name))));
} else if (curr->target == ASYNCIFY_CHECK_CALL_INDEX) {
replaceCurrent(builder->makeBinary(
EqInt32,
@@ -1392,7 +1401,8 @@ private:
offset,
STACK_ALIGN,
builder->makeLocalGet(tempIndex, Type::i32),
- type));
+ type,
+ getModule()->memories[0]->name));
offset += size;
}
Expression* load;
@@ -1440,7 +1450,8 @@ private:
STACK_ALIGN,
builder->makeLocalGet(tempIndex, Type::i32),
localGet,
- type));
+ type,
+ getModule()->memories[0]->name));
offset += size;
++j;
}
@@ -1458,7 +1469,8 @@ private:
4,
builder->makeGetStackPos(),
builder->makeLocalGet(tempIndex, Type::i32),
- Type::i32),
+ Type::i32,
+ getModule()->memories[0]->name),
builder->makeIncStackPos(4));
}
@@ -1483,7 +1495,7 @@ struct Asyncify : public Pass {
bool optimize = runner->options.optimizeLevel > 0;
// Ensure there is a memory, as we need it.
- MemoryUtils::ensureExists(module->memory);
+ MemoryUtils::ensureExists(module);
// Find which things can change the state.
auto stateChangingImports = String::trim(read_possible_response_file(
@@ -1659,14 +1671,16 @@ private:
int32_t(DataOffset::BStackPos),
4,
builder.makeGlobalGet(ASYNCIFY_DATA, Type::i32),
- Type::i32);
+ Type::i32,
+ module->memories[0]->name);
auto* stackEnd =
builder.makeLoad(4,
false,
int32_t(DataOffset::BStackEnd),
4,
builder.makeGlobalGet(ASYNCIFY_DATA, Type::i32),
- Type::i32);
+ Type::i32,
+ module->memories[0]->name);
body->list.push_back(
builder.makeIf(builder.makeBinary(GtUInt32, stackPos, stackEnd),
builder.makeUnreachable()));
diff --git a/src/passes/AvoidReinterprets.cpp b/src/passes/AvoidReinterprets.cpp
index c2607725d..feea4871f 100644
--- a/src/passes/AvoidReinterprets.cpp
+++ b/src/passes/AvoidReinterprets.cpp
@@ -115,11 +115,11 @@ struct AvoidReinterprets : public WalkerPass<PostWalker<AvoidReinterprets>> {
void optimize(Function* func) {
std::set<Load*> unoptimizables;
- auto indexType = getModule()->memory.indexType;
for (auto& [load, info] : infos) {
if (info.reinterpreted && canReplaceWithReinterpret(load)) {
// We should use another load here, to avoid reinterprets.
- info.ptrLocal = Builder::addVar(func, indexType);
+ auto mem = getModule()->getMemory(load->memory);
+ info.ptrLocal = Builder::addVar(func, mem->indexType);
info.reinterpretedLocal =
Builder::addVar(func, load->type.reinterpret());
} else {
@@ -173,7 +173,8 @@ struct AvoidReinterprets : public WalkerPass<PostWalker<AvoidReinterprets>> {
auto& info = iter->second;
Builder builder(*module);
auto* ptr = curr->ptr;
- auto indexType = getModule()->memory.indexType;
+ auto mem = getModule()->getMemory(curr->memory);
+ auto indexType = mem->indexType;
curr->ptr = builder.makeLocalGet(info.ptrLocal, indexType);
// Note that the other load can have its sign set to false - if the
// original were an integer, the other is a float anyhow; and if
@@ -195,7 +196,8 @@ struct AvoidReinterprets : public WalkerPass<PostWalker<AvoidReinterprets>> {
load->offset,
load->align,
ptr,
- load->type.reinterpret());
+ load->type.reinterpret(),
+ load->memory);
}
} finalOptimizer(infos, localGraph, getModule(), getPassOptions());
diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp
index 11707d4f3..002e4568d 100644
--- a/src/passes/I64ToI32Lowering.cpp
+++ b/src/passes/I64ToI32Lowering.cpp
@@ -386,7 +386,8 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
curr->offset + 4,
std::min(uint32_t(curr->align), uint32_t(4)),
builder->makeLocalGet(ptrTemp, Type::i32),
- Type::i32));
+ Type::i32,
+ curr->memory));
} else if (curr->signed_) {
loadHigh = builder->makeLocalSet(
highBits,
@@ -432,7 +433,8 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
std::min(uint32_t(curr->align), uint32_t(4)),
builder->makeLocalGet(ptrTemp, Type::i32),
builder->makeLocalGet(highBits, Type::i32),
- Type::i32);
+ Type::i32,
+ curr->memory);
replaceCurrent(builder->blockify(setPtr, curr, storeHigh));
}
}
@@ -594,7 +596,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
Type::i32));
setOutParam(result, std::move(highBits));
replaceCurrent(result);
- MemoryUtils::ensureExists(getModule()->memory);
+ MemoryUtils::ensureExists(getModule());
ABI::wasm2js::ensureHelpers(getModule());
}
@@ -612,7 +614,7 @@ struct I64ToI32Lowering : public WalkerPass<PostWalker<I64ToI32Lowering>> {
Type::none),
builder->makeCall(ABI::wasm2js::SCRATCH_LOAD_F64, {}, Type::f64));
replaceCurrent(result);
- MemoryUtils::ensureExists(getModule()->memory);
+ MemoryUtils::ensureExists(getModule());
ABI::wasm2js::ensureHelpers(getModule());
}
diff --git a/src/passes/InstrumentMemory.cpp b/src/passes/InstrumentMemory.cpp
index 1180c5183..486bc7c1f 100644
--- a/src/passes/InstrumentMemory.cpp
+++ b/src/passes/InstrumentMemory.cpp
@@ -100,8 +100,9 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
void visitLoad(Load* curr) {
id++;
Builder builder(*getModule());
- auto indexType = getModule()->memory.indexType;
- auto offset = builder.makeConstPtr(curr->offset.addr);
+ auto mem = getModule()->getMemory(curr->memory);
+ auto indexType = mem->indexType;
+ auto offset = builder.makeConstPtr(curr->offset.addr, indexType);
curr->ptr = builder.makeCall(load_ptr,
{builder.makeConst(int32_t(id)),
builder.makeConst(int32_t(curr->bytes)),
@@ -132,8 +133,9 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
void visitStore(Store* curr) {
id++;
Builder builder(*getModule());
- auto indexType = getModule()->memory.indexType;
- auto offset = builder.makeConstPtr(curr->offset.addr);
+ auto mem = getModule()->getMemory(curr->memory);
+ auto indexType = mem->indexType;
+ auto offset = builder.makeConstPtr(curr->offset.addr, indexType);
curr->ptr = builder.makeCall(store_ptr,
{builder.makeConst(int32_t(id)),
builder.makeConst(int32_t(curr->bytes)),
@@ -246,7 +248,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
}
void visitModule(Module* curr) {
- auto indexType = curr->memory.indexType;
+ auto indexType =
+ curr->memories.empty() ? Type::i32 : curr->memories[0]->indexType;
// Load.
addImport(
diff --git a/src/passes/Memory64Lowering.cpp b/src/passes/Memory64Lowering.cpp
index 4c2770e3a..7e581c22b 100644
--- a/src/passes/Memory64Lowering.cpp
+++ b/src/passes/Memory64Lowering.cpp
@@ -30,79 +30,101 @@ namespace wasm {
struct Memory64Lowering : public WalkerPass<PostWalker<Memory64Lowering>> {
void run(PassRunner* runner, Module* module) override {
- if (module->memory.is64()) {
- super::run(runner, module);
- }
+ super::run(runner, module);
}
- void wrapAddress64(Expression*& ptr) {
+ void wrapAddress64(Expression*& ptr, Name memoryName) {
if (ptr->type == Type::unreachable) {
return;
}
auto& module = *getModule();
- assert(module.memory.is64());
- assert(ptr->type == Type::i64);
- Builder builder(module);
- ptr = builder.makeUnary(UnaryOp::WrapInt64, ptr);
+ auto memory = module.getMemory(memoryName);
+ if (memory->is64()) {
+ assert(ptr->type == Type::i64);
+ Builder builder(module);
+ ptr = builder.makeUnary(UnaryOp::WrapInt64, ptr);
+ }
}
- void extendAddress64(Expression*& ptr) {
+ void extendAddress64(Expression*& ptr, Name memoryName) {
if (ptr->type == Type::unreachable) {
return;
}
auto& module = *getModule();
- assert(module.memory.is64());
- assert(ptr->type == Type::i64);
- ptr->type = Type::i32;
- Builder builder(module);
- ptr = builder.makeUnary(UnaryOp::ExtendUInt32, ptr);
+ auto memory = module.getMemory(memoryName);
+ if (memory->is64()) {
+ assert(ptr->type == Type::i64);
+ ptr->type = Type::i32;
+ Builder builder(module);
+ ptr = builder.makeUnary(UnaryOp::ExtendUInt32, ptr);
+ }
}
- void visitLoad(Load* curr) { wrapAddress64(curr->ptr); }
+ void visitLoad(Load* curr) { wrapAddress64(curr->ptr, curr->memory); }
- void visitStore(Store* curr) { wrapAddress64(curr->ptr); }
+ void visitStore(Store* curr) { wrapAddress64(curr->ptr, curr->memory); }
void visitMemorySize(MemorySize* curr) {
- auto size = static_cast<Expression*>(curr);
- extendAddress64(size);
- curr->ptrType = Type::i32;
- replaceCurrent(size);
+ auto& module = *getModule();
+ auto memory = module.getMemory(curr->memory);
+ if (memory->is64()) {
+ auto size = static_cast<Expression*>(curr);
+ extendAddress64(size, curr->memory);
+ curr->ptrType = Type::i32;
+ replaceCurrent(size);
+ }
}
void visitMemoryGrow(MemoryGrow* curr) {
- wrapAddress64(curr->delta);
- auto size = static_cast<Expression*>(curr);
- extendAddress64(size);
- curr->ptrType = Type::i32;
- replaceCurrent(size);
+ auto& module = *getModule();
+ auto memory = module.getMemory(curr->memory);
+ if (memory->is64()) {
+ wrapAddress64(curr->delta, curr->memory);
+ auto size = static_cast<Expression*>(curr);
+ extendAddress64(size, curr->memory);
+ curr->ptrType = Type::i32;
+ replaceCurrent(size);
+ }
}
- void visitMemoryInit(MemoryInit* curr) { wrapAddress64(curr->dest); }
+ void visitMemoryInit(MemoryInit* curr) {
+ wrapAddress64(curr->dest, curr->memory);
+ }
void visitMemoryFill(MemoryFill* curr) {
- wrapAddress64(curr->dest);
- wrapAddress64(curr->size);
+ wrapAddress64(curr->dest, curr->memory);
+ wrapAddress64(curr->size, curr->memory);
}
void visitMemoryCopy(MemoryCopy* curr) {
- wrapAddress64(curr->dest);
- wrapAddress64(curr->source);
- wrapAddress64(curr->size);
+ wrapAddress64(curr->dest, curr->destMemory);
+ wrapAddress64(curr->source, curr->sourceMemory);
+ wrapAddress64(curr->size, curr->destMemory);
}
- void visitAtomicRMW(AtomicRMW* curr) { wrapAddress64(curr->ptr); }
+ void visitAtomicRMW(AtomicRMW* curr) {
+ wrapAddress64(curr->ptr, curr->memory);
+ }
- void visitAtomicCmpxchg(AtomicCmpxchg* curr) { wrapAddress64(curr->ptr); }
+ void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+ wrapAddress64(curr->ptr, curr->memory);
+ }
- void visitAtomicWait(AtomicWait* curr) { wrapAddress64(curr->ptr); }
+ void visitAtomicWait(AtomicWait* curr) {
+ wrapAddress64(curr->ptr, curr->memory);
+ }
- void visitAtomicNotify(AtomicNotify* curr) { wrapAddress64(curr->ptr); }
+ void visitAtomicNotify(AtomicNotify* curr) {
+ wrapAddress64(curr->ptr, curr->memory);
+ }
void visitMemory(Memory* memory) {
// This is visited last.
- memory->indexType = Type::i32;
- if (memory->hasMax() && memory->max > Memory::kMaxSize32) {
- memory->max = Memory::kMaxSize32;
+ if (memory->is64()) {
+ memory->indexType = Type::i32;
+ if (memory->hasMax() && memory->max > Memory::kMaxSize32) {
+ memory->max = Memory::kMaxSize32;
+ }
}
}
diff --git a/src/passes/MemoryPacking.cpp b/src/passes/MemoryPacking.cpp
index 3be08e7b9..cd4a6698d 100644
--- a/src/passes/MemoryPacking.cpp
+++ b/src/passes/MemoryPacking.cpp
@@ -83,24 +83,26 @@ const size_t DATA_DROP_SIZE = 3;
Expression*
makeGtShiftedMemorySize(Builder& builder, Module& module, MemoryInit* curr) {
+ auto mem = module.getMemory(curr->memory);
return builder.makeBinary(
- module.memory.is64() ? GtUInt64 : GtUInt32,
+ mem->is64() ? GtUInt64 : GtUInt32,
curr->dest,
- builder.makeBinary(module.memory.is64() ? ShlInt64 : ShlInt32,
- builder.makeMemorySize(),
- builder.makeConstPtr(16)));
+ builder.makeBinary(mem->is64() ? ShlInt64 : ShlInt32,
+ builder.makeMemorySize(mem->name),
+ builder.makeConstPtr(16, mem->indexType)));
}
} // anonymous namespace
struct MemoryPacking : public Pass {
void run(PassRunner* runner, Module* module) override;
- bool canOptimize(const Memory& memory,
+ bool canOptimize(std::vector<std::unique_ptr<Memory>>& memories,
std::vector<std::unique_ptr<DataSegment>>& dataSegments,
const PassOptions& passOptions);
void optimizeBulkMemoryOps(PassRunner* runner, Module* module);
void getSegmentReferrers(Module* module, ReferrersMap& referrers);
- void dropUnusedSegments(std::vector<std::unique_ptr<DataSegment>>& segments,
+ void dropUnusedSegments(Module* module,
+ std::vector<std::unique_ptr<DataSegment>>& segments,
ReferrersMap& referrers);
bool canSplit(const std::unique_ptr<DataSegment>& segment,
const Referrers& referrers);
@@ -123,7 +125,8 @@ struct MemoryPacking : public Pass {
};
void MemoryPacking::run(PassRunner* runner, Module* module) {
- if (!canOptimize(module->memory, module->dataSegments, runner->options)) {
+ // Does not have multi-memories support
+ if (!canOptimize(module->memories, module->dataSegments, runner->options)) {
return;
}
@@ -140,7 +143,7 @@ void MemoryPacking::run(PassRunner* runner, Module* module) {
// like, such as memory.inits not having both zero offset and size.
optimizeBulkMemoryOps(runner, module);
getSegmentReferrers(module, referrers);
- dropUnusedSegments(segments, referrers);
+ dropUnusedSegments(module, segments, referrers);
}
// The new, split memory segments
@@ -171,6 +174,7 @@ void MemoryPacking::run(PassRunner* runner, Module* module) {
}
segments.swap(packed);
+ module->updateDataSegmentsMap();
if (module->features.hasBulkMemory()) {
replaceBulkMemoryOps(runner, module, replacements);
@@ -178,17 +182,17 @@ void MemoryPacking::run(PassRunner* runner, Module* module) {
}
bool MemoryPacking::canOptimize(
- const Memory& memory,
+ std::vector<std::unique_ptr<Memory>>& memories,
std::vector<std::unique_ptr<DataSegment>>& dataSegments,
const PassOptions& passOptions) {
- if (!memory.exists) {
+ if (memories.empty() || memories.size() > 1) {
return false;
}
-
+ auto& memory = memories[0];
// We must optimize under the assumption that memory has been initialized to
// zero. That is the case for a memory declared in the module, but for a
// memory that is imported, we must be told that it is zero-initialized.
- if (memory.imported() && !passOptions.zeroFilledMemory) {
+ if (memory->imported() && !passOptions.zeroFilledMemory) {
return false;
}
@@ -472,6 +476,7 @@ void MemoryPacking::getSegmentReferrers(Module* module,
}
void MemoryPacking::dropUnusedSegments(
+ Module* module,
std::vector<std::unique_ptr<DataSegment>>& segments,
ReferrersMap& referrers) {
std::vector<std::unique_ptr<DataSegment>> usedSegments;
@@ -508,6 +513,7 @@ void MemoryPacking::dropUnusedSegments(
}
}
std::swap(segments, usedSegments);
+ module->updateDataSegmentsMap();
std::swap(referrers, usedReferrers);
}
@@ -563,6 +569,7 @@ void MemoryPacking::createSplitSegments(
segmentCount++;
}
auto curr = Builder::makeDataSegment(name,
+ segment->memory,
segment->isPassive,
offset,
&segment->data[range.start],
@@ -711,11 +718,12 @@ void MemoryPacking::createReplacements(Module* module,
// Create new memory.init or memory.fill
if (range.isZero) {
Expression* value = builder.makeConst(Literal::makeZero(Type::i32));
- appendResult(builder.makeMemoryFill(dest, value, size));
+ appendResult(builder.makeMemoryFill(dest, value, size, init->memory));
} else {
size_t offsetBytes = std::max(start, range.start) - range.start;
Expression* offset = builder.makeConst(int32_t(offsetBytes));
- appendResult(builder.makeMemoryInit(initIndex, dest, offset, size));
+ appendResult(
+ builder.makeMemoryInit(initIndex, dest, offset, size, init->memory));
initIndex++;
}
}
diff --git a/src/passes/Metrics.cpp b/src/passes/Metrics.cpp
index 70d79c12c..480273da9 100644
--- a/src/passes/Metrics.cpp
+++ b/src/passes/Metrics.cpp
@@ -54,22 +54,25 @@ struct Metrics
ModuleUtils::iterDefinedGlobals(*module,
[&](Global* curr) { walkGlobal(curr); });
- // add imports / funcs / globals / exports / tables
+ // add imports / funcs / globals / exports / tables / memories
counts["[imports]"] = imports.getNumImports();
counts["[funcs]"] = imports.getNumDefinedFunctions();
counts["[globals]"] = imports.getNumDefinedGlobals();
counts["[tags]"] = imports.getNumDefinedTags();
counts["[exports]"] = module->exports.size();
counts["[tables]"] = imports.getNumDefinedTables();
+ counts["[memories]"] = imports.getNumDefinedMemories();
// add memory
- walkMemory(&module->memory);
+ for (auto& memory : module->memories) {
+ walkMemory(memory.get());
+ }
Index size = 0;
for (auto& segment : module->dataSegments) {
walkDataSegment(segment.get());
size += segment->data.size();
}
- if (!module->dataSegments.empty()) {
+ if (!module->memories.empty()) {
counts["[memory-data]"] = size;
}
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index e3a5774b1..4fe26e8ee 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -1159,14 +1159,14 @@ struct OptimizeInstructions
if (curr->type == Type::unreachable) {
return;
}
- optimizeMemoryAccess(curr->ptr, curr->offset);
+ optimizeMemoryAccess(curr->ptr, curr->offset, curr->memory);
}
void visitStore(Store* curr) {
if (curr->type == Type::unreachable) {
return;
}
- optimizeMemoryAccess(curr->ptr, curr->offset);
+ optimizeMemoryAccess(curr->ptr, curr->offset, curr->memory);
optimizeStoredValue(curr->value, curr->bytes);
if (auto* unary = curr->value->dynCast<Unary>()) {
if (unary->op == WrapInt64) {
@@ -2912,7 +2912,7 @@ private:
}
// fold constant factors into the offset
- void optimizeMemoryAccess(Expression*& ptr, Address& offset) {
+ void optimizeMemoryAccess(Expression*& ptr, Address& offset, Name memory) {
// ptr may be a const, but it isn't worth folding that in (we still have a
// const); in fact, it's better to do the opposite for gzip purposes as well
// as for readability.
@@ -2920,7 +2920,8 @@ private:
if (last) {
uint64_t value64 = last->value.getInteger();
uint64_t offset64 = offset;
- if (getModule()->memory.is64()) {
+ auto mem = getModule()->getMemory(memory);
+ if (mem->is64()) {
last->value = Literal(int64_t(value64 + offset64));
offset = 0;
} else {
@@ -3797,36 +3798,53 @@ private:
case 1:
case 2:
case 4: {
- return builder.makeStore(
- bytes, // bytes
- 0, // offset
- 1, // align
- memCopy->dest,
- builder.makeLoad(bytes, false, 0, 1, memCopy->source, Type::i32),
- Type::i32);
+ return builder.makeStore(bytes, // bytes
+ 0, // offset
+ 1, // align
+ memCopy->dest,
+ builder.makeLoad(bytes,
+ false,
+ 0,
+ 1,
+ memCopy->source,
+ Type::i32,
+ memCopy->sourceMemory),
+ Type::i32,
+ memCopy->destMemory);
}
case 8: {
- return builder.makeStore(
- bytes, // bytes
- 0, // offset
- 1, // align
- memCopy->dest,
- builder.makeLoad(bytes, false, 0, 1, memCopy->source, Type::i64),
- Type::i64);
+ return builder.makeStore(bytes, // bytes
+ 0, // offset
+ 1, // align
+ memCopy->dest,
+ builder.makeLoad(bytes,
+ false,
+ 0,
+ 1,
+ memCopy->source,
+ Type::i64,
+ memCopy->sourceMemory),
+ Type::i64,
+ memCopy->destMemory);
}
case 16: {
if (options.shrinkLevel == 0) {
// This adds an extra 2 bytes so apply it only for
// minimal shrink level
if (getModule()->features.hasSIMD()) {
- return builder.makeStore(
- bytes, // bytes
- 0, // offset
- 1, // align
- memCopy->dest,
- builder.makeLoad(
- bytes, false, 0, 1, memCopy->source, Type::v128),
- Type::v128);
+ return builder.makeStore(bytes, // bytes
+ 0, // offset
+ 1, // align
+ memCopy->dest,
+ builder.makeLoad(bytes,
+ false,
+ 0,
+ 1,
+ memCopy->source,
+ Type::v128,
+ memCopy->sourceMemory),
+ Type::v128,
+ memCopy->destMemory);
}
}
break;
@@ -3873,7 +3891,8 @@ private:
align,
memFill->dest,
builder.makeConst<uint32_t>(value),
- Type::i32);
+ Type::i32,
+ memFill->memory);
}
case 2: {
return builder.makeStore(2,
@@ -3881,7 +3900,8 @@ private:
align,
memFill->dest,
builder.makeConst<uint32_t>(value * 0x0101U),
- Type::i32);
+ Type::i32,
+ memFill->memory);
}
case 4: {
// transform only when "value" or shrinkLevel equal to zero due to
@@ -3893,7 +3913,8 @@ private:
align,
memFill->dest,
builder.makeConst<uint32_t>(value * 0x01010101U),
- Type::i32);
+ Type::i32,
+ memFill->memory);
}
break;
}
@@ -3907,7 +3928,8 @@ private:
align,
memFill->dest,
builder.makeConst<uint64_t>(value * 0x0101010101010101ULL),
- Type::i64);
+ Type::i64,
+ memFill->memory);
}
break;
}
@@ -3921,7 +3943,8 @@ private:
align,
memFill->dest,
builder.makeConst<uint8_t[16]>(values),
- Type::v128);
+ Type::v128,
+ memFill->memory);
} else {
// { i64.store(d, C', 0), i64.store(d, C', 8) }
auto destType = memFill->dest->type;
@@ -3933,14 +3956,16 @@ private:
align,
builder.makeLocalTee(tempLocal, memFill->dest, destType),
builder.makeConst<uint64_t>(value * 0x0101010101010101ULL),
- Type::i64),
+ Type::i64,
+ memFill->memory),
builder.makeStore(
8,
offset + 8,
align,
builder.makeLocalGet(tempLocal, destType),
builder.makeConst<uint64_t>(value * 0x0101010101010101ULL),
- Type::i64),
+ Type::i64,
+ memFill->memory),
});
}
}
@@ -3952,8 +3977,13 @@ private:
}
// memory.fill(d, v, 1) ==> store8(d, v)
if (bytes == 1LL) {
- return builder.makeStore(
- 1, offset, align, memFill->dest, memFill->value, Type::i32);
+ return builder.makeStore(1,
+ offset,
+ align,
+ memFill->dest,
+ memFill->value,
+ Type::i32,
+ memFill->memory);
}
return nullptr;
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 62dc58c48..87c33ed93 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -59,6 +59,14 @@ std::ostream& printName(Name name, std::ostream& o) {
return o;
}
+std::ostream& printMemoryName(Name name, std::ostream& o, Module* wasm) {
+ if (!wasm || wasm->memories.size() > 1) {
+ o << ' ';
+ printName(name, o);
+ }
+ return o;
+}
+
static std::ostream& printLocal(Index index, Function* func, std::ostream& o) {
Name name;
if (func) {
@@ -521,6 +529,7 @@ struct PrintExpressionContents
o << (curr->signed_ ? "_s" : "_u");
}
restoreNormalColor(o);
+ printMemoryName(curr->memory, o, wasm);
if (curr->offset) {
o << " offset=" << curr->offset;
}
@@ -546,6 +555,7 @@ struct PrintExpressionContents
}
}
restoreNormalColor(o);
+ printMemoryName(curr->memory, o, wasm);
if (curr->offset) {
o << " offset=" << curr->offset;
}
@@ -596,6 +606,7 @@ struct PrintExpressionContents
o << "_u";
}
restoreNormalColor(o);
+ printMemoryName(curr->memory, o, wasm);
if (curr->offset) {
o << " offset=" << curr->offset;
}
@@ -609,6 +620,7 @@ struct PrintExpressionContents
o << "_u";
}
restoreNormalColor(o);
+ printMemoryName(curr->memory, o, wasm);
if (curr->offset) {
o << " offset=" << curr->offset;
}
@@ -619,12 +631,14 @@ struct PrintExpressionContents
assert(type == Type::i32 || type == Type::i64);
o << "memory.atomic.wait" << (type == Type::i32 ? "32" : "64");
restoreNormalColor(o);
+ printMemoryName(curr->memory, o, wasm);
if (curr->offset) {
o << " offset=" << curr->offset;
}
}
void visitAtomicNotify(AtomicNotify* curr) {
printMedium(o, "memory.atomic.notify");
+ printMemoryName(curr->memory, o, wasm);
if (curr->offset) {
o << " offset=" << curr->offset;
}
@@ -813,6 +827,7 @@ struct PrintExpressionContents
break;
}
restoreNormalColor(o);
+ printMemoryName(curr->memory, o, wasm);
if (curr->offset) {
o << " offset=" << curr->offset;
}
@@ -849,6 +864,7 @@ struct PrintExpressionContents
break;
}
restoreNormalColor(o);
+ printMemoryName(curr->memory, o, wasm);
if (curr->offset) {
o << " offset=" << curr->offset;
}
@@ -861,6 +877,7 @@ struct PrintExpressionContents
prepareColor(o);
o << "memory.init";
restoreNormalColor(o);
+ printMemoryName(curr->memory, o, wasm);
o << ' ' << curr->segment;
}
void visitDataDrop(DataDrop* curr) {
@@ -873,11 +890,14 @@ struct PrintExpressionContents
prepareColor(o);
o << "memory.copy";
restoreNormalColor(o);
+ printMemoryName(curr->destMemory, o, wasm);
+ printMemoryName(curr->sourceMemory, o, wasm);
}
void visitMemoryFill(MemoryFill* curr) {
prepareColor(o);
o << "memory.fill";
restoreNormalColor(o);
+ printMemoryName(curr->memory, o, wasm);
}
void visitConst(Const* curr) {
o << curr->value.type << ".const " << curr->value;
@@ -1917,8 +1937,14 @@ struct PrintExpressionContents
}
void visitDrop(Drop* curr) { printMedium(o, "drop"); }
void visitReturn(Return* curr) { printMedium(o, "return"); }
- void visitMemorySize(MemorySize* curr) { printMedium(o, "memory.size"); }
- void visitMemoryGrow(MemoryGrow* curr) { printMedium(o, "memory.grow"); }
+ void visitMemorySize(MemorySize* curr) {
+ printMedium(o, "memory.size");
+ printMemoryName(curr->memory, o, wasm);
+ }
+ void visitMemoryGrow(MemoryGrow* curr) {
+ printMedium(o, "memory.grow");
+ printMemoryName(curr->memory, o, wasm);
+ }
void visitRefNull(RefNull* curr) {
printMedium(o, "ref.null ");
printHeapType(o, curr->type.getHeapType(), wasm);
@@ -3129,14 +3155,11 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> {
o << ")";
}
void visitMemory(Memory* curr) {
- if (!curr->exists) {
- return;
- }
if (curr->imported()) {
doIndent(o, indent);
o << '(';
emitImportHeader(curr);
- printMemoryHeader(&currModule->memory);
+ printMemoryHeader(curr);
o << ')' << maybeNewLine;
} else {
doIndent(o, indent);
@@ -3390,6 +3413,7 @@ public:
PrintSExpression print(o);
print.setFull(true);
print.setDebugInfo(runner->options.debugInfo);
+ print.currModule = module;
print.visitModule(module);
}
};
@@ -3407,6 +3431,7 @@ public:
PrintSExpression print(o);
print.setDebugInfo(runner->options.debugInfo);
print.setStackIR(true);
+ print.currModule = module;
print.visitModule(module);
}
};
diff --git a/src/passes/RemoveNonJSOps.cpp b/src/passes/RemoveNonJSOps.cpp
index 1c112e760..84df4ec1e 100644
--- a/src/passes/RemoveNonJSOps.cpp
+++ b/src/passes/RemoveNonJSOps.cpp
@@ -122,7 +122,7 @@ struct RemoveNonJSOpsPass : public WalkerPass<PostWalker<RemoveNonJSOpsPass>> {
}
// Intrinsics may use memory, so ensure the module has one.
- MemoryUtils::ensureExists(module->memory);
+ MemoryUtils::ensureExists(module);
// Add missing globals
for (auto& [name, type] : neededImportedGlobals) {
diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp
index 7116475cd..1b1174745 100644
--- a/src/passes/RemoveUnusedModuleElements.cpp
+++ b/src/passes/RemoveUnusedModuleElements.cpp
@@ -38,6 +38,7 @@ typedef std::pair<ModuleElementKind, Name> ModuleElement;
// Finds reachabilities
// TODO: use Effects to determine if a memory is used
+// This pass does not have multi-memories support
struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
Module* module;
@@ -281,7 +282,7 @@ struct RemoveUnusedModuleElements : public Pass {
}
// Check for special imports, which are roots.
bool importsMemory = false;
- if (module->memory.imported()) {
+ if (!module->memories.empty() && module->memories[0]->imported()) {
importsMemory = true;
}
// For now, all functions that can be called indirectly are marked as roots.
@@ -367,13 +368,10 @@ struct RemoveUnusedModuleElements : public Pass {
if (!importsMemory) {
// The memory is unobservable to the outside, we can remove the
// contents.
- module->dataSegments.clear();
+ module->removeDataSegments([&](DataSegment* curr) { return true; });
}
- if (module->dataSegments.empty()) {
- module->memory.exists = false;
- module->memory.module = module->memory.base = Name();
- module->memory.initial = 0;
- module->memory.max = 0;
+ if (module->dataSegments.empty() && !module->memories.empty()) {
+ module->removeMemory(module->memories[0]->name);
}
}
}
diff --git a/src/passes/SafeHeap.cpp b/src/passes/SafeHeap.cpp
index 068c8ef73..eccb521d2 100644
--- a/src/passes/SafeHeap.cpp
+++ b/src/passes/SafeHeap.cpp
@@ -82,10 +82,11 @@ struct AccessInstrumenter : public WalkerPass<PostWalker<AccessInstrumenter>> {
return;
}
Builder builder(*getModule());
- replaceCurrent(
- builder.makeCall(getLoadName(curr),
- {curr->ptr, builder.makeConstPtr(curr->offset.addr)},
- curr->type));
+ auto memory = getModule()->getMemory(curr->memory);
+ replaceCurrent(builder.makeCall(
+ getLoadName(curr),
+ {curr->ptr, builder.makeConstPtr(curr->offset.addr, memory->indexType)},
+ curr->type));
}
void visitStore(Store* curr) {
@@ -94,9 +95,12 @@ struct AccessInstrumenter : public WalkerPass<PostWalker<AccessInstrumenter>> {
return;
}
Builder builder(*getModule());
+ auto memory = getModule()->getMemory(curr->memory);
replaceCurrent(builder.makeCall(
getStoreName(curr),
- {curr->ptr, builder.makeConstPtr(curr->offset.addr), curr->value},
+ {curr->ptr,
+ builder.makeConstPtr(curr->offset.addr, memory->indexType),
+ curr->value},
Type::none));
}
};
@@ -131,6 +135,7 @@ struct SafeHeap : public Pass {
void run(PassRunner* runner, Module* module) override {
options = runner->options;
+ assert(!module->memories.empty());
// add imports
addImports(module);
// instrument loads and stores
@@ -151,7 +156,7 @@ struct SafeHeap : public Pass {
void addImports(Module* module) {
ImportInfo info(*module);
- auto indexType = module->memory.indexType;
+ auto indexType = module->memories[0]->indexType;
if (auto* existing = info.getImportedFunction(ENV, GET_SBRK_PTR)) {
getSbrkPtr = existing->name;
} else if (auto* existing = module->getExportOrNull(GET_SBRK_PTR)) {
@@ -202,6 +207,7 @@ struct SafeHeap : public Pass {
continue;
}
load.type = type;
+ load.memory = module->memories[0]->name;
for (Index bytes : {1, 2, 4, 8, 16}) {
load.bytes = bytes;
if (bytes > type.getByteSize() || (type == Type::f32 && bytes != 4) ||
@@ -221,8 +227,9 @@ struct SafeHeap : public Pass {
}
for (auto isAtomic : {true, false}) {
load.isAtomic = isAtomic;
- if (isAtomic && !isPossibleAtomicOperation(
- align, bytes, module->memory.shared, type)) {
+ if (isAtomic &&
+ !isPossibleAtomicOperation(
+ align, bytes, module->memories[0]->shared, type)) {
continue;
}
addLoadFunc(load, module);
@@ -240,6 +247,7 @@ struct SafeHeap : public Pass {
}
store.valueType = valueType;
store.type = Type::none;
+ store.memory = module->memories[0]->name;
for (Index bytes : {1, 2, 4, 8, 16}) {
store.bytes = bytes;
if (bytes > valueType.getByteSize() ||
@@ -255,8 +263,9 @@ struct SafeHeap : public Pass {
}
for (auto isAtomic : {true, false}) {
store.isAtomic = isAtomic;
- if (isAtomic && !isPossibleAtomicOperation(
- align, bytes, module->memory.shared, valueType)) {
+ if (isAtomic &&
+ !isPossibleAtomicOperation(
+ align, bytes, module->memories[0]->shared, valueType)) {
continue;
}
addStoreFunc(store, module);
@@ -273,22 +282,30 @@ struct SafeHeap : public Pass {
return;
}
// pointer, offset
- auto indexType = module->memory.indexType;
+ auto memory = module->getMemory(style.memory);
+ auto indexType = memory->indexType;
auto funcSig = Signature({indexType, indexType}, style.type);
auto func = Builder::makeFunction(name, funcSig, {indexType});
Builder builder(*module);
auto* block = builder.makeBlock();
block->list.push_back(builder.makeLocalSet(
2,
- builder.makeBinary(module->memory.is64() ? AddInt64 : AddInt32,
+ builder.makeBinary(memory->is64() ? AddInt64 : AddInt32,
builder.makeLocalGet(0, indexType),
builder.makeLocalGet(1, indexType))));
// check for reading past valid memory: if pointer + offset + bytes
- block->list.push_back(
- makeBoundsCheck(style.type, builder, 2, style.bytes, module));
+ block->list.push_back(makeBoundsCheck(style.type,
+ builder,
+ 2,
+ style.bytes,
+ module,
+ memory->indexType,
+ memory->is64(),
+ memory->name));
// check proper alignment
if (style.align > 1) {
- block->list.push_back(makeAlignCheck(style.align, builder, 2, module));
+ block->list.push_back(
+ makeAlignCheck(style.align, builder, 2, module, memory->name));
}
// do the load
auto* load = module->allocator.alloc<Load>();
@@ -312,7 +329,9 @@ struct SafeHeap : public Pass {
if (module->getFunctionOrNull(name)) {
return;
}
- auto indexType = module->memory.indexType;
+ auto memory = module->getMemory(style.memory);
+ auto indexType = memory->indexType;
+ bool is64 = memory->is64();
// pointer, offset, value
auto funcSig =
Signature({indexType, indexType, style.valueType}, Type::none);
@@ -321,19 +340,27 @@ struct SafeHeap : public Pass {
auto* block = builder.makeBlock();
block->list.push_back(builder.makeLocalSet(
3,
- builder.makeBinary(module->memory.is64() ? AddInt64 : AddInt32,
+ builder.makeBinary(is64 ? AddInt64 : AddInt32,
builder.makeLocalGet(0, indexType),
builder.makeLocalGet(1, indexType))));
// check for reading past valid memory: if pointer + offset + bytes
- block->list.push_back(
- makeBoundsCheck(style.valueType, builder, 3, style.bytes, module));
+ block->list.push_back(makeBoundsCheck(style.valueType,
+ builder,
+ 3,
+ style.bytes,
+ module,
+ indexType,
+ is64,
+ memory->name));
// check proper alignment
if (style.align > 1) {
- block->list.push_back(makeAlignCheck(style.align, builder, 3, module));
+ block->list.push_back(
+ makeAlignCheck(style.align, builder, 3, module, memory->name));
}
// do the store
auto* store = module->allocator.alloc<Store>();
*store = style; // basically the same as the template we are given!
+ store->memory = memory->name;
store->ptr = builder.makeLocalGet(3, indexType);
store->value = builder.makeLocalGet(2, style.valueType);
block->list.push_back(store);
@@ -342,11 +369,15 @@ struct SafeHeap : public Pass {
module->addFunction(std::move(func));
}
- Expression*
- makeAlignCheck(Address align, Builder& builder, Index local, Module* module) {
- auto indexType = module->memory.indexType;
+ Expression* makeAlignCheck(Address align,
+ Builder& builder,
+ Index local,
+ Module* module,
+ Name memoryName) {
+ auto memory = module->getMemory(memoryName);
+ auto indexType = memory->indexType;
Expression* ptrBits = builder.makeLocalGet(local, indexType);
- if (module->memory.is64()) {
+ if (memory->is64()) {
ptrBits = builder.makeUnary(WrapInt64, ptrBits);
}
return builder.makeIf(
@@ -355,17 +386,21 @@ struct SafeHeap : public Pass {
builder.makeCall(alignfault, {}, Type::none));
}
- Expression* makeBoundsCheck(
- Type type, Builder& builder, Index local, Index bytes, Module* module) {
- auto indexType = module->memory.indexType;
- auto upperOp = module->memory.is64()
- ? options.lowMemoryUnused ? LtUInt64 : EqInt64
- : options.lowMemoryUnused ? LtUInt32 : EqInt32;
+ Expression* makeBoundsCheck(Type type,
+ Builder& builder,
+ Index local,
+ Index bytes,
+ Module* module,
+ Type indexType,
+ bool is64,
+ Name memory) {
+ auto upperOp = is64 ? options.lowMemoryUnused ? LtUInt64 : EqInt64
+ : options.lowMemoryUnused ? LtUInt32 : EqInt32;
auto upperBound = options.lowMemoryUnused ? PassOptions::LowMemoryBound : 0;
Expression* brkLocation;
if (sbrk.is()) {
brkLocation =
- builder.makeCall(sbrk, {builder.makeConstPtr(0)}, indexType);
+ builder.makeCall(sbrk, {builder.makeConstPtr(0, indexType)}, indexType);
} else {
Expression* sbrkPtr;
if (dynamicTopPtr.is()) {
@@ -373,22 +408,23 @@ struct SafeHeap : public Pass {
} else {
sbrkPtr = builder.makeCall(getSbrkPtr, {}, indexType);
}
- auto size = module->memory.is64() ? 8 : 4;
- brkLocation = builder.makeLoad(size, false, 0, size, sbrkPtr, indexType);
+ auto size = is64 ? 8 : 4;
+ brkLocation =
+ builder.makeLoad(size, false, 0, size, sbrkPtr, indexType, memory);
}
- auto gtuOp = module->memory.is64() ? GtUInt64 : GtUInt32;
- auto addOp = module->memory.is64() ? AddInt64 : AddInt32;
+ auto gtuOp = is64 ? GtUInt64 : GtUInt32;
+ auto addOp = is64 ? AddInt64 : AddInt32;
return builder.makeIf(
builder.makeBinary(
OrInt32,
builder.makeBinary(upperOp,
builder.makeLocalGet(local, indexType),
- builder.makeConstPtr(upperBound)),
+ builder.makeConstPtr(upperBound, indexType)),
builder.makeBinary(
gtuOp,
builder.makeBinary(addOp,
builder.makeLocalGet(local, indexType),
- builder.makeConstPtr(bytes)),
+ builder.makeConstPtr(bytes, indexType)),
brkLocation)),
builder.makeCall(segfault, {}, Type::none));
}
diff --git a/src/passes/SpillPointers.cpp b/src/passes/SpillPointers.cpp
index 46b1fb47c..04193c2d2 100644
--- a/src/passes/SpillPointers.cpp
+++ b/src/passes/SpillPointers.cpp
@@ -74,7 +74,7 @@ struct SpillPointers
Type pointerType;
void spillPointers() {
- pointerType = getModule()->memory.indexType;
+ pointerType = getModule()->memories[0]->indexType;
// we only care about possible pointers
auto* func = getFunction();
@@ -192,7 +192,8 @@ struct SpillPointers
pointerType.getByteSize(),
builder.makeLocalGet(spillLocal, pointerType),
builder.makeLocalGet(index, pointerType),
- pointerType));
+ pointerType,
+ getModule()->memories[0]->name));
}
// add the (modified) call
block->list.push_back(call);
diff --git a/src/passes/StackCheck.cpp b/src/passes/StackCheck.cpp
index 4b1054597..fd7ed6c0f 100644
--- a/src/passes/StackCheck.cpp
+++ b/src/passes/StackCheck.cpp
@@ -146,15 +146,17 @@ struct StackCheck : public Pass {
Builder builder(*module);
// Add the globals.
+ Type indexType =
+ module->memories.empty() ? Type::i32 : module->memories[0]->indexType;
auto stackBase =
module->addGlobal(builder.makeGlobal(stackBaseName,
stackPointer->type,
- builder.makeConstPtr(0),
+ builder.makeConstPtr(0, indexType),
Builder::Mutable));
auto stackLimit =
module->addGlobal(builder.makeGlobal(stackLimitName,
stackPointer->type,
- builder.makeConstPtr(0),
+ builder.makeConstPtr(0, indexType),
Builder::Mutable));
// Instrument all the code.
diff --git a/src/shell-interface.h b/src/shell-interface.h
index d1cf3290e..98349055b 100644
--- a/src/shell-interface.h
+++ b/src/shell-interface.h
@@ -57,8 +57,6 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
static_assert(!(sizeof(T) & (sizeof(T) - 1)), "must be a power of 2");
return 0 == (reinterpret_cast<uintptr_t>(address) & (sizeof(T) - 1));
}
- Memory(Memory&) = delete;
- Memory& operator=(const Memory&) = delete;
public:
Memory() = default;
@@ -92,14 +90,14 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
return loaded;
}
}
- } memory;
+ };
+ std::map<Name, Memory> memories;
std::unordered_map<Name, std::vector<Literal>> tables;
std::map<Name, std::shared_ptr<ModuleRunner>> linkedInstances;
ShellExternalInterface(
- std::map<Name, std::shared_ptr<ModuleRunner>> linkedInstances_ = {})
- : memory() {
+ std::map<Name, std::shared_ptr<ModuleRunner>> linkedInstances_ = {}) {
linkedInstances.swap(linkedInstances_);
}
virtual ~ShellExternalInterface() = default;
@@ -114,9 +112,11 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
}
void init(Module& wasm, ModuleRunner& instance) override {
- if (wasm.memory.exists && !wasm.memory.imported()) {
- memory.resize(wasm.memory.initial * wasm::Memory::kPageSize);
- }
+ ModuleUtils::iterDefinedMemories(wasm, [&](wasm::Memory* memory) {
+ auto shellMemory = Memory();
+ shellMemory.resize(memory->initial * wasm::Memory::kPageSize);
+ memories[memory->name] = shellMemory;
+ });
ModuleUtils::iterDefinedTables(
wasm, [&](Table* table) { tables[table->name].resize(table->initial); });
}
@@ -195,31 +195,119 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
}
}
- int8_t load8s(Address addr) override { return memory.get<int8_t>(addr); }
- uint8_t load8u(Address addr) override { return memory.get<uint8_t>(addr); }
- int16_t load16s(Address addr) override { return memory.get<int16_t>(addr); }
- uint16_t load16u(Address addr) override { return memory.get<uint16_t>(addr); }
- int32_t load32s(Address addr) override { return memory.get<int32_t>(addr); }
- uint32_t load32u(Address addr) override { return memory.get<uint32_t>(addr); }
- int64_t load64s(Address addr) override { return memory.get<int64_t>(addr); }
- uint64_t load64u(Address addr) override { return memory.get<uint64_t>(addr); }
- std::array<uint8_t, 16> load128(Address addr) override {
+ int8_t load8s(Address addr, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("load8s on non-existing memory");
+ }
+ auto& memory = it->second;
+ return memory.get<int8_t>(addr);
+ }
+ uint8_t load8u(Address addr, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("load8u on non-existing memory");
+ }
+ auto& memory = it->second;
+ return memory.get<uint8_t>(addr);
+ }
+ int16_t load16s(Address addr, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("load16s on non-existing memory");
+ }
+ auto& memory = it->second;
+ return memory.get<int16_t>(addr);
+ }
+ uint16_t load16u(Address addr, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("load16u on non-existing memory");
+ }
+ auto& memory = it->second;
+ return memory.get<uint16_t>(addr);
+ }
+ int32_t load32s(Address addr, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("load32s on non-existing memory");
+ }
+ auto& memory = it->second;
+ return memory.get<int32_t>(addr);
+ }
+ uint32_t load32u(Address addr, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("load32u on non-existing memory");
+ }
+ auto& memory = it->second;
+ return memory.get<uint32_t>(addr);
+ }
+ int64_t load64s(Address addr, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("load64s on non-existing memory");
+ }
+ auto& memory = it->second;
+ return memory.get<int64_t>(addr);
+ }
+ uint64_t load64u(Address addr, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("load64u on non-existing memory");
+ }
+ auto& memory = it->second;
+ return memory.get<uint64_t>(addr);
+ }
+ std::array<uint8_t, 16> load128(Address addr, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("load128 on non-existing memory");
+ }
+ auto& memory = it->second;
return memory.get<std::array<uint8_t, 16>>(addr);
}
- void store8(Address addr, int8_t value) override {
+ void store8(Address addr, int8_t value, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("store8 on non-existing memory");
+ }
+ auto& memory = it->second;
memory.set<int8_t>(addr, value);
}
- void store16(Address addr, int16_t value) override {
+ void store16(Address addr, int16_t value, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("store16 on non-existing memory");
+ }
+ auto& memory = it->second;
memory.set<int16_t>(addr, value);
}
- void store32(Address addr, int32_t value) override {
+ void store32(Address addr, int32_t value, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("store32 on non-existing memory");
+ }
+ auto& memory = it->second;
memory.set<int32_t>(addr, value);
}
- void store64(Address addr, int64_t value) override {
+ void store64(Address addr, int64_t value, Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("store64 on non-existing memory");
+ }
+ auto& memory = it->second;
memory.set<int64_t>(addr, value);
}
- void store128(Address addr, const std::array<uint8_t, 16>& value) override {
+ void store128(Address addr,
+ const std::array<uint8_t, 16>& value,
+ Name memoryName) override {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("store128 on non-existing memory");
+ }
+ auto& memory = it->second;
memory.set<std::array<uint8_t, 16>>(addr, value);
}
@@ -250,12 +338,18 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
return table[index];
}
- bool growMemory(Address /*oldSize*/, Address newSize) override {
+ bool
+ growMemory(Name memoryName, Address /*oldSize*/, Address newSize) override {
// Apply a reasonable limit on memory size, 1GB, to avoid DOS on the
// interpreter.
if (newSize > 1024 * 1024 * 1024) {
return false;
}
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ trap("growMemory on non-existing memory");
+ }
+ auto& memory = it->second;
memory.resize(newSize);
return true;
}
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index 4d0a8d7b7..cdefe29f1 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -185,7 +185,7 @@ void TranslateToFuzzReader::build() {
void TranslateToFuzzReader::setupMemory() {
// Add memory itself
- MemoryUtils::ensureExists(wasm.memory);
+ MemoryUtils::ensureExists(&wasm);
if (wasm.features.hasBulkMemory()) {
size_t memCovered = 0;
// need at least one segment for memory.inits
@@ -202,12 +202,14 @@ void TranslateToFuzzReader::setupMemory() {
if (!segment->isPassive) {
segment->offset = builder.makeConst(int32_t(memCovered));
memCovered += segSize;
+ segment->memory = wasm.memories[0]->name;
}
wasm.dataSegments.push_back(std::move(segment));
}
} else {
// init some data
auto segment = builder.makeDataSegment();
+ segment->memory = wasm.memories[0]->name;
segment->offset = builder.makeConst(int32_t(0));
segment->setName(Name::fromInt(0), false);
wasm.dataSegments.push_back(std::move(segment));
@@ -229,7 +231,7 @@ void TranslateToFuzzReader::setupMemory() {
std::vector<Expression*> contents;
contents.push_back(
builder.makeLocalSet(0, builder.makeConst(uint32_t(5381))));
- auto zero = Literal::makeFromInt32(0, wasm.memory.indexType);
+ auto zero = Literal::makeFromInt32(0, wasm.memories[0]->indexType);
for (Index i = 0; i < USABLE_MEMORY; i++) {
contents.push_back(builder.makeLocalSet(
0,
@@ -241,7 +243,13 @@ void TranslateToFuzzReader::setupMemory() {
builder.makeLocalGet(0, Type::i32),
builder.makeConst(uint32_t(5))),
builder.makeLocalGet(0, Type::i32)),
- builder.makeLoad(1, false, i, 1, builder.makeConst(zero), Type::i32))));
+ builder.makeLoad(1,
+ false,
+ i,
+ 1,
+ builder.makeConst(zero),
+ Type::i32,
+ wasm.memories[0]->name))));
}
contents.push_back(builder.makeLocalGet(0, Type::i32));
auto* body = builder.makeBlock(contents);
@@ -251,7 +259,8 @@ void TranslateToFuzzReader::setupMemory() {
builder.makeExport(hasher->name, hasher->name, ExternalKind::Function));
// Export memory so JS fuzzing can use it
if (!wasm.getExportOrNull("memory")) {
- wasm.addExport(builder.makeExport("memory", "0", ExternalKind::Memory));
+ wasm.addExport(builder.makeExport(
+ "memory", wasm.memories[0]->name, ExternalKind::Memory));
}
}
@@ -354,25 +363,26 @@ void TranslateToFuzzReader::finalizeMemory() {
maxOffset = maxOffset + offset->value.getInteger();
}
}
- wasm.memory.initial = std::max(
- wasm.memory.initial,
+ wasm.memories[0]->initial = std::max(
+ wasm.memories[0]->initial,
Address((maxOffset + Memory::kPageSize - 1) / Memory::kPageSize));
}
- wasm.memory.initial = std::max(wasm.memory.initial, USABLE_MEMORY);
+ wasm.memories[0]->initial =
+ std::max(wasm.memories[0]->initial, USABLE_MEMORY);
// Avoid an unlimited memory size, which would make fuzzing very difficult
// as different VMs will run out of system memory in different ways.
- if (wasm.memory.max == Memory::kUnlimitedSize) {
- wasm.memory.max = wasm.memory.initial;
+ if (wasm.memories[0]->max == Memory::kUnlimitedSize) {
+ wasm.memories[0]->max = wasm.memories[0]->initial;
}
- if (wasm.memory.max <= wasm.memory.initial) {
+ if (wasm.memories[0]->max <= wasm.memories[0]->initial) {
// To allow growth to work (which a testcase may assume), try to make the
// maximum larger than the initial.
// TODO: scan the wasm for grow instructions?
- wasm.memory.max =
- std::min(Address(wasm.memory.initial + 1), Address(Memory::kMaxSize32));
+ wasm.memories[0]->max = std::min(Address(wasm.memories[0]->initial + 1),
+ Address(Memory::kMaxSize32));
}
// Avoid an imported memory (which the fuzz harness would need to handle).
- wasm.memory.module = wasm.memory.base = Name();
+ wasm.memories[0]->module = wasm.memories[0]->base = Name();
}
void TranslateToFuzzReader::finalizeTable() {
@@ -1403,12 +1413,12 @@ Expression* TranslateToFuzzReader::makeTupleExtract(Type type) {
}
Expression* TranslateToFuzzReader::makePointer() {
- auto* ret = make(wasm.memory.indexType);
+ auto* ret = make(wasm.memories[0]->indexType);
// with high probability, mask the pointer so it's in a reasonable
// range. otherwise, most pointers are going to be out of range and
// most memory ops will just trap
if (!allowOOB || !oneIn(10)) {
- if (wasm.memory.is64()) {
+ if (wasm.memories[0]->is64()) {
ret = builder.makeBinary(
AndInt64, ret, builder.makeConst(int64_t(USABLE_MEMORY - 1)));
} else {
@@ -1427,11 +1437,19 @@ Expression* TranslateToFuzzReader::makeNonAtomicLoad(Type type) {
bool signed_ = get() & 1;
switch (upTo(3)) {
case 0:
- return builder.makeLoad(1, signed_, offset, 1, ptr, type);
+ return builder.makeLoad(
+ 1, signed_, offset, 1, ptr, type, wasm.memories[0]->name);
case 1:
- return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
+ return builder.makeLoad(
+ 2, signed_, offset, pick(1, 2), ptr, type, wasm.memories[0]->name);
case 2:
- return builder.makeLoad(4, signed_, offset, pick(1, 2, 4), ptr, type);
+ return builder.makeLoad(4,
+ signed_,
+ offset,
+ pick(1, 2, 4),
+ ptr,
+ type,
+ wasm.memories[0]->name);
}
WASM_UNREACHABLE("unexpected value");
}
@@ -1439,29 +1457,49 @@ Expression* TranslateToFuzzReader::makeNonAtomicLoad(Type type) {
bool signed_ = get() & 1;
switch (upTo(4)) {
case 0:
- return builder.makeLoad(1, signed_, offset, 1, ptr, type);
+ return builder.makeLoad(
+ 1, signed_, offset, 1, ptr, type, wasm.memories[0]->name);
case 1:
- return builder.makeLoad(2, signed_, offset, pick(1, 2), ptr, type);
+ return builder.makeLoad(
+ 2, signed_, offset, pick(1, 2), ptr, type, wasm.memories[0]->name);
case 2:
- return builder.makeLoad(4, signed_, offset, pick(1, 2, 4), ptr, type);
+ return builder.makeLoad(4,
+ signed_,
+ offset,
+ pick(1, 2, 4),
+ ptr,
+ type,
+ wasm.memories[0]->name);
case 3:
- return builder.makeLoad(
- 8, signed_, offset, pick(1, 2, 4, 8), ptr, type);
+ return builder.makeLoad(8,
+ signed_,
+ offset,
+ pick(1, 2, 4, 8),
+ ptr,
+ type,
+ wasm.memories[0]->name);
}
WASM_UNREACHABLE("unexpected value");
}
case Type::f32: {
- return builder.makeLoad(4, false, offset, pick(1, 2, 4), ptr, type);
+ return builder.makeLoad(
+ 4, false, offset, pick(1, 2, 4), ptr, type, wasm.memories[0]->name);
}
case Type::f64: {
- return builder.makeLoad(8, false, offset, pick(1, 2, 4, 8), ptr, type);
+ return builder.makeLoad(
+ 8, false, offset, pick(1, 2, 4, 8), ptr, type, wasm.memories[0]->name);
}
case Type::v128: {
if (!wasm.features.hasSIMD()) {
return makeTrivial(type);
}
- return builder.makeLoad(
- 16, false, offset, pick(1, 2, 4, 8, 16), ptr, type);
+ return builder.makeLoad(16,
+ false,
+ offset,
+ pick(1, 2, 4, 8, 16),
+ ptr,
+ type,
+ wasm.memories[0]->name);
}
case Type::none:
case Type::unreachable:
@@ -1484,7 +1522,7 @@ Expression* TranslateToFuzzReader::makeLoad(Type type) {
}
// make it atomic
auto* load = ret->cast<Load>();
- wasm.memory.shared = true;
+ wasm.memories[0]->shared = true;
load->isAtomic = true;
load->signed_ = false;
load->align = load->bytes;
@@ -1511,6 +1549,7 @@ Expression* TranslateToFuzzReader::makeNonAtomicStore(Type type) {
store->value = make(Type::unreachable);
break;
}
+ store->memory = wasm.memories[0]->name;
store->finalize();
return store;
}
@@ -1526,40 +1565,58 @@ Expression* TranslateToFuzzReader::makeNonAtomicStore(Type type) {
case Type::i32: {
switch (upTo(3)) {
case 0:
- return builder.makeStore(1, offset, 1, ptr, value, type);
+ return builder.makeStore(
+ 1, offset, 1, ptr, value, type, wasm.memories[0]->name);
case 1:
- return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
+ return builder.makeStore(
+ 2, offset, pick(1, 2), ptr, value, type, wasm.memories[0]->name);
case 2:
- return builder.makeStore(4, offset, pick(1, 2, 4), ptr, value, type);
+ return builder.makeStore(
+ 4, offset, pick(1, 2, 4), ptr, value, type, wasm.memories[0]->name);
}
WASM_UNREACHABLE("invalid value");
}
case Type::i64: {
switch (upTo(4)) {
case 0:
- return builder.makeStore(1, offset, 1, ptr, value, type);
+ return builder.makeStore(
+ 1, offset, 1, ptr, value, type, wasm.memories[0]->name);
case 1:
- return builder.makeStore(2, offset, pick(1, 2), ptr, value, type);
+ return builder.makeStore(
+ 2, offset, pick(1, 2), ptr, value, type, wasm.memories[0]->name);
case 2:
- return builder.makeStore(4, offset, pick(1, 2, 4), ptr, value, type);
- case 3:
return builder.makeStore(
- 8, offset, pick(1, 2, 4, 8), ptr, value, type);
+ 4, offset, pick(1, 2, 4), ptr, value, type, wasm.memories[0]->name);
+ case 3:
+ return builder.makeStore(8,
+ offset,
+ pick(1, 2, 4, 8),
+ ptr,
+ value,
+ type,
+ wasm.memories[0]->name);
}
WASM_UNREACHABLE("invalid value");
}
case Type::f32: {
- return builder.makeStore(4, offset, pick(1, 2, 4), ptr, value, type);
+ return builder.makeStore(
+ 4, offset, pick(1, 2, 4), ptr, value, type, wasm.memories[0]->name);
}
case Type::f64: {
- return builder.makeStore(8, offset, pick(1, 2, 4, 8), ptr, value, type);
+ return builder.makeStore(
+ 8, offset, pick(1, 2, 4, 8), ptr, value, type, wasm.memories[0]->name);
}
case Type::v128: {
if (!wasm.features.hasSIMD()) {
return makeTrivial(type);
}
- return builder.makeStore(
- 16, offset, pick(1, 2, 4, 8, 16), ptr, value, type);
+ return builder.makeStore(16,
+ offset,
+ pick(1, 2, 4, 8, 16),
+ ptr,
+ value,
+ type,
+ wasm.memories[0]->name);
}
case Type::none:
case Type::unreachable:
@@ -1584,7 +1641,7 @@ Expression* TranslateToFuzzReader::makeStore(Type type) {
return store;
}
// make it atomic
- wasm.memory.shared = true;
+ wasm.memories[0]->shared = true;
store->isAtomic = true;
store->align = store->bytes;
return store;
@@ -2530,7 +2587,7 @@ Expression* TranslateToFuzzReader::makeAtomic(Type type) {
if (!allowMemory) {
return makeTrivial(type);
}
- wasm.memory.shared = true;
+ wasm.memories[0]->shared = true;
if (type == Type::none) {
return builder.makeAtomicFence();
}
@@ -2540,12 +2597,17 @@ Expression* TranslateToFuzzReader::makeAtomic(Type type) {
auto expectedType = pick(Type::i32, Type::i64);
auto* expected = make(expectedType);
auto* timeout = make(Type::i64);
- return builder.makeAtomicWait(
- ptr, expected, timeout, expectedType, logify(get()));
+ return builder.makeAtomicWait(ptr,
+ expected,
+ timeout,
+ expectedType,
+ logify(get()),
+ wasm.memories[0]->name);
} else {
auto* ptr = makePointer();
auto* count = make(Type::i32);
- return builder.makeAtomicNotify(ptr, count, logify(get()));
+ return builder.makeAtomicNotify(
+ ptr, count, logify(get()), wasm.memories[0]->name);
}
}
Index bytes;
@@ -2598,12 +2660,13 @@ Expression* TranslateToFuzzReader::makeAtomic(Type type) {
offset,
ptr,
value,
- type);
+ type,
+ wasm.memories[0]->name);
} else {
auto* expected = make(type);
auto* replacement = make(type);
return builder.makeAtomicCmpxchg(
- bytes, offset, ptr, expected, replacement, type);
+ bytes, offset, ptr, expected, replacement, type, wasm.memories[0]->name);
}
}
@@ -2804,7 +2867,7 @@ Expression* TranslateToFuzzReader::makeSIMDLoad() {
WASM_UNREACHABLE("Unexpected SIMD loads");
}
Expression* ptr = makePointer();
- return builder.makeSIMDLoad(op, offset, align, ptr);
+ return builder.makeSIMDLoad(op, offset, align, ptr, wasm.memories[0]->name);
}
Expression* TranslateToFuzzReader::makeBulkMemory(Type type) {
@@ -2868,7 +2931,8 @@ Expression* TranslateToFuzzReader::makeMemoryInit() {
Expression* dest = makePointer();
Expression* offset = builder.makeConst(int32_t(offsetVal));
Expression* size = builder.makeConst(int32_t(sizeVal));
- return builder.makeMemoryInit(segment, dest, offset, size);
+ return builder.makeMemoryInit(
+ segment, dest, offset, size, wasm.memories[0]->name);
}
Expression* TranslateToFuzzReader::makeDataDrop() {
@@ -2884,8 +2948,9 @@ Expression* TranslateToFuzzReader::makeMemoryCopy() {
}
Expression* dest = makePointer();
Expression* source = makePointer();
- Expression* size = make(wasm.memory.indexType);
- return builder.makeMemoryCopy(dest, source, size);
+ Expression* size = make(wasm.memories[0]->indexType);
+ return builder.makeMemoryCopy(
+ dest, source, size, wasm.memories[0]->name, wasm.memories[0]->name);
}
Expression* TranslateToFuzzReader::makeMemoryFill() {
@@ -2894,8 +2959,8 @@ Expression* TranslateToFuzzReader::makeMemoryFill() {
}
Expression* dest = makePointer();
Expression* value = make(Type::i32);
- Expression* size = make(wasm.memory.indexType);
- return builder.makeMemoryFill(dest, value, size);
+ Expression* size = make(wasm.memories[0]->indexType);
+ return builder.makeMemoryFill(dest, value, size, wasm.memories[0]->name);
}
Type TranslateToFuzzReader::getSingleConcreteType() {
diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp
index 6150441cd..91128471c 100644
--- a/src/tools/wasm-ctor-eval.cpp
+++ b/src/tools/wasm-ctor-eval.cpp
@@ -122,14 +122,11 @@ std::unique_ptr<Module> buildEnvModule(Module& wasm) {
// create an exported memory with the same initial and max size
ModuleUtils::iterImportedMemories(wasm, [&](Memory* memory) {
if (memory->module == env->name) {
- env->memory.name = wasm.memory.name;
- env->memory.exists = true;
- env->memory.initial = memory->initial;
- env->memory.max = memory->max;
- env->memory.shared = memory->shared;
- env->memory.indexType = memory->indexType;
+ auto* copied = ModuleUtils::copyMemory(memory, *env);
+ copied->module = Name();
+ copied->base = Name();
env->addExport(Builder(*env).makeExport(
- wasm.memory.base, wasm.memory.name, ExternalKind::Memory));
+ memory->base, copied->name, ExternalKind::Memory));
}
});
@@ -147,7 +144,7 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
std::map<Name, std::shared_ptr<EvallingModuleRunner>> linkedInstances;
// A representation of the contents of wasm memory as we execute.
- std::vector<char> memory;
+ std::unordered_map<Name, std::vector<char>> memories;
CtorEvalExternalInterface(
std::map<Name, std::shared_ptr<EvallingModuleRunner>> linkedInstances_ =
@@ -160,8 +157,8 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
void applyToModule() {
clearApplyState();
- // If nothing was ever written to memory then there is nothing to update.
- if (!memory.empty()) {
+ // If nothing was ever written to memories then there is nothing to update.
+ if (!memories.empty()) {
applyMemoryToModule();
}
@@ -171,6 +168,12 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
void init(Module& wasm_, EvallingModuleRunner& instance_) override {
wasm = &wasm_;
instance = &instance_;
+ for (auto& memory : wasm->memories) {
+ if (!memory->imported()) {
+ std::vector<char> data;
+ memories[memory->name] = data;
+ }
+ }
}
void importGlobals(GlobalValueSet& globals, Module& wasm_) override {
@@ -204,7 +207,7 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
}
// Write out a count of i32(0) and return __WASI_ERRNO_SUCCESS (0).
- store32(arguments[0].geti32(), 0);
+ store32(arguments[0].geti32(), 0, wasm->memories[0]->name);
return {Literal(int32_t(0))};
}
@@ -225,7 +228,7 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
}
// Write out an argc of i32(0) and return a __WASI_ERRNO_SUCCESS (0).
- store32(arguments[0].geti32(), 0);
+ store32(arguments[0].geti32(), 0, wasm->memories[0]->name);
return {Literal(int32_t(0))};
}
@@ -336,29 +339,47 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
// called during initialization
void tableStore(Name tableName, Index index, const Literal& value) override {}
- int8_t load8s(Address addr) override { return doLoad<int8_t>(addr); }
- uint8_t load8u(Address addr) override { return doLoad<uint8_t>(addr); }
- int16_t load16s(Address addr) override { return doLoad<int16_t>(addr); }
- uint16_t load16u(Address addr) override { return doLoad<uint16_t>(addr); }
- int32_t load32s(Address addr) override { return doLoad<int32_t>(addr); }
- uint32_t load32u(Address addr) override { return doLoad<uint32_t>(addr); }
- int64_t load64s(Address addr) override { return doLoad<int64_t>(addr); }
- uint64_t load64u(Address addr) override { return doLoad<uint64_t>(addr); }
+ int8_t load8s(Address addr, Name memoryName) override {
+ return doLoad<int8_t>(addr, memoryName);
+ }
+ uint8_t load8u(Address addr, Name memoryName) override {
+ return doLoad<uint8_t>(addr, memoryName);
+ }
+ int16_t load16s(Address addr, Name memoryName) override {
+ return doLoad<int16_t>(addr, memoryName);
+ }
+ uint16_t load16u(Address addr, Name memoryName) override {
+ return doLoad<uint16_t>(addr, memoryName);
+ }
+ int32_t load32s(Address addr, Name memoryName) override {
+ return doLoad<int32_t>(addr, memoryName);
+ }
+ uint32_t load32u(Address addr, Name memoryName) override {
+ return doLoad<uint32_t>(addr, memoryName);
+ }
+ int64_t load64s(Address addr, Name memoryName) override {
+ return doLoad<int64_t>(addr, memoryName);
+ }
+ uint64_t load64u(Address addr, Name memoryName) override {
+ return doLoad<uint64_t>(addr, memoryName);
+ }
- void store8(Address addr, int8_t value) override {
- doStore<int8_t>(addr, value);
+ void store8(Address addr, int8_t value, Name memoryName) override {
+ doStore<int8_t>(addr, value, memoryName);
}
- void store16(Address addr, int16_t value) override {
- doStore<int16_t>(addr, value);
+ void store16(Address addr, int16_t value, Name memoryName) override {
+ doStore<int16_t>(addr, value, memoryName);
}
- void store32(Address addr, int32_t value) override {
- doStore<int32_t>(addr, value);
+ void store32(Address addr, int32_t value, Name memoryName) override {
+ doStore<int32_t>(addr, value, memoryName);
}
- void store64(Address addr, int64_t value) override {
- doStore<int64_t>(addr, value);
+ void store64(Address addr, int64_t value, Name memoryName) override {
+ doStore<int64_t>(addr, value, memoryName);
}
- bool growMemory(Address /*oldSize*/, Address /*newSize*/) override {
+ bool growMemory(Name memoryName,
+ Address /*oldSize*/,
+ Address /*newSize*/) override {
throw FailToEvalException("grow memory");
}
@@ -385,8 +406,12 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
private:
// TODO: handle unaligned too, see shell-interface
-
- template<typename T> T* getMemory(Address address) {
+ template<typename T> T* getMemory(Address address, Name memoryName) {
+ auto it = memories.find(memoryName);
+ if (it == memories.end()) {
+ Fatal() << "memory not found: " << memoryName;
+ }
+ auto& memory = it->second;
// resize the memory buffer as needed.
auto max = address + sizeof(T);
if (max > memory.size()) {
@@ -395,15 +420,15 @@ private:
return (T*)(&memory[address]);
}
- template<typename T> void doStore(Address address, T value) {
+ template<typename T> void doStore(Address address, T value, Name memoryName) {
// do a memcpy to avoid undefined behavior if unaligned
- memcpy(getMemory<T>(address), &value, sizeof(T));
+ memcpy(getMemory<T>(address, memoryName), &value, sizeof(T));
}
- template<typename T> T doLoad(Address address) {
+ template<typename T> T doLoad(Address address, Name memoryName) {
// do a memcpy to avoid undefined behavior if unaligned
T ret;
- memcpy(&ret, getMemory<T>(address), sizeof(T));
+ memcpy(&ret, getMemory<T>(address, memoryName), sizeof(T));
return ret;
}
@@ -431,14 +456,15 @@ private:
auto curr = builder.makeDataSegment();
curr->offset = builder.makeConst(int32_t(0));
curr->setName(Name::fromInt(0), false);
- wasm->dataSegments.push_back(std::move(curr));
+ curr->memory = wasm->memories[0]->name;
+ wasm->addDataSegment(std::move(curr));
}
auto& segment = wasm->dataSegments[0];
assert(segment->offset->cast<Const>()->value.getInteger() == 0);
// Copy the current memory contents after execution into the Module's
// memory.
- segment->data = memory;
+ segment->data = memories[wasm->memories[0]->name];
}
// Serializing GC data requires more work than linear memory, because
diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp
index 51eafb652..4b20e922b 100644
--- a/src/tools/wasm-shell.cpp
+++ b/src/tools/wasm-shell.cpp
@@ -284,9 +284,7 @@ protected:
}
}
});
- if (wasm.memory.imported()) {
- reportUnknownImport(&wasm.memory);
- }
+ ModuleUtils::iterImportedMemories(wasm, reportUnknownImport);
}
if (!invalid && id == ASSERT_TRAP) {
@@ -352,11 +350,10 @@ protected:
spectest->addExport(
builder.makeExport("table", Name::fromInt(0), ExternalKind::Table));
- spectest->memory.exists = true;
- spectest->memory.initial = 1;
- spectest->memory.max = 2;
- spectest->addExport(builder.makeExport(
- "memory", spectest->memory.name, ExternalKind::Memory));
+ Memory* memory =
+ spectest->addMemory(builder.makeMemory(Name::fromInt(0), 1, 2));
+ spectest->addExport(
+ builder.makeExport("memory", memory->name, ExternalKind::Memory));
modules["spectest"].swap(spectest);
modules["spectest"]->features = FeatureSet::All;
diff --git a/src/tools/wasm-split/instrumenter.cpp b/src/tools/wasm-split/instrumenter.cpp
index c23a70f06..50da9d034 100644
--- a/src/tools/wasm-split/instrumenter.cpp
+++ b/src/tools/wasm-split/instrumenter.cpp
@@ -108,13 +108,15 @@ void Instrumenter::instrumentFuncs() {
}
// (i32.atomic.store8 offset=funcidx (i32.const 0) (i32.const 1))
Index funcIdx = 0;
+ assert(!wasm->memories.empty());
ModuleUtils::iterDefinedFunctions(*wasm, [&](Function* func) {
func->body = builder.makeSequence(
builder.makeAtomicStore(1,
funcIdx,
- builder.makeConstPtr(0),
+ builder.makeConstPtr(0, Type::i32),
builder.makeConst(uint32_t(1)),
- Type::i32),
+ Type::i32,
+ wasm->memories[0]->name),
func->body,
func->body->type);
++funcIdx;
@@ -168,9 +170,22 @@ void Instrumenter::addProfileExport() {
return builder.makeConst(int32_t(profileSize));
};
+ // Also make sure there is a memory with enough pages to write into
+ size_t pages = (profileSize + Memory::kPageSize - 1) / Memory::kPageSize;
+ if (wasm->memories.empty()) {
+ wasm->addMemory(Builder::makeMemory("0"));
+ wasm->memories[0]->initial = pages;
+ wasm->memories[0]->max = pages;
+ } else if (wasm->memories[0]->initial < pages) {
+ wasm->memories[0]->initial = pages;
+ if (wasm->memories[0]->max < pages) {
+ wasm->memories[0]->max = pages;
+ }
+ }
+
// Write the hash followed by all the time stamps
- Expression* writeData =
- builder.makeStore(8, 0, 1, getAddr(), hashConst(), Type::i64);
+ Expression* writeData = builder.makeStore(
+ 8, 0, 1, getAddr(), hashConst(), Type::i64, wasm->memories[0]->name);
uint32_t offset = 8;
switch (options.storageKind) {
@@ -183,7 +198,8 @@ void Instrumenter::addProfileExport() {
1,
getAddr(),
builder.makeGlobalGet(global, Type::i32),
- Type::i32));
+ Type::i32,
+ wasm->memories[0]->name));
offset += 4;
}
break;
@@ -232,8 +248,10 @@ void Instrumenter::addProfileExport() {
getAddr(),
builder.makeBinary(
MulInt32, getFuncIdx(), builder.makeConst(uint32_t(4)))),
- builder.makeAtomicLoad(1, 0, getFuncIdx(), Type::i32),
- Type::i32),
+ builder.makeAtomicLoad(
+ 1, 0, getFuncIdx(), Type::i32, wasm->memories[0]->name),
+ Type::i32,
+ wasm->memories[0]->name),
builder.makeLocalSet(
funcIdxVar,
builder.makeBinary(
@@ -253,21 +271,8 @@ void Instrumenter::addProfileExport() {
wasm->addExport(
Builder::makeExport(options.profileExport, name, ExternalKind::Function));
- // Also make sure there is a memory with enough pages to write into
- size_t pages = (profileSize + Memory::kPageSize - 1) / Memory::kPageSize;
- if (!wasm->memory.exists) {
- wasm->memory.exists = true;
- wasm->memory.initial = pages;
- wasm->memory.max = pages;
- } else if (wasm->memory.initial < pages) {
- wasm->memory.initial = pages;
- if (wasm->memory.max < pages) {
- wasm->memory.max = pages;
- }
- }
-
// Export the memory if it is not already exported or imported.
- if (!wasm->memory.imported()) {
+ if (!wasm->memories[0]->imported()) {
bool memoryExported = false;
for (auto& ex : wasm->exports) {
if (ex->kind == ExternalKind::Memory) {
@@ -276,10 +281,10 @@ void Instrumenter::addProfileExport() {
}
}
if (!memoryExported) {
- wasm->addExport(
- Builder::makeExport("profile-memory",
- Names::getValidExportName(*wasm, wasm->memory.name),
- ExternalKind::Memory));
+ wasm->addExport(Builder::makeExport(
+ "profile-memory",
+ Names::getValidExportName(*wasm, wasm->memories[0]->name),
+ ExternalKind::Memory));
}
}
}
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 6b05c38cc..9424f6fda 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1187,6 +1187,7 @@ class WasmBinaryWriter {
std::unordered_map<Name, Index> globalIndexes;
std::unordered_map<Name, Index> tableIndexes;
std::unordered_map<Name, Index> elemIndexes;
+ std::unordered_map<Name, Index> memoryIndexes;
std::unordered_map<Name, Index> dataIndexes;
BinaryIndexes(Module& wasm) {
@@ -1209,6 +1210,7 @@ class WasmBinaryWriter {
addIndexes(wasm.functions, functionIndexes);
addIndexes(wasm.tags, tagIndexes);
addIndexes(wasm.tables, tableIndexes);
+ addIndexes(wasm.memories, memoryIndexes);
for (auto& curr : wasm.elementSegments) {
auto index = elemIndexes.size();
@@ -1281,7 +1283,7 @@ public:
int32_t startSubsection(BinaryConsts::UserSections::Subsection code);
void finishSubsection(int32_t start);
void writeStart();
- void writeMemory();
+ void writeMemories();
void writeTypes();
void writeImports();
@@ -1297,6 +1299,7 @@ public:
uint32_t getFunctionIndex(Name name) const;
uint32_t getTableIndex(Name name) const;
+ uint32_t getMemoryIndex(Name name) const;
uint32_t getGlobalIndex(Name name) const;
uint32_t getTagIndex(Name name) const;
uint32_t getTypeIndex(HeapType type) const;
@@ -1466,12 +1469,13 @@ public:
void verifyInt64(int64_t x);
void readHeader();
void readStart();
- void readMemory();
+ void readMemories();
void readTypes();
// gets a name in the combined import+defined space
Name getFunctionName(Index index);
Name getTableName(Index index);
+ Name getMemoryName(Index index);
Name getGlobalName(Index index);
Name getTagName(Index index);
@@ -1526,6 +1530,15 @@ public:
// names
std::vector<std::unique_ptr<ElementSegment>> elementSegments;
+ // we store memories here after being read from binary, before we know their
+ // names
+ std::vector<std::unique_ptr<Memory>> memories;
+ // we store memory imports here before wasm.addMemoryImport after we know
+ // their names
+ std::vector<Memory*> memoryImports;
+ // at index i we have all references to the memory i
+ std::map<Index, std::vector<wasm::Name*>> memoryRefs;
+
// we store data here after being read from binary, before we know their names
std::vector<std::unique_ptr<DataSegment>> dataSegments;
@@ -1646,7 +1659,7 @@ public:
BreakTarget getBreakTarget(int32_t offset);
Name getExceptionTargetName(int32_t offset);
- void readMemoryAccess(Address& alignment, Address& offset);
+ Index readMemoryAccess(Address& alignment, Address& offset);
void visitIf(If* curr);
void visitLoop(Loop* curr);
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 3677b9796..69e7a7c6a 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -107,14 +107,30 @@ public:
return seg;
}
+ static std::unique_ptr<Memory> makeMemory(Name name,
+ Address initial = 0,
+ Address max = Memory::kMaxSize32,
+ bool shared = false,
+ Type indexType = Type::i32) {
+ auto memory = std::make_unique<Memory>();
+ memory->name = name;
+ memory->initial = initial;
+ memory->max = max;
+ memory->shared = shared;
+ memory->indexType = indexType;
+ return memory;
+ }
+
static std::unique_ptr<DataSegment>
makeDataSegment(Name name = "",
+ Name memory = "",
bool isPassive = false,
Expression* offset = nullptr,
const char* init = "",
Address size = 0) {
auto seg = std::make_unique<DataSegment>();
seg->name = name;
+ seg->memory = memory;
seg->isPassive = isPassive;
seg->offset = offset;
seg->data.resize(size);
@@ -354,7 +370,8 @@ public:
uint32_t offset,
unsigned align,
Expression* ptr,
- Type type) {
+ Type type,
+ Name memory) {
auto* ret = wasm.allocator.alloc<Load>();
ret->isAtomic = false;
ret->bytes = bytes;
@@ -363,11 +380,12 @@ public:
ret->align = align;
ret->ptr = ptr;
ret->type = type;
+ ret->memory = memory;
return ret;
}
- Load*
- makeAtomicLoad(unsigned bytes, uint32_t offset, Expression* ptr, Type type) {
- Load* load = makeLoad(bytes, false, offset, bytes, ptr, type);
+ Load* makeAtomicLoad(
+ unsigned bytes, uint32_t offset, Expression* ptr, Type type, Name memory) {
+ Load* load = makeLoad(bytes, false, offset, bytes, ptr, type, memory);
load->isAtomic = true;
return load;
}
@@ -375,7 +393,8 @@ public:
Expression* expected,
Expression* timeout,
Type expectedType,
- Address offset) {
+ Address offset,
+ Name memory) {
auto* wait = wasm.allocator.alloc<AtomicWait>();
wait->offset = offset;
wait->ptr = ptr;
@@ -383,15 +402,19 @@ public:
wait->timeout = timeout;
wait->expectedType = expectedType;
wait->finalize();
+ wait->memory = memory;
return wait;
}
- AtomicNotify*
- makeAtomicNotify(Expression* ptr, Expression* notifyCount, Address offset) {
+ AtomicNotify* makeAtomicNotify(Expression* ptr,
+ Expression* notifyCount,
+ Address offset,
+ Name memory) {
auto* notify = wasm.allocator.alloc<AtomicNotify>();
notify->offset = offset;
notify->ptr = ptr;
notify->notifyCount = notifyCount;
notify->finalize();
+ notify->memory = memory;
return notify;
}
AtomicFence* makeAtomicFence() { return wasm.allocator.alloc<AtomicFence>(); }
@@ -400,7 +423,8 @@ public:
unsigned align,
Expression* ptr,
Expression* value,
- Type type) {
+ Type type,
+ Name memory) {
auto* ret = wasm.allocator.alloc<Store>();
ret->isAtomic = false;
ret->bytes = bytes;
@@ -409,6 +433,7 @@ public:
ret->ptr = ptr;
ret->value = value;
ret->valueType = type;
+ ret->memory = memory;
ret->finalize();
assert(ret->value->type.isConcrete() ? ret->value->type == type : true);
return ret;
@@ -417,8 +442,9 @@ public:
uint32_t offset,
Expression* ptr,
Expression* value,
- Type type) {
- Store* store = makeStore(bytes, offset, bytes, ptr, value, type);
+ Type type,
+ Name memory) {
+ Store* store = makeStore(bytes, offset, bytes, ptr, value, type, memory);
store->isAtomic = true;
return store;
}
@@ -427,7 +453,8 @@ public:
uint32_t offset,
Expression* ptr,
Expression* value,
- Type type) {
+ Type type,
+ Name memory) {
auto* ret = wasm.allocator.alloc<AtomicRMW>();
ret->op = op;
ret->bytes = bytes;
@@ -436,6 +463,7 @@ public:
ret->value = value;
ret->type = type;
ret->finalize();
+ ret->memory = memory;
return ret;
}
AtomicCmpxchg* makeAtomicCmpxchg(unsigned bytes,
@@ -443,7 +471,8 @@ public:
Expression* ptr,
Expression* expected,
Expression* replacement,
- Type type) {
+ Type type,
+ Name memory) {
auto* ret = wasm.allocator.alloc<AtomicCmpxchg>();
ret->bytes = bytes;
ret->offset = offset;
@@ -452,6 +481,7 @@ public:
ret->replacement = replacement;
ret->type = type;
ret->finalize();
+ ret->memory = memory;
return ret;
}
SIMDExtract*
@@ -505,13 +535,17 @@ public:
ret->finalize();
return ret;
}
- SIMDLoad*
- makeSIMDLoad(SIMDLoadOp op, Address offset, Address align, Expression* ptr) {
+ SIMDLoad* makeSIMDLoad(SIMDLoadOp op,
+ Address offset,
+ Address align,
+ Expression* ptr,
+ Name memory) {
auto* ret = wasm.allocator.alloc<SIMDLoad>();
ret->op = op;
ret->offset = offset;
ret->align = align;
ret->ptr = ptr;
+ ret->memory = memory;
ret->finalize();
return ret;
}
@@ -520,7 +554,8 @@ public:
Address align,
uint8_t index,
Expression* ptr,
- Expression* vec) {
+ Expression* vec,
+ Name memory) {
auto* ret = wasm.allocator.alloc<SIMDLoadStoreLane>();
ret->op = op;
ret->offset = offset;
@@ -529,17 +564,20 @@ public:
ret->ptr = ptr;
ret->vec = vec;
ret->finalize();
+ ret->memory = memory;
return ret;
}
MemoryInit* makeMemoryInit(uint32_t segment,
Expression* dest,
Expression* offset,
- Expression* size) {
+ Expression* size,
+ Name memory) {
auto* ret = wasm.allocator.alloc<MemoryInit>();
ret->segment = segment;
ret->dest = dest;
ret->offset = offset;
ret->size = size;
+ ret->memory = memory;
ret->finalize();
return ret;
}
@@ -549,21 +587,29 @@ public:
ret->finalize();
return ret;
}
- MemoryCopy*
- makeMemoryCopy(Expression* dest, Expression* source, Expression* size) {
+ MemoryCopy* makeMemoryCopy(Expression* dest,
+ Expression* source,
+ Expression* size,
+ Name destMemory,
+ Name sourceMemory) {
auto* ret = wasm.allocator.alloc<MemoryCopy>();
ret->dest = dest;
ret->source = source;
ret->size = size;
+ ret->destMemory = destMemory;
+ ret->sourceMemory = sourceMemory;
ret->finalize();
return ret;
}
- MemoryFill*
- makeMemoryFill(Expression* dest, Expression* value, Expression* size) {
+ MemoryFill* makeMemoryFill(Expression* dest,
+ Expression* value,
+ Expression* size,
+ Name memory) {
auto* ret = wasm.allocator.alloc<MemoryFill>();
ret->dest = dest;
ret->value = value;
ret->size = size;
+ ret->memory = memory;
ret->finalize();
return ret;
}
@@ -582,8 +628,8 @@ public:
ret->finalize();
return ret;
}
- Const* makeConstPtr(uint64_t val) {
- return makeConst(Literal::makeFromInt64(val, wasm.memory.indexType));
+ Const* makeConstPtr(uint64_t val, Type indexType) {
+ return makeConst(Literal::makeFromInt64(val, indexType));
}
Binary* makeBinary(BinaryOp op, Expression* left, Expression* right) {
auto* ret = wasm.allocator.alloc<Binary>();
@@ -618,20 +664,24 @@ public:
ret->value = value;
return ret;
}
- MemorySize* makeMemorySize() {
+ MemorySize* makeMemorySize(Name memoryName) {
+ auto memory = wasm.getMemory(memoryName);
auto* ret = wasm.allocator.alloc<MemorySize>();
- if (wasm.memory.is64()) {
+ if (memory->is64()) {
ret->make64();
}
+ ret->memory = memoryName;
ret->finalize();
return ret;
}
- MemoryGrow* makeMemoryGrow(Expression* delta) {
+ MemoryGrow* makeMemoryGrow(Expression* delta, Name memoryName) {
+ auto memory = wasm.getMemory(memoryName);
auto* ret = wasm.allocator.alloc<MemoryGrow>();
- if (wasm.memory.is64()) {
+ if (memory->is64()) {
ret->make64();
}
ret->delta = delta;
+ ret->memory = memoryName;
ret->finalize();
return ret;
}
diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def
index 0e3f60826..ff0f41d50 100644
--- a/src/wasm-delegations-fields.def
+++ b/src/wasm-delegations-fields.def
@@ -266,6 +266,7 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_ADDRESS(Load, offset);
DELEGATE_FIELD_ADDRESS(Load, align);
DELEGATE_FIELD_INT(Load, isAtomic);
+ DELEGATE_FIELD_NAME(Load, memory);
DELEGATE_END(Load);
break;
}
@@ -278,6 +279,7 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_ADDRESS(Store, align);
DELEGATE_FIELD_INT(Store, isAtomic);
DELEGATE_FIELD_TYPE(Store, valueType);
+ DELEGATE_FIELD_NAME(Store, memory);
DELEGATE_END(Store);
break;
}
@@ -288,6 +290,7 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_INT(AtomicRMW, op);
DELEGATE_FIELD_INT(AtomicRMW, bytes);
DELEGATE_FIELD_ADDRESS(AtomicRMW, offset);
+ DELEGATE_FIELD_NAME(AtomicRMW, memory);
DELEGATE_END(AtomicRMW);
break;
}
@@ -298,6 +301,7 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_CHILD(AtomicCmpxchg, ptr);
DELEGATE_FIELD_INT(AtomicCmpxchg, bytes);
DELEGATE_FIELD_ADDRESS(AtomicCmpxchg, offset);
+ DELEGATE_FIELD_NAME(AtomicCmpxchg, memory);
DELEGATE_END(AtomicCmpxchg);
break;
}
@@ -308,6 +312,7 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_CHILD(AtomicWait, ptr);
DELEGATE_FIELD_ADDRESS(AtomicWait, offset);
DELEGATE_FIELD_TYPE(AtomicWait, expectedType);
+ DELEGATE_FIELD_NAME(AtomicWait, memory);
DELEGATE_END(AtomicWait);
break;
}
@@ -316,6 +321,7 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_CHILD(AtomicNotify, notifyCount);
DELEGATE_FIELD_CHILD(AtomicNotify, ptr);
DELEGATE_FIELD_ADDRESS(AtomicNotify, offset);
+ DELEGATE_FIELD_NAME(AtomicNotify, memory);
DELEGATE_END(AtomicNotify);
break;
}
@@ -373,6 +379,7 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_INT(SIMDLoad, op);
DELEGATE_FIELD_ADDRESS(SIMDLoad, offset);
DELEGATE_FIELD_ADDRESS(SIMDLoad, align);
+ DELEGATE_FIELD_NAME(SIMDLoad, memory);
DELEGATE_END(SIMDLoad);
break;
}
@@ -384,6 +391,7 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_ADDRESS(SIMDLoadStoreLane, offset);
DELEGATE_FIELD_ADDRESS(SIMDLoadStoreLane, align);
DELEGATE_FIELD_INT(SIMDLoadStoreLane, index);
+ DELEGATE_FIELD_NAME(SIMDLoadStoreLane, memory);
DELEGATE_END(SIMDLoadStoreLane);
break;
}
@@ -393,6 +401,7 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_CHILD(MemoryInit, offset);
DELEGATE_FIELD_CHILD(MemoryInit, dest);
DELEGATE_FIELD_INT(MemoryInit, segment);
+ DELEGATE_FIELD_NAME(MemoryInit, memory);
DELEGATE_END(MemoryInit);
break;
}
@@ -407,6 +416,8 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_CHILD(MemoryCopy, size);
DELEGATE_FIELD_CHILD(MemoryCopy, source);
DELEGATE_FIELD_CHILD(MemoryCopy, dest);
+ DELEGATE_FIELD_NAME(MemoryCopy, sourceMemory);
+ DELEGATE_FIELD_NAME(MemoryCopy, destMemory);
DELEGATE_END(MemoryCopy);
break;
}
@@ -415,6 +426,7 @@ switch (DELEGATE_ID) {
DELEGATE_FIELD_CHILD(MemoryFill, size);
DELEGATE_FIELD_CHILD(MemoryFill, value);
DELEGATE_FIELD_CHILD(MemoryFill, dest);
+ DELEGATE_FIELD_NAME(MemoryFill, memory);
DELEGATE_END(MemoryFill);
break;
}
@@ -462,6 +474,7 @@ switch (DELEGATE_ID) {
case Expression::Id::MemorySizeId: {
DELEGATE_START(MemorySize);
DELEGATE_FIELD_TYPE(MemorySize, ptrType);
+ DELEGATE_FIELD_NAME(MemorySize, memory);
DELEGATE_END(MemorySize);
break;
}
@@ -469,6 +482,7 @@ switch (DELEGATE_ID) {
DELEGATE_START(MemoryGrow);
DELEGATE_FIELD_TYPE(MemoryGrow, ptrType);
DELEGATE_FIELD_CHILD(MemoryGrow, delta);
+ DELEGATE_FIELD_NAME(MemoryGrow, memory);
DELEGATE_END(MemoryGrow);
break;
}
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 254a1a2e2..fec560e35 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -2273,7 +2273,7 @@ public:
Literals& arguments,
Type result,
SubType& instance) = 0;
- virtual bool growMemory(Address oldSize, Address newSize) = 0;
+ virtual bool growMemory(Name name, Address oldSize, Address newSize) = 0;
virtual bool growTable(Name name,
const Literal& value,
Index oldSize,
@@ -2284,18 +2284,18 @@ public:
// the default impls for load and store switch on the sizes. you can either
// customize load/store, or the sub-functions which they call
- virtual Literal load(Load* load, Address addr) {
+ virtual Literal load(Load* load, Address addr, Name memory) {
switch (load->type.getBasic()) {
case Type::i32: {
switch (load->bytes) {
case 1:
- return load->signed_ ? Literal((int32_t)load8s(addr))
- : Literal((int32_t)load8u(addr));
+ return load->signed_ ? Literal((int32_t)load8s(addr, memory))
+ : Literal((int32_t)load8u(addr, memory));
case 2:
- return load->signed_ ? Literal((int32_t)load16s(addr))
- : Literal((int32_t)load16u(addr));
+ return load->signed_ ? Literal((int32_t)load16s(addr, memory))
+ : Literal((int32_t)load16u(addr, memory));
case 4:
- return Literal((int32_t)load32s(addr));
+ return Literal((int32_t)load32s(addr, memory));
default:
WASM_UNREACHABLE("invalid size");
}
@@ -2304,45 +2304,45 @@ public:
case Type::i64: {
switch (load->bytes) {
case 1:
- return load->signed_ ? Literal((int64_t)load8s(addr))
- : Literal((int64_t)load8u(addr));
+ return load->signed_ ? Literal((int64_t)load8s(addr, memory))
+ : Literal((int64_t)load8u(addr, memory));
case 2:
- return load->signed_ ? Literal((int64_t)load16s(addr))
- : Literal((int64_t)load16u(addr));
+ return load->signed_ ? Literal((int64_t)load16s(addr, memory))
+ : Literal((int64_t)load16u(addr, memory));
case 4:
- return load->signed_ ? Literal((int64_t)load32s(addr))
- : Literal((int64_t)load32u(addr));
+ return load->signed_ ? Literal((int64_t)load32s(addr, memory))
+ : Literal((int64_t)load32u(addr, memory));
case 8:
- return Literal((int64_t)load64s(addr));
+ return Literal((int64_t)load64s(addr, memory));
default:
WASM_UNREACHABLE("invalid size");
}
break;
}
case Type::f32:
- return Literal(load32u(addr)).castToF32();
+ return Literal(load32u(addr, memory)).castToF32();
case Type::f64:
- return Literal(load64u(addr)).castToF64();
+ return Literal(load64u(addr, memory)).castToF64();
case Type::v128:
- return Literal(load128(addr).data());
+ return Literal(load128(addr, load->memory).data());
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
}
WASM_UNREACHABLE("invalid type");
}
- virtual void store(Store* store, Address addr, Literal value) {
+ virtual void store(Store* store, Address addr, Literal value, Name memory) {
switch (store->valueType.getBasic()) {
case Type::i32: {
switch (store->bytes) {
case 1:
- store8(addr, value.geti32());
+ store8(addr, value.geti32(), memory);
break;
case 2:
- store16(addr, value.geti32());
+ store16(addr, value.geti32(), memory);
break;
case 4:
- store32(addr, value.geti32());
+ store32(addr, value.geti32(), memory);
break;
default:
WASM_UNREACHABLE("invalid store size");
@@ -2352,16 +2352,16 @@ public:
case Type::i64: {
switch (store->bytes) {
case 1:
- store8(addr, value.geti64());
+ store8(addr, value.geti64(), memory);
break;
case 2:
- store16(addr, value.geti64());
+ store16(addr, value.geti64(), memory);
break;
case 4:
- store32(addr, value.geti64());
+ store32(addr, value.geti64(), memory);
break;
case 8:
- store64(addr, value.geti64());
+ store64(addr, value.geti64(), memory);
break;
default:
WASM_UNREACHABLE("invalid store size");
@@ -2370,13 +2370,13 @@ public:
}
// write floats carefully, ensuring all bits reach memory
case Type::f32:
- store32(addr, value.reinterpreti32());
+ store32(addr, value.reinterpreti32(), memory);
break;
case Type::f64:
- store64(addr, value.reinterpreti64());
+ store64(addr, value.reinterpreti64(), memory);
break;
case Type::v128:
- store128(addr, value.getv128());
+ store128(addr, value.getv128(), memory);
break;
case Type::none:
case Type::unreachable:
@@ -2384,31 +2384,48 @@ public:
}
}
- virtual int8_t load8s(Address addr) { WASM_UNREACHABLE("unimp"); }
- virtual uint8_t load8u(Address addr) { WASM_UNREACHABLE("unimp"); }
- virtual int16_t load16s(Address addr) { WASM_UNREACHABLE("unimp"); }
- virtual uint16_t load16u(Address addr) { WASM_UNREACHABLE("unimp"); }
- virtual int32_t load32s(Address addr) { WASM_UNREACHABLE("unimp"); }
- virtual uint32_t load32u(Address addr) { WASM_UNREACHABLE("unimp"); }
- virtual int64_t load64s(Address addr) { WASM_UNREACHABLE("unimp"); }
- virtual uint64_t load64u(Address addr) { WASM_UNREACHABLE("unimp"); }
- virtual std::array<uint8_t, 16> load128(Address addr) {
+ virtual int8_t load8s(Address addr, Name memoryName) {
+ WASM_UNREACHABLE("unimp");
+ }
+ virtual uint8_t load8u(Address addr, Name memoryName) {
+ WASM_UNREACHABLE("unimp");
+ }
+ virtual int16_t load16s(Address addr, Name memoryName) {
+ WASM_UNREACHABLE("unimp");
+ }
+ virtual uint16_t load16u(Address addr, Name memoryName) {
+ WASM_UNREACHABLE("unimp");
+ }
+ virtual int32_t load32s(Address addr, Name memoryName) {
+ WASM_UNREACHABLE("unimp");
+ }
+ virtual uint32_t load32u(Address addr, Name memoryName) {
+ WASM_UNREACHABLE("unimp");
+ }
+ virtual int64_t load64s(Address addr, Name memoryName) {
+ WASM_UNREACHABLE("unimp");
+ }
+ virtual uint64_t load64u(Address addr, Name memoryName) {
+ WASM_UNREACHABLE("unimp");
+ }
+ virtual std::array<uint8_t, 16> load128(Address addr, Name memoryName) {
WASM_UNREACHABLE("unimp");
}
- virtual void store8(Address addr, int8_t value) {
+ virtual void store8(Address addr, int8_t value, Name memoryName) {
WASM_UNREACHABLE("unimp");
}
- virtual void store16(Address addr, int16_t value) {
+ virtual void store16(Address addr, int16_t value, Name memoryName) {
WASM_UNREACHABLE("unimp");
}
- virtual void store32(Address addr, int32_t value) {
+ virtual void store32(Address addr, int32_t value, Name memoryName) {
WASM_UNREACHABLE("unimp");
}
- virtual void store64(Address addr, int64_t value) {
+ virtual void store64(Address addr, int64_t value, Name memoryName) {
WASM_UNREACHABLE("unimp");
}
- virtual void store128(Address addr, const std::array<uint8_t, 16>&) {
+ virtual void
+ store128(Address addr, const std::array<uint8_t, 16>&, Name memoryName) {
WASM_UNREACHABLE("unimp");
}
@@ -2441,8 +2458,6 @@ public:
externalInterface(externalInterface), linkedInstances(linkedInstances_) {
// import globals from the outside
externalInterface->importGlobals(globals, wasm);
- // prepare memory
- memorySize = wasm.memory.initial;
// generate internal (non-imported) globals
ModuleUtils::iterDefinedGlobals(wasm, [&](Global* global) {
globals[global->name] = self()->visit(global->init).values;
@@ -2556,7 +2571,27 @@ private:
});
}
+ struct MemoryInstanceInfo {
+ // The ModuleRunner instance in which the memory is defined.
+ SubType* instance;
+ // The name the memory has in that interface.
+ Name name;
+ };
+
+ MemoryInstanceInfo getMemoryInstanceInfo(Name name) {
+ auto* memory = wasm.getMemory(name);
+ MemoryInstanceInfo memoryInterfaceInfo;
+ if (!memory->imported()) {
+ return MemoryInstanceInfo{self(), name};
+ }
+
+ auto& importedInstance = linkedInstances.at(memory->module);
+ auto* memoryExport = importedInstance->wasm.getExport(memory->base);
+ return importedInstance->getMemoryInstanceInfo(memoryExport->value);
+ }
+
void initializeMemoryContents() {
+ initializeMemorySizes();
Const offset;
offset.value = Literal(uint32_t(0));
offset.finalize();
@@ -2572,6 +2607,7 @@ private:
size.finalize();
MemoryInit init;
+ init.memory = segment->memory;
init.segment = i;
init.dest = segment->offset;
init.offset = &offset;
@@ -2587,6 +2623,31 @@ private:
}
}
+ // in pages, used to keep track of memorySize throughout the below memops
+ std::unordered_map<Name, Address> memorySizes;
+
+ void initializeMemorySizes() {
+ for (auto& memory : wasm.memories) {
+ memorySizes[memory->name] = memory->initial;
+ }
+ }
+
+ Address getMemorySize(Name memory) {
+ auto iter = memorySizes.find(memory);
+ if (iter == memorySizes.end()) {
+ externalInterface->trap("getMemorySize called on non-existing memory");
+ }
+ return iter->second;
+ }
+
+ void setMemorySize(Name memory, Address size) {
+ auto iter = memorySizes.find(memory);
+ if (iter == memorySizes.end()) {
+ externalInterface->trap("setMemorySize called on non-existing memory");
+ }
+ memorySizes[memory] = size;
+ }
+
public:
class FunctionScope {
public:
@@ -2645,15 +2706,6 @@ private:
SmallVector<std::pair<WasmException, Name>, 4> exceptionStack;
protected:
- // Returns the instance that defines the memory used by this one.
- SubType* getMemoryInstance() {
- auto* inst = self();
- while (inst->wasm.memory.imported()) {
- inst = inst->linkedInstances.at(inst->wasm.memory.module).get();
- }
- return inst;
- }
-
// Returns a reference to the current value of a potentially imported global
Literals& getGlobal(Name name) {
auto* inst = self();
@@ -2874,12 +2926,14 @@ public:
return flow;
}
NOTE_EVAL1(flow);
- auto* inst = getMemoryInstance();
- auto addr = inst->getFinalAddress(curr, flow.getSingleValue());
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
+ auto addr =
+ info.instance->getFinalAddress(curr, flow.getSingleValue(), memorySize);
if (curr->isAtomic) {
- inst->checkAtomicAddress(addr, curr->bytes);
+ info.instance->checkAtomicAddress(addr, curr->bytes, memorySize);
}
- auto ret = inst->externalInterface->load(curr, addr);
+ auto ret = info.instance->externalInterface->load(curr, addr, info.name);
NOTE_EVAL1(addr);
NOTE_EVAL1(ret);
return ret;
@@ -2894,14 +2948,17 @@ public:
if (value.breaking()) {
return value;
}
- auto* inst = getMemoryInstance();
- auto addr = inst->getFinalAddress(curr, ptr.getSingleValue());
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
+ auto addr =
+ info.instance->getFinalAddress(curr, ptr.getSingleValue(), memorySize);
if (curr->isAtomic) {
- inst->checkAtomicAddress(addr, curr->bytes);
+ info.instance->checkAtomicAddress(addr, curr->bytes, memorySize);
}
NOTE_EVAL1(addr);
NOTE_EVAL1(value);
- inst->externalInterface->store(curr, addr, value.getSingleValue());
+ info.instance->externalInterface->store(
+ curr, addr, value.getSingleValue(), info.name);
return Flow();
}
@@ -2916,11 +2973,14 @@ public:
return value;
}
NOTE_EVAL1(ptr);
- auto* inst = getMemoryInstance();
- auto addr = inst->getFinalAddress(curr, ptr.getSingleValue());
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
+ auto addr =
+ info.instance->getFinalAddress(curr, ptr.getSingleValue(), memorySize);
NOTE_EVAL1(addr);
NOTE_EVAL1(value);
- auto loaded = inst->doAtomicLoad(addr, curr->bytes, curr->type);
+ auto loaded = info.instance->doAtomicLoad(
+ addr, curr->bytes, curr->type, info.name, memorySize);
NOTE_EVAL1(loaded);
auto computed = value.getSingleValue();
switch (curr->op) {
@@ -2942,7 +3002,8 @@ public:
case RMWXchg:
break;
}
- inst->doAtomicStore(addr, curr->bytes, computed);
+ info.instance->doAtomicStore(
+ addr, curr->bytes, computed, info.name, memorySize);
return loaded;
}
Flow visitAtomicCmpxchg(AtomicCmpxchg* curr) {
@@ -2960,16 +3021,20 @@ public:
if (replacement.breaking()) {
return replacement;
}
- auto* inst = getMemoryInstance();
- auto addr = inst->getFinalAddress(curr, ptr.getSingleValue());
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
+ auto addr =
+ info.instance->getFinalAddress(curr, ptr.getSingleValue(), memorySize);
expected = Flow(wrapToSmallerSize(expected.getSingleValue(), curr->bytes));
NOTE_EVAL1(addr);
NOTE_EVAL1(expected);
NOTE_EVAL1(replacement);
- auto loaded = inst->doAtomicLoad(addr, curr->bytes, curr->type);
+ auto loaded = info.instance->doAtomicLoad(
+ addr, curr->bytes, curr->type, info.name, memorySize);
NOTE_EVAL1(loaded);
if (loaded == expected.getSingleValue()) {
- inst->doAtomicStore(addr, curr->bytes, replacement.getSingleValue());
+ info.instance->doAtomicStore(
+ addr, curr->bytes, replacement.getSingleValue(), info.name, memorySize);
}
return loaded;
}
@@ -2990,10 +3055,13 @@ public:
if (timeout.breaking()) {
return timeout;
}
- auto* inst = getMemoryInstance();
auto bytes = curr->expectedType.getByteSize();
- auto addr = inst->getFinalAddress(curr, ptr.getSingleValue(), bytes);
- auto loaded = inst->doAtomicLoad(addr, bytes, curr->expectedType);
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
+ auto addr = info.instance->getFinalAddress(
+ curr, ptr.getSingleValue(), bytes, memorySize);
+ auto loaded = info.instance->doAtomicLoad(
+ addr, bytes, curr->expectedType, info.name, memorySize);
NOTE_EVAL1(loaded);
if (loaded != expected.getSingleValue()) {
return Literal(int32_t(1)); // not equal
@@ -3014,10 +3082,12 @@ public:
if (count.breaking()) {
return count;
}
- auto* inst = getMemoryInstance();
- auto addr = inst->getFinalAddress(curr, ptr.getSingleValue(), 4);
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
+ auto addr =
+ info.instance->getFinalAddress(curr, ptr.getSingleValue(), 4, memorySize);
// Just check TODO actual threads support
- inst->checkAtomicAddress(addr, 4);
+ info.instance->checkAtomicAddress(addr, 4, memorySize);
return Literal(int32_t(0)); // none woken up
}
Flow visitSIMDLoad(SIMDLoad* curr) {
@@ -3043,6 +3113,7 @@ public:
}
Flow visitSIMDLoadSplat(SIMDLoad* curr) {
Load load;
+ load.memory = curr->memory;
load.type = Type::i32;
load.bytes = curr->getMemBytes();
load.signed_ = false;
@@ -3082,30 +3153,37 @@ public:
}
NOTE_EVAL1(flow);
Address src(uint32_t(flow.getSingleValue().geti32()));
- auto* inst = getMemoryInstance();
+ auto info = getMemoryInstanceInfo(curr->memory);
auto loadLane = [&](Address addr) {
switch (curr->op) {
case Load8x8SVec128:
- return Literal(int32_t(inst->externalInterface->load8s(addr)));
+ return Literal(
+ int32_t(info.instance->externalInterface->load8s(addr, info.name)));
case Load8x8UVec128:
- return Literal(int32_t(inst->externalInterface->load8u(addr)));
+ return Literal(
+ int32_t(info.instance->externalInterface->load8u(addr, info.name)));
case Load16x4SVec128:
- return Literal(int32_t(inst->externalInterface->load16s(addr)));
+ return Literal(int32_t(
+ info.instance->externalInterface->load16s(addr, info.name)));
case Load16x4UVec128:
- return Literal(int32_t(inst->externalInterface->load16u(addr)));
+ return Literal(int32_t(
+ info.instance->externalInterface->load16u(addr, info.name)));
case Load32x2SVec128:
- return Literal(int64_t(inst->externalInterface->load32s(addr)));
+ return Literal(int64_t(
+ info.instance->externalInterface->load32s(addr, info.name)));
case Load32x2UVec128:
- return Literal(int64_t(inst->externalInterface->load32u(addr)));
+ return Literal(int64_t(
+ info.instance->externalInterface->load32u(addr, info.name)));
default:
WASM_UNREACHABLE("unexpected op");
}
WASM_UNREACHABLE("invalid op");
};
+ auto memorySize = info.instance->getMemorySize(info.name);
auto fillLanes = [&](auto lanes, size_t laneBytes) {
for (auto& lane : lanes) {
- lane = loadLane(
- inst->getFinalAddress(curr, Literal(uint32_t(src)), laneBytes));
+ lane = loadLane(info.instance->getFinalAddress(
+ curr, Literal(uint32_t(src)), laneBytes, memorySize));
src = Address(uint32_t(src) + laneBytes);
}
return Literal(lanes);
@@ -3137,16 +3215,19 @@ public:
return flow;
}
NOTE_EVAL1(flow);
- auto* inst = getMemoryInstance();
- Address src =
- inst->getFinalAddress(curr, flow.getSingleValue(), curr->getMemBytes());
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
+ Address src = info.instance->getFinalAddress(
+ curr, flow.getSingleValue(), curr->getMemBytes(), memorySize);
auto zero =
Literal::makeZero(curr->op == Load32ZeroVec128 ? Type::i32 : Type::i64);
if (curr->op == Load32ZeroVec128) {
- auto val = Literal(inst->externalInterface->load32u(src));
+ auto val =
+ Literal(info.instance->externalInterface->load32u(src, info.name));
return Literal(std::array<Literal, 4>{{val, zero, zero, zero}});
} else {
- auto val = Literal(inst->externalInterface->load64u(src));
+ auto val =
+ Literal(info.instance->externalInterface->load64u(src, info.name));
return Literal(std::array<Literal, 2>{{val, zero}});
}
}
@@ -3157,9 +3238,10 @@ public:
return flow;
}
NOTE_EVAL1(flow);
- auto* inst = getMemoryInstance();
- Address addr =
- inst->getFinalAddress(curr, flow.getSingleValue(), curr->getMemBytes());
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
+ Address addr = info.instance->getFinalAddress(
+ curr, flow.getSingleValue(), curr->getMemBytes(), memorySize);
flow = self()->visit(curr->vec);
if (flow.breaking()) {
return flow;
@@ -3170,10 +3252,12 @@ public:
case Store8LaneVec128: {
std::array<Literal, 16> lanes = vec.getLanesUI8x16();
if (curr->isLoad()) {
- lanes[curr->index] = Literal(inst->externalInterface->load8u(addr));
+ lanes[curr->index] =
+ Literal(info.instance->externalInterface->load8u(addr, info.name));
return Literal(lanes);
} else {
- inst->externalInterface->store8(addr, lanes[curr->index].geti32());
+ info.instance->externalInterface->store8(
+ addr, lanes[curr->index].geti32(), info.name);
return {};
}
}
@@ -3181,10 +3265,12 @@ public:
case Store16LaneVec128: {
std::array<Literal, 8> lanes = vec.getLanesUI16x8();
if (curr->isLoad()) {
- lanes[curr->index] = Literal(inst->externalInterface->load16u(addr));
+ lanes[curr->index] =
+ Literal(info.instance->externalInterface->load16u(addr, info.name));
return Literal(lanes);
} else {
- inst->externalInterface->store16(addr, lanes[curr->index].geti32());
+ info.instance->externalInterface->store16(
+ addr, lanes[curr->index].geti32(), info.name);
return {};
}
}
@@ -3192,10 +3278,12 @@ public:
case Store32LaneVec128: {
std::array<Literal, 4> lanes = vec.getLanesI32x4();
if (curr->isLoad()) {
- lanes[curr->index] = Literal(inst->externalInterface->load32u(addr));
+ lanes[curr->index] =
+ Literal(info.instance->externalInterface->load32u(addr, info.name));
return Literal(lanes);
} else {
- inst->externalInterface->store32(addr, lanes[curr->index].geti32());
+ info.instance->externalInterface->store32(
+ addr, lanes[curr->index].geti32(), info.name);
return {};
}
}
@@ -3203,10 +3291,12 @@ public:
case Load64LaneVec128: {
std::array<Literal, 2> lanes = vec.getLanesI64x2();
if (curr->isLoad()) {
- lanes[curr->index] = Literal(inst->externalInterface->load64u(addr));
+ lanes[curr->index] =
+ Literal(info.instance->externalInterface->load64u(addr, info.name));
return Literal(lanes);
} else {
- inst->externalInterface->store64(addr, lanes[curr->index].geti64());
+ info.instance->externalInterface->store64(
+ addr, lanes[curr->index].geti64(), info.name);
return {};
}
}
@@ -3215,38 +3305,44 @@ public:
}
Flow visitMemorySize(MemorySize* curr) {
NOTE_ENTER("MemorySize");
- auto* inst = getMemoryInstance();
- return Literal::makeFromInt64(inst->memorySize,
- inst->wasm.memory.indexType);
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
+ auto* memory = info.instance->wasm.getMemory(info.name);
+ return Literal::makeFromInt64(memorySize, memory->indexType);
}
Flow visitMemoryGrow(MemoryGrow* curr) {
NOTE_ENTER("MemoryGrow");
- auto* inst = getMemoryInstance();
- auto indexType = inst->wasm.memory.indexType;
- auto fail = Literal::makeFromInt64(-1, indexType);
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
+ auto* memory = info.instance->wasm.getMemory(info.name);
+ auto indexType = memory->indexType;
+ auto fail = Literal::makeFromInt64(-1, memory->indexType);
Flow flow = self()->visit(curr->delta);
if (flow.breaking()) {
return flow;
}
- Flow ret = Literal::makeFromInt64(inst->memorySize, indexType);
+ Flow ret = Literal::makeFromInt64(memorySize, indexType);
uint64_t delta = flow.getSingleValue().getUnsigned();
if (delta > uint32_t(-1) / Memory::kPageSize && indexType == Type::i32) {
return fail;
}
- if (inst->memorySize >= uint32_t(-1) - delta && indexType == Type::i32) {
+ if (memorySize >= uint32_t(-1) - delta && indexType == Type::i32) {
return fail;
}
- auto newSize = inst->memorySize + delta;
- if (newSize > inst->wasm.memory.max) {
+ auto newSize = memorySize + delta;
+ if (newSize > memory->max) {
return fail;
}
- if (!inst->externalInterface->growMemory(
- inst->memorySize * Memory::kPageSize, newSize * Memory::kPageSize)) {
+ if (!info.instance->externalInterface->growMemory(
+ info.name,
+ memorySize * Memory::kPageSize,
+ newSize * Memory::kPageSize)) {
// We failed to grow the memory in practice, even though it was valid
// to try to do so.
return fail;
}
- inst->memorySize = newSize;
+ memorySize = newSize;
+ info.instance->setMemorySize(info.name, memorySize);
return ret;
}
Flow visitMemoryInit(MemoryInit* curr) {
@@ -3280,15 +3376,17 @@ public:
if ((uint64_t)offsetVal + sizeVal > segment->data.size()) {
trap("out of bounds segment access in memory.init");
}
- auto* inst = getMemoryInstance();
- if (destVal + sizeVal > inst->memorySize * Memory::kPageSize) {
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
+ if (destVal + sizeVal > memorySize * Memory::kPageSize) {
trap("out of bounds memory access in memory.init");
}
for (size_t i = 0; i < sizeVal; ++i) {
Literal addr(destVal + i);
- inst->externalInterface->store8(
- inst->getFinalAddressWithoutOffset(addr, 1),
- segment->data[offsetVal + i]);
+ info.instance->externalInterface->store8(
+ info.instance->getFinalAddressWithoutOffset(addr, 1, memorySize),
+ segment->data[offsetVal + i],
+ info.name);
}
return {};
}
@@ -3318,9 +3416,12 @@ public:
Address sourceVal(source.getSingleValue().getUnsigned());
Address sizeVal(size.getSingleValue().getUnsigned());
- auto* inst = getMemoryInstance();
- if (sourceVal + sizeVal > inst->memorySize * Memory::kPageSize ||
- destVal + sizeVal > inst->memorySize * Memory::kPageSize ||
+ auto destInfo = getMemoryInstanceInfo(curr->destMemory);
+ auto sourceInfo = getMemoryInstanceInfo(curr->sourceMemory);
+ auto destMemorySize = destInfo.instance->getMemorySize(destInfo.name);
+ auto sourceMemorySize = sourceInfo.instance->getMemorySize(sourceInfo.name);
+ if (sourceVal + sizeVal > sourceMemorySize * Memory::kPageSize ||
+ destVal + sizeVal > destMemorySize * Memory::kPageSize ||
// FIXME: better/cheaper way to detect wrapping?
sourceVal + sizeVal < sourceVal || sourceVal + sizeVal < sizeVal ||
destVal + sizeVal < destVal || destVal + sizeVal < sizeVal) {
@@ -3337,10 +3438,14 @@ public:
step = -1;
}
for (int64_t i = start; i != end; i += step) {
- inst->externalInterface->store8(
- inst->getFinalAddressWithoutOffset(Literal(destVal + i), 1),
- inst->externalInterface->load8s(
- inst->getFinalAddressWithoutOffset(Literal(sourceVal + i), 1)));
+ destInfo.instance->externalInterface->store8(
+ destInfo.instance->getFinalAddressWithoutOffset(
+ Literal(destVal + i), 1, destMemorySize),
+ sourceInfo.instance->externalInterface->load8s(
+ sourceInfo.instance->getFinalAddressWithoutOffset(
+ Literal(sourceVal + i), 1, sourceMemorySize),
+ sourceInfo.name),
+ destInfo.name);
}
return {};
}
@@ -3364,17 +3469,21 @@ public:
Address destVal(dest.getSingleValue().getUnsigned());
Address sizeVal(size.getSingleValue().getUnsigned());
- auto* inst = getMemoryInstance();
+ auto info = getMemoryInstanceInfo(curr->memory);
+ auto memorySize = info.instance->getMemorySize(info.name);
// FIXME: cheaper wrapping detection?
- if (destVal > inst->memorySize * Memory::kPageSize ||
- sizeVal > inst->memorySize * Memory::kPageSize ||
- destVal + sizeVal > inst->memorySize * Memory::kPageSize) {
+ if (destVal > memorySize * Memory::kPageSize ||
+ sizeVal > memorySize * Memory::kPageSize ||
+ destVal + sizeVal > memorySize * Memory::kPageSize) {
trap("out of bounds memory access in memory.fill");
}
uint8_t val(value.getSingleValue().geti32());
for (size_t i = 0; i < sizeVal; ++i) {
- inst->externalInterface->store8(
- inst->getFinalAddressWithoutOffset(Literal(destVal + i), 1), val);
+ info.instance->externalInterface->store8(
+ info.instance->getFinalAddressWithoutOffset(
+ Literal(destVal + i), 1, memorySize),
+ val,
+ info.name);
}
return {};
}
@@ -3550,8 +3659,6 @@ public:
static const Index maxDepth = 250;
protected:
- Address memorySize; // in pages
-
void trapIfGt(uint64_t lhs, uint64_t rhs, const char* msg) {
if (lhs > rhs) {
std::stringstream ss;
@@ -3561,34 +3668,37 @@ protected:
}
template<class LS>
- Address getFinalAddress(LS* curr, Literal ptr, Index bytes) {
+ Address
+ getFinalAddress(LS* curr, Literal ptr, Index bytes, Address memorySize) {
Address memorySizeBytes = memorySize * Memory::kPageSize;
uint64_t addr = ptr.type == Type::i32 ? ptr.geti32() : ptr.geti64();
trapIfGt(curr->offset, memorySizeBytes, "offset > memory");
trapIfGt(addr, memorySizeBytes - curr->offset, "final > memory");
addr += curr->offset;
trapIfGt(bytes, memorySizeBytes, "bytes > memory");
- checkLoadAddress(addr, bytes);
+ checkLoadAddress(addr, bytes, memorySize);
return addr;
}
- template<class LS> Address getFinalAddress(LS* curr, Literal ptr) {
- return getFinalAddress(curr, ptr, curr->bytes);
+ template<class LS>
+ Address getFinalAddress(LS* curr, Literal ptr, Address memorySize) {
+ return getFinalAddress(curr, ptr, curr->bytes, memorySize);
}
- Address getFinalAddressWithoutOffset(Literal ptr, Index bytes) {
+ Address
+ getFinalAddressWithoutOffset(Literal ptr, Index bytes, Address memorySize) {
uint64_t addr = ptr.type == Type::i32 ? ptr.geti32() : ptr.geti64();
- checkLoadAddress(addr, bytes);
+ checkLoadAddress(addr, bytes, memorySize);
return addr;
}
- void checkLoadAddress(Address addr, Index bytes) {
+ void checkLoadAddress(Address addr, Index bytes, Address memorySize) {
Address memorySizeBytes = memorySize * Memory::kPageSize;
trapIfGt(addr, memorySizeBytes - bytes, "highest > memory");
}
- void checkAtomicAddress(Address addr, Index bytes) {
- checkLoadAddress(addr, bytes);
+ void checkAtomicAddress(Address addr, Index bytes, Address memorySize) {
+ checkLoadAddress(addr, bytes, memorySize);
// Unaligned atomics trap.
if (bytes > 1) {
if (addr & (bytes - 1)) {
@@ -3597,8 +3707,9 @@ protected:
}
}
- Literal doAtomicLoad(Address addr, Index bytes, Type type) {
- checkAtomicAddress(addr, bytes);
+ Literal doAtomicLoad(
+ Address addr, Index bytes, Type type, Name memoryName, Address memorySize) {
+ checkAtomicAddress(addr, bytes, memorySize);
Const ptr;
ptr.value = Literal(int32_t(addr));
ptr.type = Type::i32;
@@ -3611,11 +3722,16 @@ protected:
load.isAtomic = true; // understatement
load.ptr = &ptr;
load.type = type;
- return externalInterface->load(&load, addr);
+ load.memory = memoryName;
+ return externalInterface->load(&load, addr, memoryName);
}
- void doAtomicStore(Address addr, Index bytes, Literal toStore) {
- checkAtomicAddress(addr, bytes);
+ void doAtomicStore(Address addr,
+ Index bytes,
+ Literal toStore,
+ Name memoryName,
+ Address memorySize) {
+ checkAtomicAddress(addr, bytes, memorySize);
Const ptr;
ptr.value = Literal(int32_t(addr));
ptr.type = Type::i32;
@@ -3629,7 +3745,8 @@ protected:
store.ptr = &ptr;
store.value = &value;
store.valueType = value.type;
- return externalInterface->store(&store, addr, toStore);
+ store.memory = memoryName;
+ return externalInterface->store(&store, addr, toStore, memoryName);
}
ExternalInterface* externalInterface;
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 64f764721..c91c01842 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -126,6 +126,7 @@ class SExpressionWasmBuilder {
std::vector<Name> functionNames;
std::vector<Name> tableNames;
+ std::vector<Name> memoryNames;
std::vector<Name> globalNames;
std::vector<Name> tagNames;
int functionCounter = 0;
@@ -158,6 +159,7 @@ private:
void preParseFunctionType(Element& s);
bool isImport(Element& curr);
void preParseImports(Element& curr);
+ void preParseMemory(Element& curr);
void parseModuleElement(Element& curr);
// function parsing state
@@ -168,10 +170,15 @@ private:
Name getFunctionName(Element& s);
Name getTableName(Element& s);
+ Name getMemoryName(Element& s);
Name getGlobalName(Element& s);
Name getTagName(Element& s);
void parseStart(Element& s) { wasm.addStart(getFunctionName(*s[1])); }
+ Name getMemoryNameAtIdx(Index i);
+ bool isMemory64(Name memoryName);
+ bool hasMemoryIdx(Element& s, Index defaultSize, Index i);
+
// returns the next index in s
size_t parseFunctionNames(Element& s, Name& name, Name& exportName);
void parseFunction(Element& s, bool preParseImport = false);
@@ -311,8 +318,12 @@ private:
// Helper functions
Type parseOptionalResultType(Element& s, Index& i);
- Index parseMemoryLimits(Element& s, Index i);
- Index parseMemoryIndex(Element& s, Index i);
+ Index parseMemoryLimits(Element& s, Index i, std::unique_ptr<Memory>& memory);
+ Index parseMemoryIndex(Element& s, Index i, std::unique_ptr<Memory>& memory);
+ Index parseMemoryForInstruction(const std::string& instrName,
+ Memory& memory,
+ Element& s,
+ Index i);
std::vector<Type> parseParamOrLocal(Element& s);
std::vector<NameType> parseParamOrLocal(Element& s, size_t& localIndex);
std::vector<Type> parseResults(Element& s);
@@ -326,12 +337,7 @@ private:
void stringToBinary(const char* input, size_t size, std::vector<char>& data);
void parseMemory(Element& s, bool preParseImport = false);
void parseData(Element& s);
- void parseInnerData(Element& s,
- Index i,
- Name name,
- bool hasExplicitName,
- Expression* offset,
- bool isPassive);
+ void parseInnerData(Element& s, Index i, std::unique_ptr<DataSegment>& seg);
void parseExport(Element& s);
void parseImport(Element& s);
void parseGlobal(Element& s, bool preParseImport = false);
diff --git a/src/wasm-stack.h b/src/wasm-stack.h
index 2a007739d..28c3a0836 100644
--- a/src/wasm-stack.h
+++ b/src/wasm-stack.h
@@ -122,7 +122,10 @@ public:
MappedLocals mappedLocals;
private:
- void emitMemoryAccess(size_t alignment, size_t bytes, uint32_t offset);
+ void emitMemoryAccess(size_t alignment,
+ size_t bytes,
+ uint32_t offset,
+ Name memory);
int32_t getBreakIndex(Name name);
WasmBinaryWriter& parent;
diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h
index 7c10be3a9..a77356a4c 100644
--- a/src/wasm-traversal.h
+++ b/src/wasm-traversal.h
@@ -258,7 +258,9 @@ struct Walker : public VisitorType {
for (auto& curr : module->elementSegments) {
self->walkElementSegment(curr.get());
}
- self->walkMemory(&module->memory);
+ for (auto& curr : module->memories) {
+ self->walkMemory(curr.get());
+ }
for (auto& curr : module->dataSegments) {
self->walkDataSegment(curr.get());
}
diff --git a/src/wasm.h b/src/wasm.h
index 04d4391a2..62a63e493 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -969,6 +969,7 @@ public:
Address align;
bool isAtomic;
Expression* ptr;
+ Name memory;
// type must be set during creation, cannot be inferred
@@ -987,6 +988,7 @@ public:
Expression* ptr;
Expression* value;
Type valueType;
+ Name memory;
void finalize();
};
@@ -1001,6 +1003,7 @@ public:
Address offset;
Expression* ptr;
Expression* value;
+ Name memory;
void finalize();
};
@@ -1015,6 +1018,7 @@ public:
Expression* ptr;
Expression* expected;
Expression* replacement;
+ Name memory;
void finalize();
};
@@ -1029,6 +1033,7 @@ public:
Expression* expected;
Expression* timeout;
Type expectedType;
+ Name memory;
void finalize();
};
@@ -1041,6 +1046,7 @@ public:
Address offset;
Expression* ptr;
Expression* notifyCount;
+ Name memory;
void finalize();
};
@@ -1129,6 +1135,7 @@ public:
Address offset;
Address align;
Expression* ptr;
+ Name memory;
Index getMemBytes();
void finalize();
@@ -1146,6 +1153,7 @@ public:
uint8_t index;
Expression* ptr;
Expression* vec;
+ Name memory;
bool isStore();
bool isLoad() { return !isStore(); }
@@ -1162,6 +1170,7 @@ public:
Expression* dest;
Expression* offset;
Expression* size;
+ Name memory;
void finalize();
};
@@ -1184,6 +1193,8 @@ public:
Expression* dest;
Expression* source;
Expression* size;
+ Name destMemory;
+ Name sourceMemory;
void finalize();
};
@@ -1196,6 +1207,7 @@ public:
Expression* dest;
Expression* value;
Expression* size;
+ Name memory;
void finalize();
};
@@ -1279,6 +1291,7 @@ public:
MemorySize(MixedArena& allocator) : MemorySize() {}
Type ptrType = Type::i32;
+ Name memory;
void make64();
void finalize();
@@ -1291,6 +1304,7 @@ public:
Expression* delta = nullptr;
Type ptrType = Type::i32;
+ Name memory;
void make64();
void finalize();
@@ -2029,6 +2043,7 @@ public:
class DataSegment : public Named {
public:
+ Name memory;
bool isPassive = false;
Expression* offset = nullptr;
std::vector<char> data; // TODO: optimize
@@ -2042,18 +2057,15 @@ public:
static const Address::address32_t kMaxSize32 =
(uint64_t(4) * 1024 * 1024 * 1024) / kPageSize;
- bool exists = false;
Address initial = 0; // sizes are in pages
Address max = kMaxSize32;
bool shared = false;
Type indexType = Type::i32;
- Memory() { name = Name::fromInt(0); }
bool hasMax() { return max != kUnlimitedSize; }
bool is64() { return indexType == Type::i64; }
void clear() {
- exists = false;
name = "";
initial = 0;
max = kMaxSize32;
@@ -2100,10 +2112,10 @@ public:
std::vector<std::unique_ptr<Global>> globals;
std::vector<std::unique_ptr<Tag>> tags;
std::vector<std::unique_ptr<ElementSegment>> elementSegments;
+ std::vector<std::unique_ptr<Memory>> memories;
std::vector<std::unique_ptr<DataSegment>> dataSegments;
std::vector<std::unique_ptr<Table>> tables;
- Memory memory;
Name start;
std::vector<UserSection> userSections;
@@ -2135,6 +2147,7 @@ private:
std::unordered_map<Name, Export*> exportsMap;
std::unordered_map<Name, Function*> functionsMap;
std::unordered_map<Name, Table*> tablesMap;
+ std::unordered_map<Name, Memory*> memoriesMap;
std::unordered_map<Name, ElementSegment*> elementSegmentsMap;
std::unordered_map<Name, DataSegment*> dataSegmentsMap;
std::unordered_map<Name, Global*> globalsMap;
@@ -2147,12 +2160,14 @@ public:
Function* getFunction(Name name);
Table* getTable(Name name);
ElementSegment* getElementSegment(Name name);
+ Memory* getMemory(Name name);
DataSegment* getDataSegment(Name name);
Global* getGlobal(Name name);
Tag* getTag(Name name);
Export* getExportOrNull(Name name);
Table* getTableOrNull(Name name);
+ Memory* getMemoryOrNull(Name name);
ElementSegment* getElementSegmentOrNull(Name name);
DataSegment* getDataSegmentOrNull(Name name);
Function* getFunctionOrNull(Name name);
@@ -2168,6 +2183,7 @@ public:
Function* addFunction(std::unique_ptr<Function>&& curr);
Table* addTable(std::unique_ptr<Table>&& curr);
ElementSegment* addElementSegment(std::unique_ptr<ElementSegment>&& curr);
+ Memory* addMemory(std::unique_ptr<Memory>&& curr);
DataSegment* addDataSegment(std::unique_ptr<DataSegment>&& curr);
Global* addGlobal(std::unique_ptr<Global>&& curr);
Tag* addTag(std::unique_ptr<Tag>&& curr);
@@ -2178,6 +2194,7 @@ public:
void removeFunction(Name name);
void removeTable(Name name);
void removeElementSegment(Name name);
+ void removeMemory(Name name);
void removeDataSegment(Name name);
void removeGlobal(Name name);
void removeTag(Name name);
@@ -2186,10 +2203,12 @@ public:
void removeFunctions(std::function<bool(Function*)> pred);
void removeTables(std::function<bool(Table*)> pred);
void removeElementSegments(std::function<bool(ElementSegment*)> pred);
+ void removeMemories(std::function<bool(Memory*)> pred);
void removeDataSegments(std::function<bool(DataSegment*)> pred);
void removeGlobals(std::function<bool(Global*)> pred);
void removeTags(std::function<bool(Tag*)> pred);
+ void updateDataSegmentsMap();
void updateMaps();
void clearDebugInfo();
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();
diff --git a/src/wasm2js.h b/src/wasm2js.h
index 442fd0d6e..cc4d363ec 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -103,7 +103,7 @@ bool hasActiveSegments(Module& wasm) {
}
bool needsBufferView(Module& wasm) {
- if (!wasm.memory.exists) {
+ if (wasm.memories.empty()) {
return false;
}
@@ -414,8 +414,8 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
ValueBuilder::appendArgumentToFunction(asmFunc, ENV);
// add memory import
- if (wasm->memory.exists) {
- if (wasm->memory.imported()) {
+ if (!wasm->memories.empty()) {
+ if (wasm->memories[0]->imported()) {
// find memory and buffer in imports
Ref theVar = ValueBuilder::makeVar();
asmFunc[3]->push_back(theVar);
@@ -423,7 +423,7 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
theVar,
"memory",
ValueBuilder::makeDot(ValueBuilder::makeName(ENV),
- ValueBuilder::makeName(wasm->memory.base)));
+ ValueBuilder::makeName(wasm->memories[0]->base)));
// Assign `buffer = memory.buffer`
Ref buf = ValueBuilder::makeVar();
@@ -436,7 +436,7 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
// If memory is growable, override the imported memory's grow method to
// ensure so that when grow is called from the output it works as expected
- if (wasm->memory.max > wasm->memory.initial) {
+ if (wasm->memories[0]->max > wasm->memories[0]->initial) {
asmFunc[3]->push_back(
ValueBuilder::makeStatement(ValueBuilder::makeBinary(
ValueBuilder::makeDot(ValueBuilder::makeName("memory"),
@@ -452,8 +452,8 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
BUFFER,
ValueBuilder::makeNew(ValueBuilder::makeCall(
ValueBuilder::makeName("ArrayBuffer"),
- ValueBuilder::makeInt(Address::address32_t(wasm->memory.initial.addr *
- Memory::kPageSize)))));
+ ValueBuilder::makeInt(Address::address32_t(
+ wasm->memories[0]->initial.addr * Memory::kPageSize)))));
}
}
@@ -536,7 +536,7 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
}
void Wasm2JSBuilder::addBasics(Ref ast, Module* wasm) {
- if (wasm->memory.exists) {
+ if (!wasm->memories.empty()) {
// heaps, var HEAP8 = new global.Int8Array(buffer); etc
auto addHeap = [&](IString name, IString view) {
Ref theVar = ValueBuilder::makeVar();
@@ -732,7 +732,7 @@ void Wasm2JSBuilder::addExports(Ref ast, Module* wasm) {
Ref growDesc = ValueBuilder::makeObject();
ValueBuilder::appendToObjectWithQuotes(
descs, IString("grow"), growDesc);
- if (wasm->memory.max > wasm->memory.initial) {
+ if (wasm->memories[0]->max > wasm->memories[0]->initial) {
ValueBuilder::appendToObjectWithQuotes(
growDesc,
IString("value"),
@@ -805,7 +805,7 @@ void Wasm2JSBuilder::addExports(Ref ast, Module* wasm) {
Fatal() << "unsupported export type: " << export_->name << "\n";
}
}
- if (wasm->memory.exists) {
+ if (!wasm->memories.empty()) {
addMemoryFuncs(ast, wasm);
}
ast->push_back(
@@ -1474,7 +1474,8 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m,
}
Ref visitStore(Store* curr) {
- if (module->memory.initial < module->memory.max &&
+ if (!module->memories.empty() &&
+ module->memories[0]->initial < module->memories[0]->max &&
curr->type != Type::unreachable) {
// In JS, if memory grows then it is dangerous to write
// HEAP[f()] = ..
@@ -2006,8 +2007,8 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m,
}
Ref visitMemoryGrow(MemoryGrow* curr) {
- if (module->memory.exists &&
- module->memory.max > module->memory.initial) {
+ if (!module->memories.empty() &&
+ module->memories[0]->max > module->memories[0]->initial) {
return ValueBuilder::makeCall(
WASM_MEMORY_GROW,
makeJsCoercion(visit(curr->delta, EXPRESSION_RESULT),
@@ -2382,7 +2383,8 @@ void Wasm2JSBuilder::addMemoryFuncs(Ref ast, Module* wasm) {
JsType::JS_INT)));
ast->push_back(memorySizeFunc);
- if (wasm->memory.max > wasm->memory.initial) {
+ if (!wasm->memories.empty() &&
+ wasm->memories[0]->max > wasm->memories[0]->initial) {
addMemoryGrowFunc(ast, wasm);
}
}
@@ -2482,7 +2484,7 @@ void Wasm2JSBuilder::addMemoryGrowFunc(Ref ast, Module* wasm) {
ValueBuilder::makeName(IString("newBuffer"))));
// apply the changes to the memory import
- if (wasm->memory.imported()) {
+ if (!wasm->memories.empty() && wasm->memories[0]->imported()) {
ValueBuilder::appendToBlock(
block,
ValueBuilder::makeBinary(
@@ -2625,9 +2627,9 @@ void Wasm2JSGlue::emitPostES6() {
//
// Note that the translation here expects that the lower values of this memory
// can be used for conversions, so make sure there's at least one page.
- if (wasm.memory.exists && wasm.memory.imported()) {
+ if (!wasm.memories.empty() && wasm.memories[0]->imported()) {
out << "var mem" << moduleName.str << " = new ArrayBuffer("
- << wasm.memory.initial.addr * Memory::kPageSize << ");\n";
+ << wasm.memories[0]->initial.addr * Memory::kPageSize << ");\n";
}
// Actually invoke the `asmFunc` generated function, passing in all global
@@ -2709,7 +2711,7 @@ void Wasm2JSGlue::emitMemory() {
// If there are no memory segments, we don't need to emit any support code for
// segment creation.
- if ((!wasm.memory.exists) || wasm.dataSegments.empty()) {
+ if (wasm.dataSegments.empty()) {
return;
}
diff --git a/test/binaryen.js/expressions.js b/test/binaryen.js/expressions.js
index 40d4194fd..71846f3c6 100644
--- a/test/binaryen.js/expressions.js
+++ b/test/binaryen.js/expressions.js
@@ -476,7 +476,7 @@ console.log("# GlobalSet");
console.log("# MemorySize");
(function testMemorySize() {
const module = new binaryen.Module();
-
+ module.setMemory(1, 1, null);
var type = binaryen.i32;
const theMemorySize = binaryen.MemorySize(module.memory.size());
assert(theMemorySize instanceof binaryen.MemorySize);
@@ -492,7 +492,7 @@ console.log("# MemorySize");
assert(
theMemorySize.toText()
==
- "(memory.size)\n"
+ "(memory.size $0)\n"
);
module.dispose();
@@ -501,6 +501,7 @@ console.log("# MemorySize");
console.log("# MemoryGrow");
(function testMemoryGrow() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var type = binaryen.i32;
var delta = module.i32.const(1);
@@ -521,7 +522,7 @@ console.log("# MemoryGrow");
assert(
theMemoryGrow.toText()
==
- "(memory.grow\n (i32.const 2)\n)\n"
+ "(memory.grow $0\n (i32.const 2)\n)\n"
);
module.dispose();
@@ -530,6 +531,7 @@ console.log("# MemoryGrow");
console.log("# Load");
(function testLoad() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var offset = 16;
var align = 2;
@@ -566,7 +568,7 @@ console.log("# Load");
assert(
theLoad.toText()
==
- "(i64.atomic.load offset=32 align=4\n (i32.const 128)\n)\n"
+ "(i64.atomic.load $0 offset=32 align=4\n (i32.const 128)\n)\n"
);
module.dispose();
@@ -575,6 +577,7 @@ console.log("# Load");
console.log("# Store");
(function testStore() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var offset = 16;
var align = 2;
@@ -615,7 +618,7 @@ console.log("# Store");
assert(
theStore.toText()
==
- "(i64.atomic.store offset=32 align=4\n (i32.const 128)\n (i32.const 2)\n)\n"
+ "(i64.atomic.store $0 offset=32 align=4\n (i32.const 128)\n (i32.const 2)\n)\n"
);
module.dispose();
@@ -822,6 +825,7 @@ console.log("# Return");
console.log("# AtomicRMW");
(function testAtomicRMW() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var op = binaryen.Operations.AtomicRMWAdd;
var offset = 8;
@@ -855,7 +859,7 @@ console.log("# AtomicRMW");
assert(
theAtomicRMW.toText()
==
- "(i64.atomic.rmw16.sub_u offset=16\n (i32.const 4)\n (i64.const 5)\n)\n"
+ "(i64.atomic.rmw16.sub_u $0 offset=16\n (i32.const 4)\n (i64.const 5)\n)\n"
);
module.dispose();
@@ -864,6 +868,7 @@ console.log("# AtomicRMW");
console.log("# AtomicCmpxchg");
(function testAtomicCmpxchg() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var offset = 8;
var ptr = module.i32.const(2);
@@ -897,7 +902,7 @@ console.log("# AtomicCmpxchg");
assert(
theAtomicCmpxchg.toText()
==
- "(i64.atomic.rmw16.cmpxchg_u offset=16\n (i32.const 5)\n (i64.const 6)\n (i64.const 7)\n)\n"
+ "(i64.atomic.rmw16.cmpxchg_u $0 offset=16\n (i32.const 5)\n (i64.const 6)\n (i64.const 7)\n)\n"
);
module.dispose();
@@ -906,6 +911,7 @@ console.log("# AtomicCmpxchg");
console.log("# AtomicWait");
(function testAtomicWait() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var ptr = module.i32.const(2);
var expected = module.i32.const(3);
@@ -935,7 +941,7 @@ console.log("# AtomicWait");
assert(
theAtomicWait.toText()
==
- "(memory.atomic.wait64\n (i32.const 5)\n (i32.const 6)\n (i64.const 7)\n)\n"
+ "(memory.atomic.wait64 $0\n (i32.const 5)\n (i32.const 6)\n (i64.const 7)\n)\n"
);
module.dispose();
@@ -944,6 +950,7 @@ console.log("# AtomicWait");
console.log("# AtomicNotify");
(function testAtomicNotify() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var ptr = module.i32.const(1);
var notifyCount = module.i32.const(2);
@@ -966,7 +973,7 @@ console.log("# AtomicNotify");
assert(
theAtomicNotify.toText()
==
- "(memory.atomic.notify\n (i32.const 3)\n (i32.const 4)\n)\n"
+ "(memory.atomic.notify $0\n (i32.const 3)\n (i32.const 4)\n)\n"
);
module.dispose();
@@ -1172,6 +1179,7 @@ console.log("# SIMDShift");
console.log("# SIMDLoad");
(function testSIMDLoad() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var op = binaryen.Operations.Load8x8SVec128;
var offset = 16;
@@ -1201,7 +1209,7 @@ console.log("# SIMDLoad");
assert(
theSIMDLoad.toText()
==
- "(v128.load8_splat offset=32 align=4\n (i32.const 2)\n)\n"
+ "(v128.load8_splat $0 offset=32 align=4\n (i32.const 2)\n)\n"
);
module.dispose();
@@ -1210,6 +1218,7 @@ console.log("# SIMDLoad");
console.log("# SIMDLoadStoreLane");
(function testSIMDLoadStoreLane() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var op = binaryen.Operations.Load8LaneVec128;
var offset = 16;
@@ -1249,7 +1258,7 @@ console.log("# SIMDLoadStoreLane");
assert(
theSIMDLoadStoreLane.toText()
==
- "(v128.load16_lane offset=32 2\n (i32.const 2)\n (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)\n)\n"
+ "(v128.load16_lane $0 offset=32 2\n (i32.const 2)\n (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)\n)\n"
);
theSIMDLoadStoreLane.op = op = binaryen.Operations.Store16LaneVec128;
@@ -1263,7 +1272,7 @@ console.log("# SIMDLoadStoreLane");
assert(
theSIMDLoadStoreLane.toText()
==
- "(v128.store16_lane offset=32 2\n (i32.const 2)\n (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)\n)\n"
+ "(v128.store16_lane $0 offset=32 2\n (i32.const 2)\n (v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)\n)\n"
);
module.dispose();
@@ -1272,6 +1281,7 @@ console.log("# SIMDLoadStoreLane");
console.log("# MemoryInit");
(function testMemoryInit() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var segment = 1;
var dest = module.i32.const(2);
@@ -1302,7 +1312,7 @@ console.log("# MemoryInit");
assert(
theMemoryInit.toText()
==
- "(memory.init 5\n (i32.const 6)\n (i32.const 7)\n (i32.const 8)\n)\n"
+ "(memory.init $0 5\n (i32.const 6)\n (i32.const 7)\n (i32.const 8)\n)\n"
);
module.dispose();
@@ -1338,6 +1348,7 @@ console.log("# DataDrop");
console.log("# MemoryCopy");
(function testMemoryCopy() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var dest = module.i32.const(1);
var source = module.i32.const(2);
@@ -1364,7 +1375,7 @@ console.log("# MemoryCopy");
assert(
theMemoryCopy.toText()
==
- "(memory.copy\n (i32.const 4)\n (i32.const 5)\n (i32.const 6)\n)\n"
+ "(memory.copy $0 $0\n (i32.const 4)\n (i32.const 5)\n (i32.const 6)\n)\n"
);
module.dispose();
@@ -1373,6 +1384,7 @@ console.log("# MemoryCopy");
console.log("# MemoryFill");
(function testMemoryFill() {
const module = new binaryen.Module();
+ module.setMemory(1, 1, null);
var dest = module.i32.const(1);
var value = module.i32.const(2);
@@ -1399,7 +1411,7 @@ console.log("# MemoryFill");
assert(
theMemoryFill.toText()
==
- "(memory.fill\n (i32.const 4)\n (i32.const 5)\n (i32.const 6)\n)\n"
+ "(memory.fill $0\n (i32.const 4)\n (i32.const 5)\n (i32.const 6)\n)\n"
);
module.dispose();
diff --git a/test/binaryen.js/expressions.js.txt b/test/binaryen.js/expressions.js.txt
index b9107f5c1..fbf69888a 100644
--- a/test/binaryen.js/expressions.js.txt
+++ b/test/binaryen.js/expressions.js.txt
@@ -65,20 +65,20 @@
)
# MemorySize
-(memory.size)
+(memory.size $0)
# MemoryGrow
-(memory.grow
+(memory.grow $0
(i32.const 2)
)
# Load
-(i64.atomic.load offset=32 align=4
+(i64.atomic.load $0 offset=32 align=4
(i32.const 128)
)
# Store
-(i64.atomic.store offset=32 align=4
+(i64.atomic.store $0 offset=32 align=4
(i32.const 128)
(i32.const 2)
)
@@ -115,27 +115,27 @@
)
# AtomicRMW
-(i64.atomic.rmw16.sub_u offset=16
+(i64.atomic.rmw16.sub_u $0 offset=16
(i32.const 4)
(i64.const 5)
)
# AtomicCmpxchg
-(i64.atomic.rmw16.cmpxchg_u offset=16
+(i64.atomic.rmw16.cmpxchg_u $0 offset=16
(i32.const 5)
(i64.const 6)
(i64.const 7)
)
# AtomicWait
-(memory.atomic.wait64
+(memory.atomic.wait64 $0
(i32.const 5)
(i32.const 6)
(i64.const 7)
)
# AtomicNotify
-(memory.atomic.notify
+(memory.atomic.notify $0
(i32.const 3)
(i32.const 4)
)
@@ -175,23 +175,23 @@
)
# SIMDLoad
-(v128.load8_splat offset=32 align=4
+(v128.load8_splat $0 offset=32 align=4
(i32.const 2)
)
# SIMDLoadStoreLane
-(v128.load16_lane offset=32 2
+(v128.load16_lane $0 offset=32 2
(i32.const 2)
(v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)
)
-(v128.store16_lane offset=32 2
+(v128.store16_lane $0 offset=32 2
(i32.const 2)
(v128.const i32x4 0x01010101 0x01010101 0x01010101 0x01010101)
)
# MemoryInit
-(memory.init 5
+(memory.init $0 5
(i32.const 6)
(i32.const 7)
(i32.const 8)
@@ -201,14 +201,14 @@
(data.drop 2)
# MemoryCopy
-(memory.copy
+(memory.copy $0 $0
(i32.const 4)
(i32.const 5)
(i32.const 6)
)
# MemoryFill
-(memory.fill
+(memory.fill $0
(i32.const 4)
(i32.const 5)
(i32.const 6)
diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js
index 59f398da9..95c2568e6 100644
--- a/test/binaryen.js/kitchen-sink.js
+++ b/test/binaryen.js/kitchen-sink.js
@@ -178,6 +178,19 @@ function test_core() {
// Module creation
module = new binaryen.Module();
+ // Memory
+ module.setMemory(1, 256, "mem", [
+ {
+ passive: false,
+ offset: module.i32.const(10),
+ data: "hello, world".split('').map(function(x) { return x.charCodeAt(0) })
+ },
+ {
+ passive: true,
+ offset: null,
+ data: "I am passive".split('').map(function(x) { return x.charCodeAt(0) })
+ }
+ ], true);
// Create a tag
var tag = module.addTag("a-tag", binaryen.i32, binaryen.none);
@@ -723,21 +736,6 @@ function test_core() {
assert(module.getNumTables() === 1);
assert(module.getNumElementSegments() === 1);
- // Memory. One per module
-
- module.setMemory(1, 256, "mem", [
- {
- passive: false,
- offset: module.i32.const(10),
- data: "hello, world".split('').map(function(x) { return x.charCodeAt(0) })
- },
- {
- passive: true,
- offset: null,
- data: "I am passive".split('').map(function(x) { return x.charCodeAt(0) })
- }
- ], true);
-
// Start function. One per module
var starter = module.addFunction("starter", binaryen.none, binaryen.none, [], module.nop());
module.setStart(starter);
@@ -1141,6 +1139,7 @@ function test_for_each() {
function test_expression_info() {
module = new binaryen.Module();
+ module.setMemory(1, 1, null);
// Issue #2392
console.log("getExpressionInfo(memory.grow)=" + JSON.stringify(binaryen.getExpressionInfo(module.memory.grow(1))));
diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt
index 2a5a05fe8..1be13aefe 100644
--- a/test/binaryen.js/kitchen-sink.js.txt
+++ b/test/binaryen.js/kitchen-sink.js.txt
@@ -130,10 +130,10 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7}
(table $t0 1 funcref)
(elem $e0 (i32.const 0) "$kitchen()sinker")
(tag $a-tag (param i32))
+ (export "mem" (memory $0))
(export "kitchen_sinker" (func "$kitchen()sinker"))
(export "a-global-exp" (global $a-global))
(export "a-tag-exp" (tag $a-tag))
- (export "mem" (memory $0))
(start $starter)
(func "$kitchen()sinker" (param $0 i32) (param $1 i64) (param $2 f32) (param $3 f64) (result i32)
(local $4 i32)
@@ -2234,10 +2234,10 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7}
(table $t0 1 funcref)
(elem $e0 (i32.const 0) "$kitchen()sinker")
(tag $a-tag (param i32))
+ (export "mem" (memory $0))
(export "kitchen_sinker" (func "$kitchen()sinker"))
(export "a-global-exp" (global $a-global))
(export "a-tag-exp" (tag $a-tag))
- (export "mem" (memory $0))
(start $starter)
(func "$kitchen()sinker" (param $0 i32) (param $1 i64) (param $2 f32) (param $3 f64) (result i32)
(local $4 i32)
diff --git a/test/binaryen.js/memory-info.js.txt b/test/binaryen.js/memory-info.js.txt
index 39d1290ae..ba04d7442 100644
--- a/test/binaryen.js/memory-info.js.txt
+++ b/test/binaryen.js/memory-info.js.txt
@@ -3,7 +3,7 @@ true
{"module":"","base":"","initial":1,"shared":false,"max":64}
true
{"module":"","base":"","initial":1,"shared":true,"max":64}
-false
+true
{"module":"env","base":"memory","initial":0,"shared":false,"max":65536}
-false
+true
{"module":"env","base":"memory","initial":0,"shared":true,"max":65536}
diff --git a/test/binaryen.js/sideffects.js b/test/binaryen.js/sideffects.js
index e3187041d..be5414aed 100644
--- a/test/binaryen.js/sideffects.js
+++ b/test/binaryen.js/sideffects.js
@@ -17,6 +17,7 @@ console.log("SideEffects.TrapsNeverHappen=" + binaryen.SideEffects.TrapsNeverHap
console.log("SideEffects.Any=" + binaryen.SideEffects.Any);
var module = new binaryen.Module();
+module.setMemory(1, 1, null);
assert(
binaryen.getSideEffects(
module.i32.const(1),
diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c
index dab64522a..cb8349f89 100644
--- a/test/example/c-api-kitchen-sink.c
+++ b/test/example/c-api-kitchen-sink.c
@@ -160,7 +160,7 @@ BinaryenExpressionRef makeMemoryInit(BinaryenModuleRef module) {
BinaryenExpressionRef dest = makeInt32(module, 1024);
BinaryenExpressionRef offset = makeInt32(module, 0);
BinaryenExpressionRef size = makeInt32(module, 12);
- return BinaryenMemoryInit(module, 0, dest, offset, size);
+ return BinaryenMemoryInit(module, 0, dest, offset, size, "0");
};
BinaryenExpressionRef makeDataDrop(BinaryenModuleRef module) {
@@ -171,14 +171,14 @@ BinaryenExpressionRef makeMemoryCopy(BinaryenModuleRef module) {
BinaryenExpressionRef dest = makeInt32(module, 2048);
BinaryenExpressionRef source = makeInt32(module, 1024);
BinaryenExpressionRef size = makeInt32(module, 12);
- return BinaryenMemoryCopy(module, dest, source, size);
+ return BinaryenMemoryCopy(module, dest, source, size, "0", "0");
};
BinaryenExpressionRef makeMemoryFill(BinaryenModuleRef module) {
BinaryenExpressionRef dest = makeInt32(module, 0);
BinaryenExpressionRef value = makeInt32(module, 42);
BinaryenExpressionRef size = makeInt32(module, 1024);
- return BinaryenMemoryFill(module, dest, value, size);
+ return BinaryenMemoryFill(module, dest, value, size, "0");
};
// tests
@@ -488,7 +488,8 @@ void test_core() {
segmentOffsets,
segmentSizes,
2,
- 1);
+ 1,
+ "0");
BinaryenExpressionRef valueList[] = {
// Unary
@@ -784,29 +785,29 @@ void test_core() {
makeSIMDShift(module, BinaryenShrUVecI64x2()),
// SIMD load
BinaryenSIMDLoad(
- module, BinaryenLoad8SplatVec128(), 0, 1, makeInt32(module, 128)),
+ module, BinaryenLoad8SplatVec128(), 0, 1, makeInt32(module, 128), "0"),
BinaryenSIMDLoad(
- module, BinaryenLoad16SplatVec128(), 16, 1, makeInt32(module, 128)),
+ module, BinaryenLoad16SplatVec128(), 16, 1, makeInt32(module, 128), "0"),
BinaryenSIMDLoad(
- module, BinaryenLoad32SplatVec128(), 16, 4, makeInt32(module, 128)),
+ module, BinaryenLoad32SplatVec128(), 16, 4, makeInt32(module, 128), "0"),
BinaryenSIMDLoad(
- module, BinaryenLoad64SplatVec128(), 0, 4, makeInt32(module, 128)),
+ module, BinaryenLoad64SplatVec128(), 0, 4, makeInt32(module, 128), "0"),
BinaryenSIMDLoad(
- module, BinaryenLoad8x8SVec128(), 0, 8, makeInt32(module, 128)),
+ module, BinaryenLoad8x8SVec128(), 0, 8, makeInt32(module, 128), "0"),
BinaryenSIMDLoad(
- module, BinaryenLoad8x8UVec128(), 0, 8, makeInt32(module, 128)),
+ module, BinaryenLoad8x8UVec128(), 0, 8, makeInt32(module, 128), "0"),
BinaryenSIMDLoad(
- module, BinaryenLoad16x4SVec128(), 0, 8, makeInt32(module, 128)),
+ module, BinaryenLoad16x4SVec128(), 0, 8, makeInt32(module, 128), "0"),
BinaryenSIMDLoad(
- module, BinaryenLoad16x4UVec128(), 0, 8, makeInt32(module, 128)),
+ module, BinaryenLoad16x4UVec128(), 0, 8, makeInt32(module, 128), "0"),
BinaryenSIMDLoad(
- module, BinaryenLoad32x2SVec128(), 0, 8, makeInt32(module, 128)),
+ module, BinaryenLoad32x2SVec128(), 0, 8, makeInt32(module, 128), "0"),
BinaryenSIMDLoad(
- module, BinaryenLoad32x2UVec128(), 0, 8, makeInt32(module, 128)),
+ module, BinaryenLoad32x2UVec128(), 0, 8, makeInt32(module, 128), "0"),
BinaryenSIMDLoad(
- module, BinaryenLoad32ZeroVec128(), 0, 4, makeInt32(module, 128)),
+ module, BinaryenLoad32ZeroVec128(), 0, 4, makeInt32(module, 128), "0"),
BinaryenSIMDLoad(
- module, BinaryenLoad64ZeroVec128(), 0, 8, makeInt32(module, 128)),
+ module, BinaryenLoad64ZeroVec128(), 0, 8, makeInt32(module, 128), "0"),
// SIMD load/store lane
BinaryenSIMDLoadStoreLane(module,
BinaryenLoad8LaneVec128(),
@@ -814,57 +815,64 @@ void test_core() {
1,
0,
makeInt32(module, 128),
- makeVec128(module, v128_bytes)),
+ makeVec128(module, v128_bytes),
+ "0"),
BinaryenSIMDLoadStoreLane(module,
BinaryenLoad16LaneVec128(),
0,
2,
0,
makeInt32(module, 128),
- makeVec128(module, v128_bytes)),
+ makeVec128(module, v128_bytes),
+ "0"),
BinaryenSIMDLoadStoreLane(module,
BinaryenLoad32LaneVec128(),
0,
4,
0,
makeInt32(module, 128),
- makeVec128(module, v128_bytes)),
+ makeVec128(module, v128_bytes),
+ "0"),
BinaryenSIMDLoadStoreLane(module,
BinaryenLoad64LaneVec128(),
0,
8,
0,
makeInt32(module, 128),
- makeVec128(module, v128_bytes)),
-
+ makeVec128(module, v128_bytes),
+ "0"),
BinaryenSIMDLoadStoreLane(module,
BinaryenStore8LaneVec128(),
0,
1,
0,
makeInt32(module, 128),
- makeVec128(module, v128_bytes)),
+ makeVec128(module, v128_bytes),
+ "0"),
BinaryenSIMDLoadStoreLane(module,
BinaryenStore16LaneVec128(),
0,
2,
0,
makeInt32(module, 128),
- makeVec128(module, v128_bytes)),
+ makeVec128(module, v128_bytes),
+ "0"),
BinaryenSIMDLoadStoreLane(module,
BinaryenStore32LaneVec128(),
0,
4,
0,
makeInt32(module, 128),
- makeVec128(module, v128_bytes)),
+ makeVec128(module, v128_bytes),
+ "0"),
BinaryenSIMDLoadStoreLane(module,
BinaryenStore64LaneVec128(),
0,
8,
0,
makeInt32(module, 128),
- makeVec128(module, v128_bytes)),
+ makeVec128(module, v128_bytes),
+ "0"),
// Other SIMD
makeSIMDShuffle(module),
makeSIMDTernary(module, BinaryenBitselectVec128()),
@@ -914,14 +922,16 @@ void test_core() {
BinaryenDrop(
module,
BinaryenLocalTee(module, 0, makeInt32(module, 102), BinaryenTypeInt32())),
- BinaryenLoad(module, 4, 0, 0, 0, BinaryenTypeInt32(), makeInt32(module, 1)),
- BinaryenLoad(module, 2, 1, 2, 1, BinaryenTypeInt64(), makeInt32(module, 8)),
BinaryenLoad(
- module, 4, 0, 0, 0, BinaryenTypeFloat32(), makeInt32(module, 2)),
+ module, 4, 0, 0, 0, BinaryenTypeInt32(), makeInt32(module, 1), "0"),
+ BinaryenLoad(
+ module, 2, 1, 2, 1, BinaryenTypeInt64(), makeInt32(module, 8), "0"),
+ BinaryenLoad(
+ module, 4, 0, 0, 0, BinaryenTypeFloat32(), makeInt32(module, 2), "0"),
BinaryenLoad(
- module, 8, 0, 2, 8, BinaryenTypeFloat64(), makeInt32(module, 9)),
- BinaryenStore(module, 4, 0, 0, temp13, temp14, BinaryenTypeInt32()),
- BinaryenStore(module, 8, 2, 4, temp15, temp16, BinaryenTypeInt64()),
+ module, 8, 0, 2, 8, BinaryenTypeFloat64(), makeInt32(module, 9), "0"),
+ BinaryenStore(module, 4, 0, 0, temp13, temp14, BinaryenTypeInt32(), "0"),
+ BinaryenStore(module, 8, 2, 4, temp15, temp16, BinaryenTypeInt64(), "0"),
BinaryenSelect(module, temp10, temp11, temp12, BinaryenTypeAuto()),
BinaryenReturn(module, makeInt32(module, 1337)),
// Tail call
@@ -1002,12 +1012,13 @@ void test_core() {
4,
0,
temp6,
- BinaryenAtomicLoad(module, 4, 0, BinaryenTypeInt32(), temp6),
- BinaryenTypeInt32()),
- BinaryenDrop(
- module,
- BinaryenAtomicWait(module, temp6, temp6, temp16, BinaryenTypeInt32())),
- BinaryenDrop(module, BinaryenAtomicNotify(module, temp6, temp6)),
+ BinaryenAtomicLoad(module, 4, 0, BinaryenTypeInt32(), temp6, "0"),
+ BinaryenTypeInt32(),
+ "0"),
+ BinaryenDrop(module,
+ BinaryenAtomicWait(
+ module, temp6, temp6, temp16, BinaryenTypeInt32(), "0")),
+ BinaryenDrop(module, BinaryenAtomicNotify(module, temp6, temp6, "0")),
BinaryenAtomicFence(module),
// Tuples
BinaryenTupleMake(module, tupleElements4a, 4),
@@ -1022,8 +1033,8 @@ void test_core() {
BinaryenPop(module, BinaryenTypeExternref()),
BinaryenPop(module, iIfF),
// Memory
- BinaryenMemorySize(module),
- BinaryenMemoryGrow(module, makeInt32(module, 0)),
+ BinaryenMemorySize(module, "0"),
+ BinaryenMemoryGrow(module, makeInt32(module, 0), "0"),
// GC
BinaryenI31New(module, makeInt32(module, 0)),
BinaryenI31Get(module, i31refExpr, 1),
@@ -1683,7 +1694,8 @@ void test_for_each() {
segmentOffsets,
segmentSizes,
2,
- 0);
+ 0,
+ "0");
BinaryenAddGlobal(module,
"a-global",
BinaryenTypeInt32(),
diff --git a/test/example/c-api-relooper-unreachable-if.cpp b/test/example/c-api-relooper-unreachable-if.cpp
index e8bfc43bc..c63ca0204 100644
--- a/test/example/c-api-relooper-unreachable-if.cpp
+++ b/test/example/c-api-relooper-unreachable-if.cpp
@@ -28,13 +28,20 @@ int main() {
segmentOffsets,
segmentSizes,
0,
- 0);
+ 0,
+ "0");
}
the_relooper = RelooperCreate(the_module);
expressions[1] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
expressions[2] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[3] = BinaryenStore(
- the_module, 4, 0, 0, expressions[2], expressions[1], BinaryenTypeInt32());
+ expressions[3] = BinaryenStore(the_module,
+ 4,
+ 0,
+ 0,
+ expressions[2],
+ expressions[1],
+ BinaryenTypeInt32(),
+ "0");
expressions[4] = BinaryenReturn(the_module, expressions[0]);
{
BinaryenExpressionRef children[] = {expressions[3], expressions[4]};
@@ -43,8 +50,8 @@ int main() {
}
relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[5]);
expressions[6] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[7] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[6]);
+ expressions[7] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[6], "0");
expressions[8] = BinaryenLocalSet(the_module, 0, expressions[7]);
relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[8]);
RelooperAddBranch(
@@ -66,8 +73,14 @@ int main() {
the_relooper = RelooperCreate(the_module);
expressions[10] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
expressions[11] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[12] = BinaryenStore(
- the_module, 4, 0, 0, expressions[11], expressions[10], BinaryenTypeInt32());
+ expressions[12] = BinaryenStore(the_module,
+ 4,
+ 0,
+ 0,
+ expressions[11],
+ expressions[10],
+ BinaryenTypeInt32(),
+ "0");
expressions[13] = BinaryenReturn(the_module, expressions[0]);
{
BinaryenExpressionRef children[] = {expressions[12], expressions[13]};
@@ -76,8 +89,8 @@ int main() {
}
relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[14]);
expressions[15] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[16] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[15]);
+ expressions[16] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[15], "0");
expressions[17] = BinaryenLocalSet(the_module, 0, expressions[16]);
relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[17]);
RelooperAddBranch(
@@ -115,8 +128,8 @@ int main() {
RelooperAddBranch(
relooperBlocks[1], relooperBlocks[1], expressions[0], expressions[0]);
expressions[21] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[22] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[21]);
+ expressions[22] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[21], "0");
expressions[23] = BinaryenLocalSet(the_module, 0, expressions[22]);
relooperBlocks[2] = RelooperAddBlock(the_relooper, expressions[23]);
RelooperAddBranch(
@@ -139,8 +152,14 @@ int main() {
the_relooper = RelooperCreate(the_module);
expressions[25] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
expressions[26] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[27] = BinaryenStore(
- the_module, 4, 0, 0, expressions[26], expressions[25], BinaryenTypeInt32());
+ expressions[27] = BinaryenStore(the_module,
+ 4,
+ 0,
+ 0,
+ expressions[26],
+ expressions[25],
+ BinaryenTypeInt32(),
+ "0");
expressions[28] = BinaryenReturn(the_module, expressions[0]);
{
BinaryenExpressionRef children[] = {expressions[27], expressions[28]};
@@ -149,8 +168,8 @@ int main() {
}
relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[29]);
expressions[30] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[31] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[30]);
+ expressions[31] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[30], "0");
expressions[32] = BinaryenLocalSet(the_module, 0, expressions[31]);
relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[32]);
RelooperAddBranch(
@@ -174,8 +193,14 @@ int main() {
the_relooper = RelooperCreate(the_module);
expressions[34] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
expressions[35] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[36] = BinaryenStore(
- the_module, 4, 0, 0, expressions[35], expressions[34], BinaryenTypeInt32());
+ expressions[36] = BinaryenStore(the_module,
+ 4,
+ 0,
+ 0,
+ expressions[35],
+ expressions[34],
+ BinaryenTypeInt32(),
+ "0");
expressions[37] = BinaryenReturn(the_module, expressions[0]);
{
BinaryenExpressionRef children[] = {expressions[36], expressions[37]};
@@ -184,8 +209,8 @@ int main() {
}
relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[38]);
expressions[39] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[40] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[39]);
+ expressions[40] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[39], "0");
expressions[41] = BinaryenLocalSet(the_module, 0, expressions[40]);
relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[41]);
RelooperAddBranch(
@@ -232,8 +257,14 @@ int main() {
relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[49]);
expressions[50] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
expressions[51] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[52] = BinaryenStore(
- the_module, 4, 0, 0, expressions[51], expressions[50], BinaryenTypeInt32());
+ expressions[52] = BinaryenStore(the_module,
+ 4,
+ 0,
+ 0,
+ expressions[51],
+ expressions[50],
+ BinaryenTypeInt32(),
+ "0");
expressions[53] = BinaryenReturn(the_module, expressions[0]);
{
BinaryenExpressionRef children[] = {expressions[52], expressions[53]};
@@ -244,8 +275,8 @@ int main() {
RelooperAddBranch(
relooperBlocks[0], relooperBlocks[1], expressions[0], expressions[0]);
expressions[55] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[56] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[55]);
+ expressions[56] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[55], "0");
expressions[57] = BinaryenLocalSet(the_module, 3, expressions[56]);
relooperBlocks[2] = RelooperAddBlock(the_relooper, expressions[57]);
RelooperAddBranch(
@@ -287,20 +318,38 @@ int main() {
BinaryenBinary(the_module, 36, expressions[72], expressions[71]);
expressions[74] = BinaryenUnary(the_module, 24, expressions[73]);
expressions[75] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[76] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[75]);
+ expressions[76] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[75], "0");
expressions[77] = BinaryenConst(the_module, BinaryenLiteralInt32(128));
expressions[78] =
BinaryenBinary(the_module, 1, expressions[76], expressions[77]);
expressions[79] =
BinaryenLocalTee(the_module, 3, expressions[78], BinaryenTypeInt32());
- expressions[80] = BinaryenStore(
- the_module, 4, 0, 0, expressions[75], expressions[79], BinaryenTypeInt32());
+ expressions[80] = BinaryenStore(the_module,
+ 4,
+ 0,
+ 0,
+ expressions[75],
+ expressions[79],
+ BinaryenTypeInt32(),
+ "0");
expressions[81] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
- expressions[82] = BinaryenStore(
- the_module, 4, 0, 0, expressions[81], expressions[70], BinaryenTypeInt32());
- expressions[83] = BinaryenStore(
- the_module, 4, 4, 0, expressions[81], expressions[74], BinaryenTypeInt32());
+ expressions[82] = BinaryenStore(the_module,
+ 4,
+ 0,
+ 0,
+ expressions[81],
+ expressions[70],
+ BinaryenTypeInt32(),
+ "0");
+ expressions[83] = BinaryenStore(the_module,
+ 4,
+ 4,
+ 0,
+ expressions[81],
+ expressions[74],
+ BinaryenTypeInt32(),
+ "0");
{
BinaryenExpressionRef children[] = {expressions[60],
expressions[62],
@@ -313,8 +362,8 @@ int main() {
}
relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[84]);
expressions[85] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
- expressions[86] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[85]);
+ expressions[86] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[85], "0");
expressions[87] = BinaryenLocalSet(the_module, 1, expressions[86]);
expressions[88] = BinaryenLocalGet(the_module, 1, BinaryenTypeInt32());
expressions[89] = BinaryenLocalSet(the_module, 4, expressions[88]);
@@ -322,8 +371,14 @@ int main() {
expressions[91] = BinaryenLocalSet(the_module, 5, expressions[90]);
expressions[92] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
expressions[93] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[94] = BinaryenStore(
- the_module, 4, 0, 0, expressions[93], expressions[92], BinaryenTypeInt32());
+ expressions[94] = BinaryenStore(the_module,
+ 4,
+ 0,
+ 0,
+ expressions[93],
+ expressions[92],
+ BinaryenTypeInt32(),
+ "0");
expressions[95] = BinaryenLocalGet(the_module, 5, BinaryenTypeInt32());
expressions[96] = BinaryenReturn(the_module, expressions[95]);
{
@@ -337,8 +392,8 @@ int main() {
}
relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[97]);
expressions[98] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
- expressions[99] =
- BinaryenLoad(the_module, 4, 0, 8, 0, BinaryenTypeInt32(), expressions[98]);
+ expressions[99] = BinaryenLoad(
+ the_module, 4, 0, 8, 0, BinaryenTypeInt32(), expressions[98], "0");
RelooperAddBranch(
relooperBlocks[0], relooperBlocks[1], expressions[99], expressions[0]);
expressions[100] = BinaryenUnreachable(the_module);
@@ -346,8 +401,8 @@ int main() {
RelooperAddBranch(
relooperBlocks[0], relooperBlocks[2], expressions[0], expressions[0]);
expressions[101] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[102] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[101]);
+ expressions[102] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[101], "0");
expressions[103] = BinaryenLocalSet(the_module, 6, expressions[102]);
relooperBlocks[3] = RelooperAddBlock(the_relooper, expressions[103]);
RelooperAddBranch(
@@ -403,8 +458,8 @@ int main() {
BinaryenBinary(the_module, 36, expressions[119], expressions[118]);
expressions[121] = BinaryenUnary(the_module, 24, expressions[120]);
expressions[122] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[123] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[122]);
+ expressions[123] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[122], "0");
expressions[124] = BinaryenConst(the_module, BinaryenLiteralInt32(128));
expressions[125] =
BinaryenBinary(the_module, 1, expressions[123], expressions[124]);
@@ -416,7 +471,8 @@ int main() {
0,
expressions[122],
expressions[126],
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
expressions[128] = BinaryenLocalGet(the_module, 5, BinaryenTypeInt32());
expressions[129] = BinaryenStore(the_module,
4,
@@ -424,14 +480,16 @@ int main() {
0,
expressions[128],
expressions[117],
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
expressions[130] = BinaryenStore(the_module,
4,
4,
0,
expressions[128],
expressions[121],
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
{
BinaryenExpressionRef children[] = {
expressions[115], expressions[127], expressions[129], expressions[130]};
@@ -440,8 +498,8 @@ int main() {
}
relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[131]);
expressions[132] = BinaryenLocalGet(the_module, 5, BinaryenTypeInt32());
- expressions[133] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[132]);
+ expressions[133] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[132], "0");
expressions[134] = BinaryenLocalSet(the_module, 3, expressions[133]);
expressions[135] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
expressions[136] = BinaryenLocalSet(the_module, 6, expressions[135]);
@@ -470,7 +528,8 @@ int main() {
0,
expressions[145],
expressions[144],
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
expressions[147] = BinaryenLocalGet(the_module, 8, BinaryenTypeInt32());
expressions[148] = BinaryenReturn(the_module, expressions[147]);
{
@@ -483,8 +542,8 @@ int main() {
RelooperAddBranch(
relooperBlocks[0], relooperBlocks[1], expressions[0], expressions[0]);
expressions[150] = BinaryenLocalGet(the_module, 5, BinaryenTypeInt32());
- expressions[151] =
- BinaryenLoad(the_module, 4, 0, 8, 0, BinaryenTypeInt32(), expressions[150]);
+ expressions[151] = BinaryenLoad(
+ the_module, 4, 0, 8, 0, BinaryenTypeInt32(), expressions[150], "0");
RelooperAddBranch(
relooperBlocks[1], relooperBlocks[2], expressions[151], expressions[0]);
expressions[152] = BinaryenUnreachable(the_module);
@@ -494,8 +553,8 @@ int main() {
RelooperAddBranch(
relooperBlocks[2], relooperBlocks[3], expressions[0], expressions[0]);
expressions[153] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[154] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[153]);
+ expressions[154] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[153], "0");
expressions[155] = BinaryenLocalSet(the_module, 9, expressions[154]);
relooperBlocks[5] = RelooperAddBlock(the_relooper, expressions[155]);
RelooperAddBranch(
@@ -538,7 +597,8 @@ int main() {
segmentOffsets,
segmentSizes,
0,
- 0);
+ 0,
+ "0");
}
expressions[157] = BinaryenConst(the_module, BinaryenLiteralInt32(65535));
expressions[158] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
@@ -548,7 +608,8 @@ int main() {
0,
expressions[158],
expressions[157],
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
expressions[160] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
expressions[161] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
{
@@ -598,8 +659,8 @@ int main() {
BinaryenBinary(the_module, 36, expressions[182], expressions[181]);
expressions[184] = BinaryenUnary(the_module, 24, expressions[183]);
expressions[185] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[186] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[185]);
+ expressions[186] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[185], "0");
expressions[187] = BinaryenConst(the_module, BinaryenLiteralInt32(128));
expressions[188] =
BinaryenBinary(the_module, 1, expressions[186], expressions[187]);
@@ -611,7 +672,8 @@ int main() {
0,
expressions[185],
expressions[189],
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
expressions[191] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
expressions[192] = BinaryenStore(the_module,
4,
@@ -619,14 +681,16 @@ int main() {
0,
expressions[191],
expressions[180],
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
expressions[193] = BinaryenStore(the_module,
4,
4,
0,
expressions[191],
expressions[184],
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
{
BinaryenExpressionRef children[] = {expressions[166],
expressions[168],
@@ -641,8 +705,8 @@ int main() {
}
relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[194]);
expressions[195] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
- expressions[196] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[195]);
+ expressions[196] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[195], "0");
expressions[197] = BinaryenLocalSet(the_module, 7, expressions[196]);
expressions[198] = BinaryenLocalGet(the_module, 8, BinaryenTypeInt32());
expressions[199] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
@@ -652,7 +716,8 @@ int main() {
0,
expressions[199],
expressions[198],
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
expressions[201] = BinaryenLocalGet(the_module, 7, BinaryenTypeInt32());
expressions[202] = BinaryenReturn(the_module, expressions[201]);
{
@@ -663,8 +728,8 @@ int main() {
}
relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[203]);
expressions[204] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
- expressions[205] =
- BinaryenLoad(the_module, 4, 0, 8, 0, BinaryenTypeInt32(), expressions[204]);
+ expressions[205] = BinaryenLoad(
+ the_module, 4, 0, 8, 0, BinaryenTypeInt32(), expressions[204], "0");
RelooperAddBranch(
relooperBlocks[0], relooperBlocks[1], expressions[205], expressions[0]);
expressions[206] = BinaryenUnreachable(the_module);
@@ -672,8 +737,8 @@ int main() {
RelooperAddBranch(
relooperBlocks[0], relooperBlocks[2], expressions[0], expressions[0]);
expressions[207] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[208] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[207]);
+ expressions[208] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[207], "0");
expressions[209] = BinaryenLocalSet(the_module, 8, expressions[208]);
relooperBlocks[3] = RelooperAddBlock(the_relooper, expressions[209]);
RelooperAddBranch(
@@ -719,7 +784,8 @@ int main() {
0,
expressions[219],
expressions[218],
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
expressions[221] = BinaryenLocalGet(the_module, 3, BinaryenTypeInt32());
expressions[222] = BinaryenReturn(the_module, expressions[221]);
{
@@ -733,8 +799,8 @@ int main() {
}
relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[223]);
expressions[224] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[225] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[224]);
+ expressions[225] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[224], "0");
expressions[226] = BinaryenLocalSet(the_module, 4, expressions[225]);
relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[226]);
RelooperAddBranch(
@@ -780,7 +846,8 @@ int main() {
0,
expressions[241],
expressions[240],
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
expressions[243] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
expressions[244] = BinaryenReturn(the_module, expressions[243]);
{
@@ -796,8 +863,8 @@ int main() {
}
relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[245]);
expressions[246] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[247] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[246]);
+ expressions[247] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[246], "0");
expressions[248] = BinaryenLocalSet(the_module, 7, expressions[247]);
relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[248]);
RelooperAddBranch(
@@ -848,7 +915,8 @@ int main() {
0,
expressions[263],
expressions[262],
- BinaryenTypeInt64());
+ BinaryenTypeInt64(),
+ "0");
expressions[265] = BinaryenLocalGet(the_module, 6, BinaryenTypeInt32());
expressions[266] = BinaryenReturn(the_module, expressions[265]);
{
@@ -864,8 +932,8 @@ int main() {
}
relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[267]);
expressions[268] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[269] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt64(), expressions[268]);
+ expressions[269] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt64(), expressions[268], "0");
expressions[270] = BinaryenLocalSet(the_module, 7, expressions[269]);
relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[270]);
RelooperAddBranch(
diff --git a/test/example/c-api-unused-mem.cpp b/test/example/c-api-unused-mem.cpp
index d395753f7..6c0fd14c1 100644
--- a/test/example/c-api-unused-mem.cpp
+++ b/test/example/c-api-unused-mem.cpp
@@ -29,7 +29,8 @@ int main() {
segmentOffsets,
segmentSizes,
0,
- 0);
+ 0,
+ "0");
}
the_relooper = RelooperCreate(the_module);
{
@@ -40,8 +41,14 @@ int main() {
relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[1]);
expressions[2] = BinaryenLocalGet(the_module, 0, BinaryenTypeInt32());
expressions[3] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[4] = BinaryenStore(
- the_module, 4, 0, 0, expressions[3], expressions[2], BinaryenTypeInt32());
+ expressions[4] = BinaryenStore(the_module,
+ 4,
+ 0,
+ 0,
+ expressions[3],
+ expressions[2],
+ BinaryenTypeInt32(),
+ "0");
expressions[5] = BinaryenReturn(the_module, expressions[0]);
{
BinaryenExpressionRef children[] = {expressions[4], expressions[5]};
@@ -52,8 +59,8 @@ int main() {
RelooperAddBranch(
relooperBlocks[0], relooperBlocks[1], expressions[0], expressions[0]);
expressions[7] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[8] =
- BinaryenLoad(the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[7]);
+ expressions[8] = BinaryenLoad(
+ the_module, 4, 0, 0, 0, BinaryenTypeInt32(), expressions[7], "0");
expressions[9] = BinaryenLocalSet(the_module, 0, expressions[8]);
relooperBlocks[2] = RelooperAddBlock(the_relooper, expressions[9]);
RelooperAddBranch(
@@ -86,12 +93,19 @@ int main() {
segmentOffsets,
segmentSizes,
0,
- 0);
+ 0,
+ "0");
}
expressions[11] = BinaryenConst(the_module, BinaryenLiteralInt32(65535));
expressions[12] = BinaryenConst(the_module, BinaryenLiteralInt32(0));
- expressions[13] = BinaryenStore(
- the_module, 4, 0, 0, expressions[12], expressions[11], BinaryenTypeInt32());
+ expressions[13] = BinaryenStore(the_module,
+ 4,
+ 0,
+ 0,
+ expressions[12],
+ expressions[11],
+ BinaryenTypeInt32(),
+ "0");
{
BinaryenExpressionRef operands[] = {0};
expressions[14] =
diff --git a/test/example/relooper-fuzz.c b/test/example/relooper-fuzz.c
index d953d9cf2..f0b727f4c 100644
--- a/test/example/relooper-fuzz.c
+++ b/test/example/relooper-fuzz.c
@@ -25,7 +25,8 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 27)) // jumps of 4 bytes
),
BinaryenUnreachable(module),
@@ -45,29 +46,32 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
// optionally, print the return value
BinaryenExpressionRef args[] = {BinaryenBinary(
module,
BinaryenSubInt32(),
BinaryenConst(module, BinaryenLiteralInt32(0)),
- BinaryenLoad(
- module,
- 4,
- 0,
- 4,
- 0,
- BinaryenTypeInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4)))))};
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 4,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0"))};
BinaryenExpressionRef debugger;
if (1)
debugger = BinaryenCall(module, "print", args, 1, BinaryenTypeNone());
@@ -89,7 +93,9 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))));
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0");
BinaryenExpressionRef checkBodyList[] = {halter, incer, debugger, returner};
BinaryenExpressionRef checkBody =
BinaryenBlock(module,
@@ -338,7 +344,8 @@ int main() {
0,
BinaryenConst(module, BinaryenLiteralInt32(8 + 4 * i)),
BinaryenConst(module, BinaryenLiteralInt32(decisions[i])),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
}
}
full[numDecisions] = body;
@@ -362,7 +369,7 @@ int main() {
BinaryenTypeNone());
// memory
- BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+ BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0, "0");
assert(BinaryenModuleValidate(module));
diff --git a/test/example/relooper-fuzz1.c b/test/example/relooper-fuzz1.c
index 9e49fbcd3..f481fe713 100644
--- a/test/example/relooper-fuzz1.c
+++ b/test/example/relooper-fuzz1.c
@@ -23,7 +23,8 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 30)) // jumps of 4 bytes
),
BinaryenUnreachable(module),
@@ -43,29 +44,32 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
// optionally, print the return value
BinaryenExpressionRef args[] = {BinaryenBinary(
module,
BinaryenSubInt32(),
BinaryenConst(module, BinaryenLiteralInt32(0)),
- BinaryenLoad(
- module,
- 4,
- 0,
- 4,
- 0,
- BinaryenTypeInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4)))))};
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 4,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0"))};
BinaryenExpressionRef debugger;
if (1)
debugger = BinaryenCall(module, "print", args, 1, BinaryenTypeNone());
@@ -87,7 +91,9 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))));
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0");
BinaryenExpressionRef checkBodyList[] = {halter, incer, debugger, returner};
BinaryenExpressionRef checkBody =
BinaryenBlock(module,
@@ -337,7 +343,8 @@ int main() {
0,
BinaryenConst(module, BinaryenLiteralInt32(8 + 4 * i)),
BinaryenConst(module, BinaryenLiteralInt32(decisions[i])),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
}
}
full[numDecisions] = body;
@@ -359,7 +366,7 @@ int main() {
BinaryenTypeNone());
// memory
- BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+ BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0, "0");
assert(BinaryenModuleValidate(module));
diff --git a/test/example/relooper-fuzz2.c b/test/example/relooper-fuzz2.c
index a48b86e2a..c179606a0 100644
--- a/test/example/relooper-fuzz2.c
+++ b/test/example/relooper-fuzz2.c
@@ -23,7 +23,8 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 27)) // jumps of 4 bytes
),
BinaryenUnreachable(module),
@@ -43,29 +44,32 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
// optionally, print the return value
BinaryenExpressionRef args[] = {BinaryenBinary(
module,
BinaryenSubInt32(),
BinaryenConst(module, BinaryenLiteralInt32(0)),
- BinaryenLoad(
- module,
- 4,
- 0,
- 4,
- 0,
- BinaryenTypeInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4)))))};
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 4,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0"))};
BinaryenExpressionRef debugger;
if (1)
debugger = BinaryenCall(module, "print", args, 1, BinaryenTypeNone());
@@ -87,7 +91,9 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))));
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0");
BinaryenExpressionRef checkBodyList[] = {halter, incer, debugger, returner};
BinaryenExpressionRef checkBody =
BinaryenBlock(module,
@@ -266,47 +272,49 @@ int main() {
b0,
b1,
NULL,
- BinaryenStore(
- module,
- 4,
- 0,
- 0,
- BinaryenConst(module, BinaryenLiteralInt32(4)),
- BinaryenBinary(
- module,
- BinaryenAddInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
- BinaryenTypeInt32()));
+ BinaryenStore(module,
+ 4,
+ 0,
+ 0,
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ BinaryenBinary(
+ module,
+ BinaryenAddInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
+ BinaryenTypeInt32(),
+ "0"));
RelooperAddBranch(
b1,
b1,
NULL,
- BinaryenStore(
- module,
- 4,
- 0,
- 0,
- BinaryenConst(module, BinaryenLiteralInt32(4)),
- BinaryenBinary(
- module,
- BinaryenAddInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
- BinaryenTypeInt32()));
+ BinaryenStore(module,
+ 4,
+ 0,
+ 0,
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ BinaryenBinary(
+ module,
+ BinaryenAddInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
+ BinaryenTypeInt32(),
+ "0"));
{
BinaryenIndex values[] = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
@@ -333,9 +341,11 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 6))),
- BinaryenTypeInt32()));
+ BinaryenTypeInt32(),
+ "0"));
}
RelooperAddBranchForSwitch(
@@ -343,48 +353,50 @@ int main() {
b4,
NULL,
0,
- BinaryenStore(
- module,
- 4,
- 0,
- 0,
- BinaryenConst(module, BinaryenLiteralInt32(4)),
- BinaryenBinary(
- module,
- BinaryenAddInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
- BinaryenTypeInt32()));
+ BinaryenStore(module,
+ 4,
+ 0,
+ 0,
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ BinaryenBinary(
+ module,
+ BinaryenAddInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
+ BinaryenTypeInt32(),
+ "0"));
RelooperAddBranchForSwitch(
b3,
b6,
NULL,
0,
- BinaryenStore(
- module,
- 4,
- 0,
- 0,
- BinaryenConst(module, BinaryenLiteralInt32(4)),
- BinaryenBinary(
- module,
- BinaryenAddInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenConst(module, BinaryenLiteralInt32(4 * 5))),
- BinaryenTypeInt32()));
+ BinaryenStore(module,
+ 4,
+ 0,
+ 0,
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ BinaryenBinary(
+ module,
+ BinaryenAddInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ BinaryenConst(module, BinaryenLiteralInt32(4 * 5))),
+ BinaryenTypeInt32(),
+ "0"));
RelooperAddBranch(
b4,
@@ -397,71 +409,74 @@ int main() {
BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
BinaryenConst(module, BinaryenLiteralInt32(2))),
BinaryenConst(module, BinaryenLiteralInt32(0))),
- BinaryenStore(
- module,
- 4,
- 0,
- 0,
- BinaryenConst(module, BinaryenLiteralInt32(4)),
- BinaryenBinary(
- module,
- BinaryenAddInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenConst(module, BinaryenLiteralInt32(4 * 5))),
- BinaryenTypeInt32()));
+ BinaryenStore(module,
+ 4,
+ 0,
+ 0,
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ BinaryenBinary(
+ module,
+ BinaryenAddInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ BinaryenConst(module, BinaryenLiteralInt32(4 * 5))),
+ BinaryenTypeInt32(),
+ "0"));
RelooperAddBranch(
b4,
b3,
NULL,
- BinaryenStore(
- module,
- 4,
- 0,
- 0,
- BinaryenConst(module, BinaryenLiteralInt32(4)),
- BinaryenBinary(
- module,
- BinaryenAddInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenConst(module, BinaryenLiteralInt32(4 * 3))),
- BinaryenTypeInt32()));
+ BinaryenStore(module,
+ 4,
+ 0,
+ 0,
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ BinaryenBinary(
+ module,
+ BinaryenAddInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ BinaryenConst(module, BinaryenLiteralInt32(4 * 3))),
+ BinaryenTypeInt32(),
+ "0"));
RelooperAddBranchForSwitch(
b5,
b1,
NULL,
0,
- BinaryenStore(
- module,
- 4,
- 0,
- 0,
- BinaryenConst(module, BinaryenLiteralInt32(4)),
- BinaryenBinary(
- module,
- BinaryenAddInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
- BinaryenTypeInt32()));
+ BinaryenStore(module,
+ 4,
+ 0,
+ 0,
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ BinaryenBinary(
+ module,
+ BinaryenAddInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
+ BinaryenTypeInt32(),
+ "0"));
{
BinaryenIndex values[] = {0, 3, 6, 9, 12, 15, 18, 21, 24, 27,
@@ -488,9 +503,11 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 2))),
- BinaryenTypeInt32()));
+ BinaryenTypeInt32(),
+ "0"));
}
{
@@ -519,9 +536,11 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 3))),
- BinaryenTypeInt32()));
+ BinaryenTypeInt32(),
+ "0"));
}
RelooperAddBranchForSwitch(
@@ -529,24 +548,25 @@ int main() {
b2,
NULL,
0,
- BinaryenStore(
- module,
- 4,
- 0,
- 0,
- BinaryenConst(module, BinaryenLiteralInt32(4)),
- BinaryenBinary(
- module,
- BinaryenAddInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenConst(module, BinaryenLiteralInt32(4 * 3))),
- BinaryenTypeInt32()));
+ BinaryenStore(module,
+ 4,
+ 0,
+ 0,
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ BinaryenBinary(
+ module,
+ BinaryenAddInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ BinaryenConst(module, BinaryenLiteralInt32(4 * 3))),
+ BinaryenTypeInt32(),
+ "0"));
RelooperAddBranch(
b7,
@@ -559,70 +579,73 @@ int main() {
BinaryenLocalGet(module, 0, BinaryenTypeInt32()),
BinaryenConst(module, BinaryenLiteralInt32(2))),
BinaryenConst(module, BinaryenLiteralInt32(0))),
- BinaryenStore(
- module,
- 4,
- 0,
- 0,
- BinaryenConst(module, BinaryenLiteralInt32(4)),
- BinaryenBinary(
- module,
- BinaryenAddInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenConst(module, BinaryenLiteralInt32(4 * 1))),
- BinaryenTypeInt32()));
+ BinaryenStore(module,
+ 4,
+ 0,
+ 0,
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ BinaryenBinary(
+ module,
+ BinaryenAddInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ BinaryenConst(module, BinaryenLiteralInt32(4 * 1))),
+ BinaryenTypeInt32(),
+ "0"));
RelooperAddBranch(
b7,
b1,
NULL,
- BinaryenStore(
- module,
- 4,
- 0,
- 0,
- BinaryenConst(module, BinaryenLiteralInt32(4)),
- BinaryenBinary(
- module,
- BinaryenAddInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
- BinaryenTypeInt32()));
+ BinaryenStore(module,
+ 4,
+ 0,
+ 0,
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ BinaryenBinary(
+ module,
+ BinaryenAddInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ BinaryenConst(module, BinaryenLiteralInt32(4 * 4))),
+ BinaryenTypeInt32(),
+ "0"));
RelooperAddBranch(
b8,
b8,
NULL,
- BinaryenStore(
- module,
- 4,
- 0,
- 0,
- BinaryenConst(module, BinaryenLiteralInt32(4)),
- BinaryenBinary(
- module,
- BinaryenAddInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenConst(module, BinaryenLiteralInt32(4 * 2))),
- BinaryenTypeInt32()));
+ BinaryenStore(module,
+ 4,
+ 0,
+ 0,
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ BinaryenBinary(
+ module,
+ BinaryenAddInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ BinaryenConst(module, BinaryenLiteralInt32(4 * 2))),
+ BinaryenTypeInt32(),
+ "0"));
BinaryenExpressionRef body = RelooperRenderAndDispose(relooper, b0, 1);
@@ -644,7 +667,8 @@ int main() {
0,
BinaryenConst(module, BinaryenLiteralInt32(8 + 4 * i)),
BinaryenConst(module, BinaryenLiteralInt32(decisions[i])),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
}
}
full[numDecisions] = body;
@@ -666,7 +690,7 @@ int main() {
BinaryenTypeNone());
// memory
- BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+ BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0, "0");
// optionally, optimize
if (0)
diff --git a/test/example/relooper-merge1.c b/test/example/relooper-merge1.c
index 491839f36..f7939adc6 100644
--- a/test/example/relooper-merge1.c
+++ b/test/example/relooper-merge1.c
@@ -23,7 +23,8 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
),
BinaryenUnreachable(module),
@@ -43,29 +44,32 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
// optionally, print the return value
BinaryenExpressionRef args[] = {BinaryenBinary(
module,
BinaryenSubInt32(),
BinaryenConst(module, BinaryenLiteralInt32(0)),
- BinaryenLoad(
- module,
- 4,
- 0,
- 4,
- 0,
- BinaryenTypeInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4)))))};
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 4,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0"))};
BinaryenExpressionRef debugger;
if (1)
debugger = BinaryenCall(module, "print", args, 1, BinaryenTypeNone());
@@ -87,7 +91,9 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))));
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0");
BinaryenExpressionRef checkBodyList[] = {halter, incer, debugger, returner};
BinaryenExpressionRef checkBody =
BinaryenBlock(module,
@@ -226,7 +232,7 @@ int main() {
BinaryenTypeNone());
// memory
- BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+ BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0, "0");
// optionally, optimize
if (0)
diff --git a/test/example/relooper-merge2.c b/test/example/relooper-merge2.c
index ed5fc0f4d..be8fba500 100644
--- a/test/example/relooper-merge2.c
+++ b/test/example/relooper-merge2.c
@@ -23,7 +23,8 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
),
BinaryenUnreachable(module),
@@ -43,29 +44,32 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
// optionally, print the return value
BinaryenExpressionRef args[] = {BinaryenBinary(
module,
BinaryenSubInt32(),
BinaryenConst(module, BinaryenLiteralInt32(0)),
- BinaryenLoad(
- module,
- 4,
- 0,
- 4,
- 0,
- BinaryenTypeInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4)))))};
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 4,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0"))};
BinaryenExpressionRef debugger;
if (1)
debugger = BinaryenCall(module, "print", args, 1, BinaryenTypeNone());
@@ -87,7 +91,9 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))));
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0");
BinaryenExpressionRef checkBodyList[] = {halter, incer, debugger, returner};
BinaryenExpressionRef checkBody =
BinaryenBlock(module,
@@ -241,7 +247,7 @@ int main() {
BinaryenTypeNone());
// memory
- BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+ BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0, "0");
// optionally, optimize
if (0)
diff --git a/test/example/relooper-merge3.c b/test/example/relooper-merge3.c
index 655b4d22b..f1e3d8a54 100644
--- a/test/example/relooper-merge3.c
+++ b/test/example/relooper-merge3.c
@@ -23,7 +23,8 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
),
BinaryenUnreachable(module),
@@ -43,29 +44,32 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
// optionally, print the return value
BinaryenExpressionRef args[] = {BinaryenBinary(
module,
BinaryenSubInt32(),
BinaryenConst(module, BinaryenLiteralInt32(0)),
- BinaryenLoad(
- module,
- 4,
- 0,
- 4,
- 0,
- BinaryenTypeInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4)))))};
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 4,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0"))};
BinaryenExpressionRef debugger;
if (1)
debugger = BinaryenCall(module, "print", args, 1, BinaryenTypeNone());
@@ -87,7 +91,9 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))));
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0");
BinaryenExpressionRef checkBodyList[] = {halter, incer, debugger, returner};
BinaryenExpressionRef checkBody =
BinaryenBlock(module,
@@ -225,7 +231,7 @@ int main() {
BinaryenTypeNone());
// memory
- BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+ BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0, "0");
// optionally, optimize
if (0)
diff --git a/test/example/relooper-merge4.c b/test/example/relooper-merge4.c
index 2e5624421..b379800dd 100644
--- a/test/example/relooper-merge4.c
+++ b/test/example/relooper-merge4.c
@@ -23,7 +23,8 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
),
BinaryenUnreachable(module),
@@ -43,29 +44,32 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
// optionally, print the return value
BinaryenExpressionRef args[] = {BinaryenBinary(
module,
BinaryenSubInt32(),
BinaryenConst(module, BinaryenLiteralInt32(0)),
- BinaryenLoad(
- module,
- 4,
- 0,
- 4,
- 0,
- BinaryenTypeInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4)))))};
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 4,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0"))};
BinaryenExpressionRef debugger;
if (1)
debugger = BinaryenCall(module, "print", args, 1, BinaryenTypeNone());
@@ -87,7 +91,9 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))));
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0");
BinaryenExpressionRef checkBodyList[] = {halter, incer, debugger, returner};
BinaryenExpressionRef checkBody =
BinaryenBlock(module,
@@ -225,7 +231,7 @@ int main() {
BinaryenTypeNone());
// memory
- BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+ BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0, "0");
// optionally, optimize
if (0)
diff --git a/test/example/relooper-merge5.c b/test/example/relooper-merge5.c
index 41a36c102..d678a630e 100644
--- a/test/example/relooper-merge5.c
+++ b/test/example/relooper-merge5.c
@@ -23,7 +23,8 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
),
BinaryenUnreachable(module),
@@ -43,29 +44,32 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
// optionally, print the return value
BinaryenExpressionRef args[] = {BinaryenBinary(
module,
BinaryenSubInt32(),
BinaryenConst(module, BinaryenLiteralInt32(0)),
- BinaryenLoad(
- module,
- 4,
- 0,
- 4,
- 0,
- BinaryenTypeInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4)))))};
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 4,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0"))};
BinaryenExpressionRef debugger;
if (1)
debugger = BinaryenCall(module, "print", args, 1, BinaryenTypeNone());
@@ -87,7 +91,9 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))));
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0");
BinaryenExpressionRef checkBodyList[] = {halter, incer, debugger, returner};
BinaryenExpressionRef checkBody =
BinaryenBlock(module,
@@ -225,7 +231,7 @@ int main() {
BinaryenTypeNone());
// memory
- BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+ BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0, "0");
// optionally, optimize
if (0)
diff --git a/test/example/relooper-merge6.c b/test/example/relooper-merge6.c
index 23e639cb1..9d9d33361 100644
--- a/test/example/relooper-merge6.c
+++ b/test/example/relooper-merge6.c
@@ -23,7 +23,8 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4 * 12)) // jumps of 4 bytes
),
BinaryenUnreachable(module),
@@ -43,29 +44,32 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
BinaryenConst(module, BinaryenLiteralInt32(4))),
- BinaryenTypeInt32());
+ BinaryenTypeInt32(),
+ "0");
// optionally, print the return value
BinaryenExpressionRef args[] = {BinaryenBinary(
module,
BinaryenSubInt32(),
BinaryenConst(module, BinaryenLiteralInt32(0)),
- BinaryenLoad(
- module,
- 4,
- 0,
- 4,
- 0,
- BinaryenTypeInt32(),
- BinaryenLoad(module,
- 4,
- 0,
- 0,
- 0,
- BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4)))))};
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 4,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenLoad(module,
+ 4,
+ 0,
+ 0,
+ 0,
+ BinaryenTypeInt32(),
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0"))};
BinaryenExpressionRef debugger;
if (1)
debugger = BinaryenCall(module, "print", args, 1, BinaryenTypeNone());
@@ -87,7 +91,9 @@ int main() {
0,
0,
BinaryenTypeInt32(),
- BinaryenConst(module, BinaryenLiteralInt32(4))));
+ BinaryenConst(module, BinaryenLiteralInt32(4)),
+ "0"),
+ "0");
BinaryenExpressionRef checkBodyList[] = {halter, incer, debugger, returner};
BinaryenExpressionRef checkBody =
BinaryenBlock(module,
@@ -228,7 +234,7 @@ int main() {
BinaryenTypeNone());
// memory
- BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0);
+ BinaryenSetMemory(module, 1, 1, "mem", NULL, NULL, NULL, NULL, 0, 0, "0");
// optionally, optimize
if (0)
diff --git a/test/lit/multi-memories-atomics64.wast b/test/lit/multi-memories-atomics64.wast
new file mode 100644
index 000000000..15941b12a
--- /dev/null
+++ b/test/lit/multi-memories-atomics64.wast
@@ -0,0 +1,704 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
+;; RUN: wasm-as %s -all -g -o %t.wasm
+;; RUN: wasm-dis %t.wasm -o - | filecheck %s
+
+(module
+ ;; CHECK: (type $0 (func))
+ (type $0 (func))
+ ;; CHECK: (memory $appMemory (shared i64 23 256))
+ (memory $appMemory (shared i64 23 256))
+ ;; CHECK: (memory $dataMemory (shared i64 23 256))
+ (memory $dataMemory (shared i64 23 256))
+ ;; CHECK: (memory $instrumentMemory (shared i64 23 256))
+ (memory $instrumentMemory (shared i64 23 256))
+ ;; CHECK: (func $atomic-loadstore
+ ;; CHECK-NEXT: (local $0 i64)
+ ;; CHECK-NEXT: (local $1 i64)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.load8_u $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.load8_u $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.load16_u $dataMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.load16_u $instrumentMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.load $dataMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.load $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.load8_u $appMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.load8_u $dataMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.load16_u $appMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.load16_u $appMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.load32_u $instrumentMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.load32_u $appMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.load $appMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.load $instrumentMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.atomic.store $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.atomic.store $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.atomic.store8 $instrumentMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.atomic.store8 $dataMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.atomic.store16 $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.atomic.store16 $dataMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.atomic.store $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.atomic.store $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.atomic.store8 $dataMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.atomic.store8 $instrumentMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.atomic.store16 $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.atomic.store16 $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.atomic.store32 $instrumentMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i64.atomic.store32 $dataMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $atomic-loadstore (type $0)
+ (local $0 i64)
+ (local $1 i64)
+ (local $2 i32)
+ (drop
+ (i32.atomic.load8_u 0 offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i32.atomic.load8_u $appMemory offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i32.atomic.load16_u 1 offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i32.atomic.load16_u $instrumentMemory offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i32.atomic.load 1 offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i32.atomic.load $appMemory offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load8_u
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load8_u $dataMemory
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load16_u
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load16_u $appMemory
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load32_u 2
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load32_u $appMemory
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load $instrumentMemory
+ (local.get $0)
+ )
+ )
+ (i32.atomic.store 0 offset=4 align=4
+ (local.get $0)
+ (local.get $2)
+ )
+ (i32.atomic.store $appMemory offset=4 align=4
+ (local.get $0)
+ (local.get $2)
+ )
+ (i32.atomic.store8 2 offset=4 align=1
+ (local.get $0)
+ (local.get $2)
+ )
+ (i32.atomic.store8 $dataMemory offset=4 align=1
+ (local.get $0)
+ (local.get $2)
+ )
+ (i32.atomic.store16 0 offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ (i32.atomic.store16 $dataMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ (i64.atomic.store offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store $appMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store8 1 offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store8 $instrumentMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store16 offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store16 $appMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store32 2 offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store32 $dataMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $atomic-rmw
+ ;; CHECK-NEXT: (local $0 i64)
+ ;; CHECK-NEXT: (local $1 i64)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw.add $dataMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw.add $instrumentMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw8.add_u $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw8.add_u $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw16.and_u $dataMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw16.and_u $instrumentMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.rmw32.or_u $appMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.rmw32.or_u $appMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw8.xchg_u $appMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw8.xchg_u $dataMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $atomic-rmw (type $0)
+ (local $0 i64)
+ (local $1 i64)
+ (local $2 i32)
+ (drop
+ (i32.atomic.rmw.add $dataMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw.add 2 offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.add_u 0 offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.add_u $appMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw16.and_u 1 align=2
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw16.and_u $instrumentMemory align=2
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i64.atomic.rmw32.or_u 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (drop
+ (i64.atomic.rmw32.or_u $appMemory
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.xchg_u 0 align=1
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.xchg_u $dataMemory align=1
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ )
+ ;; CHECK: (func $atomic-cmpxchg
+ ;; CHECK-NEXT: (local $0 i64)
+ ;; CHECK-NEXT: (local $1 i64)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw.cmpxchg $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw.cmpxchg $instrumentMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw8.cmpxchg_u $appMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.atomic.rmw8.cmpxchg_u $appMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.rmw.cmpxchg $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.rmw.cmpxchg $dataMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.rmw32.cmpxchg_u $instrumentMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i64.atomic.rmw32.cmpxchg_u $dataMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $atomic-cmpxchg (type $0)
+ (local $0 i64)
+ (local $1 i64)
+ (local $2 i32)
+ (drop
+ (i32.atomic.rmw.cmpxchg 0 offset=4
+ (local.get $0)
+ (local.get $2)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw.cmpxchg $instrumentMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.cmpxchg_u
+ (local.get $0)
+ (local.get $2)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.cmpxchg_u $appMemory
+ (local.get $0)
+ (local.get $2)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i64.atomic.rmw.cmpxchg offset=4
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (i64.atomic.rmw.cmpxchg $dataMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (i64.atomic.rmw32.cmpxchg_u 2 align=4
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (i64.atomic.rmw32.cmpxchg_u $dataMemory align=4
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ )
+ ;; CHECK: (func $atomic-wait-notify
+ ;; CHECK-NEXT: (local $0 i64)
+ ;; CHECK-NEXT: (local $1 i64)
+ ;; CHECK-NEXT: (local $2 i32)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.wait32 $dataMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.wait32 $instrumentMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.wait32 $appMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.wait32 $instrumentMemory offset=4
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.notify $dataMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.notify $dataMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.notify $appMemory offset=24
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.notify $dataMemory offset=24
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.wait64 $instrumentMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.wait64 $instrumentMemory
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.wait64 $appMemory offset=16
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (memory.atomic.wait64 $appMemory offset=16
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $atomic-wait-notify (type $0)
+ (local $0 i64)
+ (local $1 i64)
+ (local $2 i32)
+ (drop
+ (memory.atomic.wait32 $dataMemory
+ (local.get $0)
+ (local.get $2)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait32 2
+ (local.get $0)
+ (local.get $2)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait32 $appMemory offset=4 align=4
+ (local.get $0)
+ (local.get $2)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait32 2 offset=4 align=4
+ (local.get $0)
+ (local.get $2)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.notify 1
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (memory.atomic.notify $dataMemory
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (memory.atomic.notify $appMemory offset=24 align=4
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (memory.atomic.notify 1 offset=24 align=4
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (memory.atomic.wait64 $instrumentMemory
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait64 2
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait64 $appMemory align=8 offset=16
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait64 0 align=8 offset=16
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ )
+ ;; CHECK: (func $atomic-fence
+ ;; CHECK-NEXT: (atomic.fence)
+ ;; CHECK-NEXT: )
+ (func $atomic-fence (type $0)
+ (atomic.fence)
+ )
+)
diff --git a/test/lit/multi-memories-basics.wast b/test/lit/multi-memories-basics.wast
new file mode 100644
index 000000000..42b60915b
--- /dev/null
+++ b/test/lit/multi-memories-basics.wast
@@ -0,0 +1,175 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
+;; RUN: wasm-as %s -all -g -o %t.wasm
+;; RUN: wasm-dis %t.wasm -o - | filecheck %s
+
+(module
+ ;; CHECK: (import "env" "memory" (memory $importedMemory 1 1))
+
+ ;; CHECK: (memory $memory1 1 500)
+ (memory $memory1 1 500)
+ ;; CHECK: (memory $memory2 1 800)
+ (memory $memory2 1 800)
+ ;; CHECK: (memory $memory3 1 400)
+ (memory $memory3 1 400)
+ (data (memory $memory1) (i32.const 0) "a" "" "bcd")
+ (import "env" "memory" (memory $importedMemory 1 1))
+ ;; CHECK: (data (i32.const 0) "abcd")
+
+ ;; CHECK: (func $memory.fill
+ ;; CHECK-NEXT: (memory.fill $memory2
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 1)
+ ;; CHECK-NEXT: (i32.const 2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $memory.fill
+ (memory.fill 1
+ (i32.const 0)
+ (i32.const 1)
+ (i32.const 2)
+ )
+ )
+ ;; CHECK: (func $memory.copy
+ ;; CHECK-NEXT: (memory.copy $memory2 $memory3
+ ;; CHECK-NEXT: (i32.const 512)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $memory.copy
+ (memory.copy 1 2
+ (i32.const 512)
+ (i32.const 0)
+ (i32.const 12)
+ )
+ )
+ ;; CHECK: (func $memory.init
+ ;; CHECK-NEXT: (memory.init $memory1 0
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 45)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $memory.init
+ (memory.init 0 0
+ (i32.const 0)
+ (i32.const 0)
+ (i32.const 45)
+ )
+ )
+ ;; CHECK: (func $memory.grow (result i32)
+ ;; CHECK-NEXT: (memory.grow $memory3
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $memory.grow (result i32)
+ (memory.grow 2
+ (i32.const 10)
+ )
+ )
+ ;; CHECK: (func $memory.size (result i32)
+ ;; CHECK-NEXT: (memory.size $memory3)
+ ;; CHECK-NEXT: )
+ (func $memory.size (result i32)
+ (memory.size 2)
+ )
+ ;; CHECK: (func $loads
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load $memory1
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load $memory3
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load16_s $memory2
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load16_s $memory2
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load8_s $memory3
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load8_s $memory3
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load16_u $memory1
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load16_u $memory1
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load8_u $memory2
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.load8_u $memory2
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $loads
+ (drop (i32.load 0 (i32.const 12)))
+ (drop (i32.load $memory3 (i32.const 12)))
+ (drop (i32.load16_s 1 (i32.const 12)))
+ (drop (i32.load16_s $memory2 (i32.const 12)))
+ (drop (i32.load8_s 2 (i32.const 12)))
+ (drop (i32.load8_s $memory3 (i32.const 12)))
+ (drop (i32.load16_u 0 (i32.const 12)))
+ (drop (i32.load16_u $memory1 (i32.const 12)))
+ (drop (i32.load8_u 1 (i32.const 12)))
+ (drop (i32.load8_u $memory2 (i32.const 12)))
+ )
+ ;; CHECK: (func $stores
+ ;; CHECK-NEXT: (i32.store $memory1
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: (i32.const 115)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.store $memory1
+ ;; CHECK-NEXT: (i32.const 12)
+ ;; CHECK-NEXT: (i32.const 115)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.store16 $memory2
+ ;; CHECK-NEXT: (i32.const 20)
+ ;; CHECK-NEXT: (i32.const 31353)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.store16 $importedMemory
+ ;; CHECK-NEXT: (i32.const 20)
+ ;; CHECK-NEXT: (i32.const 31353)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.store8 $memory3
+ ;; CHECK-NEXT: (i32.const 23)
+ ;; CHECK-NEXT: (i32.const 120)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (i32.store8 $memory3
+ ;; CHECK-NEXT: (i32.const 23)
+ ;; CHECK-NEXT: (i32.const 120)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $stores
+ (i32.store 0 (i32.const 12) (i32.const 115))
+ (i32.store $memory1 (i32.const 12) (i32.const 115))
+ (i32.store16 1 (i32.const 20) (i32.const 31353))
+ (i32.store16 $importedMemory (i32.const 20) (i32.const 31353))
+ (i32.store8 2 (i32.const 23) (i32.const 120))
+ (i32.store8 $memory3 (i32.const 23) (i32.const 120))
+ )
+)
+
diff --git a/test/lit/multi-memories-simd.wast b/test/lit/multi-memories-simd.wast
new file mode 100644
index 000000000..184d98876
--- /dev/null
+++ b/test/lit/multi-memories-simd.wast
@@ -0,0 +1,635 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
+;; RUN: wasm-as %s -all -g -o %t.wasm
+;; RUN: wasm-dis %t.wasm -o - | filecheck %s
+
+(module
+ ;; CHECK: (memory $memorya 1 1)
+ (memory $memorya 1 1)
+ ;; CHECK: (memory $memoryb 1 1)
+ (memory $memoryb 1 1)
+ ;; CHECK: (memory $memoryc 1 1)
+ (memory $memoryc 1 1)
+ ;; CHECK: (memory $memoryd 1 1)
+ (memory $memoryd 1 1)
+ ;; CHECK: (func $v128.load (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load $memorya
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load (param $0 i32) (result v128)
+ (v128.load offset=0 align=16
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load2 (param $0 i32) (result v128)
+ (v128.load $memoryb offset=0 align=16
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load8x8_s (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load8x8_s $memoryc
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load8x8_s (param $0 i32) (result v128)
+ (v128.load8x8_s 2
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load8x8_s2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load8x8_s $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load8x8_s2 (param $0 i32) (result v128)
+ (v128.load8x8_s 1
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load8x8_u (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load8x8_u $memoryd
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load8x8_u (param $0 i32) (result v128)
+ (v128.load8x8_u 3
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load8x8_u2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load8x8_u $memoryd
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load8x8_u2 (param $0 i32) (result v128)
+ (v128.load8x8_u $memoryd
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load16x4_s (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load16x4_s $memorya
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load16x4_s (param $0 i32) (result v128)
+ (v128.load16x4_s 0
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load16x4_s2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load16x4_s $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load16x4_s2 (param $0 i32) (result v128)
+ (v128.load16x4_s $memoryb
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load16x4_u (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load16x4_u $memorya
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load16x4_u (param $0 i32) (result v128)
+ (v128.load16x4_u 0
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load16x4_u2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load16x4_u $memorya
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load16x4_u2 (param $0 i32) (result v128)
+ (v128.load16x4_u $memorya
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load32x2_s (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load32x2_s $memoryc
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load32x2_s (param $0 i32) (result v128)
+ (v128.load32x2_s 2
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load32x2_s2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load32x2_s $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load32x2_s2 (param $0 i32) (result v128)
+ (v128.load32x2_s $memoryb
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load32x2_u (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load32x2_u $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load32x2_u (param $0 i32) (result v128)
+ (v128.load32x2_u 1
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load32x2_u2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load32x2_u $memoryc
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load32x2_u2 (param $0 i32) (result v128)
+ (v128.load32x2_u $memoryc
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load8_splat (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load8_splat $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load8_splat (param $0 i32) (result v128)
+ (v128.load8_splat 1
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load8_splat2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load8_splat $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load8_splat2 (param $0 i32) (result v128)
+ (v128.load8_splat $memoryb
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load16_splat (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load16_splat $memorya
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load16_splat (param $0 i32) (result v128)
+ (v128.load16_splat $memorya
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load16_splat2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load16_splat $memorya
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load16_splat2 (param $0 i32) (result v128)
+ (v128.load16_splat 0
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load32_splat (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load32_splat $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load32_splat (param $0 i32) (result v128)
+ (v128.load32_splat 1
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load32_splat2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load32_splat $memoryd
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load32_splat2 (param $0 i32) (result v128)
+ (v128.load32_splat $memoryd
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load64_splat (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load64_splat $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_splat (param $0 i32) (result v128)
+ (v128.load64_splat 1
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load64_splat2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load64_splat $memorya
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_splat2 (param $0 i32) (result v128)
+ (v128.load64_splat $memorya
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.store (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store $memorya
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store (param $0 i32) (param $1 v128)
+ (v128.store 0 offset=0 align=16
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store2 (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store2 (param $0 i32) (param $1 v128)
+ (v128.store 1 offset=0 align=16
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load8_lane (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load8_lane $memorya 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load8_lane (param $0 i32) (param $1 v128) (result v128)
+ (v128.load8_lane 0 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load8_lane2 (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load8_lane $memoryb 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load8_lane2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load8_lane $memoryb 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load16_lane (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load16_lane $memoryb 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load16_lane (param $0 i32) (param $1 v128) (result v128)
+ (v128.load16_lane 1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load16_lane2 (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load16_lane $memoryd 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load16_lane2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load16_lane $memoryd 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load32_lane (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load32_lane $memorya 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load32_lane (param $0 i32) (param $1 v128) (result v128)
+ (v128.load32_lane $memorya 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load32_lane2 (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load32_lane $memoryb 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load32_lane2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load32_lane 1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load64_lane (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load64_lane $memoryd 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_lane (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memoryd 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load64_lane2 (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load64_lane $memoryb 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_lane2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane 1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load64_lane_align (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load64_lane $memorya align=1 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_lane_align (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane 0 align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load64_lane_align2 (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load64_lane $memoryb align=1 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_lane_align2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memoryb align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load64_lane_offset (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load64_lane $memoryc offset=32 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_lane_offset (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane 2 offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load64_lane_offset2 (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load64_lane $memoryb offset=32 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_lane_offset2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memoryb offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load64_lane_align_offset (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load64_lane $memorya offset=32 align=1 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_lane_align_offset (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane align=1 offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load64_lane_align_offset2 (param $0 i32) (param $1 v128) (result v128)
+ ;; CHECK-NEXT: (v128.load64_lane $memoryd offset=32 align=1 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_lane_align_offset2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memoryd align=1 offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store8_lane (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store8_lane $memorya 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store8_lane (param $0 i32) (param $1 v128)
+ (v128.store8_lane 0 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store8_lane2 (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store8_lane $memoryd 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store8_lane2 (param $0 i32) (param $1 v128)
+ (v128.store8_lane $memoryd 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store16_lane (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store16_lane $memorya 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store16_lane (param $0 i32) (param $1 v128)
+ (v128.store16_lane $memorya 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store16_lane2 (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store16_lane $memoryb 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store16_lane2 (param $0 i32) (param $1 v128)
+ (v128.store16_lane 1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store32_lane (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store32_lane $memoryb 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store32_lane (param $0 i32) (param $1 v128)
+ (v128.store32_lane $memoryb 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store32_lane2 (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store32_lane $memoryc 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store32_lane2 (param $0 i32) (param $1 v128)
+ (v128.store32_lane 2 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store64_lane (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store64_lane $memoryc 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store64_lane (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memoryc 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store64_lane2 (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store64_lane $memoryb 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store64_lane2 (param $0 i32) (param $1 v128)
+ (v128.store64_lane 1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store64_lane_align (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store64_lane $memoryb align=1 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store64_lane_align (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memoryb align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store64_lane_align2 (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store64_lane $memorya align=1 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store64_lane_align2 (param $0 i32) (param $1 v128)
+ (v128.store64_lane 0 align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store64_lane_offset (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store64_lane $memoryd offset=32 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store64_lane_offset (param $0 i32) (param $1 v128)
+ (v128.store64_lane 3 offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store64_lane_offset2 (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store64_lane $memorya offset=32 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store64_lane_offset2 (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memorya offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store64_lane_align_offset (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store64_lane $memoryb offset=32 align=1 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store64_lane_align_offset (param $0 i32) (param $1 v128)
+ (v128.store64_lane 1 align=1 offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.store64_lane_align_offset2 (param $0 i32) (param $1 v128)
+ ;; CHECK-NEXT: (v128.store64_lane $memoryd offset=32 align=1 0
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: (local.get $1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.store64_lane_align_offset2 (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memoryd align=1 offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ ;; CHECK: (func $v128.load32_zero (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load32_zero $memorya
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load32_zero (param $0 i32) (result v128)
+ (v128.load32_zero 0
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load32_zero2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load32_zero $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load32_zero2 (param $0 i32) (result v128)
+ (v128.load32_zero $memoryb
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load64_zero (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load64_zero $memoryb
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_zero (param $0 i32) (result v128)
+ (v128.load64_zero 1
+ (local.get $0)
+ )
+ )
+ ;; CHECK: (func $v128.load64_zero2 (param $0 i32) (result v128)
+ ;; CHECK-NEXT: (v128.load64_zero $memoryc
+ ;; CHECK-NEXT: (local.get $0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $v128.load64_zero2 (param $0 i32) (result v128)
+ (v128.load64_zero $memoryc
+ (local.get $0)
+ )
+ )
+)
+
diff --git a/test/lit/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.wast b/test/lit/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.wast
index 6c9a598bb..e0045579d 100644
--- a/test/lit/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.wast
+++ b/test/lit/passes/O3_inline-functions-with-loops_flexible-inline-max-function-size=30.wast
@@ -8,6 +8,8 @@
(type $t0 (func (param i32) (result i32)))
;; CHECK: (memory $memory 0)
+ ;; CHECK: (export "memory" (memory $memory))
+
;; CHECK: (export "fib" (func $fib))
;; CHECK: (export "looped" (func $looped))
@@ -20,8 +22,6 @@
;; CHECK: (export "t3" (func $t3))
- ;; CHECK: (export "memory" (memory $memory))
-
;; CHECK: (func $fib (; has Stack IR ;) (param $0 i32) (result i32)
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.le_s
diff --git a/test/lit/passes/O4_disable-bulk-memory.wast b/test/lit/passes/O4_disable-bulk-memory.wast
index 4a6293d65..8200df5a3 100644
--- a/test/lit/passes/O4_disable-bulk-memory.wast
+++ b/test/lit/passes/O4_disable-bulk-memory.wast
@@ -80,8 +80,8 @@
(global $global$6 i32 (i32.const 100))
;; CHECK: (elem (i32.const 0) $null)
- ;; CHECK: (export "memory" (memory $0))
- (export "memory" (memory $0))
+ ;; CHECK: (export "memory" (memory $1))
+ (export "memory" (memory $1))
;; CHECK: (export "table" (table $0))
(export "table" (table $0))
;; CHECK: (export "init" (func $assembly/index/init))
diff --git a/test/lit/wasm-split/export-name-already-exists.wast b/test/lit/wasm-split/export-name-already-exists.wast
index 708929e98..83951795a 100644
--- a/test/lit/wasm-split/export-name-already-exists.wast
+++ b/test/lit/wasm-split/export-name-already-exists.wast
@@ -4,5 +4,6 @@
;; CHECK: error: Export foo already exists.
(module
+ (memory 0 0)
(export "foo" (memory 0 0))
)
diff --git a/test/lit/wasm-split/instrument-in-memory.wast b/test/lit/wasm-split/instrument-in-memory.wast
index 568ce2207..3a3c19d7f 100644
--- a/test/lit/wasm-split/instrument-in-memory.wast
+++ b/test/lit/wasm-split/instrument-in-memory.wast
@@ -7,6 +7,7 @@
(module
(import "env" "foo" (func $foo))
(export "bar" (func $bar))
+ (memory $0 1 1)
(func $bar
(call $foo)
)
diff --git a/test/lit/wasm-split/merge-profiles.wast b/test/lit/wasm-split/merge-profiles.wast
index fdaf6678e..2d09fefaa 100644
--- a/test/lit/wasm-split/merge-profiles.wast
+++ b/test/lit/wasm-split/merge-profiles.wast
@@ -22,6 +22,7 @@
;; SPLIT-NEXT: Splitting out functions: qux{{$}}
(module
+ (memory 0 0)
(export "memory" (memory 0 0))
(export "foo" (func $foo))
(export "bar" (func $bar))
diff --git a/test/lit/wasm-split/mismatched-hashes.wast b/test/lit/wasm-split/mismatched-hashes.wast
index fd3ebb8d3..347fb1746 100644
--- a/test/lit/wasm-split/mismatched-hashes.wast
+++ b/test/lit/wasm-split/mismatched-hashes.wast
@@ -19,5 +19,6 @@
;; RUN: wasm-split %s --profile=%t.prof -o1 %t.1.wasm -o2 %t.2.wasm
(module
+ (memory 0 0)
(export "memory" (memory 0 0))
)
diff --git a/test/multi-memories-atomics64.wasm b/test/multi-memories-atomics64.wasm
new file mode 100644
index 000000000..a13826285
--- /dev/null
+++ b/test/multi-memories-atomics64.wasm
Binary files differ
diff --git a/test/multi-memories-atomics64.wasm.fromBinary b/test/multi-memories-atomics64.wasm.fromBinary
new file mode 100644
index 000000000..565a5e63a
--- /dev/null
+++ b/test/multi-memories-atomics64.wasm.fromBinary
@@ -0,0 +1,352 @@
+(module
+ (type $0 (func))
+ (memory $appMemory (shared i64 23 256))
+ (memory $dataMemory (shared i64 23 256))
+ (memory $instrumentMemory (shared i64 23 256))
+ (func $atomic-loadstore
+ (local $0 i64)
+ (local $1 i64)
+ (local $2 i32)
+ (drop
+ (i32.atomic.load8_u $appMemory offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i32.atomic.load8_u $appMemory offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i32.atomic.load16_u $dataMemory offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i32.atomic.load16_u $instrumentMemory offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i32.atomic.load $dataMemory offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i32.atomic.load $appMemory offset=4
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load8_u $appMemory
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load8_u $dataMemory
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load16_u $appMemory
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load16_u $appMemory
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load32_u $instrumentMemory
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load32_u $appMemory
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load $appMemory
+ (local.get $0)
+ )
+ )
+ (drop
+ (i64.atomic.load $instrumentMemory
+ (local.get $0)
+ )
+ )
+ (i32.atomic.store $appMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ (i32.atomic.store $appMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ (i32.atomic.store8 $instrumentMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ (i32.atomic.store8 $dataMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ (i32.atomic.store16 $appMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ (i32.atomic.store16 $dataMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ (i64.atomic.store $appMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store $appMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store8 $dataMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store8 $instrumentMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store16 $appMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store16 $appMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store32 $instrumentMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ (i64.atomic.store32 $dataMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $atomic-rmw
+ (local $0 i64)
+ (local $1 i64)
+ (local $2 i32)
+ (drop
+ (i32.atomic.rmw.add $dataMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw.add $instrumentMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.add_u $appMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.add_u $appMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw16.and_u $dataMemory
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw16.and_u $instrumentMemory
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i64.atomic.rmw32.or_u $appMemory
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (drop
+ (i64.atomic.rmw32.or_u $appMemory
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.xchg_u $appMemory
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.xchg_u $dataMemory
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ )
+ (func $atomic-cmpxchg
+ (local $0 i64)
+ (local $1 i64)
+ (local $2 i32)
+ (drop
+ (i32.atomic.rmw.cmpxchg $appMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw.cmpxchg $instrumentMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.cmpxchg_u $appMemory
+ (local.get $0)
+ (local.get $2)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i32.atomic.rmw8.cmpxchg_u $appMemory
+ (local.get $0)
+ (local.get $2)
+ (local.get $2)
+ )
+ )
+ (drop
+ (i64.atomic.rmw.cmpxchg $appMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (i64.atomic.rmw.cmpxchg $dataMemory offset=4
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (i64.atomic.rmw32.cmpxchg_u $instrumentMemory
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (i64.atomic.rmw32.cmpxchg_u $dataMemory
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ )
+ (func $atomic-wait-notify
+ (local $0 i64)
+ (local $1 i64)
+ (local $2 i32)
+ (drop
+ (memory.atomic.wait32 $dataMemory
+ (local.get $0)
+ (local.get $2)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait32 $instrumentMemory
+ (local.get $0)
+ (local.get $2)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait32 $appMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait32 $instrumentMemory offset=4
+ (local.get $0)
+ (local.get $2)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.notify $dataMemory
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (memory.atomic.notify $dataMemory
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (memory.atomic.notify $appMemory offset=24
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (memory.atomic.notify $dataMemory offset=24
+ (local.get $0)
+ (local.get $2)
+ )
+ )
+ (drop
+ (memory.atomic.wait64 $instrumentMemory
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait64 $instrumentMemory
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait64 $appMemory offset=16
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ (drop
+ (memory.atomic.wait64 $appMemory offset=16
+ (local.get $0)
+ (local.get $1)
+ (local.get $1)
+ )
+ )
+ )
+ (func $atomic-fence
+ (atomic.fence)
+ )
+)
+
diff --git a/test/multi-memories-basics.wasm b/test/multi-memories-basics.wasm
new file mode 100644
index 000000000..d75c74cff
--- /dev/null
+++ b/test/multi-memories-basics.wasm
Binary files differ
diff --git a/test/multi-memories-basics.wasm.fromBinary b/test/multi-memories-basics.wasm.fromBinary
new file mode 100644
index 000000000..62b926531
--- /dev/null
+++ b/test/multi-memories-basics.wasm.fromBinary
@@ -0,0 +1,117 @@
+(module
+ (type $none_=>_none (func))
+ (type $none_=>_i32 (func (result i32)))
+ (import "env" "memory" (memory $importedMemory 1 1))
+ (memory $memory1 1 500)
+ (memory $memory2 1 800)
+ (memory $memory3 1 400)
+ (data (i32.const 0) "abcd")
+ (func $memory.fill
+ (memory.fill $memory2
+ (i32.const 0)
+ (i32.const 1)
+ (i32.const 2)
+ )
+ )
+ (func $memory.copy
+ (memory.copy $memory2 $memory3
+ (i32.const 512)
+ (i32.const 0)
+ (i32.const 12)
+ )
+ )
+ (func $memory.init
+ (memory.init $memory1 0
+ (i32.const 0)
+ (i32.const 0)
+ (i32.const 45)
+ )
+ )
+ (func $memory.grow (result i32)
+ (memory.grow $memory3
+ (i32.const 10)
+ )
+ )
+ (func $memory.size (result i32)
+ (memory.size $memory3)
+ )
+ (func $loads
+ (drop
+ (i32.load $memory1
+ (i32.const 12)
+ )
+ )
+ (drop
+ (i32.load $memory3
+ (i32.const 12)
+ )
+ )
+ (drop
+ (i32.load16_s $memory2
+ (i32.const 12)
+ )
+ )
+ (drop
+ (i32.load16_s $memory2
+ (i32.const 12)
+ )
+ )
+ (drop
+ (i32.load8_s $memory3
+ (i32.const 12)
+ )
+ )
+ (drop
+ (i32.load8_s $memory3
+ (i32.const 12)
+ )
+ )
+ (drop
+ (i32.load16_u $memory1
+ (i32.const 12)
+ )
+ )
+ (drop
+ (i32.load16_u $memory1
+ (i32.const 12)
+ )
+ )
+ (drop
+ (i32.load8_u $memory2
+ (i32.const 12)
+ )
+ )
+ (drop
+ (i32.load8_u $memory2
+ (i32.const 12)
+ )
+ )
+ )
+ (func $stores
+ (i32.store $memory1
+ (i32.const 12)
+ (i32.const 115)
+ )
+ (i32.store $memory1
+ (i32.const 12)
+ (i32.const 115)
+ )
+ (i32.store16 $memory2
+ (i32.const 20)
+ (i32.const 31353)
+ )
+ (i32.store16 $importedMemory
+ (i32.const 20)
+ (i32.const 31353)
+ )
+ (i32.store8 $memory3
+ (i32.const 23)
+ (i32.const 120)
+ )
+ (i32.store8 $memory3
+ (i32.const 23)
+ (i32.const 120)
+ )
+ )
+)
+
diff --git a/test/multi-memories-simd.wasm b/test/multi-memories-simd.wasm
new file mode 100644
index 000000000..e8925efd6
--- /dev/null
+++ b/test/multi-memories-simd.wasm
Binary files differ
diff --git a/test/multi-memories-simd.wasm.fromBinary b/test/multi-memories-simd.wasm.fromBinary
new file mode 100644
index 000000000..48cde73c3
--- /dev/null
+++ b/test/multi-memories-simd.wasm.fromBinary
@@ -0,0 +1,320 @@
+(module
+ (type $i32_=>_v128 (func (param i32) (result v128)))
+ (type $i32_v128_=>_none (func (param i32 v128)))
+ (type $i32_v128_=>_v128 (func (param i32 v128) (result v128)))
+ (memory $memorya 1 1)
+ (memory $memoryb 1 1)
+ (memory $memoryc 1 1)
+ (memory $memoryd 1 1)
+ (func $v128.load (param $0 i32) (result v128)
+ (v128.load $memorya
+ (local.get $0)
+ )
+ )
+ (func $v128.load2 (param $0 i32) (result v128)
+ (v128.load $memoryb
+ (local.get $0)
+ )
+ )
+ (func $v128.load8x8_s (param $0 i32) (result v128)
+ (v128.load8x8_s $memoryc
+ (local.get $0)
+ )
+ )
+ (func $v128.load8x8_s2 (param $0 i32) (result v128)
+ (v128.load8x8_s $memoryb
+ (local.get $0)
+ )
+ )
+ (func $v128.load8x8_u (param $0 i32) (result v128)
+ (v128.load8x8_u $memoryd
+ (local.get $0)
+ )
+ )
+ (func $v128.load8x8_u2 (param $0 i32) (result v128)
+ (v128.load8x8_u $memoryd
+ (local.get $0)
+ )
+ )
+ (func $v128.load16x4_s (param $0 i32) (result v128)
+ (v128.load16x4_s $memorya
+ (local.get $0)
+ )
+ )
+ (func $v128.load16x4_s2 (param $0 i32) (result v128)
+ (v128.load16x4_s $memoryb
+ (local.get $0)
+ )
+ )
+ (func $v128.load16x4_u (param $0 i32) (result v128)
+ (v128.load16x4_u $memorya
+ (local.get $0)
+ )
+ )
+ (func $v128.load16x4_u2 (param $0 i32) (result v128)
+ (v128.load16x4_u $memorya
+ (local.get $0)
+ )
+ )
+ (func $v128.load32x2_s (param $0 i32) (result v128)
+ (v128.load32x2_s $memoryc
+ (local.get $0)
+ )
+ )
+ (func $v128.load32x2_s2 (param $0 i32) (result v128)
+ (v128.load32x2_s $memoryb
+ (local.get $0)
+ )
+ )
+ (func $v128.load32x2_u (param $0 i32) (result v128)
+ (v128.load32x2_u $memoryb
+ (local.get $0)
+ )
+ )
+ (func $v128.load32x2_u2 (param $0 i32) (result v128)
+ (v128.load32x2_u $memoryc
+ (local.get $0)
+ )
+ )
+ (func $v128.load8_splat (param $0 i32) (result v128)
+ (v128.load8_splat $memoryb
+ (local.get $0)
+ )
+ )
+ (func $v128.load8_splat2 (param $0 i32) (result v128)
+ (v128.load8_splat $memoryb
+ (local.get $0)
+ )
+ )
+ (func $v128.load16_splat (param $0 i32) (result v128)
+ (v128.load16_splat $memorya
+ (local.get $0)
+ )
+ )
+ (func $v128.load16_splat2 (param $0 i32) (result v128)
+ (v128.load16_splat $memorya
+ (local.get $0)
+ )
+ )
+ (func $v128.load32_splat (param $0 i32) (result v128)
+ (v128.load32_splat $memoryb
+ (local.get $0)
+ )
+ )
+ (func $v128.load32_splat2 (param $0 i32) (result v128)
+ (v128.load32_splat $memoryd
+ (local.get $0)
+ )
+ )
+ (func $v128.load64_splat (param $0 i32) (result v128)
+ (v128.load64_splat $memoryb
+ (local.get $0)
+ )
+ )
+ (func $v128.load64_splat2 (param $0 i32) (result v128)
+ (v128.load64_splat $memorya
+ (local.get $0)
+ )
+ )
+ (func $v128.store (param $0 i32) (param $1 v128)
+ (v128.store $memorya
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store2 (param $0 i32) (param $1 v128)
+ (v128.store $memoryb
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load8_lane (param $0 i32) (param $1 v128) (result v128)
+ (v128.load8_lane $memorya 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load8_lane2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load8_lane $memoryb 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load16_lane (param $0 i32) (param $1 v128) (result v128)
+ (v128.load16_lane $memoryb 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load16_lane2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load16_lane $memoryd 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load32_lane (param $0 i32) (param $1 v128) (result v128)
+ (v128.load32_lane $memorya 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load32_lane2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load32_lane $memoryb 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load64_lane (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memoryd 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load64_lane2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memoryb 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load64_lane_align (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memorya align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load64_lane_align2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memoryb align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load64_lane_offset (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memoryc offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load64_lane_offset2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memoryb offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load64_lane_align_offset (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memorya offset=32 align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load64_lane_align_offset2 (param $0 i32) (param $1 v128) (result v128)
+ (v128.load64_lane $memoryd offset=32 align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store8_lane (param $0 i32) (param $1 v128)
+ (v128.store8_lane $memorya 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store8_lane2 (param $0 i32) (param $1 v128)
+ (v128.store8_lane $memoryd 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store16_lane (param $0 i32) (param $1 v128)
+ (v128.store16_lane $memorya 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store16_lane2 (param $0 i32) (param $1 v128)
+ (v128.store16_lane $memoryb 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store32_lane (param $0 i32) (param $1 v128)
+ (v128.store32_lane $memoryb 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store32_lane2 (param $0 i32) (param $1 v128)
+ (v128.store32_lane $memoryc 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store64_lane (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memoryc 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store64_lane2 (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memoryb 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store64_lane_align (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memoryb align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store64_lane_align2 (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memorya align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store64_lane_offset (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memoryd offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store64_lane_offset2 (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memorya offset=32 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store64_lane_align_offset (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memoryb offset=32 align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.store64_lane_align_offset2 (param $0 i32) (param $1 v128)
+ (v128.store64_lane $memoryd offset=32 align=1 0
+ (local.get $0)
+ (local.get $1)
+ )
+ )
+ (func $v128.load32_zero (param $0 i32) (result v128)
+ (v128.load32_zero $memorya
+ (local.get $0)
+ )
+ )
+ (func $v128.load32_zero2 (param $0 i32) (result v128)
+ (v128.load32_zero $memoryb
+ (local.get $0)
+ )
+ )
+ (func $v128.load64_zero (param $0 i32) (result v128)
+ (v128.load64_zero $memoryb
+ (local.get $0)
+ )
+ )
+ (func $v128.load64_zero2 (param $0 i32) (result v128)
+ (v128.load64_zero $memoryc
+ (local.get $0)
+ )
+ )
+)
+
diff --git a/test/passes/O3_low-memory-unused_metrics.txt b/test/passes/O3_low-memory-unused_metrics.txt
index d33277eb6..3bdce2921 100644
--- a/test/passes/O3_low-memory-unused_metrics.txt
+++ b/test/passes/O3_low-memory-unused_metrics.txt
@@ -3,6 +3,8 @@ total
[funcs] : 1
[globals] : 0
[imports] : 10
+ [memories] : 0
+ [memory-data] : 0
[table-data] : 0
[tables] : 0
[tags] : 0
diff --git a/test/passes/converge_O3_metrics.bin.txt b/test/passes/converge_O3_metrics.bin.txt
index fbf978433..4a2d8a5c1 100644
--- a/test/passes/converge_O3_metrics.bin.txt
+++ b/test/passes/converge_O3_metrics.bin.txt
@@ -3,6 +3,7 @@ total
[funcs] : 6
[globals] : 1
[imports] : 3
+ [memories] : 0
[memory-data] : 28
[table-data] : 429
[tables] : 0
@@ -229,6 +230,7 @@ total
[funcs] : 6
[globals] : 0 -1
[imports] : 3
+ [memories] : 0
[memory-data] : 28
[table-data] : 429
[tables] : 0
@@ -448,6 +450,7 @@ total
[funcs] : 6
[globals] : 0
[imports] : 3
+ [memories] : 0
[memory-data] : 28
[table-data] : 429
[tables] : 0
diff --git a/test/passes/func-metrics.txt b/test/passes/func-metrics.txt
index a8b6885c4..9471e49e4 100644
--- a/test/passes/func-metrics.txt
+++ b/test/passes/func-metrics.txt
@@ -3,6 +3,7 @@ global
[funcs] : 3
[globals] : 1
[imports] : 0
+ [memories] : 1
[memory-data] : 9
[table-data] : 3
[tables] : 1
@@ -96,6 +97,7 @@ global
[funcs] : 0
[globals] : 0
[imports] : 0
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 0
@@ -106,6 +108,7 @@ global
[funcs] : 3
[globals] : 0
[imports] : 1
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 0
@@ -182,6 +185,7 @@ global
[funcs] : 1
[globals] : 0
[imports] : 1
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 0
@@ -215,6 +219,7 @@ global
[funcs] : 1
[globals] : 0
[imports] : 1
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 0
@@ -244,6 +249,7 @@ global
[funcs] : 1
[globals] : 1
[imports] : 1
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 1
diff --git a/test/passes/fuzz_metrics_noprint.bin.txt b/test/passes/fuzz_metrics_noprint.bin.txt
index 4c481cd8f..2df80ff72 100644
--- a/test/passes/fuzz_metrics_noprint.bin.txt
+++ b/test/passes/fuzz_metrics_noprint.bin.txt
@@ -3,6 +3,7 @@ total
[funcs] : 50
[globals] : 7
[imports] : 4
+ [memories] : 1
[memory-data] : 4
[table-data] : 17
[tables] : 1
diff --git a/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.txt b/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.txt
index e94bc3531..b9624c55d 100644
--- a/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.txt
+++ b/test/passes/generate-stack-ir_optimize-stack-ir_print-stack-ir_optimize-level=3.txt
@@ -34,21 +34,21 @@
(local $temp f64)
block $topmost (result f64)
i32.const 8
- f64.load
+ f64.load $0
i32.const 16
- f64.load
+ f64.load $0
f64.add
i32.const 16
- f64.load
+ f64.load $0
f64.neg
f64.add
i32.const 8
- f64.load
+ f64.load $0
f64.neg
f64.add
local.set $temp
i32.const 24
- i32.load
+ i32.load $0
i32.const 0
i32.gt_s
if
@@ -56,7 +56,7 @@
br $topmost
end
i32.const 32
- f64.load
+ f64.load $0
f64.const 0
f64.gt
if
@@ -323,7 +323,7 @@
(func $i64-store32 (param $0 i32) (param $1 i64)
local.get $0
local.get $1
- i64.store32
+ i64.store32 $0
)
(func $return-unreachable (result i32)
i32.const 1
diff --git a/test/passes/metrics_all-features.txt b/test/passes/metrics_all-features.txt
index 255e809c2..bd3368b49 100644
--- a/test/passes/metrics_all-features.txt
+++ b/test/passes/metrics_all-features.txt
@@ -3,6 +3,7 @@ total
[funcs] : 1
[globals] : 1
[imports] : 0
+ [memories] : 1
[memory-data] : 9
[table-data] : 3
[tables] : 1
@@ -70,6 +71,7 @@ total
[funcs] : 0
[globals] : 0
[imports] : 0
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 0
diff --git a/test/passes/metrics_strip-debug_metrics.bin.txt b/test/passes/metrics_strip-debug_metrics.bin.txt
index 9760353e0..0022a8b54 100644
--- a/test/passes/metrics_strip-debug_metrics.bin.txt
+++ b/test/passes/metrics_strip-debug_metrics.bin.txt
@@ -3,6 +3,7 @@ total
[funcs] : 1
[globals] : 0
[imports] : 0
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 1
@@ -13,6 +14,7 @@ total
[funcs] : 1
[globals] : 0
[imports] : 0
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 1
diff --git a/test/passes/metrics_strip-producers_metrics.bin.txt b/test/passes/metrics_strip-producers_metrics.bin.txt
index 072f7c827..428401ece 100644
--- a/test/passes/metrics_strip-producers_metrics.bin.txt
+++ b/test/passes/metrics_strip-producers_metrics.bin.txt
@@ -3,6 +3,7 @@ total
[funcs] : 1
[globals] : 0
[imports] : 0
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 1
@@ -13,6 +14,7 @@ total
[funcs] : 1
[globals] : 0
[imports] : 0
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 1
diff --git a/test/passes/print_g_metrics.bin.txt b/test/passes/print_g_metrics.bin.txt
index ac035635d..2dbceb433 100644
--- a/test/passes/print_g_metrics.bin.txt
+++ b/test/passes/print_g_metrics.bin.txt
@@ -69,6 +69,7 @@ total
[funcs] : 3
[globals] : 1
[imports] : 0
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 37
diff --git a/test/passes/sparse_matrix_liveness.bin.txt b/test/passes/sparse_matrix_liveness.bin.txt
index b55f1023a..d669ee16f 100644
--- a/test/passes/sparse_matrix_liveness.bin.txt
+++ b/test/passes/sparse_matrix_liveness.bin.txt
@@ -3,6 +3,7 @@ total
[funcs] : 1
[globals] : 0
[imports] : 0
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 4
@@ -16,6 +17,7 @@ total
[funcs] : 1
[globals] : 0
[imports] : 0
+ [memories] : 0
[tables] : 0
[tags] : 0
[total] : 4
diff --git a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
index ad0779876..aac1cbc83 100644
--- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
+++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
@@ -3,6 +3,7 @@ total
[funcs] : 12
[globals] : 6
[imports] : 5
+ [memories] : 1
[memory-data] : 22
[table-data] : 4
[tables] : 1
diff --git a/test/spec/imports.wast b/test/spec/imports.wast
index 43ffedaee..2ef8574e7 100644
--- a/test/spec/imports.wast
+++ b/test/spec/imports.wast
@@ -489,19 +489,6 @@
(assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000))
(assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access")
-(assert_invalid
- (module (import "" "" (memory 1)) (import "" "" (memory 1)))
- "multiple memories"
-)
-(assert_invalid
- (module (import "" "" (memory 1)) (memory 0))
- "multiple memories"
-)
-(assert_invalid
- (module (memory 0) (memory 0))
- "multiple memories"
-)
-
(module (import "test" "memory-2-inf" (memory 2)))
(module (import "test" "memory-2-inf" (memory 1)))
(module (import "test" "memory-2-inf" (memory 0)))
diff --git a/test/spec/memory.wast b/test/spec/memory.wast
index 3c426450a..c4e932b0e 100644
--- a/test/spec/memory.wast
+++ b/test/spec/memory.wast
@@ -5,9 +5,6 @@
(module (memory 1 256))
(module (memory 0 65536))
-(assert_invalid (module (memory 0) (memory 0)) "multiple memories")
-(assert_invalid (module (memory (import "spectest" "memory") 0) (memory 0)) "multiple memories")
-
(module (memory (data)) (func (export "memsize") (result i32) (memory.size)))
(assert_return (invoke "memsize") (i32.const 0))
(module (memory (data "")) (func (export "memsize") (result i32) (memory.size)))
diff --git a/test/spec/memory64.wast b/test/spec/memory64.wast
index da4ba591e..683bfe211 100644
--- a/test/spec/memory64.wast
+++ b/test/spec/memory64.wast
@@ -5,9 +5,6 @@
(module (memory i64 1 256))
(module (memory i64 0 65536))
-(assert_invalid (module (memory i64 0) (memory i64 0)) "multiple memories")
-(assert_invalid (module (memory (import "spectest" "memory") i64 0) (memory i64 0)) "multiple memories")
-
(module (memory i64 (data)) (func (export "memsize") (result i64) (memory.size)))
(assert_return (invoke "memsize") (i64.const 0))
(module (memory i64 (data "")) (func (export "memsize") (result i64) (memory.size)))
diff --git a/test/spec/multi-memories_size.wast b/test/spec/multi-memories_size.wast
new file mode 100644
index 000000000..8f0e7bdc3
--- /dev/null
+++ b/test/spec/multi-memories_size.wast
@@ -0,0 +1,35 @@
+(module
+ (memory $appMemory 0)
+ (memory $dataMemory 2)
+ (memory $instrumentMemory 4)
+ (func (export "size") (result i32) (memory.size))
+ (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz))))
+ (func (export "size1") (result i32) (memory.size 1))
+ (func (export "grow1") (param $sz i32) (drop (memory.grow 1 (local.get $sz))))
+ (func (export "size2") (result i32) (memory.size 2))
+ (func (export "grow2") (param $sz i32) (drop (memory.grow 2 (local.get $sz))))
+)
+
+(assert_return (invoke "size") (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "grow" (i32.const 4)))
+(assert_return (invoke "size") (i32.const 5))
+(assert_return (invoke "grow" (i32.const 0)))
+(assert_return (invoke "size") (i32.const 5))
+
+(assert_return (invoke "size1") (i32.const 2))
+(assert_return (invoke "grow1" (i32.const 2)))
+(assert_return (invoke "size1") (i32.const 4))
+(assert_return (invoke "grow1" (i32.const 4)))
+(assert_return (invoke "size1") (i32.const 8))
+(assert_return (invoke "grow1" (i32.const 0)))
+(assert_return (invoke "size1") (i32.const 8))
+
+(assert_return (invoke "size2") (i32.const 4))
+(assert_return (invoke "grow2" (i32.const 4)))
+(assert_return (invoke "size2") (i32.const 8))
+(assert_return (invoke "grow2" (i32.const 8)))
+(assert_return (invoke "size2") (i32.const 16))
+(assert_return (invoke "grow2" (i32.const 0)))
+(assert_return (invoke "size2") (i32.const 16))
diff --git a/test/spec/old_import.wast b/test/spec/old_import.wast
index a26c16e48..eba633388 100644
--- a/test/spec/old_import.wast
+++ b/test/spec/old_import.wast
@@ -179,19 +179,6 @@
(assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000))
(assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access")
-(assert_invalid
- (module (import "" "" (memory 1)) (import "" "" (memory 1)))
- "multiple memories"
-)
-(assert_invalid
- (module (import "" "" (memory 1)) (memory 0))
- "multiple memories"
-)
-(assert_invalid
- (module (memory 0) (memory 0))
- "multiple memories"
-)
-
(assert_unlinkable
(module (import "spectest" "unknown" (memory 1)))
"unknown import"