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