Skip to content

Commit a42cb34

Browse files
fix: correct memory64 execution and backend errors
Signed-off-by: Henry <mail@henrygressmann.de>
1 parent 68f85f6 commit a42cb34

18 files changed

Lines changed: 497 additions & 253 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2424
- Typed function tuples now support up to 20 parameters or results. `WasmTupleChain` is deprecated. Use untyped functions for larger signatures.
2525
- Module types now use one dense recursive type space, while function types are resolved through `Function::ty(&Store)`.
2626
- Globals are stored in separate 32-bit, 64-bit, and 128-bit value lanes, avoiding tagged value conversion during guest execution.
27+
- `LinearMemory` mutation methods and custom memory-backend factories now return `Trap` errors so lazy backend failures can be propagated.
2728

2829
### Fixed
2930

3031
- Directly defined imports now reject handles from a different `Store`.
3132
- Tail calls to host functions now return directly to the caller frame.
33+
- Fixed Memory64 bulk-memory operations and optimized stores using the wrong value-stack lane.
34+
- Fixed `memory.init` bounds checks, operand lowering, and local-memory allocation analysis.
35+
- Fixed Memory64 default limits and host-size handling, including 32-bit targets.
3236

3337
### Breaking Changes
3438

‎Cargo.toml‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,7 @@ wasmparser = { version = "0.256", default-features = false }
3535
wast = "256"
3636
wat = "1.256"
3737

38-
criterion = { version = "0.8", default-features = false, features = [
39-
"cargo_bench_support",
40-
"rayon"
41-
] }
38+
criterion = { version = "0.8", default-features = false, features = ["cargo_bench_support", "rayon"] }
4239

4340
[[example]]
4441
name = "wasm-rust"

