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