wasmer/backend/sys/entities/
engine.rs

1//! Data types, functions and traits for `sys` runtime's `Engine` implementation.
2
3use std::{path::Path, sync::Arc};
4
5use shared_buffer::OwnedBuffer;
6pub use wasmer_compiler::{Artifact, BaseTunables, Engine, EngineBuilder, Tunables};
7use wasmer_types::{CompilationProgressCallback, DeserializeError, Features, target::Target};
8
9use crate::{BackendEngine, BackendModule};
10
11/// Get the default config for the sys Engine
12#[allow(unreachable_code)]
13#[cfg(feature = "compiler")]
14pub fn get_default_compiler_config() -> Option<Box<dyn wasmer_compiler::CompilerConfig>> {
15    cfg_if::cfg_if! {
16        if #[cfg(feature = "cranelift")] {
17            Some(Box::<wasmer_compiler_cranelift::Cranelift>::default())
18        } else if #[cfg(feature = "llvm")] {
19            Some(Box::<wasmer_compiler_llvm::LLVM>::default())
20        } else if #[cfg(feature = "singlepass")] {
21            Some(Box::<wasmer_compiler_singlepass::Singlepass>::default())
22        }
23        else {
24            None
25        }
26    }
27}
28
29/// Returns the default engine for the Sys engine
30pub fn default_engine() -> Engine {
31    #[cfg(feature = "compiler")]
32    fn get_engine() -> Engine {
33        if let Some(config) = get_default_compiler_config() {
34            EngineBuilder::new(config).engine()
35        } else {
36            EngineBuilder::headless().engine()
37        }
38    }
39
40    #[cfg(not(feature = "compiler"))]
41    fn get_engine() -> Engine {
42        EngineBuilder::headless().engine()
43    }
44
45    let mut engine = get_engine();
46    let tunables = BaseTunables::for_target(engine.target());
47    engine.set_tunables(tunables);
48    engine
49}
50
51/// The custom trait to access to all the `sys` function in the common
52/// engine.
53pub trait NativeEngineExt {
54    /// Create a new `Engine` with the given config
55    #[cfg(feature = "compiler")]
56    fn new(
57        compiler_config: Box<dyn wasmer_compiler::CompilerConfig>,
58        target: Target,
59        features: Features,
60    ) -> Self;
61
62    /// Create a headless `Engine`
63    ///
64    /// A headless engine is an engine without any compiler attached.
65    /// This is useful for assuring a minimal runtime for running
66    /// WebAssembly modules.
67    ///
68    /// For example, for running in IoT devices where compilers are very
69    /// expensive, or also to optimize startup speed.
70    ///
71    /// # Important
72    ///
73    /// Headless engines can't compile or validate any modules,
74    /// they just take already processed Modules (via `Module::serialize`).
75    fn headless() -> Self;
76
77    /// Gets the target
78    fn target(&self) -> &Target;
79
80    /// Attach a Tunable to this engine
81    fn set_tunables(&mut self, tunables: impl Tunables + Send + Sync + 'static);
82
83    /// Get a reference to attached Tunable of this engine
84    fn tunables(&self) -> &dyn Tunables;
85
86    /// Compile a module from bytes with a progress callback.
87    ///
88    /// The callback is invoked with progress updates during the compilation process.
89    /// The callback also may return an error to abort the compilation.
90    ///
91    /// Signature of the callback function: `Fn(CompilationProgress) -> Result<(), UserAbort> + Send + Sync + 'static`
92    ///
93    /// # Aborting compilation
94    ///
95    /// The callback has to return a `Result<(), UserAbort>`.
96    ///
97    /// If the callback returns an error, the compilation will fail with a `CompileError::Aborted`.
98    fn new_module_with_progress(
99        &self,
100        bytes: &[u8],
101        on_progress: CompilationProgressCallback,
102    ) -> Result<crate::Module, wasmer_types::CompileError>;
103
104    /// Load a serialized WebAssembly module from a memory mapped file and deserialize it.
105    ///
106    /// NOTE: you should almost always prefer [`Self::deserialize_from_mmapped_file`].
107    ///
108    /// # Safety
109    /// See [`Artifact::deserialize_unchecked`].
110    unsafe fn deserialize_from_mmapped_file_unchecked(
111        &self,
112        file_ref: &Path,
113    ) -> Result<crate::Module, DeserializeError>;
114
115    /// Load a serialized WebAssembly module from a memory mapped file and deserialize it.
116    ///
117    /// # Safety
118    /// See [`Artifact::deserialize`].
119    unsafe fn deserialize_from_mmapped_file(
120        &self,
121        file_ref: &Path,
122    ) -> Result<crate::Module, DeserializeError>;
123}
124
125impl NativeEngineExt for crate::engine::Engine {
126    #[cfg(feature = "compiler")]
127    fn new(
128        compiler_config: Box<dyn wasmer_compiler::CompilerConfig>,
129        target: Target,
130        features: Features,
131    ) -> Self {
132        Self {
133            be: BackendEngine::Sys(Engine::new(compiler_config, target, features)),
134            id: Self::atomic_next_engine_id(),
135        }
136    }
137
138    fn headless() -> Self {
139        Self {
140            be: BackendEngine::Sys(Engine::headless()),
141            id: Self::atomic_next_engine_id(),
142        }
143    }
144
145    fn target(&self) -> &Target {
146        match self.be {
147            BackendEngine::Sys(ref s) => s.target(),
148            _ => panic!("Not a `sys` engine!"),
149        }
150    }
151
152    fn set_tunables(&mut self, tunables: impl Tunables + Send + Sync + 'static) {
153        match self.be {
154            BackendEngine::Sys(ref mut s) => s.set_tunables(tunables),
155            _ => panic!("Not a `sys` engine!"),
156        }
157    }
158
159    fn tunables(&self) -> &dyn Tunables {
160        match self.be {
161            BackendEngine::Sys(ref s) => s.tunables(),
162            _ => panic!("Not a `sys` engine!"),
163        }
164    }
165
166    fn new_module_with_progress(
167        &self,
168        bytes: &[u8],
169        on_progress: CompilationProgressCallback,
170    ) -> Result<crate::Module, wasmer_types::CompileError> {
171        crate::BackendModule::new_with_progress(self, bytes, on_progress).map(crate::Module)
172    }
173
174    unsafe fn deserialize_from_mmapped_file_unchecked(
175        &self,
176        file_ref: &Path,
177    ) -> Result<crate::Module, DeserializeError> {
178        let file = std::fs::File::open(file_ref)?;
179        let buffer = OwnedBuffer::from_file(&file)
180            .map_err(|e| DeserializeError::Generic(format!("{e:?}")))?;
181        let artifact = unsafe { Arc::new(Artifact::deserialize_unchecked(self.as_sys(), buffer)?) };
182        Ok(crate::Module(BackendModule::Sys(
183            super::module::Module::from_artifact(artifact),
184        )))
185    }
186
187    unsafe fn deserialize_from_mmapped_file(
188        &self,
189        file_ref: &Path,
190    ) -> Result<crate::Module, DeserializeError> {
191        let file = std::fs::File::open(file_ref)?;
192        let buffer = OwnedBuffer::from_file(&file)
193            .map_err(|e| DeserializeError::Generic(format!("{e:?}")))?;
194        let artifact = unsafe { Arc::new(Artifact::deserialize(self.as_sys(), buffer)?) };
195        Ok(crate::Module(BackendModule::Sys(
196            super::module::Module::from_artifact(artifact),
197        )))
198    }
199}
200
201impl crate::Engine {
202    /// Consume [`self`] into a [`crate::backend::sys::engine::Engine`].
203    pub fn into_sys(self) -> crate::backend::sys::engine::Engine {
204        match self.be {
205            BackendEngine::Sys(s) => s,
206            _ => panic!("Not a `sys` engine!"),
207        }
208    }
209
210    /// Convert a reference to [`self`] into a reference [`crate::backend::sys::engine::Engine`].
211    pub fn as_sys(&self) -> &crate::backend::sys::engine::Engine {
212        match self.be {
213            BackendEngine::Sys(ref s) => s,
214            _ => panic!("Not a `sys` engine!"),
215        }
216    }
217
218    /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::sys::engine::Engine`].
219    pub fn as_sys_mut(&mut self) -> &mut crate::backend::sys::engine::Engine {
220        match self.be {
221            BackendEngine::Sys(ref mut s) => s,
222            _ => panic!("Not a `sys` engine!"),
223        }
224    }
225
226    /// Return true if [`self`] is an engine from the `sys` runtime.
227    pub fn is_sys(&self) -> bool {
228        matches!(self.be, BackendEngine::Sys(_))
229    }
230}
231
232impl From<Engine> for crate::Engine {
233    fn from(value: Engine) -> Self {
234        Self {
235            be: BackendEngine::Sys(value),
236            id: Self::atomic_next_engine_id(),
237        }
238    }
239}
240
241impl From<&Engine> for crate::Engine {
242    fn from(value: &Engine) -> Self {
243        Self {
244            be: BackendEngine::Sys(value.cloned()),
245            id: Self::atomic_next_engine_id(),
246        }
247    }
248}
249
250impl From<EngineBuilder> for crate::Engine {
251    fn from(value: EngineBuilder) -> Self {
252        Self {
253            be: BackendEngine::Sys(value.engine()),
254            id: Self::atomic_next_engine_id(),
255        }
256    }
257}
258
259#[cfg(feature = "cranelift")]
260impl From<wasmer_compiler_cranelift::Cranelift> for crate::Engine {
261    fn from(value: wasmer_compiler_cranelift::Cranelift) -> Self {
262        Self {
263            be: BackendEngine::Sys(value.into()),
264            id: Self::atomic_next_engine_id(),
265        }
266    }
267}
268
269#[cfg(feature = "singlepass")]
270impl From<wasmer_compiler_singlepass::Singlepass> for crate::Engine {
271    fn from(value: wasmer_compiler_singlepass::Singlepass) -> Self {
272        Self {
273            be: BackendEngine::Sys(value.into()),
274            id: Self::atomic_next_engine_id(),
275        }
276    }
277}
278
279#[cfg(feature = "llvm")]
280impl From<wasmer_compiler_llvm::LLVM> for crate::Engine {
281    fn from(value: wasmer_compiler_llvm::LLVM) -> Self {
282        Self {
283            be: BackendEngine::Sys(value.into()),
284            id: Self::atomic_next_engine_id(),
285        }
286    }
287}