1#[cfg(feature = "unwind")]
4use crate::dwarf::WriterRelocate;
5
6use crate::{
7 address_map::get_function_address_map,
8 config::Cranelift,
9 func_environ::{get_function_name, FuncEnvironment},
10 trampoline::{
11 make_trampoline_dynamic_function, make_trampoline_function_call, FunctionBuilderContext,
12 },
13 translator::{
14 compiled_function_unwind_info, irlibcall_to_libcall, irreloc_to_relocationkind,
15 signature_to_cranelift_ir, CraneliftUnwindInfo, FuncTranslator,
16 },
17};
18use cranelift_codegen::{
19 ir::{self, ExternalName, UserFuncName},
20 Context, FinalizedMachReloc, FinalizedRelocTarget, MachTrap,
21};
22
23#[cfg(feature = "unwind")]
24use gimli::write::{Address, EhFrame, FrameTable};
25
26#[cfg(feature = "rayon")]
27use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
28use std::sync::Arc;
29
30use wasmer_compiler::{
31 types::{
32 function::{Compilation, CompiledFunction, CompiledFunctionFrameInfo, Dwarf, FunctionBody},
33 module::CompileModuleInfo,
34 relocation::{Relocation, RelocationTarget},
35 section::SectionIndex,
36 target::{CallingConvention, Target},
37 unwind::CompiledFunctionUnwindInfo,
38 },
39 Compiler, FunctionBinaryReader, FunctionBodyData, MiddlewareBinaryReader, ModuleMiddleware,
40 ModuleMiddlewareChain, ModuleTranslationState,
41};
42use wasmer_types::entity::{EntityRef, PrimaryMap};
43use wasmer_types::{
44 CompileError, FunctionIndex, LocalFunctionIndex, ModuleInfo, SignatureIndex, TrapCode,
45 TrapInformation,
46};
47
48pub struct CraneliftCompiler {
51 config: Cranelift,
52}
53
54impl CraneliftCompiler {
55 pub fn new(config: Cranelift) -> Self {
57 Self { config }
58 }
59
60 pub fn config(&self) -> &Cranelift {
62 &self.config
63 }
64}
65
66impl Compiler for CraneliftCompiler {
67 fn name(&self) -> &str {
68 "cranelift"
69 }
70
71 fn get_middlewares(&self) -> &[Arc<dyn ModuleMiddleware>] {
73 &self.config.middlewares
74 }
75
76 fn compile_module(
79 &self,
80 target: &Target,
81 compile_info: &CompileModuleInfo,
82 module_translation_state: &ModuleTranslationState,
83 function_body_inputs: PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
84 ) -> Result<Compilation, CompileError> {
85 let isa = self
86 .config()
87 .isa(target)
88 .map_err(|error| CompileError::Codegen(error.to_string()))?;
89 let frontend_config = isa.frontend_config();
90 let memory_styles = &compile_info.memory_styles;
91 let table_styles = &compile_info.table_styles;
92 let module = &compile_info.module;
93 let signatures = module
94 .signatures
95 .iter()
96 .map(|(_sig_index, func_type)| signature_to_cranelift_ir(func_type, frontend_config))
97 .collect::<PrimaryMap<SignatureIndex, ir::Signature>>();
98
99 #[cfg(feature = "unwind")]
101 let dwarf_frametable = if function_body_inputs.is_empty() {
102 None
106 } else {
107 match target.triple().default_calling_convention() {
108 Ok(CallingConvention::SystemV) => {
109 match isa.create_systemv_cie() {
110 Some(cie) => {
111 let mut dwarf_frametable = FrameTable::default();
112 let cie_id = dwarf_frametable.add_cie(cie);
113 Some((dwarf_frametable, cie_id))
114 }
115 None => None,
117 }
118 }
119 _ => None,
120 }
121 };
122
123 let mut custom_sections = PrimaryMap::new();
124
125 #[cfg(not(feature = "rayon"))]
126 let mut func_translator = FuncTranslator::new();
127 #[cfg(not(feature = "rayon"))]
128 let (functions, fdes): (Vec<CompiledFunction>, Vec<_>) = function_body_inputs
129 .iter()
130 .collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
131 .into_iter()
132 .map(|(i, input)| {
133 let func_index = module.func_index(i);
134 let mut context = Context::new();
135 let mut func_env = FuncEnvironment::new(
136 isa.frontend_config(),
137 module,
138 &signatures,
139 &memory_styles,
140 table_styles,
141 );
142 context.func.name = match get_function_name(func_index) {
143 ExternalName::User(nameref) => {
144 if context.func.params.user_named_funcs().is_valid(nameref) {
145 let name = &context.func.params.user_named_funcs()[nameref];
146 UserFuncName::User(name.clone())
147 } else {
148 UserFuncName::default()
149 }
150 }
151 ExternalName::TestCase(testcase) => UserFuncName::Testcase(testcase),
152 _ => UserFuncName::default(),
153 };
154 context.func.signature = signatures[module.functions[func_index]].clone();
155 let mut reader =
159 MiddlewareBinaryReader::new_with_offset(input.data, input.module_offset);
160 reader.set_middleware_chain(
161 self.config
162 .middlewares
163 .generate_function_middleware_chain(i),
164 );
165
166 func_translator.translate(
167 module_translation_state,
168 &mut reader,
169 &mut context.func,
170 &mut func_env,
171 i,
172 )?;
173
174 let mut code_buf: Vec<u8> = Vec::new();
175 context
176 .compile_and_emit(&*isa, &mut code_buf, &mut Default::default())
177 .map_err(|error| CompileError::Codegen(error.inner.to_string()))?;
178
179 let result = context.compiled_code().unwrap();
180 let func_relocs = result
181 .buffer
182 .relocs()
183 .into_iter()
184 .map(|r| mach_reloc_to_reloc(module, r))
185 .collect::<Vec<_>>();
186
187 let traps = result
188 .buffer
189 .traps()
190 .into_iter()
191 .map(mach_trap_to_trap)
192 .collect::<Vec<_>>();
193
194 let (unwind_info, fde) = match compiled_function_unwind_info(&*isa, &context)? {
195 #[cfg(feature = "unwind")]
196 CraneliftUnwindInfo::Fde(fde) => {
197 if dwarf_frametable.is_some() {
198 let fde = fde.to_fde(Address::Symbol {
199 symbol: WriterRelocate::FUNCTION_SYMBOL,
202 addend: i.index() as _,
205 });
206 (Some(CompiledFunctionUnwindInfo::Dwarf), Some(fde))
208 } else {
209 (None, None)
210 }
211 }
212 #[cfg(feature = "unwind")]
213 other => (other.maybe_into_to_windows_unwind(), None),
214
215 #[cfg(not(feature = "unwind"))]
218 other => (other.maybe_into_to_windows_unwind(), None::<()>),
219 };
220
221 let range = reader.range();
222 let address_map = get_function_address_map(&context, range, code_buf.len());
223
224 Ok((
225 CompiledFunction {
226 body: FunctionBody {
227 body: code_buf,
228 unwind_info,
229 },
230 relocations: func_relocs,
231 frame_info: CompiledFunctionFrameInfo { address_map, traps },
232 },
233 fde,
234 ))
235 })
236 .collect::<Result<Vec<_>, CompileError>>()?
237 .into_iter()
238 .unzip();
239 #[cfg(feature = "rayon")]
240 let (functions, fdes): (Vec<CompiledFunction>, Vec<_>) = function_body_inputs
241 .iter()
242 .collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
243 .par_iter()
244 .map_init(FuncTranslator::new, |func_translator, (i, input)| {
245 let func_index = module.func_index(*i);
246 let mut context = Context::new();
247 let mut func_env = FuncEnvironment::new(
248 isa.frontend_config(),
249 module,
250 &signatures,
251 memory_styles,
252 table_styles,
253 );
254 context.func.name = match get_function_name(func_index) {
255 ExternalName::User(nameref) => {
256 if context.func.params.user_named_funcs().is_valid(nameref) {
257 let name = &context.func.params.user_named_funcs()[nameref];
258 UserFuncName::User(name.clone())
259 } else {
260 UserFuncName::default()
261 }
262 }
263 ExternalName::TestCase(testcase) => UserFuncName::Testcase(testcase),
264 _ => UserFuncName::default(),
265 };
266 context.func.signature = signatures[module.functions[func_index]].clone();
267 let mut reader =
272 MiddlewareBinaryReader::new_with_offset(input.data, input.module_offset);
273 reader.set_middleware_chain(
274 self.config
275 .middlewares
276 .generate_function_middleware_chain(*i),
277 );
278
279 func_translator.translate(
280 module_translation_state,
281 &mut reader,
282 &mut context.func,
283 &mut func_env,
284 *i,
285 )?;
286
287 let mut code_buf: Vec<u8> = Vec::new();
288 context
289 .compile_and_emit(&*isa, &mut code_buf, &mut Default::default())
290 .map_err(|error| CompileError::Codegen(format!("{error:#?}")))?;
291
292 let result = context.compiled_code().unwrap();
293 let func_relocs = result
294 .buffer
295 .relocs()
296 .iter()
297 .map(|r| mach_reloc_to_reloc(module, r))
298 .collect::<Vec<_>>();
299
300 let traps = result
301 .buffer
302 .traps()
303 .iter()
304 .map(mach_trap_to_trap)
305 .collect::<Vec<_>>();
306
307 let (unwind_info, fde) = match compiled_function_unwind_info(&*isa, &context)? {
308 #[cfg(feature = "unwind")]
309 CraneliftUnwindInfo::Fde(fde) => {
310 if dwarf_frametable.is_some() {
311 let fde = fde.to_fde(Address::Symbol {
312 symbol: WriterRelocate::FUNCTION_SYMBOL,
315 addend: i.index() as _,
318 });
319 (Some(CompiledFunctionUnwindInfo::Dwarf), Some(fde))
321 } else {
322 (None, None)
323 }
324 }
325 #[cfg(feature = "unwind")]
326 other => (other.maybe_into_to_windows_unwind(), None),
327
328 #[cfg(not(feature = "unwind"))]
331 other => (other.maybe_into_to_windows_unwind(), None::<()>),
332 };
333
334 let range = reader.range();
335 let address_map = get_function_address_map(&context, range, code_buf.len());
336
337 Ok((
338 CompiledFunction {
339 body: FunctionBody {
340 body: code_buf,
341 unwind_info,
342 },
343 relocations: func_relocs,
344 frame_info: CompiledFunctionFrameInfo { address_map, traps },
345 },
346 fde,
347 ))
348 })
349 .collect::<Result<Vec<_>, CompileError>>()?
350 .into_iter()
351 .unzip();
352
353 #[cfg(feature = "unwind")]
354 let dwarf = if let Some((mut dwarf_frametable, cie_id)) = dwarf_frametable {
355 for fde in fdes.into_iter().flatten() {
356 dwarf_frametable.add_fde(cie_id, fde);
357 }
358 let mut eh_frame = EhFrame(WriterRelocate::new(target.triple().endianness().ok()));
359 dwarf_frametable.write_eh_frame(&mut eh_frame).unwrap();
360
361 let eh_frame_section = eh_frame.0.into_section();
362 custom_sections.push(eh_frame_section);
363 Some(Dwarf::new(SectionIndex::new(custom_sections.len() - 1)))
364 } else {
365 None
366 };
367 #[cfg(not(feature = "unwind"))]
368 let dwarf = None;
369
370 #[cfg(not(feature = "rayon"))]
372 let mut cx = FunctionBuilderContext::new();
373 #[cfg(not(feature = "rayon"))]
374 let function_call_trampolines = module
375 .signatures
376 .values()
377 .collect::<Vec<_>>()
378 .into_iter()
379 .map(|sig| make_trampoline_function_call(&*isa, &mut cx, sig))
380 .collect::<Result<Vec<FunctionBody>, CompileError>>()?
381 .into_iter()
382 .collect::<PrimaryMap<SignatureIndex, FunctionBody>>();
383 #[cfg(feature = "rayon")]
384 let function_call_trampolines = module
385 .signatures
386 .values()
387 .collect::<Vec<_>>()
388 .par_iter()
389 .map_init(FunctionBuilderContext::new, |cx, sig| {
390 make_trampoline_function_call(&*isa, cx, sig)
391 })
392 .collect::<Result<Vec<FunctionBody>, CompileError>>()?
393 .into_iter()
394 .collect::<PrimaryMap<SignatureIndex, FunctionBody>>();
395
396 use wasmer_types::VMOffsets;
397 let offsets = VMOffsets::new_for_trampolines(frontend_config.pointer_bytes());
398 #[cfg(not(feature = "rayon"))]
400 let mut cx = FunctionBuilderContext::new();
401 #[cfg(not(feature = "rayon"))]
402 let dynamic_function_trampolines = module
403 .imported_function_types()
404 .collect::<Vec<_>>()
405 .into_iter()
406 .map(|func_type| make_trampoline_dynamic_function(&*isa, &offsets, &mut cx, &func_type))
407 .collect::<Result<Vec<_>, CompileError>>()?
408 .into_iter()
409 .collect::<PrimaryMap<FunctionIndex, FunctionBody>>();
410 #[cfg(feature = "rayon")]
411 let dynamic_function_trampolines = module
412 .imported_function_types()
413 .collect::<Vec<_>>()
414 .par_iter()
415 .map_init(FunctionBuilderContext::new, |cx, func_type| {
416 make_trampoline_dynamic_function(&*isa, &offsets, cx, func_type)
417 })
418 .collect::<Result<Vec<_>, CompileError>>()?
419 .into_iter()
420 .collect::<PrimaryMap<FunctionIndex, FunctionBody>>();
421
422 Ok(Compilation {
423 functions: functions.into_iter().collect(),
424 custom_sections,
425 function_call_trampolines,
426 dynamic_function_trampolines,
427 debug: dwarf,
428 })
429 }
430}
431
432fn mach_reloc_to_reloc(module: &ModuleInfo, reloc: &FinalizedMachReloc) -> Relocation {
433 let FinalizedMachReloc {
434 offset,
435 kind,
436 addend,
437 target,
438 } = &reloc;
439 let name = match target {
440 FinalizedRelocTarget::ExternalName(external_name) => external_name,
441 FinalizedRelocTarget::Func(_) => {
442 unimplemented!("relocations to offset in the same function are not yet supported")
443 }
444 };
445 let reloc_target: RelocationTarget = if let ExternalName::User(extname_ref) = name {
446 RelocationTarget::LocalFunc(
448 module
449 .local_func_index(FunctionIndex::from_u32(extname_ref.as_u32()))
450 .expect("The provided function should be local"),
451 )
452 } else if let ExternalName::LibCall(libcall) = name {
453 RelocationTarget::LibCall(irlibcall_to_libcall(*libcall))
454 } else {
455 panic!("unrecognized external target")
456 };
457 Relocation {
458 kind: irreloc_to_relocationkind(*kind),
459 reloc_target,
460 offset: *offset,
461 addend: *addend,
462 }
463}
464
465fn mach_trap_to_trap(trap: &MachTrap) -> TrapInformation {
466 let &MachTrap { offset, code } = trap;
467 TrapInformation {
468 code_offset: offset,
469 trap_code: translate_ir_trapcode(code),
470 }
471}
472
473fn translate_ir_trapcode(trap: ir::TrapCode) -> TrapCode {
475 match trap {
476 ir::TrapCode::StackOverflow => TrapCode::StackOverflow,
477 ir::TrapCode::HeapOutOfBounds => TrapCode::HeapAccessOutOfBounds,
478 ir::TrapCode::HeapMisaligned => TrapCode::UnalignedAtomic,
479 ir::TrapCode::TableOutOfBounds => TrapCode::TableAccessOutOfBounds,
480 ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull,
481 ir::TrapCode::BadSignature => TrapCode::BadSignature,
482 ir::TrapCode::IntegerOverflow => TrapCode::IntegerOverflow,
483 ir::TrapCode::IntegerDivisionByZero => TrapCode::IntegerDivisionByZero,
484 ir::TrapCode::BadConversionToInteger => TrapCode::BadConversionToInteger,
485 ir::TrapCode::UnreachableCodeReached => TrapCode::UnreachableCodeReached,
486 ir::TrapCode::Interrupt => unimplemented!("Interrupts not supported"),
487 ir::TrapCode::NullReference | ir::TrapCode::NullI31Ref => {
488 unimplemented!("Null reference not supported")
489 }
490 ir::TrapCode::User(_user_code) => unimplemented!("User trap code not supported"),
491 }
494}