1use crate::{
3 error::{VmError, WasmEdgeError},
4 ImportObject, Instance, Module, Store, WasmEdgeResult, WasmValue,
5};
6use sys::AsInstance;
7use wasmedge_sys as sys;
8
9pub trait SyncInst: AsInstance {}
10impl<T> SyncInst for ImportObject<T> {}
11impl SyncInst for Instance {}
12
13#[derive(Debug)]
73pub struct Vm<'inst, T: ?Sized + SyncInst> {
74 store: Store<'inst, T>,
75 active_instance: Option<sys::Instance>,
76}
77impl<'inst, T: ?Sized + SyncInst> Vm<'inst, T> {
78 pub fn new(store: Store<'inst, T>) -> Self {
79 Vm {
81 store,
82 active_instance: None,
83 }
84 }
85
86 pub fn register_module(
99 &mut self,
100 mod_name: Option<&str>,
101 module: Module,
102 ) -> WasmEdgeResult<&mut Self> {
103 match mod_name {
104 Some(name) => {
105 self.store.register_named_module(name, &module)?;
106 }
107 None => {
108 self.active_instance = Some(self.store.register_active_module(&module)?);
109 }
110 };
111
112 Ok(self)
113 }
114
115 pub fn run_func(
129 &mut self,
130 mod_name: Option<&str>,
131 func_name: impl AsRef<str>,
132 args: impl IntoIterator<Item = WasmValue>,
133 ) -> WasmEdgeResult<Vec<WasmValue>> {
134 let (mut func, executor) = match mod_name {
135 Some(mod_name) => {
136 if let Some((inst, executor)) = self.store.get_instance_and_executor(mod_name) {
137 (inst.get_func_mut(func_name.as_ref())?, executor)
138 } else if let Some((wasm_mod, executor)) =
139 self.store.get_named_wasm_and_executor(mod_name)
140 {
141 (wasm_mod.get_func_mut(func_name.as_ref())?, executor)
142 } else {
143 return Err(Box::new(WasmEdgeError::Vm(VmError::NotFoundModule(
144 mod_name.into(),
145 ))));
146 }
147 }
148 None => {
149 let active_inst = self
150 .active_instance
151 .as_mut()
152 .ok_or(Box::new(WasmEdgeError::Vm(VmError::NotFoundActiveModule)))?;
153
154 (
155 active_inst.get_func_mut(func_name.as_ref())?,
156 self.store.executor(),
157 )
158 }
159 };
160 executor.call_func(&mut func, args)
161 }
162
163 #[cfg(all(target_os = "linux", not(target_env = "musl")))]
179 pub fn run_func_with_timeout(
180 &mut self,
181 mod_name: Option<&str>,
182 func_name: impl AsRef<str>,
183 args: impl IntoIterator<Item = WasmValue>,
184 timeout: std::time::Duration,
185 ) -> WasmEdgeResult<Vec<WasmValue>> {
186 let (mut func, executor) = match mod_name {
187 Some(mod_name) => {
188 if let Some((inst, executor)) = self.store.get_instance_and_executor(mod_name) {
189 (inst.get_func_mut(func_name.as_ref())?, executor)
190 } else if let Some((wasm_mod, executor)) =
191 self.store.get_named_wasm_and_executor(mod_name)
192 {
193 (wasm_mod.get_func_mut(func_name.as_ref())?, executor)
194 } else {
195 return Err(Box::new(WasmEdgeError::Vm(VmError::NotFoundModule(
196 mod_name.into(),
197 ))));
198 }
199 }
200 None => {
201 let active_inst = self
202 .active_instance
203 .as_mut()
204 .ok_or(Box::new(WasmEdgeError::Vm(VmError::NotFoundActiveModule)))?;
205
206 (
207 active_inst.get_func_mut(func_name.as_ref())?,
208 self.store.executor(),
209 )
210 }
211 };
212 executor.call_func_with_timeout(&mut func, args, timeout)
213 }
214
215 pub fn store(&self) -> &Store<'inst, T> {
217 &self.store
218 }
219
220 pub fn store_mut(&mut self) -> &mut Store<'inst, T> {
222 &mut self.store
223 }
224
225 pub fn active_module(&self) -> Option<&Instance> {
231 self.active_instance.as_ref()
232 }
233
234 pub fn active_module_mut(&mut self) -> Option<&mut Instance> {
240 self.active_instance.as_mut()
241 }
242
243 pub fn contains_module(&self, mod_name: impl AsRef<str>) -> bool {
250 self.store.contains(mod_name)
251 }
252
253 pub fn named_instance_count(&self) -> usize {
255 self.store.named_instance_count()
256 }
257
258 pub fn instance_names(&self) -> Vec<String> {
260 self.store.instance_names()
261 }
262}
263
264#[cfg(test)]
265mod tests {
266 use std::collections::HashMap;
267
268 use wasmedge_types::wat2wasm;
269
270 use super::*;
271 use crate::{params, WasmVal};
272
273 #[test]
274 #[cfg(target_os = "linux")]
275 fn test_vmbuilder() -> Result<(), Box<dyn std::error::Error>> {
277 use crate::{params, plugin::PluginManager};
278
279 PluginManager::load(None)?;
281
282 PluginManager::names().iter().for_each(|name| {
283 println!("plugin name: {}", name);
284 });
285
286 let wasm_app_file = "examples/wasmedge-sys/data/test_crypto.wasm";
287
288 let mut wasi = crate::wasi::WasiModule::create(None, None, None).unwrap();
289 let mut wasi_crypto_asymmetric_common =
290 PluginManager::load_wasi_crypto_asymmetric_common().unwrap();
291 let mut wasi_crypto_signatures = PluginManager::load_wasi_crypto_signatures().unwrap();
292 let mut wasi_crypto_symmetric = PluginManager::load_wasi_crypto_symmetric().unwrap();
293
294 let mut instances = HashMap::new();
295 instances.insert(wasi.name().to_string(), wasi.as_mut());
296 instances.insert(
297 wasi_crypto_asymmetric_common.name().unwrap(),
298 &mut wasi_crypto_asymmetric_common,
299 );
300 instances.insert(
301 wasi_crypto_signatures.name().unwrap(),
302 &mut wasi_crypto_signatures,
303 );
304 instances.insert(
305 wasi_crypto_symmetric.name().unwrap(),
306 &mut wasi_crypto_symmetric,
307 );
308
309 let mut vm = Vm::new(Store::new(None, instances).unwrap());
310
311 let module = Module::from_file(None, &wasm_app_file).unwrap();
312
313 vm.register_module(Some("wasm-app"), module).unwrap();
314 vm.run_func(Some("wasm-app"), "_start", params!())?;
315
316 Ok(())
317 }
318
319 #[test]
320 fn test_vm_run_func_from_file() {
321 let mut vm =
323 Vm::new(Store::new(None, HashMap::<String, &mut dyn SyncInst>::new()).unwrap());
324
325 let file = std::env::current_dir()
327 .unwrap()
328 .join("examples/wasmedge-sys/data/fibonacci.wat");
329
330 let fib_module = Module::from_file(None, file).unwrap();
332 vm.register_module(None, fib_module).unwrap();
333 let result = vm.run_func(None, "fib", params!(10i32));
334 assert!(result.is_ok());
335 let returns = result.unwrap();
336 assert_eq!(returns.len(), 1);
337 assert_eq!(returns[0].to_i32(), 89);
338 }
339
340 #[test]
341 fn test_vm_run_func_from_bytes() {
342 let mut vm =
344 Vm::new(Store::new(None, HashMap::<String, &mut dyn SyncInst>::new()).unwrap());
345
346 let result = wat2wasm(
349 br#"(module
350 (export "fib" (func $fib))
351 (func $fib (param $n i32) (result i32)
352 (if
353 (i32.lt_s
354 (local.get $n)
355 (i32.const 2)
356 )
357 (then
358 (return (i32.const 1))
359 )
360 )
361 (return
362 (i32.add
363 (call $fib
364 (i32.sub
365 (local.get $n)
366 (i32.const 2)
367 )
368 )
369 (call $fib
370 (i32.sub
371 (local.get $n)
372 (i32.const 1)
373 )
374 )
375 )
376 )
377 )
378 )
379 "#,
380 );
381 assert!(result.is_ok());
382 let wasm_bytes = result.unwrap();
383
384 let fib_module = Module::from_bytes(None, wasm_bytes).unwrap();
386 vm.register_module(None, fib_module).unwrap();
387 let result = vm.run_func(None, "fib", params!(10i32));
388 assert!(result.is_ok());
389 let returns = result.unwrap();
390 assert_eq!(returns.len(), 1);
391 assert_eq!(returns[0].to_i32(), 89);
392 }
393
394 #[test]
395 fn test_vm_run_func_in_named_module_instance() {
396 let mut vm =
398 Vm::new(Store::new(None, HashMap::<String, &mut dyn SyncInst>::new()).unwrap());
399
400 let result = wat2wasm(
403 br#"(module
404 (export "fib" (func $fib))
405 (func $fib (param $n i32) (result i32)
406 (if
407 (i32.lt_s
408 (local.get $n)
409 (i32.const 2)
410 )
411 (then
412 (return (i32.const 1))
413 )
414 )
415 (return
416 (i32.add
417 (call $fib
418 (i32.sub
419 (local.get $n)
420 (i32.const 2)
421 )
422 )
423 (call $fib
424 (i32.sub
425 (local.get $n)
426 (i32.const 1)
427 )
428 )
429 )
430 )
431 )
432 )
433 "#,
434 );
435 assert!(result.is_ok());
436 let wasm_bytes = result.unwrap();
437 let fib_module = Module::from_bytes(None, wasm_bytes).unwrap();
438 vm.register_module(Some("extern"), fib_module).unwrap();
439 let result = vm.run_func(Some("extern"), "fib", params!(10));
441 assert!(result.is_ok());
442 let returns = result.unwrap();
443 assert_eq!(returns.len(), 1);
444 assert_eq!(returns[0].to_i32(), 89);
445 }
446}