wasper 0.1.3

A Webassembly interpreter written in Rust without standard library
Documentation
use super::memory::{data_active, data_passiv};
use super::runtime::{eval_const, Addr, Runtime, RuntimeError, PAGE_SIZE};
use super::table::{elem_active, elem_passiv};
use super::value::{Ref, Value};
use crate::binary::FuncType;
use crate::binary::ValType;
use crate::binary::{Data, DataMode, Elem, Limits, Memory, Table};
use crate::binary::{ElemMode, RefType};
use crate::binary::{Global, GlobalType};
#[cfg(not(feature = "std"))]
use crate::lib::*;
use core::fmt::Debug;
use opt_vec::OptVec;

#[derive(Debug, PartialEq, Clone)]
pub enum FuncInst {
    InnerFunc {
        instance_addr: Addr,
        start: usize,
        functype: FuncType,
        locals: Vec<ValType>,
    },
    HostFunc {
        functype: FuncType,
        name: String,
    },
}

impl FuncInst {
    pub fn functype(&self) -> &FuncType {
        match self {
            FuncInst::InnerFunc { functype, .. } | FuncInst::HostFunc { functype, .. } => functype,
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub struct GlobalInst {
    pub globaltype: GlobalType,
    pub value: Value,
}

#[derive(Debug, PartialEq, Clone)]
pub struct TableInst {
    pub tabletype: Table,
    pub elem: Vec<Ref>,
}

#[derive(Debug, PartialEq, Clone)]
pub struct ElemInst {
    pub reftype: RefType,
    pub elem: Vec<Ref>,
}

#[derive(Debug, PartialEq, Clone)]
pub struct MemInst {
    pub limits: Limits,
    pub data: Vec<u8>,
}

#[derive(Debug, PartialEq, Clone)]
pub struct DataInst {
    pub data: Vec<u8>,
}

#[derive(Debug, PartialEq, Clone)]
pub struct Store {
    pub globals: OptVec<GlobalInst>,
    pub tables: OptVec<TableInst>,
    pub mems: OptVec<MemInst>,
    pub funcs: OptVec<FuncInst>,
    pub elems: OptVec<ElemInst>,
    pub datas: OptVec<DataInst>,
}

impl Store {
    pub fn new() -> Self {
        Self {
            funcs: OptVec::new(),
            globals: OptVec::new(),
            tables: OptVec::new(),
            mems: OptVec::new(),
            elems: OptVec::new(),
            datas: OptVec::new(),
        }
    }

    pub fn update_func_inst(&mut self, funcaddrs: &Vec<Addr>, instance_addr: Addr) {
        for &funcaddr in funcaddrs {
            match &mut self.funcs[funcaddr as usize] {
                FuncInst::InnerFunc {
                    instance_addr: addr,
                    ..
                } => {
                    *addr = instance_addr;
                }
                _ => {}
            }
        }
    }

    pub fn allocate_global(&mut self, global: Global) -> Result<Addr, RuntimeError> {
        Ok(self.globals.push(GlobalInst {
            globaltype: global.type_,
            value: eval_const(&global.value)?,
        }))
    }

    pub fn allocate_table(&mut self, table: Table) -> Addr {
        let min = table.limits.min() as usize;
        self.tables.push(TableInst {
            tabletype: table,
            elem: vec![Ref::Null; min],
        })
    }

    pub fn allocate_elem(&mut self, elem: Elem) -> Result<Option<Addr>, RuntimeError> {
        match &elem.mode {
            ElemMode::Passiv => Ok(Some(elem_passiv(&mut self.elems, elem)?)),
            ElemMode::Active { tableidx, offset } => {
                let offset = match eval_const(&offset)? {
                    Value::I32(v) => v,
                    _ => unreachable!(),
                } as usize;
                elem_active(&mut self.tables[*tableidx as usize], offset, elem)?;
                Ok(None)
            }
            ElemMode::Declarative => Ok(None),
        }
    }

    pub fn allocate_mem(&mut self, mem: &Memory) -> Addr {
        let min = mem.0.min() as usize;
        self.mems.push(MemInst {
            limits: mem.0.clone(),
            data: vec![0; min * PAGE_SIZE],
        })
    }

    pub fn allocate_data(
        &mut self,
        memidx: usize,
        data: Data,
    ) -> Result<Option<Addr>, RuntimeError> {
        match &data.mode {
            DataMode::Passive => Ok(Some(data_passiv(&mut self.datas, data))),
            DataMode::Active { offset, .. } => {
                let offset = match eval_const(&offset)? {
                    Value::I32(v) => v,
                    _ => unreachable!(),
                } as usize;
                data_active(&mut self.mems[memidx], data, offset);
                Ok(None)
            }
        }
    }

    pub fn free_runtime(&mut self, runtime: Runtime) {
        for inst in runtime.instances() {
            for faddr in inst.funcaddrs {
                self.funcs.remove(faddr);
            }
            for daddr in inst.dataaddrs {
                self.datas.remove(daddr);
            }
            for eaddr in inst.elemaddrs {
                self.elems.remove(eaddr);
            }
            for gaddr in inst.globaladdrs {
                self.globals.remove(gaddr);
            }
            for taddr in inst.tableaddrs {
                self.tables.remove(taddr);
            }
            if let Some(maddr) = inst.memaddr {
                self.mems.remove(maddr);
            }
        }
    }
}