summaryrefslogtreecommitdiff
path: root/src/wasm-interpreter.h
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/wasm-interpreter.h
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/wasm-interpreter.h')
-rw-r--r--src/wasm-interpreter.h89
1 files changed, 72 insertions, 17 deletions
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 {};
}