1#[cfg(feature = "unwind")]
4use crate::dwarf::WriterRelocate;
5
6#[cfg(feature = "unwind")]
7use crate::eh::{
8 CompactUnwindEntryData, FunctionLsdaData, build_compact_unwind_section, build_function_lsda,
9 build_lsda_section, build_tag_section, compact_unwind_encoding_aarch64,
10};
11
12#[cfg(feature = "unwind")]
13use crate::translator::CraneliftUnwindInfo;
14use crate::{
15 address_map::get_function_address_map,
16 config::{Cranelift, CraneliftOptLevel},
17 func_environ::{FuncEnvironment, get_function_name},
18 trampoline::{
19 FunctionBuilderContext, make_trampoline_dynamic_function, make_trampoline_function_call,
20 },
21 translator::{
22 FuncTranslator, compiled_function_unwind_info, irlibcall_to_libcall,
23 irreloc_to_relocationkind, signature_to_cranelift_ir,
24 },
25};
26use cranelift_codegen::{
27 Context, FinalizedMachReloc, FinalizedRelocTarget, MachTrap,
28 ir::{self, ExternalName, UserFuncName},
29};
30
31#[cfg(feature = "unwind")]
32use cranelift_codegen::gimli::{
33 constants::DW_EH_PE_absptr,
34 write::{Address, EhFrame, FrameDescriptionEntry, FrameTable, Writer},
35};
36
37use itertools::Itertools;
38use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
39#[cfg(feature = "unwind")]
40use std::collections::HashMap;
41use std::sync::Arc;
42use wasmer_compiler::WASM_TRAMPOLINE_ESTIMATED_BODY_SIZE;
43use wasmer_compiler::elf::{CompileOutput, compile_output_in_memory, compile_output_objects};
44use wasmer_compiler::types::function::Compilation;
45
46use wasmer_compiler::progress::ProgressContext;
47#[cfg(feature = "unwind")]
48use wasmer_compiler::types::{section::SectionIndex, unwind::CompiledFunctionUnwindInfo};
49use wasmer_compiler::{
50 Compiler, FunctionBinaryReader, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware,
51 ModuleMiddlewareChain, ModuleTranslationState, WasmSourceMap,
52 types::{
53 function::{
54 CompiledFunction, CompiledFunctionFrameInfo, FunctionBody, RkyvCompilation, UnwindInfo,
55 },
56 module::CompileModuleInfo,
57 relocation::{Relocation, RelocationKind, RelocationTarget},
58 section::{CustomSection, CustomSectionProtection, SectionBody},
59 },
60};
61use wasmer_compiler::{build_function_buckets, translate_function_buckets};
62#[cfg(feature = "unwind")]
63use wasmer_types::LibCall;
64#[cfg(feature = "unwind")]
65use wasmer_types::entity::EntityRef;
66use wasmer_types::entity::PrimaryMap;
67#[cfg(feature = "unwind")]
68use wasmer_types::target::CallingConvention;
69use wasmer_types::target::Target;
70use wasmer_types::{
71 CompilationProgressCallback, CompileError, FunctionIndex, LocalFunctionIndex, ModuleInfo,
72 SignatureIndex, TrapCode, TrapInformation,
73};
74
75pub struct CraneliftCompiledFunction {
76 function: CompiledFunction,
77 #[cfg(feature = "unwind")]
78 fde: Option<FrameDescriptionEntry>,
79 #[cfg(feature = "unwind")]
80 function_lsda: Option<FunctionLsdaData>,
81 #[cfg(feature = "unwind")]
82 compact_unwind_encoding: Option<u32>,
83}
84
85impl wasmer_compiler::CompiledFunction for CraneliftCompiledFunction {}
86
87#[derive(Debug)]
90pub struct CraneliftCompiler {
91 config: Cranelift,
92}
93
94impl CraneliftCompiler {
95 pub fn new(config: Cranelift) -> Self {
97 Self { config }
98 }
99
100 pub fn config(&self) -> &Cranelift {
102 &self.config
103 }
104
105 fn compile_module_internal(
108 &self,
109 target: &Target,
110 compile_info: &CompileModuleInfo,
111 compile_info_blob: &[u8],
112 module_translation_state: &ModuleTranslationState,
113 function_body_inputs: PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
114 progress_callback: Option<&CompilationProgressCallback>,
115 ) -> Result<Compilation, CompileError> {
116 let function_max_stack_usage = function_body_inputs.iter().map(|_| None).collect();
117 let isa = self
118 .config()
119 .isa(target)
120 .map_err(|error| CompileError::Codegen(error.to_string()))?;
121 let frontend_config = isa.frontend_config();
122 #[cfg(feature = "unwind")]
123 let pointer_bytes = frontend_config.pointer_bytes();
124 #[cfg(feature = "unwind")]
125 let emit_macho_compact_unwind = matches!(
126 target.triple(),
127 target_lexicon::Triple {
128 binary_format: target_lexicon::BinaryFormat::Macho,
129 operating_system: target_lexicon::OperatingSystem::Darwin(_),
130 architecture: target_lexicon::Architecture::Aarch64(_),
131 ..
132 }
133 );
134 let memory_styles = &compile_info.memory_styles;
135 let table_styles = &compile_info.table_styles;
136 let module = &compile_info.module;
137 let source_map = Arc::new(if self.config.experimental_artifact {
138 WasmSourceMap::new(module, module_translation_state, &function_body_inputs)
139 .map_err(CompileError::Codegen)?
140 } else {
141 WasmSourceMap::default()
142 });
143
144 let signatures = module
145 .signatures
146 .iter()
147 .map(|(_sig_index, func_type)| {
148 signature_to_cranelift_ir(func_type, frontend_config, target.triple().architecture)
149 })
150 .collect::<PrimaryMap<SignatureIndex, ir::Signature>>();
151 let signature_hashes = &module.signature_hashes;
152
153 let total_function_call_trampolines = module.signatures.len();
154 let total_dynamic_trampolines = module.num_imported_functions;
155 let total_steps = WASM_TRAMPOLINE_ESTIMATED_BODY_SIZE
156 * ((total_dynamic_trampolines + total_function_call_trampolines) as u64)
157 + function_body_inputs
158 .iter()
159 .map(|(_, body)| body.data.len() as u64)
160 .sum::<u64>();
161 let progress = progress_callback
162 .cloned()
163 .map(|cb| ProgressContext::new(cb, total_steps, "cranelift::functions"));
164
165 #[cfg(feature = "unwind")]
167 let dwarf_frametable = if function_body_inputs.is_empty() {
168 None
172 } else {
173 match target.triple().default_calling_convention() {
174 Ok(CallingConvention::SystemV) => match isa.create_systemv_cie() {
175 Some(mut cie) => {
176 cie.personality = Some((
177 DW_EH_PE_absptr,
178 Address::Symbol {
179 symbol: WriterRelocate::PERSONALITY_SYMBOL,
180 addend: 0,
181 },
182 ));
183 cie.lsda_encoding = Some(DW_EH_PE_absptr);
184 let mut dwarf_frametable = FrameTable::default();
185 let cie_id = dwarf_frametable.add_cie(cie);
186 Some((dwarf_frametable, cie_id))
187 }
188 None => None,
190 },
191 _ => None,
192 }
193 };
194
195 let compile_function = |func_translator: &mut FuncTranslator,
198 i: &LocalFunctionIndex,
199 input: &FunctionBodyData|
200 -> Result<
201 CompileOutput<CraneliftCompiledFunction>,
202 CompileError,
203 > {
204 let func_index = module.func_index(*i);
205 let mut context = Context::new();
206 let mut func_env = FuncEnvironment::new(
207 isa.frontend_config(),
208 target.triple().architecture,
209 module,
210 &signatures,
211 signature_hashes,
212 memory_styles,
213 table_styles,
214 );
215 context.func.name = match get_function_name(&mut context.func, func_index) {
216 ExternalName::User(nameref) => {
217 if context.func.params.user_named_funcs().is_valid(nameref) {
218 let name = &context.func.params.user_named_funcs()[nameref];
219 UserFuncName::User(name.clone())
220 } else {
221 UserFuncName::default()
222 }
223 }
224 ExternalName::TestCase(testcase) => UserFuncName::Testcase(testcase),
225 _ => UserFuncName::default(),
226 };
227 context.func.signature = signatures[module.functions[func_index]].clone();
228 let mut reader =
233 MiddlewareBinaryReader::new_with_offset(input.data, input.module_offset);
234 reader.set_middleware_chain(
235 self.config
236 .middlewares
237 .generate_function_middleware_chain(*i),
238 );
239
240 func_translator.translate(
241 module_translation_state,
242 &mut reader,
243 &mut context.func,
244 &mut func_env,
245 *i,
246 )?;
247
248 if let Some(callbacks) = self.config.callbacks.as_ref() {
249 use wasmer_compiler::misc::CompiledKind;
250
251 callbacks.preopt_ir(
252 &CompiledKind::Local(*i, compile_info.module.get_function_name(func_index)),
253 &compile_info.module.hash_string(),
254 context.func.display().to_string().as_bytes(),
255 );
256 }
257
258 let mut code_buf: Vec<u8> = Vec::new();
259 let mut ctrl_plane = Default::default();
260 let func_name_map = context.func.params.user_named_funcs().clone();
261 let result = context
262 .compile(&*isa, &mut ctrl_plane)
263 .map_err(|error| CompileError::Codegen(format!("{error:#?}")))?;
264 code_buf.extend_from_slice(result.code_buffer());
265
266 if let Some(callbacks) = self.config.callbacks.as_ref() {
267 use wasmer_compiler::misc::CompiledKind;
268
269 callbacks.obj_memory_buffer(
270 &CompiledKind::Local(*i, compile_info.module.get_function_name(func_index)),
271 &compile_info.module.hash_string(),
272 &code_buf,
273 );
274 callbacks.asm_memory_buffer(
275 &CompiledKind::Local(*i, compile_info.module.get_function_name(func_index)),
276 &compile_info.module.hash_string(),
277 target.triple().architecture,
278 &code_buf,
279 )?;
280 }
281
282 let func_relocs = result
283 .buffer
284 .relocs()
285 .iter()
286 .map(|r| mach_reloc_to_reloc(module, &func_name_map, r))
287 .collect::<Vec<_>>();
288
289 let traps = result
290 .buffer
291 .traps()
292 .iter()
293 .map(mach_trap_to_trap)
294 .collect::<Vec<_>>();
295
296 #[cfg(feature = "unwind")]
297 let emit_lsda = dwarf_frametable.is_some() || emit_macho_compact_unwind;
298
299 #[cfg(feature = "unwind")]
300 let compact_unwind_encoding = if emit_macho_compact_unwind {
301 Some(
302 compact_unwind_encoding_aarch64(&result.buffer.unwind_info).map_err(|error| {
303 CompileError::Codegen(format!(
304 "failed to encode aarch64 Mach-O compact unwind for function {}: {error}",
305 i.index()
306 ))
307 })?,
308 )
309 } else {
310 None
311 };
312
313 #[cfg(feature = "unwind")]
314 let function_lsda = if emit_lsda {
315 build_function_lsda(
316 result.buffer.call_sites(),
317 result.buffer.data().len(),
318 pointer_bytes,
319 self.config.experimental_artifact,
320 )
321 } else {
322 None
323 };
324
325 #[allow(unused)]
326 let (unwind_info, fde) = match compiled_function_unwind_info(&*isa, &context)? {
327 #[cfg(feature = "unwind")]
328 CraneliftUnwindInfo::Fde(fde) => {
329 if dwarf_frametable.is_some() {
330 let addend = if self.config.experimental_artifact {
334 0
335 } else {
336 i.index() as _
339 };
340 let fde = fde.to_fde(Address::Symbol {
341 symbol: WriterRelocate::FUNCTION_SYMBOL,
344 addend,
345 });
346 (Some(CompiledFunctionUnwindInfo::Dwarf), Some(fde))
348 } else {
349 (None, None)
350 }
351 }
352 #[cfg(feature = "unwind")]
353 other => (other.maybe_into_to_windows_unwind(), None),
354
355 #[cfg(not(feature = "unwind"))]
358 other => (other.maybe_into_to_windows_unwind(), None::<()>),
359 };
360
361 let range = reader.range();
362 let address_map = get_function_address_map(&context, range, code_buf.len());
363
364 let compiled = CraneliftCompiledFunction {
365 function: CompiledFunction {
366 body: FunctionBody {
367 body: code_buf,
368 unwind_info,
369 },
370 relocations: func_relocs,
371 frame_info: CompiledFunctionFrameInfo { address_map, traps },
372 maximum_stack_usage: None,
373 },
374 #[cfg(feature = "unwind")]
375 fde,
376 #[cfg(feature = "unwind")]
377 function_lsda,
378 #[cfg(feature = "unwind")]
379 compact_unwind_encoding,
380 };
381
382 if self.config.experimental_artifact {
383 let object = crate::elf::emit_local_function(
384 #[cfg(feature = "unwind")]
385 &*isa,
386 target,
387 *i,
388 &compile_info.module.get_function_name(func_index),
389 compile_info.module.name.as_deref(),
390 &compiled.function,
391 &source_map,
392 #[cfg(feature = "unwind")]
393 compiled.fde,
394 #[cfg(feature = "unwind")]
395 compiled.function_lsda,
396 )?;
397 Ok(CompileOutput::Object(object, None))
398 } else {
399 Ok(CompileOutput::InMemory(compiled))
400 }
401 };
402
403 #[cfg_attr(not(feature = "unwind"), allow(unused_mut))]
404 let mut custom_sections = PrimaryMap::new();
405
406 let num_threads = self.config.num_threads.get();
407 let pool = rayon::ThreadPoolBuilder::new()
408 .num_threads(num_threads)
409 .build()
410 .unwrap();
411 let results = {
412 use wasmer_compiler::WASM_LARGE_FUNCTION_THRESHOLD;
413
414 let buckets =
415 build_function_buckets(&function_body_inputs, WASM_LARGE_FUNCTION_THRESHOLD / 3);
416 let largest_bucket = buckets.first().map(|b| b.size).unwrap_or_default();
417 tracing::debug!(buckets = buckets.len(), largest_bucket, "buckets built");
418
419 translate_function_buckets(
420 &pool,
421 || FuncTranslator::new(self.config.allow_experimental_unaligned_memory_accesses),
422 |func_translator, i, input| compile_function(func_translator, i, input),
423 progress.clone(),
424 &buckets,
425 )?
426 };
427
428 let module_hash = module.hash_string();
429
430 let function_call_trampoline_outputs = module
432 .signatures
433 .iter()
434 .collect_vec()
435 .par_iter()
436 .map_init(FunctionBuilderContext::new, |cx, (sig_index, sig)| {
437 let kind = wasmer_compiler::misc::CompiledKind::FunctionCallTrampoline(
438 *sig_index,
439 (*sig).clone(),
440 );
441 let trampoline = make_trampoline_function_call(
442 &self.config().callbacks,
443 &*isa,
444 target.triple().architecture,
445 cx,
446 &kind,
447 sig,
448 &module_hash,
449 )?;
450 if let Some(progress) = progress.as_ref() {
451 progress.notify_steps(WASM_TRAMPOLINE_ESTIMATED_BODY_SIZE)?;
452 }
453 if self.config.experimental_artifact {
454 Ok(CompileOutput::Object(
455 wasmer_compiler::elf::emit_function_body(target, &kind, &trampoline)?,
456 None,
457 ))
458 } else {
459 Ok(CompileOutput::InMemory(trampoline))
460 }
461 })
462 .collect::<Result<Vec<_>, CompileError>>()?;
463
464 use wasmer_types::VMOffsets;
465 let offsets = VMOffsets::new_for_trampolines(frontend_config.pointer_bytes());
466 let dynamic_function_trampoline_outputs = module
468 .imported_function_types()
469 .enumerate()
470 .collect_vec()
471 .par_iter()
472 .map_init(FunctionBuilderContext::new, |cx, (index, func_type)| {
473 let kind = wasmer_compiler::misc::CompiledKind::DynamicFunctionTrampoline(
474 FunctionIndex::from_u32(*index as u32),
475 func_type.clone(),
476 );
477 let trampoline = make_trampoline_dynamic_function(
478 &self.config().callbacks,
479 &*isa,
480 target.triple().architecture,
481 &offsets,
482 cx,
483 &kind,
484 func_type,
485 &module_hash,
486 )?;
487 if let Some(progress) = progress.as_ref() {
488 progress.notify_steps(WASM_TRAMPOLINE_ESTIMATED_BODY_SIZE)?;
489 }
490 if self.config.experimental_artifact {
491 Ok(CompileOutput::Object(
492 wasmer_compiler::elf::emit_function_body(target, &kind, &trampoline)?,
493 None,
494 ))
495 } else {
496 Ok(CompileOutput::InMemory(trampoline))
497 }
498 })
499 .collect::<Result<Vec<_>, CompileError>>()?;
500
501 if self.config.experimental_artifact {
502 let object_files = compile_output_objects(results);
503 let trampoline_objects = compile_output_objects(function_call_trampoline_outputs);
504 let dynamic_trampoline_objects =
505 compile_output_objects(dynamic_function_trampoline_outputs);
506 return wasmer_compiler::elf::link_module(
507 &pool,
508 target,
509 compile_info_blob,
510 object_files,
511 Vec::new(),
512 trampoline_objects,
513 dynamic_trampoline_objects,
514 self.config
515 .callbacks
516 .as_ref()
517 .map(|callbacks| callbacks.debug_dir().clone()),
518 module.hash().map(|hash| hash.to_string()),
519 function_max_stack_usage,
520 );
521 }
522
523 let results = compile_output_in_memory(results);
524
525 let mut functions = Vec::with_capacity(function_body_inputs.len());
526 #[cfg(feature = "unwind")]
527 let mut fdes = Vec::with_capacity(function_body_inputs.len());
528 #[cfg(feature = "unwind")]
529 let mut lsda_data = Vec::with_capacity(function_body_inputs.len());
530 #[cfg(feature = "unwind")]
531 let mut compact_unwind_entries = Vec::new();
532
533 for compiled in results {
534 let CraneliftCompiledFunction {
535 function,
536 #[cfg(feature = "unwind")]
537 fde,
538 #[cfg(feature = "unwind")]
539 function_lsda,
540 #[cfg(feature = "unwind")]
541 compact_unwind_encoding,
542 } = compiled;
543 #[cfg(feature = "unwind")]
544 let local_function_index = LocalFunctionIndex::new(functions.len());
545 functions.push(function);
546 #[cfg(feature = "unwind")]
547 {
548 fdes.push(fde);
549 lsda_data.push(function_lsda);
550 if let Some(compact_encoding) = compact_unwind_encoding {
551 let function_length = functions
552 .last()
553 .expect("function was just pushed")
554 .body
555 .body
556 .len()
557 .try_into()
558 .map_err(|_| {
559 CompileError::Codegen(
560 "function body too large for Mach-O compact unwind".into(),
561 )
562 })?;
563 compact_unwind_entries.push((
564 local_function_index,
565 function_length,
566 compact_encoding,
567 ));
568 }
569 }
570 }
571
572 #[cfg(feature = "unwind")]
573 let (_tag_section_index, lsda_section_index, function_lsda_offsets) =
574 if dwarf_frametable.is_some() || emit_macho_compact_unwind {
575 let mut tag_section_index = None;
576 let mut tag_offsets = HashMap::new();
577 if let Some((tag_section, offsets)) = build_tag_section(&lsda_data) {
578 custom_sections.push(tag_section);
579 tag_section_index = Some(SectionIndex::new(custom_sections.len() - 1));
580 tag_offsets = offsets;
581 }
582 let lsda_vec = lsda_data;
583 let (lsda_section, offsets_per_function) =
584 build_lsda_section(lsda_vec, pointer_bytes, &tag_offsets, tag_section_index);
585 let mut lsda_section_index = None;
586 if let Some(section) = lsda_section {
587 custom_sections.push(section);
588 lsda_section_index = Some(SectionIndex::new(custom_sections.len() - 1));
589 }
590 (tag_section_index, lsda_section_index, offsets_per_function)
591 } else {
592 (None, None, vec![None; functions.len()])
593 };
594
595 #[cfg_attr(not(feature = "unwind"), allow(unused_mut))]
596 let mut unwind_info = UnwindInfo::default();
597
598 #[cfg(feature = "unwind")]
599 if let Some((mut dwarf_frametable, cie_id)) = dwarf_frametable {
600 for (func_idx, fde_opt) in fdes.into_iter().enumerate() {
601 if let Some(mut fde) = fde_opt {
602 let has_lsda = function_lsda_offsets
603 .get(func_idx)
604 .and_then(|v| *v)
605 .is_some();
606 let lsda_address = if has_lsda {
607 debug_assert!(
608 lsda_section_index.is_some(),
609 "LSDA offsets require an LSDA section"
610 );
611 if lsda_section_index.is_some() {
612 let symbol =
613 WriterRelocate::lsda_symbol(LocalFunctionIndex::new(func_idx));
614 Address::Symbol { symbol, addend: 0 }
615 } else {
616 Address::Constant(0)
617 }
618 } else {
619 Address::Constant(0)
620 };
621 fde.lsda = Some(lsda_address);
622 dwarf_frametable.add_fde(cie_id, fde);
623 }
624 }
625
626 let mut writer = WriterRelocate::new(target.triple().endianness().ok());
627 if let Some(lsda_section_index) = lsda_section_index {
628 for (func_idx, offset) in function_lsda_offsets.iter().enumerate() {
629 if let Some(offset) = offset {
630 writer.register_lsda_symbol(
631 WriterRelocate::lsda_symbol(LocalFunctionIndex::new(func_idx)),
632 RelocationTarget::CustomSection(lsda_section_index),
633 *offset,
634 );
635 }
636 }
637 }
638
639 let mut eh_frame = EhFrame(writer);
640 dwarf_frametable.write_eh_frame(&mut eh_frame).unwrap();
641 eh_frame.write(&[0, 0, 0, 0]).unwrap(); let eh_frame_section = eh_frame.0.into_section();
644 custom_sections.push(eh_frame_section);
645 unwind_info.eh_frame = Some(SectionIndex::new(custom_sections.len() - 1));
646 };
647
648 #[cfg(feature = "unwind")]
649 if emit_macho_compact_unwind {
650 let entries = compact_unwind_entries
651 .into_iter()
652 .map(|(function, function_length, compact_encoding)| {
653 let lsda_offset = function_lsda_offsets
654 .get(function.index())
655 .and_then(|offset| *offset);
656 CompactUnwindEntryData {
657 function,
658 function_length,
659 compact_encoding,
660 lsda_offset,
661 }
662 })
663 .collect::<Vec<_>>();
664 if let Some(section) = build_compact_unwind_section(entries, lsda_section_index) {
665 custom_sections.push(section);
666 unwind_info.compact_unwind = Some(SectionIndex::new(custom_sections.len() - 1));
667 }
668 }
669
670 let function_call_trampolines = compile_output_in_memory(function_call_trampoline_outputs)
671 .into_iter()
672 .collect();
673 let dynamic_function_trampolines =
674 compile_output_in_memory(dynamic_function_trampoline_outputs)
675 .into_iter()
676 .collect();
677
678 let mut got = wasmer_compiler::types::function::GOT::empty();
679
680 #[cfg(feature = "unwind")]
681 if emit_macho_compact_unwind {
682 let got_idx = SectionIndex::from_u32(custom_sections.len() as u32);
683 custom_sections.push(CustomSection {
684 protection: CustomSectionProtection::Read,
685 alignment: Some(pointer_bytes.into()),
686 bytes: SectionBody::new_with_vec(vec![0; pointer_bytes as usize]),
687 relocations: vec![Relocation {
688 kind: match pointer_bytes {
689 4 => RelocationKind::Abs4,
690 8 => RelocationKind::Abs8,
691 _ => unreachable!("unsupported pointer size for Mach-O compact unwind GOT"),
692 },
693 reloc_target: RelocationTarget::LibCall(LibCall::EHPersonality),
694 offset: 0,
695 addend: 0,
696 }],
697 });
698 got.index = Some(got_idx);
699 }
700
701 Ok(Compilation::Rkyv {
702 compilation: RkyvCompilation {
703 functions: functions.into_iter().collect(),
704 custom_sections,
705 function_call_trampolines,
706 dynamic_function_trampolines,
707 unwind_info,
708 got,
709 },
710 function_max_stack_usage,
711 })
712 }
713}
714
715impl Compiler for CraneliftCompiler {
716 fn name(&self) -> &str {
717 "cranelift"
718 }
719
720 fn get_perfmap_enabled(&self) -> bool {
721 self.config.enable_perfmap
722 }
723
724 fn get_debugger(&self) -> Option<wasmer_compiler::Debugger> {
725 self.config.debugger
726 }
727
728 fn deterministic_id(&self) -> String {
729 use wasmer_compiler::DeterministicIdComponent as Component;
730
731 let mut components = vec![Component::Cranelift];
732 components.push(match self.config.opt_level {
733 CraneliftOptLevel::None => Component::OptNone,
734 CraneliftOptLevel::Speed => Component::OptSpeed,
735 CraneliftOptLevel::SpeedAndSize => Component::OptSpeedAndSize,
736 });
737 if self.config.enable_nan_canonicalization {
738 components.push(Component::NanCanonicalization);
739 }
740 if self.config.enable_pic {
741 components.push(Component::Pic);
742 }
743 if self.config.allow_experimental_unaligned_memory_accesses {
744 components.push(Component::ExperimentalUnalignedMemoryAccesses);
745 }
746
747 components
748 .into_iter()
749 .map(|component| component.to_string())
750 .collect_vec()
751 .join("-")
752 }
753
754 fn artifact_format(&self) -> String {
755 if self.config.experimental_artifact {
756 wasmer_compiler::ArtifactFormat::Native
757 } else {
758 wasmer_compiler::ArtifactFormat::Rkyv
759 }
760 .to_string()
761 }
762
763 fn get_middlewares(&self) -> &[Arc<dyn ModuleMiddleware>] {
765 &self.config.middlewares
766 }
767
768 fn compile_module(
771 &self,
772 target: &Target,
773 compile_info: &CompileModuleInfo,
774 compile_info_blob: &[u8],
775 module_translation_state: &ModuleTranslationState,
776 function_body_inputs: PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
777 progress_callback: Option<&CompilationProgressCallback>,
778 ) -> Result<Compilation, CompileError> {
779 self.compile_module_internal(
780 target,
781 compile_info,
782 compile_info_blob,
783 module_translation_state,
784 function_body_inputs,
785 progress_callback,
786 )
787 }
788}
789
790fn mach_reloc_to_reloc(
791 module: &ModuleInfo,
792 func_index_map: &cranelift_entity::PrimaryMap<ir::UserExternalNameRef, ir::UserExternalName>,
793 reloc: &FinalizedMachReloc,
794) -> Relocation {
795 let FinalizedMachReloc {
796 offset,
797 kind,
798 addend,
799 target,
800 } = &reloc;
801 let name = match target {
802 FinalizedRelocTarget::ExternalName(external_name) => external_name,
803 FinalizedRelocTarget::Func(_) => {
804 unimplemented!("relocations to offset in the same function are not yet supported")
805 }
806 };
807 let reloc_target: RelocationTarget = if let ExternalName::User(extname_ref) = name {
808 let func_index = func_index_map[*extname_ref].index;
809 RelocationTarget::LocalFunc(
811 module
812 .local_func_index(FunctionIndex::from_u32(func_index))
813 .expect("The provided function should be local"),
814 )
815 } else if let ExternalName::LibCall(libcall) = name {
816 RelocationTarget::LibCall(irlibcall_to_libcall(*libcall))
817 } else {
818 panic!("unrecognized external target")
819 };
820 Relocation {
821 kind: irreloc_to_relocationkind(*kind),
822 reloc_target,
823 offset: *offset,
824 addend: *addend,
825 }
826}
827
828fn mach_trap_to_trap(trap: &MachTrap) -> TrapInformation {
829 let &MachTrap { offset, code } = trap;
830 TrapInformation {
831 code_offset: offset,
832 trap_code: translate_ir_trapcode(code),
833 }
834}
835
836fn translate_ir_trapcode(trap: ir::TrapCode) -> TrapCode {
838 if trap == ir::TrapCode::STACK_OVERFLOW {
839 TrapCode::StackOverflow
840 } else if trap == ir::TrapCode::HEAP_OUT_OF_BOUNDS {
841 TrapCode::HeapAccessOutOfBounds
842 } else if trap == crate::TRAP_HEAP_MISALIGNED {
843 TrapCode::UnalignedAtomic
844 } else if trap == crate::TRAP_TABLE_OUT_OF_BOUNDS {
845 TrapCode::TableAccessOutOfBounds
846 } else if trap == crate::TRAP_INDIRECT_CALL_TO_NULL {
847 TrapCode::IndirectCallToNull
848 } else if trap == crate::TRAP_BAD_SIGNATURE {
849 TrapCode::BadSignature
850 } else if trap == ir::TrapCode::INTEGER_OVERFLOW {
851 TrapCode::IntegerOverflow
852 } else if trap == ir::TrapCode::INTEGER_DIVISION_BY_ZERO {
853 TrapCode::IntegerDivisionByZero
854 } else if trap == ir::TrapCode::BAD_CONVERSION_TO_INTEGER {
855 TrapCode::BadConversionToInteger
856 } else if trap == crate::TRAP_UNREACHABLE {
857 TrapCode::UnreachableCodeReached
858 } else if trap == crate::TRAP_INTERRUPT {
859 unimplemented!("Interrupts not supported")
860 } else if trap == crate::TRAP_NULL_REFERENCE || trap == crate::TRAP_NULL_I31_REF {
861 unimplemented!("Null reference not supported")
862 } else {
863 unimplemented!("Trap code {trap:?} not supported")
864 }
865}