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

Skip to content

Commit ec26f4b

Browse files
feat: preserve null refs when returning
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 52eda3e commit ec26f4b

File tree

9 files changed

+78
-52
lines changed

9 files changed

+78
-52
lines changed

crates/parser/src/conversion.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,8 @@ pub(crate) fn convert_valtype(valtype: &wasmparser::ValType) -> ValType {
202202
F32 => ValType::F32,
203203
F64 => ValType::F64,
204204
V128 => unimplemented!("128-bit values are not supported yet"),
205-
FuncRef => ValType::FuncRef,
206-
ExternRef => ValType::ExternRef,
205+
FuncRef => ValType::RefFunc,
206+
ExternRef => ValType::RefExtern,
207207
}
208208
}
209209

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,11 @@ fn exec_one(
171171
let call_ty = module.func_ty(*type_addr);
172172

173173
let func_idx = stack.values.pop_t::<u32>()?;
174-
let actual_func_addr = table.borrow().get(func_idx as usize)?;
174+
let actual_func_addr = table
175+
.borrow()
176+
.get(func_idx as usize)?
177+
.ok_or_else(|| Trap::UninitializedElement { index: func_idx as usize })?;
178+
175179
let resolved_func_addr = module.resolve_func_addr(actual_func_addr);
176180

177181
// prepare the call frame
@@ -565,12 +569,12 @@ fn exec_one(
565569
I64TruncF32U => checked_conv_float!(f32, u64, i64, stack),
566570
I64TruncF64U => checked_conv_float!(f64, u64, i64, stack),
567571

568-
// TODO: uninitialized element traps
569572
TableGet(table_index) => {
570573
let table_idx = module.resolve_table_addr(*table_index);
571574
let table = store.get_table(table_idx as usize)?;
572575
let idx = stack.values.pop_t::<i32>()? as usize;
573-
stack.values.push(table.borrow().get(idx)?.into());
576+
let v = table.borrow().get_wasm_val(idx)?;
577+
stack.values.push(v.into());
574578
}
575579

576580
TableSet(table_index) => {

crates/tinywasm/src/runtime/value.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,20 @@ impl RawWasmValue {
2727
ValType::I64 => WasmValue::I64(self.0 as i64),
2828
ValType::F32 => WasmValue::F32(f32::from_bits(self.0 as u32)),
2929
ValType::F64 => WasmValue::F64(f64::from_bits(self.0)),
30-
ValType::ExternRef => WasmValue::RefExtern(match self.0 {
31-
0 => None,
32-
_ => Some(self.0 as u32),
33-
}),
34-
ValType::FuncRef => WasmValue::RefFunc(match self.0 {
35-
0 => None,
36-
_ => Some(self.0 as u32),
37-
}),
30+
ValType::RefExtern => {
31+
if self.0 == -1i64 as u64 {
32+
WasmValue::RefNull(ValType::RefExtern)
33+
} else {
34+
WasmValue::RefExtern(self.0 as u32)
35+
}
36+
}
37+
ValType::RefFunc => {
38+
if self.0 == -1i64 as u64 {
39+
WasmValue::RefNull(ValType::RefFunc)
40+
} else {
41+
WasmValue::RefFunc(self.0 as u32)
42+
}
43+
}
3844
}
3945
}
4046
}
@@ -46,8 +52,9 @@ impl From<WasmValue> for RawWasmValue {
4652
WasmValue::I64(i) => Self(i as u64),
4753
WasmValue::F32(i) => Self(i.to_bits() as u64),
4854
WasmValue::F64(i) => Self(i.to_bits()),
49-
WasmValue::RefExtern(v) => Self(v.unwrap_or(0) as u64),
50-
WasmValue::RefFunc(v) => Self(v.unwrap_or(0) as u64),
55+
WasmValue::RefExtern(v) => Self(v as i64 as u64),
56+
WasmValue::RefFunc(v) => Self(v as i64 as u64),
57+
WasmValue::RefNull(_) => Self(-1i64 as u64),
5158
}
5259
}
5360
}

