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

Commit 7d93300

Browse files
feat: basic memory ops
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
1 parent 54c1b75 commit 7d93300

File tree

5 files changed

+100
-17
lines changed

5 files changed

+100
-17
lines changed

crates/tinywasm/src/instance.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl ModuleInstance {
4242

4343
let func_addrs = store.add_funcs(module.data.funcs.into(), idx);
4444
let table_addrs = store.add_tables(module.data.table_types.into(), idx);
45-
let mem_addrs = store.add_mems(module.data.memory_types.into(), idx);
45+
let mem_addrs = store.add_mems(module.data.memory_types.into(), idx)?;
4646

4747
let global_addrs = store.add_globals(module.data.globals.into(), &module.data.imports, &imports, idx)?;
4848
let elem_addrs = store.add_elems(module.data.elements.into(), idx);
@@ -99,6 +99,16 @@ impl ModuleInstance {
9999
self.0.func_addrs[addr as usize]
100100
}
101101

102+
// resolve a table address to the global store address
103+
pub(crate) fn resolve_table_addr(&self, addr: TableAddr) -> TableAddr {
104+
self.0.table_addrs[addr as usize]
105+
}
106+
107+
// resolve a memory address to the global store address
108+
pub(crate) fn resolve_mem_addr(&self, addr: MemAddr) -> MemAddr {
109+
self.0.mem_addrs[addr as usize]
110+
}
111+
102112
// resolve a global address to the global store address
103113
pub(crate) fn resolve_global_addr(&self, addr: GlobalAddr) -> GlobalAddr {
104114
self.0.global_addrs[addr as usize]

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

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ use crate::{
55
get_label_args,
66
log::debug,
77
runtime::{BlockType, LabelFrame},
8-
CallFrame, Error, ModuleInstance, RawWasmValue, Result, Store,
8+
CallFrame, Error, ModuleInstance, Result, Store,
99
};
10-
use alloc::vec::Vec;
10+
use alloc::{format, vec::Vec};
1111
use log::info;
12-
use tinywasm_types::{ConstInstruction, Instruction};
12+
use tinywasm_types::Instruction;
1313

1414
mod macros;
1515
mod traits;
@@ -272,6 +272,37 @@ fn exec_one(
272272
F32Const(val) => stack.values.push((*val).into()),
273273
F64Const(val) => stack.values.push((*val).into()),
274274

275+
MemorySize(addr, byte) => {
276+
if *byte != 0 {
277+
unimplemented!("memory.size with byte != 0");
278+
}
279+
280+
let mem_idx = module.resolve_mem_addr(*addr);
281+
let mem = store.get_mem(mem_idx as usize)?;
282+
stack.values.push(mem.borrow().size().into());
283+
}
284+
285+
MemoryGrow(addr, byte) => {
286+
if *byte != 0 {
287+
unimplemented!("memory.grow with byte != 0");
288+
}
289+
290+
let mem_idx = module.resolve_mem_addr(*addr);
291+
let mem = store.get_mem(mem_idx as usize)?;
292+
293+
let (res, prev_size) = {
294+
let mut mem = mem.borrow_mut();
295+
let prev_size = mem.size();
296+
let new_size = prev_size + stack.values.pop_t::<i32>()?;
297+
(mem.grow(new_size), prev_size)
298+
};
299+
300+
match res {
301+
Ok(_) => stack.values.push(prev_size.into()),
302+
Err(_) => stack.values.push((-1).into()),
303+
}
304+
}
305+
275306
I64Eqz => comp_zero!(==, i64, stack),
276307
I32Eqz => comp_zero!(==, i32, stack),
277308

crates/tinywasm/src/store.rs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ use core::{
33
sync::atomic::{AtomicUsize, Ordering},
44
};
55

6-
use alloc::{format, rc::Rc, vec::Vec};
6+
use alloc::{format, rc::Rc, string::ToString, vec, vec::Vec};
77
use tinywasm_types::{
8-
Addr, Data, Element, ElementKind, FuncAddr, Function, Global, GlobalType, Import, Instruction, MemAddr, MemoryType,
9-
ModuleInstanceAddr, TableAddr, TableType, TypeAddr, ValType,
8+
Addr, Data, Element, ElementKind, FuncAddr, Function, Global, GlobalType, Import, Instruction, MemAddr, MemoryArch,
9+
MemoryType, ModuleInstanceAddr, TableAddr, TableType, TypeAddr, ValType,
1010
};
1111

1212
use crate::{
@@ -84,7 +84,7 @@ impl Default for Store {
8484
pub(crate) struct StoreData {
8585
pub(crate) funcs: Vec<Rc<FunctionInstance>>,
8686
pub(crate) tables: Vec<TableInstance>,
87-
pub(crate) mems: Vec<Rc<MemoryInstance>>,
87+
pub(crate) mems: Vec<Rc<RefCell<MemoryInstance>>>,
8888
pub(crate) globals: Vec<Rc<RefCell<GlobalInstance>>>,
8989
pub(crate) elems: Vec<ElemInstance>,
9090
pub(crate) datas: Vec<DataInstance>,
@@ -130,14 +130,20 @@ impl Store {
130130
}
131131

132132
/// Add memories to the store, returning their addresses in the store
133-
pub(crate) fn add_mems(&mut self, mems: Vec<MemoryType>, idx: ModuleInstanceAddr) -> Vec<MemAddr> {
133+
pub(crate) fn add_mems(&mut self, mems: Vec<MemoryType>, idx: ModuleInstanceAddr) -> Result<Vec<MemAddr>> {
134134
let mem_count = self.data.mems.len();
135135
let mut mem_addrs = Vec::with_capacity(mem_count);
136136
for (i, mem) in mems.into_iter().enumerate() {
137-
self.data.mems.push(Rc::new(MemoryInstance::new(mem, idx)));
137+
if let MemoryArch::I64 = mem.arch {
138+
return Err(Error::UnsupportedFeature("64-bit memories".to_string()));
139+
}
140+
self.data
141+
.mems
142+
.push(Rc::new(RefCell::new(MemoryInstance::new(mem, idx))));
143+
138144
mem_addrs.push((i + mem_count) as MemAddr);
139145
}
140-
mem_addrs
146+
Ok(mem_addrs)
141147
}
142148

143149
/// Add globals to the store, returning their addresses in the store
@@ -236,6 +242,15 @@ impl Store {
236242
.ok_or_else(|| Error::Other(format!("function {} not found", addr)))
237243
}
238244

245+
/// Get the memory at the actual index in the store
246+
pub(crate) fn get_mem(&self, addr: usize) -> Result<&Rc<RefCell<MemoryInstance>>> {
247+
self.data
248+
.mems
249+
.get(addr)
250+
.ok_or_else(|| Error::Other(format!("memory {} not found", addr)))
251+
}
252+
253+
/// Get the global at the actual index in the store
239254
pub(crate) fn get_global_val(&self, addr: usize) -> Result<RawWasmValue> {
240255
self.data
241256
.globals
@@ -300,24 +315,51 @@ impl TableInstance {
300315
}
301316
}
302317

318+
pub(crate) const PAGE_SIZE: usize = 64_000;
319+
pub(crate) const MAX_PAGES: usize = 65536;
320+
pub(crate) const MAX_SIZE: usize = PAGE_SIZE * MAX_PAGES;
321+
303322
/// A WebAssembly Memory Instance
304323
///
305324
/// See <https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances>
306325
#[derive(Debug)]
307326
pub(crate) struct MemoryInstance {
308327
pub(crate) kind: MemoryType,
309328
pub(crate) data: Vec<u8>,
329+
pub(crate) page_count: usize,
310330
pub(crate) owner: ModuleInstanceAddr, // index into store.module_instances
311331
}
312332

313333
impl MemoryInstance {
314334
pub(crate) fn new(kind: MemoryType, owner: ModuleInstanceAddr) -> Self {
335+
debug_assert!(kind.page_count_initial <= kind.page_count_max.unwrap_or(MAX_PAGES as u64));
336+
315337
Self {
316338
kind,
317-
data: Vec::new(),
339+
data: vec![0; PAGE_SIZE * kind.page_count_initial as usize],
340+
page_count: kind.page_count_initial as usize,
318341
owner,
319342
}
320343
}
344+
345+
pub(crate) fn size(&self) -> i32 {
346+
self.page_count as i32
347+
}
348+
349+
pub(crate) fn grow(&mut self, delta: i32) -> Result<i32> {
350+
let current_pages = self.size();
351+
let new_pages = current_pages + delta;
352+
if new_pages < 0 || new_pages > MAX_PAGES as i32 {
353+
return Err(Error::Other(format!("memory size out of bounds: {}", new_pages)));
354+
}
355+
let new_size = new_pages as usize * PAGE_SIZE;
356+
if new_size > MAX_SIZE {
357+
return Err(Error::Other(format!("memory size out of bounds: {}", new_size)));
358+
}
359+
self.data.resize(new_size, 0);
360+
self.page_count = new_pages as usize;
361+
Ok(current_pages)
362+
}
321363
}
322364

323365
/// A WebAssembly Global Instance

0 commit comments

Comments
 (0)