wasmer_runtime_core_x/table/
anyfunc.rs

1use crate::{
2    error::CreationError,
3    instance::DynFunc,
4    sig_registry::SigRegistry,
5    structures::TypedIndex,
6    types::{FuncSig, TableDescriptor},
7    vm,
8};
9
10use std::convert::TryFrom;
11use std::{ptr, sync::Arc};
12
13enum AnyfuncInner<'a> {
14    Host {
15        ptr: *const vm::Func,
16        signature: Arc<FuncSig>,
17    },
18    Managed(DynFunc<'a>),
19}
20
21/// Anyfunc data type.
22pub struct Anyfunc<'a> {
23    inner: AnyfuncInner<'a>,
24}
25
26impl<'a> Anyfunc<'a> {
27    /// Create a new `Anyfunc`.
28    pub unsafe fn new<Sig>(func: *const vm::Func, signature: Sig) -> Self
29    where
30        Sig: Into<Arc<FuncSig>>,
31    {
32        Self {
33            inner: AnyfuncInner::Host {
34                ptr: func as _,
35                signature: signature.into(),
36            },
37        }
38    }
39}
40
41impl<'a> From<DynFunc<'a>> for Anyfunc<'a> {
42    fn from(function: DynFunc<'a>) -> Self {
43        Anyfunc {
44            inner: AnyfuncInner::Managed(function),
45        }
46    }
47}
48
49impl<'a> TryFrom<Anyfunc<'a>> for DynFunc<'a> {
50    type Error = ();
51
52    fn try_from(anyfunc: Anyfunc<'a>) -> Result<Self, Self::Error> {
53        match anyfunc.inner {
54            AnyfuncInner::Managed(df) => Ok(df),
55            _ => Err(()),
56        }
57    }
58}
59
60/*
61// TODO: implement this when `vm::Anyfunc` is updated (aka avoiding the linear scan in `wrap`)
62impl<'a, Args: WasmTypeList, Rets: WasmTypeList> TryFrom<Anyfunc<'a>> for Func<'a, Args, Rets> {
63    type Error = ();
64
65    fn try_from(anyfunc: Anyfunc<'a>) -> Result<Self, Self::Error> {
66        match anyfunc.inner {
67            AnyfuncInner::Host {
68                ptr,
69                ctx,
70                signature,
71            } => {
72                // TODO: return more specific error
73                let ptr = NonNull::new(ptr as _).ok_or(())?;
74                if signature.params() != Args::types() || signature.returns() != Rets::types() {
75                    // TODO: return more specific error
76                    return Err(());
77                }
78                let wasm = todo!("Figure out how to get typed_func::Wasm");
79                // TODO: handle func_env
80                let func_env = None;
81                Ok(unsafe { Func::from_raw_parts(wasm, ptr, func_env, ctx) })
82            }
83            _ => Err(()),
84        }
85    }
86}
87*/
88
89pub struct AnyfuncTable {
90    pub(crate) backing: Vec<vm::Anyfunc>,
91    max: Option<u32>,
92}
93
94impl AnyfuncTable {
95    pub fn new(
96        desc: TableDescriptor,
97        local: &mut vm::LocalTable,
98    ) -> Result<Box<Self>, CreationError> {
99        let initial_table_backing_len = desc.minimum as usize;
100
101        let mut storage = Box::new(AnyfuncTable {
102            backing: vec![vm::Anyfunc::null(); initial_table_backing_len],
103            max: desc.maximum,
104        });
105
106        let storage_ptr: *mut AnyfuncTable = &mut *storage;
107
108        local.base = storage.backing.as_mut_ptr() as *mut u8;
109        local.count = storage.backing.len();
110        local.table = storage_ptr as *mut ();
111
112        Ok(storage)
113    }
114
115    pub fn current_size(&self) -> u32 {
116        self.backing.len() as u32
117    }
118
119    pub fn internal_buffer(&mut self) -> &mut [vm::Anyfunc] {
120        &mut self.backing
121    }
122
123    pub fn grow(&mut self, delta: u32, local: &mut vm::LocalTable) -> Option<u32> {
124        let starting_len = self.backing.len() as u32;
125
126        let new_len = starting_len.checked_add(delta)?;
127
128        if let Some(max) = self.max {
129            if new_len > max {
130                return None;
131            }
132        }
133
134        self.backing.resize(new_len as usize, vm::Anyfunc::null());
135
136        local.base = self.backing.as_mut_ptr() as *mut u8;
137        local.count = self.backing.len();
138
139        Some(starting_len)
140    }
141
142    // hidden and `pub(crate)` due to incomplete implementation (blocked on `wrap` issue)
143    #[doc(hidden)]
144    /// Get The vm::AnyFunc at the given index.
145    pub(crate) fn get<'outer_table>(&self, index: u32) -> Option<Anyfunc<'outer_table>> {
146        let vm_any_func = self.backing.get(index as usize)?;
147        let signature = SigRegistry.lookup_signature(vm_any_func.sig_id.into());
148        // TODO: this function should take a generic type param indicating what type of
149        // anyfunc we want `host` or `managed` (or perhaps we should just return DynFunc/Func directly here).
150        //
151        // The issue with the current implementation is that through `StorableInTable`, we'll call
152        // `TryFrom<Anyfuc> for Dynfunc` which will always fail because we always return a `Host` function here.
153        Some(Anyfunc {
154            inner: AnyfuncInner::Host {
155                ptr: vm_any_func.func,
156                signature,
157            },
158        })
159    }
160
161    pub fn set(&mut self, index: u32, element: Anyfunc) -> Result<(), ()> {
162        if let Some(slot) = self.backing.get_mut(index as usize) {
163            let anyfunc = match element.inner {
164                AnyfuncInner::Host { ptr, signature } => {
165                    let sig_index = SigRegistry.lookup_sig_index(signature);
166                    let sig_id = vm::SigId(sig_index.index() as u32);
167
168                    vm::Anyfunc {
169                        func: ptr,
170                        ctx: ptr::null_mut(),
171                        sig_id,
172                    }
173                }
174                AnyfuncInner::Managed(ref func) => {
175                    let sig_index = SigRegistry.lookup_sig_index(Arc::clone(&func.signature));
176                    let sig_id = vm::SigId(sig_index.index() as u32);
177
178                    vm::Anyfunc {
179                        func: func.raw(),
180                        ctx: func.instance_inner.vmctx,
181                        sig_id,
182                    }
183                }
184            };
185
186            *slot = anyfunc;
187
188            Ok(())
189        } else {
190            Err(())
191        }
192    }
193}