‎benches/memory_backends.rs‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ fn criterion_benchmark(c: &mut Criterion) {
7878
bench_grow(&mut group, "paged", || {
7979
PagedMemory::try_new(PAGE_SIZE, CHUNK_SIZE).expect("bench memory should be constructible")
8080
});
81-
8281
bench_write_all(
8382
&mut group,
8483
"vec",

‎crates/cli/src/output.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub fn format_memory_type(ty: &MemoryType) -> String {
4848
MemoryArch::I32 => "i32",
4949
MemoryArch::I64 => "i64",
5050
};
51-
let max = if ty.page_count_max() == ty.page_count_initial() && ty.max_size() == ty.initial_size() {
51+
let max = if ty.page_count_max() == ty.page_count_initial() {
5252
ty.page_count_initial().to_string()
5353
} else {
5454
ty.page_count_max().to_string()

‎crates/parser/src/visit.rs‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,10 +477,7 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder<'_> {
477477
terminating [] => [] { visit_unreachable => Unreachable, visit_return => Return }
478478
memory_index [] => [Addr] { visit_memory_size(memory: u32) => MemorySize }
479479
memory_index [Addr] => [Addr] { visit_memory_grow(memory: u32) => MemoryGrow }
480-
memory_index [Addr, S32, Addr] => [] {
481-
visit_memory_init(data_index: u32, memory: u32) => MemoryInit,
482-
visit_memory_fill(memory: u32) => MemoryFill,
483-
}
480+
memory_index [Addr, S32, Addr] => [] { visit_memory_fill(memory: u32) => MemoryFill }
484481
table [Addr] => [S32] { visit_table_get(table: u32) => TableGet }
485482
table [Addr, S32] => [] { visit_table_set(table: u32) => TableSet }
486483
table [] => [Addr] { visit_table_size(table: u32) => TableSize }
@@ -941,6 +938,11 @@ impl<'a> wasmparser::VisitOperator<'a> for FunctionBuilder<'_> {
941938
self.emit(&[dst, src, len], &[], Instruction::MemoryCopy { dst_mem, src_mem })
942939
}
943940

941+
fn visit_memory_init(&mut self, data_index: u32, memory: u32) -> Self::Output {
942+
let dst = self.metadata.memory_size(memory)?;
943+
self.emit(&[dst, ValueLane::S32, ValueLane::S32], &[], Instruction::MemoryInit(data_index, memory))
944+
}
945+
944946
fn visit_br_on_cast(
945947
&mut self,
946948
relative_depth: u32,

‎crates/tinywasm/src/interpreter/executor.rs‎

Lines changed: 87 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use alloc::boxed::Box;
88
use alloc::vec::Vec;
99

1010
use alloc::sync::Arc;
11-
use interpreter::stack::{CallFrame, ValueStack};
11+
use interpreter::stack::CallFrame;
1212
use tinywasm_types::*;
1313

1414
use super::ExecState;
@@ -30,19 +30,6 @@ pub(crate) struct Executor<'store, const BUDGETED: bool> {
3030
}
3131

3232
impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
33-
#[inline(always)]
34-
fn pop_memory_addr<const N: usize>(
35-
stack: &mut ValueStack,
36-
mem: &MemoryInstance,
37-
offset: u64,
38-
) -> Result<usize, Trap> {
39-
if mem.is_64bit() {
40-
mem.effective_addr_64::<N>(<i64>::stack_pop(stack) as u64, offset)
41-
} else {
42-
mem.effective_addr_32::<N>(<i32>::stack_pop(stack) as u32, offset)
43-
}
44-
}
45-
4633
pub(crate) fn new(store: &'store mut Store, cf: CallFrame, call_stack_base: u32) -> Self {
4734
let wasm_func = store.state.get_wasm_func(cf.func_addr);
4835
let module = store
@@ -1133,7 +1120,7 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
11331120
self.store.host_params = params;
11341121
let res = cold_err!(result).map_err(|error| Trap::HostFunction(Box::new(error)))?;
11351122

1136-
self.store.value_stack.extend_from_wasmvalues(&res)?;
1123+
self.store.value_stack.extend_wasmvalues(res.iter().copied())?;
11371124
if TAIL {
11381125
Ok(self.exec_return())
11391126
} else {
@@ -1304,10 +1291,22 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
13041291
addr_local: u8,
13051292
value_local: u8,
13061293
) -> Result<(), Trap> {
1307-
let base = u32::local_get(&self.store.value_stack, &self.cf, u16::from(addr_local));
13081294
let value = T::local_get(&self.store.value_stack, &self.cf, u16::from(value_local));
1309-
let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(memarg.mem_addr()));
1310-
let addr = mem.effective_addr_32::<N>(base, memarg.offset())?;
1295+
let mem_addr = self.module.resolve_mem_addr(memarg.mem_addr());
1296+
let mem = self.store.state.get_mem(mem_addr);
1297+
let addr = if mem.is_64bit() {
1298+
let base = u64::local_get(&self.store.value_stack, &self.cf, u16::from(addr_local));
1299+
let base = cold_err!(usize::try_from(base).map_err(|_| Trap::MemoryOutOfBounds {
1300+
offset: usize::MAX,
1301+
len: N,
1302+
max: mem.inner.len(),
1303+
}))?;
1304+
mem.effective_addr::<N>(base, memarg.offset())?
1305+
} else {
1306+
let base = u32::local_get(&self.store.value_stack, &self.cf, u16::from(addr_local));
1307+
mem.effective_addr::<N>(base as usize, memarg.offset())?
1308+
};
1309+
let mem = self.store.state.get_mem_mut(mem_addr);
13111310
value.store_at(&mut *mem.inner, addr)
13121311
}
13131312

@@ -1322,10 +1321,15 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
13221321
let mem = self.store.state.get_mem(mem_addr);
13231322
let addr = if mem.is_64bit() {
13241323
let base = i64::local_get(&self.store.value_stack, &self.cf, u16::from(addr_local)) as u64;
1325-
mem.effective_addr_64::<N>(base, memarg.offset())?
1324+
let base = cold_err!(usize::try_from(base).map_err(|_| Trap::MemoryOutOfBounds {
1325+
offset: usize::MAX,
1326+
len: N,
1327+
max: mem.inner.len(),
1328+
}))?;
1329+
mem.effective_addr::<N>(base, memarg.offset())?
13261330
} else {
13271331
let base = u32::local_get(&self.store.value_stack, &self.cf, u16::from(addr_local));
1328-
mem.effective_addr_32::<N>(base, memarg.offset())?
1332+
mem.effective_addr::<N>(base as usize, memarg.offset())?
13291333
};
13301334

13311335
let mem = self.store.state.get_mem_mut(mem_addr);
@@ -1344,10 +1348,12 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
13441348
let rhs = T::stack_pop(&mut self.store.value_stack);
13451349
let lhs = T::stack_pop(&mut self.store.value_stack);
13461350
let acc = T::stack_pop(&mut self.store.value_stack);
1347-
let addr = i32::stack_pop(&mut self.store.value_stack);
13481351
let fma = acc + lhs * rhs;
1349-
let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(m.mem_addr()));
1350-
let addr = mem.effective_addr_32::<N>(addr as u32, m.offset())?;
1352+
let mem_addr = self.module.resolve_mem_addr(m.mem_addr());
1353+
let mem = self.store.state.get_mem(mem_addr);
1354+
let base = self.store.value_stack.pop_memory_operand(mem.kind.arch())?;
1355+
let addr = mem.effective_addr::<N>(base, m.offset())?;
1356+
let mem = self.store.state.get_mem_mut(mem_addr);
13511357
fma.store_at(&mut *mem.inner, addr)?;
13521358
Ok(())
13531359
}
@@ -1361,10 +1367,15 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
13611367
let mem = self.store.state.get_mem(self.module.resolve_mem_addr(memarg.mem_addr()));
13621368
let addr = if mem.is_64bit() {
13631369
let base = i64::local_get(&self.store.value_stack, &self.cf, u16::from(addr_local)) as u64;
1364-
mem.effective_addr_64::<N>(base, memarg.offset())?
1370+
let base = cold_err!(usize::try_from(base).map_err(|_| Trap::MemoryOutOfBounds {
1371+
offset: usize::MAX,
1372+
len: N,
1373+
max: mem.inner.len(),
1374+
}))?;
1375+
mem.effective_addr::<N>(base, memarg.offset())?
13651376
} else {
13661377
let base = u32::local_get(&self.store.value_stack, &self.cf, u16::from(addr_local));
1367-
mem.effective_addr_32::<N>(base, memarg.offset())?
1378+
mem.effective_addr::<N>(base as usize, memarg.offset())?
13681379
};
13691380
T::load_at(&*mem.inner, addr)
13701381
}
@@ -1659,56 +1670,69 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
16591670
}
16601671

