Skip to content

Commit

Permalink
feat: basic memory ops
Browse files Browse the repository at this point in the history
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
  • Loading branch information
explodingcamera committed Jan 6, 2024
1 parent 54c1b75 commit 7d93300
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 17 deletions.
12 changes: 11 additions & 1 deletion crates/tinywasm/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl ModuleInstance {

let func_addrs = store.add_funcs(module.data.funcs.into(), idx);
let table_addrs = store.add_tables(module.data.table_types.into(), idx);
let mem_addrs = store.add_mems(module.data.memory_types.into(), idx);
let mem_addrs = store.add_mems(module.data.memory_types.into(), idx)?;

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

// resolve a table address to the global store address
pub(crate) fn resolve_table_addr(&self, addr: TableAddr) -> TableAddr {
self.0.table_addrs[addr as usize]
}

// resolve a memory address to the global store address
pub(crate) fn resolve_mem_addr(&self, addr: MemAddr) -> MemAddr {
self.0.mem_addrs[addr as usize]
}

// resolve a global address to the global store address
pub(crate) fn resolve_global_addr(&self, addr: GlobalAddr) -> GlobalAddr {
self.0.global_addrs[addr as usize]
Expand Down
37 changes: 34 additions & 3 deletions crates/tinywasm/src/runtime/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use crate::{
get_label_args,
log::debug,
runtime::{BlockType, LabelFrame},
CallFrame, Error, ModuleInstance, RawWasmValue, Result, Store,
CallFrame, Error, ModuleInstance, Result, Store,
};
use alloc::vec::Vec;
use alloc::{format, vec::Vec};
use log::info;
use tinywasm_types::{ConstInstruction, Instruction};
use tinywasm_types::Instruction;

mod macros;
mod traits;
Expand Down Expand Up @@ -272,6 +272,37 @@ fn exec_one(
F32Const(val) => stack.values.push((*val).into()),
F64Const(val) => stack.values.push((*val).into()),

MemorySize(addr, byte) => {
if *byte != 0 {
unimplemented!("memory.size with byte != 0");
}

let mem_idx = module.resolve_mem_addr(*addr);
let mem = store.get_mem(mem_idx as usize)?;
stack.values.push(mem.borrow().size().into());
}

MemoryGrow(addr, byte) => {
if *byte != 0 {
unimplemented!("memory.grow with byte != 0");
}

let mem_idx = module.resolve_mem_addr(*addr);
let mem = store.get_mem(mem_idx as usize)?;

let (res, prev_size) = {
let mut mem = mem.borrow_mut();
let prev_size = mem.size();
let new_size = prev_size + stack.values.pop_t::<i32>()?;
(mem.grow(new_size), prev_size)
};

match res {
Ok(_) => stack.values.push(prev_size.into()),
Err(_) => stack.values.push((-1).into()),
}
}

I64Eqz => comp_zero!(==, i64, stack),
I32Eqz => comp_zero!(==, i32, stack),

Expand Down
58 changes: 50 additions & 8 deletions crates/tinywasm/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use core::{
sync::atomic::{AtomicUsize, Ordering},
};

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

use crate::{
Expand Down Expand Up @@ -84,7 +84,7 @@ impl Default for Store {
pub(crate) struct StoreData {
pub(crate) funcs: Vec<Rc<FunctionInstance>>,
pub(crate) tables: Vec<TableInstance>,
pub(crate) mems: Vec<Rc<MemoryInstance>>,
pub(crate) mems: Vec<Rc<RefCell<MemoryInstance>>>,
pub(crate) globals: Vec<Rc<RefCell<GlobalInstance>>>,
pub(crate) elems: Vec<ElemInstance>,
pub(crate) datas: Vec<DataInstance>,
Expand Down Expand Up @@ -130,14 +130,20 @@ impl Store {
}

/// Add memories to the store, returning their addresses in the store
pub(crate) fn add_mems(&mut self, mems: Vec<MemoryType>, idx: ModuleInstanceAddr) -> Vec<MemAddr> {
pub(crate) fn add_mems(&mut self, mems: Vec<MemoryType>, idx: ModuleInstanceAddr) -> Result<Vec<MemAddr>> {
let mem_count = self.data.mems.len();
let mut mem_addrs = Vec::with_capacity(mem_count);
for (i, mem) in mems.into_iter().enumerate() {
self.data.mems.push(Rc::new(MemoryInstance::new(mem, idx)));
if let MemoryArch::I64 = mem.arch {
return Err(Error::UnsupportedFeature("64-bit memories".to_string()));
}
self.data
.mems
.push(Rc::new(RefCell::new(MemoryInstance::new(mem, idx))));

mem_addrs.push((i + mem_count) as MemAddr);
}
mem_addrs
Ok(mem_addrs)
}

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

/// Get the memory at the actual index in the store
pub(crate) fn get_mem(&self, addr: usize) -> Result<&Rc<RefCell<MemoryInstance>>> {
self.data
.mems
.get(addr)
.ok_or_else(|| Error::Other(format!("memory {} not found", addr)))
}

/// Get the global at the actual index in the store
pub(crate) fn get_global_val(&self, addr: usize) -> Result<RawWasmValue> {
self.data
.globals
Expand Down Expand Up @@ -300,24 +315,51 @@ impl TableInstance {
}
}

pub(crate) const PAGE_SIZE: usize = 64_000;
pub(crate) const MAX_PAGES: usize = 65536;
pub(crate) const MAX_SIZE: usize = PAGE_SIZE * MAX_PAGES;

/// A WebAssembly Memory Instance
///
/// See <https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances>
#[derive(Debug)]
pub(crate) struct MemoryInstance {
pub(crate) kind: MemoryType,
pub(crate) data: Vec<u8>,
pub(crate) page_count: usize,
pub(crate) owner: ModuleInstanceAddr, // index into store.module_instances
}

impl MemoryInstance {
pub(crate) fn new(kind: MemoryType, owner: ModuleInstanceAddr) -> Self {
debug_assert!(kind.page_count_initial <= kind.page_count_max.unwrap_or(MAX_PAGES as u64));

Self {
kind,
data: Vec::new(),
data: vec![0; PAGE_SIZE * kind.page_count_initial as usize],
page_count: kind.page_count_initial as usize,
owner,
}
}

pub(crate) fn size(&self) -> i32 {
self.page_count as i32
}

pub(crate) fn grow(&mut self, delta: i32) -> Result<i32> {
let current_pages = self.size();
let new_pages = current_pages + delta;
if new_pages < 0 || new_pages > MAX_PAGES as i32 {
return Err(Error::Other(format!("memory size out of bounds: {}", new_pages)));
}
let new_size = new_pages as usize * PAGE_SIZE;
if new_size > MAX_SIZE {
return Err(Error::Other(format!("memory size out of bounds: {}", new_size)));
}
self.data.resize(new_size, 0);
self.page_count = new_pages as usize;
Ok(current_pages)
}
}

/// A WebAssembly Global Instance
Expand Down
Loading

0 comments on commit 7d93300

Please sign in to comment.