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