16611672
fn exec_memory_copy(&mut self, dst_mem: u32, src_mem: u32) -> Result<(), Trap> {
1662-
let size = i32::stack_pop(&mut self.store.value_stack);
1663-
let src = i32::stack_pop(&mut self.store.value_stack);
1664-
let dst = i32::stack_pop(&mut self.store.value_stack);
16651673
let dst_mem_addr = self.module.resolve_mem_addr(dst_mem);
1674+
let src_mem_addr = self.module.resolve_mem_addr(src_mem);
1675+
let dst_arch = self.store.state.get_mem(dst_mem_addr).kind.arch();
1676+
let src_arch = self.store.state.get_mem(src_mem_addr).kind.arch();
1677+
let len_arch =
1678+
if dst_arch == MemoryArch::I32 || src_arch == MemoryArch::I32 { MemoryArch::I32 } else { MemoryArch::I64 };
1679+
let size = self.store.value_stack.pop_memory_operand(len_arch)?;
1680+
let src = self.store.value_stack.pop_memory_operand(src_arch)?;
1681+
let dst = self.store.value_stack.pop_memory_operand(dst_arch)?;
16661682

16671683
if dst_mem == src_mem {
16681684
// copy within the same memory
16691685
let mem = self.store.state.get_mem_mut(dst_mem_addr);
1670-
mem.copy_within(dst as usize, src as usize, size as usize)?;
1686+
mem.copy_within(dst, src, size)?;
16711687
} else {
16721688
// copy between two memories
1673-
let src_mem_addr = self.module.resolve_mem_addr(src_mem);
16741689
let (dst_memory, src_memory) = self.store.state.get_mems_mut(dst_mem_addr, src_mem_addr);
1675-
dst_memory.copy_from_memory(dst as usize, src_memory, src as usize, size as usize)?;
1690+
dst_memory.copy_from_memory(dst, src_memory, src, size)?;
16761691
}
16771692
Ok(())
16781693
}
16791694

