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