Skip to content

Commit

Permalink
feat: const instruction global get
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 24, 2024
1 parent 4223bb7 commit c9ecfea
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 68 deletions.
56 changes: 38 additions & 18 deletions crates/tinywasm/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,17 +257,7 @@ impl Imports {

if let Some(addr) = self.modules.get(&name.module) {
let instance = store.get_module_instance(*addr)?;
let export_addr = instance.export(&import.name)?;

// TODO: validate kind and type
match &export_addr {
ExternVal::Global(_) => {}
ExternVal::Table(_) => {}
ExternVal::Mem(_) => {}
ExternVal::Func(_) => {}
}

return Some(ResolvedExtern::Store(export_addr));
return Some(ResolvedExtern::Store(instance.export(&import.name)?));
}

None
Expand Down Expand Up @@ -354,13 +344,43 @@ impl Imports {
.into());
}

// TODO: check if the type matches

match val {
ExternVal::Global(g) => imports.globals.push(g),
ExternVal::Table(t) => imports.tables.push(t),
ExternVal::Mem(m) => imports.memories.push(m),
ExternVal::Func(f) => imports.funcs.push(f),
match (val, &import.kind) {
(ExternVal::Global(global_addr), ImportKind::Global(ty)) => {
let global = store.get_global(global_addr as usize)?;
Self::compare_types(import, &global.borrow().ty, ty)?;
imports.globals.push(global_addr);
}
(ExternVal::Table(table_addr), ImportKind::Table(ty)) => {
let table = store.get_table(table_addr as usize)?;
// TODO: do we need to check any limits?
Self::compare_types(import, &table.borrow().kind.element_type, &ty.element_type)?;
imports.tables.push(table_addr);
}
(ExternVal::Mem(memory_addr), ImportKind::Memory(ty)) => {
let mem = store.get_mem(memory_addr as usize)?;
// TODO: do we need to check any limits?
Self::compare_types(import, &mem.borrow().kind.arch, &ty.arch)?;
imports.memories.push(memory_addr);
}
(ExternVal::Func(func_addr), ImportKind::Function(ty)) => {
let func = store.get_func(func_addr as usize)?;
let import_func_type = module.data.func_types.get(*ty as usize).ok_or_else(|| {
crate::LinkingError::IncompatibleImportType {
module: import.module.to_string(),
name: import.name.to_string(),
}
})?;

Self::compare_types(import, func.func.ty(), import_func_type)?;
imports.funcs.push(func_addr);
}
_ => {
return Err(crate::LinkingError::IncompatibleImportType {
module: import.module.to_string(),
name: import.name.to_string(),
}
.into());
}
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions crates/tinywasm/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,13 @@ impl ModuleInstance {
let data = module.data;

// TODO: check if the compiler correctly optimizes this to prevent wasted allocations
addrs.globals.extend(store.init_globals(data.globals.into(), idx)?);
addrs.funcs.extend(store.init_funcs(data.funcs.into(), idx)?);
addrs.tables.extend(store.init_tables(data.table_types.into(), idx)?);
addrs.memories.extend(store.init_memories(data.memory_types.into(), idx)?);

let (elem_addrs, elem_trapped) = store.init_elements(&addrs.tables, &addrs.funcs, data.elements.into(), idx)?;
let global_addrs = store.init_globals(addrs.globals, data.globals.into(), idx)?;
let (elem_addrs, elem_trapped) =
store.init_elements(&addrs.tables, &addrs.funcs, &global_addrs, data.elements.into(), idx)?;
let (data_addrs, data_trapped) = store.init_datas(&addrs.memories, data.data.into(), idx)?;

let instance = ModuleInstanceInner {
Expand All @@ -82,7 +83,7 @@ impl ModuleInstance {
func_addrs: addrs.funcs.into_boxed_slice(),
table_addrs: addrs.tables.into_boxed_slice(),
mem_addrs: addrs.memories.into_boxed_slice(),
global_addrs: addrs.globals.into_boxed_slice(),
global_addrs: global_addrs.into_boxed_slice(),
elem_addrs,
data_addrs,
func_start: data.start_func,
Expand Down
93 changes: 61 additions & 32 deletions crates/tinywasm/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,20 @@ impl Store {
}

/// Add globals to the store, returning their addresses in the store
pub(crate) fn init_globals(&mut self, globals: Vec<Global>, idx: ModuleInstanceAddr) -> Result<Vec<Addr>> {
pub(crate) fn init_globals(
&mut self,
mut imported_globals: Vec<GlobalAddr>,
new_globals: Vec<Global>,
idx: ModuleInstanceAddr,
) -> Result<Vec<Addr>> {
let global_count = self.data.globals.len();
let mut global_addrs = Vec::with_capacity(global_count);
for (i, global) in globals.iter().enumerate() {
imported_globals.reserve_exact(new_globals.len());
let mut global_addrs = imported_globals;

for (i, global) in new_globals.iter().enumerate() {
self.data.globals.push(Rc::new(RefCell::new(GlobalInstance::new(
global.ty,
self.eval_const(&global.init)?,
self.eval_const(&global.init, &global_addrs)?,
idx,
))));
global_addrs.push((i + global_count) as Addr);
Expand All @@ -173,27 +180,41 @@ impl Store {
Ok(global_addrs)
}

fn elem_addr(&self, item: &ElementItem, globals: &[Addr]) -> Result<Option<u32>> {
let res = match item {
ElementItem::Func(addr) => Some(*addr),
ElementItem::Expr(ConstInstruction::RefFunc(addr)) => Some(*addr),
ElementItem::Expr(ConstInstruction::RefNull(_ty)) => None,
ElementItem::Expr(ConstInstruction::GlobalGet(addr)) => {
let addr = globals.get(*addr as usize).copied().ok_or_else(|| {
Error::Other(format!("global {} not found. This should have been caught by the validator", addr))
})?;

let global = self.data.globals[addr as usize].clone();
let val = global.borrow().value;
Some(val.into())
}
_ => return Err(Error::UnsupportedFeature(format!("const expression other than ref: {:?}", item))),
};

Ok(res)
}

/// Add elements to the store, returning their addresses in the store
/// Should be called after the tables have been added
pub(crate) fn init_elements(
&mut self,
table_addrs: &[TableAddr],
func_addrs: &[FuncAddr],
global_addrs: &[Addr],
elements: Vec<Element>,
idx: ModuleInstanceAddr,
) -> Result<(Box<[Addr]>, Option<Trap>)> {
let elem_count = self.data.elements.len();
let mut elem_addrs = Vec::with_capacity(elem_count);
for (i, element) in elements.into_iter().enumerate() {
let init = element
.items
.iter()
.map(|item| {
item.addr().ok_or_else(|| {
Error::UnsupportedFeature(format!("const expression other than ref: {:?}", item))
})
})
.collect::<Result<Vec<_>>>()?;
let init =
element.items.iter().map(|item| self.elem_addr(item, global_addrs)).collect::<Result<Vec<_>>>()?;

log::error!("element kind: {:?}", element.kind);

Expand Down Expand Up @@ -330,16 +351,23 @@ impl Store {
}

/// Evaluate a constant expression
pub(crate) fn eval_const(&self, const_instr: &tinywasm_types::ConstInstruction) -> Result<RawWasmValue> {
pub(crate) fn eval_const(
&self,
const_instr: &tinywasm_types::ConstInstruction,
module_global_addrs: &[Addr],
) -> Result<RawWasmValue> {
use tinywasm_types::ConstInstruction::*;
let val = match const_instr {
F32Const(f) => RawWasmValue::from(*f),
F64Const(f) => RawWasmValue::from(*f),
I32Const(i) => RawWasmValue::from(*i),
I64Const(i) => RawWasmValue::from(*i),
GlobalGet(addr) => {
let addr = *addr as usize;
let global = self.data.globals[addr].clone();
let addr = module_global_addrs.get(*addr as usize).copied().ok_or_else(|| {
Error::Other(format!("global {} not found. This should have been caught by the validator", addr))
})?;

let global = self.data.globals[addr as usize].clone();
let val = global.borrow().value;
val
}
Expand Down Expand Up @@ -369,8 +397,16 @@ impl Store {
self.data.elements.get(addr).ok_or_else(|| Error::Other(format!("element {} not found", addr)))
}

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

/// Get the global at the actual index in the store
pub fn get_global_val(&self, addr: usize) -> Result<RawWasmValue> {
log::error!("getting global: {}", addr);
log::error!("globals: {:?}", self.data.globals);

self.data
.globals
.get(addr)
Expand Down Expand Up @@ -461,25 +497,18 @@ impl TableInstance {
}

pub(crate) fn set(&mut self, table_idx: usize, value: Addr) -> Result<()> {
self.grow_to_fit(table_idx + 1)
.ok_or_else(|| {
Error::Trap(crate::Trap::TableOutOfBounds { offset: table_idx, len: 1, max: self.elements.len() })
})
.and_then(|_| {
self.elements[table_idx] = TableElement::Initialized(value);
Ok(())
})
self.grow_to_fit(table_idx + 1).map(|_| self.elements[table_idx] = TableElement::Initialized(value))
}

pub(crate) fn grow_to_fit(&mut self, new_size: usize) -> Option<()> {
pub(crate) fn grow_to_fit(&mut self, new_size: usize) -> Result<()> {
if new_size > self.elements.len() {
if new_size <= self.kind.size_max.unwrap_or(MAX_TABLE_SIZE) as usize {
self.elements.resize(new_size, TableElement::Uninitialized);
} else {
return None;
if new_size > self.kind.size_max.unwrap_or(MAX_TABLE_SIZE) as usize {
return Err(crate::Trap::TableOutOfBounds { offset: new_size, len: 1, max: self.elements.len() }.into());
}

self.elements.resize(new_size, TableElement::Uninitialized);
}
Some(())
Ok(())
}

pub(crate) fn size(&self) -> i32 {
Expand Down Expand Up @@ -620,13 +649,13 @@ impl MemoryInstance {
#[derive(Debug)]
pub(crate) struct GlobalInstance {
pub(crate) value: RawWasmValue,
pub(crate) _ty: GlobalType,
pub(crate) ty: GlobalType,
pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances
}

impl GlobalInstance {
pub(crate) fn new(ty: GlobalType, value: RawWasmValue, owner: ModuleInstanceAddr) -> Self {
Self { _ty: ty, value, _owner: owner }
Self { ty, value, _owner: owner }
}
}

Expand Down
Loading

0 comments on commit c9ecfea

Please sign in to comment.