16801695
fn exec_memory_fill(&mut self, addr: u32) -> Result<(), Trap> {
1681-
let size = i32::stack_pop(&mut self.store.value_stack);
1696+
let mem_addr = self.module.resolve_mem_addr(addr);
1697+
let arch = self.store.state.get_mem(mem_addr).kind.arch();
1698+
let size = self.store.value_stack.pop_memory_operand(arch)?;
16821699
let val = i32::stack_pop(&mut self.store.value_stack);
1683-
let dst = i32::stack_pop(&mut self.store.value_stack);
1684-
self.exec_memory_fill_impl(addr, dst, val as u8, size)
1700+
let dst = self.store.value_stack.pop_memory_operand(arch)?;
1701+
self.exec_memory_fill_impl(mem_addr, dst, val as u8, size)
16851702
}
16861703

16871704
fn exec_memory_fill_imm(&mut self, addr: u32, val: u8, size: i32) -> Result<(), Trap> {
1688-
let dst = i32::stack_pop(&mut self.store.value_stack);
1689-
self.exec_memory_fill_impl(addr, dst, val, size)
1705+
let mem_addr = self.module.resolve_mem_addr(addr);
1706+
let arch = self.store.state.get_mem(mem_addr).kind.arch();
1707+
let dst = self.store.value_stack.pop_memory_operand(arch)?;
1708+
self.exec_memory_fill_impl(mem_addr, dst, val, size as u32 as usize)
16901709
}
16911710

