wasmer_engine_native_asml_fork/
engine.rs

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