diff options
author | Alon Zakai <azakai@google.com> | 2024-08-16 12:53:52 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-16 12:53:52 -0700 |
commit | 958ff4115e542ef1d0ae712f4961e342386efe54 (patch) | |
tree | 7805d641d9a73b32650a053931c4bd8c3814d804 /src/wasm-interpreter.h | |
parent | 7209629bec3961fcc12b150ba6df546d3997b6c2 (diff) | |
download | binaryen-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.h | 95 |
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); |