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

Commit 3361f92

Browse files
chore: refactor executor, add LocalCopy instructions
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
1 parent 4425733 commit 3361f92

File tree

25 files changed

+770
-809
lines changed

25 files changed

+770
-809
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
},
55
"rust-analyzer.linkedProjects": [
66
"./Cargo.toml",
7-
]
7+
],
88
}

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/parser/src/conversion.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ pub(crate) fn convert_module_code(
176176

177177
// maps a local's address to the index in the type's locals array
178178
let mut local_addr_map = Vec::with_capacity(count as usize);
179-
let mut local_counts = LocalCounts::default();
179+
let mut local_counts = ValueCounts::default();
180180

181181
for (i, local) in locals_reader.into_iter().enumerate() {
182182
let local = local?;
@@ -186,20 +186,20 @@ pub(crate) fn convert_module_code(
186186
for i in 0..validator.len_locals() {
187187
match validator.get_local_type(i) {
188188
Some(wasmparser::ValType::I32) | Some(wasmparser::ValType::F32) => {
189-
local_addr_map.push(local_counts.local_32);
190-
local_counts.local_32 += 1;
189+
local_addr_map.push(local_counts.c32);
190+
local_counts.c32 += 1;
191191
}
192192
Some(wasmparser::ValType::I64) | Some(wasmparser::ValType::F64) => {
193-
local_addr_map.push(local_counts.local_64);
194-
local_counts.local_64 += 1;
193+
local_addr_map.push(local_counts.c64);
194+
local_counts.c64 += 1;
195195
}
196196
Some(wasmparser::ValType::V128) => {
197-
local_addr_map.push(local_counts.local_128);
198-
local_counts.local_128 += 1;
197+
local_addr_map.push(local_counts.c128);
198+
local_counts.c128 += 1;
199199
}
200200
Some(wasmparser::ValType::Ref(_)) => {
201-
local_addr_map.push(local_counts.local_ref);
202-
local_counts.local_ref += 1;
201+
local_addr_map.push(local_counts.cref);
202+
local_counts.cref += 1;
203203
}
204204
None => return Err(crate::ParseError::UnsupportedOperator("Unknown local type".to_string())),
205205
}

crates/parser/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ impl Parser {
5959
sign_extension: true,
6060
saturating_float_to_int: true,
6161
function_references: true,
62+
tail_call: true,
6263

6364
component_model: false,
6465
component_model_nested_names: false,
@@ -71,7 +72,6 @@ impl Parser {
7172
memory_control: false,
7273
relaxed_simd: false,
7374
simd: false,
74-
tail_call: false,
7575
threads: false,
7676
multi_memory: false, // should be working mostly
7777
custom_page_sizes: false,

crates/parser/src/module.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ use crate::{conversion, ParseError, Result};
33
use alloc::string::ToString;
44
use alloc::{boxed::Box, format, vec::Vec};
55
use tinywasm_types::{
6-
Data, Element, Export, FuncType, Global, Import, Instruction, LocalCounts, MemoryType, TableType, TinyWasmModule,
7-
WasmFunction,
6+
Data, Element, Export, FuncType, Global, Import, Instruction, MemoryType, TableType, TinyWasmModule, ValType,
7+
ValueCounts, ValueCountsSmall, WasmFunction,
88
};
99
use wasmparser::{FuncValidatorAllocations, Payload, Validator};
1010

11-
pub(crate) type Code = (Box<[Instruction]>, LocalCounts);
11+
pub(crate) type Code = (Box<[Instruction]>, ValueCounts);
1212

1313
#[derive(Default)]
1414
pub(crate) struct ModuleReader {
@@ -193,10 +193,18 @@ impl ModuleReader {
193193
.code
194194
.into_iter()
195195
.zip(self.code_type_addrs)
196-
.map(|((instructions, locals), ty_idx)| WasmFunction {
197-
instructions,
198-
locals,
199-
ty: self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone(),
196+
.map(|((instructions, locals), ty_idx)| {
197+
let mut params = ValueCountsSmall::default();
198+
let ty = self.func_types.get(ty_idx as usize).expect("No func type for func, this is a bug").clone();
199+
for param in ty.params.iter() {
200+
match param {
201+
ValType::I32 | ValType::F32 => params.c32 += 1,
202+
ValType::I64 | ValType::F64 => params.c64 += 1,
203+
ValType::V128 => params.c128 += 1,
204+
ValType::RefExtern | ValType::RefFunc => params.cref += 1,
205+
}
206+
}
207+
WasmFunction { instructions, params, locals, ty }
200208
})
201209
.collect::<Vec<_>>()
202210
.into_boxed_slice();

crates/parser/src/visit.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ macro_rules! impl_visit_operator {
122122
(@@sign_extension $($rest:tt)* ) => {};
123123
(@@saturating_float_to_int $($rest:tt)* ) => {};
124124
(@@bulk_memory $($rest:tt)* ) => {};
125+
(@@tail_call $($rest:tt)* ) => {};
125126
(@@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => {
126127
#[cold]
127128
fn $visit(&mut self $($(,$arg: $argty)*)?) {
@@ -317,6 +318,14 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
317318
visit_i64_trunc_sat_f64_u, Instruction::I64TruncSatF64U
318319
}
319320

321+
fn visit_return_call(&mut self, function_index: u32) -> Self::Output {
322+
self.instructions.push(Instruction::ReturnCall(function_index));
323+
}
324+
325+
fn visit_return_call_indirect(&mut self, type_index: u32, table_index: u32) -> Self::Output {
326+
self.instructions.push(Instruction::ReturnCallIndirect(type_index, table_index));
327+
}
328+
320329
fn visit_global_set(&mut self, global_index: u32) -> Self::Output {
321330
match self.validator.get_operand_type(0) {
322331
Some(Some(t)) => self.instructions.push(match t {
@@ -385,6 +394,30 @@ impl<'a, R: WasmModuleResources> wasmparser::VisitOperator<'a> for FunctionBuild
385394
return;
386395
};
387396

397+
match self.instructions.last() {
398+
Some(Instruction::LocalGet32(from))
399+
| Some(Instruction::LocalGet64(from))
400+
| Some(Instruction::LocalGet128(from))
401+
| Some(Instruction::LocalGetRef(from)) => {
402+
let from = *from;
403+
self.instructions.pop();
404+
// validation will ensure that the last instruction is the correct local.get
405+
match self.validator.get_operand_type(0) {
406+
Some(Some(t)) => self.instructions.push(match t {
407+
wasmparser::ValType::I32 => Instruction::LocalCopy32(from, resolved_idx),
408+
wasmparser::ValType::F32 => Instruction::LocalCopy32(from, resolved_idx),
409+
wasmparser::ValType::I64 => Instruction::LocalCopy64(from, resolved_idx),
410+
wasmparser::ValType::F64 => Instruction::LocalCopy64(from, resolved_idx),
411+
wasmparser::ValType::V128 => Instruction::LocalCopy128(from, resolved_idx),
412+
wasmparser::ValType::Ref(_) => Instruction::LocalCopyRef(from, resolved_idx),
413+
}),
414+
_ => self.visit_unreachable(),
415+
}
416+
return;
417+
}
418+
_ => {}
419+
}
420+
388421
match self.validator.get_operand_type(0) {
389422
Some(Some(t)) => self.instructions.push(match t {
390423
wasmparser::ValType::I32 => Instruction::LocalSet32(resolved_idx),

crates/tinywasm/benches/argon2id.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fn argon2id_run(module: TinyWasmModule) -> Result<()> {
2525
let mut store = Store::default();
2626
let instance = ModuleInstance::instantiate(&mut store, module.into(), None)?;
2727
let argon2 = instance.exported_func::<(i32, i32, i32), i32>(&store, "argon2id")?;
28-
argon2.call(&mut store, (1000, 1, 1))?;
28+
argon2.call(&mut store, (1000, 2, 1))?;
2929
Ok(())
3030
}
3131

crates/tinywasm/src/error.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use alloc::string::{String, ToString};
2-
use core::fmt::Display;
2+
use core::{fmt::Display, ops::ControlFlow};
33
use tinywasm_types::FuncType;
44

55
#[cfg(feature = "parser")]
@@ -23,15 +23,6 @@ pub enum Error {
2323
/// A function did not return a value
2424
FuncDidNotReturn,
2525

26-
/// The stack is empty
27-
ValueStackUnderflow,
28-
29-
/// The label stack is empty
30-
BlockStackUnderflow,
31-
32-
/// The call stack is empty
33-
CallStackUnderflow,
34-
3526
/// An invalid label type was encountered
3627
InvalidLabelType,
3728

@@ -189,13 +180,10 @@ impl Display for Error {
189180

190181
Self::Trap(trap) => write!(f, "trap: {}", trap),
191182
Self::Linker(err) => write!(f, "linking error: {}", err),
192-
Self::CallStackUnderflow => write!(f, "call stack empty"),
193183
Self::InvalidLabelType => write!(f, "invalid label type"),
194184
Self::Other(message) => write!(f, "unknown error: {}", message),
195185
Self::UnsupportedFeature(feature) => write!(f, "unsupported feature: {}", feature),
196186
Self::FuncDidNotReturn => write!(f, "function did not return"),
197-
Self::BlockStackUnderflow => write!(f, "label stack underflow"),
198-
Self::ValueStackUnderflow => write!(f, "value stack underflow"),
199187
Self::InvalidStore => write!(f, "invalid store"),
200188
}
201189
}
@@ -249,3 +237,16 @@ impl From<tinywasm_parser::ParseError> for Error {
249237

250238
/// A wrapper around [`core::result::Result`] for tinywasm operations
251239
pub type Result<T, E = Error> = crate::std::result::Result<T, E>;
240+
241+
pub(crate) trait Controlify<T> {
242+
fn to_cf(self) -> ControlFlow<Option<Error>, T>;
243+
}
244+
245+
impl<T> Controlify<T> for Result<T, Error> {
246+
fn to_cf(self) -> ControlFlow<Option<Error>, T> {
247+
match self {
248+
Ok(value) => ControlFlow::Continue(value),
249+
Err(err) => ControlFlow::Break(Some(err)),
250+
}
251+
}
252+
}

crates/tinywasm/src/func.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl FuncHandle {
4848
return Err(Error::Other("Type mismatch".into()));
4949
}
5050

51-
let func_inst = store.get_func(self.addr)?;
51+
let func_inst = store.get_func(&self.addr);
5252
let wasm_func = match &func_inst.func {
5353
Function::Host(host_func) => {
5454
let func = &host_func.clone().func;
@@ -76,7 +76,7 @@ impl FuncHandle {
7676
// assert!(stack.values.len() >= result_m);
7777

7878
// 2. Pop m values from the stack
79-
let res = stack.values.pop_results(&func_ty.results)?;
79+
let res = stack.values.pop_results(&func_ty.results);
8080

8181
// The values are returned as the results of the invocation.
8282
Ok(res)

crates/tinywasm/src/imports.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,6 @@ impl Extern {
143143
}
144144

145145
/// Create a new typed function import
146-
// TODO: currently, this is slower than `Extern::func` because of the type conversions.
147-
// we should be able to optimize this and make it even faster than `Extern::func`.
148146
pub fn typed_func<P, R>(func: impl Fn(FuncContext<'_>, P) -> Result<R> + 'static) -> Self
149147
where
150148
P: FromWasmValueTuple + ValTypesFromTuple,
@@ -388,23 +386,23 @@ impl Imports {
388386

389387
match (val, &import.kind) {
390388
(ExternVal::Global(global_addr), ImportKind::Global(ty)) => {
391-
let global = store.get_global(global_addr)?;
389+
let global = store.get_global(&global_addr);
392390
Self::compare_types(import, &global.ty, ty)?;
393391
imports.globals.push(global_addr);
394392
}
395393
(ExternVal::Table(table_addr), ImportKind::Table(ty)) => {
396-
let table = store.get_table(table_addr)?;
394+
let table = store.get_table(&table_addr);
397395
Self::compare_table_types(import, &table.kind, ty)?;
398396
imports.tables.push(table_addr);
399397
}
400398
(ExternVal::Memory(memory_addr), ImportKind::Memory(ty)) => {
401-
let mem = store.get_mem(memory_addr)?;
402-
let (size, kind) = { (mem.page_count(), mem.kind) };
399+
let mem = store.get_mem(&memory_addr);
400+
let (size, kind) = { (mem.page_count, mem.kind) };
403401
Self::compare_memory_types(import, &kind, ty, Some(size))?;
404402
imports.memories.push(memory_addr);
405403
}
406404
(ExternVal::Func(func_addr), ImportKind::Function(ty)) => {
407-
let func = store.get_func(func_addr)?;
405+
let func = store.get_func(&func_addr);
408406
let import_func_type = module
409407
.0
410408
.func_types

0 commit comments

Comments
 (0)