summaryrefslogtreecommitdiff
path: root/src/wasm-interpreter.h
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-08-16 12:53:52 -0700
committerGitHub <noreply@github.com>2024-08-16 12:53:52 -0700
commit958ff4115e542ef1d0ae712f4961e342386efe54 (patch)
tree7805d641d9a73b32650a053931c4bd8c3814d804 /src/wasm-interpreter.h
parent7209629bec3961fcc12b150ba6df546d3997b6c2 (diff)
downloadbinaryen-958ff4115e542ef1d0ae712f4961e342386efe54.tar.gz
binaryen-958ff4115e542ef1d0ae712f4961e342386efe54.tar.bz2
binaryen-958ff4115e542ef1d0ae712f4961e342386efe54.zip
Implement table.init (#6827)
Also use TableInit in the interpreter to initialize module's table state, which will now handle traps properly, fixing #6431
Diffstat (limited to 'src/wasm-interpreter.h')
-rw-r--r--src/wasm-interpreter.h95
1 files changed, 75 insertions, 20 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 7fd5b3cd3..644a141a2 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1417,6 +1417,7 @@ public:
Flow visitTableGrow(TableGrow* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitTableFill(TableFill* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitTableCopy(TableCopy* curr) { WASM_UNREACHABLE("unimp"); }
+ Flow visitTableInit(TableInit* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitTry(Try* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitTryTable(TryTable* curr) { WASM_UNREACHABLE("unimp"); }
Flow visitThrow(Throw* curr) {
@@ -2354,6 +2355,10 @@ public:
NOTE_ENTER("TableCopy");
return Flow(NONCONSTANT_FLOW);
}
+ Flow visitTableInit(TableInit* curr) {
+ NOTE_ENTER("TableInit");
+ return Flow(NONCONSTANT_FLOW);
+ }
Flow visitLoad(Load* curr) {
NOTE_ENTER("Load");
return Flow(NONCONSTANT_FLOW);
@@ -2821,23 +2826,24 @@ private:
}
}
+ Const zero;
+ zero.value = Literal(uint32_t(0));
+ zero.finalize();
+
ModuleUtils::iterActiveElementSegments(wasm, [&](ElementSegment* segment) {
- Address offset =
- (uint32_t)self()->visit(segment->offset).getSingleValue().geti32();
-
- Table* table = wasm.getTable(segment->table);
- ExternalInterface* extInterface = externalInterface;
- Name tableName = segment->table;
- if (table->imported()) {
- auto inst = linkedInstances.at(table->module);
- extInterface = inst->externalInterface;
- tableName = inst->wasm.getExport(table->base)->value;
- }
+ Const size;
+ size.value = Literal(uint32_t(segment->data.size()));
+ size.finalize();
- for (Index i = 0; i < segment->data.size(); ++i) {
- Flow ret = self()->visit(segment->data[i]);
- extInterface->tableStore(tableName, offset + i, ret.getSingleValue());
- }
+ TableInit init;
+ init.table = segment->table;
+ init.segment = segment->name;
+ init.dest = segment->offset;
+ init.offset = &zero;
+ init.size = &size;
+ init.finalize();
+
+ self()->visit(&init);
droppedElementSegments.insert(segment->name);
});
@@ -2865,9 +2871,10 @@ private:
void initializeMemoryContents() {
initializeMemorySizes();
- Const offset;
- offset.value = Literal(uint32_t(0));
- offset.finalize();
+
+ Const zero;
+ zero.value = Literal(uint32_t(0));
+ zero.finalize();
// apply active memory segments
for (size_t i = 0, e = wasm.dataSegments.size(); i < e; ++i) {
@@ -2883,7 +2890,7 @@ private:
init.memory = segment->memory;
init.segment = segment->name;
init.dest = segment->offset;
- init.offset = &offset;
+ init.offset = &zero;
init.size = &size;
init.finalize();
@@ -3251,6 +3258,54 @@ public:
return {};
}
+ Flow visitTableInit(TableInit* curr) {
+ NOTE_ENTER("TableInit");
+ Flow dest = self()->visit(curr->dest);
+ if (dest.breaking()) {
+ return dest;
+ }
+ Flow offset = self()->visit(curr->offset);
+ if (offset.breaking()) {
+ return offset;
+ }
+ Flow size = self()->visit(curr->size);
+ if (size.breaking()) {
+ return size;
+ }
+ NOTE_EVAL1(dest);
+ NOTE_EVAL1(offset);
+ NOTE_EVAL1(size);
+
+ auto* segment = wasm.getElementSegment(curr->segment);
+
+ Address destVal(dest.getSingleValue().getUnsigned());
+ Address offsetVal(uint32_t(offset.getSingleValue().geti32()));
+ Address sizeVal(uint32_t(size.getSingleValue().geti32()));
+
+ if (offsetVal + sizeVal > 0 &&
+ droppedElementSegments.count(curr->segment)) {
+ trap("out of bounds segment access in table.init");
+ }
+ if (offsetVal + sizeVal > segment->data.size()) {
+ trap("out of bounds segment access in table.init");
+ }
+ auto info = getTableInstanceInfo(curr->table);
+ auto tableSize = info.interface()->tableSize(info.name);
+ if (destVal + sizeVal > tableSize) {
+ trap("out of bounds table access in table.init");
+ }
+ for (size_t i = 0; i < sizeVal; ++i) {
+ // FIXME: We should not call visit() here more than once at runtime. The
+ // values in the segment should be computed once during startup,
+ // and then read here as needed. For example, if we had a
+ // struct.new here then we should not allocate a new struct each
+ // time we table.init that data.
+ auto value = self()->visit(segment->data[offsetVal + i]).getSingleValue();
+ info.interface()->tableStore(info.name, destVal + i, value);
+ }
+ return {};
+ }
+
Flow visitLocalGet(LocalGet* curr) {
NOTE_ENTER("LocalGet");
auto index = curr->index;
@@ -3741,7 +3796,7 @@ public:
if (offsetVal + sizeVal > 0 && droppedDataSegments.count(curr->segment)) {
trap("out of bounds segment access in memory.init");
}
- if ((uint64_t)offsetVal + sizeVal > segment->data.size()) {
+ if (offsetVal + sizeVal > segment->data.size()) {
trap("out of bounds segment access in memory.init");
}
auto info = getMemoryInstanceInfo(curr->memory);