xwasmi/
func.rs

1#[allow(unused_imports)]
2use alloc::prelude::v1::*;
3use alloc::rc::{Rc, Weak};
4use core::fmt;
5use host::Externals;
6use isa;
7use module::ModuleInstance;
8use xwasm::elements::Local;
9use runner::{check_function_args, Interpreter, InterpreterState};
10use types::ValueType;
11use value::RuntimeValue;
12use {Signature, Trap};
13
14/// Reference to a function (See [`FuncInstance`] for details).
15///
16/// This reference has a reference-counting semantics.
17///
18/// [`FuncInstance`]: struct.FuncInstance.html
19#[derive(Clone, Debug)]
20pub struct FuncRef(Rc<FuncInstance>);
21
22impl ::core::ops::Deref for FuncRef {
23    type Target = FuncInstance;
24    fn deref(&self) -> &FuncInstance {
25        &self.0
26    }
27}
28
29/// Runtime representation of a function.
30///
31/// Functions are the unit of organization of code in WebAssembly. Each function takes a sequence of values
32/// as parameters and either optionally return a value or trap.
33/// Functions can call other function including itself (i.e recursive calls are allowed) and imported functions
34/// (i.e functions defined in another module or by the host environment).
35///
36/// Functions can be defined either:
37///
38/// - by a xwasm module,
39/// - by the host environment and passed to a xwasm module as an import.
40///   See more in [`Externals`].
41///
42/// [`Externals`]: trait.Externals.html
43pub struct FuncInstance(FuncInstanceInternal);
44
45#[derive(Clone)]
46pub(crate) enum FuncInstanceInternal {
47    Internal {
48        signature: Rc<Signature>,
49        module: Weak<ModuleInstance>,
50        body: Rc<FuncBody>,
51    },
52    Host {
53        signature: Signature,
54        host_func_index: usize,
55    },
56}
57
58impl fmt::Debug for FuncInstance {
59    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
60        match self.as_internal() {
61            &FuncInstanceInternal::Internal { ref signature, .. } => {
62                // We can't write description of self.module here, because it generate
63                // debug string for function instances and this will lead to infinite loop.
64                write!(f, "Internal {{ signature={:?} }}", signature,)
65            }
66            &FuncInstanceInternal::Host { ref signature, .. } => {
67                write!(f, "Host {{ signature={:?} }}", signature)
68            }
69        }
70    }
71}
72
73impl FuncInstance {
74    /// Allocate a function instance for a host function.
75    ///
76    /// When this function instance will be called by the xwasm code,
77    /// the instance of [`Externals`] will be invoked by calling `invoke_index`
78    /// with specified `host_func_index` here.
79    /// This call will be made with the `signature` provided here.
80    ///
81    /// [`Externals`]: trait.Externals.html
82    pub fn alloc_host(signature: Signature, host_func_index: usize) -> FuncRef {
83        let func = FuncInstanceInternal::Host {
84            signature,
85            host_func_index,
86        };
87        FuncRef(Rc::new(FuncInstance(func)))
88    }
89
90    /// Returns [signature] of this function instance.
91    ///
92    /// This function instance can only be called with matching signatures.
93    ///
94    /// [signature]: struct.Signature.html
95    pub fn signature(&self) -> &Signature {
96        match *self.as_internal() {
97            FuncInstanceInternal::Internal { ref signature, .. } => signature,
98            FuncInstanceInternal::Host { ref signature, .. } => signature,
99        }
100    }
101
102    pub(crate) fn as_internal(&self) -> &FuncInstanceInternal {
103        &self.0
104    }
105
106    pub(crate) fn alloc_internal(
107        module: Weak<ModuleInstance>,
108        signature: Rc<Signature>,
109        body: FuncBody,
110    ) -> FuncRef {
111        let func = FuncInstanceInternal::Internal {
112            signature,
113            module: module,
114            body: Rc::new(body),
115        };
116        FuncRef(Rc::new(FuncInstance(func)))
117    }
118
119    pub(crate) fn body(&self) -> Option<Rc<FuncBody>> {
120        match *self.as_internal() {
121            FuncInstanceInternal::Internal { ref body, .. } => Some(Rc::clone(body)),
122            FuncInstanceInternal::Host { .. } => None,
123        }
124    }
125
126    /// Invoke this function.
127    ///
128    /// # Errors
129    ///
130    /// Returns `Err` if `args` types is not match function [`signature`] or
131    /// if [`Trap`] at execution time occured.
132    ///
133    /// [`signature`]: #method.signature
134    /// [`Trap`]: #enum.Trap.html
135    pub fn invoke<E: Externals>(
136        func: &FuncRef,
137        args: &[RuntimeValue],
138        externals: &mut E,
139    ) -> Result<Option<RuntimeValue>, Trap> {
140        check_function_args(func.signature(), &args)?;
141        match *func.as_internal() {
142            FuncInstanceInternal::Internal { .. } => {
143                let mut interpreter = Interpreter::new(func, args)?;
144                interpreter.start_execution(externals)
145            }
146            FuncInstanceInternal::Host {
147                ref host_func_index,
148                ..
149            } => externals.invoke_index(*host_func_index, args.into()),
150        }
151    }
152
153    /// Invoke the function, get a resumable handle. This handle can then be used to [`start_execution`]. If a
154    /// Host trap happens, caller can use [`resume_execution`] to feed the expected return value back in, and then
155    /// continue the execution.
156    ///
157    /// This is an experimental API, and this functionality may not be available in other WebAssembly engines.
158    ///
159    /// # Errors
160    ///
161    /// Returns `Err` if `args` types is not match function [`signature`].
162    ///
163    /// [`signature`]: #method.signature
164    /// [`Trap`]: #enum.Trap.html
165    /// [`start_execution`]: struct.FuncInvocation.html#method.start_execution
166    /// [`resume_execution`]: struct.FuncInvocation.html#method.resume_execution
167    pub fn invoke_resumable<'args>(
168        func: &FuncRef,
169        args: &'args [RuntimeValue],
170    ) -> Result<FuncInvocation<'args>, Trap> {
171        check_function_args(func.signature(), &args)?;
172        match *func.as_internal() {
173            FuncInstanceInternal::Internal { .. } => {
174                let interpreter = Interpreter::new(func, args)?;
175                Ok(FuncInvocation {
176                    kind: FuncInvocationKind::Internal(interpreter),
177                })
178            }
179            FuncInstanceInternal::Host {
180                ref host_func_index,
181                ..
182            } => Ok(FuncInvocation {
183                kind: FuncInvocationKind::Host {
184                    args,
185                    host_func_index: *host_func_index,
186                    finished: false,
187                },
188            }),
189        }
190    }
191}
192
193/// A resumable invocation error.
194#[derive(Debug)]
195pub enum ResumableError {
196    /// Trap happened.
197    Trap(Trap),
198    /// The invocation is not resumable.
199    ///
200    /// Invocations are only resumable if a host function is called, and the host function returns a trap of `Host` kind. For other cases, this error will be returned. This includes:
201    /// - The invocation is directly a host function.
202    /// - The invocation has not been started.
203    /// - The invocation returns normally or returns any trap other than `Host` kind.
204    ///
205    /// This error is returned by [`resume_execution`].
206    ///
207    /// [`resume_execution`]: struct.FuncInvocation.html#method.resume_execution
208    NotResumable,
209    /// The invocation has already been started.
210    ///
211    /// This error is returned by [`start_execution`].
212    ///
213    /// [`start_execution`]: struct.FuncInvocation.html#method.start_execution
214    AlreadyStarted,
215}
216
217impl From<Trap> for ResumableError {
218    fn from(trap: Trap) -> Self {
219        ResumableError::Trap(trap)
220    }
221}
222
223/// A resumable invocation handle. This struct is returned by `FuncInstance::invoke_resumable`.
224pub struct FuncInvocation<'args> {
225    kind: FuncInvocationKind<'args>,
226}
227
228enum FuncInvocationKind<'args> {
229    Internal(Interpreter),
230    Host {
231        args: &'args [RuntimeValue],
232        host_func_index: usize,
233        finished: bool,
234    },
235}
236
237impl<'args> FuncInvocation<'args> {
238    /// Whs this invocation is currently resumable.
239    pub fn is_resumable(&self) -> bool {
240        match &self.kind {
241            &FuncInvocationKind::Internal(ref interpreter) => interpreter.state().is_resumable(),
242            &FuncInvocationKind::Host { .. } => false,
243        }
244    }
245
246    /// If the invocation is resumable, the expected return value type to be feed back in.
247    pub fn resumable_value_type(&self) -> Option<ValueType> {
248        match &self.kind {
249            &FuncInvocationKind::Internal(ref interpreter) => match interpreter.state() {
250                &InterpreterState::Resumable(ref value_type) => value_type.clone(),
251                _ => None,
252            },
253            &FuncInvocationKind::Host { .. } => None,
254        }
255    }
256
257    /// Start the invocation execution.
258    pub fn start_execution<'externals, E: Externals + 'externals>(
259        &mut self,
260        externals: &'externals mut E,
261    ) -> Result<Option<RuntimeValue>, ResumableError> {
262        match self.kind {
263            FuncInvocationKind::Internal(ref mut interpreter) => {
264                if interpreter.state() != &InterpreterState::Initialized {
265                    return Err(ResumableError::AlreadyStarted);
266                }
267                Ok(interpreter.start_execution(externals)?)
268            }
269            FuncInvocationKind::Host {
270                ref args,
271                ref mut finished,
272                ref host_func_index,
273            } => {
274                if *finished {
275                    return Err(ResumableError::AlreadyStarted);
276                }
277                *finished = true;
278                Ok(externals.invoke_index(*host_func_index, args.clone().into())?)
279            }
280        }
281    }
282
283    /// Resume an execution if a previous trap of Host kind happened.
284    ///
285    /// `return_val` must be of the value type [`resumable_value_type`], defined by the host function import. Otherwise,
286    /// `UnexpectedSignature` trap will be returned. The current invocation must also be resumable
287    /// [`is_resumable`]. Otherwise, a `NotResumable` error will be returned.
288    ///
289    /// [`resumable_value_type`]: #method.resumable_value_type
290    /// [`is_resumable`]: #method.is_resumable
291    pub fn resume_execution<'externals, E: Externals + 'externals>(
292        &mut self,
293        return_val: Option<RuntimeValue>,
294        externals: &'externals mut E,
295    ) -> Result<Option<RuntimeValue>, ResumableError> {
296        use crate::TrapKind;
297
298        if return_val.map(|v| v.value_type()) != self.resumable_value_type() {
299            return Err(ResumableError::Trap(Trap::new(
300                TrapKind::UnexpectedSignature,
301            )));
302        }
303
304        match &mut self.kind {
305            FuncInvocationKind::Internal(interpreter) => {
306                if interpreter.state().is_resumable() {
307                    Ok(interpreter.resume_execution(return_val, externals)?)
308                } else {
309                    Err(ResumableError::AlreadyStarted)
310                }
311            }
312            FuncInvocationKind::Host { .. } => Err(ResumableError::NotResumable),
313        }
314    }
315}
316
317#[derive(Clone, Debug)]
318pub struct FuncBody {
319    pub locals: Vec<Local>,
320    pub code: isa::Instructions,
321}