wasmer_compiler_llvm/
compiler.rs

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 std::sync::Arc;
13use wasmer_compiler::types::function::{Compilation, Dwarf};
14use wasmer_compiler::types::module::CompileModuleInfo;
15use wasmer_compiler::{
16    types::{
17        relocation::RelocationTarget,
18        section::{CustomSection, CustomSectionProtection, SectionBody, SectionIndex},
19        symbols::{Symbol, SymbolRegistry},
20        target::Target,
21    },
22    Compiler, FunctionBodyData, ModuleMiddleware, ModuleTranslationState,
23};
24use wasmer_types::entity::{EntityRef, PrimaryMap};
25use wasmer_types::{CompileError, FunctionIndex, LocalFunctionIndex, SignatureIndex};
26
27//use std::sync::Mutex;
28
29/// A compiler that compiles a WebAssembly module with LLVM, translating the Wasm to LLVM IR,
30/// optimizing it and then translating to assembly.
31pub struct LLVMCompiler {
32    config: LLVM,
33}
34
35impl LLVMCompiler {
36    /// Creates a new LLVM compiler
37    pub fn new(config: LLVM) -> LLVMCompiler {
38        LLVMCompiler { config }
39    }
40
41    /// Gets the config for this Compiler
42    fn config(&self) -> &LLVM {
43        &self.config
44    }
45}
46
47struct ShortNames {}
48
49impl SymbolRegistry for ShortNames {
50    fn symbol_to_name(&self, symbol: Symbol) -> String {
51        match symbol {
52            Symbol::Metadata => "M".to_string(),
53            Symbol::LocalFunction(index) => format!("f{}", index.index()),
54            Symbol::Section(index) => format!("s{}", index.index()),
55            Symbol::FunctionCallTrampoline(index) => format!("t{}", index.index()),
56            Symbol::DynamicFunctionTrampoline(index) => format!("d{}", index.index()),
57        }
58    }
59
60    fn name_to_symbol(&self, name: &str) -> Option<Symbol> {
61        if name.len() < 2 {
62            return None;
63        }
64        let (ty, idx) = name.split_at(1);
65        if ty.starts_with('M') {
66            return Some(Symbol::Metadata);
67        }
68
69        let idx = idx.parse::<u32>().ok()?;
70        match ty.chars().next().unwrap() {
71            'f' => Some(Symbol::LocalFunction(LocalFunctionIndex::from_u32(idx))),
72            's' => Some(Symbol::Section(SectionIndex::from_u32(idx))),
73            't' => Some(Symbol::FunctionCallTrampoline(SignatureIndex::from_u32(
74                idx,
75            ))),
76            'd' => Some(Symbol::DynamicFunctionTrampoline(FunctionIndex::from_u32(
77                idx,
78            ))),
79            _ => None,
80        }
81    }
82}
83
84impl LLVMCompiler {
85    fn compile_native_object(
86        &self,
87        target: &Target,
88        compile_info: &CompileModuleInfo,
89        module_translation: &ModuleTranslationState,
90        function_body_inputs: &PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
91        symbol_registry: &dyn SymbolRegistry,
92        wasmer_metadata: &[u8],
93    ) -> Result<Vec<u8>, CompileError> {
94        let target_machine = self.config().target_machine(target);
95        let ctx = Context::create();
96
97        // TODO: https:/github.com/rayon-rs/rayon/issues/822
98
99        let merged_bitcode = function_body_inputs.into_iter().par_bridge().map_init(
100            || {
101                let target_machine = self.config().target_machine(target);
102                FuncTranslator::new(target_machine)
103            },
104            |func_translator, (i, input)| {
105                let module = func_translator.translate_to_module(
106                    &compile_info.module,
107                    module_translation,
108                    &i,
109                    input,
110                    self.config(),
111                    &compile_info.memory_styles,
112                    &compile_info.table_styles,
113                    symbol_registry,
114                )?;
115                Ok(module.write_bitcode_to_memory().as_slice().to_vec())
116            },
117        );
118
119        let trampolines_bitcode = compile_info.module.signatures.iter().par_bridge().map_init(
120            || {
121                let target_machine = self.config().target_machine(target);
122                FuncTrampoline::new(target_machine)
123            },
124            |func_trampoline, (i, sig)| {
125                let name = symbol_registry.symbol_to_name(Symbol::FunctionCallTrampoline(i));
126                let module = func_trampoline.trampoline_to_module(sig, self.config(), &name)?;
127                Ok(module.write_bitcode_to_memory().as_slice().to_vec())
128            },
129        );
130
131        let dynamic_trampolines_bitcode =
132            compile_info.module.functions.iter().par_bridge().map_init(
133                || {
134                    let target_machine = self.config().target_machine(target);
135                    (
136                        FuncTrampoline::new(target_machine),
137                        &compile_info.module.signatures,
138                    )
139                },
140                |(func_trampoline, signatures), (i, sig)| {
141                    let sig = &signatures[*sig];
142                    let name = symbol_registry.symbol_to_name(Symbol::DynamicFunctionTrampoline(i));
143                    let module =
144                        func_trampoline.dynamic_trampoline_to_module(sig, self.config(), &name)?;
145                    Ok(module.write_bitcode_to_memory().as_slice().to_vec())
146                },
147            );
148
149        let merged_bitcode = merged_bitcode
150            .chain(trampolines_bitcode)
151            .chain(dynamic_trampolines_bitcode)
152            .collect::<Result<Vec<_>, CompileError>>()?
153            .into_par_iter()
154            .reduce_with(|bc1, bc2| {
155                let ctx = Context::create();
156                let membuf = MemoryBuffer::create_from_memory_range(&bc1, "");
157                let m1 = Module::parse_bitcode_from_buffer(&membuf, &ctx).unwrap();
158                let membuf = MemoryBuffer::create_from_memory_range(&bc2, "");
159                let m2 = Module::parse_bitcode_from_buffer(&membuf, &ctx).unwrap();
160                m1.link_in_module(m2).unwrap();
161                m1.write_bitcode_to_memory().as_slice().to_vec()
162            });
163        let merged_module = if let Some(bc) = merged_bitcode {
164            let membuf = MemoryBuffer::create_from_memory_range(&bc, "");
165            Module::parse_bitcode_from_buffer(&membuf, &ctx).unwrap()
166        } else {
167            ctx.create_module("")
168        };
169
170        let i8_ty = ctx.i8_type();
171        let metadata_init = i8_ty.const_array(
172            wasmer_metadata
173                .iter()
174                .map(|v| i8_ty.const_int(*v as u64, false))
175                .collect::<Vec<_>>()
176                .as_slice(),
177        );
178        let metadata_gv = merged_module.add_global(
179            metadata_init.get_type(),
180            None,
181            &symbol_registry.symbol_to_name(wasmer_compiler::types::symbols::Symbol::Metadata),
182        );
183        metadata_gv.set_initializer(&metadata_init);
184        metadata_gv.set_linkage(Linkage::DLLExport);
185        metadata_gv.set_dll_storage_class(DLLStorageClass::Export);
186        metadata_gv.set_alignment(16);
187
188        if self.config().enable_verifier {
189            merged_module.verify().unwrap();
190        }
191
192        let memory_buffer = target_machine
193            .write_to_memory_buffer(&merged_module, FileType::Object)
194            .unwrap();
195        if let Some(ref callbacks) = self.config.callbacks {
196            callbacks.obj_memory_buffer(&CompiledKind::Module, &memory_buffer);
197        }
198
199        Ok(memory_buffer.as_slice().to_vec())
200    }
201}
202
203impl Compiler for LLVMCompiler {
204    fn name(&self) -> &str {
205        "llvm"
206    }
207
208    /// Get the middlewares for this compiler
209    fn get_middlewares(&self) -> &[Arc<dyn ModuleMiddleware>] {
210        &self.config.middlewares
211    }
212
213    fn experimental_native_compile_module(
214        &self,
215        target: &Target,
216        compile_info: &CompileModuleInfo,
217        module_translation: &ModuleTranslationState,
218        // The list of function bodies
219        function_body_inputs: &PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
220        symbol_registry: &dyn SymbolRegistry,
221        // The metadata to inject into the wasmer_metadata section of the object file.
222        wasmer_metadata: &[u8],
223    ) -> Option<Result<Vec<u8>, CompileError>> {
224        Some(self.compile_native_object(
225            target,
226            compile_info,
227            module_translation,
228            function_body_inputs,
229            symbol_registry,
230            wasmer_metadata,
231        ))
232    }
233
234    /// Compile the module using LLVM, producing a compilation result with
235    /// associated relocations.
236    fn compile_module(
237        &self,
238        target: &Target,
239        compile_info: &CompileModuleInfo,
240        module_translation: &ModuleTranslationState,
241        function_body_inputs: PrimaryMap<LocalFunctionIndex, FunctionBodyData<'_>>,
242    ) -> Result<Compilation, CompileError> {
243        //let data = Arc::new(Mutex::new(0));
244        let memory_styles = &compile_info.memory_styles;
245        let table_styles = &compile_info.table_styles;
246
247        let module = &compile_info.module;
248
249        // TODO: merge constants in sections.
250
251        let mut module_custom_sections = PrimaryMap::new();
252        let mut frame_section_bytes = vec![];
253        let mut frame_section_relocations = vec![];
254        let functions = function_body_inputs
255            .iter()
256            .collect::<Vec<(LocalFunctionIndex, &FunctionBodyData<'_>)>>()
257            .par_iter()
258            .map_init(
259                || {
260                    let target_machine = self.config().target_machine(target);
261                    FuncTranslator::new(target_machine)
262                },
263                |func_translator, (i, input)| {
264                    // TODO: remove (to serialize)
265                    //let _data = data.lock().unwrap();
266                    func_translator.translate(
267                        module,
268                        module_translation,
269                        i,
270                        input,
271                        self.config(),
272                        memory_styles,
273                        table_styles,
274                        &ShortNames {},
275                    )
276                },
277            )
278            .collect::<Result<Vec<_>, CompileError>>()?
279            .into_iter()
280            .map(|mut compiled_function| {
281                let first_section = module_custom_sections.len() as u32;
282                for (section_index, custom_section) in compiled_function.custom_sections.iter() {
283                    // TODO: remove this call to clone()
284                    let mut custom_section = custom_section.clone();
285                    for reloc in &mut custom_section.relocations {
286                        if let RelocationTarget::CustomSection(index) = reloc.reloc_target {
287                            reloc.reloc_target = RelocationTarget::CustomSection(
288                                SectionIndex::from_u32(first_section + index.as_u32()),
289                            )
290                        }
291                    }
292                    if compiled_function
293                        .eh_frame_section_indices
294                        .contains(&section_index)
295                    {
296                        let offset = frame_section_bytes.len() as u32;
297                        for reloc in &mut custom_section.relocations {
298                            reloc.offset += offset;
299                        }
300                        frame_section_bytes.extend_from_slice(custom_section.bytes.as_slice());
301                        frame_section_relocations.extend(custom_section.relocations);
302                        // TODO: we do this to keep the count right, remove it.
303                        module_custom_sections.push(CustomSection {
304                            protection: CustomSectionProtection::Read,
305                            bytes: SectionBody::new_with_vec(vec![]),
306                            relocations: vec![],
307                        });
308                    } else {
309                        module_custom_sections.push(custom_section);
310                    }
311                }
312                for reloc in &mut compiled_function.compiled_function.relocations {
313                    if let RelocationTarget::CustomSection(index) = reloc.reloc_target {
314                        reloc.reloc_target = RelocationTarget::CustomSection(
315                            SectionIndex::from_u32(first_section + index.as_u32()),
316                        )
317                    }
318                }
319                compiled_function.compiled_function
320            })
321            .collect::<PrimaryMap<LocalFunctionIndex, _>>();
322
323        let dwarf = if !frame_section_bytes.is_empty() {
324            let dwarf = Some(Dwarf::new(SectionIndex::from_u32(
325                module_custom_sections.len() as u32,
326            )));
327            // Do not terminate dwarf info with a zero-length CIE.
328            // Because more info will be added later
329            // in lib/object/src/module.rs emit_compilation
330            module_custom_sections.push(CustomSection {
331                protection: CustomSectionProtection::Read,
332                bytes: SectionBody::new_with_vec(frame_section_bytes),
333                relocations: frame_section_relocations,
334            });
335            dwarf
336        } else {
337            None
338        };
339
340        let function_call_trampolines = module
341            .signatures
342            .values()
343            .collect::<Vec<_>>()
344            .par_iter()
345            .map_init(
346                || {
347                    let target_machine = self.config().target_machine(target);
348                    FuncTrampoline::new(target_machine)
349                },
350                |func_trampoline, sig| func_trampoline.trampoline(sig, self.config(), ""),
351            )
352            .collect::<Vec<_>>()
353            .into_iter()
354            .collect::<Result<PrimaryMap<_, _>, CompileError>>()?;
355
356        let dynamic_function_trampolines = module
357            .imported_function_types()
358            .collect::<Vec<_>>()
359            .par_iter()
360            .map_init(
361                || {
362                    let target_machine = self.config().target_machine(target);
363                    FuncTrampoline::new(target_machine)
364                },
365                |func_trampoline, func_type| {
366                    func_trampoline.dynamic_trampoline(func_type, self.config(), "")
367                },
368            )
369            .collect::<Result<Vec<_>, CompileError>>()?
370            .into_iter()
371            .collect::<PrimaryMap<_, _>>();
372
373        Ok(Compilation {
374            functions,
375            custom_sections: module_custom_sections,
376            function_call_trampolines,
377            dynamic_function_trampolines,
378            debug: dwarf,
379        })
380    }
381}