Skip to content
This repository was archived by the owner on Oct 3, 2025. It is now read-only.

Commit 275b13f

Browse files
wip: better bulk memory support
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
1 parent 1cca6de commit 275b13f

File tree

8 files changed

+91
-10
lines changed

8 files changed

+91
-10
lines changed

benchmarks/benches/argon2id.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ fn criterion_benchmark(c: &mut Criterion) {
4343
group.measurement_time(std::time::Duration::from_secs(7));
4444
group.sample_size(10);
4545

46-
group.bench_function("native", |b| b.iter(|| run_native(black_box(params))));
46+
// group.bench_function("native", |b| b.iter(|| run_native(black_box(params))));
4747
group.bench_function("tinywasm", |b| b.iter(|| run_tinywasm(ARGON2ID, black_box(params), "argon2id")));
48-
group.bench_function("wasmi", |b| b.iter(|| run_wasmi(ARGON2ID, black_box(params), "argon2id")));
49-
group.bench_function("wasmer", |b| b.iter(|| run_wasmer(ARGON2ID, black_box(params), "argon2id")));
48+
// group.bench_function("wasmi", |b| b.iter(|| run_wasmi(ARGON2ID, black_box(params), "argon2id")));
49+
// group.bench_function("wasmer", |b| b.iter(|| run_wasmer(ARGON2ID, black_box(params), "argon2id")));
5050
}
5151

