1use crate::config::LLVM;
2use crate::trampoline::FuncTrampoline;
3use crate::translator::FuncTranslator;
4use crate::CompiledKind;
5use inkwell::context::Context;
6use inkwell::memory_buffer::MemoryBuffer;
7use inkwell::module::{Linkage, Module};
8use inkwell::targets::FileType;
9use inkwell::DLLStorageClass;
10use rayon::iter::ParallelBridge;
11use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
12use rayon::ThreadPoolBuilder;
13use std::collections::{HashMap, HashSet};
14use std::sync::Arc;
15use wasmer_compiler::types::function::{Compilation, UnwindInfo};
16use wasmer_compiler::types::module::CompileModuleInfo;
17use wasmer_compiler::types::relocation::RelocationKind;
18use wasmer_compiler::{
19 types::{
20 relocation::RelocationTarget,
21 section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex},
22 symbols::{Symbol, SymbolRegistry},
23 },
24 Compiler, FunctionBodyData, ModuleMiddleware, ModuleTranslationState,
25};
26use wasmer_types::entity::{EntityRef, PrimaryMap};
27use wasmer_types::target::Target;
28use wasmer_types::{CompileError, FunctionIndex, LocalFunctionIndex, ModuleInfo, SignatureIndex};
29use wasmer_vm::LibCall;
30
31#[derive(Debug)]
34pub struct LLVMCompiler {
35 config: LLVM,
36}
37
38impl LLVMCompiler {
39 pub fn new(config: LLVM) -> LLVMCompiler {
41 LLVMCompiler { config }
42 }
43
44 fn config(&self) -> &LLVM {
46 &self.config
47 }
48}
49
50struct ShortNames {}
51
52impl SymbolRegistry for ShortNames {
53 fn symbol_to_name(&self, symbol: Symbol) -> String {
54 match symbol {
55 Symbol::Metadata => "M".to_string(),
56 Symbol::LocalFunction(index) => format!("f{}", index.index()),
57 Symbol::Section(index) => format!("s{}", index.index()),
58 Symbol::FunctionCallTrampoline(index) => format!("t{}", index.index()),
59 Symbol::DynamicFunctionTrampoline(index) => format!("d{}", index.index()),
60 }
61 }
62
63 fn name_to_symbol(&self, name: &str) -> Option<Symbol> {
64 if name.len() < 2 {
65 return None;
66 }
67 let (ty, idx) = name.split_at(1);
68 if ty.starts_with('M') {
69 return Some(Symbol::Metadata);
70 }
71
72 let idx = idx.parse::<u32>().ok()?;
73 match ty.chars().next().unwrap() {
74 'f' => Some(Symbol::LocalFunction(LocalFunctionIndex::from_u32(idx))),
75 's' => Some(Symbol::Section(SectionIndex::from_u32(idx))),
76 't' => Some(Symbol::FunctionCallTrampoline(SignatureIndex::from_u32(
77 idx,
78 ))),
79 'd' => Some(Symbol::DynamicFunctionTrampoline(FunctionIndex::from_u32(
80 idx,
81 ))),
82 _ => None,
83 }
84 }
85}
86
87struct ModuleBasedSymbolRegistry {
88 wasm_module: Arc<ModuleInfo>,
89 local_func_names: HashMap<String, LocalFunctionIndex>,
90 short_names: ShortNames,
91}
92
93impl ModuleBasedSymbolRegistry {
94 fn new(wasm_module: Arc<ModuleInfo>) -> Self {
95 let local_func_names = HashMap::from_iter(
96 wasm_module
97 .function_names
98 .iter()
99 .map(|(f, v)| (wasm_module.local_func_index(*f), v))
100 .filter(|(f, _)| f.is_some())
101 .map(|(f, v)| (v.clone(), f.unwrap())),
102 );
103 Self {
104 wasm_module,
105 local_func_names,
106 short_names: ShortNames {},
107 }
108 }
109}
110
111impl SymbolRegistry for ModuleBasedSymbolRegistry {
112 fn symbol_to_name(&self, symbol: Symbol) -> String {
113 match symbol {
114 Symbol::LocalFunction(index) => self
115 .wasm_module
116 .function_names
117 .get(&self.wasm_module.func_index(index))
118 .cloned()
119 .unwrap_or(self.short_names.symbol_to_name(symbol)),
120 _ => self.short_names.symbol_to_name(symbol),
121 }
122 }
123
124 fn name_to_symbol(&self, name: &str) -> Option<Symbol> {
125 if let Some(idx) = self.local_func_names.get(name) {
126 Some(Symbol::LocalFunction(*idx))
127 } else {
128 self.short_names.name_to_symbol(name)
129 }
130 }
131}
132
133impl LLVMCompiler {
134 #[allow(clippy::too_many_arguments)]
135 fn compile_native_object(
136 &self,
137 target: &Target,
138 compile_info: &CompileModuleInfo,
139 module_translation: &ModuleTranslationState,
140 function_body_inputs: &PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
141 symbol_registry: &dyn SymbolRegistry,
142 wasmer_metadata: &[u8],
143 binary_format: target_lexicon::BinaryFormat,
144 ) -> Result<Vec<u8>, CompileError> {
145 let target_machine = self.config().target_machine(target);
146 let ctx = Context::create();
147
148 let merged_bitcode = function_body_inputs.into_iter().par_bridge().map_init(
151 || {
152 let target_machine = self.config().target_machine(target);
153 FuncTranslator::new(target_machine, binary_format).unwrap()
154 },
155 |func_translator, (i, input)| {
156 let module = func_translator.translate_to_module(
157 &compile_info.module,
158 module_translation,
159 &i,
160 input,
161 self.config(),
162 &compile_info.memory_styles,
163 &compile_info.table_styles,
164 symbol_registry,
165 )?;
166
167 Ok(module.write_bitcode_to_memory().as_slice().to_vec())
168 },
169 );
170
171 let trampolines_bitcode = compile_info.module.signatures.iter().par_bridge().map_init(
172 || {
173 let target_machine = self.config().target_machine(target);
174 FuncTrampoline::new(target_machine, binary_format).unwrap()
175 },
176 |func_trampoline, (i, sig)| {
177 let name = symbol_registry.symbol_to_name(Symbol::FunctionCallTrampoline(i));
178 let module = func_trampoline.trampoline_to_module(
179 sig,
180 self.config(),
181 &name,
182 compile_info,
183 )?;
184 Ok(module.write_bitcode_to_memory().as_slice().to_vec())
185 },
186 );
187
188 let dynamic_trampolines_bitcode =
189 compile_info.module.functions.iter().par_bridge().map_init(
190 || {
191 let target_machine = self.config().target_machine(target);
192 (
193 FuncTrampoline::new(target_machine, binary_format).unwrap(),
194 &compile_info.module.signatures,
195 )
196 },
197 |(func_trampoline, signatures), (i, sig)| {
198 let sig = &signatures[*sig];
199 let name = symbol_registry.symbol_to_name(Symbol::DynamicFunctionTrampoline(i));
200 let module =
201 func_trampoline.dynamic_trampoline_to_module(sig, self.config(), &name)?;
202 Ok(module.write_bitcode_to_memory().as_slice().to_vec())
203 },
204 );
205
206 let merged_bitcode = merged_bitcode
207 .chain(trampolines_bitcode)
208 .chain(dynamic_trampolines_bitcode)
209 .collect::<Result<Vec<_>, CompileError>>()?
210 .into_par_iter()
211 .reduce_with(|bc1, bc2| {
212 let ctx = Context::create();
213 let membuf = MemoryBuffer::create_from_memory_range(&bc1, "");
214 let m1 = Module::parse_bitcode_from_buffer(&membuf, &ctx).unwrap();
215 let membuf = MemoryBuffer::create_from_memory_range(&bc2, "");
216 let m2 = Module::parse_bitcode_from_buffer(&membuf, &ctx).unwrap();
217 m1.link_in_module(m2).unwrap();
218 m1.write_bitcode_to_memory().as_slice().to_vec()
219 });
220 let merged_module = if let Some(bc) = merged_bitcode {
221 let membuf = MemoryBuffer::create_from_memory_range(&bc, "");
222 Module::parse_bitcode_from_buffer(&membuf, &ctx).unwrap()
223 } else {
224 ctx.create_module("")
225 };
226
227 let i8_ty = ctx.i8_type();
228 let metadata_init = i8_ty.const_array(
229 wasmer_metadata
230 .iter()
231 .map(|v| i8_ty.const_int(*v as u64, false))
232 .collect::<Vec<_>>()
233 .as_slice(),
234 );
235 let metadata_gv = merged_module.add_global(
236 metadata_init.get_type(),
237 None,
238 &symbol_registry.symbol_to_name(wasmer_compiler::types::symbols::Symbol::Metadata),
239 );
240 metadata_gv.set_initializer(&metadata_init);
241 metadata_gv.set_linkage(Linkage::DLLExport);
242 metadata_gv.set_dll_storage_class(DLLStorageClass::Export);
243 metadata_gv.set_alignment(16);
244
245 if self.config().enable_verifier {
246 merged_module.verify().unwrap();
247 }
248
249 let memory_buffer = target_machine
250 .write_to_memory_buffer(&merged_module, FileType::Object)
251 .unwrap();
252 if let Some(ref callbacks) = self.config.callbacks {
253 callbacks.obj_memory_buffer(&CompiledKind::Module, &memory_buffer);
254 }
255
256 tracing::trace!("Finished compling the module!");
257 Ok(memory_buffer.as_slice().to_vec())
258 }
259}
260
261impl Compiler for LLVMCompiler {
262 fn name(&self) -> &str {
263 "llvm"
264 }
265
266 fn get_perfmap_enabled(&self) -> bool {
267 self.config.enable_perfmap
268 }
269
270 fn deterministic_id(&self) -> String {
271 let mut ret = format!(
272 "llvm-{}",
273 match self.config.opt_level {
274 inkwell::OptimizationLevel::None => "opt0",
275 inkwell::OptimizationLevel::Less => "optl",
276 inkwell::OptimizationLevel::Default => "optd",
277 inkwell::OptimizationLevel::Aggressive => "opta",
278 }
279 );
280
281 if self.config.enable_g0m0_opt {
282 ret.push_str("-g0m0");
283 }
284
285 ret
286 }
287
288 fn get_middlewares(&self) -> &[Arc<dyn ModuleMiddleware>] {
290 &self.config.middlewares
291 }
292
293 fn experimental_native_compile_module(
294 &self,
295 target: &Target,
296 compile_info: &CompileModuleInfo,
297 module_translation: &ModuleTranslationState,
298 function_body_inputs: &PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
300 symbol_registry: &dyn SymbolRegistry,
301 wasmer_metadata: &[u8],
303 ) -> Option<Result<Vec<u8>, CompileError>> {
304 Some(self.compile_native_object(
305 target,
306 compile_info,
307 module_translation,
308 function_body_inputs,
309 symbol_registry,
310 wasmer_metadata,
311 self.config.target_binary_format(target),
312 ))
313 }
314
315 fn compile_module(
318 &self,
319 target: &Target,
320 compile_info: &CompileModuleInfo,
321 module_translation: &ModuleTranslationState,
322 function_body_inputs: PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
323 ) -> Result<Compilation, CompileError> {
324 let memory_styles = &compile_info.memory_styles;
327 let table_styles = &compile_info.table_styles;
328 let binary_format = self.config.target_binary_format(target);
329
330 let module = &compile_info.module;
331
332 let mut module_custom_sections = PrimaryMap::new();
335
336 let mut eh_frame_section_bytes = vec![];
337 let mut eh_frame_section_relocations = vec![];
338
339 let mut compact_unwind_section_bytes = vec![];
340 let mut compact_unwind_section_relocations = vec![];
341
342 let mut got_targets: HashSet<wasmer_compiler::types::relocation::RelocationTarget> = if matches!(
343 target.triple().binary_format,
344 target_lexicon::BinaryFormat::Macho
345 ) {
346 HashSet::from_iter(vec![RelocationTarget::LibCall(LibCall::EHPersonality)])
347 } else {
348 HashSet::default()
349 };
350
351 let symbol_registry = ModuleBasedSymbolRegistry::new(module.clone());
352
353 let functions = if self.config.num_threads.get() > 1 {
354 let pool = ThreadPoolBuilder::new()
355 .num_threads(self.config.num_threads.get())
356 .build()
357 .map_err(|e| CompileError::Resource(e.to_string()))?;
358 pool.install(|| {
359 function_body_inputs
360 .iter()
361 .collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
362 .par_iter()
363 .map_init(
364 || {
365 let target_machine = self.config().target_machine(target);
366 FuncTranslator::new(target_machine, binary_format).unwrap()
367 },
368 |func_translator, (i, input)| {
369 func_translator.translate(
373 module,
374 module_translation,
375 i,
376 input,
377 self.config(),
378 memory_styles,
379 table_styles,
380 &symbol_registry,
381 )
382 },
383 )
384 .collect::<Result<Vec<_>, CompileError>>()
385 })?
386 } else {
387 let target_machine = self.config().target_machine(target);
388 let func_translator = FuncTranslator::new(target_machine, binary_format).unwrap();
389
390 function_body_inputs
391 .iter()
392 .collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
393 .into_iter()
394 .map(|(i, input)| {
395 func_translator.translate(
399 module,
400 module_translation,
401 &i,
402 input,
403 self.config(),
404 memory_styles,
405 table_styles,
406 &symbol_registry,
407 )
408 })
409 .collect::<Result<Vec<_>, CompileError>>()?
410 };
411
412 let functions = functions
413 .into_iter()
414 .map(|mut compiled_function| {
415 let first_section = module_custom_sections.len() as u32;
416 for (section_index, custom_section) in compiled_function.custom_sections.iter() {
417 let mut custom_section = custom_section.clone();
419 for reloc in &mut custom_section.relocations {
420 if let RelocationTarget::CustomSection(index) = reloc.reloc_target {
421 reloc.reloc_target = RelocationTarget::CustomSection(
422 SectionIndex::from_u32(first_section + index.as_u32()),
423 )
424 }
425
426 if reloc.kind.needs_got() {
427 got_targets.insert(reloc.reloc_target);
428 }
429 }
430
431 if compiled_function
432 .eh_frame_section_indices
433 .contains(§ion_index)
434 {
435 let offset = eh_frame_section_bytes.len() as u32;
436 for reloc in &mut custom_section.relocations {
437 reloc.offset += offset;
438 }
439 eh_frame_section_bytes.extend_from_slice(custom_section.bytes.as_slice());
440 eh_frame_section_relocations.extend(custom_section.relocations);
441 module_custom_sections.push(CustomSection {
443 protection: CustomSectionProtection::Read,
444 alignment: None,
445 bytes: SectionBody::new_with_vec(vec![]),
446 relocations: vec![],
447 });
448 } else if compiled_function
449 .compact_unwind_section_indices
450 .contains(§ion_index)
451 {
452 let offset = compact_unwind_section_bytes.len() as u32;
453 for reloc in &mut custom_section.relocations {
454 reloc.offset += offset;
455 }
456 compact_unwind_section_bytes
457 .extend_from_slice(custom_section.bytes.as_slice());
458 compact_unwind_section_relocations.extend(custom_section.relocations);
459 module_custom_sections.push(CustomSection {
461 protection: CustomSectionProtection::Read,
462 alignment: None,
463 bytes: SectionBody::new_with_vec(vec![]),
464 relocations: vec![],
465 });
466 } else {
467 module_custom_sections.push(custom_section);
468 }
469 }
470 for reloc in &mut compiled_function.compiled_function.relocations {
471 if let RelocationTarget::CustomSection(index) = reloc.reloc_target {
472 reloc.reloc_target = RelocationTarget::CustomSection(
473 SectionIndex::from_u32(first_section + index.as_u32()),
474 )
475 }
476
477 if reloc.kind.needs_got() {
478 got_targets.insert(reloc.reloc_target);
479 }
480 }
481 compiled_function.compiled_function
482 })
483 .collect::<PrimaryMap<LocalFunctionIndex, _>>();
484
485 let mut unwind_info = UnwindInfo::default();
486
487 if !eh_frame_section_bytes.is_empty() {
488 let eh_frame_idx = SectionIndex::from_u32(module_custom_sections.len() as u32);
489 module_custom_sections.push(CustomSection {
493 protection: CustomSectionProtection::Read,
494 alignment: None,
495 bytes: SectionBody::new_with_vec(eh_frame_section_bytes),
496 relocations: eh_frame_section_relocations,
497 });
498 unwind_info.eh_frame = Some(eh_frame_idx);
499 }
500
501 if !compact_unwind_section_bytes.is_empty() {
502 let cu_index = SectionIndex::from_u32(module_custom_sections.len() as u32);
503 module_custom_sections.push(CustomSection {
504 protection: CustomSectionProtection::Read,
505 alignment: None,
506 bytes: SectionBody::new_with_vec(compact_unwind_section_bytes),
507 relocations: compact_unwind_section_relocations,
508 });
509 unwind_info.compact_unwind = Some(cu_index);
510 }
511
512 let function_call_trampolines = if self.config.num_threads.get() > 1 {
513 let pool = ThreadPoolBuilder::new()
514 .num_threads(self.config.num_threads.get())
515 .build()
516 .map_err(|e| CompileError::Resource(e.to_string()))?;
517 pool.install(|| {
518 module
519 .signatures
520 .values()
521 .collect::<Vec<_>>()
522 .par_iter()
523 .map_init(
524 || {
525 let target_machine = self.config().target_machine(target);
526 FuncTrampoline::new(target_machine, binary_format).unwrap()
527 },
528 |func_trampoline, sig| {
529 func_trampoline.trampoline(sig, self.config(), "", compile_info)
530 },
531 )
532 .collect::<Vec<_>>()
533 .into_iter()
534 .collect::<Result<PrimaryMap<_, _>, CompileError>>()
535 })?
536 } else {
537 let target_machine = self.config().target_machine(target);
538 let func_trampoline = FuncTrampoline::new(target_machine, binary_format).unwrap();
539 module
540 .signatures
541 .values()
542 .collect::<Vec<_>>()
543 .into_iter()
544 .map(|sig| func_trampoline.trampoline(sig, self.config(), "", compile_info))
545 .collect::<Vec<_>>()
546 .into_iter()
547 .collect::<Result<PrimaryMap<_, _>, CompileError>>()?
548 };
549
550 let dynamic_function_trampolines = if self.config.num_threads.get() > 1 {
551 let pool = ThreadPoolBuilder::new()
552 .num_threads(self.config.num_threads.get())
553 .build()
554 .map_err(|e| CompileError::Resource(e.to_string()))?;
555 pool.install(|| {
556 module
557 .imported_function_types()
558 .collect::<Vec<_>>()
559 .par_iter()
560 .map_init(
561 || {
562 let target_machine = self.config().target_machine(target);
563 FuncTrampoline::new(target_machine, binary_format).unwrap()
564 },
565 |func_trampoline, func_type| {
566 func_trampoline.dynamic_trampoline(func_type, self.config(), "")
567 },
568 )
569 .collect::<Vec<_>>()
570 .into_iter()
571 .collect::<Result<PrimaryMap<_, _>, CompileError>>()
572 })?
573 } else {
574 let target_machine = self.config().target_machine(target);
575 let func_trampoline = FuncTrampoline::new(target_machine, binary_format).unwrap();
576 module
577 .imported_function_types()
578 .collect::<Vec<_>>()
579 .into_iter()
580 .map(|func_type| func_trampoline.dynamic_trampoline(&func_type, self.config(), ""))
581 .collect::<Vec<_>>()
582 .into_iter()
583 .collect::<Result<PrimaryMap<_, _>, CompileError>>()?
584 };
585
586 let mut got = wasmer_compiler::types::function::GOT::empty();
587
588 if !got_targets.is_empty() {
589 let pointer_width = target
590 .triple()
591 .pointer_width()
592 .map_err(|_| CompileError::Codegen("Could not get pointer width".to_string()))?;
593
594 let got_entry_size = match pointer_width {
595 target_lexicon::PointerWidth::U64 => 8,
596 target_lexicon::PointerWidth::U32 => 4,
597 target_lexicon::PointerWidth::U16 => todo!(),
598 };
599
600 let got_entry_reloc_kind = match pointer_width {
601 target_lexicon::PointerWidth::U64 => RelocationKind::Abs8,
602 target_lexicon::PointerWidth::U32 => RelocationKind::Abs4,
603 target_lexicon::PointerWidth::U16 => todo!(),
604 };
605
606 let got_data: Vec<u8> = vec![0; got_targets.len() * got_entry_size];
607 let mut got_relocs = vec![];
608
609 for (i, target) in got_targets.into_iter().enumerate() {
610 got_relocs.push(wasmer_compiler::types::relocation::Relocation {
611 kind: got_entry_reloc_kind,
612 reloc_target: target,
613 offset: (i * got_entry_size) as u32,
614 addend: 0,
615 });
616 }
617
618 let got_idx = SectionIndex::from_u32(module_custom_sections.len() as u32);
619 module_custom_sections.push(CustomSection {
620 protection: CustomSectionProtection::Read,
621 alignment: None,
622 bytes: SectionBody::new_with_vec(got_data),
623 relocations: got_relocs,
624 });
625 got.index = Some(got_idx);
626 };
627
628 tracing::trace!("Finished compling the module!");
629 Ok(Compilation {
630 functions,
631 custom_sections: module_custom_sections,
632 function_call_trampolines,
633 dynamic_function_trampolines,
634 unwind_info,
635 got,
636 })
637 }
638
639 fn with_opts(
640 &mut self,
641 suggested_compiler_opts: &wasmer_types::target::UserCompilerOptimizations,
642 ) -> Result<(), CompileError> {
643 if suggested_compiler_opts.pass_params.is_some_and(|v| v) {
644 self.config.enable_g0m0_opt = true;
645 }
646 Ok(())
647 }
648}