use super::state::{Freg32, Freg64, Inst, Ip, Ireg, Mem0Len, Mem0Ptr, Sp};
#[cfg(feature = "simd")]
use crate::core::simd::ImmLaneIdx;
#[cfg(doc)]
use crate::instance::{InstanceEntity, ThinPtr};
use crate::{
DataSegment,
ElementSegment,
Error,
Func,
Global,
Handle,
Memory,
Nullable,
RefType,
Table,
TrapCode,
V128,
core::{CoreMemory as MemoryEntity, CoreTable as TableEntity, RawVal, ShiftAmount},
engine::{
FuncEntry,
InOutParams,
executor::{
LoadFromCellsByValue,
StoreToCells,
handler::{Break, Control, DoneReason, args::Args},
},
utils::unreachable_unchecked,
},
func::{FuncEntity, HostFuncEntity, Trampoline},
instance::{DataAddr, ElemAddr, FuncAddr, GlobalAddr, HandleAndEntity, MemoryAddr, TableAddr},
ir::{
self,
Address,
BoundedSlotSpan,
Local,
Offset,
Offset16,
Slot,
SlotAndReg,
SlotSpan,
Table0,
},
store::{CallHooks, PrunedStore, StoreError},
};
use core::{num::NonZero, ptr::NonNull};
macro_rules! out_of_fuel {
($store:expr, $args:expr, $required_fuel:expr) => {{
$store.stack_mut().sync_ip($args.ip);
$store
.stack_mut()
.sync_regs($args.ireg, $args.freg32, $args.freg64);
done!(
$store,
$crate::engine::executor::handler::DoneReason::out_of_fuel($required_fuel),
)
}};
}
macro_rules! consume_fuel {
($state:expr, $ip:expr, $args:expr, $fuel:expr, $eval:expr $(,)? ) => {{
if let ::core::result::Result::Err($crate::errors::FuelError::OutOfFuel { required_fuel }) =
$fuel.consume_fuel_if($eval)
{
$args.set_ip($ip);
out_of_fuel!($state, $args, required_fuel)
}
}};
}
pub fn compile_or_get_func_entry(
store: &mut PrunedStore,
func: &FuncEntry,
) -> Result<(Ip, u16, u16), Error> {
let (fuel, features) = store.inner_mut().fuel_and_features();
let compiled_func = func.get_or_compile(Some(fuel), features)?;
let ip = Ip::from(compiled_func.ops());
let len_local_slots = compiled_func.len_local_slots();
let len_stack_slots = compiled_func.len_stack_slots();
Ok((ip, len_local_slots, len_stack_slots))
}
macro_rules! compile_or_get_func_entry {
($state:expr, $func:expr) => {{
match $crate::engine::executor::handler::utils::compile_or_get_func_entry($state, $func) {
Ok((ip, len_local_slots, len_stack_slots)) => (ip, len_local_slots, len_stack_slots),
Err(error) => done!($state, DoneReason::error(error)),
}
}};
}
macro_rules! trap {
($trap_code:expr) => {{
return $crate::engine::executor::handler::Control::Break(
$crate::engine::executor::handler::Break::from($trap_code),
);
}};
}
macro_rules! done {
($store:expr, $reason:expr $(,)? ) => {{
$store.inner_mut().exec_mut().done_with(move || {
<_ as ::core::convert::Into<$crate::engine::executor::handler::DoneReason>>::into(
$reason,
)
});
return $crate::engine::executor::handler::dispatch::control_break();
}};
}
pub trait IntoControl {
type Value;
fn into_control(self) -> Control<Self::Value, Break>;
}
impl<T> IntoControl for Result<T, TrapCode> {
type Value = T;
fn into_control(self) -> Control<Self::Value, Break> {
match self {
Ok(value) => Control::Continue(value),
Err(trap_code) => Control::Break(Break::from(trap_code)),
}
}
}
macro_rules! impl_into_control {
( $($ty:ty),* $(,)? ) => {
$(
impl IntoControl for $ty {
type Value = Self;
fn into_control(self) -> Control<Self::Value, Break> {
Control::Continue(self)
}
}
)*
};
}
impl_into_control! {
bool,
u8, u16, u32, u64, usize,
i8, i16, i32, i64, isize,
f32, f64,
V128,
RawVal,
}
pub trait GetValue<T> {
fn get_value(src: Self, sp: Sp, ireg: Ireg, freg32: Freg32, freg64: Freg64) -> T;
}
macro_rules! impl_get_value {
( $($ty:ty),* $(,)? ) => {
$(
impl GetValue<$ty> for $ty {
#[inline(always)]
fn get_value(src: Self, _sp: Sp, _ireg: Ireg, _freg32: Freg32, _freg64: Freg64) -> $ty {
src
}
}
)*
};
}
impl_get_value!(
u8,
u16,
u32,
u64,
i8,
i16,
i32,
i64,
f32,
f64,
NonZero<i32>,
NonZero<i64>,
NonZero<u32>,
NonZero<u64>,
Address,
Offset16,
ShiftAmount,
V128,
);
#[cfg(feature = "simd")]
impl_get_value!([ImmLaneIdx<32>; 16]);
impl GetValue<u64> for Offset {
#[inline(always)]
fn get_value(src: Self, _sp: Sp, _ireg: Ireg, _freg32: Freg32, _freg64: Freg64) -> u64 {
u64::from(src)
}
}
macro_rules! impl_get_value_for_ireg {
( $($prim:ty),* $(,)? ) => {
$(
impl GetValue<$prim> for ir::Reg<i64> {
#[inline]
fn get_value(_src: Self, _sp: Sp, ireg: Ireg, _freg32: Freg32, _freg64: Freg64) -> $prim {
<$prim as From<Ireg>>::from(ireg)
}
}
)*
};
}
impl_get_value_for_ireg!(bool, i8, i16, i32, i64, u8, u16, u32, u64, ShiftAmount);
impl From<Ireg> for ShiftAmount {
#[inline]
fn from(value: Ireg) -> Self {
Self::from(u8::from(value))
}
}
impl GetValue<f32> for ir::Reg<f32> {
#[inline]
fn get_value(_src: Self, _sp: Sp, _ireg: Ireg, freg32: Freg32, _freg64: Freg64) -> f32 {
f32::from(freg32)
}
}
impl GetValue<f64> for ir::Reg<f64> {
#[inline]
fn get_value(_src: Self, _sp: Sp, _ireg: Ireg, _freg32: Freg32, freg64: Freg64) -> f64 {
f64::from(freg64)
}
}
impl<const N: u16, T> GetValue<T> for Local<N>
where
T: LoadFromCellsByValue,
{
#[inline]
fn get_value(_src: Self, sp: Sp, ireg: Ireg, freg32: Freg32, freg64: Freg64) -> T {
<Slot as GetValue<T>>::get_value(Slot::from(N), sp, ireg, freg32, freg64)
}
}
impl<T> GetValue<T> for Slot
where
T: LoadFromCellsByValue,
{
#[inline]
fn get_value(src: Self, sp: Sp, _ireg: Ireg, _freg32: Freg32, _freg64: Freg64) -> T {
unsafe { sp.get::<T>(src) }
}
}
#[inline]
pub fn get_slot_value<L>(src: Slot, sp: Sp) -> L
where
Slot: GetValue<L>,
{
<Slot as GetValue<L>>::get_value(
src,
sp,
Ireg::default(),
Freg32::default(),
Freg64::default(),
)
}
#[inline]
pub fn get_value<T, L>(src: T, sp: Sp, ireg: Ireg, freg32: Freg32, freg64: Freg64) -> L
where
T: GetValue<L>,
{
<T as GetValue<L>>::get_value(src, sp, ireg, freg32, freg64)
}
pub trait SetValue<T> {
#[must_use]
fn set_value(
dst: Self,
src: T,
sp: Sp,
ireg: Ireg,
freg32: Freg32,
freg64: Freg64,
) -> (Ireg, Freg32, Freg64);
}
impl<T> SetValue<T> for ir::Reg<i64>
where
T: Into<Ireg>,
{
#[inline]
fn set_value(
_dst: Self,
src: T,
_sp: Sp,
_ireg: Ireg,
freg32: Freg32,
freg64: Freg64,
) -> (Ireg, Freg32, Freg64) {
(src.into(), freg32, freg64)
}
}
impl<T> SetValue<T> for ir::Reg<f32>
where
T: Into<Freg32>,
{
#[inline]
fn set_value(
_dst: Self,
src: T,
_sp: Sp,
ireg: Ireg,
_freg32: Freg32,
freg64: Freg64,
) -> (Ireg, Freg32, Freg64) {
(ireg, src.into(), freg64)
}
}
impl<T> SetValue<T> for ir::Reg<f64>
where
T: Into<Freg64>,
{
#[inline]
fn set_value(
_dst: Self,
src: T,
_sp: Sp,
ireg: Ireg,
freg32: Freg32,
_freg64: Freg64,
) -> (Ireg, Freg32, Freg64) {
(ireg, freg32, src.into())
}
}
impl<const N: u16, T> SetValue<T> for Local<N>
where
T: StoreToCells,
{
#[inline]
fn set_value(
_dst: Self,
src: T,
sp: Sp,
ireg: Ireg,
freg32: Freg32,
freg64: Freg64,
) -> (Ireg, Freg32, Freg64) {
<Slot as SetValue<T>>::set_value(Slot::from(N), src, sp, ireg, freg32, freg64)
}
}
impl<T> SetValue<T> for SlotAndReg<i64>
where
T: StoreToCells + Into<Ireg> + Copy,
{
#[inline]
fn set_value(
dst: Self,
src: T,
sp: Sp,
ireg: Ireg,
freg32: Freg32,
freg64: Freg64,
) -> (Ireg, Freg32, Freg64) {
let (ireg, freg32, freg64) = set_value(dst.slot, src, sp, ireg, freg32, freg64);
set_value(dst.reg, src, sp, ireg, freg32, freg64)
}
}
impl<T> SetValue<T> for SlotAndReg<f32>
where
T: StoreToCells + Into<Freg32> + Copy,
{
#[inline]
fn set_value(
dst: Self,
src: T,
sp: Sp,
ireg: Ireg,
freg32: Freg32,
freg64: Freg64,
) -> (Ireg, Freg32, Freg64) {
let (ireg, freg32, freg64) = set_value(dst.slot, src, sp, ireg, freg32, freg64);
set_value(dst.reg, src, sp, ireg, freg32, freg64)
}
}
impl<T> SetValue<T> for SlotAndReg<f64>
where
T: StoreToCells + Into<Freg64> + Copy,
{
#[inline]
fn set_value(
dst: Self,
src: T,
sp: Sp,
ireg: Ireg,
freg32: Freg32,
freg64: Freg64,
) -> (Ireg, Freg32, Freg64) {
let (ireg, freg32, freg64) = set_value(dst.slot, src, sp, ireg, freg32, freg64);
set_value(dst.reg, src, sp, ireg, freg32, freg64)
}
}
impl<T> SetValue<T> for Slot
where
T: StoreToCells,
{
#[inline]
fn set_value(
dst: Self,
src: T,
sp: Sp,
ireg: Ireg,
freg32: Freg32,
freg64: Freg64,
) -> (Ireg, Freg32, Freg64) {
unsafe { sp.set::<T>(dst, src) };
(ireg, freg32, freg64)
}
}
#[inline]
pub fn set_slot_value<T, V>(dst: T, src: V, sp: Sp)
where
T: SetValue<V>,
{
_ = <T as SetValue<V>>::set_value(
dst,
src,
sp,
Ireg::default(),
Freg32::default(),
Freg64::default(),
);
}
#[inline]
#[must_use]
pub fn set_value<T, V>(
dst: T,
src: V,
sp: Sp,
ireg: Ireg,
freg32: Freg32,
freg64: Freg64,
) -> (Ireg, Freg32, Freg64)
where
T: SetValue<V>,
{
<T as SetValue<V>>::set_value(dst, src, sp, ireg, freg32, freg64)
}
pub fn exec_copy_span(sp: Sp, dst: SlotSpan, src: SlotSpan, len: u16) {
debug_assert_ne!(dst, src);
debug_assert!(len > 0);
let op = match dst.head() <= src.head() {
true => exec_copy_span_asc,
false => exec_copy_span_des,
};
op(sp, dst, src, len)
}
pub fn exec_copy_span_asc(sp: Sp, dst: SlotSpan, src: SlotSpan, len: u16) {
debug_assert!(dst.head() < src.head());
debug_assert!(len > 0);
let mut dst = dst.head();
let mut src = src.head();
let dst_end = dst.next_n(len);
while dst != dst_end {
let value: u64 = get_slot_value(src, sp);
set_slot_value(dst, value, sp);
dst = dst.next();
src = src.next();
}
}
pub fn exec_copy_span_des(sp: Sp, dst: SlotSpan, src: SlotSpan, len: u16) {
debug_assert!(dst.head() > src.head());
debug_assert!(len > 0);
let dst_end = dst.head();
let mut dst = dst.head().next_n(len);
let mut src = src.head().next_n(len);
while dst != dst_end {
dst = dst.prev();
src = src.prev();
let value: u64 = get_slot_value(src, sp);
set_slot_value(dst, value, sp);
}
}
#[inline]
pub fn is_default_memory(_instance: Inst, memory: ir::MemoryAddr) -> bool {
u32::from(memory) == 0
}
pub fn extract_mem0(inst: Inst) -> (Mem0Ptr, Mem0Len) {
let Some(addr) = (unsafe { inst.as_ptr().layout() }).memory_addr(0) else {
return (Mem0Ptr::from([].as_mut_ptr()), Mem0Len::from(0));
};
let Some(mem0) = (unsafe { inst.as_ptr().get_memory(addr) }) else {
unsafe { unreachable_unchecked!("missing memory at: {addr:?}") }
};
let mem0 = unsafe { mem0.as_ref() };
let mem0 = mem0.entity();
let mem0 = unsafe { &mut *mem0.as_ptr() }.data_mut();
let mem0_ptr = mem0.as_mut_ptr();
let mem0_len = mem0.len();
(Mem0Ptr::from(mem0_ptr), Mem0Len::from(mem0_len))
}
pub fn memory_slice(memory: &MemoryEntity, pos: usize, len: usize) -> Result<&[u8], TrapCode> {
memory
.data()
.get(pos..)
.and_then(|memory| memory.get(..len))
.ok_or(TrapCode::MemoryOutOfBounds)
}
pub fn memory_slice_mut(
memory: &mut MemoryEntity,
pos: usize,
len: usize,
) -> Result<&mut [u8], TrapCode> {
memory
.data_mut()
.get_mut(pos..)
.and_then(|memory| memory.get_mut(..len))
.ok_or(TrapCode::MemoryOutOfBounds)
}
trait LoadEntry<Addr> {
type Entry;
unsafe fn load_entry_ptr(self, addr: Addr) -> NonNull<Self::Entry>;
}
macro_rules! impl_load_entry_for_inst {
(
$(
ir::$addr:ident -> $handle:ident = $getter:ident
);* $(;)?
) => {
$(
impl LoadEntry<ir::$addr> for Inst {
type Entry = HandleAndEntity<$handle>;
#[inline]
unsafe fn load_entry_ptr(self, addr: ir::$addr) -> NonNull<Self::Entry> {
let addr = <$addr>::from(::core::primitive::u32::from(addr));
let Some(entry) = (unsafe { self.as_ptr().$getter(addr) }) else {
unsafe {
$crate::engine::utils::unreachable_unchecked!(
::core::concat!("missing ", ::core::stringify!($handle), " at: {:?}"),
addr,
)
}
};
entry
}
}
)*
};
}
impl_load_entry_for_inst! {
ir::GlobalAddr -> Global = get_global;
ir::MemoryAddr -> Memory = get_memory;
ir::TableAddr -> Table = get_table;
ir::FuncAddr -> Func = get_func;
ir::DataAddr -> DataSegment = get_data;
ir::ElemAddr -> ElementSegment = get_elem;
}
pub trait LoadEntity<Addr> {
type Entity;
unsafe fn load_entity_ptr(self, addr: Addr) -> NonNull<Self::Entity>;
unsafe fn load_entity_mut(self, _store: &mut PrunedStore, addr: Addr) -> &mut Self::Entity;
}
macro_rules! impl_load_entity_for_inst {
(
$(
ir::$addr:ident -> $handle:ident
);* $(;)?
) => {
$(
impl LoadEntity<ir::$addr> for Inst {
type Entity = <$handle as Handle>::Entity;
#[inline]
unsafe fn load_entity_ptr(self, addr: ir::$addr) -> NonNull<Self::Entity> {
unsafe { self.load_entry_ptr(addr).as_ref() }.entity()
}
#[inline]
unsafe fn load_entity_mut(self, _store: &mut PrunedStore, addr: ir::$addr) -> &mut Self::Entity {
unsafe { self.load_entity_ptr(addr).as_mut() }
}
}
)*
};
}
impl_load_entity_for_inst! {
ir::GlobalAddr -> Global;
ir::MemoryAddr -> Memory;
ir::TableAddr -> Table;
ir::FuncAddr -> Func;
ir::ElemAddr -> ElementSegment;
ir::DataAddr -> DataSegment;
}
impl LoadEntity<Table0> for Inst {
type Entity = TableEntity;
#[inline]
unsafe fn load_entity_ptr(self, _addr: Table0) -> NonNull<Self::Entity> {
let Some(entity) = (unsafe { self.as_ptr().get_table0() }) else {
unsafe { unreachable_unchecked!("missing table entity for table 0") }
};
entity
}
#[inline]
unsafe fn load_entity_mut(self, _store: &mut PrunedStore, addr: Table0) -> &mut Self::Entity {
unsafe { self.load_entity_ptr(addr).as_mut() }
}
}
pub trait LoadHandle<Addr> {
type Handle;
unsafe fn load_handle(self, addr: Addr) -> Self::Handle;
}
macro_rules! impl_load_handle_for_inst {
(
$(
ir::$addr:ident -> $handle:ident
);* $(;)?
) => {
$(
impl LoadHandle<ir::$addr> for Inst {
type Handle = $handle;
#[inline]
unsafe fn load_handle(self, addr: ir::$addr) -> Self::Handle {
let entry_ref = unsafe { self.load_entry_ptr(addr).as_ref() };
entry_ref.handle()
}
}
)*
};
}
impl_load_handle_for_inst! {
ir::MemoryAddr -> Memory;
ir::TableAddr -> Table;
ir::FuncAddr -> Func;
}
#[inline]
pub fn load_func_entry(inst: Inst, func: ir::FuncAddr) -> (Func, NonNull<FuncEntity>) {
let entry_ref = unsafe { inst.load_entry_ptr(func).as_ref() };
let handle = entry_ref.handle();
let entity = entry_ref.entity();
(handle, entity)
}
#[inline]
pub fn resolve_indirect_func<Idx, Table>(
index: Idx,
table: Table,
func_type: ir::FuncType,
store: &mut PrunedStore,
args: &mut Args,
) -> Result<(Func, NonNull<FuncEntity>), TrapCode>
where
Idx: GetValue<u64>,
Inst: LoadEntity<Table, Entity = TableEntity>,
{
let index = get_value(index, args.sp, args.ireg, args.freg32, args.freg64);
let table = args.fetch_table(store, table);
let rawref = table.get(index).ok_or(TrapCode::TableOutOfBounds)?;
debug_assert!(matches!(rawref.ty(), RefType::Func));
let funcref = <Nullable<Func>>::from_raw_parts(rawref.raw(), &*store);
let func = funcref.val().ok_or(TrapCode::IndirectCallToNull)?;
let func_entity = store.inner_mut().resolve_func_ptr(func);
let actual_fnty = unsafe { func_entity.as_ref() }.ty_dedup().repr_entity();
if actual_fnty != u32::from(func_type) {
return Err(TrapCode::BadSignature);
}
Ok((*func, func_entity))
}
pub fn update_instance(
instance: Inst,
new_instance: Inst,
mem0: Mem0Ptr,
mem0_len: Mem0Len,
) -> (Inst, Mem0Ptr, Mem0Len) {
if new_instance == instance {
return (instance, mem0, mem0_len);
}
let (mem0, mem0_len) = extract_mem0(new_instance);
(new_instance, mem0, mem0_len)
}
#[inline(always)]
pub fn call_func_entry(
store: &mut PrunedStore,
caller_ip: Ip,
caller_sp: Sp,
params: BoundedSlotSpan,
func: &FuncEntry,
instance: Option<Inst>,
) -> Control<(Ip, Sp), Break> {
let (callee_ip, len_local_slots, len_stack_slots) = compile_or_get_func_entry!(store, func);
let callee_sp = store
.stack_mut()
.push_frame(
caller_sp,
Some(caller_ip),
callee_ip,
params,
len_local_slots,
len_stack_slots,
instance,
)
.into_control()?;
Control::Continue((callee_ip, callee_sp))
}
#[inline(always)]
pub fn return_call_func_entry(
store: &mut PrunedStore,
caller_sp: Sp,
params: BoundedSlotSpan,
func: &FuncEntry,
instance: Option<Inst>,
) -> Control<(Ip, Sp), Break> {
let (callee_ip, len_local_slots, len_stack_slots) = compile_or_get_func_entry!(store, func);
let callee_sp = store
.stack_mut()
.replace_frame(
caller_sp,
callee_ip,
params,
len_local_slots,
len_stack_slots,
instance,
)
.into_control()?;
Control::Continue((callee_ip, callee_sp))
}
#[inline]
fn invoke_host(
store: &mut PrunedStore,
trampoline: Trampoline,
instance: Option<Inst>,
inout: InOutParams,
call_hooks: CallHooks,
) -> Result<(), Error> {
match store.call_host_func(trampoline, instance, inout, call_hooks) {
Ok(()) => {}
Err(StoreError::External(error)) => return Err(error),
Err(StoreError::Internal(error)) => unsafe {
unreachable_unchecked!(
"internal interpreter error while executing host function: {error}"
)
},
}
Ok(())
}
pub fn call_host(
store: &mut PrunedStore,
func: Func,
caller_ip: Option<Ip>,
host_func: HostFuncEntity,
params: BoundedSlotSpan,
instance: Option<Inst>,
call_hooks: CallHooks,
) -> Control<Sp, Break> {
debug_assert_eq!(params.len(), host_func.len_param_cells());
let trampoline = *host_func.trampoline();
let (sp, frame) = store
.stack_mut()
.prepare_host_frame(caller_ip, params, host_func.len_result_cells())
.into_control()?;
let inout = store.stack_mut().host_inout(frame);
if let Err(error) = invoke_host(store, trampoline, instance, inout, call_hooks) {
done!(store, DoneReason::host_error(error, func, params.span()))
}
Control::Continue(sp)
}
pub fn return_call_host(
store: &mut PrunedStore,
func: Func,
host_func: HostFuncEntity,
params: BoundedSlotSpan,
instance: Inst,
) -> Control<(Ip, Sp, Inst), Break> {
debug_assert_eq!(params.len(), host_func.len_param_cells());
let trampoline = *host_func.trampoline();
let (control, frame) = store
.stack_mut()
.return_prepare_host_frame(params, host_func.len_result_cells(), instance)
.into_control()?;
let inout = store.stack_mut().host_inout(frame);
if let Err(error) = invoke_host(store, trampoline, Some(instance), inout, CallHooks::Call) {
let reason = match control {
Control::Continue(_) => DoneReason::host_error(error, func, params.span()),
Control::Break(_) => DoneReason::error(error),
};
done!(store, reason)
}
match control {
Control::Continue((ip, sp, instance)) => Control::Continue((ip, sp, instance)),
Control::Break(sp) => done!(store, DoneReason::Return(sp)),
}
}
#[inline]
#[expect(clippy::too_many_arguments)]
pub fn call_wasm_or_host(
store: &mut PrunedStore,
caller_ip: Ip,
caller_sp: Sp,
func: Func,
func_entity: NonNull<FuncEntity>,
params: BoundedSlotSpan,
mem0: Mem0Ptr,
mem0_len: Mem0Len,
instance: Inst,
) -> Control<(Ip, Sp, Mem0Ptr, Mem0Len, Inst), Break> {
let func_entity = unsafe { func_entity.as_ref() };
let wasm_func = match func_entity {
FuncEntity::Wasm(wasm_func) => wasm_func,
FuncEntity::Host(host_func) => {
let sp = call_host(
store,
func,
Some(caller_ip),
*host_func,
params,
Some(instance),
CallHooks::Call,
)?;
let (mem0, mem0_len) = extract_mem0(instance);
return Control::Continue((caller_ip, sp, mem0, mem0_len, instance));
}
};
let callee_instance: Inst = wasm_func.instance();
let (callee_ip, callee_sp) = call_func_entry(
store,
caller_ip,
caller_sp,
params,
wasm_func.func_entry(),
Some(callee_instance),
)?;
let (instance, mem0, mem0_len) = update_instance(instance, callee_instance, mem0, mem0_len);
Control::Continue((callee_ip, callee_sp, mem0, mem0_len, instance))
}
#[inline]
#[expect(clippy::too_many_arguments)]
pub fn return_call_wasm_or_host(
store: &mut PrunedStore,
caller_sp: Sp,
func: Func,
func_entity: NonNull<FuncEntity>,
params: BoundedSlotSpan,
mem0: Mem0Ptr,
mem0_len: Mem0Len,
instance: Inst,
) -> Control<(Ip, Sp, Mem0Ptr, Mem0Len, Inst), Break> {
let func_entity = unsafe { func_entity.as_ref() };
let wasm_func = match func_entity {
FuncEntity::Wasm(wasm_func) => wasm_func,
FuncEntity::Host(host_func) => {
let (callee_ip, sp, new_instance) =
return_call_host(store, func, *host_func, params, instance)?;
let (mem0, mem0_len) = extract_mem0(new_instance);
return Control::Continue((callee_ip, sp, mem0, mem0_len, new_instance));
}
};
let callee_instance: Inst = wasm_func.instance();
let (callee_ip, callee_sp) = return_call_func_entry(
store,
caller_sp,
params,
wasm_func.func_entry(),
Some(callee_instance),
)?;
let (instance, mem0, mem0_len) = update_instance(instance, callee_instance, mem0, mem0_len);
Control::Continue((callee_ip, callee_sp, mem0, mem0_len, instance))
}