crates/tinywasm/src/store.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ impl Store {
335335
let val = global.borrow().value;
336336
val
337337
}
338-
RefNull(v) => v.default_value().into(),
338+
RefNull(_) => RawWasmValue::from(0),
339339
RefFunc(idx) => RawWasmValue::from(*idx as i64),
340340
};
341341
Ok(val)
@@ -414,27 +414,36 @@ impl FunctionInstance {
414414
#[derive(Debug)]
415415
pub(crate) struct TableInstance {
416416
pub(crate) elements: Vec<Option<Addr>>,
417-
pub(crate) _kind: TableType,
417+
pub(crate) kind: TableType,
418418
pub(crate) _owner: ModuleInstanceAddr, // index into store.module_instances
419419
}
420420

421421
impl TableInstance {
422422
pub(crate) fn new(kind: TableType, owner: ModuleInstanceAddr) -> Self {
423-
Self { elements: vec![None; kind.size_initial as usize], _kind: kind, _owner: owner }
423+
Self { elements: vec![None; kind.size_initial as usize], kind, _owner: owner }
424424
}
425425

426-
pub(crate) fn get(&self, addr: usize) -> Result<Addr> {
427-
self.elements
428-
.get(addr)
429-
.copied()
430-
.ok_or_else(|| Error::Trap(Trap::UndefinedElement { index: addr }))
431-
.map(|elem| elem.ok_or_else(|| Trap::UninitializedElement { index: addr }.into()))?
426+
pub(crate) fn get_wasm_val(&self, addr: usize) -> Result<WasmValue> {
427+
Ok(match self.kind.element_type {
428+
ValType::RefFunc => {
429+
self.get(addr)?.map(|v| WasmValue::RefFunc(v)).unwrap_or(WasmValue::RefNull(ValType::RefFunc))
430+
}
431+
ValType::RefExtern => {
432+
self.get(addr)?.map(|v| WasmValue::RefExtern(v)).unwrap_or(WasmValue::RefNull(ValType::RefExtern))
433+
}
434+
_ => unimplemented!("unsupported table type: {:?}", self.kind.element_type),
435+
})
436+
}
437+
438+
pub(crate) fn get(&self, addr: usize) -> Result<Option<Addr>> {
439+
self.elements.get(addr).copied().ok_or_else(|| Error::Trap(Trap::UndefinedElement { index: addr }))
432440
}
433441

434442
pub(crate) fn set(&mut self, addr: usize, value: Addr) -> Result<()> {
435443
if addr >= self.elements.len() {
436444
return Err(Error::Other(format!("table element {} not found", addr)));
437445
}
446+
438447
self.elements[addr] = Some(value);
439448
Ok(())
440449
}

crates/tinywasm/tests/generated/mvp.csv

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

crates/tinywasm/tests/generated/progress-mvp.svg

Lines changed: 4 additions & 4 deletions
Loading

crates/tinywasm/tests/testsuite/run.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ impl TestSuite {
8383
let mut imports = Imports::new();
8484

8585
let table =
86-
Extern::table(TableType::new(ValType::FuncRef, 10, Some(20)), WasmValue::default_for(ValType::FuncRef));
86+
Extern::table(TableType::new(ValType::RefFunc, 10, Some(20)), WasmValue::default_for(ValType::RefFunc));
8787

8888
let print = Extern::typed_func(|_ctx: tinywasm::FuncContext, _: ()| {
8989
log::debug!("print");
@@ -464,6 +464,8 @@ impl TestSuite {
464464
));
465465
}
466466

467+
log::debug!("outcomes: {:?}", outcomes);
468+
467469
outcomes.iter().zip(expected).enumerate().try_for_each(|(i, (outcome, exp))| {
468470
(outcome.eq_loose(&exp))
469471
.then_some(())

crates/tinywasm/tests/testsuite/util.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::panic::{self, AssertUnwindSafe};
22

33
use eyre::{eyre, Result};
4-
use tinywasm_types::{ModuleInstanceAddr, TinyWasmModule, WasmValue};
4+
use tinywasm_types::{ModuleInstanceAddr, TinyWasmModule, ValType, WasmValue};
55

66
pub fn try_downcast_panic(panic: Box<dyn std::any::Any + Send>) -> String {
77
let info = panic.downcast_ref::<panic::PanicInfo>().or(None).map(|p| p.to_string()).clone();
@@ -77,10 +77,10 @@ fn wastarg2tinywasmvalue(arg: wast::WastArg) -> Result<tinywasm_types::WasmValue
7777
F64(f) => WasmValue::F64(f64::from_bits(f.bits)),
7878
I32(i) => WasmValue::I32(i),
7979
I64(i) => WasmValue::I64(i),
80-
RefExtern(v) => WasmValue::RefExtern(Some(v)),
80+
RefExtern(v) => WasmValue::RefExtern(v),
8181
RefNull(t) => match t {
82-
wast::core::HeapType::Func => WasmValue::RefFunc(None),
83-
wast::core::HeapType::Extern => WasmValue::RefExtern(None),
82+
wast::core::HeapType::Func => WasmValue::RefNull(ValType::RefFunc),
83+
wast::core::HeapType::Extern => WasmValue::RefNull(ValType::RefExtern),
8484
_ => return Err(eyre!("unsupported arg type: refnull: {:?}", t)),
8585
},
8686
v => return Err(eyre!("unsupported arg type: {:?}", v)),
@@ -99,16 +99,16 @@ fn wastret2tinywasmvalue(arg: wast::WastRet) -> Result<tinywasm_types::WasmValue
9999
I32(i) => WasmValue::I32(i),
100100
I64(i) => WasmValue::I64(i),
101101
RefNull(t) => match t {
102-
Some(wast::core::HeapType::Func) => WasmValue::RefFunc(None),
103-
Some(wast::core::HeapType::Extern) => WasmValue::RefExtern(None),
102+
Some(wast::core::HeapType::Func) => WasmValue::RefNull(ValType::RefFunc),
103+
Some(wast::core::HeapType::Extern) => WasmValue::RefNull(ValType::RefExtern),
104104
_ => return Err(eyre!("unsupported arg type: refnull: {:?}", t)),
105105
},
106106
RefExtern(v) => match v {
107-
Some(v) => WasmValue::RefExtern(Some(v)),
107+
Some(v) => WasmValue::RefExtern(v),
108108
_ => return Err(eyre!("unsupported arg type: refextern: {:?}", v)),
109109
},
110110
RefFunc(v) => match v {
111-
Some(wast::token::Index::Num(n, _)) => WasmValue::RefFunc(Some(n)),
111+
Some(wast::token::Index::Num(n, _)) => WasmValue::RefFunc(n),
112112
_ => return Err(eyre!("unsupported arg type: reffunc: {:?}", v)),
113113
},
114114
a => return Err(eyre!("unsupported arg type {:?}", a)),

crates/types/src/lib.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,10 @@ pub enum WasmValue {
8383
F32(f32),
8484
/// A 64-bit float.
8585
F64(f64),
86-
// Vec types
87-
// V128(i128),
88-
// RefHost(FuncAddr),
89-
RefExtern(Option<ExternAddr>),
90-
RefFunc(Option<FuncAddr>),
86+
87+
RefExtern(ExternAddr),
88+
RefFunc(FuncAddr),
89+
RefNull(ValType),
9190
}
9291

9392
impl WasmValue {
@@ -97,8 +96,10 @@ impl WasmValue {
9796
Self::I64(i) => ConstInstruction::I64Const(*i),
9897
Self::F32(i) => ConstInstruction::F32Const(*i),
9998
Self::F64(i) => ConstInstruction::F64Const(*i),
100-
Self::RefExtern(None) => ConstInstruction::RefNull(ValType::ExternRef),
101-
Self::RefFunc(None) => ConstInstruction::RefNull(ValType::FuncRef),
99+
100+
Self::RefFunc(i) => ConstInstruction::RefFunc(*i),
101+
Self::RefNull(ty) => ConstInstruction::RefNull(*ty),
102+
102103
// Self::RefExtern(addr) => ConstInstruction::RefExtern(*addr),
103104
_ => unimplemented!("no const_instr for {:?}", self),
104105
}
@@ -111,15 +112,16 @@ impl WasmValue {
111112
ValType::I64 => Self::I64(0),
112113
ValType::F32 => Self::F32(0.0),
113114
ValType::F64 => Self::F64(0.0),
114-
ValType::FuncRef => Self::RefFunc(None),
115-
ValType::ExternRef => Self::RefExtern(None),
115+
ValType::RefFunc => Self::RefNull(ValType::RefFunc),
116+
ValType::RefExtern => Self::RefNull(ValType::RefExtern),
116117
}
117118
}
118119

119120
pub fn eq_loose(&self, other: &Self) -> bool {
120121
match (self, other) {
121122
(Self::I32(a), Self::I32(b)) => a == b,
122123
(Self::I64(a), Self::I64(b)) => a == b,
124+
(Self::RefNull(v), Self::RefNull(v2)) => v == v2,
123125
(Self::RefExtern(addr), Self::RefExtern(addr2)) => addr == addr2,
124126
(Self::RefFunc(addr), Self::RefFunc(addr2)) => addr == addr2,
125127
(Self::F32(a), Self::F32(b)) => {
@@ -230,6 +232,7 @@ impl Debug for WasmValue {
230232
WasmValue::F64(i) => write!(f, "f64({})", i),
231233
WasmValue::RefExtern(addr) => write!(f, "ref.extern({:?})", addr),
232234
WasmValue::RefFunc(addr) => write!(f, "ref.func({:?})", addr),
235+
WasmValue::RefNull(ty) => write!(f, "ref.null({:?})", ty),
233236
// WasmValue::V128(i) => write!(f, "v128({})", i),
234237
}
235238
}
@@ -243,8 +246,9 @@ impl WasmValue {
243246
Self::I64(_) => ValType::I64,
244247
Self::F32(_) => ValType::F32,
245248
Self::F64(_) => ValType::F64,
246-
Self::RefExtern(_) => ValType::ExternRef,
247-
Self::RefFunc(_) => ValType::FuncRef,
249+
Self::RefExtern(_) => ValType::RefExtern,
250+
Self::RefFunc(_) => ValType::RefFunc,
251+
Self::RefNull(ty) => *ty,
248252
}
249253
}
250254
}
@@ -261,9 +265,9 @@ pub enum ValType {
261265
/// A 64-bit float.
262266
F64,
263267
/// A reference to a function.
264-
FuncRef,
268+
RefFunc,
265269
/// A reference to an external value.
266-
ExternRef,
270+
RefExtern,
267271
}
268272

269273
impl ValType {
@@ -392,7 +396,7 @@ pub struct TableType {
392396

393397
impl TableType {
394398
pub fn empty() -> Self {
395-
Self { element_type: ValType::FuncRef, size_initial: 0, size_max: None }
399+
Self { element_type: ValType::RefFunc, size_initial: 0, size_max: None }
396400
}
397401

398402
pub fn new(element_type: ValType, size_initial: u32, size_max: Option<u32>) -> Self {

0 commit comments

Comments
 (0)