summaryrefslogtreecommitdiff
path: root/src/wasm-interpreter.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm-interpreter.h')
-rw-r--r--src/wasm-interpreter.h56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 8eb52e634..3599def90 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1392,6 +1392,7 @@ public:
Flow visitTableSize(TableSize* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitTableGrow(TableGrow* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitTableFill(TableFill* curr) { WASM_UNREACHABLE("unimp"); }
+ Flow visitTableCopy(TableCopy* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitTry(Try* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitThrow(Throw* curr) {
NOTE_ENTER("Throw");
@@ -2210,6 +2211,10 @@ public:
NOTE_ENTER("TableFill");
return Flow(NONCONSTANT_FLOW);
}
+ Flow visitTableCopy(TableCopy* curr) {
+ NOTE_ENTER("TableCopy");
+ return Flow(NONCONSTANT_FLOW);
+ }
Flow visitLoad(Load* curr) {
NOTE_ENTER("Load");
return Flow(NONCONSTANT_FLOW);
@@ -3027,6 +3032,57 @@ public:
return Flow();
}
+ Flow visitTableCopy(TableCopy* curr) {
+ NOTE_ENTER("TableCopy");
+ Flow dest = self()->visit(curr->dest);
+ if (dest.breaking()) {
+ return dest;
+ }
+ Flow source = self()->visit(curr->source);
+ if (source.breaking()) {
+ return source;
+ }
+ Flow size = self()->visit(curr->size);
+ if (size.breaking()) {
+ return size;
+ }
+ NOTE_EVAL1(dest);
+ NOTE_EVAL1(source);
+ NOTE_EVAL1(size);
+ Address destVal(dest.getSingleValue().getUnsigned());
+ Address sourceVal(source.getSingleValue().getUnsigned());
+ Address sizeVal(size.getSingleValue().getUnsigned());
+
+ auto destInfo = getTableInterfaceInfo(curr->destTable);
+ auto sourceInfo = getTableInterfaceInfo(curr->sourceTable);
+ auto destTableSize = destInfo.interface->tableSize(destInfo.name);
+ auto sourceTableSize = sourceInfo.interface->tableSize(sourceInfo.name);
+ if (sourceVal + sizeVal > sourceTableSize ||
+ destVal + sizeVal > destTableSize ||
+ // FIXME: better/cheaper way to detect wrapping?
+ sourceVal + sizeVal < sourceVal || sourceVal + sizeVal < sizeVal ||
+ destVal + sizeVal < destVal || destVal + sizeVal < sizeVal) {
+ trap("out of bounds segment access in table.copy");
+ }
+
+ int64_t start = 0;
+ int64_t end = sizeVal;
+ int step = 1;
+ // Reverse direction if source is below dest
+ if (sourceVal < destVal) {
+ start = int64_t(sizeVal) - 1;
+ end = -1;
+ step = -1;
+ }
+ for (int64_t i = start; i != end; i += step) {
+ destInfo.interface->tableStore(
+ destInfo.name,
+ destVal + i,
+ sourceInfo.interface->tableLoad(sourceInfo.name, sourceVal + i));
+ }
+ return {};
+ }
+
Flow visitLocalGet(LocalGet* curr) {
NOTE_ENTER("LocalGet");
auto index = curr->index;