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,
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#[derive(Debug)]
88pub struct CraneliftCompiler {
89 config: Cranelift,
90}
91
92impl CraneliftCompiler {
93 pub fn new(config: Cranelift) -> Self {
95 Self { config }
96 }
97
98 pub fn config(&self) -> &Cranelift {
100 &self.config
101 }
102
103 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 #[cfg(feature = "unwind")]
154 let dwarf_frametable = if function_body_inputs.is_empty() {
155 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 None => None,
177 },
178 _ => None,
179 }
180 };
181
182 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 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 symbol: WriterRelocate::FUNCTION_SYMBOL,
316 addend: i.index() as _,
319 });
320 (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 #[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(); 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 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 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 fn get_middlewares(&self) -> &[Arc<dyn ModuleMiddleware>] {
639 &self.config.middlewares
640 }
641
642 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 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
709fn 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}