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

Commit 29018ba

Browse files
chore: progress towards linking modules
Signed-off-by: Henry Gressmann <[email protected]>
1 parent cc1c5bb commit 29018ba

File tree

9 files changed

+119
-57
lines changed

9 files changed

+119
-57
lines changed

crates/tinywasm/src/imports.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ use alloc::{
33
collections::BTreeMap,
44
string::{String, ToString},
55
};
6-
use tinywasm_types::{Global, GlobalType, WasmValue};
6+
use tinywasm_types::{Global, GlobalType, ModuleInstanceAddr, WasmValue};
77

88
#[derive(Debug)]
99
#[non_exhaustive]
1010
/// An external value
1111
pub enum Extern {
1212
/// A global value
1313
Global(Global),
14+
/// A registered module
15+
Module(String),
1416
// Func(HostFunc),
1517
// Table(Table),
1618
}
@@ -39,16 +41,39 @@ pub struct ExternName {
3941
/// Imports for a module instance
4042
pub struct Imports {
4143
values: BTreeMap<ExternName, Extern>,
44+
modules: BTreeMap<String, ModuleInstanceAddr>,
45+
}
46+
47+
pub(crate) struct LinkedImports {
48+
pub(crate) values: BTreeMap<ExternName, Extern>,
49+
}
50+
51+
impl LinkedImports {
52+
pub(crate) fn get(&self, module: &str, name: &str) -> Option<&Extern> {
53+
self.values.get(&ExternName {
54+
module: module.to_string(),
55+
name: name.to_string(),
56+
})
57+
}
4258
}
4359

4460
impl Imports {
4561
/// Create a new empty import set
4662
pub fn new() -> Self {
4763
Imports {
4864
values: BTreeMap::new(),
65+
modules: BTreeMap::new(),
4966
}
5067
}
5168

69+
/// Link a module
70+
///
71+
/// This will automatically link all imported values
72+
pub fn link_module(&mut self, name: &str, addr: ModuleInstanceAddr) -> Result<&mut Self> {
73+
self.modules.insert(name.to_string(), addr);
74+
Ok(self)
75+
}
76+
5277
/// Define an import
5378
pub fn define(&mut self, module: &str, name: &str, value: Extern) -> Result<&mut Self> {
5479
self.values.insert(
@@ -61,10 +86,8 @@ impl Imports {
6186
Ok(self)
6287
}
6388

64-
pub(crate) fn get(&self, module: &str, name: &str) -> Option<&Extern> {
65-
self.values.get(&ExternName {
66-
module: module.to_string(),
67-
name: name.to_string(),
68-
})
89+
pub(crate) fn link(self, store: &mut crate::Store, module: &crate::Module) -> Result<LinkedImports> {
90+
let values = self.values;
91+
Ok(LinkedImports { values })
6992
}
7093
}

crates/tinywasm/src/instance.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,22 @@ pub(crate) struct ModuleInstanceInner {
3636
}
3737

3838
impl ModuleInstance {
39+
/// Get the module instance's address
40+
pub fn id(&self) -> ModuleInstanceAddr {
41+
self.0.idx
42+
}
43+
3944
/// Instantiate the module in the given store
4045
pub fn instantiate(store: &mut Store, module: Module, imports: Option<Imports>) -> Result<Self> {
4146
let idx = store.next_module_instance_idx();
4247
let imports = imports.unwrap_or_default();
48+
let linked_imports = imports.link(store, &module)?;
4349

4450
let func_addrs = store.add_funcs(module.data.funcs.into(), idx);
4551
let table_addrs = store.add_tables(module.data.table_types.into(), idx);
4652
let mem_addrs = store.add_mems(module.data.memory_types.into(), idx)?;
47-
48-
let global_addrs = store.add_globals(module.data.globals.into(), &module.data.imports, &imports, idx)?;
49-
let elem_addrs = store.add_elems(module.data.elements.into(), idx);
53+
let global_addrs = store.add_globals(module.data.globals.into(), &module.data.imports, &linked_imports, idx)?;
54+
let elem_addrs = store.add_elems(module.data.elements.into(), idx)?;
5055
let data_addrs = store.add_datas(module.data.data.into(), idx);
5156

5257
let instance = ModuleInstanceInner {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! More generic macros for various instructions
22
//!
33
//! These macros are used to generate the actual instruction implementations.
4+
//! In some basic tests this generated better assembly than using generic functions, even when inlined.
5+
//! (Something to revisit in the future)
46
57
/// Load a value from memory
68
macro_rules! mem_load {
@@ -37,6 +39,7 @@ macro_rules! mem_store {
3739
}};
3840

3941
($store_type:ty, $target_type:ty, $arg:ident, $stack:ident, $store:ident, $module:ident) => {{
42+
// likewise, there could be a lot of performance improvements here
4043
let mem_idx = $module.resolve_mem_addr($arg.mem_addr);
4144
let mem = $store.get_mem(mem_idx as usize)?;
4245

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,6 @@ fn exec_one(
164164
}
165165
}
166166

167-
// Else(_end_offset) => {
168-
// // end the if block
169-
// cf.break_to(0, &mut stack.values)?;
170-
// }
171167
Loop(args, end_offset) => {
172168
// let params = stack.values.pop_block_params(*args, &module)?;
173169
cf.enter_label(
@@ -240,6 +236,7 @@ fn exec_one(
240236
}
241237
}
242238

239+
// We're essentially using else as a EndBlockFrame instruction
243240
Else(end_offset) => {
244241
let Some(block) = cf.labels.pop() else {
245242
panic!("else: no label to end, this should have been validated by the parser");

crates/tinywasm/src/runtime/stack.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ pub(crate) use call_stack::CallFrame;
99
/// A WebAssembly Stack
1010
#[derive(Debug, Default)]
1111
pub struct Stack {
12-
// keeping this typed for now to make it easier to debug
13-
// TODO: Maybe split into Vec<u8> and Vec<ValType> for better memory usage?
1412
pub(crate) values: ValueStack,
15-
16-
/// The call stack
1713
pub(crate) call_stack: CallStack,
1814
}

crates/tinywasm/src/store.rs

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use tinywasm_types::{
1313

1414
use crate::{
1515
runtime::{self, DefaultRuntime},
16-
Error, Extern, Imports, ModuleInstance, RawWasmValue, Result,
16+
Error, Extern, LinkedImports, ModuleInstance, RawWasmValue, Result,
1717
};
1818

1919
// global store id counter
@@ -153,7 +153,7 @@ impl Store {
153153
&mut self,
154154
globals: Vec<Global>,
155155
wasm_imports: &[Import],
156-
user_imports: &Imports,
156+
user_imports: &LinkedImports,
157157
idx: ModuleInstanceAddr,
158158
) -> Result<Vec<Addr>> {
159159
// TODO: initialize imported globals
@@ -191,41 +191,58 @@ impl Store {
191191
let iterator = imported_globals.into_iter().chain(globals.as_ref());
192192

193193
for (i, global) in iterator.enumerate() {
194-
use tinywasm_types::ConstInstruction::*;
195-
let val = match global.init {
196-
F32Const(f) => RawWasmValue::from(f),
197-
F64Const(f) => RawWasmValue::from(f),
198-
I32Const(i) => RawWasmValue::from(i),
199-
I64Const(i) => RawWasmValue::from(i),
200-
GlobalGet(addr) => {
201-
let addr = global_addrs[addr as usize];
202-
let global = self.data.globals[addr as usize].clone();
203-
let val = global.borrow().value;
204-
val
205-
}
206-
RefNull(_) => RawWasmValue::default(),
207-
RefFunc(idx) => RawWasmValue::from(idx as i64),
208-
};
209-
210-
self.data
211-
.globals
212-
.push(Rc::new(RefCell::new(GlobalInstance::new(global.ty, val, idx))));
213-
194+
self.data.globals.push(Rc::new(RefCell::new(GlobalInstance::new(
195+
global.ty,
196+
self.eval_const(&global.init)?,
197+
idx,
198+
))));
214199
global_addrs.push((i + global_count) as Addr);
215200
}
216-
log::debug!("global_addrs: {:?}", global_addrs);
201+
217202
Ok(global_addrs)
218203
}
219204

205+
pub(crate) fn eval_const(&self, const_instr: &tinywasm_types::ConstInstruction) -> Result<RawWasmValue> {
206+
use tinywasm_types::ConstInstruction::*;
207+
let val = match const_instr {
208+
F32Const(f) => RawWasmValue::from(*f),
209+
F64Const(f) => RawWasmValue::from(*f),
210+
I32Const(i) => RawWasmValue::from(*i),
211+
I64Const(i) => RawWasmValue::from(*i),
212+
GlobalGet(addr) => {
213+
let addr = *addr as usize;
214+
let global = self.data.globals[addr].clone();
215+
let val = global.borrow().value;
216+
val
217+
}
218+
RefNull(_) => RawWasmValue::default(),
219+
RefFunc(idx) => RawWasmValue::from(*idx as i64),
220+
};
221+
Ok(val)
222+
}
223+
220224
/// Add elements to the store, returning their addresses in the store
221-
pub(crate) fn add_elems(&mut self, elems: Vec<Element>, idx: ModuleInstanceAddr) -> Vec<Addr> {
225+
/// Should be called after the tables have been added
226+
pub(crate) fn add_elems(&mut self, elems: Vec<Element>, idx: ModuleInstanceAddr) -> Result<Vec<Addr>> {
222227
let elem_count = self.data.elems.len();
223228
let mut elem_addrs = Vec::with_capacity(elem_count);
224229
for (i, elem) in elems.into_iter().enumerate() {
225230
self.data.elems.push(ElemInstance::new(elem.kind, idx));
226231
elem_addrs.push((i + elem_count) as Addr);
232+
233+
// match elem.kind {
234+
// ElementKind::Active { table, offset } => {
235+
// // let table = self.data.tables[table as usize];
236+
237+
// // let offset = self.eval_const(&offset)?;
238+
// // let offset = offset.raw_value() as usize;
239+
// // let offset = offset + elem_addrs[i] as usize;
240+
// // let offset = offset as Addr;
241+
// }
242+
// }
227243
}
228-
elem_addrs
244+
245+
Ok(elem_addrs)
229246
}
230247

231248
/// Add data to the store, returning their addresses in the store
@@ -313,8 +330,8 @@ pub(crate) struct TableInstance {
313330
impl TableInstance {
314331
pub(crate) fn new(kind: TableType, owner: ModuleInstanceAddr) -> Self {
315332
Self {
333+
elements: vec![0; kind.size_initial as usize],
316334
kind,
317-
elements: Vec::new(),
318335
owner,
319336
}
320337
}

0 commit comments

Comments
 (0)