Skip to content

Commit

Permalink
feat: imports
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 64606e0 commit 54c1b75
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 44 deletions.
2 changes: 1 addition & 1 deletion crates/cli/src/bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ fn main() -> Result<()> {

fn run(module: Module, func: Option<String>, args: Vec<WasmValue>) -> Result<()> {
let mut store = tinywasm::Store::default();
let instance = module.instantiate(&mut store)?;
let instance = module.instantiate(&mut store, None)?;

if let Some(func) = func {
let func = instance.exported_func_by_name(&store, &func)?;
Expand Down
70 changes: 70 additions & 0 deletions crates/tinywasm/src/imports.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use crate::Result;
use alloc::{
collections::BTreeMap,
string::{String, ToString},
};
use tinywasm_types::{Global, GlobalType, WasmValue};

#[derive(Debug)]
#[non_exhaustive]
/// An external value
pub enum Extern {
/// A global value
Global(Global),
// Func(HostFunc),
// Table(Table),
}

impl Extern {
/// Create a new global import
pub fn global(val: WasmValue, mutable: bool) -> Self {
Self::Global(Global {
ty: GlobalType {
ty: val.val_type(),
mutable,
},
init: val.const_instr(),
})
}
}

#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
/// Name of an import
pub struct ExternName {
module: String,
name: String,
}

#[derive(Debug, Default)]
/// Imports for a module instance
pub struct Imports {
values: BTreeMap<ExternName, Extern>,
}

impl Imports {
/// Create a new empty import set
pub fn new() -> Self {
Imports {
values: BTreeMap::new(),
}
}

/// Define an import
pub fn define(&mut self, module: &str, name: &str, value: Extern) -> Result<&mut Self> {
self.values.insert(
ExternName {
module: module.to_string(),
name: name.to_string(),
},
value,
);
Ok(self)
}

pub(crate) fn get(&self, module: &str, name: &str) -> Option<&Extern> {
self.values.get(&ExternName {
module: module.to_string(),
name: name.to_string(),
})
}
}
7 changes: 4 additions & 3 deletions crates/tinywasm/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use tinywasm_types::{

use crate::{
func::{FromWasmValueTuple, IntoWasmValueTuple},
Error, ExportInstance, FuncHandle, Module, Result, Store, TypedFuncHandle,
Error, ExportInstance, FuncHandle, Imports, Module, Result, Store, TypedFuncHandle,
};

/// A WebAssembly Module Instance
Expand Down Expand Up @@ -36,14 +36,15 @@ pub(crate) struct ModuleInstanceInner {

impl ModuleInstance {
/// Instantiate the module in the given store
pub fn instantiate(store: &mut Store, module: Module) -> Result<Self> {
pub fn instantiate(store: &mut Store, module: Module, imports: Option<Imports>) -> Result<Self> {
let idx = store.next_module_instance_idx();
let imports = imports.unwrap_or_default();

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 global_addrs = store.add_globals(module.data.globals.into(), &module.data.imports, 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);
let data_addrs = store.add_datas(module.data.data.into(), idx);

Expand Down
5 changes: 4 additions & 1 deletion crates/tinywasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
//! // This will allocate the module and its globals into the store
//! // and execute the module's start function.
//! // Every ModuleInstance has its own ID space for functions, globals, etc.
//! let instance = module.instantiate(&mut store)?;
//! let instance = module.instantiate(&mut store, None)?;
//!
//! // Get a typed handle to the exported "add" function
//! // Alternatively, you can use `instance.get_func` to get an untyped handle
Expand Down Expand Up @@ -94,6 +94,9 @@ pub use export::ExportInstance;
mod func;
pub use func::{FuncHandle, TypedFuncHandle};

mod imports;
pub use imports::*;

mod runtime;
pub use runtime::*;

Expand Down
10 changes: 3 additions & 7 deletions crates/tinywasm/src/module.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use tinywasm_types::TinyWasmModule;

use crate::{ModuleInstance, Result, Store};
use crate::{Imports, ModuleInstance, Result, Store};

#[derive(Debug)]
/// A WebAssembly Module
Expand Down Expand Up @@ -53,12 +53,8 @@ impl Module {
/// If you want to run the start function yourself, use `ModuleInstance::instantiate`
///
/// See <https://webassembly.github.io/spec/core/exec/modules.html#exec-instantiation>
pub fn instantiate(
self,
store: &mut Store,
// imports: Option<()>,
) -> Result<ModuleInstance> {
let instance = ModuleInstance::instantiate(store, self)?;
pub fn instantiate(self, store: &mut Store, imports: Option<Imports>) -> Result<ModuleInstance> {
let instance = ModuleInstance::instantiate(store, self, imports)?;

// TODO: this currently panics if theres no start fn
// let _ = instance.start(store)?;
Expand Down
50 changes: 28 additions & 22 deletions crates/tinywasm/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use tinywasm_types::{

use crate::{
runtime::{self, DefaultRuntime},
Error, ModuleInstance, RawWasmValue, Result,
Error, Extern, Imports, ModuleInstance, RawWasmValue, Result,
};

// global store id counter
Expand Down Expand Up @@ -144,36 +144,42 @@ impl Store {
pub(crate) fn add_globals(
&mut self,
globals: Vec<Global>,
imports: &[Import],
wasm_imports: &[Import],
user_imports: &Imports,
idx: ModuleInstanceAddr,
) -> Vec<Addr> {
let global_count = self.data.globals.len();
let mut global_addrs = Vec::with_capacity(global_count);

) -> Result<Vec<Addr>> {
// TODO: initialize imported globals
let imported_globals = imports
let imported_globals = wasm_imports
.iter()
.filter_map(|import| match &import.kind {
tinywasm_types::ImportKind::Global(t) => Some(t),
tinywasm_types::ImportKind::Global(_) => Some(import),
_ => None,
})
.collect::<Vec<_>>();

for (i, global) in imported_globals.into_iter().enumerate() {
log::debug!("imported global: {:?}", global);
self.data.globals.push(Rc::new(RefCell::new(GlobalInstance::new(
global.clone(),
global.ty.default_value().into(),
idx,
))));
global_addrs.push((i + global_count) as Addr);
}
.map(|import| {
let Some(global) = user_imports.get(&import.module, &import.name) else {
return Err(Error::Other(format!(
"global import not found for {}::{}",
import.module, import.name
)));
};
match global {
Extern::Global(global) => Ok(global),
_ => Err(Error::Other(format!(
"expected global import for {}::{}",
import.module, import.name
))),
}
})
.collect::<Result<Vec<_>>>()?;

let global_count = self.data.globals.len();
let mut global_addrs = Vec::with_capacity(global_count);

log::debug!("globals: {:?}", globals);
for (i, global) in globals.into_iter().enumerate() {
// TODO: initialize globals
let globals = globals.into_iter();
let iterator = imported_globals.into_iter().chain(globals.as_ref());

for (i, global) in iterator.enumerate() {
use tinywasm_types::ConstInstruction::*;
let val = match global.init {
F32Const(f) => RawWasmValue::from(f),
Expand All @@ -197,7 +203,7 @@ impl Store {
global_addrs.push((i + global_count) as Addr);
}
log::debug!("global_addrs: {:?}", global_addrs);
global_addrs
Ok(global_addrs)
}

/// Add elements to the store, returning their addresses in the store
Expand Down
Loading

0 comments on commit 54c1b75

Please sign in to comment.