1692-
fn exec_memory_fill_impl(&mut self, addr: u32, dst: i32, val: u8, size: i32) -> Result<(), Trap> {
1693-
let mem = self.store.state.get_mem_mut(self.module.resolve_mem_addr(addr));
1711+
fn exec_memory_fill_impl(&mut self, mem_addr: MemAddr, dst: usize, val: u8, size: usize) -> Result<(), Trap> {
1712+
let mem = self.store.state.get_mem_mut(mem_addr);
16941713
let max = mem.inner.len();
1695-
if mem.inner.fill(dst as usize, size as usize, val).is_none() {
1696-
return cold!(Err(Trap::MemoryOutOfBounds { offset: dst as usize, len: size as usize, max }));
1714+
if mem.inner.fill(dst, size, val)?.is_none() {
1715+
return cold!(Err(Trap::MemoryOutOfBounds { offset: dst, len: size, max }));
16971716
}
16981717
Ok(())
16991718
}
17001719

17011720
fn exec_memory_init(&mut self, data_index: u32, mem_index: u32) -> Result<(), Trap> {
1702-
let size = i32::stack_pop(&mut self.store.value_stack);
1703-
let offset = i32::stack_pop(&mut self.store.value_stack);
1704-
let dst = i32::stack_pop(&mut self.store.value_stack);
1721+
let size = u32::stack_pop(&mut self.store.value_stack) as usize;
1722+
let offset = u32::stack_pop(&mut self.store.value_stack) as usize;
1723+
let mem_addr = self.module.resolve_mem_addr(mem_index);
1724+
let arch = self.store.state.get_mem(mem_addr).kind.arch();
1725+
let dst = self.store.value_stack.pop_memory_operand(arch)?;
17051726

17061727
let data = &self.store.state.data[self.module.resolve_data_addr(data_index) as usize];
1707-
let mem = &mut self.store.state.memories[self.module.resolve_mem_addr(mem_index) as usize];
1728+
let mem = &mut self.store.state.memories[mem_addr as usize];
17081729
let data_len = data.data.as_ref().map_or(0, |d| d.len());
17091730
let mem_len = mem.inner.len();
1710-
if ((size + offset) as usize > data_len) || ((dst + size) as usize > mem_len) {
1711-
return cold!(Err(Trap::MemoryOutOfBounds { offset: offset as usize, len: size as usize, max: data_len }));
1731+
if offset.checked_add(size).is_none_or(|end| end > data_len) {
1732+
return cold!(Err(Trap::MemoryOutOfBounds { offset, len: size, max: data_len }));
1733+
}
1734+
if dst.checked_add(size).is_none_or(|end| end > mem_len) {
1735+
return cold!(Err(Trap::MemoryOutOfBounds { offset: dst, len: size, max: mem_len }));
17121736
}
17131737

17141738
if size == 0 {
@@ -1719,8 +1743,8 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
17191743
return cold!(Err(Trap::MemoryOutOfBounds { offset: 0, len: 0, max: 0 }));
17201744
};
17211745

1722-
if mem.inner.write_all(dst as usize, &data[offset as usize..((offset + size) as usize)]).is_none() {
1723-
return cold!(Err(Trap::MemoryOutOfBounds { offset: dst as usize, len: size as usize, max: mem_len }));
1746+
if mem.inner.write_all(dst, &data[offset..offset + size])?.is_none() {
1747+
return cold!(Err(Trap::MemoryOutOfBounds { offset: dst, len: size, max: mem_len }));
17241748
}
17251749
Ok(())
17261750
}
@@ -1753,7 +1777,8 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
17531777
lane: u8,
17541778
) -> Result<(), Trap> {
17551779
let mem = self.store.state.get_mem(self.module.resolve_mem_addr(mem_addr));
1756-
let addr = Self::pop_memory_addr::<LOAD_SIZE>(&mut self.store.value_stack, mem, offset)?;
1780+
let base = self.store.value_stack.pop_memory_operand(mem.kind.arch())?;
1781+
let addr = mem.effective_addr::<LOAD_SIZE>(base, offset)?;
17571782
let val = LOAD::load_at(&*mem.inner, addr)?;
17581783
let offset = lane as usize * LOAD_SIZE;
17591784
let mut imm = <Value128>::stack_pop(&mut self.store.value_stack).to_mem_bytes();
@@ -1770,7 +1795,8 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
17701795
cast: impl Fn(LOAD) -> TARGET,
17711796
) -> Result<(), Trap> {
17721797
let mem = self.store.state.get_mem(self.module.resolve_mem_addr(mem_addr));
1773-
let addr = Self::pop_memory_addr::<LOAD_SIZE>(&mut self.store.value_stack, mem, offset)?;
1798+
let base = self.store.value_stack.pop_memory_operand(mem.kind.arch())?;
1799+
let addr = mem.effective_addr::<LOAD_SIZE>(base, offset)?;
17741800
let value = cold_err!(LOAD::load_at(&*mem.inner, addr))?;
17751801
self.store.value_stack.push(cast(value))
17761802
}
@@ -1787,8 +1813,10 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
17871813
val_bytes.copy_from_slice(&bytes[lane_offset..lane_offset + N]);
17881814
let val = U::from_mem_bytes(val_bytes);
17891815
let mem_addr = self.module.resolve_mem_addr(mem_addr);
1816+
let mem = self.store.state.get_mem(mem_addr);
1817+
let base = self.store.value_stack.pop_memory_operand(mem.kind.arch())?;
1818+
let addr = mem.effective_addr::<N>(base, offset)?;
17901819
let mem = self.store.state.get_mem_mut(mem_addr);
1791-
let addr = Self::pop_memory_addr::<N>(&mut self.store.value_stack, mem, offset)?;
17921820
cold_err!(val.store_at(&mut *mem.inner, addr))?;
17931821
Ok(())
17941822
}
@@ -1803,8 +1831,10 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
18031831
let val = cast(val);
18041832

18051833
let mem_addr = self.module.resolve_mem_addr(mem_addr);
1834+
let mem = self.store.state.get_mem(mem_addr);
1835+
let base = self.store.value_stack.pop_memory_operand(mem.kind.arch())?;
1836+
let addr = mem.effective_addr::<N>(base, offset)?;
18061837
let mem = self.store.state.get_mem_mut(mem_addr);
1807-
let addr = Self::pop_memory_addr::<N>(&mut self.store.value_stack, mem, offset)?;
18081838
cold_err!(val.store_at(&mut *mem.inner, addr))?;
18091839
Ok(())
18101840
}
@@ -1876,7 +1906,11 @@ impl<'store, const BUDGETED: bool> Executor<'store, BUDGETED> {
18761906
MemoryArch::I32 => <i32>::stack_pop(&mut self.store.value_stack) as u32 as u64,
18771907
MemoryArch::I64 => <i64>::stack_pop(&mut self.store.value_stack) as u64,
18781908
};
1879-
usize::try_from(value).map_err(|_| Trap::TableOutOfBounds { offset: usize::MAX, len: 1, max: usize::MAX })
1909+
cold_err!(usize::try_from(value).map_err(|_| Trap::TableOutOfBounds {
1910+
offset: usize::MAX,
1911+
len: 1,
1912+
max: usize::MAX,
1913+
}))
18801914
}
18811915
}
18821916

