wasmtime_lightbeam/
lib.rs

1//! Support for compiling with Lightbeam.
2//!
3//! This crates provides an implementation of [`Compiler`] in the form of
4//! [`Lightbeam`].
5
6#![allow(dead_code)]
7
8use anyhow::Result;
9use cranelift_codegen::binemit;
10use cranelift_codegen::ir::{self, ExternalName};
11use object::write::Object;
12use std::any::Any;
13use std::collections::BTreeMap;
14use wasmtime_environ::{
15    BuiltinFunctionIndex, CompileError, Compiler, FlagValue, FunctionBodyData, FunctionInfo,
16    Module, ModuleTranslation, PrimaryMap, TrapInformation, Tunables, TypeTables, VMOffsets,
17};
18use wasmtime_environ::{
19    DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex,
20    GlobalIndex, MemoryIndex, TableIndex, Trampoline, TypeIndex, WasmFuncType,
21};
22
23/// A compiler that compiles a WebAssembly module with Lightbeam, directly translating the Wasm file.
24pub struct Lightbeam;
25
26impl Compiler for Lightbeam {
27    fn compile_function(
28        &self,
29        _translation: &ModuleTranslation,
30        _i: DefinedFuncIndex,
31        _function_body: FunctionBodyData<'_>,
32        _tunables: &Tunables,
33        _types: &TypeTables,
34    ) -> Result<Box<dyn Any + Send>, CompileError> {
35        unimplemented!()
36        // if tunables.generate_native_debuginfo {
37        //     return Err(CompileError::DebugInfoNotSupported);
38        // }
39        // let func_index = translation.module.func_index(i);
40
41        // let env = FuncEnvironment::new(isa.frontend_config().pointer_bytes(), translation);
42        // let mut codegen_session: CodeGenSession<_> = CodeGenSession::new(
43        //     translation.function_body_inputs.len() as u32,
44        //     &env,
45        //     lightbeam::microwasm::I32,
46        // );
47
48        // let mut reloc_sink = RelocSink::new(func_index);
49        // let mut trap_sink = TrapSink::new();
50        // lightbeam::translate_function(
51        //     &mut codegen_session,
52        //     Sinks {
53        //         relocs: &mut reloc_sink,
54        //         traps: &mut trap_sink,
55        //         offsets: &mut NullOffsetSink,
56        //     },
57        //     i.as_u32(),
58        //     function_body.body,
59        // )
60        // .map_err(|e| CompileError::Codegen(format!("Failed to translate function: {}", e)))?;
61
62        // let code_section = codegen_session
63        //     .into_translated_code_section()
64        //     .map_err(|e| CompileError::Codegen(format!("Failed to generate output code: {}", e)))?;
65
66        // Ok(CompiledFunction {
67        //     // TODO: try to remove copy here (?)
68        //     body: code_section.buffer().to_vec(),
69        //     traps: trap_sink.traps,
70        //     relocations: reloc_sink.func_relocs,
71
72        //     // not implemented for lightbeam currently
73        //     unwind_info: None,
74        //     stack_maps: Default::default(),
75        //     stack_slots: Default::default(),
76        //     value_labels_ranges: Default::default(),
77        //     address_map: Default::default(),
78        //     jt_offsets: Default::default(),
79        // })
80    }
81
82    fn emit_obj(
83        &self,
84        _module: &ModuleTranslation,
85        _types: &TypeTables,
86        _funcs: PrimaryMap<DefinedFuncIndex, Box<dyn Any + Send>>,
87        _emit_dwarf: bool,
88        _obj: &mut Object,
89    ) -> Result<(PrimaryMap<DefinedFuncIndex, FunctionInfo>, Vec<Trampoline>)> {
90        unimplemented!()
91    }
92
93    fn emit_trampoline_obj(
94        &self,
95        _ty: &WasmFuncType,
96        _host_fn: usize,
97        _obj: &mut Object,
98    ) -> Result<(Trampoline, Trampoline)> {
99        unimplemented!()
100    }
101
102    fn triple(&self) -> &target_lexicon::Triple {
103        unimplemented!()
104    }
105
106    fn flags(&self) -> BTreeMap<String, FlagValue> {
107        unimplemented!()
108    }
109
110    fn isa_flags(&self) -> BTreeMap<String, FlagValue> {
111        unimplemented!()
112    }
113}
114
115/// Implementation of a relocation sink that just saves all the information for later
116struct RelocSink {
117    /// Current function index.
118    func_index: FuncIndex,
119    // /// Relocations recorded for the function.
120    // func_relocs: Vec<Relocation>,
121}
122
123impl binemit::RelocSink for RelocSink {
124    fn reloc_external(
125        &mut self,
126        _offset: binemit::CodeOffset,
127        _srcloc: ir::SourceLoc,
128        _reloc: binemit::Reloc,
129        _name: &ExternalName,
130        _addend: binemit::Addend,
131    ) {
132        unimplemented!()
133        // let reloc_target = if let ExternalName::User { namespace, index } = *name {
134        //     debug_assert_eq!(namespace, 0);
135        //     RelocationTarget::UserFunc(FuncIndex::from_u32(index))
136        // } else if let ExternalName::LibCall(libcall) = *name {
137        //     RelocationTarget::LibCall(libcall)
138        // } else {
139        //     panic!("unrecognized external name")
140        // };
141        // self.func_relocs.push(Relocation {
142        //     reloc,
143        //     reloc_target,
144        //     offset,
145        //     addend,
146        // });
147    }
148
149    fn reloc_constant(
150        &mut self,
151        _code_offset: binemit::CodeOffset,
152        _reloc: binemit::Reloc,
153        _constant_offset: ir::ConstantOffset,
154    ) {
155        // Do nothing for now: cranelift emits constant data after the function code and also emits
156        // function code with correct relative offsets to the constant data.
157    }
158
159    fn reloc_jt(
160        &mut self,
161        _offset: binemit::CodeOffset,
162        _reloc: binemit::Reloc,
163        _jt: ir::JumpTable,
164    ) {
165        unimplemented!()
166        // self.func_relocs.push(Relocation {
167        //     reloc,
168        //     reloc_target: RelocationTarget::JumpTable(self.func_index, jt),
169        //     offset,
170        //     addend: 0,
171        // });
172    }
173}
174
175impl RelocSink {
176    /// Return a new `RelocSink` instance.
177    fn new(func_index: FuncIndex) -> Self {
178        Self {
179            func_index,
180            // func_relocs: Vec::new(),
181        }
182    }
183}
184
185/// Implementation of a trap sink that simply stores all trap info in-memory
186#[derive(Default)]
187struct TrapSink {
188    /// The in-memory vector of trap info
189    traps: Vec<TrapInformation>,
190}
191
192impl TrapSink {
193    /// Create a new `TrapSink`
194    fn new() -> Self {
195        Self::default()
196    }
197}
198
199impl binemit::TrapSink for TrapSink {
200    fn trap(
201        &mut self,
202        _code_offset: binemit::CodeOffset,
203        _source_loc: ir::SourceLoc,
204        _trap_code: ir::TrapCode,
205    ) {
206        unimplemented!()
207        // self.traps.push(TrapInformation {
208        //     code_offset,
209        //     trap_code,
210        // });
211    }
212}
213
214/// The `FuncEnvironment` implementation for use by the `ModuleEnvironment`.
215struct FuncEnvironment<'module_environment> {
216    /// The module-level environment which this function-level environment belongs to.
217    module: &'module_environment Module,
218
219    /// Offsets to struct fields accessed by JIT code.
220    offsets: VMOffsets<u8>,
221}
222
223impl<'module_environment> FuncEnvironment<'module_environment> {
224    fn new(pointer_bytes: u8, translation: &'module_environment ModuleTranslation<'_>) -> Self {
225        Self {
226            module: &translation.module,
227            offsets: VMOffsets::new(pointer_bytes, &translation.module),
228        }
229    }
230}
231
232// TODO: This is necessary as if Lightbeam used `FuncEnvironment` directly it would cause
233//       a circular dependency graph. We should extract common types out into a separate
234//       crate that Lightbeam can use but until then we need this trait.
235impl lightbeam::ModuleContext for FuncEnvironment<'_> {
236    type Signature = ir::Signature;
237    type GlobalType = ir::Type;
238
239    fn func_index(&self, defined_func_index: u32) -> u32 {
240        self.module
241            .func_index(DefinedFuncIndex::from_u32(defined_func_index))
242            .as_u32()
243    }
244
245    fn defined_func_index(&self, func_index: u32) -> Option<u32> {
246        self.module
247            .defined_func_index(FuncIndex::from_u32(func_index))
248            .map(DefinedFuncIndex::as_u32)
249    }
250
251    fn defined_global_index(&self, global_index: u32) -> Option<u32> {
252        self.module
253            .defined_global_index(GlobalIndex::from_u32(global_index))
254            .map(DefinedGlobalIndex::as_u32)
255    }
256
257    fn global_type(&self, _global_index: u32) -> &Self::GlobalType {
258        unimplemented!()
259        // &self.module.globals[GlobalIndex::from_u32(global_index)].ty
260    }
261
262    fn func_type_index(&self, func_idx: u32) -> u32 {
263        self.module.functions[FuncIndex::from_u32(func_idx)].as_u32()
264    }
265
266    fn signature(&self, _index: u32) -> &Self::Signature {
267        panic!("not implemented")
268    }
269
270    fn defined_table_index(&self, table_index: u32) -> Option<u32> {
271        self.module
272            .defined_table_index(TableIndex::from_u32(table_index))
273            .map(DefinedTableIndex::as_u32)
274    }
275
276    fn defined_memory_index(&self, memory_index: u32) -> Option<u32> {
277        self.module
278            .defined_memory_index(MemoryIndex::from_u32(memory_index))
279            .map(DefinedMemoryIndex::as_u32)
280    }
281
282    fn vmctx_builtin_function(&self, func_index: u32) -> u32 {
283        self.offsets
284            .vmctx_builtin_function(BuiltinFunctionIndex::from_u32(func_index))
285    }
286
287    fn vmctx_vmfunction_import_body(&self, func_index: u32) -> u32 {
288        self.offsets
289            .vmctx_vmfunction_import_body(FuncIndex::from_u32(func_index))
290    }
291    fn vmctx_vmfunction_import_vmctx(&self, func_index: u32) -> u32 {
292        self.offsets
293            .vmctx_vmfunction_import_vmctx(FuncIndex::from_u32(func_index))
294    }
295
296    fn vmctx_vmglobal_import_from(&self, global_index: u32) -> u32 {
297        self.offsets
298            .vmctx_vmglobal_import_from(GlobalIndex::from_u32(global_index))
299    }
300    fn vmctx_vmglobal_definition(&self, defined_global_index: u32) -> u32 {
301        self.offsets
302            .vmctx_vmglobal_definition(DefinedGlobalIndex::from_u32(defined_global_index))
303    }
304    fn vmctx_vmmemory_import_from(&self, memory_index: u32) -> u32 {
305        self.offsets
306            .vmctx_vmmemory_import_from(MemoryIndex::from_u32(memory_index))
307    }
308    fn vmctx_vmmemory_definition(&self, defined_memory_index: u32) -> u32 {
309        self.offsets
310            .vmctx_vmmemory_definition(DefinedMemoryIndex::from_u32(defined_memory_index))
311    }
312    fn vmctx_vmmemory_definition_base(&self, defined_memory_index: u32) -> u32 {
313        self.offsets
314            .vmctx_vmmemory_definition_base(DefinedMemoryIndex::from_u32(defined_memory_index))
315    }
316    fn vmctx_vmmemory_definition_current_length(&self, defined_memory_index: u32) -> u32 {
317        self.offsets
318            .vmctx_vmmemory_definition_current_length(DefinedMemoryIndex::from_u32(
319                defined_memory_index,
320            ))
321    }
322    fn vmmemory_definition_base(&self) -> u8 {
323        self.offsets.vmmemory_definition_base()
324    }
325    fn vmmemory_definition_current_length(&self) -> u8 {
326        self.offsets.vmmemory_definition_current_length()
327    }
328    fn vmctx_vmtable_import_from(&self, table_index: u32) -> u32 {
329        self.offsets
330            .vmctx_vmtable_import_from(TableIndex::from_u32(table_index))
331    }
332    fn vmctx_vmtable_definition(&self, defined_table_index: u32) -> u32 {
333        self.offsets
334            .vmctx_vmtable_definition(DefinedTableIndex::from_u32(defined_table_index))
335    }
336    fn vmctx_vmtable_definition_base(&self, defined_table_index: u32) -> u32 {
337        self.offsets
338            .vmctx_vmtable_definition_base(DefinedTableIndex::from_u32(defined_table_index))
339    }
340    fn vmctx_vmtable_definition_current_elements(&self, defined_table_index: u32) -> u32 {
341        self.offsets
342            .vmctx_vmtable_definition_current_elements(DefinedTableIndex::from_u32(
343                defined_table_index,
344            ))
345    }
346    fn vmtable_definition_base(&self) -> u8 {
347        self.offsets.vmtable_definition_base()
348    }
349    fn vmtable_definition_current_elements(&self) -> u8 {
350        self.offsets.vmtable_definition_current_elements()
351    }
352    fn vmcaller_checked_anyfunc_type_index(&self) -> u8 {
353        self.offsets.vmcaller_checked_anyfunc_type_index()
354    }
355    fn vmcaller_checked_anyfunc_func_ptr(&self) -> u8 {
356        self.offsets.vmcaller_checked_anyfunc_func_ptr()
357    }
358    fn vmcaller_checked_anyfunc_vmctx(&self) -> u8 {
359        self.offsets.vmcaller_checked_anyfunc_vmctx()
360    }
361    fn size_of_vmcaller_checked_anyfunc(&self) -> u8 {
362        self.offsets.size_of_vmcaller_checked_anyfunc()
363    }
364    fn vmctx_vmshared_signature_id(&self, signature_idx: u32) -> u32 {
365        self.offsets
366            .vmctx_vmshared_signature_id(TypeIndex::from_u32(signature_idx))
367    }
368
369    // TODO: type of a global
370}