1use crate::DylibArtifact;
4use libloading::Library;
5use loupe::MemoryUsage;
6use std::path::Path;
7use std::sync::Arc;
8use std::sync::Mutex;
9use wasmer_compiler::{CompileError, Target};
10#[cfg(feature = "compiler")]
11use wasmer_compiler::{Compiler, Triple};
12use wasmer_engine::{Artifact, DeserializeError, Engine, EngineId, Tunables};
13#[cfg(feature = "compiler")]
14use wasmer_types::Features;
15use wasmer_types::FunctionType;
16use wasmer_vm::{
17 FuncDataRegistry, SignatureRegistry, VMCallerCheckedAnyfunc, VMFuncRef, VMSharedSignatureIndex,
18};
19
20#[derive(Clone, MemoryUsage)]
22pub struct DylibEngine {
23 inner: Arc<Mutex<DylibEngineInner>>,
24 target: Arc<Target>,
26 engine_id: EngineId,
27}
28
29impl DylibEngine {
30 #[cfg(feature = "compiler")]
32 pub fn new(compiler: Box<dyn Compiler>, target: Target, features: Features) -> Self {
33 let is_cross_compiling = *target.triple() != Triple::host();
34 let linker = Linker::find_linker(is_cross_compiling);
35
36 Self {
37 inner: Arc::new(Mutex::new(DylibEngineInner {
38 compiler: Some(compiler),
39 signatures: SignatureRegistry::new(),
40 func_data: Arc::new(FuncDataRegistry::new()),
41 prefixer: None,
42 features,
43 is_cross_compiling,
44 linker,
45 libraries: vec![],
46 })),
47 target: Arc::new(target),
48 engine_id: EngineId::default(),
49 }
50 }
51
52 pub fn headless() -> Self {
66 Self {
67 inner: Arc::new(Mutex::new(DylibEngineInner {
68 #[cfg(feature = "compiler")]
69 compiler: None,
70 #[cfg(feature = "compiler")]
71 features: Features::default(),
72 signatures: SignatureRegistry::new(),
73 func_data: Arc::new(FuncDataRegistry::new()),
74 prefixer: None,
75 is_cross_compiling: false,
76 linker: Linker::None,
77 libraries: vec![],
78 })),
79 target: Arc::new(Target::default()),
80 engine_id: EngineId::default(),
81 }
82 }
83
84 pub fn set_deterministic_prefixer<F>(&mut self, prefixer: F)
95 where
96 F: Fn(&[u8]) -> String + Send + 'static,
97 {
98 let mut inner = self.inner_mut();
99 inner.prefixer = Some(Box::new(prefixer));
100 }
101
102 pub(crate) fn inner(&self) -> std::sync::MutexGuard<'_, DylibEngineInner> {
103 self.inner.lock().unwrap()
104 }
105
106 pub(crate) fn inner_mut(&self) -> std::sync::MutexGuard<'_, DylibEngineInner> {
107 self.inner.lock().unwrap()
108 }
109}
110
111impl Engine for DylibEngine {
112 fn target(&self) -> &Target {
114 &self.target
115 }
116
117 fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex {
119 let compiler = self.inner();
120 compiler.signatures().register(func_type)
121 }
122
123 fn register_function_metadata(&self, func_data: VMCallerCheckedAnyfunc) -> VMFuncRef {
124 let compiler = self.inner();
125 compiler.func_data().register(func_data)
126 }
127
128 fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
130 let compiler = self.inner();
131 compiler.signatures().lookup(sig)
132 }
133
134 fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {
136 self.inner().validate(binary)
137 }
138
139 #[cfg(feature = "compiler")]
141 fn compile(
142 &self,
143 binary: &[u8],
144 tunables: &dyn Tunables,
145 ) -> Result<Arc<dyn Artifact>, CompileError> {
146 Ok(Arc::new(DylibArtifact::new(self, binary, tunables)?))
147 }
148
149 #[cfg(not(feature = "compiler"))]
151 fn compile(
152 &self,
153 _binary: &[u8],
154 _tunables: &dyn Tunables,
155 ) -> Result<Arc<dyn Artifact>, CompileError> {
156 Err(CompileError::Codegen(
157 "The `DylibEngine` is operating in headless mode, so it cannot compile a module."
158 .to_string(),
159 ))
160 }
161
162 unsafe fn deserialize(&self, bytes: &[u8]) -> Result<Arc<dyn Artifact>, DeserializeError> {
164 Ok(Arc::new(DylibArtifact::deserialize(self, bytes)?))
165 }
166
167 unsafe fn deserialize_from_file(
170 &self,
171 file_ref: &Path,
172 ) -> Result<Arc<dyn Artifact>, DeserializeError> {
173 Ok(Arc::new(DylibArtifact::deserialize_from_file(
174 self, file_ref,
175 )?))
176 }
177
178 fn id(&self) -> &EngineId {
179 &self.engine_id
180 }
181
182 fn cloned(&self) -> Arc<dyn Engine + Send + Sync> {
183 Arc::new(self.clone())
184 }
185}
186
187#[derive(Clone, Copy, MemoryUsage)]
188pub(crate) enum Linker {
189 None,
190 Clang11,
191 Clang10,
192 Clang,
193 Gcc,
194}
195
196impl Linker {
197 #[cfg(feature = "compiler")]
198 fn find_linker(is_cross_compiling: bool) -> Self {
199 let (possibilities, requirements): (&[_], _) = if is_cross_compiling {
200 (
201 &[Self::Clang11, Self::Clang10, Self::Clang],
202 "at least one of `clang-11`, `clang-10`, or `clang`",
203 )
204 } else {
205 (&[Self::Gcc], "`gcc`")
206 };
207 *possibilities
208 .iter()
209 .find(|linker| which::which(linker.executable()).is_ok())
210 .unwrap_or_else(|| {
211 panic!(
212 "Need {} installed in order to use `DylibEngine` when {}cross-compiling",
213 requirements,
214 if is_cross_compiling { "" } else { "not " }
215 )
216 })
217 }
218
219 pub(crate) fn executable(self) -> &'static str {
220 match self {
221 Self::None => "",
222 Self::Clang11 => "clang-11",
223 Self::Clang10 => "clang-10",
224 Self::Clang => "clang",
225 Self::Gcc => "gcc",
226 }
227 }
228}
229
230#[derive(MemoryUsage)]
232pub struct DylibEngineInner {
233 #[cfg(feature = "compiler")]
235 compiler: Option<Box<dyn Compiler>>,
236
237 #[cfg(feature = "compiler")]
239 features: Features,
240
241 signatures: SignatureRegistry,
244
245 func_data: Arc<FuncDataRegistry>,
249
250 #[loupe(skip)]
254 prefixer: Option<Box<dyn Fn(&[u8]) -> String + Send>>,
255
256 is_cross_compiling: bool,
258
259 linker: Linker,
261
262 #[loupe(skip)]
264 libraries: Vec<Library>,
265}
266
267impl DylibEngineInner {
268 #[cfg(feature = "compiler")]
270 pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
271 if self.compiler.is_none() {
272 return Err(CompileError::Codegen("The `DylibEngine` is operating in headless mode, so it can only execute already compiled Modules.".to_string()));
273 }
274 Ok(&**self
275 .compiler
276 .as_ref()
277 .expect("Can't get compiler reference"))
278 }
279
280 #[cfg(feature = "compiler")]
281 pub(crate) fn get_prefix(&self, bytes: &[u8]) -> String {
282 if let Some(prefixer) = &self.prefixer {
283 prefixer(bytes)
284 } else {
285 "".to_string()
286 }
287 }
288
289 #[cfg(feature = "compiler")]
290 pub(crate) fn features(&self) -> &Features {
291 &self.features
292 }
293
294 #[cfg(feature = "compiler")]
296 pub fn validate(&self, data: &[u8]) -> Result<(), CompileError> {
297 self.compiler()?.validate_module(self.features(), data)
298 }
299
300 #[cfg(not(feature = "compiler"))]
302 pub fn validate<'data>(&self, _data: &'data [u8]) -> Result<(), CompileError> {
303 Err(CompileError::Validate(
304 "The `DylibEngine` is not compiled with compiler support, which is required for validating".to_string(),
305 ))
306 }
307
308 pub fn signatures(&self) -> &SignatureRegistry {
310 &self.signatures
311 }
312
313 pub(crate) fn func_data(&self) -> &Arc<FuncDataRegistry> {
315 &self.func_data
316 }
317
318 pub(crate) fn is_cross_compiling(&self) -> bool {
319 self.is_cross_compiling
320 }
321
322 pub(crate) fn linker(&self) -> Linker {
323 self.linker
324 }
325
326 pub(crate) fn add_library(&mut self, library: Library) {
327 self.libraries.push(library);
328 }
329}