5252
criterion_group!(

crates/parser/src/visit.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -534,12 +534,8 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder {
534534
}
535535
define_primitive_operands! {
536536
visit_memory_fill, Instruction::MemoryFill, u32,
537-
visit_data_drop, Instruction::DataDrop, u32
538-
}
539-
540-
#[inline(always)]
541-
fn visit_elem_drop(&mut self, _elem_index: u32) -> Self::Output {
542-
self.unsupported("elem_drop")
537+
visit_data_drop, Instruction::DataDrop, u32,
538+
visit_elem_drop, Instruction::ElemDrop, u32
543539
}
544540

545541
#[inline(always)]

crates/tinywasm/src/runtime/interpreter/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ impl<'store, 'stack> Executor<'store, 'stack> {
102102
MemoryFill(addr) => self.exec_memory_fill(*addr)?,
103103
MemoryInit(data_idx, mem_idx) => self.exec_memory_init(*data_idx, *mem_idx)?,
104104
DataDrop(data_index) => self.exec_data_drop(*data_index)?,
105+
ElemDrop(elem_index) => self.exec_elem_drop(*elem_index)?,
106+
TableCopy { from, to } => self.exec_table_copy(*from, *to)?,
105107

106108
I32Store { mem_addr, offset } => mem_store!(i32, (mem_addr, offset), self),
107109
I64Store { mem_addr, offset } => mem_store!(i64, (mem_addr, offset), self),
@@ -609,6 +611,31 @@ impl<'store, 'stack> Executor<'store, 'stack> {
609611
Ok(())
610612
}
611613

614+
#[inline(always)]
615+
fn exec_elem_drop(&mut self, elem_index: u32) -> Result<()> {
616+
self.store.get_elem_mut(self.module.resolve_elem_addr(elem_index))?.drop();
617+
Ok(())
618+
}
619+
620+
#[inline(always)]
621+
fn exec_table_copy(&mut self, from: u32, to: u32) -> Result<()> {
622+
let size: i32 = self.stack.values.pop()?.into();
623+
let src: i32 = self.stack.values.pop()?.into();
624+
let dst: i32 = self.stack.values.pop()?.into();
625+
626+
if from == to {
627+
let mut table_from = self.store.get_table(self.module.resolve_table_addr(from))?.borrow_mut();
628+
// copy within the same memory
629+
table_from.copy_within(dst as usize, src as usize, size as usize)?;
630+
} else {
631+
// copy between two memories
632+
let table_from = self.store.get_table(self.module.resolve_table_addr(from))?.borrow();
633+
let mut table_to = self.store.get_table(self.module.resolve_table_addr(to))?.borrow_mut();
634+
table_to.copy_from_slice(dst as usize, table_from.load(src as usize, size as usize)?)?;
635+
}
636+
Ok(())
637+
}
638+
612639
#[inline(always)]
613640
fn exec_call(&mut self, v: u32) -> Result<ExecResult> {
614641
let func_inst = self.store.get_func(self.module.resolve_func_addr(v))?;

crates/tinywasm/src/store/element.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,8 @@ impl ElementInstance {
1616
pub(crate) fn new(kind: ElementKind, owner: ModuleInstanceAddr, items: Option<Vec<TableElement>>) -> Self {
1717
Self { kind, _owner: owner, items }
1818
}
19+
20+
pub(crate) fn drop(&mut self) {
21+
self.items.is_some().then(|| self.items.take());
22+
}
1923
}

crates/tinywasm/src/store/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ impl Store {
147147
self.data.elements.get(addr as usize).ok_or_else(|| Self::not_found_error("element"))
148148
}
149149

150+
/// Get the element at the actual index in the store
151+
#[inline]
152+
pub(crate) fn get_elem_mut(&mut self, addr: ElemAddr) -> Result<&mut ElementInstance> {
153+
self.data.elements.get_mut(addr as usize).ok_or_else(|| Self::not_found_error("element"))
154+
}
155+
150156
/// Get the global at the actual index in the store
151157
#[inline]
152158
pub(crate) fn get_global(&self, addr: GlobalAddr) -> Result<&GlobalInstance> {

crates/tinywasm/src/store/table.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ impl TableInstance {
2020
Self { elements: vec![TableElement::Uninitialized; kind.size_initial as usize], kind, _owner: owner }
2121
}
2222

23+
#[inline(never)]
24+
#[cold]
25+
fn trap_oob(&self, addr: usize, len: usize) -> Error {
26+
Error::Trap(crate::Trap::TableOutOfBounds { offset: addr, len, max: self.elements.len() })
27+
}
28+
2329
pub(crate) fn get_wasm_val(&self, addr: TableAddr) -> Result<WasmValue> {
2430
let val = self.get(addr)?.addr();
2531

@@ -34,6 +40,47 @@ impl TableInstance {
3440
self.elements.get(addr as usize).ok_or_else(|| Error::Trap(Trap::UndefinedElement { index: addr as usize }))
3541
}
3642

43+
pub(crate) fn copy_from_slice(&mut self, dst: usize, src: &[TableElement]) -> Result<()> {
44+
let end = dst.checked_add(src.len()).ok_or_else(|| self.trap_oob(dst, src.len()))?;
45+
46+
if end > self.elements.len() {
47+
return Err(self.trap_oob(dst, src.len()));
48+
}
49+
50+
self.elements[dst..end].copy_from_slice(src);
51+
Ok(())
52+
}
53+
54+
pub(crate) fn load(&self, addr: usize, len: usize) -> Result<&[TableElement]> {
55+
let Some(end) = addr.checked_add(len) else {
56+
return Err(self.trap_oob(addr, len));
57+
};
58+
59+
if end > self.elements.len() || end < addr {
60+
return Err(self.trap_oob(addr, len));
61+
}
62+
63+
Ok(&self.elements[addr..end])
64+
}
65+
66+
pub(crate) fn copy_within(&mut self, dst: usize, src: usize, len: usize) -> Result<()> {
67+
// Calculate the end of the source slice
68+
let src_end = src.checked_add(len).ok_or_else(|| self.trap_oob(src, len))?;
69+
if src_end > self.elements.len() {
70+
return Err(self.trap_oob(src, len));
71+
}
72+
73+
// Calculate the end of the destination slice
74+
let dst_end = dst.checked_add(len).ok_or_else(|| self.trap_oob(dst, len))?;
75+
if dst_end > self.elements.len() {
76+
return Err(self.trap_oob(dst, len));
77+
}
78+
79+
// Perform the copy
80+
self.elements.copy_within(src..src_end, dst);
81+
Ok(())
82+
}
83+
3784
pub(crate) fn set(&mut self, table_idx: TableAddr, value: Addr) -> Result<()> {
3885
self.grow_to_fit(table_idx as usize + 1)
3986
.map(|_| self.elements[table_idx as usize] = TableElement::Initialized(value))

crates/tinywasm/tests/generated/2.0.csv

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

crates/types/src/instructions.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ pub enum Instruction {
211211
MemoryCopy(MemAddr, MemAddr),
212212
MemoryFill(MemAddr),
213213
DataDrop(DataAddr),
214+
ElemDrop(ElemAddr),
214215
}
215216

216217
#[cfg(test)]

0 commit comments

Comments
 (0)