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