1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::cell::UnsafeCell;
4use core::mem;
5use core::pin::Pin;
6use core::ptr::{self, NonNull};
7
8use crate::environment::Environment;
9use crate::error::{Error, Result};
10use crate::function::Function;
11use crate::module::{Module, ParsedModule};
12use crate::utils::eq_cstr_str;
13
14type PinnedAnyClosure = Pin<Box<dyn core::any::Any + 'static>>;
15
16#[derive(Debug)]
18pub struct Runtime {
19 raw: NonNull<ffi::M3Runtime>,
20 environment: Environment,
21 closure_store: UnsafeCell<Vec<PinnedAnyClosure>>,
23 module_data: UnsafeCell<Vec<Box<[u8]>>>,
25}
26
27impl Runtime {
28 pub fn new(environment: &Environment, stack_size: u32) -> Result<Self> {
34 unsafe {
35 NonNull::new(ffi::m3_NewRuntime(
36 environment.as_ptr(),
37 stack_size,
38 ptr::null_mut(),
39 ))
40 }
41 .ok_or_else(Error::malloc_error)
42 .map(|raw| Runtime {
43 raw,
44 environment: environment.clone(),
45 closure_store: UnsafeCell::new(Vec::new()),
46 module_data: UnsafeCell::new(Vec::new()),
47 })
48 }
49
50 pub fn parse_and_load_module<'rt, TData: Into<Box<[u8]>>>(
52 &'rt self,
53 bytes: TData,
54 ) -> Result<Module<'rt>> {
55 Module::parse(&self.environment, bytes).and_then(|module| self.load_module(module))
56 }
57
58 pub fn load_module<'rt>(&'rt self, module: ParsedModule) -> Result<Module<'rt>> {
64 if &self.environment != module.environment() {
65 Err(Error::ModuleLoadEnvMismatch)
66 } else {
67 let raw_mod = module.as_ptr();
68 Error::from_ffi_res(unsafe { ffi::m3_LoadModule(self.raw.as_ptr(), raw_mod) })?;
69 unsafe { (*self.module_data.get()).push(module.take_data()) };
72
73 Ok(Module::from_raw(self, raw_mod))
74 }
75 }
76
77 pub fn find_function<'rt, ARGS, RET>(&'rt self, name: &str) -> Result<Function<'rt, ARGS, RET>>
82 where
83 ARGS: crate::WasmArgs,
84 RET: crate::WasmType,
85 {
86 self.modules()
87 .find_map(|module| match module.find_function::<ARGS, RET>(name) {
88 res @ (Ok(_) | Err(Error::InvalidFunctionSignature)) => Some(res),
89 _ => None,
90 })
91 .unwrap_or(Err(Error::FunctionNotFound))
92 }
93
94 pub fn find_module<'rt>(&'rt self, name: &str) -> Result<Module<'rt>> {
101 unsafe {
102 let mut module = ptr::NonNull::new(self.raw.as_ref().modules);
103 while let Some(raw_mod) = module {
104 if eq_cstr_str(raw_mod.as_ref().name, name) {
105 return Ok(Module::from_raw(self, raw_mod.as_ptr()));
106 }
107
108 module = ptr::NonNull::new(raw_mod.as_ref().next);
109 }
110 Err(Error::ModuleNotFound)
111 }
112 }
113
114 pub fn modules<'rt>(&'rt self) -> impl Iterator<Item = Module<'rt>> + 'rt {
116 let mut module = unsafe { ptr::NonNull::new(self.raw.as_ref().modules) };
119 core::iter::from_fn(move || {
120 let next = unsafe { module.and_then(|module| ptr::NonNull::new(module.as_ref().next)) };
121 mem::replace(&mut module, next).map(|raw| Module::from_raw(self, raw.as_ptr()))
122 })
123 }
124
125 pub fn resize_memory(&self, num_pages: u32) -> Result<()> {
131 Error::from_ffi_res(unsafe { ffi::ResizeMemory(self.raw.as_ptr(), num_pages) })
132 }
133
134 pub unsafe fn memory(&self) -> *const [u8] {
140 let len = (*self.mallocated()).length as usize;
141 let data = if len == 0 {
142 ptr::NonNull::dangling().as_ptr()
143 } else {
144 self.mallocated().offset(1).cast()
145 };
146 ptr::slice_from_raw_parts(data, len)
147 }
148
149 pub unsafe fn memory_mut(&self) -> *mut [u8] {
155 let len = (*self.mallocated()).length as usize;
156 let data = if len == 0 {
157 ptr::NonNull::dangling().as_ptr()
158 } else {
159 self.mallocated().offset(1).cast()
160 };
161 ptr::slice_from_raw_parts_mut(data, len)
162 }
163
164 pub fn stack(&self) -> *const [ffi::m3slot_t] {
166 unsafe {
167 ptr::slice_from_raw_parts(
168 self.raw.as_ref().stack.cast::<ffi::m3slot_t>(),
169 self.raw.as_ref().numStackSlots as usize,
170 )
171 }
172 }
173
174 pub fn stack_mut(&self) -> *mut [ffi::m3slot_t] {
176 unsafe {
177 ptr::slice_from_raw_parts_mut(
178 self.raw.as_ref().stack.cast::<ffi::m3slot_t>(),
179 self.raw.as_ref().numStackSlots as usize,
180 )
181 }
182 }
183}
184
185impl Runtime {
186 pub(crate) unsafe fn mallocated(&self) -> *mut ffi::M3MemoryHeader {
187 self.raw.as_ref().memory.mallocated
188 }
189
190 pub(crate) fn push_closure(&self, closure: PinnedAnyClosure) {
191 unsafe { (*self.closure_store.get()).push(closure) };
192 }
193
194 pub(crate) fn as_ptr(&self) -> ffi::IM3Runtime {
195 self.raw.as_ptr()
196 }
197}
198
199impl Drop for Runtime {
200 fn drop(&mut self) {
201 unsafe { ffi::m3_FreeRuntime(self.raw.as_ptr()) };
202 }
203}
204
205#[test]
206fn create_and_drop_rt() {
207 let env = Environment::new().expect("env alloc failure");
208 assert!(Runtime::new(&env, 1024 * 64).is_ok());
209}