‎crates/tinywasm/src/interpreter/stack/value_stack.rs‎

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use alloc::{vec, vec::Vec};
22
use core::hint::cold_path;
3-
use tinywasm_types::{ValueCounts, WasmType, WasmValue};
3+
use tinywasm_types::{MemoryArch, ValueCounts, WasmType, WasmValue};
44

55
use super::StackBase;
66
use crate::engine::{Config, StackConfig};
@@ -280,6 +280,24 @@ impl ValueStack {
280280
T::stack_push(self, value)
281281
}
282282

283+
#[inline(always)]
284+
pub(crate) fn pop_memory_operand(&mut self, arch: MemoryArch) -> Result<usize, Trap> {
285+
match arch {
286+
MemoryArch::I32 => Ok(self.stack_32.pop() as usize),
287+
MemoryArch::I64 => {
288+
let value = self.stack_64.pop();
289+
#[cfg(target_pointer_width = "64")]
290+
return Ok(value as usize);
291+
#[cfg(not(target_pointer_width = "64"))]
292+
return cold_err!(usize::try_from(value).map_err(|_| Trap::MemoryOutOfBounds {
293+
offset: usize::MAX,
294+
len: 0,
295+
max: usize::MAX,
296+
}));
297+
}
298+
}
299+
}
300+
283301
#[inline]
284302
pub(crate) fn select_multi(&mut self, counts: ValueCounts) {
285303
let condition = i32::stack_pop(self) != 0;
@@ -305,7 +323,7 @@ impl ValueStack {
305323
locals: ValueCounts,
306324
base: StackBase,
307325
) -> Result<StackBase, Trap> {
308-
self.extend_from_wasmvalues(values).inspect_err(|_| self.truncate_to_base(base))?;
326+
self.extend_wasmvalues(values.iter().copied()).inspect_err(|_| self.truncate_to_base(base))?;
309327
self.enter_locals(&params, &locals).inspect_err(|_| self.truncate_to_base(base))
310328
}
311329

@@ -363,10 +381,6 @@ impl ValueStack {
363381
WasmValues { stack: self, state, types: types.iter(), index, pin_refs }
364382
}
365383

366-
pub(crate) fn extend_from_wasmvalues(&mut self, values: &[WasmValue]) -> Result<(), Trap> {
367-
self.extend_wasmvalues(values.iter().copied())
368-
}
369-
370384
pub(crate) fn extend_wasmvalues(&mut self, values: impl Iterator<Item = WasmValue>) -> Result<(), Trap> {
371385
for value in values {
372386
match value {

0 commit comments

Comments
 (0)