wasmer_engine_object_file/
engine.rs

1use crate::ObjectFileArtifact;
2use std::io::Read;
3use std::path::Path;
4use std::sync::{Arc, Mutex};
5#[cfg(feature = "compiler")]
6use wasmer_compiler::Compiler;
7use wasmer_compiler::{CompileError, Target};
8use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables};
9#[cfg(feature = "compiler")]
10use wasmer_types::Features;
11use wasmer_types::FunctionType;
12use wasmer_vm::{SignatureRegistry, VMSharedSignatureIndex};
13
14/// A WebAssembly `ObjectFile` Engine.
15#[derive(Clone)]
16pub struct ObjectFileEngine {
17    inner: Arc<Mutex<ObjectFileEngineInner>>,
18    /// The target for the compiler
19    target: Arc<Target>,
20    engine_id: EngineId,
21}
22
23impl ObjectFileEngine {
24    /// Create a new `ObjectFileEngine` with the given config
25    #[cfg(feature = "compiler")]
26    pub fn new(compiler: Box<dyn Compiler>, target: Target, features: Features) -> Self {
27        Self {
28            inner: Arc::new(Mutex::new(ObjectFileEngineInner {
29                compiler: Some(compiler),
30                signatures: SignatureRegistry::new(),
31                prefixer: None,
32                features,
33            })),
34            target: Arc::new(target),
35            engine_id: EngineId::default(),
36        }
37    }
38
39    /// Create a headless `ObjectFileEngine`
40    ///
41    /// A headless engine is an engine without any compiler attached.
42    /// This is useful for assuring a minimal runtime for running
43    /// WebAssembly modules.
44    ///
45    /// For example, for running in IoT devices where compilers are very
46    /// expensive, or also to optimize startup speed.
47    ///
48    /// # Important
49    ///
50    /// Headless engines can't compile or validate any modules,
51    /// they just take already processed Modules (via `Module::serialize`).
52    pub fn headless() -> Self {
53        Self {
54            inner: Arc::new(Mutex::new(ObjectFileEngineInner {
55                #[cfg(feature = "compiler")]
56                compiler: None,
57                #[cfg(feature = "compiler")]
58                features: Features::default(),
59                signatures: SignatureRegistry::new(),
60                prefixer: None,
61            })),
62            target: Arc::new(Target::default()),
63            engine_id: EngineId::default(),
64        }
65    }
66
67    /// Sets a prefixer for the wasm module, so we can avoid any collisions
68    /// in the exported function names on the generated shared object.
69    ///
70    /// This, allows us to rather than have functions named `wasmer_function_1`
71    /// to be named `wasmer_function_PREFIX_1`.
72    ///
73    /// # Important
74    ///
75    /// This prefixer function should be deterministic, so the compilation
76    /// remains deterministic.
77    pub fn set_deterministic_prefixer<F>(&mut self, prefixer: F)
78    where
79        F: Fn(&[u8]) -> String + Send + 'static,
80    {
81        let mut inner = self.inner_mut();
82        inner.prefixer = Some(Box::new(prefixer));
83    }
84
85    pub(crate) fn inner(&self) -> std::sync::MutexGuard<'_, ObjectFileEngineInner> {
86        self.inner.lock().unwrap()
87    }
88
89    pub(crate) fn inner_mut(&self) -> std::sync::MutexGuard<'_, ObjectFileEngineInner> {
90        self.inner.lock().unwrap()
91    }
92}
93
94impl Engine for ObjectFileEngine {
95    /// The target
96    fn target(&self) -> &Target {
97        &self.target
98    }
99
100    /// Register a signature
101    fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex {
102        let compiler = self.inner();
103        compiler.signatures().register(func_type)
104    }
105
106    /// Lookup a signature
107    fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
108        let compiler = self.inner();
109        compiler.signatures().lookup(sig)
110    }
111
112    /// Validates a WebAssembly module
113    fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {
114        self.inner().validate(binary)
115    }
116
117    /// Compile a WebAssembly binary
118    #[cfg(feature = "compiler")]
119    fn compile(
120        &self,
121        binary: &[u8],
122        tunables: &dyn Tunables,
123    ) -> Result<Arc<dyn Artifact>, CompileError> {
124        Ok(Arc::new(ObjectFileArtifact::new(&self, binary, tunables)?))
125    }
126
127    /// Compile a WebAssembly binary (it will fail because the `compiler` flag is disabled).
128    #[cfg(not(feature = "compiler"))]
129    fn compile(
130        &self,
131        _binary: &[u8],
132        _tunables: &dyn Tunables,
133    ) -> Result<Arc<dyn Artifact>, CompileError> {
134        Err(CompileError::Codegen(
135            "The `ObjectFileEngine` is operating in headless mode, so it cannot compile a module."
136                .to_string(),
137        ))
138    }
139
140    /// Deserializes a WebAssembly module (binary content of a Shared Object file)
141    unsafe fn deserialize(&self, bytes: &[u8]) -> Result<Arc<dyn Artifact>, DeserializeError> {
142        Ok(Arc::new(ObjectFileArtifact::deserialize(&self, &bytes)?))
143    }
144
145    /// Deserializes a WebAssembly module from a path
146    /// It should point to a Shared Object file generated by this engine.
147    unsafe fn deserialize_from_file(
148        &self,
149        file_ref: &Path,
150    ) -> Result<Arc<dyn Artifact>, DeserializeError> {
151        let mut f = std::fs::File::open(file_ref)?;
152        let mut vec = vec![];
153        f.read_to_end(&mut vec)?;
154
155        self.deserialize(&vec[..])
156    }
157
158    fn id(&self) -> &EngineId {
159        &self.engine_id
160    }
161
162    fn cloned(&self) -> Arc<dyn Engine + Send + Sync> {
163        Arc::new(self.clone())
164    }
165}
166
167/// The inner contents of `ObjectFileEngine`
168pub struct ObjectFileEngineInner {
169    /// The compiler
170    #[cfg(feature = "compiler")]
171    compiler: Option<Box<dyn Compiler>>,
172    /// The WebAssembly features to use
173    #[cfg(feature = "compiler")]
174    features: Features,
175    /// The signature registry is used mainly to operate with trampolines
176    /// performantly.
177    signatures: SignatureRegistry,
178    /// The prefixer returns the a String to prefix each of
179    /// the functions in the shared object generated by the `ObjectFileEngine`,
180    /// so we can assure no collisions.
181    prefixer: Option<Box<dyn Fn(&[u8]) -> String + Send>>,
182}
183
184impl ObjectFileEngineInner {
185    /// Gets the compiler associated to this engine.
186    #[cfg(feature = "compiler")]
187    pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
188        if self.compiler.is_none() {
189            return Err(CompileError::Codegen("The `ObjectFileEngine` is operating in headless mode, so it can only execute already compiled Modules.".to_string()));
190        }
191        Ok(&**self
192            .compiler
193            .as_ref()
194            .expect("Can't get compiler reference"))
195    }
196
197    #[cfg(feature = "compiler")]
198    pub(crate) fn get_prefix(&self, bytes: &[u8]) -> String {
199        if let Some(prefixer) = &self.prefixer {
200            prefixer(&bytes)
201        } else {
202            "".to_string()
203        }
204    }
205
206    #[cfg(feature = "compiler")]
207    pub(crate) fn features(&self) -> &Features {
208        &self.features
209    }
210
211    /// Validate the module
212    #[cfg(feature = "compiler")]
213    pub fn validate<'data>(&self, data: &'data [u8]) -> Result<(), CompileError> {
214        self.compiler()?.validate_module(self.features(), data)
215    }
216
217    /// Validate the module
218    #[cfg(not(feature = "compiler"))]
219    pub fn validate<'data>(&self, _data: &'data [u8]) -> Result<(), CompileError> {
220        Err(CompileError::Validate(
221            "The `ObjectFileEngine` is not compiled with compiler support, which is required for validating".to_string(),
222        ))
223    }
224
225    /// Shared signature registry.
226    pub fn signatures(&self) -> &SignatureRegistry {
227        &self.signatures
228    }
229}