virtual_machine/
manager.rs

1//! Virtual Machine Manager - Global singleton for WASM runtime management.
2
3//!
4//! The Manager provides a centralized interface for initializing the WASM runtime,
5//! registering host functions, and executing WASM modules. It maintains a global
6//! singleton instance that can be accessed throughout the system.
7
8use core::{ffi::CStr, mem::forget};
9
10use alloc::{string::ToString, vec, vec::Vec};
11use file_system::UniqueFileIdentifier;
12use synchronization::once_lock::OnceLock;
13use wamr_rust_sdk::{
14    sys::{wasm_runtime_is_xip_file, wasm_runtime_load, wasm_runtime_register_module},
15    value::WasmValue,
16};
17
18use crate::{Error, Instance, Module, Registrable, Result, Runtime};
19
20/// Global singleton instance of the Virtual Machine Manager
21static MANAGER_INSTANCE: OnceLock<Manager> = OnceLock::new();
22
23/// Initialize the Virtual Machine Manager with a set of registrable host functions.
24///
25/// This function must be called once before any WASM operations can be performed.
26/// It creates a global singleton Manager instance that will persist for the
27/// lifetime of the application.
28///
29/// # Arguments
30///
31/// * `Registrables` - Array of traits implementing host functions that can be called from WASM
32///
33/// # Returns
34///
35/// A static reference to the initialized Manager instance
36///
37/// # Example
38///
39/// ```rust,ignore
40/// let manager = Initialize(&[&MyHostFunctions]);
41/// ```
42pub fn initialize(registrables: &[&dyn Registrable]) -> &'static Manager {
43    MANAGER_INSTANCE
44        .get_or_init(|| Manager::new(registrables).expect("Cannot create virtual machine manager"));
45
46    get_instance()
47}
48
49/// Get a reference to the initialized Virtual Machine Manager instance.
50///
51/// # Panics
52///
53/// Panics if called before `Initialize()` has been called.
54///
55/// # Returns
56///
57/// A static reference to the Manager instance
58pub fn get_instance() -> &'static Manager {
59    MANAGER_INSTANCE
60        .try_get()
61        .expect("Cannot get virtual machine manager instance before initialization")
62}
63
64/// The Virtual Machine Manager handles WASM runtime lifecycle and module execution.
65///
66/// This struct encapsulates the WASM runtime and provides high-level operations
67/// for executing WASM modules with proper I/O redirection and resource management.
68pub struct Manager {
69    runtime: Runtime,
70}
71
72unsafe impl Send for Manager {}
73
74unsafe impl Sync for Manager {}
75
76impl Manager {
77    /// Create a new Virtual Machine Manager with the given registrable host functions.
78    ///
79    /// This function initializes the WASM runtime, registers all provided host functions,
80    /// and pre-loads any modules that the registrables provide.
81    ///
82    /// # Arguments
83    ///
84    /// * `Registrables` - Array of objects implementing host functions and optionally providing WASM modules
85    ///
86    /// # Returns
87    ///
88    /// A new Manager instance or an error if initialization fails
89    ///
90    /// # Errors
91    ///
92    /// Returns an error if:
93    /// - Runtime initialization fails
94    /// - Host function registration fails  
95    /// - Module loading fails
96    pub fn new(registrables: &[&dyn Registrable]) -> Result<Self> {
97        let mut runtime_builder = Runtime::builder();
98
99        for registrable in registrables {
100            runtime_builder = runtime_builder.register(*registrable);
101        }
102
103        let runtime = runtime_builder.build()?;
104
105        let manager = Self { runtime };
106
107        for registrable in registrables {
108            if let Some(module_binary) = registrable.get_binary() {
109                manager.load_module(module_binary, registrable.is_xip(), registrable.get_name())?;
110            }
111        }
112
113        Ok(manager)
114    }
115
116    /// Load a WASM module from a buffer for execution.
117    ///
118    /// This method loads a WASM module into the runtime, either as a regular module
119    /// or as an XIP (execute-in-place) module for AOT compiled binaries.
120    ///
121    /// # Arguments
122    ///
123    /// * `Buffer` - The WASM module bytecode
124    /// * `XIP` - Whether this is an XIP AOT compiled module
125    /// * `Name` - Name to register the module under
126    ///
127    /// # Returns
128    ///
129    /// Success or an error if loading fails
130    ///
131    /// # Errors
132    ///
133    /// Returns an error if the module is not an XIP AOT compiled module or if the module cannot be loaded from the buffer.
134    fn load_module(&self, buffer: &[u8], xip: bool, name: &str) -> Result<()> {
135        if unsafe { xip && !wasm_runtime_is_xip_file(buffer.as_ptr(), buffer.len() as u32) } {
136            return Err(Error::InvalidModule);
137        }
138
139        unsafe {
140            let mut buffer = if xip {
141                Vec::from_raw_parts(buffer.as_ptr() as *mut u8, buffer.len(), buffer.len())
142            } else {
143                buffer.to_vec()
144            };
145
146            let mut error_buffer = [0_i8; 128];
147
148            let module = wasm_runtime_load(
149                buffer.as_mut_ptr(),
150                buffer.len() as u32,
151                error_buffer.as_mut_ptr(),
152                error_buffer.len() as u32,
153            );
154
155            if module.is_null() {
156                return Err(Error::CompilationError(
157                    CStr::from_ptr(error_buffer.as_ptr())
158                        .to_string_lossy()
159                        .to_string(),
160                ));
161            }
162
163            if !wasm_runtime_register_module(
164                name.as_ptr() as *const i8,
165                module,
166                error_buffer.as_mut_ptr(),
167                error_buffer.len() as u32,
168            ) {
169                return Err(Error::InternalError);
170            }
171
172            forget(buffer);
173        }
174
175        Ok(())
176    }
177
178    /// Execute a WASM module with the specified I/O configuration.
179    ///
180    /// This is the main entry point for executing WASM modules. It creates a new
181    /// module instance, sets up the execution environment with proper I/O redirection,
182    /// and calls the module's main function.
183    ///
184    /// # Arguments
185    ///
186    /// * `Buffer` - The WASM module bytecode to execute
187    /// * `Stack_size` - Stack size in bytes for the WASM instance
188    /// * `Standard_in` - File identifier for standard input
189    /// * `Standard_out` - File identifier for standard output  
190    /// * `Standard_error` - File identifier for standard error
191    ///
192    /// # Returns
193    ///
194    /// The return values from the WASM module's main function
195    ///
196    /// # Errors
197    ///
198    /// Returns an error if module loading, instantiation, or execution fails
199    pub async fn execute(
200        &'static self,
201        buffer: Vec<u8>,
202        stack_size: usize,
203        standard_in: UniqueFileIdentifier,
204        standard_out: UniqueFileIdentifier,
205        standard_error: UniqueFileIdentifier,
206    ) -> Result<Vec<WasmValue>> {
207        abi::get_instance()
208            .call_abi(async || {
209                let module = Module::from_buffer(
210                    &self.runtime,
211                    buffer,
212                    "module",
213                    standard_in,
214                    standard_out,
215                    standard_error,
216                )
217                .await?;
218
219                let instance = Instance::new(&self.runtime, &module, stack_size).unwrap();
220
221                let result = instance.call_main(&vec![])?;
222
223                Ok(result)
224            })
225            .await
226    }
227}