1use crate::engine::builder::EngineBuilder;
4#[cfg(not(target_arch = "wasm32"))]
5use crate::{
6 types::{
7 function::FunctionBodyLike,
8 section::{CustomSectionLike, CustomSectionProtection, SectionIndex},
9 },
10 Artifact, BaseTunables, CodeMemory, FunctionExtent, GlobalFrameInfoRegistration, Tunables,
11};
12#[cfg(feature = "compiler")]
13use crate::{Compiler, CompilerConfig};
14
15#[cfg(not(target_arch = "wasm32"))]
16use shared_buffer::OwnedBuffer;
17
18#[cfg(not(target_arch = "wasm32"))]
19use std::path::Path;
20use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
21use std::sync::{Arc, Mutex};
22
23#[cfg(feature = "compiler")]
24use wasmer_types::Features;
25#[cfg(not(target_arch = "wasm32"))]
26use wasmer_types::{
27 entity::PrimaryMap, DeserializeError, FunctionIndex, FunctionType, LocalFunctionIndex,
28 SignatureIndex,
29};
30use wasmer_types::{target::Target, CompileError, HashAlgorithm, ModuleInfo};
31
32#[cfg(not(target_arch = "wasm32"))]
33use wasmer_vm::{
34 FunctionBodyPtr, SectionBodyPtr, SignatureRegistry, VMFunctionBody, VMSharedSignatureIndex,
35 VMTrampoline,
36};
37
38#[derive(Clone)]
40pub struct Engine {
41 inner: Arc<Mutex<EngineInner>>,
42 target: Arc<Target>,
44 engine_id: EngineId,
45 #[cfg(not(target_arch = "wasm32"))]
46 tunables: Arc<dyn Tunables + Send + Sync>,
47 name: String,
48 hash_algorithm: Option<HashAlgorithm>,
49}
50
51impl Engine {
52 #[cfg(feature = "compiler")]
54 pub fn new(
55 compiler_config: Box<dyn CompilerConfig>,
56 target: Target,
57 features: Features,
58 ) -> Self {
59 #[cfg(not(target_arch = "wasm32"))]
60 let tunables = BaseTunables::for_target(&target);
61 let compiler = compiler_config.compiler();
62 let name = format!("engine-{}", compiler.name());
63 Self {
64 inner: Arc::new(Mutex::new(EngineInner {
65 compiler: Some(compiler),
66 features,
67 #[cfg(not(target_arch = "wasm32"))]
68 code_memory: vec![],
69 #[cfg(not(target_arch = "wasm32"))]
70 signatures: SignatureRegistry::new(),
71 })),
72 target: Arc::new(target),
73 engine_id: EngineId::default(),
74 #[cfg(not(target_arch = "wasm32"))]
75 tunables: Arc::new(tunables),
76 name,
77 hash_algorithm: None,
78 }
79 }
80
81 pub fn name(&self) -> &str {
83 self.name.as_str()
84 }
85
86 pub fn set_hash_algorithm(&mut self, hash_algorithm: Option<HashAlgorithm>) {
88 self.hash_algorithm = hash_algorithm;
89 }
90
91 pub fn hash_algorithm(&self) -> Option<HashAlgorithm> {
93 self.hash_algorithm
94 }
95
96 pub fn deterministic_id(&self) -> String {
98 #[cfg(feature = "compiler")]
99 {
100 let i = self.inner();
101 if let Some(ref c) = i.compiler {
102 return c.deterministic_id();
103 } else {
104 return self.name.clone();
105 }
106 }
107
108 #[allow(unreachable_code)]
109 {
110 self.name.to_string()
111 }
112 }
113
114 pub fn headless() -> Self {
128 let target = Target::default();
129 #[cfg(not(target_arch = "wasm32"))]
130 let tunables = BaseTunables::for_target(&target);
131 Self {
132 inner: Arc::new(Mutex::new(EngineInner {
133 #[cfg(feature = "compiler")]
134 compiler: None,
135 #[cfg(feature = "compiler")]
136 features: Features::default(),
137 #[cfg(not(target_arch = "wasm32"))]
138 code_memory: vec![],
139 #[cfg(not(target_arch = "wasm32"))]
140 signatures: SignatureRegistry::new(),
141 })),
142 target: Arc::new(target),
143 engine_id: EngineId::default(),
144 #[cfg(not(target_arch = "wasm32"))]
145 tunables: Arc::new(tunables),
146 name: "engine-headless".to_string(),
147 hash_algorithm: None,
148 }
149 }
150
151 pub fn inner(&self) -> std::sync::MutexGuard<'_, EngineInner> {
153 self.inner.lock().unwrap()
154 }
155
156 pub fn inner_mut(&self) -> std::sync::MutexGuard<'_, EngineInner> {
158 self.inner.lock().unwrap()
159 }
160
161 pub fn target(&self) -> &Target {
163 &self.target
164 }
165
166 #[cfg(not(target_arch = "wasm32"))]
168 pub fn register_signature(&self, func_type: &FunctionType) -> VMSharedSignatureIndex {
169 let compiler = self.inner();
170 compiler.signatures().register(func_type)
171 }
172
173 #[cfg(not(target_arch = "wasm32"))]
175 pub fn lookup_signature(&self, sig: VMSharedSignatureIndex) -> Option<FunctionType> {
176 let compiler = self.inner();
177 compiler.signatures().lookup(sig)
178 }
179
180 #[cfg(feature = "compiler")]
182 pub fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {
183 self.inner().validate(binary)
184 }
185
186 #[cfg(feature = "compiler")]
188 #[cfg(not(target_arch = "wasm32"))]
189 pub fn compile(&self, binary: &[u8]) -> Result<Arc<Artifact>, CompileError> {
190 Ok(Arc::new(Artifact::new(
191 self,
192 binary,
193 self.tunables.as_ref(),
194 self.hash_algorithm,
195 )?))
196 }
197
198 #[cfg(not(feature = "compiler"))]
200 #[cfg(not(target_arch = "wasm32"))]
201 pub fn compile(
202 &self,
203 _binary: &[u8],
204 _tunables: &dyn Tunables,
205 ) -> Result<Arc<Artifact>, CompileError> {
206 Err(CompileError::Codegen(
207 "The Engine is operating in headless mode, so it can not compile Modules.".to_string(),
208 ))
209 }
210
211 #[cfg(not(target_arch = "wasm32"))]
212 pub unsafe fn deserialize_unchecked(
219 &self,
220 bytes: OwnedBuffer,
221 ) -> Result<Arc<Artifact>, DeserializeError> {
222 Ok(Arc::new(Artifact::deserialize_unchecked(self, bytes)?))
223 }
224
225 #[cfg(not(target_arch = "wasm32"))]
232 pub unsafe fn deserialize(
233 &self,
234 bytes: OwnedBuffer,
235 ) -> Result<Arc<Artifact>, DeserializeError> {
236 Ok(Arc::new(Artifact::deserialize(self, bytes)?))
237 }
238
239 #[cfg(not(target_arch = "wasm32"))]
244 pub unsafe fn deserialize_from_file(
245 &self,
246 file_ref: &Path,
247 ) -> Result<Arc<Artifact>, DeserializeError> {
248 let file = std::fs::File::open(file_ref)?;
249 self.deserialize(
250 OwnedBuffer::from_file(&file).map_err(|e| DeserializeError::Generic(e.to_string()))?,
251 )
252 }
253
254 #[cfg(not(target_arch = "wasm32"))]
260 pub unsafe fn deserialize_from_file_unchecked(
261 &self,
262 file_ref: &Path,
263 ) -> Result<Arc<Artifact>, DeserializeError> {
264 let file = std::fs::File::open(file_ref)?;
265 self.deserialize_unchecked(
266 OwnedBuffer::from_file(&file).map_err(|e| DeserializeError::Generic(e.to_string()))?,
267 )
268 }
269
270 pub fn id(&self) -> &EngineId {
276 &self.engine_id
277 }
278
279 pub fn cloned(&self) -> Self {
281 self.clone()
282 }
283
284 #[cfg(not(target_arch = "wasm32"))]
286 pub fn set_tunables(&mut self, tunables: impl Tunables + Send + Sync + 'static) {
287 self.tunables = Arc::new(tunables);
288 }
289
290 #[cfg(not(target_arch = "wasm32"))]
292 pub fn tunables(&self) -> &dyn Tunables {
293 self.tunables.as_ref()
294 }
295
296 #[allow(unused)]
304 pub fn with_opts(
305 &mut self,
306 suggested_opts: &wasmer_types::target::UserCompilerOptimizations,
307 ) -> Result<(), CompileError> {
308 #[cfg(feature = "compiler")]
309 {
310 let mut i = self.inner_mut();
311 if let Some(ref mut c) = i.compiler {
312 c.with_opts(suggested_opts)?;
313 }
314 }
315
316 Ok(())
317 }
318}
319
320impl std::fmt::Debug for Engine {
321 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
322 write!(f, "{}", self.deterministic_id())
323 }
324}
325
326pub struct EngineInner {
328 #[cfg(feature = "compiler")]
329 compiler: Option<Box<dyn Compiler>>,
331 #[cfg(feature = "compiler")]
332 features: Features,
334 #[cfg(not(target_arch = "wasm32"))]
337 code_memory: Vec<CodeMemory>,
338 #[cfg(not(target_arch = "wasm32"))]
341 signatures: SignatureRegistry,
342}
343
344impl std::fmt::Debug for EngineInner {
345 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
346 let mut formatter = f.debug_struct("EngineInner");
347 #[cfg(feature = "compiler")]
348 {
349 formatter.field("compiler", &self.compiler);
350 formatter.field("features", &self.features);
351 }
352
353 #[cfg(not(target_arch = "wasm32"))]
354 {
355 formatter.field("signatures", &self.signatures);
356 }
357
358 formatter.finish()
359 }
360}
361
362impl EngineInner {
363 #[cfg(feature = "compiler")]
365 pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
366 match self.compiler.as_ref() {
367 None => Err(CompileError::Codegen(
368 "No compiler compiled into executable".to_string(),
369 )),
370 Some(compiler) => Ok(&**compiler),
371 }
372 }
373
374 #[cfg(feature = "compiler")]
376 pub fn validate(&self, data: &[u8]) -> Result<(), CompileError> {
377 let compiler = self.compiler()?;
378 compiler.validate_module(&self.features, data)
379 }
380
381 #[cfg(feature = "compiler")]
383 pub fn features(&self) -> &Features {
384 &self.features
385 }
386
387 #[cfg(not(target_arch = "wasm32"))]
389 #[allow(clippy::type_complexity)]
390 pub(crate) fn allocate<'a, FunctionBody, CustomSection>(
391 &'a mut self,
392 _module: &wasmer_types::ModuleInfo,
393 functions: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
394 function_call_trampolines: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
395 dynamic_function_trampolines: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
396 custom_sections: impl ExactSizeIterator<Item = &'a CustomSection> + Clone + 'a,
397 ) -> Result<
398 (
399 PrimaryMap<LocalFunctionIndex, FunctionExtent>,
400 PrimaryMap<SignatureIndex, VMTrampoline>,
401 PrimaryMap<FunctionIndex, FunctionBodyPtr>,
402 PrimaryMap<SectionIndex, SectionBodyPtr>,
403 ),
404 CompileError,
405 >
406 where
407 FunctionBody: FunctionBodyLike<'a> + 'a,
408 CustomSection: CustomSectionLike<'a> + 'a,
409 {
410 let functions_len = functions.len();
411 let function_call_trampolines_len = function_call_trampolines.len();
412
413 let function_bodies = functions
414 .chain(function_call_trampolines)
415 .chain(dynamic_function_trampolines)
416 .collect::<Vec<_>>();
417 let (executable_sections, data_sections): (Vec<_>, _) = custom_sections
418 .clone()
419 .partition(|section| section.protection() == CustomSectionProtection::ReadExecute);
420 self.code_memory.push(CodeMemory::new());
421
422 let (mut allocated_functions, allocated_executable_sections, allocated_data_sections) =
423 self.code_memory
424 .last_mut()
425 .unwrap()
426 .allocate(
427 function_bodies.as_slice(),
428 executable_sections.as_slice(),
429 data_sections.as_slice(),
430 )
431 .map_err(|message| {
432 CompileError::Resource(format!(
433 "failed to allocate memory for functions: {message}",
434 ))
435 })?;
436
437 let allocated_functions_result = allocated_functions
438 .drain(0..functions_len)
439 .map(|slice| FunctionExtent {
440 ptr: FunctionBodyPtr(slice.as_ptr()),
441 length: slice.len(),
442 })
443 .collect::<PrimaryMap<LocalFunctionIndex, _>>();
444
445 let mut allocated_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
446 PrimaryMap::new();
447 for ptr in allocated_functions
448 .drain(0..function_call_trampolines_len)
449 .map(|slice| slice.as_ptr())
450 {
451 let trampoline =
452 unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
453 allocated_function_call_trampolines.push(trampoline);
454 }
455
456 let allocated_dynamic_function_trampolines = allocated_functions
457 .drain(..)
458 .map(|slice| FunctionBodyPtr(slice.as_ptr()))
459 .collect::<PrimaryMap<FunctionIndex, _>>();
460
461 let mut exec_iter = allocated_executable_sections.iter();
462 let mut data_iter = allocated_data_sections.iter();
463 let allocated_custom_sections = custom_sections
464 .map(|section| {
465 SectionBodyPtr(
466 if section.protection() == CustomSectionProtection::ReadExecute {
467 exec_iter.next()
468 } else {
469 data_iter.next()
470 }
471 .unwrap()
472 .as_ptr(),
473 )
474 })
475 .collect::<PrimaryMap<SectionIndex, _>>();
476 Ok((
477 allocated_functions_result,
478 allocated_function_call_trampolines,
479 allocated_dynamic_function_trampolines,
480 allocated_custom_sections,
481 ))
482 }
483
484 #[cfg(not(target_arch = "wasm32"))]
485 pub(crate) fn publish_compiled_code(&mut self) {
487 self.code_memory.last_mut().unwrap().publish();
488 }
489
490 #[cfg(not(target_arch = "wasm32"))]
491 pub(crate) fn publish_eh_frame(&mut self, eh_frame: Option<&[u8]>) -> Result<(), CompileError> {
493 self.code_memory
494 .last_mut()
495 .unwrap()
496 .unwind_registry_mut()
497 .publish(eh_frame)
498 .map_err(|e| {
499 CompileError::Resource(format!("Error while publishing the unwind code: {e}"))
500 })?;
501 Ok(())
502 }
503
504 #[cfg(not(target_arch = "wasm32"))]
505 pub(crate) fn register_compact_unwind(
507 &mut self,
508 compact_unwind: Option<&[u8]>,
509 eh_personality_addr_in_got: Option<usize>,
510 ) -> Result<(), CompileError> {
511 self.code_memory
512 .last_mut()
513 .unwrap()
514 .unwind_registry_mut()
515 .register_compact_unwind(compact_unwind, eh_personality_addr_in_got)
516 .map_err(|e| {
517 CompileError::Resource(format!("Error while publishing the unwind code: {e}"))
518 })?;
519 Ok(())
520 }
521
522 #[cfg(not(target_arch = "wasm32"))]
524 pub fn signatures(&self) -> &SignatureRegistry {
525 &self.signatures
526 }
527
528 #[cfg(not(target_arch = "wasm32"))]
529 pub(crate) fn register_frame_info(&mut self, frame_info: GlobalFrameInfoRegistration) {
531 self.code_memory
532 .last_mut()
533 .unwrap()
534 .register_frame_info(frame_info);
535 }
536
537 #[cfg(not(target_arch = "wasm32"))]
538 #[allow(unused)]
539 pub(crate) fn register_perfmap(
540 &self,
541 finished_functions: &PrimaryMap<LocalFunctionIndex, FunctionExtent>,
542 module_info: &ModuleInfo,
543 ) -> Result<(), CompileError> {
544 #[cfg(feature = "compiler")]
545 {
546 use std::io::Write;
547 if self
548 .compiler
549 .as_ref()
550 .is_some_and(|v| v.get_perfmap_enabled())
551 {
552 let filename = format!("/tmp/perf-{}.map", std::process::id());
553 let mut file = std::io::BufWriter::new(std::fs::File::create(filename).unwrap());
554
555 for (func_index, code) in finished_functions.iter() {
556 let func_index = module_info.func_index(func_index);
557 let name = if let Some(func_name) = module_info.function_names.get(&func_index)
558 {
559 func_name.clone()
560 } else {
561 format!("{:p}", code.ptr.0)
562 };
563
564 let sanitized_name = name.replace(['\n', '\r'], "_");
565 let line = format!(
566 "{:p} {:x} {}\n",
567 code.ptr.0 as *const _, code.length, sanitized_name
568 );
569 write!(file, "{line}").map_err(|e| CompileError::Codegen(e.to_string()))?;
570 file.flush()
571 .map_err(|e| CompileError::Codegen(e.to_string()))?;
572 }
573 }
574 }
575
576 Ok(())
577 }
578}
579
580#[cfg(feature = "compiler")]
581impl From<Box<dyn CompilerConfig>> for Engine {
582 fn from(config: Box<dyn CompilerConfig>) -> Self {
583 EngineBuilder::new(config).engine()
584 }
585}
586
587impl From<EngineBuilder> for Engine {
588 fn from(engine_builder: EngineBuilder) -> Self {
589 engine_builder.engine()
590 }
591}
592
593impl From<&Self> for Engine {
594 fn from(engine_ref: &Self) -> Self {
595 engine_ref.cloned()
596 }
597}
598
599#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
600#[repr(transparent)]
601pub struct EngineId {
603 id: usize,
604}
605
606impl EngineId {
607 pub fn id(&self) -> String {
609 format!("{}", &self.id)
610 }
611}
612
613impl Clone for EngineId {
614 fn clone(&self) -> Self {
615 Self::default()
616 }
617}
618
619impl Default for EngineId {
620 fn default() -> Self {
621 static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
622 Self {
623 id: NEXT_ID.fetch_add(1, SeqCst),
624 }
625 }
626}