Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0382b06

Browse files
chore: support partially initialized module instances
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 31df65a commit 0382b06

File tree

5 files changed

+48
-22
lines changed

5 files changed

+48
-22
lines changed

crates/parser/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,11 @@ impl TryFrom<ModuleReader> for TinyWasmModule {
120120
WasmFunction {
121121
instructions: f.body,
122122
locals: f.locals,
123-
ty: reader.func_types.get(ty_idx as usize).unwrap().clone(),
123+
ty: reader
124+
.func_types
125+
.get(ty_idx as usize)
126+
.expect("No func type for func, this is a bug")
127+
.clone(),
124128
},
125129
)
126130
})

crates/tinywasm/src/instance.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub struct ModuleInstance(Arc<ModuleInstanceInner>);
2020
#[allow(dead_code)]
2121
#[derive(Debug)]
2222
pub(crate) struct ModuleInstanceInner {
23+
pub(crate) failed_to_instantiate: bool,
24+
2325
pub(crate) store_id: usize,
2426
pub(crate) idx: ModuleInstanceAddr,
2527

@@ -69,10 +71,11 @@ impl ModuleInstance {
6971
addrs.tables.extend(store.init_tables(data.table_types.into(), idx)?);
7072
addrs.memories.extend(store.init_memories(data.memory_types.into(), idx)?);
7173

72-
let elem_addrs = store.init_elements(&addrs.tables, &addrs.funcs, data.elements.into(), idx)?;
73-
let data_addrs = store.init_datas(&addrs.memories, data.data.into(), idx)?;
74+
let (elem_addrs, elem_trapped) = store.init_elements(&addrs.tables, &addrs.funcs, data.elements.into(), idx)?;
75+
let (data_addrs, data_trapped) = store.init_datas(&addrs.memories, data.data.into(), idx)?;
7476

7577
let instance = ModuleInstanceInner {
78+
failed_to_instantiate: elem_trapped.is_some() || data_trapped.is_some(),
7679
store_id: store.id(),
7780
idx,
7881
types: data.func_types,
@@ -90,6 +93,14 @@ impl ModuleInstance {
9093
let instance = ModuleInstance::new(instance);
9194
store.add_instance(instance.clone())?;
9295

96+
if let Some(trap) = elem_trapped {
97+
return Err(trap.into());
98+
};
99+
100+
if let Some(trap) = data_trapped {
101+
return Err(trap.into());
102+
};
103+
93104
Ok(instance)
94105
}
95106

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
runtime::{BlockType, LabelFrame},
77
CallFrame, Error, FuncContext, LabelArgs, ModuleInstance, Result, Store, Trap,
88
};
9-
use alloc::{string::ToString, vec::Vec};
9+
use alloc::{format, string::ToString, vec::Vec};
1010
use tinywasm_types::{ElementKind, Instruction, ValType};
1111

1212
mod macros;
@@ -25,10 +25,7 @@ impl DefaultRuntime {
2525
// The function to execute, gets updated from ExecResult::Call
2626
let mut instrs = &wasm_func.instructions;
2727

28-
let mut current_module = store
29-
.get_module_instance(func_inst.owner)
30-
.expect("exec expected module instance to exist for function")
31-
.clone();
28+
let mut current_module = store.get_module_instance(func_inst.owner).unwrap().clone();
3229

3330
while let Some(instr) = instrs.get(cf.instr_ptr) {
3431
match exec_one(&mut cf, instr, instrs, stack, store, &current_module)? {
@@ -40,7 +37,15 @@ impl DefaultRuntime {
4037
instrs = &wasm_func.instructions;
4138

4239
if cf.func_instance.owner != current_module.id() {
43-
current_module.swap(store.get_module_instance(cf.func_instance.owner).unwrap().clone());
40+
current_module.swap(
41+
store
42+
.get_module_instance(cf.func_instance.owner)
43+
.expect(&format!(
44+
"exec expected module instance {} to exist for function",
45+
cf.func_instance.owner
46+
))
47+
.clone(),
48+
);
4449
}
4550

4651
continue;

crates/tinywasm/src/store.rs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ impl Store {
4646

4747
/// Get a module instance by the internal id
4848
pub fn get_module_instance(&self, addr: ModuleInstanceAddr) -> Option<&ModuleInstance> {
49+
log::debug!("existing module instances: {:?}", self.module_instances.len());
4950
self.module_instances.get(addr as usize)
5051
}
5152

@@ -180,7 +181,7 @@ impl Store {
180181
func_addrs: &[FuncAddr],
181182
elements: Vec<Element>,
182183
idx: ModuleInstanceAddr,
183-
) -> Result<Box<[Addr]>> {
184+
) -> Result<(Box<[Addr]>, Option<Trap>)> {
184185
let elem_count = self.data.elements.len();
185186
let mut elem_addrs = Vec::with_capacity(elem_count);
186187
for (i, element) in elements.into_iter().enumerate() {
@@ -214,15 +215,17 @@ impl Store {
214215
.copied()
215216
.ok_or_else(|| Error::Other(format!("table {} not found for element {}", table, i)))?;
216217

217-
// a. Let n be the length of the vector elem[i].init
218-
// b. Execute the instruction sequence einstrs
219-
// c. Execute the instruction i32.const 0
220-
// d. Execute the instruction i32.const n
221-
// e. Execute the instruction table.init tableidx i
222218
if let Some(table) = self.data.tables.get_mut(table_addr as usize) {
223-
table.borrow_mut().init(func_addrs, offset, &init)?;
219+
// In wasm 2.0, it's possible to call a function that hasn't been instantiated yet,
220+
// when using a partially initialized active element segments.
221+
// This isn't mentioned in the spec, but the "unofficial" testsuite has a test for it:
222+
// https://github.com/WebAssembly/testsuite/blob/5a1a590603d81f40ef471abba70a90a9ae5f4627/linking.wast#L264-L276
223+
// I have NO IDEA why this is allowed, but it is.
224+
if let Err(Error::Trap(trap)) = table.borrow_mut().init(func_addrs, offset, &init) {
225+
return Ok((elem_addrs.into_boxed_slice(), Some(trap)));
226+
}
224227
} else {
225-
log::error!("table {} not found", table);
228+
return Err(Error::Other(format!("table {} not found for element {}", table, i)));
226229
}
227230

228231
// f. Execute the instruction elm.drop i
@@ -235,7 +238,7 @@ impl Store {
235238
}
236239

237240
// this should be optimized out by the compiler
238-
Ok(elem_addrs.into_boxed_slice())
241+
Ok((elem_addrs.into_boxed_slice(), None))
239242
}
240243

241244
/// Add data to the store, returning their addresses in the store
@@ -244,7 +247,7 @@ impl Store {
244247
mem_addrs: &[MemAddr],
245248
datas: Vec<Data>,
246249
idx: ModuleInstanceAddr,
247-
) -> Result<Box<[Addr]>> {
250+
) -> Result<(Box<[Addr]>, Option<Trap>)> {
248251
let data_count = self.data.datas.len();
249252
let mut data_addrs = Vec::with_capacity(data_count);
250253
for (i, data) in datas.into_iter().enumerate() {
@@ -268,7 +271,10 @@ impl Store {
268271
Error::Other(format!("memory {} not found for data segment {}", mem_addr, i))
269272
})?;
270273

271-
mem.borrow_mut().store(offset as usize, 0, &data.data)?;
274+
// See comment for active element sections in the function above why we need to do this here
275+
if let Err(Error::Trap(trap)) = mem.borrow_mut().store(offset as usize, 0, &data.data) {
276+
return Ok((data_addrs.into_boxed_slice(), Some(trap)));
277+
}
272278

273279
// drop the data
274280
continue;
@@ -281,7 +287,7 @@ impl Store {
281287
}
282288

283289
// this should be optimized out by the compiler
284-
Ok(data_addrs.into_boxed_slice())
290+
Ok((data_addrs.into_boxed_slice(), None))
285291
}
286292

287293
pub(crate) fn add_global(&mut self, ty: GlobalType, value: RawWasmValue, idx: ModuleInstanceAddr) -> Result<Addr> {

0 commit comments

Comments
 (0)