wasmer_compiler_cranelift/
compiler.rs

1//! Support for compiling with Cranelift.
2
3#[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,
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 rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
38#[cfg(feature = "unwind")]
39use std::collections::HashMap;
40use std::sync::Arc;
41use wasmer_compiler::WASM_TRAMPOLINE_ESTIMATED_BODY_SIZE;
42use wasmer_compiler::types::function::Compilation;
43
44use wasmer_compiler::progress::ProgressContext;
45#[cfg(feature = "unwind")]
46use wasmer_compiler::types::{section::SectionIndex, unwind::CompiledFunctionUnwindInfo};
47use wasmer_compiler::{
48    Compiler, FunctionBinaryReader, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware,
49    ModuleMiddlewareChain, ModuleTranslationState,
50    types::{
51        function::{
52            CompiledFunction, CompiledFunctionFrameInfo, FunctionBody, RkyvCompilation, UnwindInfo,
53        },
54        module::CompileModuleInfo,
55        relocation::{Relocation, RelocationKind, RelocationTarget},
56        section::{CustomSection, CustomSectionProtection, SectionBody},
57    },
58};
59use wasmer_compiler::{build_function_buckets, translate_function_buckets};
60#[cfg(feature = "unwind")]
61use wasmer_types::LibCall;
62#[cfg(feature = "unwind")]
63use wasmer_types::entity::EntityRef;
64use wasmer_types::entity::PrimaryMap;
65#[cfg(feature = "unwind")]
66use wasmer_types::target::CallingConvention;
67use wasmer_types::target::Target;
68use wasmer_types::{
69    CompilationProgressCallback, CompileError, FunctionIndex, LocalFunctionIndex, ModuleInfo,
70    SignatureIndex, TrapCode, TrapInformation,
71};
72
73pub struct CraneliftCompiledFunction {
74    function: CompiledFunction,
75    #[cfg(feature = "unwind")]
76    fde: Option<FrameDescriptionEntry>,
77    #[cfg(feature = "unwind")]
78    function_lsda: Option<FunctionLsdaData>,
79    #[cfg(feature = "unwind")]
80    compact_unwind_encoding: Option<u32>,
81}
82
83impl wasmer_compiler::CompiledFunction for CraneliftCompiledFunction {}
84
85/// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR,
86/// optimizing it and then translating to assembly.
87#[derive(Debug)]
88pub struct CraneliftCompiler {
89    config: Cranelift,
90}
91
92impl CraneliftCompiler {
93    /// Creates a new Cranelift compiler
94    pub fn new(config: Cranelift) -> Self {
95        Self { config }
96    }
97
98    /// Gets the WebAssembly features for this Compiler
99    pub fn config(&self) -> &Cranelift {
100        &self.config
101    }
102
103    // Helper function to create an easy scope boundary for the thread pool used
104    // in [`Self::compile_module`].
105    fn compile_module_internal(
106        &self,
107        target: &Target,
108        compile_info: &CompileModuleInfo,
109        module_translation_state: &ModuleTranslationState,
110        function_body_inputs: PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
111        progress_callback: Option<&CompilationProgressCallback>,
112    ) -> Result<Compilation, CompileError> {
113        let isa = self
114            .config()
115            .isa(target)
116            .map_err(|error| CompileError::Codegen(error.to_string()))?;
117        let frontend_config = isa.frontend_config();
118        #[cfg(feature = "unwind")]
119        let pointer_bytes = frontend_config.pointer_bytes();
120        #[cfg(feature = "unwind")]
121        let emit_macho_compact_unwind = matches!(
122            target.triple(),
123            target_lexicon::Triple {
124                binary_format: target_lexicon::BinaryFormat::Macho,
125                operating_system: target_lexicon::OperatingSystem::Darwin(_),
126                architecture: target_lexicon::Architecture::Aarch64(_),
127                ..
128            }
129        );
130        let memory_styles = &compile_info.memory_styles;
131        let table_styles = &compile_info.table_styles;
132        let module = &compile_info.module;
133        let signatures = module
134            .signatures
135            .iter()
136            .map(|(_sig_index, func_type)| signature_to_cranelift_ir(func_type, frontend_config))
137            .collect::<PrimaryMap<SignatureIndex, ir::Signature>>();
138        let signature_hashes = &module.signature_hashes;
139
140        let total_function_call_trampolines = module.signatures.len();
141        let total_dynamic_trampolines = module.num_imported_functions;
142        let total_steps = WASM_TRAMPOLINE_ESTIMATED_BODY_SIZE
143            * ((total_dynamic_trampolines + total_function_call_trampolines) as u64)
144            + function_body_inputs
145                .iter()
146                .map(|(_, body)| body.data.len() as u64)
147                .sum::<u64>();
148        let progress = progress_callback
149            .cloned()
150            .map(|cb| ProgressContext::new(cb, total_steps, "cranelift::functions"));
151
152        // Generate the frametable
153        #[cfg(feature = "unwind")]
154        let dwarf_frametable = if function_body_inputs.is_empty() {
155            // If we have no function body inputs, we don't need to
156            // construct the `FrameTable`. Constructing it, with empty
157            // FDEs will cause some issues in Linux.
158            None
159        } else {
160            match target.triple().default_calling_convention() {
161                Ok(CallingConvention::SystemV) => match isa.create_systemv_cie() {
162                    Some(mut cie) => {
163                        cie.personality = Some((
164                            DW_EH_PE_absptr,
165                            Address::Symbol {
166                                symbol: WriterRelocate::PERSONALITY_SYMBOL,
167                                addend: 0,
168                            },
169                        ));
170                        cie.lsda_encoding = Some(DW_EH_PE_absptr);
171                        let mut dwarf_frametable = FrameTable::default();
172                        let cie_id = dwarf_frametable.add_cie(cie);
173                        Some((dwarf_frametable, cie_id))
174                    }
175                    // Even though we are in a SystemV system, Cranelift doesn't support it
176                    None => None,
177                },
178                _ => None,
179            }
180        };
181
182        // The `compile_function` closure is used for both the sequential and
183        // parallel compilation paths to avoid code duplication.
184        let compile_function = |func_translator: &mut FuncTranslator,
185                                i: &LocalFunctionIndex,
186                                input: &FunctionBodyData|
187         -> Result<CraneliftCompiledFunction, CompileError> {
188            let func_index = module.func_index(*i);
189            let mut context = Context::new();
190            let mut func_env = FuncEnvironment::new(
191                isa.frontend_config(),
192                module,
193                &signatures,
194                signature_hashes,
195                memory_styles,
196                table_styles,
197            );
198            context.func.name = match get_function_name(&mut context.func, func_index) {
199                ExternalName::User(nameref) => {
200                    if context.func.params.user_named_funcs().is_valid(nameref) {
201                        let name = &context.func.params.user_named_funcs()[nameref];
202                        UserFuncName::User(name.clone())
203                    } else {
204                        UserFuncName::default()
205                    }
206                }
207                ExternalName::TestCase(testcase) => UserFuncName::Testcase(testcase),
208                _ => UserFuncName::default(),
209            };
210            context.func.signature = signatures[module.functions[func_index]].clone();
211            // if generate_debug_info {
212            //     context.func.collect_debug_info();
213            // }
214
215            let mut reader =
216                MiddlewareBinaryReader::new_with_offset(input.data, input.module_offset);
217            reader.set_middleware_chain(
218                self.config
219                    .middlewares
220                    .generate_function_middleware_chain(*i),
221            );
222
223            func_translator.translate(
224                module_translation_state,
225                &mut reader,
226                &mut context.func,
227                &mut func_env,
228                *i,
229            )?;
230
231            if let Some(callbacks) = self.config.callbacks.as_ref() {
232                use wasmer_compiler::misc::CompiledKind;
233
234                callbacks.preopt_ir(
235                    &CompiledKind::Local(*i, compile_info.module.get_function_name(func_index)),
236                    &compile_info.module.hash_string(),
237                    context.func.display().to_string().as_bytes(),
238                );
239            }
240
241            let mut code_buf: Vec<u8> = Vec::new();
242            let mut ctrl_plane = Default::default();
243            let func_name_map = context.func.params.user_named_funcs().clone();
244            let result = context
245                .compile(&*isa, &mut ctrl_plane)
246                .map_err(|error| CompileError::Codegen(format!("{error:#?}")))?;
247            code_buf.extend_from_slice(result.code_buffer());
248
249            if let Some(callbacks) = self.config.callbacks.as_ref() {
250                use wasmer_compiler::misc::CompiledKind;
251
252                callbacks.obj_memory_buffer(
253                    &CompiledKind::Local(*i, compile_info.module.get_function_name(func_index)),
254                    &compile_info.module.hash_string(),
255                    &code_buf,
256                );
257                callbacks.asm_memory_buffer(
258                    &CompiledKind::Local(*i, compile_info.module.get_function_name(func_index)),
259                    &compile_info.module.hash_string(),
260                    target.triple().architecture,
261                    &code_buf,
262                )?;
263            }
264
265            let func_relocs = result
266                .buffer
267                .relocs()
268                .iter()
269                .map(|r| mach_reloc_to_reloc(module, &func_name_map, r))
270                .collect::<Vec<_>>();
271
272            let traps = result
273                .buffer
274                .traps()
275                .iter()
276                .map(mach_trap_to_trap)
277                .collect::<Vec<_>>();
278
279            #[cfg(feature = "unwind")]
280            let emit_lsda = dwarf_frametable.is_some() || emit_macho_compact_unwind;
281
282            #[cfg(feature = "unwind")]
283            let compact_unwind_encoding = if emit_macho_compact_unwind {
284                Some(
285                    compact_unwind_encoding_aarch64(&result.buffer.unwind_info).map_err(|error| {
286                        CompileError::Codegen(format!(
287                            "failed to encode aarch64 Mach-O compact unwind for function {}: {error}",
288                            i.index()
289                        ))
290                    })?,
291                )
292            } else {
293                None
294            };
295
296            #[cfg(feature = "unwind")]
297            let function_lsda = if emit_lsda {
298                build_function_lsda(
299                    result.buffer.call_sites(),
300                    result.buffer.data().len(),
301                    pointer_bytes,
302                )
303            } else {
304                None
305            };
306
307            #[allow(unused)]
308            let (unwind_info, fde) = match compiled_function_unwind_info(&*isa, &context)? {
309                #[cfg(feature = "unwind")]
310                CraneliftUnwindInfo::Fde(fde) => {
311                    if dwarf_frametable.is_some() {
312                        let fde = fde.to_fde(Address::Symbol {
313                            // The symbol is the kind of relocation.
314                            // "0" is used for functions
315                            symbol: WriterRelocate::FUNCTION_SYMBOL,
316                            // We use the addend as a way to specify the
317                            // function index
318                            addend: i.index() as _,
319                        });
320                        // The unwind information is inserted into the dwarf section
321                        (Some(CompiledFunctionUnwindInfo::Dwarf), Some(fde))
322                    } else {
323                        (None, None)
324                    }
325                }
326                #[cfg(feature = "unwind")]
327                other => (other.maybe_into_to_windows_unwind(), None),
328
329                // This is a bit hacky, but necessary since gimli is not
330                // available when the "unwind" feature is disabled.
331                #[cfg(not(feature = "unwind"))]
332                other => (other.maybe_into_to_windows_unwind(), None::<()>),
333            };
334
335            let range = reader.range();
336            let address_map = get_function_address_map(&context, range, code_buf.len());
337
338            Ok(CraneliftCompiledFunction {
339                function: CompiledFunction {
340                    body: FunctionBody {
341                        body: code_buf,
342                        unwind_info,
343                    },
344                    relocations: func_relocs,
345                    frame_info: CompiledFunctionFrameInfo { address_map, traps },
346                    maximum_stack_usage: None,
347                },
348                #[cfg(feature = "unwind")]
349                fde,
350                #[cfg(feature = "unwind")]
351                function_lsda,
352                #[cfg(feature = "unwind")]
353                compact_unwind_encoding,
354            })
355        };
356
357        #[cfg_attr(not(feature = "unwind"), allow(unused_mut))]
358        let mut custom_sections = PrimaryMap::new();
359
360        let results = {
361            use wasmer_compiler::WASM_LARGE_FUNCTION_THRESHOLD;
362
363            let buckets =
364                build_function_buckets(&function_body_inputs, WASM_LARGE_FUNCTION_THRESHOLD / 3);
365            let largest_bucket = buckets.first().map(|b| b.size).unwrap_or_default();
366            tracing::debug!(buckets = buckets.len(), largest_bucket, "buckets built");
367            let num_threads = self.config.num_threads.get();
368            let pool = rayon::ThreadPoolBuilder::new()
369                .num_threads(num_threads)
370                .build()
371                .unwrap();
372
373            translate_function_buckets(
374                &pool,
375                || FuncTranslator::new(self.config.allow_experimental_unaligned_memory_accesses),
376                |func_translator, i, input| compile_function(func_translator, i, input),
377                progress.clone(),
378                &buckets,
379            )?
380        };
381
382        let mut functions = Vec::with_capacity(function_body_inputs.len());
383        #[cfg(feature = "unwind")]
384        let mut fdes = Vec::with_capacity(function_body_inputs.len());
385        #[cfg(feature = "unwind")]
386        let mut lsda_data = Vec::with_capacity(function_body_inputs.len());
387        #[cfg(feature = "unwind")]
388        let mut compact_unwind_entries = Vec::new();
389
390        for compiled in results {
391            let CraneliftCompiledFunction {
392                function,
393                #[cfg(feature = "unwind")]
394                fde,
395                #[cfg(feature = "unwind")]
396                function_lsda,
397                #[cfg(feature = "unwind")]
398                compact_unwind_encoding,
399            } = compiled;
400            #[cfg(feature = "unwind")]
401            let local_function_index = LocalFunctionIndex::new(functions.len());
402            functions.push(function);
403            #[cfg(feature = "unwind")]
404            {
405                fdes.push(fde);
406                lsda_data.push(function_lsda);
407                if let Some(compact_encoding) = compact_unwind_encoding {
408                    let function_length = functions
409                        .last()
410                        .expect("function was just pushed")
411                        .body
412                        .body
413                        .len()
414                        .try_into()
415                        .map_err(|_| {
416                            CompileError::Codegen(
417                                "function body too large for Mach-O compact unwind".into(),
418                            )
419                        })?;
420                    compact_unwind_entries.push((
421                        local_function_index,
422                        function_length,
423                        compact_encoding,
424                    ));
425                }
426            }
427        }
428
429        #[cfg(feature = "unwind")]
430        let (_tag_section_index, lsda_section_index, function_lsda_offsets) =
431            if dwarf_frametable.is_some() || emit_macho_compact_unwind {
432                let mut tag_section_index = None;
433                let mut tag_offsets = HashMap::new();
434                if let Some((tag_section, offsets)) = build_tag_section(&lsda_data) {
435                    custom_sections.push(tag_section);
436                    tag_section_index = Some(SectionIndex::new(custom_sections.len() - 1));
437                    tag_offsets = offsets;
438                }
439                let lsda_vec = lsda_data;
440                let (lsda_section, offsets_per_function) =
441                    build_lsda_section(lsda_vec, pointer_bytes, &tag_offsets, tag_section_index);
442                let mut lsda_section_index = None;
443                if let Some(section) = lsda_section {
444                    custom_sections.push(section);
445                    lsda_section_index = Some(SectionIndex::new(custom_sections.len() - 1));
446                }
447                (tag_section_index, lsda_section_index, offsets_per_function)
448            } else {
449                (None, None, vec![None; functions.len()])
450            };
451
452        #[cfg_attr(not(feature = "unwind"), allow(unused_mut))]
453        let mut unwind_info = UnwindInfo::default();
454
455        #[cfg(feature = "unwind")]
456        if let Some((mut dwarf_frametable, cie_id)) = dwarf_frametable {
457            for (func_idx, fde_opt) in fdes.into_iter().enumerate() {
458                if let Some(mut fde) = fde_opt {
459                    let has_lsda = function_lsda_offsets
460                        .get(func_idx)
461                        .and_then(|v| *v)
462                        .is_some();
463                    let lsda_address = if has_lsda {
464                        debug_assert!(
465                            lsda_section_index.is_some(),
466                            "LSDA offsets require an LSDA section"
467                        );
468                        if lsda_section_index.is_some() {
469                            let symbol =
470                                WriterRelocate::lsda_symbol(LocalFunctionIndex::new(func_idx));
471                            Address::Symbol { symbol, addend: 0 }
472                        } else {
473                            Address::Constant(0)
474                        }
475                    } else {
476                        Address::Constant(0)
477                    };
478                    fde.lsda = Some(lsda_address);
479                    dwarf_frametable.add_fde(cie_id, fde);
480                }
481            }
482
483            let mut writer = WriterRelocate::new(target.triple().endianness().ok());
484            if let Some(lsda_section_index) = lsda_section_index {
485                for (func_idx, offset) in function_lsda_offsets.iter().enumerate() {
486                    if let Some(offset) = offset {
487                        writer.register_lsda_symbol(
488                            WriterRelocate::lsda_symbol(LocalFunctionIndex::new(func_idx)),
489                            RelocationTarget::CustomSection(lsda_section_index),
490                            *offset,
491                        );
492                    }
493                }
494            }
495
496            let mut eh_frame = EhFrame(writer);
497            dwarf_frametable.write_eh_frame(&mut eh_frame).unwrap();
498            eh_frame.write(&[0, 0, 0, 0]).unwrap(); // Write a 0 length at the end of the table.
499
500            let eh_frame_section = eh_frame.0.into_section();
501            custom_sections.push(eh_frame_section);
502            unwind_info.eh_frame = Some(SectionIndex::new(custom_sections.len() - 1));
503        };
504
505        #[cfg(feature = "unwind")]
506        if emit_macho_compact_unwind {
507            let entries = compact_unwind_entries
508                .into_iter()
509                .map(|(function, function_length, compact_encoding)| {
510                    let lsda_offset = function_lsda_offsets
511                        .get(function.index())
512                        .and_then(|offset| *offset);
513                    CompactUnwindEntryData {
514                        function,
515                        function_length,
516                        compact_encoding,
517                        lsda_offset,
518                    }
519                })
520                .collect::<Vec<_>>();
521            if let Some(section) = build_compact_unwind_section(entries, lsda_section_index) {
522                custom_sections.push(section);
523                unwind_info.compact_unwind = Some(SectionIndex::new(custom_sections.len() - 1));
524            }
525        }
526
527        let module_hash = module.hash_string();
528
529        // function call trampolines (only for local functions, by signature)
530        let function_call_trampolines = module
531            .signatures
532            .iter()
533            .collect::<Vec<_>>()
534            .par_iter()
535            .map_init(FunctionBuilderContext::new, |cx, (sig_index, sig)| {
536                let kind = wasmer_compiler::misc::CompiledKind::FunctionCallTrampoline(
537                    *sig_index,
538                    (*sig).clone(),
539                );
540                let trampoline = make_trampoline_function_call(
541                    &self.config().callbacks,
542                    &*isa,
543                    target.triple().architecture,
544                    cx,
545                    &kind,
546                    sig,
547                    &module_hash,
548                )?;
549                if let Some(progress) = progress.as_ref() {
550                    progress.notify_steps(WASM_TRAMPOLINE_ESTIMATED_BODY_SIZE)?;
551                }
552                Ok(trampoline)
553            })
554            .collect::<Result<Vec<FunctionBody>, CompileError>>()?
555            .into_iter()
556            .collect();
557
558        use wasmer_types::VMOffsets;
559        let offsets = VMOffsets::new_for_trampolines(frontend_config.pointer_bytes());
560        // dynamic function trampolines (only for imported functions)
561        let dynamic_function_trampolines = module
562            .imported_function_types()
563            .enumerate()
564            .collect::<Vec<_>>()
565            .par_iter()
566            .map_init(FunctionBuilderContext::new, |cx, (index, func_type)| {
567                let kind = wasmer_compiler::misc::CompiledKind::DynamicFunctionTrampoline(
568                    FunctionIndex::from_u32(*index as u32),
569                    func_type.clone(),
570                );
571                let trampoline = make_trampoline_dynamic_function(
572                    &self.config().callbacks,
573                    &*isa,
574                    target.triple().architecture,
575                    &offsets,
576                    cx,
577                    &kind,
578                    func_type,
579                    &module_hash,
580                )?;
581                if let Some(progress) = progress.as_ref() {
582                    progress.notify_steps(WASM_TRAMPOLINE_ESTIMATED_BODY_SIZE)?;
583                }
584                Ok(trampoline)
585            })
586            .collect::<Result<Vec<_>, CompileError>>()?
587            .into_iter()
588            .collect();
589
590        let mut got = wasmer_compiler::types::function::GOT::empty();
591
592        #[cfg(feature = "unwind")]
593        if emit_macho_compact_unwind {
594            let got_idx = SectionIndex::from_u32(custom_sections.len() as u32);
595            custom_sections.push(CustomSection {
596                protection: CustomSectionProtection::Read,
597                alignment: Some(pointer_bytes.into()),
598                bytes: SectionBody::new_with_vec(vec![0; pointer_bytes as usize]),
599                relocations: vec![Relocation {
600                    kind: match pointer_bytes {
601                        4 => RelocationKind::Abs4,
602                        8 => RelocationKind::Abs8,
603                        _ => unreachable!("unsupported pointer size for Mach-O compact unwind GOT"),
604                    },
605                    reloc_target: RelocationTarget::LibCall(LibCall::EHPersonality),
606                    offset: 0,
607                    addend: 0,
608                }],
609            });
610            got.index = Some(got_idx);
611        }
612
613        Ok(Compilation::Rkyv(RkyvCompilation {
614            functions: functions.into_iter().collect(),
615            custom_sections,
616            function_call_trampolines,
617            dynamic_function_trampolines,
618            unwind_info,
619            got,
620        }))
621    }
622}
623
624impl Compiler for CraneliftCompiler {
625    fn name(&self) -> &str {
626        "cranelift"
627    }
628
629    fn get_perfmap_enabled(&self) -> bool {
630        self.config.enable_perfmap
631    }
632
633    fn deterministic_id(&self) -> String {
634        String::from("cranelift")
635    }
636
637    /// Get the middlewares for this compiler
638    fn get_middlewares(&self) -> &[Arc<dyn ModuleMiddleware>] {
639        &self.config.middlewares
640    }
641
642    /// Compile the module using Cranelift, producing a compilation result with
643    /// associated relocations.
644    fn compile_module(
645        &self,
646        target: &Target,
647        compile_info: &CompileModuleInfo,
648        _compile_info_blob: &[u8],
649        module_translation_state: &ModuleTranslationState,
650        function_body_inputs: PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
651        progress_callback: Option<&CompilationProgressCallback>,
652    ) -> Result<Compilation, CompileError> {
653        self.compile_module_internal(
654            target,
655            compile_info,
656            module_translation_state,
657            function_body_inputs,
658            progress_callback,
659        )
660    }
661}
662
663fn mach_reloc_to_reloc(
664    module: &ModuleInfo,
665    func_index_map: &cranelift_entity::PrimaryMap<ir::UserExternalNameRef, ir::UserExternalName>,
666    reloc: &FinalizedMachReloc,
667) -> Relocation {
668    let FinalizedMachReloc {
669        offset,
670        kind,
671        addend,
672        target,
673    } = &reloc;
674    let name = match target {
675        FinalizedRelocTarget::ExternalName(external_name) => external_name,
676        FinalizedRelocTarget::Func(_) => {
677            unimplemented!("relocations to offset in the same function are not yet supported")
678        }
679    };
680    let reloc_target: RelocationTarget = if let ExternalName::User(extname_ref) = name {
681        let func_index = func_index_map[*extname_ref].index;
682        //debug_assert_eq!(namespace, 0);
683        RelocationTarget::LocalFunc(
684            module
685                .local_func_index(FunctionIndex::from_u32(func_index))
686                .expect("The provided function should be local"),
687        )
688    } else if let ExternalName::LibCall(libcall) = name {
689        RelocationTarget::LibCall(irlibcall_to_libcall(*libcall))
690    } else {
691        panic!("unrecognized external target")
692    };
693    Relocation {
694        kind: irreloc_to_relocationkind(*kind),
695        reloc_target,
696        offset: *offset,
697        addend: *addend,
698    }
699}
700
701fn mach_trap_to_trap(trap: &MachTrap) -> TrapInformation {
702    let &MachTrap { offset, code } = trap;
703    TrapInformation {
704        code_offset: offset,
705        trap_code: translate_ir_trapcode(code),
706    }
707}
708
709/// Translates the Cranelift IR TrapCode into generic Trap Code
710fn translate_ir_trapcode(trap: ir::TrapCode) -> TrapCode {
711    if trap == ir::TrapCode::STACK_OVERFLOW {
712        TrapCode::StackOverflow
713    } else if trap == ir::TrapCode::HEAP_OUT_OF_BOUNDS {
714        TrapCode::HeapAccessOutOfBounds
715    } else if trap == crate::TRAP_HEAP_MISALIGNED {
716        TrapCode::UnalignedAtomic
717    } else if trap == crate::TRAP_TABLE_OUT_OF_BOUNDS {
718        TrapCode::TableAccessOutOfBounds
719    } else if trap == crate::TRAP_INDIRECT_CALL_TO_NULL {
720        TrapCode::IndirectCallToNull
721    } else if trap == crate::TRAP_BAD_SIGNATURE {
722        TrapCode::BadSignature
723    } else if trap == ir::TrapCode::INTEGER_OVERFLOW {
724        TrapCode::IntegerOverflow
725    } else if trap == ir::TrapCode::INTEGER_DIVISION_BY_ZERO {
726        TrapCode::IntegerDivisionByZero
727    } else if trap == ir::TrapCode::BAD_CONVERSION_TO_INTEGER {
728        TrapCode::BadConversionToInteger
729    } else if trap == crate::TRAP_UNREACHABLE {
730        TrapCode::UnreachableCodeReached
731    } else if trap == crate::TRAP_INTERRUPT {
732        unimplemented!("Interrupts not supported")
733    } else if trap == crate::TRAP_NULL_REFERENCE || trap == crate::TRAP_NULL_I31_REF {
734        unimplemented!("Null reference not supported")
735    } else {
736        unimplemented!("Trap code {trap:?} not supported")
737    }
738}