1use std::{
5 fs::File,
6 io::BufReader,
7 mem::size_of,
8 path::{Path, PathBuf},
9 sync::{
10 Arc,
11 atomic::{AtomicUsize, Ordering::SeqCst},
12 },
13};
14
15#[cfg(feature = "compiler")]
16use crate::ModuleEnvironment;
17use crate::{
18 ArtifactBuild, ArtifactBuildFromArchive, ArtifactCreate, Engine, EngineInner, Features,
19 FrameInfosVariant, FunctionExtent, GlobalFrameInfoRegistration, InstantiationError, Tunables,
20 WASMER_TRAP_FUNCTION_OFFSETS_SECTION_NAME, WASMER_TRAPS_SECTION_NAME,
21 engine::{link::link_module, resolver::resolve_tags, trap::register_frame_info_source},
22 lib::std::vec::IntoIter,
23 resolve_imports,
24 serialize::{MetadataHeader, SerializableCompilation, SerializableModule},
25 types::relocation::{RelocationLike, RelocationTarget},
26};
27#[cfg(feature = "static-artifact-create")]
28use crate::{Compiler, FunctionBodyData, ModuleTranslationState, types::module::CompileModuleInfo};
29#[cfg(any(feature = "static-artifact-create", feature = "static-artifact-load"))]
30use crate::{serialize::RkyvSerializableCompilation, types::symbols::ModuleMetadata};
31use itertools::Itertools;
32#[cfg(unix)]
33use std::os::fd::AsRawFd;
34#[cfg(feature = "compiler")]
35use wasmer_types::CompilationProgressCallback;
36
37use enumset::EnumSet;
38use object::{Object as _, ObjectSection as _, ReadCache, ReadRef};
39use shared_buffer::OwnedBuffer;
40
41use crate::engine::mapped_binary::DebugInfoSource;
42
43#[cfg(any(feature = "static-artifact-create", feature = "static-artifact-load"))]
44use std::mem;
45
46#[cfg(feature = "static-artifact-create")]
47use crate::object::{
48 Object, ObjectMetadataBuilder, emit_compilation, emit_data, get_object_for_target,
49};
50
51use wasmer_types::{
52 ArchivedDataInitializerLocation, ArchivedOwnedDataInitializer, CompileError, DataInitializer,
53 DataInitializerLike, DataInitializerLocation, DataInitializerLocationLike, DeserializeError,
54 FunctionIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo, OwnedDataInitializer,
55 SerializeError, SignatureIndex, TableIndex, TrapCode, TrapInformation,
56 entity::{BoxedSlice, EntityRef, PrimaryMap},
57 target::{CpuFeature, Target},
58};
59
60use wasmer_types::VMOffsets;
61use wasmer_vm::{
62 FunctionBodyPtr, InstanceAllocator, MemoryStyle, StoreObjects, TableStyle, TrapHandlerFn,
63 VMConfig, VMExtern, VMInstance, VMSignatureHash, VMTrampoline,
64};
65
66#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
67pub struct AllocatedArtifact {
68 frame_info_registered: bool,
73 frame_info_registration: Option<GlobalFrameInfoRegistration>,
77 finished_functions: BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
78
79 #[cfg_attr(feature = "artifact-size", loupe(skip))]
80 finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
81 finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
82 signatures: BoxedSlice<SignatureIndex, VMSignatureHash>,
83 finished_function_lengths: BoxedSlice<LocalFunctionIndex, usize>,
84 function_max_stack_usage: BoxedSlice<LocalFunctionIndex, Option<usize>>,
86
87 #[cfg_attr(feature = "artifact-size", loupe(skip))]
100 vm_offsets: VMOffsets,
101
102 #[cfg_attr(feature = "artifact-size", loupe(skip))]
107 elf_image: Option<(usize, DebugInfoSource)>,
108}
109
110impl AllocatedArtifact {
111 fn function_extents(&self) -> PrimaryMap<LocalFunctionIndex, FunctionExtent> {
112 assert_eq!(
113 self.finished_functions.len(),
114 self.finished_function_lengths.len(),
115 "finished_functions and finished_function_lengths must have equal length"
116 );
117 self.finished_functions
118 .iter()
119 .map(|(index, &ptr)| {
120 let length = self.finished_function_lengths[index];
121 FunctionExtent { ptr, length }
122 })
123 .collect()
124 }
125}
126
127#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
128#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
129#[repr(transparent)]
130pub struct ArtifactId {
132 id: usize,
133}
134
135impl ArtifactId {
136 pub fn id(&self) -> String {
138 format!("{}", self.id)
139 }
140}
141
142impl Clone for ArtifactId {
143 fn clone(&self) -> Self {
144 Self::default()
145 }
146}
147
148impl Default for ArtifactId {
149 fn default() -> Self {
150 static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
151 Self {
152 id: NEXT_ID.fetch_add(1, SeqCst),
153 }
154 }
155}
156
157#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
159pub struct Artifact {
160 id: ArtifactId,
161 artifact: ArtifactBuildVariant,
162 #[cfg_attr(feature = "artifact-size", loupe(skip))]
163 module_file: Option<PathBuf>,
164 allocated: Option<AllocatedArtifact>,
167}
168
169#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
173#[allow(clippy::large_enum_variant)]
174pub enum ArtifactBuildVariant {
175 Plain(ArtifactBuild),
176 Archived(ArtifactBuildFromArchive),
177}
178
179impl Artifact {
180 #[cfg(feature = "compiler")]
182 pub fn new(
183 engine: &Engine,
184 data: &[u8],
185 tunables: &dyn Tunables,
186 progress_callback: Option<CompilationProgressCallback>,
187 ) -> Result<Self, CompileError> {
188 let mut inner_engine = engine.inner_mut();
189 let environ = ModuleEnvironment::new();
190 let translation = environ.translate(data).map_err(CompileError::Wasm)?;
191 let module = translation.module;
192 let memory_styles: PrimaryMap<MemoryIndex, MemoryStyle> = module
193 .memories
194 .values()
195 .map(|memory_type| tunables.memory_style(memory_type))
196 .collect();
197 let table_styles: PrimaryMap<TableIndex, TableStyle> = module
198 .tables
199 .values()
200 .map(|table_type| tunables.table_style(table_type))
201 .collect();
202
203 let artifact = ArtifactBuild::new(
204 &mut inner_engine,
205 data,
206 engine.target(),
207 memory_styles,
208 table_styles,
209 progress_callback.as_ref(),
210 )?;
211
212 Self::from_parts_with_module_file(
213 &mut inner_engine,
214 ArtifactBuildVariant::Plain(artifact),
215 engine.target(),
216 None,
217 )
218 .map_err(|e| match e {
219 DeserializeError::Compiler(c) => c,
220
221 _ => unreachable!(),
230 })
231 }
232
233 pub fn allocated(&self) -> bool {
237 self.allocated.is_some()
238 }
239
240 pub fn id(&self) -> &ArtifactId {
246 &self.id
247 }
248
249 #[cfg(not(feature = "compiler"))]
251 pub fn new(_engine: &Engine, _data: &[u8]) -> Result<Self, CompileError> {
252 Err(CompileError::Codegen(
253 "Compilation is not enabled in the engine".to_string(),
254 ))
255 }
256
257 pub unsafe fn deserialize_file(
265 engine: &Engine,
266 path: impl AsRef<Path>,
267 ) -> Result<Self, DeserializeError> {
268 let path = path.as_ref().to_path_buf();
269 let file = File::open(&path)?;
270 let cache = ReadCache::new(BufReader::new(file));
271 let image = object::File::parse(&cache)
272 .map_err(|e| DeserializeError::CorruptedBinary(format!("cannot parse image: {e}")))?;
273 if image.format() != object::BinaryFormat::Elf {
274 return Err(DeserializeError::Incompatible(
275 "Artifact::deserialize_file only supports ELF artifacts".to_string(),
276 ));
277 }
278
279 let module_info = image
280 .section_by_name_bytes(crate::WASMER_MODULE_INFO_SECTION_NAME)
281 .ok_or_else(|| {
282 DeserializeError::CorruptedBinary("missing ModuleInfo section".to_string())
283 })?
284 .data()
285 .map_err(|e| {
286 DeserializeError::CorruptedBinary(format!(
287 "cannot load ModuleInfo section data: {e}"
288 ))
289 })?;
290 let serializable = unsafe { SerializableModule::deserialize(module_info)? };
291 if !matches!(serializable.compilation, SerializableCompilation::Elf(_)) {
292 return Err(DeserializeError::Incompatible(
293 "file does not contain an ELF artifact".to_string(),
294 ));
295 }
296
297 let artifact = ArtifactBuildVariant::Plain(ArtifactBuild::from_serializable(serializable));
298 let mut inner_engine = engine.inner_mut();
299 Self::from_parts_with_module_file(&mut inner_engine, artifact, engine.target(), Some(path))
300 }
301
302 fn deserialize_elf(engine: &Engine, bytes: &[u8]) -> Result<Option<Self>, DeserializeError> {
304 if !bytes.starts_with(&object::elf::ELFMAG) {
305 return Ok(None);
306 }
307
308 let image = object::File::parse(bytes)
309 .map_err(|e| DeserializeError::CorruptedBinary(format!("cannot parse image: {e}")))?;
310 let module_info = image
311 .section_by_name_bytes(crate::WASMER_MODULE_INFO_SECTION_NAME)
312 .ok_or_else(|| {
313 DeserializeError::CorruptedBinary("missing ModuleInfo section".to_string())
314 })?
315 .data()
316 .map_err(|e| {
317 DeserializeError::CorruptedBinary(format!(
318 "cannot load ModuleInfo section data: {e}"
319 ))
320 })?;
321 let mut serializable = unsafe { SerializableModule::deserialize(module_info)? };
322 let SerializableCompilation::Elf(elf) = &mut serializable.compilation else {
323 return Err(DeserializeError::Incompatible(
324 "ELF image does not contain an ELF artifact".to_string(),
325 ));
326 };
327 *elf = bytes.to_vec();
330
331 let artifact = ArtifactBuildVariant::Plain(ArtifactBuild::from_serializable(serializable));
332 let mut inner_engine = engine.inner_mut();
333 Self::from_parts(&mut inner_engine, artifact, engine.target()).map(Some)
334 }
335
336 pub unsafe fn deserialize(
345 engine: &Engine,
346 bytes: OwnedBuffer,
347 ) -> Result<Self, DeserializeError> {
348 unsafe {
349 if !ArtifactBuild::is_deserializable(bytes.as_ref()) {
350 if let Some(artifact) = Self::deserialize_elf(engine, bytes.as_ref())? {
351 return Ok(artifact);
352 }
353
354 let static_artifact = Self::deserialize_object(engine, bytes);
355 match static_artifact {
356 Ok(v) => {
357 return Ok(v);
358 }
359 Err(e) => {
360 return Err(DeserializeError::Incompatible(format!(
361 "The provided bytes are not a Wasmer engine artifact: {e}"
362 )));
363 }
364 }
365 }
366
367 let artifact = ArtifactBuildFromArchive::try_new(bytes, |bytes| {
368 let bytes =
369 Self::get_byte_slice(bytes, ArtifactBuild::MAGIC_HEADER.len(), bytes.len())?;
370
371 let metadata_len = MetadataHeader::parse(bytes)?;
372 let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
373 let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
374
375 SerializableModule::archive_from_slice_checked(metadata_slice)
376 })?;
377
378 let mut inner_engine = engine.inner_mut();
379 Self::from_parts(
380 &mut inner_engine,
381 ArtifactBuildVariant::Archived(artifact),
382 engine.target(),
383 )
384 }
385 }
386
387 pub unsafe fn deserialize_unchecked(
396 engine: &Engine,
397 bytes: OwnedBuffer,
398 ) -> Result<Self, DeserializeError> {
399 unsafe {
400 if !ArtifactBuild::is_deserializable(bytes.as_ref()) {
401 if let Some(artifact) = Self::deserialize_elf(engine, bytes.as_ref())? {
402 return Ok(artifact);
403 }
404
405 let static_artifact = Self::deserialize_object(engine, bytes);
406 match static_artifact {
407 Ok(v) => {
408 return Ok(v);
409 }
410 Err(e) => {
411 return Err(DeserializeError::Incompatible(format!(
412 "The provided bytes are not a Wasmer engine artifact: {e}"
413 )));
414 }
415 }
416 }
417
418 let artifact = ArtifactBuildFromArchive::try_new(bytes, |bytes| {
419 let bytes =
420 Self::get_byte_slice(bytes, ArtifactBuild::MAGIC_HEADER.len(), bytes.len())?;
421
422 let metadata_len = MetadataHeader::parse(bytes)?;
423 let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
424 let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
425
426 SerializableModule::archive_from_slice(metadata_slice)
427 })?;
428
429 let mut inner_engine = engine.inner_mut();
430 Self::from_parts(
431 &mut inner_engine,
432 ArtifactBuildVariant::Archived(artifact),
433 engine.target(),
434 )
435 }
436 }
437
438 pub fn from_parts(
440 engine_inner: &mut EngineInner,
441 artifact: ArtifactBuildVariant,
442 target: &Target,
443 ) -> Result<Self, DeserializeError> {
444 Self::from_parts_with_module_file(engine_inner, artifact, target, None)
445 }
446
447 fn from_parts_with_module_file(
448 engine_inner: &mut EngineInner,
449 artifact: ArtifactBuildVariant,
450 target: &Target,
451 module_file: Option<PathBuf>,
452 ) -> Result<Self, DeserializeError> {
453 if !target.is_native() {
454 return Ok(Self {
455 id: Default::default(),
456 artifact,
457 module_file,
458 allocated: None,
459 });
460 } else {
461 let cpu_features = artifact.cpu_features();
463 if !target.cpu_features().is_superset(cpu_features) {
464 return Err(DeserializeError::Incompatible(format!(
465 "Some CPU Features needed for the artifact are missing: {:?}",
466 cpu_features.difference(*target.cpu_features())
467 )));
468 }
469 }
470 let module_info = artifact.module_info();
471
472 let elf_file_data = match &artifact {
473 ArtifactBuildVariant::Plain(p) => {
474 if let SerializableCompilation::Elf(data) = &p.serializable.compilation {
475 Some(data.as_ref())
476 } else {
477 None
478 }
479 }
480 ArtifactBuildVariant::Archived(a) => a.get_elf_file(),
481 };
482 let mut allocated = if let Some(module_file) = module_file.as_ref() {
483 if elf_file_data.is_none() {
484 return Err(DeserializeError::Incompatible(
485 "file-backed loading only supports ELF artifacts".to_string(),
486 ));
487 }
488 Self::allocate_elf_artifact_from_path(engine_inner, module_info, module_file)?
489 } else if let Some(elf_file_data) = elf_file_data {
490 Self::allocate_elf_artifact(engine_inner, module_info, elf_file_data)?
491 } else {
492 let (
493 finished_functions,
494 finished_function_call_trampolines,
495 finished_dynamic_function_trampolines,
496 custom_sections,
497 ) = match &artifact {
498 ArtifactBuildVariant::Plain(p) => engine_inner.allocate(
499 module_info,
500 p.get_function_bodies_ref()
501 .expect("RKYV path expected")
502 .values(),
503 p.get_function_call_trampolines_ref()
504 .expect("RKYV path expected")
505 .values(),
506 p.get_dynamic_function_trampolines_ref()
507 .expect("RKYV path expected")
508 .values(),
509 p.get_custom_sections_ref()
510 .expect("RKYV path expected")
511 .values(),
512 )?,
513
514 ArtifactBuildVariant::Archived(a) => engine_inner.allocate(
515 module_info,
516 a.get_function_bodies_ref()
517 .expect("RKYV path expected")
518 .values(),
519 a.get_function_call_trampolines_ref()
520 .expect("RKYV path expected")
521 .values(),
522 a.get_dynamic_function_trampolines_ref()
523 .expect("RKYV path expected")
524 .values(),
525 a.get_custom_sections_ref()
526 .expect("RKYV path expected")
527 .values(),
528 )?,
529 };
530
531 let get_got_address: Box<dyn Fn(RelocationTarget) -> Option<usize>> = match &artifact {
532 ArtifactBuildVariant::Plain(p) => {
533 if let Some(got) = p.get_got_ref().expect("RKYV path expected").index {
534 let relocs: Vec<_> = p
535 .get_custom_section_relocations_ref()
536 .expect("RKYV path expected")[got]
537 .iter()
538 .map(|v| (v.reloc_target, v.offset))
539 .collect();
540 let got_base = custom_sections[got].0 as usize;
541 Box::new(move |t: RelocationTarget| {
542 relocs
543 .iter()
544 .find(|(v, _)| v == &t)
545 .map(|(_, o)| got_base + (*o as usize))
546 })
547 } else {
548 Box::new(|_: RelocationTarget| None)
549 }
550 }
551
552 ArtifactBuildVariant::Archived(p) => {
553 if let Some(got) = p.get_got_ref().expect("RKYV path expected").index {
554 let relocs: Vec<_> = p
555 .get_custom_section_relocations_ref()
556 .expect("RKYV path expected")[got]
557 .iter()
558 .map(|v| (v.reloc_target(), v.offset))
559 .collect();
560 let got_base = custom_sections[got].0 as usize;
561 Box::new(move |t: RelocationTarget| {
562 relocs
563 .iter()
564 .find(|(v, _)| v == &t)
565 .map(|(_, o)| got_base + (o.to_native() as usize))
566 })
567 } else {
568 Box::new(|_: RelocationTarget| None)
569 }
570 }
571 };
572 let functions_max_stack_usage = match &artifact {
573 ArtifactBuildVariant::Plain(p) => p
574 .get_function_max_stack_usage()
575 .expect("RKYV path expected")
576 .values()
577 .cloned()
578 .collect::<PrimaryMap<LocalFunctionIndex, _>>(),
579 ArtifactBuildVariant::Archived(a) => a
580 .get_function_max_stack_usage()
581 .expect("RKYV path expected")
582 .values()
583 .cloned()
584 .collect::<PrimaryMap<LocalFunctionIndex, _>>(),
585 };
586
587 match &artifact {
588 ArtifactBuildVariant::Plain(p) => link_module(
589 module_info,
590 &finished_functions,
591 &finished_dynamic_function_trampolines,
592 p.get_function_relocations()
593 .expect("RKYV path expected")
594 .iter()
595 .map(|(k, v)| (k, v.iter())),
596 &custom_sections,
597 p.get_custom_section_relocations_ref()
598 .expect("RKYV path expected")
599 .iter()
600 .map(|(k, v)| (k, v.iter())),
601 p.get_libcall_trampolines().expect("RKYV path expected"),
602 p.get_libcall_trampoline_len().expect("RKYV path expected"),
603 &get_got_address,
604 ),
605 ArtifactBuildVariant::Archived(a) => link_module(
606 module_info,
607 &finished_functions,
608 &finished_dynamic_function_trampolines,
609 a.get_function_relocations()
610 .expect("RKYV path expected")
611 .iter()
612 .map(|(k, v)| (k, v.iter())),
613 &custom_sections,
614 a.get_custom_section_relocations_ref()
615 .expect("RKYV path expected")
616 .iter()
617 .map(|(k, v)| (k, v.iter())),
618 a.get_libcall_trampolines().expect("RKYV path expected"),
619 a.get_libcall_trampoline_len().expect("RKYV path expected"),
620 &get_got_address,
621 ),
622 };
623
624 let signatures = {
626 let signature_registry = engine_inner.signatures();
627 module_info
628 .signatures
629 .values()
630 .zip(module_info.signature_hashes.values())
631 .map(|(sig, sig_hash)| signature_registry.register(sig, *sig_hash))
632 .collect::<PrimaryMap<_, _>>()
633 };
634
635 #[allow(unused_variables)]
636 let eh_frame = match &artifact {
637 ArtifactBuildVariant::Plain(p) => p
638 .get_unwind_info()
639 .expect("RKYV path expected")
640 .eh_frame
641 .map(|v| unsafe {
642 std::slice::from_raw_parts(
643 *custom_sections[v],
644 p.get_custom_sections_ref().expect("RKYV path expected")[v]
645 .bytes
646 .len(),
647 )
648 }),
649 ArtifactBuildVariant::Archived(a) => a
650 .get_unwind_info()
651 .expect("RKYV path expected")
652 .eh_frame
653 .map(|v| unsafe {
654 std::slice::from_raw_parts(
655 *custom_sections[v],
656 a.get_custom_sections_ref().expect("RKYV path expected")[v]
657 .bytes
658 .len(),
659 )
660 }),
661 };
662 #[allow(unused_variables)]
663 let compact_unwind = match &artifact {
664 ArtifactBuildVariant::Plain(p) => p
665 .get_unwind_info()
666 .expect("RKYV path expected")
667 .compact_unwind
668 .map(|v| unsafe {
669 std::slice::from_raw_parts(
670 *custom_sections[v],
671 p.get_custom_sections_ref().expect("RKYV path expected")[v]
672 .bytes
673 .len(),
674 )
675 }),
676 ArtifactBuildVariant::Archived(a) => a
677 .get_unwind_info()
678 .expect("RKYV path expected")
679 .compact_unwind
680 .map(|v| unsafe {
681 std::slice::from_raw_parts(
682 *custom_sections[v],
683 a.get_custom_sections_ref().expect("RKYV path expected")[v]
684 .bytes
685 .len(),
686 )
687 }),
688 };
689
690 #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
691 {
692 engine_inner.register_perfmap(&finished_functions, module_info)?;
693 }
694
695 engine_inner.publish_compiled_code();
697
698 #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
699 if let Some(compact_unwind) = compact_unwind {
700 engine_inner.publish_compact_unwind(
701 compact_unwind,
702 get_got_address(RelocationTarget::LibCall(wasmer_vm::LibCall::EHPersonality)),
703 )?;
704 }
705 #[cfg(not(any(
706 target_arch = "wasm32",
707 all(target_os = "macos", target_arch = "aarch64")
708 )))]
709 engine_inner.publish_eh_frame(eh_frame)?;
710
711 drop(get_got_address);
712
713 let finished_function_lengths = finished_functions
714 .values()
715 .map(|extent| extent.length)
716 .collect::<PrimaryMap<LocalFunctionIndex, usize>>()
717 .into_boxed_slice();
718 let finished_functions = finished_functions
719 .values()
720 .map(|extent| extent.ptr)
721 .collect::<PrimaryMap<LocalFunctionIndex, FunctionBodyPtr>>()
722 .into_boxed_slice();
723 let finished_function_call_trampolines =
724 finished_function_call_trampolines.into_boxed_slice();
725 let finished_dynamic_function_trampolines =
726 finished_dynamic_function_trampolines.into_boxed_slice();
727 let signatures = signatures.into_boxed_slice();
728
729 let vm_offsets = VMOffsets::new(std::mem::size_of::<usize>() as u8, module_info);
730
731 AllocatedArtifact {
732 frame_info_registered: false,
733 frame_info_registration: None,
734 finished_functions,
735 finished_function_call_trampolines,
736 finished_dynamic_function_trampolines,
737 signatures,
738 finished_function_lengths,
739 vm_offsets,
740 function_max_stack_usage: functions_max_stack_usage.into_boxed_slice(),
741 elf_image: None,
742 }
743 };
744
745 if allocated.elf_image.is_some() {
750 allocated.function_max_stack_usage = match &artifact {
751 ArtifactBuildVariant::Plain(p) => p
752 .get_function_max_stack_usage()
753 .expect("function stack usage metadata expected")
754 .values()
755 .cloned()
756 .collect::<PrimaryMap<LocalFunctionIndex, _>>()
757 .into_boxed_slice(),
758 ArtifactBuildVariant::Archived(a) => a
759 .get_function_max_stack_usage()
760 .expect("function stack usage metadata expected")
761 .values()
762 .cloned()
763 .collect::<PrimaryMap<LocalFunctionIndex, _>>()
764 .into_boxed_slice(),
765 };
766 }
767
768 let mut artifact = Self {
769 id: Default::default(),
770 artifact,
771 module_file,
772 allocated: Some(allocated),
773 };
774
775 let is_elf = artifact
776 .allocated
777 .as_ref()
778 .expect("It must be allocated")
779 .elf_image
780 .is_some();
781
782 artifact
783 .internal_register_frame_info()
784 .map_err(|e| DeserializeError::CorruptedBinary(format!("{e:?}")))?;
785 if let Some(frame_info) = artifact.internal_take_frame_info_registration() {
786 if is_elf {
787 engine_inner.register_elf_frame_info(frame_info);
788 } else {
789 engine_inner.register_frame_info(frame_info);
790 }
791 }
792
793 Ok(artifact)
794 }
795
796 fn allocate_elf_artifact(
802 engine_inner: &mut EngineInner,
803 module_info: &ModuleInfo,
804 elf_file_data: &[u8],
805 ) -> Result<AllocatedArtifact, DeserializeError> {
806 let image = object::File::parse(elf_file_data)
807 .map_err(|e| DeserializeError::CorruptedBinary(format!("cannot parse image: {e}")))?;
808 let base = engine_inner.map_elf_binary(&image, elf_file_data)?;
809 Self::allocate_elf_artifact_from_image(
810 engine_inner,
811 module_info,
812 &image,
813 base,
814 DebugInfoSource::Bytes(Arc::from(elf_file_data)),
815 )
816 }
817
818 #[cfg(unix)]
819 fn allocate_elf_artifact_from_path(
820 engine_inner: &mut EngineInner,
821 module_info: &ModuleInfo,
822 path: &Path,
823 ) -> Result<AllocatedArtifact, DeserializeError> {
824 let file = File::open(path)?;
825 let fd = file.as_raw_fd();
826 let debug_file = Arc::new(file.try_clone()?);
827 let cache = ReadCache::new(BufReader::new(file));
828 let image = object::File::parse(&cache)
829 .map_err(|e| DeserializeError::CorruptedBinary(format!("cannot parse image: {e}")))?;
830 if image.format() != object::BinaryFormat::Elf {
831 return Err(DeserializeError::Incompatible(
832 "file-backed Artifact is not ELF".to_string(),
833 ));
834 }
835 let base = engine_inner.map_elf_binary_file(&image, fd)?;
836 #[cfg(feature = "compiler")]
837 if let Some(debugger) = engine_inner.debugger() {
838 engine_inner.register_debugger(path, base, debugger)?;
839 }
840 Self::allocate_elf_artifact_from_image(
841 engine_inner,
842 module_info,
843 &image,
844 base,
845 DebugInfoSource::File(debug_file),
846 )
847 }
848
849 #[cfg(not(unix))]
850 fn allocate_elf_artifact_from_path(
851 _engine_inner: &mut EngineInner,
852 _module_info: &ModuleInfo,
853 _path: &Path,
854 ) -> Result<AllocatedArtifact, DeserializeError> {
855 Err(DeserializeError::Incompatible(
856 "file-backed ELF artifacts are only supported on Unix".to_string(),
857 ))
858 }
859
860 fn allocate_elf_artifact_from_image<'a, R: object::ReadRef<'a>>(
861 engine_inner: &mut EngineInner,
862 module_info: &ModuleInfo,
863 image: &object::File<'a, R>,
864 base: *mut std::ffi::c_void,
865 debug_info: DebugInfoSource,
866 ) -> Result<AllocatedArtifact, DeserializeError> {
867 let mut function_offsets = None;
868 for section in image.sections() {
869 let Ok(section_name) = section.name_bytes() else {
870 continue;
871 };
872 match section_name {
873 crate::WASMER_FUNCTION_OFFSETS_SECTION_NAME => {
874 let data = section.data().map_err(|e| {
875 DeserializeError::CorruptedBinary(format!(
876 "cannot load image section data: {e}"
877 ))
878 })?;
879 function_offsets = Some(
880 data.chunks_exact(std::mem::size_of::<usize>())
881 .map(|chunk| usize::from_le_bytes(chunk.try_into().unwrap()))
882 .collect_vec(),
883 );
884 }
885 crate::EH_FRAME_SECTION_NAME => {
886 engine_inner.publish_elf_eh_frame(section.address(), section.size())?;
887 }
888 _ => {}
889 }
890 }
891
892 let Some(function_offsets) = function_offsets else {
893 return Err(DeserializeError::CorruptedBinary(
894 "missing function offset section in the image".to_string(),
895 ));
896 };
897
898 let local_function_count = module_info.local_func_count();
899 let corrupted_offsets = || {
900 DeserializeError::CorruptedBinary(format!(
901 "corrupted {} section",
902 String::from_utf8_lossy(crate::WASMER_FUNCTION_OFFSETS_SECTION_NAME)
903 ))
904 };
905 let signature_count = module_info.signatures.len();
906 let dynamic_trampoline_count = module_info.imported_function_types().count();
907 let expected_offset_count = local_function_count
908 .checked_add(signature_count)
909 .and_then(|count| count.checked_add(dynamic_trampoline_count))
910 .ok_or_else(&corrupted_offsets)?;
911 if function_offsets.len() != expected_offset_count {
912 return Err(corrupted_offsets());
913 }
914
915 let (local_fn_offsets, rest) = function_offsets.split_at(local_function_count);
916 let (trampoline_offsets, dynamic_trampoline_offsets) = rest.split_at(signature_count);
917
918 let local_fn_sizes = function_offsets
920 .iter()
921 .skip(1)
922 .take(local_function_count)
923 .zip(function_offsets.iter())
924 .map(|(f1, f0)| f1.checked_sub(*f0).ok_or_else(&corrupted_offsets))
925 .collect::<Result<Vec<_>, _>>()?;
926
927 let signatures = {
928 let signature_registry = engine_inner.signatures();
929 module_info
930 .signatures
931 .values()
932 .zip(module_info.signature_hashes.values())
933 .map(|(sig, sig_hash)| signature_registry.register(sig, *sig_hash))
934 .collect::<PrimaryMap<_, _>>()
935 .into_boxed_slice()
936 };
937
938 let finished_functions = local_fn_offsets
939 .iter()
940 .map(|&offset| FunctionBodyPtr(unsafe { base.add(offset) as _ }))
941 .collect::<PrimaryMap<LocalFunctionIndex, _>>();
942
943 #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
944 let finished_function_extents = local_fn_offsets
945 .iter()
946 .zip(local_fn_sizes.iter())
947 .map(|(&ptr, &length)| FunctionExtent {
948 ptr: FunctionBodyPtr(unsafe { base.add(ptr) as _ }),
949 length,
950 })
951 .collect::<PrimaryMap<LocalFunctionIndex, _>>();
952 #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
953 engine_inner.register_perfmap(&finished_function_extents, module_info)?;
954 let finished_function_call_trampolines = trampoline_offsets
955 .iter()
956 .map(|&offset| unsafe {
957 std::mem::transmute::<*mut std::ffi::c_void, VMTrampoline>(base.add(offset))
958 })
959 .collect::<PrimaryMap<SignatureIndex, _>>()
960 .into_boxed_slice();
961 let finished_dynamic_function_trampolines = dynamic_trampoline_offsets
962 .iter()
963 .map(|&offset| FunctionBodyPtr(unsafe { base.add(offset) as _ }))
964 .collect::<PrimaryMap<FunctionIndex, _>>()
965 .into_boxed_slice();
966 let finished_function_lengths =
967 PrimaryMap::<LocalFunctionIndex, _>::from_iter(local_fn_sizes).into_boxed_slice();
968 let function_max_stack_usage = finished_functions
969 .iter()
970 .map(|_| None)
971 .collect::<PrimaryMap<LocalFunctionIndex, Option<usize>>>()
972 .into_boxed_slice();
973
974 let vm_offsets = VMOffsets::new(std::mem::size_of::<usize>() as u8, module_info);
975
976 Ok(AllocatedArtifact {
977 frame_info_registered: false,
978 frame_info_registration: None,
979 finished_functions: finished_functions.into_boxed_slice(),
980 finished_function_call_trampolines,
981 finished_dynamic_function_trampolines,
982 signatures,
983 finished_function_lengths,
984 vm_offsets,
985 function_max_stack_usage,
986 elf_image: Some((base as usize, debug_info)),
987 })
988 }
989
990 pub fn is_deserializable(bytes: &[u8]) -> bool {
992 ArtifactBuild::is_deserializable(bytes)
993 }
994}
995
996impl PartialEq for Artifact {
997 fn eq(&self, other: &Self) -> bool {
998 self.id == other.id
999 }
1000}
1001impl Eq for Artifact {}
1002
1003impl std::fmt::Debug for Artifact {
1004 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1005 f.debug_struct("Artifact")
1006 .field("artifact_id", &self.id)
1007 .field("module_info", &self.module_info())
1008 .finish()
1009 }
1010}
1011
1012impl<'a> ArtifactCreate<'a> for Artifact {
1013 type OwnedDataInitializer = <ArtifactBuildVariant as ArtifactCreate<'a>>::OwnedDataInitializer;
1014 type OwnedDataInitializerIterator =
1015 <ArtifactBuildVariant as ArtifactCreate<'a>>::OwnedDataInitializerIterator;
1016
1017 fn set_module_info_name(&mut self, name: String) -> bool {
1018 self.artifact.set_module_info_name(name)
1019 }
1020
1021 fn create_module_info(&self) -> Arc<ModuleInfo> {
1022 self.artifact.create_module_info()
1023 }
1024
1025 fn module_info(&self) -> &ModuleInfo {
1026 self.artifact.module_info()
1027 }
1028
1029 fn features(&self) -> &Features {
1030 self.artifact.features()
1031 }
1032
1033 fn cpu_features(&self) -> EnumSet<CpuFeature> {
1034 self.artifact.cpu_features()
1035 }
1036
1037 fn data_initializers(&'a self) -> Self::OwnedDataInitializerIterator {
1038 self.artifact.data_initializers()
1039 }
1040
1041 fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
1042 self.artifact.memory_styles()
1043 }
1044
1045 fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
1046 self.artifact.table_styles()
1047 }
1048
1049 fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
1050 if let Some(module_file) = &self.module_file {
1051 return std::fs::read(module_file).map_err(|e| {
1052 SerializeError::Generic(format!("Failed to serialize Artifact file: {e}"))
1053 });
1054 }
1055 self.artifact.serialize()
1056 }
1057}
1058
1059impl<'a> ArtifactCreate<'a> for ArtifactBuildVariant {
1060 type OwnedDataInitializer = OwnedDataInitializerVariant<'a>;
1061 type OwnedDataInitializerIterator = IntoIter<Self::OwnedDataInitializer>;
1062
1063 fn create_module_info(&self) -> Arc<ModuleInfo> {
1064 match self {
1065 Self::Plain(artifact) => artifact.create_module_info(),
1066 Self::Archived(artifact) => artifact.create_module_info(),
1067 }
1068 }
1069
1070 fn set_module_info_name(&mut self, name: String) -> bool {
1071 match self {
1072 Self::Plain(artifact) => artifact.set_module_info_name(name),
1073 Self::Archived(artifact) => artifact.set_module_info_name(name),
1074 }
1075 }
1076
1077 fn module_info(&self) -> &ModuleInfo {
1078 match self {
1079 Self::Plain(artifact) => artifact.module_info(),
1080 Self::Archived(artifact) => artifact.module_info(),
1081 }
1082 }
1083
1084 fn features(&self) -> &Features {
1085 match self {
1086 Self::Plain(artifact) => artifact.features(),
1087 Self::Archived(artifact) => artifact.features(),
1088 }
1089 }
1090
1091 fn cpu_features(&self) -> EnumSet<CpuFeature> {
1092 match self {
1093 Self::Plain(artifact) => artifact.cpu_features(),
1094 Self::Archived(artifact) => artifact.cpu_features(),
1095 }
1096 }
1097
1098 fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
1099 match self {
1100 Self::Plain(artifact) => artifact.memory_styles(),
1101 Self::Archived(artifact) => artifact.memory_styles(),
1102 }
1103 }
1104
1105 fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
1106 match self {
1107 Self::Plain(artifact) => artifact.table_styles(),
1108 Self::Archived(artifact) => artifact.table_styles(),
1109 }
1110 }
1111
1112 fn data_initializers(&'a self) -> Self::OwnedDataInitializerIterator {
1113 match self {
1114 Self::Plain(artifact) => artifact
1115 .data_initializers()
1116 .map(OwnedDataInitializerVariant::Plain)
1117 .collect::<Vec<_>>()
1118 .into_iter(),
1119 Self::Archived(artifact) => artifact
1120 .data_initializers()
1121 .map(OwnedDataInitializerVariant::Archived)
1122 .collect::<Vec<_>>()
1123 .into_iter(),
1124 }
1125 }
1126
1127 fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
1128 match self {
1129 Self::Plain(artifact) => artifact.serialize(),
1130 Self::Archived(artifact) => artifact.serialize(),
1131 }
1132 }
1133}
1134
1135#[derive(Clone, Copy)]
1136pub enum OwnedDataInitializerVariant<'a> {
1137 Plain(&'a OwnedDataInitializer),
1138 Archived(&'a ArchivedOwnedDataInitializer),
1139}
1140
1141impl<'a> DataInitializerLike<'a> for OwnedDataInitializerVariant<'a> {
1142 type Location = DataInitializerLocationVariant<'a>;
1143
1144 fn location(&self) -> Self::Location {
1145 match self {
1146 Self::Plain(plain) => DataInitializerLocationVariant::Plain(plain.location()),
1147 Self::Archived(archived) => {
1148 DataInitializerLocationVariant::Archived(archived.location())
1149 }
1150 }
1151 }
1152
1153 fn data(&self) -> &'a [u8] {
1154 match self {
1155 Self::Plain(plain) => plain.data(),
1156 Self::Archived(archived) => archived.data(),
1157 }
1158 }
1159}
1160
1161#[derive(Clone, Copy)]
1162pub enum DataInitializerLocationVariant<'a> {
1163 Plain(&'a DataInitializerLocation),
1164 Archived(&'a ArchivedDataInitializerLocation),
1165}
1166
1167impl DataInitializerLocationVariant<'_> {
1168 pub fn clone_to_plain(&self) -> DataInitializerLocation {
1169 match self {
1170 Self::Plain(p) => (*p).clone(),
1171 Self::Archived(a) => DataInitializerLocation {
1172 memory_index: a.memory_index(),
1173 offset_expr: a.offset_expr(),
1174 },
1175 }
1176 }
1177}
1178
1179impl DataInitializerLocationLike for DataInitializerLocationVariant<'_> {
1180 fn memory_index(&self) -> MemoryIndex {
1181 match self {
1182 Self::Plain(plain) => plain.memory_index(),
1183 Self::Archived(archived) => archived.memory_index(),
1184 }
1185 }
1186
1187 fn offset_expr(&self) -> wasmer_types::InitExpr {
1188 match self {
1189 Self::Plain(plain) => plain.offset_expr(),
1190 Self::Archived(archived) => archived.offset_expr(),
1191 }
1192 }
1193}
1194
1195impl Artifact {
1196 fn internal_register_frame_info(&mut self) -> Result<(), DeserializeError> {
1197 if self
1198 .allocated
1199 .as_ref()
1200 .expect("It must be allocated")
1201 .frame_info_registered
1202 {
1203 return Ok(()); }
1205
1206 let frame_infos = match &self.artifact {
1210 ArtifactBuildVariant::Plain(p) => p
1211 .get_frame_info_ref()
1212 .map(|f| FrameInfosVariant::Owned(f.clone())),
1213 ArtifactBuildVariant::Archived(a) => a
1214 .get_frame_info_ref()
1215 .map(|_| FrameInfosVariant::Archived(a.clone())),
1216 };
1217
1218 let elf_image = self
1219 .allocated
1220 .as_ref()
1221 .expect("It must be allocated")
1222 .elf_image
1223 .clone();
1224
1225 if frame_infos.is_some() || elf_image.is_some() {
1226 let finished_function_extents = self
1227 .allocated
1228 .as_ref()
1229 .expect("It must be allocated")
1230 .function_extents()
1231 .into_boxed_slice();
1232
1233 let (image_base, elf_data) = match elf_image {
1234 Some((base, data)) => (base, Some(data)),
1235 None => (0, None),
1236 };
1237
1238 let frame_info_registration = &mut self
1239 .allocated
1240 .as_mut()
1241 .expect("It must be allocated")
1242 .frame_info_registration;
1243
1244 *frame_info_registration = register_frame_info_source(
1245 self.artifact.create_module_info(),
1246 &finished_function_extents,
1247 frame_infos,
1248 image_base,
1249 elf_data,
1250 );
1251 }
1252
1253 self.allocated
1254 .as_mut()
1255 .expect("It must be allocated")
1256 .frame_info_registered = true;
1257
1258 Ok(())
1259 }
1260
1261 fn internal_take_frame_info_registration(&mut self) -> Option<GlobalFrameInfoRegistration> {
1262 let frame_info_registration = &mut self
1263 .allocated
1264 .as_mut()
1265 .expect("It must be allocated")
1266 .frame_info_registration;
1267
1268 frame_info_registration.take()
1269 }
1270
1271 pub fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr> {
1274 &self
1275 .allocated
1276 .as_ref()
1277 .expect("It must be allocated")
1278 .finished_functions
1279 }
1280
1281 pub fn finished_function_extents(&self) -> Option<Vec<(LocalFunctionIndex, FunctionExtent)>> {
1293 let allocated = self.allocated.as_ref()?;
1294 Some(allocated.function_extents().into_iter().collect())
1295 }
1296
1297 pub fn finished_functions_max_stack_usage(
1299 &self,
1300 ) -> Option<Vec<(LocalFunctionIndex, Option<usize>)>> {
1301 let allocated = self.allocated.as_ref()?;
1302 Some(
1303 allocated
1304 .function_max_stack_usage
1305 .into_iter()
1306 .map(|f| (f.0, *f.1))
1307 .collect(),
1308 )
1309 }
1310
1311 pub fn finished_function_call_trampolines(&self) -> &BoxedSlice<SignatureIndex, VMTrampoline> {
1314 &self
1315 .allocated
1316 .as_ref()
1317 .expect("It must be allocated")
1318 .finished_function_call_trampolines
1319 }
1320
1321 pub fn finished_dynamic_function_trampolines(
1324 &self,
1325 ) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr> {
1326 &self
1327 .allocated
1328 .as_ref()
1329 .expect("It must be allocated")
1330 .finished_dynamic_function_trampolines
1331 }
1332
1333 pub fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSignatureHash> {
1335 &self
1336 .allocated
1337 .as_ref()
1338 .expect("It must be allocated")
1339 .signatures
1340 }
1341
1342 #[allow(clippy::result_large_err)]
1344 pub fn preinstantiate(&self) -> Result<(), InstantiationError> {
1345 Ok(())
1346 }
1347
1348 #[allow(clippy::result_large_err)]
1354 pub unsafe fn instantiate(
1355 &self,
1356 tunables: &dyn Tunables,
1357 imports: &[VMExtern],
1358 context: &mut StoreObjects,
1359 ) -> Result<VMInstance, InstantiationError> {
1360 unsafe {
1361 let host_cpu_features = CpuFeature::for_host();
1364 if !host_cpu_features.is_superset(self.cpu_features()) {
1365 return Err(InstantiationError::CpuFeature(format!(
1366 "{:?}",
1367 self.cpu_features().difference(host_cpu_features)
1368 )));
1369 }
1370
1371 self.preinstantiate()?;
1372
1373 let module = self.create_module_info();
1374
1375 let tags = resolve_tags(&module, imports, context).map_err(InstantiationError::Link)?;
1376
1377 let imports = resolve_imports(
1378 &module,
1379 imports,
1380 context,
1381 self.finished_dynamic_function_trampolines(),
1382 self.memory_styles(),
1383 self.table_styles(),
1384 )
1385 .map_err(InstantiationError::Link)?;
1386
1387 let cached_offsets = self
1391 .allocated
1392 .as_ref()
1393 .map(|a| a.vm_offsets.clone())
1394 .expect("Artifact::instantiate called on a non-host artifact");
1395
1396 let (
1397 allocator,
1398 memory_definition_locations,
1399 table_definition_locations,
1400 global_definition_locations,
1401 ) = InstanceAllocator::new_with_offsets(cached_offsets, &module);
1402 let finished_memories = tunables
1403 .create_memories(
1404 context,
1405 &module,
1406 self.memory_styles(),
1407 &memory_definition_locations,
1408 )
1409 .map_err(InstantiationError::Link)?
1410 .into_boxed_slice();
1411 let finished_tables = tunables
1412 .create_tables(
1413 context,
1414 &module,
1415 self.table_styles(),
1416 &table_definition_locations,
1417 )
1418 .map_err(InstantiationError::Link)?
1419 .into_boxed_slice();
1420 let finished_globals = tunables
1421 .create_globals(context, &module, &global_definition_locations)
1422 .map_err(InstantiationError::Link)?
1423 .into_boxed_slice();
1424
1425 let handle = VMInstance::new(
1426 allocator,
1427 module,
1428 context,
1429 self.finished_functions().clone(),
1430 self.finished_function_call_trampolines().clone(),
1431 finished_memories,
1432 finished_tables,
1433 finished_globals,
1434 tags,
1435 imports,
1436 self.signatures().clone(),
1437 )
1438 .map_err(InstantiationError::Start)?;
1439 Ok(handle)
1440 }
1441 }
1442
1443 #[allow(clippy::result_large_err)]
1449 pub unsafe fn finish_instantiation(
1450 &self,
1451 config: &VMConfig,
1452 trap_handler: Option<*const TrapHandlerFn<'static>>,
1453 handle: &mut VMInstance,
1454 ) -> Result<(), InstantiationError> {
1455 unsafe {
1456 let data_initializers = self
1457 .data_initializers()
1458 .map(|init| DataInitializer {
1459 location: init.location().clone_to_plain(),
1460 data: init.data(),
1461 })
1462 .collect::<Vec<_>>();
1463 handle
1464 .finish_instantiation(config, trap_handler, &data_initializers)
1465 .map_err(InstantiationError::Start)
1466 }
1467 }
1468
1469 #[allow(clippy::type_complexity)]
1470 #[cfg(feature = "static-artifact-create")]
1471 pub fn generate_metadata<'data>(
1473 data: &'data [u8],
1474 compiler: &dyn Compiler,
1475 tunables: &dyn Tunables,
1476 features: &Features,
1477 ) -> Result<
1478 (
1479 CompileModuleInfo,
1480 PrimaryMap<LocalFunctionIndex, FunctionBodyData<'data>>,
1481 Vec<DataInitializer<'data>>,
1482 Option<ModuleTranslationState>,
1483 ),
1484 CompileError,
1485 > {
1486 let environ = ModuleEnvironment::new();
1487 let translation = environ.translate(data).map_err(CompileError::Wasm)?;
1488
1489 use crate::translator::ModuleMiddlewareChain;
1491 let mut module = translation.module;
1492 let middlewares = compiler.get_middlewares();
1493 middlewares
1494 .apply_on_module_info(&mut module)
1495 .map_err(|e| CompileError::MiddlewareError(e.to_string()))?;
1496
1497 let memory_styles: PrimaryMap<MemoryIndex, MemoryStyle> = module
1498 .memories
1499 .values()
1500 .map(|memory_type| tunables.memory_style(memory_type))
1501 .collect();
1502 let table_styles: PrimaryMap<TableIndex, TableStyle> = module
1503 .tables
1504 .values()
1505 .map(|table_type| tunables.table_style(table_type))
1506 .collect();
1507
1508 let compile_info = CompileModuleInfo {
1509 module: Arc::new(module),
1510 features: features.clone(),
1511 memory_styles,
1512 table_styles,
1513 function_max_stack_usage: PrimaryMap::new(),
1514 };
1515 Ok((
1516 compile_info,
1517 translation.function_body_inputs,
1518 translation.data_initializers,
1519 translation.module_translation_state,
1520 ))
1521 }
1522
1523 #[cfg(feature = "static-artifact-create")]
1525 #[allow(clippy::type_complexity)]
1526 pub fn metadata<'a>(
1527 compiler: &dyn Compiler,
1528 data: &'a [u8],
1529 metadata_prefix: Option<&str>,
1530 target: &Target,
1531 tunables: &dyn Tunables,
1532 features: &Features,
1533 ) -> Result<
1534 (
1535 ModuleMetadata,
1536 Option<ModuleTranslationState>,
1537 PrimaryMap<LocalFunctionIndex, FunctionBodyData<'a>>,
1538 ),
1539 CompileError,
1540 > {
1541 #[allow(dead_code)]
1542 let (compile_info, function_body_inputs, data_initializers, module_translation) =
1543 Self::generate_metadata(data, compiler, tunables, features)?;
1544
1545 let data_initializers = data_initializers
1546 .iter()
1547 .map(OwnedDataInitializer::new)
1548 .collect::<Vec<_>>()
1549 .into_boxed_slice();
1550
1551 let function_body_lengths = function_body_inputs
1555 .keys()
1556 .map(|_function_body| 0u64)
1557 .collect::<PrimaryMap<LocalFunctionIndex, u64>>();
1558
1559 let metadata = ModuleMetadata {
1560 compile_info,
1561 prefix: metadata_prefix.map(|s| s.to_string()).unwrap_or_default(),
1562 data_initializers,
1563 function_body_lengths,
1564 cpu_features: target.cpu_features().as_u64(),
1565 };
1566
1567 Ok((metadata, module_translation, function_body_inputs))
1568 }
1569
1570 #[cfg(feature = "static-artifact-create")]
1578 pub fn generate_object<'data>(
1579 compiler: &dyn Compiler,
1580 data: &[u8],
1581 metadata_prefix: Option<&str>,
1582 target: &'data Target,
1583 tunables: &dyn Tunables,
1584 features: &Features,
1585 ) -> Result<
1586 (
1587 ModuleInfo,
1588 Object<'data>,
1589 usize,
1590 Box<dyn crate::types::symbols::SymbolRegistry>,
1591 ),
1592 CompileError,
1593 > {
1594 use crate::types::{
1595 function::Compilation,
1596 symbols::{ModuleMetadataSymbolRegistry, SymbolRegistry},
1597 };
1598
1599 fn to_compile_error(err: impl std::error::Error) -> CompileError {
1600 CompileError::Codegen(format!("{err}"))
1601 }
1602
1603 let target_triple = target.triple();
1604 let (mut metadata, module_translation, function_body_inputs) =
1605 Self::metadata(compiler, data, metadata_prefix, target, tunables, features)
1606 .map_err(to_compile_error)?;
1607
1608 let compilation = compiler.compile_module(
1626 target,
1627 &metadata.compile_info,
1628 &[],
1629 module_translation.as_ref().unwrap(),
1630 function_body_inputs,
1631 None,
1632 )?;
1633 let Compilation::Rkyv {
1634 compilation,
1635 function_max_stack_usage,
1636 } = compilation
1637 else {
1638 return Err(CompileError::Codegen(
1639 "ELF compilation unsupported yet".to_string(),
1640 ));
1641 };
1642 metadata.compile_info.function_max_stack_usage = function_max_stack_usage;
1643
1644 let mut metadata_builder =
1645 ObjectMetadataBuilder::new(&metadata, target_triple).map_err(to_compile_error)?;
1646 let (_compile_info, symbol_registry) = metadata.split();
1647 let mut obj = get_object_for_target(target_triple).map_err(to_compile_error)?;
1648
1649 let object_name = ModuleMetadataSymbolRegistry {
1650 prefix: metadata_prefix.unwrap_or_default().to_string(),
1651 }
1652 .symbol_to_name(crate::types::symbols::Symbol::Metadata);
1653
1654 let default_align = match target_triple.architecture {
1655 target_lexicon::Architecture::Aarch64(_) => {
1656 if matches!(
1657 target_triple.operating_system,
1658 target_lexicon::OperatingSystem::Darwin(_)
1659 ) {
1660 8
1661 } else {
1662 4
1663 }
1664 }
1665 _ => 1,
1666 };
1667
1668 let offset = emit_data(
1669 &mut obj,
1670 object_name.as_bytes(),
1671 metadata_builder.placeholder_data(),
1672 std::cmp::max(MetadataHeader::ALIGN as u64, default_align),
1673 )
1674 .map_err(to_compile_error)?;
1675 metadata_builder.set_section_offset(offset);
1676
1677 emit_compilation(
1678 &mut obj,
1679 compilation,
1680 &symbol_registry,
1681 target_triple,
1682 &metadata_builder,
1683 )
1684 .map_err(to_compile_error)?;
1685 Ok((
1686 Arc::try_unwrap(metadata.compile_info.module).unwrap(),
1687 obj,
1688 metadata_builder.placeholder_data().len(),
1689 Box::new(symbol_registry),
1690 ))
1691 }
1692
1693 #[cfg(not(feature = "static-artifact-load"))]
1698 pub unsafe fn deserialize_object(
1699 _engine: &Engine,
1700 _bytes: OwnedBuffer,
1701 ) -> Result<Self, DeserializeError> {
1702 Err(DeserializeError::Compiler(
1703 CompileError::UnsupportedFeature("static load is not compiled in".to_string()),
1704 ))
1705 }
1706
1707 fn get_byte_slice(input: &[u8], start: usize, end: usize) -> Result<&[u8], DeserializeError> {
1708 if (start == end && input.len() > start)
1709 || (start < end && input.len() > start && input.len() >= end)
1710 {
1711 Ok(&input[start..end])
1712 } else {
1713 Err(DeserializeError::InvalidByteLength {
1714 expected: end - start,
1715 got: input.len(),
1716 })
1717 }
1718 }
1719
1720 #[cfg(feature = "static-artifact-load")]
1725 pub unsafe fn deserialize_object(
1726 engine: &Engine,
1727 bytes: OwnedBuffer,
1728 ) -> Result<Self, DeserializeError> {
1729 unsafe {
1730 use crate::serialize::SerializableCompilation;
1731
1732 let bytes = bytes.as_slice();
1733 let metadata_len = MetadataHeader::parse(bytes)?;
1734 let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
1735 let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
1736 let metadata: ModuleMetadata = ModuleMetadata::deserialize(metadata_slice)?;
1737
1738 const WORD_SIZE: usize = mem::size_of::<usize>();
1739 let mut byte_buffer = [0u8; WORD_SIZE];
1740
1741 let mut cur_offset = MetadataHeader::LEN + metadata_len;
1742
1743 let byte_buffer_slice =
1744 Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1745 byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1746 cur_offset += WORD_SIZE;
1747
1748 let num_finished_functions = usize::from_ne_bytes(byte_buffer);
1749 let mut finished_functions: PrimaryMap<LocalFunctionIndex, FunctionBodyPtr> =
1750 PrimaryMap::new();
1751
1752 let engine_inner = engine.inner();
1753 let signature_registry = engine_inner.signatures();
1754
1755 for _i in 0..num_finished_functions {
1757 let byte_buffer_slice =
1758 Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1759 byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1760 let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
1761 cur_offset += WORD_SIZE;
1762
1763 finished_functions.push(fp);
1765 }
1766
1767 let signatures = {
1769 let module = &metadata.compile_info.module;
1770 module
1771 .signatures
1772 .values()
1773 .zip(module.signature_hashes.values())
1774 .map(|(sig, sig_hash)| signature_registry.register(sig, *sig_hash))
1775 .collect::<PrimaryMap<_, _>>()
1776 };
1777
1778 let mut finished_function_call_trampolines = PrimaryMap::new();
1780
1781 let byte_buffer_slice =
1782 Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1783 byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1784 cur_offset += WORD_SIZE;
1785 let num_function_trampolines = usize::from_ne_bytes(byte_buffer);
1786 for _ in 0..num_function_trampolines {
1787 let byte_buffer_slice =
1788 Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1789 byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1790 cur_offset += WORD_SIZE;
1791 let trampoline_ptr_bytes = usize::from_ne_bytes(byte_buffer);
1792 let trampoline = mem::transmute::<usize, VMTrampoline>(trampoline_ptr_bytes);
1793 finished_function_call_trampolines.push(trampoline);
1794 }
1796
1797 let mut finished_dynamic_function_trampolines = PrimaryMap::new();
1799 let byte_buffer_slice =
1800 Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1801 byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1802 cur_offset += WORD_SIZE;
1803 let num_dynamic_trampoline_functions = usize::from_ne_bytes(byte_buffer);
1804 for _i in 0..num_dynamic_trampoline_functions {
1805 let byte_buffer_slice =
1806 Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1807 byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1808 let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
1809 cur_offset += WORD_SIZE;
1810
1811 finished_dynamic_function_trampolines.push(fp);
1814 }
1815
1816 let artifact = ArtifactBuild::from_serializable(SerializableModule {
1817 compilation: SerializableCompilation::Rkyv(RkyvSerializableCompilation::default()),
1818 compile_info: metadata.compile_info,
1819 data_initializers: metadata.data_initializers,
1820 cpu_features: metadata.cpu_features,
1821 });
1822
1823 let finished_function_lengths = finished_functions
1824 .values()
1825 .map(|_| 0)
1826 .collect::<PrimaryMap<LocalFunctionIndex, usize>>()
1827 .into_boxed_slice();
1828 let function_max_stack_usage = finished_functions
1829 .iter()
1830 .map(|_| None)
1831 .collect::<PrimaryMap<LocalFunctionIndex, Option<usize>>>()
1832 .into_boxed_slice();
1833
1834 let artifact_variant = ArtifactBuildVariant::Plain(artifact);
1837 let vm_offsets = VMOffsets::new(
1838 std::mem::size_of::<usize>() as u8,
1839 artifact_variant.module_info(),
1840 );
1841
1842 Ok(Self {
1843 id: Default::default(),
1844 artifact: artifact_variant,
1845 module_file: None,
1846 allocated: Some(AllocatedArtifact {
1847 frame_info_registered: false,
1848 frame_info_registration: None,
1849 finished_functions: finished_functions.into_boxed_slice(),
1850 finished_function_call_trampolines: finished_function_call_trampolines
1851 .into_boxed_slice(),
1852 finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
1853 .into_boxed_slice(),
1854 signatures: signatures.into_boxed_slice(),
1855 finished_function_lengths,
1856 vm_offsets,
1857 function_max_stack_usage,
1858 elf_image: None,
1859 }),
1860 })
1861 }
1862 }
1863}
1864
1865pub(crate) struct TrapReader {
1870 source: DebugInfoSource,
1871}
1872
1873impl TrapReader {
1874 pub(crate) fn new(source: DebugInfoSource) -> Self {
1875 Self { source }
1876 }
1877
1878 pub(crate) fn lookup(
1881 &self,
1882 local_index: LocalFunctionIndex,
1883 rel_pos: u32,
1884 ) -> Option<TrapInformation> {
1885 match &self.source {
1886 DebugInfoSource::Bytes(data) => {
1887 let image = object::File::parse(&data[..]).ok()?;
1888 Self::lookup_in_image(&image, local_index, rel_pos)
1889 }
1890 DebugInfoSource::File(file) => {
1891 let cache = ReadCache::new(BufReader::new(file.try_clone().ok()?));
1892 let image = object::File::parse(&cache).ok()?;
1893 Self::lookup_in_image(&image, local_index, rel_pos)
1894 }
1895 }
1896 }
1897
1898 fn lookup_in_image<'data, R: ReadRef<'data>>(
1899 image: &object::File<'data, R>,
1900 local_index: LocalFunctionIndex,
1901 rel_pos: u32,
1902 ) -> Option<TrapInformation> {
1903 let traps_section = image.section_by_name_bytes(WASMER_TRAPS_SECTION_NAME)?;
1904 let trap_offsets = image
1905 .section_by_name_bytes(WASMER_TRAP_FUNCTION_OFFSETS_SECTION_NAME)?
1906 .data()
1907 .ok()?;
1908 let slot = local_index.index().checked_mul(size_of::<usize>())?;
1909 let offset_bytes = trap_offsets.get(slot..slot + size_of::<usize>())?;
1910
1911 let trap_address = usize::from_le_bytes(offset_bytes.try_into().ok()?);
1914 let trap_offset = trap_address.checked_sub(traps_section.address() as usize)?;
1915 let traps = Self::parse_function_traps(traps_section.data().ok()?, trap_offset)?;
1916 traps
1917 .binary_search_by_key(&rel_pos, |info| info.code_offset)
1918 .ok()
1919 .map(|index| traps[index])
1920 }
1921
1922 fn parse_function_traps(
1923 traps_section: &[u8],
1924 trap_offset: usize,
1925 ) -> Option<Vec<TrapInformation>> {
1926 const WORD_SIZE: usize = size_of::<u32>();
1927 const RECORD_SIZE: usize = 2 * WORD_SIZE;
1928
1929 let data = traps_section.get(trap_offset..)?;
1930 let count = u32::from_le_bytes(data.get(..WORD_SIZE)?.try_into().ok()?) as usize;
1931 let records_len = count.checked_mul(RECORD_SIZE)?;
1932 let records = data.get(WORD_SIZE..WORD_SIZE.checked_add(records_len)?)?;
1933
1934 records
1935 .chunks_exact(RECORD_SIZE)
1936 .map(|record| {
1937 let code_offset = u32::from_le_bytes(record[..WORD_SIZE].try_into().ok()?);
1938 let code = u32::from_le_bytes(record[WORD_SIZE..].try_into().ok()?);
1939 let trap_code = unsafe { std::mem::transmute::<u32, TrapCode>(code) };
1941 Some(TrapInformation {
1942 code_offset,
1943 trap_code,
1944 })
1945 })
1946 .collect()
1947 }
1948}