summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas Lively <7121787+tlively@users.noreply.github.com>2019-04-22 15:56:38 -0700
committerGitHub <noreply@github.com>2019-04-22 15:56:38 -0700
commitd4f5162f62e9ea920abd196bd5ca2f9505e2823e (patch)
tree90cbba9a09239e7ee48f1e94d339c7b31e376cb3 /src
parent711a22c65f28029ae0ca2d31a0cd6f8be9b953c7 (diff)
downloadbinaryen-d4f5162f62e9ea920abd196bd5ca2f9505e2823e.tar.gz
binaryen-d4f5162f62e9ea920abd196bd5ca2f9505e2823e.tar.bz2
binaryen-d4f5162f62e9ea920abd196bd5ca2f9505e2823e.zip
Finish bulk memory support (#2030)
Implement interpretation of remaining bulk memory ops, add bulk memory spec tests with light modifications, fix bugs preventing the fuzzer from running correctly with bulk memory, and fix bugs found by the fuzzer.
Diffstat (limited to 'src')
-rw-r--r--src/passes/RemoveUnusedModuleElements.cpp13
-rw-r--r--src/tools/wasm-opt.cpp1
-rw-r--r--src/wasm-interpreter.h89
-rw-r--r--src/wasm-traversal.h12
-rw-r--r--src/wasm.h1
-rw-r--r--src/wasm/wasm-binary.cpp5
6 files changed, 96 insertions, 25 deletions
diff --git a/src/passes/RemoveUnusedModuleElements.cpp b/src/passes/RemoveUnusedModuleElements.cpp
index 777d2dacc..e91fafcba 100644
--- a/src/passes/RemoveUnusedModuleElements.cpp
+++ b/src/passes/RemoveUnusedModuleElements.cpp
@@ -39,6 +39,7 @@ enum class ModuleElementKind {
typedef std::pair<ModuleElementKind, Name> ModuleElement;
// Finds reachabilities
+// TODO: use Effects to determine if a memory is used
struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
Module* module;
@@ -119,6 +120,18 @@ struct ReachabilityAnalyzer : public PostWalker<ReachabilityAnalyzer> {
void visitAtomicNotify(AtomicNotify* curr) {
usesMemory = true;
}
+ void visitMemoryInit(MemoryInit* curr) {
+ usesMemory = true;
+ }
+ void visitDataDrop(DataDrop* curr) {
+ usesMemory = true;
+ }
+ void visitMemoryCopy(MemoryCopy* curr) {
+ usesMemory = true;
+ }
+ void visitMemoryFill(MemoryFill* curr) {
+ usesMemory = true;
+ }
void visitHost(Host* curr) {
if (curr->op == CurrentMemory || curr->op == GrowMemory) {
usesMemory = true;
diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp
index 6fce0f89b..519713298 100644
--- a/src/tools/wasm-opt.cpp
+++ b/src/tools/wasm-opt.cpp
@@ -240,6 +240,7 @@ int main(int argc, const char* argv[]) {
auto input = buffer.getAsChars();
WasmBinaryBuilder parser(other, input, false);
parser.read();
+ options.applyFeatures(other);
if (options.passOptions.validate) {
bool valid = WasmValidator().validate(other);
if (!valid) {
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index fcdb44c42..23121a849 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -928,10 +928,6 @@ private:
}
void initializeMemoryContents() {
- // no way to create a Block without an ArenaAllocator, so use a builder
- // instead of creating it locally.
- Builder builder(wasm);
-
Const offset;
offset.value = Literal(uint32_t(0));
offset.finalize();
@@ -955,15 +951,16 @@ private:
init.finalize();
DataDrop drop;
- drop.segment = segment.index;
+ drop.segment = i;
drop.finalize();
- Function initializer;
- initializer.body = builder.blockify(&init, &drop);
-
- FunctionScope scope(&initializer, {});
-
- RuntimeExpressionRunner(*this, scope).visit(&init);
+ // we don't actually have a function, but we need one in order to visit
+ // the memory.init and data.drop instructions.
+ Function dummyFunc;
+ FunctionScope dummyScope(&dummyFunc, {});
+ RuntimeExpressionRunner runner(*this, dummyScope);
+ runner.visit(&init);
+ runner.visit(&drop);
}
}
@@ -1228,14 +1225,20 @@ private:
trap("memory.init of dropped segment");
}
- size_t destVal(dest.value.geti32());
- size_t offsetVal(offset.value.geti32());
- size_t sizeVal(size.value.geti32());
+ Address destVal(uint32_t(dest.value.geti32()));
+ Address offsetVal(uint32_t(offset.value.geti32()));
+ Address sizeVal(uint32_t(size.value.geti32()));
+
+ instance.checkLoadAddress(destVal, 0);
+ if (offsetVal > segment.data.size()) {
+ trap("segment offset out of bounds");
+ }
+
for (size_t i = 0; i < sizeVal; ++i) {
if (offsetVal + i >= segment.data.size()) {
trap("out of bounds segment access in memory.init");
}
- Literal addr = Literal(uint32_t(destVal + i));
+ Literal addr(uint32_t(destVal + i));
instance.externalInterface->store8(
instance.getFinalAddress(addr, 1),
segment.data[offsetVal + i]
@@ -1253,12 +1256,64 @@ private:
}
Flow visitMemoryCopy(MemoryCopy *curr) {
NOTE_ENTER("MemoryCopy");
- // TODO(tlively): implement me
+ Flow dest = this->visit(curr->dest);
+ if (dest.breaking()) return dest;
+ Flow source = this->visit(curr->source);
+ if (source.breaking()) return source;
+ Flow size = this->visit(curr->size);
+ if (size.breaking()) return size;
+ NOTE_EVAL1(dest);
+ NOTE_EVAL1(source);
+ NOTE_EVAL1(size);
+ Address destVal(uint32_t(dest.value.geti32()));
+ Address sourceVal(uint32_t(source.value.geti32()));
+ Address sizeVal(uint32_t(size.value.geti32()));
+
+ instance.checkLoadAddress(destVal, 0);
+ instance.checkLoadAddress(sourceVal, 0);
+
+ size_t start = 0;
+ size_t end = sizeVal;
+ int step = 1;
+ // Reverse direction if source is below dest and they overlap
+ if (sourceVal < destVal &&
+ (sourceVal + sizeVal > destVal || sourceVal + sizeVal < sourceVal)) {
+ start = sizeVal - 1;
+ end = -1;
+ step = -1;
+ }
+ for (size_t i = start; i != end; i += step) {
+ if (i + destVal >= std::numeric_limits<uint32_t>::max()) {
+ trap("Out of bounds memory access");
+ }
+ instance.externalInterface->store8(
+ instance.getFinalAddress(Literal(uint32_t(destVal + i)), 1),
+ instance.externalInterface->load8s(
+ instance.getFinalAddress(Literal(uint32_t(sourceVal + i)), 1)));
+ }
return {};
}
Flow visitMemoryFill(MemoryFill *curr) {
NOTE_ENTER("MemoryFill");
- // TODO(tlively): implement me
+ Flow dest = this->visit(curr->dest);
+ if (dest.breaking()) return dest;
+ Flow value = this->visit(curr->value);
+ if (value.breaking()) return value;
+ Flow size = this->visit(curr->size);
+ if (size.breaking()) return size;
+ NOTE_EVAL1(dest);
+ NOTE_EVAL1(value);
+ NOTE_EVAL1(size);
+ Address destVal(uint32_t(dest.value.geti32()));
+ Address sizeVal(uint32_t(size.value.geti32()));
+
+ instance.checkLoadAddress(destVal, 0);
+
+ uint8_t val(value.value.geti32());
+ for (size_t i = 0; i < sizeVal; ++i) {
+ instance.externalInterface->store8(
+ instance.getFinalAddress(Literal(uint32_t(destVal + i)), 1), val);
+ }
return {};
}
diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h
index 8aa203fa7..38fcdb990 100644
--- a/src/wasm-traversal.h
+++ b/src/wasm-traversal.h
@@ -657,9 +657,9 @@ struct PostWalker : public Walker<SubType, VisitorType> {
}
case Expression::Id::MemoryInitId: {
self->pushTask(SubType::doVisitMemoryInit, currp);
- self->pushTask(SubType::scan, &curr->cast<MemoryInit>()->dest);
- self->pushTask(SubType::scan, &curr->cast<MemoryInit>()->offset);
self->pushTask(SubType::scan, &curr->cast<MemoryInit>()->size);
+ self->pushTask(SubType::scan, &curr->cast<MemoryInit>()->offset);
+ self->pushTask(SubType::scan, &curr->cast<MemoryInit>()->dest);
break;
}
case Expression::Id::DataDropId: {
@@ -668,16 +668,16 @@ struct PostWalker : public Walker<SubType, VisitorType> {
}
case Expression::Id::MemoryCopyId: {
self->pushTask(SubType::doVisitMemoryCopy, currp);
- self->pushTask(SubType::scan, &curr->cast<MemoryCopy>()->dest);
- self->pushTask(SubType::scan, &curr->cast<MemoryCopy>()->source);
self->pushTask(SubType::scan, &curr->cast<MemoryCopy>()->size);
+ self->pushTask(SubType::scan, &curr->cast<MemoryCopy>()->source);
+ self->pushTask(SubType::scan, &curr->cast<MemoryCopy>()->dest);
break;
}
case Expression::Id::MemoryFillId: {
self->pushTask(SubType::doVisitMemoryFill, currp);
- self->pushTask(SubType::scan, &curr->cast<MemoryFill>()->dest);
- self->pushTask(SubType::scan, &curr->cast<MemoryFill>()->value);
self->pushTask(SubType::scan, &curr->cast<MemoryFill>()->size);
+ self->pushTask(SubType::scan, &curr->cast<MemoryFill>()->value);
+ self->pushTask(SubType::scan, &curr->cast<MemoryFill>()->dest);
break;
}
case Expression::Id::ConstId: {
diff --git a/src/wasm.h b/src/wasm.h
index f4180f7a0..83809243c 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -859,7 +859,6 @@ public:
struct Segment {
bool isPassive = false;
- Index index = 0;
Expression* offset = nullptr;
std::vector<char> data; // TODO: optimize
Segment() = default;
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index f3642203d..b8c3f1049 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -1540,7 +1540,10 @@ void WasmBinaryBuilder::readDataSegments() {
}
curr.isPassive = flags & BinaryConsts::IsPassive;
if (flags & BinaryConsts::HasMemIndex) {
- curr.index = getU32LEB();
+ auto memIndex = getU32LEB();
+ if (memIndex != 0) {
+ throwError("nonzero memory index");
+ }
}
if (!curr.isPassive) {
curr.offset = readExpression();