1use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
2use std::sync::{Arc, Mutex};
3
4use crate::engine::builder::EngineBuilder;
5#[cfg(feature = "compiler")]
6use crate::{Compiler, CompilerConfig};
7
8#[cfg(not(target_arch = "wasm32"))]
9use wasmer_types::CompilationProgressCallback;
10#[cfg(feature = "compiler")]
11use wasmer_types::Features;
12use wasmer_types::{CompileError, target::Target};
13
14#[cfg(not(target_arch = "wasm32"))]
15use shared_buffer::OwnedBuffer;
16#[cfg(not(target_arch = "wasm32"))]
17use std::ffi::c_void;
18#[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
19use std::io::Write;
20#[cfg(not(target_arch = "wasm32"))]
21use std::io::{Read, Seek};
22#[cfg(all(not(target_arch = "wasm32"), unix))]
23use std::os::fd::RawFd;
24#[cfg(not(target_arch = "wasm32"))]
25use std::path::Path;
26#[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
27use wasmer_types::ModuleInfo;
28#[cfg(not(target_arch = "wasm32"))]
29use wasmer_types::{
30 DeserializeError, FunctionIndex, FunctionType, LocalFunctionIndex, SignatureHash,
31 SignatureIndex, entity::PrimaryMap,
32};
33
34#[cfg(not(target_arch = "wasm32"))]
35use crate::{
36 Artifact, BaseTunables, CodeMemory, FunctionExtent, GlobalFrameInfoRegistration, Tunables,
37 engine::mapped_binary::MemoryMappedBinary,
38 types::{
39 function::FunctionBodyLike,
40 section::{CustomSectionLike, CustomSectionProtection, SectionIndex},
41 },
42};
43
44#[cfg(not(target_arch = "wasm32"))]
45use wasmer_vm::{
46 FunctionBodyPtr, SectionBodyPtr, SignatureRegistry, VMFunctionBody, VMSignatureHash,
47 VMTrampoline,
48};
49
50#[derive(Clone)]
52pub struct Engine {
53 inner: Arc<Mutex<EngineInner>>,
54 target: Arc<Target>,
56 engine_id: EngineId,
57 #[cfg(not(target_arch = "wasm32"))]
58 tunables: Arc<dyn Tunables + Send + Sync>,
59 name: String,
60}
61
62impl Engine {
63 #[cfg(feature = "compiler")]
65 pub fn new(
66 compiler_config: Box<dyn CompilerConfig>,
67 target: Target,
68 features: Features,
69 ) -> Self {
70 #[cfg(not(target_arch = "wasm32"))]
71 let tunables = BaseTunables::for_target(&target);
72 let compiler = compiler_config.compiler();
73 let name = format!("engine-{}", compiler.name());
74 Self {
75 inner: Arc::new(Mutex::new(EngineInner {
76 compiler: Some(compiler),
77 features,
78 #[cfg(not(target_arch = "wasm32"))]
79 code_memory: vec![],
80 #[cfg(not(target_arch = "wasm32"))]
81 elf_mapped_binary: vec![],
82 #[cfg(not(target_arch = "wasm32"))]
83 signatures: SignatureRegistry::new(),
84 })),
85 target: Arc::new(target),
86 engine_id: EngineId::default(),
87 #[cfg(not(target_arch = "wasm32"))]
88 tunables: Arc::new(tunables),
89 name,
90 }
91 }
92
93 pub fn name(&self) -> &str {
95 self.name.as_str()
96 }
97
98 pub fn deterministic_id(&self) -> String {
100 #[cfg(feature = "compiler")]
101 {
102 let i = self.inner();
103 if let Some(ref c) = i.compiler {
104 return c.deterministic_id();
105 } else {
106 return self.name.clone();
107 }
108 }
109
110 #[allow(unreachable_code)]
111 {
112 self.name.to_string()
113 }
114 }
115
116 pub fn headless() -> Self {
130 let target = Target::default();
131 #[cfg(not(target_arch = "wasm32"))]
132 let tunables = BaseTunables::for_target(&target);
133 Self {
134 inner: Arc::new(Mutex::new(EngineInner {
135 #[cfg(feature = "compiler")]
136 compiler: None,
137 #[cfg(feature = "compiler")]
138 features: Features::default(),
139 #[cfg(not(target_arch = "wasm32"))]
140 code_memory: vec![],
141 #[cfg(not(target_arch = "wasm32"))]
142 elf_mapped_binary: vec![],
143 #[cfg(not(target_arch = "wasm32"))]
144 signatures: SignatureRegistry::new(),
145 })),
146 target: Arc::new(target),
147 engine_id: EngineId::default(),
148 #[cfg(not(target_arch = "wasm32"))]
149 tunables: Arc::new(tunables),
150 name: "engine-headless".to_string(),
151 }
152 }
153
154 pub fn inner(&self) -> std::sync::MutexGuard<'_, EngineInner> {
156 self.inner.lock().unwrap()
157 }
158
159 pub fn inner_mut(&self) -> std::sync::MutexGuard<'_, EngineInner> {
161 self.inner.lock().unwrap()
162 }
163
164 pub fn target(&self) -> &Target {
166 &self.target
167 }
168
169 #[cfg(not(target_arch = "wasm32"))]
171 pub fn register_signature(&self, func_type: &FunctionType) -> VMSignatureHash {
172 let compiler = self.inner();
173 compiler
174 .signatures()
175 .register(func_type, SignatureHash(func_type.signature_hash()))
176 }
177
178 #[cfg(not(target_arch = "wasm32"))]
180 pub fn lookup_signature(&self, sig_hash: VMSignatureHash) -> Option<FunctionType> {
181 let compiler = self.inner();
182 compiler.signatures().lookup_signature(sig_hash)
183 }
184
185 #[cfg(feature = "compiler")]
187 pub fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {
188 self.inner().validate(binary)
189 }
190
191 #[cfg(feature = "compiler")]
193 #[cfg(not(target_arch = "wasm32"))]
194 pub fn compile(&self, binary: &[u8]) -> Result<Arc<Artifact>, CompileError> {
195 Ok(Arc::new(Artifact::new(
196 self,
197 binary,
198 self.tunables.as_ref(),
199 None,
200 )?))
201 }
202
203 #[cfg(feature = "compiler")]
205 pub fn compile_with_progress(
206 &self,
207 binary: &[u8],
208 progress_callback: Option<CompilationProgressCallback>,
209 ) -> Result<Arc<Artifact>, CompileError> {
210 Ok(Arc::new(Artifact::new(
211 self,
212 binary,
213 self.tunables.as_ref(),
214 progress_callback,
215 )?))
216 }
217
218 #[cfg(not(feature = "compiler"))]
220 #[cfg(not(target_arch = "wasm32"))]
221 pub fn compile_with_progress(
222 &self,
223 binary: &[u8],
224 _progress_callback: Option<CompilationProgressCallback>,
225 ) -> Result<Arc<Artifact>, CompileError> {
226 self.compile(binary, self.tunables.as_ref())
227 }
228
229 #[cfg(not(feature = "compiler"))]
231 #[cfg(not(target_arch = "wasm32"))]
232 pub fn compile(
233 &self,
234 _binary: &[u8],
235 _tunables: &dyn Tunables,
236 ) -> Result<Arc<Artifact>, CompileError> {
237 Err(CompileError::Codegen(
238 "The Engine is operating in headless mode, so it can not compile Modules.".to_string(),
239 ))
240 }
241
242 #[cfg(not(target_arch = "wasm32"))]
243 pub unsafe fn deserialize_unchecked(
250 &self,
251 bytes: OwnedBuffer,
252 ) -> Result<Arc<Artifact>, DeserializeError> {
253 unsafe { Ok(Arc::new(Artifact::deserialize_unchecked(self, bytes)?)) }
254 }
255
256 #[cfg(not(target_arch = "wasm32"))]
263 pub unsafe fn deserialize(
264 &self,
265 bytes: OwnedBuffer,
266 ) -> Result<Arc<Artifact>, DeserializeError> {
267 unsafe { Ok(Arc::new(Artifact::deserialize(self, bytes)?)) }
268 }
269
270 #[cfg(not(target_arch = "wasm32"))]
275 pub unsafe fn deserialize_from_file(
276 &self,
277 file_ref: &Path,
278 ) -> Result<Arc<Artifact>, DeserializeError> {
279 unsafe {
280 let mut file = std::fs::File::open(file_ref)?;
281 let mut magic = [0; 4];
282 let is_elf = file.read_exact(&mut magic).is_ok() && magic == object::elf::ELFMAG;
283 if is_elf {
284 return Ok(Arc::new(Artifact::deserialize_file(self, file_ref)?));
285 }
286 file.rewind()?;
287 self.deserialize(
288 OwnedBuffer::from_file(&file)
289 .map_err(|e| DeserializeError::Generic(e.to_string()))?,
290 )
291 }
292 }
293
294 #[cfg(not(target_arch = "wasm32"))]
300 pub unsafe fn deserialize_from_file_unchecked(
301 &self,
302 file_ref: &Path,
303 ) -> Result<Arc<Artifact>, DeserializeError> {
304 unsafe {
305 let file = std::fs::File::open(file_ref)?;
306 self.deserialize_unchecked(
307 OwnedBuffer::from_file(&file)
308 .map_err(|e| DeserializeError::Generic(e.to_string()))?,
309 )
310 }
311 }
312
313 pub fn id(&self) -> &EngineId {
319 &self.engine_id
320 }
321
322 pub fn cloned(&self) -> Self {
324 self.clone()
325 }
326
327 #[cfg(not(target_arch = "wasm32"))]
329 pub fn set_tunables(&mut self, tunables: impl Tunables + Send + Sync + 'static) {
330 self.tunables = Arc::new(tunables);
331 }
332
333 #[cfg(not(target_arch = "wasm32"))]
335 pub fn tunables(&self) -> &dyn Tunables {
336 self.tunables.as_ref()
337 }
338
339 pub fn with_opts(
347 &mut self,
348 _suggested_opts: &wasmer_types::target::UserCompilerOptimizations,
349 ) -> Result<(), CompileError> {
350 #[cfg(feature = "compiler")]
351 {
352 let mut i = self.inner_mut();
353 if let Some(ref mut c) = i.compiler {
354 c.with_opts(_suggested_opts)?;
355 }
356 }
357
358 Ok(())
359 }
360}
361
362impl std::fmt::Debug for Engine {
363 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
364 write!(f, "{}", self.deterministic_id())
365 }
366}
367
368pub struct EngineInner {
370 #[cfg(feature = "compiler")]
371 compiler: Option<Box<dyn Compiler>>,
373 #[cfg(feature = "compiler")]
374 features: Features,
376 #[cfg(not(target_arch = "wasm32"))]
379 code_memory: Vec<CodeMemory>,
380 #[cfg(not(target_arch = "wasm32"))]
382 elf_mapped_binary: Vec<MemoryMappedBinary>,
383 #[cfg(not(target_arch = "wasm32"))]
386 signatures: SignatureRegistry,
387}
388
389impl std::fmt::Debug for EngineInner {
390 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
391 let mut formatter = f.debug_struct("EngineInner");
392 #[cfg(feature = "compiler")]
393 {
394 formatter.field("compiler", &self.compiler);
395 formatter.field("features", &self.features);
396 }
397
398 #[cfg(not(target_arch = "wasm32"))]
399 {
400 formatter.field("signatures", &self.signatures);
401 }
402
403 formatter.finish()
404 }
405}
406
407impl EngineInner {
408 #[cfg(feature = "compiler")]
410 pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
411 match self.compiler.as_ref() {
412 None => Err(CompileError::Codegen(
413 "No compiler compiled into executable".to_string(),
414 )),
415 Some(compiler) => Ok(&**compiler),
416 }
417 }
418
419 #[cfg(feature = "compiler")]
421 pub fn validate(&self, data: &[u8]) -> Result<(), CompileError> {
422 let compiler = self.compiler()?;
423 compiler.validate_module(&self.features, data)
424 }
425
426 #[cfg(feature = "compiler")]
428 pub fn features(&self) -> &Features {
429 &self.features
430 }
431
432 #[cfg(not(target_arch = "wasm32"))]
434 #[allow(clippy::type_complexity)]
435 pub(crate) fn allocate<'a, FunctionBody, CustomSection>(
436 &'a mut self,
437 _module: &wasmer_types::ModuleInfo,
438 functions: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
439 function_call_trampolines: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
440 dynamic_function_trampolines: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
441 custom_sections: impl ExactSizeIterator<Item = &'a CustomSection> + Clone + 'a,
442 ) -> Result<
443 (
444 PrimaryMap<LocalFunctionIndex, FunctionExtent>,
445 PrimaryMap<SignatureIndex, VMTrampoline>,
446 PrimaryMap<FunctionIndex, FunctionBodyPtr>,
447 PrimaryMap<SectionIndex, SectionBodyPtr>,
448 ),
449 CompileError,
450 >
451 where
452 FunctionBody: FunctionBodyLike<'a> + 'a,
453 CustomSection: CustomSectionLike<'a> + 'a,
454 {
455 let functions_len = functions.len();
456 let function_call_trampolines_len = function_call_trampolines.len();
457
458 let function_bodies = functions
459 .chain(function_call_trampolines)
460 .chain(dynamic_function_trampolines)
461 .collect::<Vec<_>>();
462 let (executable_sections, data_sections): (Vec<_>, _) = custom_sections
463 .clone()
464 .partition(|section| section.protection() == CustomSectionProtection::ReadExecute);
465 self.code_memory.push(CodeMemory::new());
466
467 let (mut allocated_functions, allocated_executable_sections, allocated_data_sections) =
468 self.code_memory
469 .last_mut()
470 .unwrap()
471 .allocate(
472 function_bodies.as_slice(),
473 executable_sections.as_slice(),
474 data_sections.as_slice(),
475 )
476 .map_err(|message| {
477 CompileError::Resource(format!(
478 "failed to allocate memory for functions: {message}",
479 ))
480 })?;
481
482 let allocated_functions_result = allocated_functions
483 .drain(0..functions_len)
484 .map(|slice| FunctionExtent {
485 ptr: FunctionBodyPtr(slice.as_ptr()),
486 length: slice.len(),
487 })
488 .collect::<PrimaryMap<LocalFunctionIndex, _>>();
489
490 let mut allocated_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
491 PrimaryMap::new();
492 for ptr in allocated_functions
493 .drain(0..function_call_trampolines_len)
494 .map(|slice| slice.as_ptr())
495 {
496 let trampoline =
497 unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
498 allocated_function_call_trampolines.push(trampoline);
499 }
500
501 let allocated_dynamic_function_trampolines = allocated_functions
502 .drain(..)
503 .map(|slice| FunctionBodyPtr(slice.as_ptr()))
504 .collect::<PrimaryMap<FunctionIndex, _>>();
505
506 let mut exec_iter = allocated_executable_sections.iter();
507 let mut data_iter = allocated_data_sections.iter();
508 let allocated_custom_sections = custom_sections
509 .map(|section| {
510 SectionBodyPtr(
511 if section.protection() == CustomSectionProtection::ReadExecute {
512 exec_iter.next()
513 } else {
514 data_iter.next()
515 }
516 .unwrap()
517 .as_ptr(),
518 )
519 })
520 .collect::<PrimaryMap<SectionIndex, _>>();
521 Ok((
522 allocated_functions_result,
523 allocated_function_call_trampolines,
524 allocated_dynamic_function_trampolines,
525 allocated_custom_sections,
526 ))
527 }
528
529 #[cfg(not(target_arch = "wasm32"))]
530 pub(crate) fn publish_compiled_code(&mut self) {
532 self.code_memory.last_mut().unwrap().publish();
533 }
534
535 #[cfg(not(target_arch = "wasm32"))]
536 #[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
537 pub(crate) fn publish_eh_frame(&mut self, eh_frame: Option<&[u8]>) -> Result<(), CompileError> {
539 self.code_memory
540 .last_mut()
541 .unwrap()
542 .unwind_registry_mut()
543 .publish_eh_frame(eh_frame)
544 .map_err(|e| {
545 CompileError::Resource(format!("Error while publishing the unwind code: {e}"))
546 })?;
547 Ok(())
548 }
549 #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
550 pub(crate) fn publish_compact_unwind(
552 &mut self,
553 compact_unwind: &[u8],
554 eh_personality_addr_in_got: Option<usize>,
555 ) -> Result<(), CompileError> {
556 self.code_memory
557 .last_mut()
558 .unwrap()
559 .unwind_registry_mut()
560 .publish_compact_unwind(compact_unwind, eh_personality_addr_in_got)
561 .map_err(|e| {
562 CompileError::Resource(format!("Error while publishing the unwind code: {e}"))
563 })?;
564 Ok(())
565 }
566
567 #[cfg(not(target_arch = "wasm32"))]
571 pub(crate) fn map_elf_binary<'a, R: object::ReadRef<'a>>(
572 &mut self,
573 object_file: &object::File<'a, R>,
574 data: &[u8],
575 ) -> Result<*mut c_void, CompileError> {
576 let map = MemoryMappedBinary::try_from_bytes(object_file, data)
577 .map_err(CompileError::Resource)?;
578 let base = map.base();
579 self.elf_mapped_binary.push(map);
580 Ok(base)
581 }
582
583 #[cfg(all(not(target_arch = "wasm32"), unix))]
585 pub(crate) fn map_elf_binary_file<'a, R: object::ReadRef<'a>>(
586 &mut self,
587 object_file: &object::File<'a, R>,
588 file: RawFd,
589 ) -> Result<*mut c_void, CompileError> {
590 let map =
591 MemoryMappedBinary::try_from_file(object_file, file).map_err(CompileError::Resource)?;
592 let base = map.base();
593 self.elf_mapped_binary.push(map);
594 Ok(base)
595 }
596
597 #[cfg(not(target_arch = "wasm32"))]
599 pub(crate) fn publish_elf_eh_frame(
600 &mut self,
601 address: u64,
602 size: u64,
603 ) -> Result<(), CompileError> {
604 self.elf_mapped_binary
605 .last_mut()
606 .unwrap()
607 .publish_eh_frame_section(address, size)
608 .map_err(|e| {
609 CompileError::Resource(format!("Error while publishing the unwind code: {e}"))
610 })
611 }
612
613 #[cfg(not(target_arch = "wasm32"))]
615 pub fn signatures(&self) -> &SignatureRegistry {
616 &self.signatures
617 }
618
619 #[cfg(not(target_arch = "wasm32"))]
620 pub(crate) fn register_frame_info(&mut self, frame_info: GlobalFrameInfoRegistration) {
622 self.code_memory
623 .last_mut()
624 .unwrap()
625 .register_frame_info(frame_info);
626 }
627
628 #[cfg(not(target_arch = "wasm32"))]
629 pub(crate) fn register_elf_frame_info(&mut self, frame_info: GlobalFrameInfoRegistration) {
631 self.elf_mapped_binary
632 .last_mut()
633 .unwrap()
634 .register_frame_info(frame_info);
635 }
636
637 #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
638 pub(crate) fn register_perfmap(
639 &self,
640 finished_functions: &PrimaryMap<LocalFunctionIndex, FunctionExtent>,
641 module_info: &ModuleInfo,
642 ) -> Result<(), CompileError> {
643 if self
644 .compiler
645 .as_ref()
646 .is_some_and(|v| v.get_perfmap_enabled())
647 {
648 use std::fs::OpenOptions;
649
650 let filename = format!("/tmp/perf-{}.map", std::process::id());
651 let file = OpenOptions::new()
653 .append(true)
654 .create(true)
655 .open(&filename)
656 .map_err(|e| {
657 CompileError::Codegen(format!("failed to open perf map file {filename}: {e}"))
658 })?;
659 let mut file = std::io::BufWriter::new(file);
660
661 for (func_index, code) in finished_functions.iter() {
662 let func_index = module_info.func_index(func_index);
663 if let Some(func_name) = module_info.function_names.get(&func_index) {
664 let sanitized_name = func_name.replace(['\n', '\r'], "_");
665 let line = format!(
666 "{:p} {:x} {sanitized_name}\n",
667 code.ptr.0 as *const _, code.length
668 );
669 write!(file, "{line}").map_err(|e| CompileError::Codegen(e.to_string()))?;
670 }
671 }
672
673 file.flush()
674 .map_err(|e| CompileError::Codegen(e.to_string()))?;
675 }
676
677 Ok(())
678 }
679}
680
681#[cfg(feature = "compiler")]
682impl From<Box<dyn CompilerConfig>> for Engine {
683 fn from(config: Box<dyn CompilerConfig>) -> Self {
684 EngineBuilder::new(config).engine()
685 }
686}
687
688impl From<EngineBuilder> for Engine {
689 fn from(engine_builder: EngineBuilder) -> Self {
690 engine_builder.engine()
691 }
692}
693
694impl From<&Self> for Engine {
695 fn from(engine_ref: &Self) -> Self {
696 engine_ref.cloned()
697 }
698}
699
700#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
701#[repr(transparent)]
702pub struct EngineId {
704 id: usize,
705}
706
707impl EngineId {
708 pub fn id(&self) -> String {
710 format!("{}", self.id)
711 }
712}
713
714impl Clone for EngineId {
715 fn clone(&self) -> Self {
716 Self::default()
717 }
718}
719
720impl Default for EngineId {
721 fn default() -> Self {
722 static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
723 Self {
724 id: NEXT_ID.fetch_add(1, SeqCst),
725 }
726 }
727}