diff --git a/Cargo.lock b/Cargo.lock index 4bc45bbdef..0f85a443b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2474,7 +2474,6 @@ dependencies = [ "log", "more-asserts", "pretty_env_logger", - "rayon", "serde", "sha2", "tempfile", @@ -2531,6 +2530,7 @@ dependencies = [ "log", "more-asserts", "object 0.20.0", + "rayon", "region", "serde", "target-lexicon", diff --git a/cranelift/codegen/src/ir/stackslot.rs b/cranelift/codegen/src/ir/stackslot.rs index bad79df5ff..13d35d37b9 100644 --- a/cranelift/codegen/src/ir/stackslot.rs +++ b/cranelift/codegen/src/ir/stackslot.rs @@ -182,7 +182,7 @@ pub struct StackLayoutInfo { /// Stack frame manager. /// /// Keep track of all the stack slots used by a function. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Default)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct StackSlots { /// All allocated stack slots. @@ -202,12 +202,7 @@ pub struct StackSlots { impl StackSlots { /// Create an empty stack slot manager. pub fn new() -> Self { - Self { - slots: PrimaryMap::new(), - outgoing: Vec::new(), - emergency: Vec::new(), - layout_info: None, - } + StackSlots::default() } /// Clear out everything. diff --git a/cranelift/entity/src/iter.rs b/cranelift/entity/src/iter.rs index 8c681023d2..fb0a8af9e0 100644 --- a/cranelift/entity/src/iter.rs +++ b/cranelift/entity/src/iter.rs @@ -1,6 +1,7 @@ //! A double-ended iterator over entity references and entities. use crate::EntityRef; +use alloc::vec; use core::iter::Enumerate; use core::marker::PhantomData; use core::slice; @@ -84,3 +85,40 @@ impl<'a, K: EntityRef, V> DoubleEndedIterator for IterMut<'a, K, V> { } impl<'a, K: EntityRef, V> ExactSizeIterator for IterMut<'a, K, V> {} + +/// Iterate over all keys in order. +pub struct IntoIter { + enumerate: Enumerate>, + unused: PhantomData, +} + +impl IntoIter { + /// Create an `IntoIter` iterator that visits the `PrimaryMap` keys and values + /// of `iter`. + pub fn new(iter: vec::IntoIter) -> Self { + Self { + enumerate: iter.enumerate(), + unused: PhantomData, + } + } +} + +impl Iterator for IntoIter { + type Item = (K, V); + + fn next(&mut self) -> Option { + self.enumerate.next().map(|(i, v)| (K::new(i), v)) + } + + fn size_hint(&self) -> (usize, Option) { + self.enumerate.size_hint() + } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + self.enumerate.next_back().map(|(i, v)| (K::new(i), v)) + } +} + +impl ExactSizeIterator for IntoIter {} diff --git a/cranelift/entity/src/map.rs b/cranelift/entity/src/map.rs index 7eb889e8b4..6e04b96841 100644 --- a/cranelift/entity/src/map.rs +++ b/cranelift/entity/src/map.rs @@ -131,6 +131,16 @@ where } } +impl Default for SecondaryMap +where + K: EntityRef, + V: Clone + Default, +{ + fn default() -> SecondaryMap { + SecondaryMap::new() + } +} + /// Immutable indexing into an `SecondaryMap`. /// /// All keys are permitted. Untouched entries have the default value. diff --git a/cranelift/entity/src/primary.rs b/cranelift/entity/src/primary.rs index 974033addd..9f43f088ce 100644 --- a/cranelift/entity/src/primary.rs +++ b/cranelift/entity/src/primary.rs @@ -1,6 +1,6 @@ //! Densely numbered entity references as mapping keys. use crate::boxed_slice::BoxedSlice; -use crate::iter::{Iter, IterMut}; +use crate::iter::{IntoIter, Iter, IterMut}; use crate::keys::Keys; use crate::EntityRef; use alloc::boxed::Box; @@ -150,6 +150,15 @@ where } } +impl Default for PrimaryMap +where + K: EntityRef, +{ + fn default() -> PrimaryMap { + PrimaryMap::new() + } +} + /// Immutable indexing into an `PrimaryMap`. /// The indexed value must be in the map. impl Index for PrimaryMap @@ -173,6 +182,18 @@ where } } +impl IntoIterator for PrimaryMap +where + K: EntityRef, +{ + type Item = (K, V); + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self.elems.into_iter()) + } +} + impl<'a, K, V> IntoIterator for &'a PrimaryMap where K: EntityRef, diff --git a/crates/debug/src/transform/address_transform.rs b/crates/debug/src/transform/address_transform.rs index db558309ce..43bfc0b636 100644 --- a/crates/debug/src/transform/address_transform.rs +++ b/crates/debug/src/transform/address_transform.rs @@ -5,8 +5,7 @@ use std::iter::FromIterator; use wasmtime_environ::entity::{EntityRef, PrimaryMap}; use wasmtime_environ::ir::SourceLoc; use wasmtime_environ::wasm::DefinedFuncIndex; -use wasmtime_environ::WasmFileInfo; -use wasmtime_environ::{FunctionAddressMap, ModuleAddressMap}; +use wasmtime_environ::{CompiledFunctions, FunctionAddressMap, WasmFileInfo}; pub type GeneratedAddress = usize; pub type WasmAddress = u64; @@ -187,11 +186,12 @@ fn build_function_lookup( } fn build_function_addr_map( - at: &ModuleAddressMap, + funcs: &CompiledFunctions, code_section_offset: u64, ) -> PrimaryMap { let mut map = PrimaryMap::new(); - for (_, ft) in at { + for (_, f) in funcs { + let ft = &f.address_map; let mut fn_map = Vec::new(); for t in &ft.instructions { if t.srcloc.is_default() { @@ -447,11 +447,12 @@ impl<'a> Iterator for TransformRangeIter<'a> { } impl AddressTransform { - pub fn new(at: &ModuleAddressMap, wasm_file: &WasmFileInfo) -> Self { + pub fn new(funcs: &CompiledFunctions, wasm_file: &WasmFileInfo) -> Self { let code_section_offset = wasm_file.code_section_offset; let mut func = BTreeMap::new(); - for (i, ft) in at { + for (i, f) in funcs { + let ft = &f.address_map; let (fn_start, fn_end, lookup) = build_function_lookup(ft, code_section_offset); func.insert( @@ -465,7 +466,7 @@ impl AddressTransform { ); } - let map = build_function_addr_map(at, code_section_offset); + let map = build_function_addr_map(funcs, code_section_offset); let func = Vec::from_iter(func.into_iter()); AddressTransform { map, func } } @@ -606,8 +607,8 @@ mod tests { use std::iter::FromIterator; use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::ir::SourceLoc; - use wasmtime_environ::WasmFileInfo; - use wasmtime_environ::{FunctionAddressMap, InstructionAddressMap, ModuleAddressMap}; + use wasmtime_environ::{CompiledFunction, WasmFileInfo}; + use wasmtime_environ::{CompiledFunctions, FunctionAddressMap, InstructionAddressMap}; #[test] fn test_get_wasm_code_offset() { @@ -640,8 +641,11 @@ mod tests { } } - fn create_simple_module(func: FunctionAddressMap) -> ModuleAddressMap { - PrimaryMap::from_iter(vec![func]) + fn create_simple_module(address_map: FunctionAddressMap) -> CompiledFunctions { + PrimaryMap::from_iter(vec![CompiledFunction { + address_map, + ..Default::default() + }]) } #[test] diff --git a/crates/debug/src/transform/expression.rs b/crates/debug/src/transform/expression.rs index c92280f69b..a1a651586b 100644 --- a/crates/debug/src/transform/expression.rs +++ b/crates/debug/src/transform/expression.rs @@ -601,6 +601,7 @@ mod tests { use super::compile_expression; use super::{AddressTransform, FunctionFrameInfo, ValueLabel, ValueLabelsRanges}; use gimli::{self, Encoding, EndianSlice, Expression, RunTimeEndian}; + use wasmtime_environ::CompiledFunction; macro_rules! expression { ($($i:literal),*) => { @@ -689,23 +690,26 @@ mod tests { use wasmtime_environ::{FunctionAddressMap, InstructionAddressMap}; let mut module_map = PrimaryMap::new(); let code_section_offset: u32 = 100; - module_map.push(FunctionAddressMap { - instructions: vec![ - InstructionAddressMap { - srcloc: SourceLoc::new(code_section_offset + 12), - code_offset: 5, - code_len: 3, - }, - InstructionAddressMap { - srcloc: SourceLoc::new(code_section_offset + 17), - code_offset: 15, - code_len: 8, - }, - ], - start_srcloc: SourceLoc::new(code_section_offset + 10), - end_srcloc: SourceLoc::new(code_section_offset + 20), - body_offset: 0, - body_len: 30, + module_map.push(CompiledFunction { + address_map: FunctionAddressMap { + instructions: vec![ + InstructionAddressMap { + srcloc: SourceLoc::new(code_section_offset + 12), + code_offset: 5, + code_len: 3, + }, + InstructionAddressMap { + srcloc: SourceLoc::new(code_section_offset + 17), + code_offset: 15, + code_len: 8, + }, + ], + start_srcloc: SourceLoc::new(code_section_offset + 10), + end_srcloc: SourceLoc::new(code_section_offset + 20), + body_offset: 0, + body_len: 30, + }, + ..Default::default() }); let fi = WasmFileInfo { code_section_offset: code_section_offset.into(), diff --git a/crates/debug/src/transform/mod.rs b/crates/debug/src/transform/mod.rs index c2dbead619..2f759ecc34 100644 --- a/crates/debug/src/transform/mod.rs +++ b/crates/debug/src/transform/mod.rs @@ -10,8 +10,7 @@ use gimli::{ use std::collections::HashSet; use thiserror::Error; use wasmtime_environ::isa::TargetIsa; -use wasmtime_environ::DebugInfoData; -use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges}; +use wasmtime_environ::{CompiledFunctions, DebugInfoData, ModuleMemoryOffset}; pub use address_transform::AddressTransform; @@ -50,11 +49,10 @@ where pub fn transform_dwarf( isa: &dyn TargetIsa, di: &DebugInfoData, - at: &ModuleAddressMap, - vmctx_info: &ModuleVmctxInfo, - ranges: &ValueLabelsRanges, + funcs: &CompiledFunctions, + memory_offset: &ModuleMemoryOffset, ) -> Result { - let addr_tr = AddressTransform::new(at, &di.wasm_file); + let addr_tr = AddressTransform::new(funcs, &di.wasm_file); let reachable = build_dependencies(&di.dwarf, &addr_tr)?.get_reachable(); let context = DebugInputContext { @@ -90,9 +88,9 @@ pub fn transform_dwarf( unit, &context, &addr_tr, - &ranges, + funcs, + memory_offset, out_encoding, - &vmctx_info, &mut out_units, &mut out_strings, &mut translated, @@ -107,8 +105,8 @@ pub fn transform_dwarf( generate_simulated_dwarf( &addr_tr, di, - &vmctx_info, - &ranges, + memory_offset, + funcs, &translated, out_encoding, &mut out_units, diff --git a/crates/debug/src/transform/simulate.rs b/crates/debug/src/transform/simulate.rs index a4a1b2f9e2..0e86087a6e 100644 --- a/crates/debug/src/transform/simulate.rs +++ b/crates/debug/src/transform/simulate.rs @@ -11,9 +11,9 @@ use wasmparser::Type as WasmType; use wasmtime_environ::entity::EntityRef; use wasmtime_environ::isa::TargetIsa; use wasmtime_environ::wasm::{get_vmctx_value_label, DefinedFuncIndex}; -use wasmtime_environ::WasmFileInfo; -use wasmtime_environ::{DebugInfoData, FunctionMetadata}; -use wasmtime_environ::{ModuleVmctxInfo, ValueLabelsRanges}; +use wasmtime_environ::{ + CompiledFunctions, DebugInfoData, FunctionMetadata, ModuleMemoryOffset, WasmFileInfo, +}; const PRODUCER_NAME: &str = "wasmtime"; @@ -120,9 +120,9 @@ fn add_wasm_types( unit: &mut write::Unit, root_id: write::UnitEntryId, out_strings: &mut write::StringTable, - vmctx_info: &ModuleVmctxInfo, + memory_offset: &ModuleMemoryOffset, ) -> WasmTypesDieRefs { - let (_wp_die_id, vmctx_die_id) = add_internal_types(unit, root_id, out_strings, vmctx_info); + let (_wp_die_id, vmctx_die_id) = add_internal_types(unit, root_id, out_strings, memory_offset); macro_rules! def_type { ($id:literal, $size:literal, $enc:path) => {{ @@ -280,8 +280,8 @@ fn check_invalid_chars_in_path(path: PathBuf) -> Option { pub fn generate_simulated_dwarf( addr_tr: &AddressTransform, di: &DebugInfoData, - vmctx_info: &ModuleVmctxInfo, - ranges: &ValueLabelsRanges, + memory_offset: &ModuleMemoryOffset, + funcs: &CompiledFunctions, translated: &HashSet, out_encoding: gimli::Encoding, out_units: &mut write::UnitTable, @@ -342,7 +342,7 @@ pub fn generate_simulated_dwarf( (unit, root_id, name_id) }; - let wasm_types = add_wasm_types(unit, root_id, out_strings, vmctx_info); + let wasm_types = add_wasm_types(unit, root_id, out_strings, memory_offset); for (i, map) in addr_tr.map().iter() { let index = i.index(); @@ -389,7 +389,7 @@ pub fn generate_simulated_dwarf( write::AttributeValue::Udata(wasm_offset), ); - if let Some(frame_info) = get_function_frame_info(vmctx_info, i, ranges) { + if let Some(frame_info) = get_function_frame_info(memory_offset, funcs, i) { let source_range = addr_tr.func_source_range(i); generate_vars( unit, diff --git a/crates/debug/src/transform/unit.rs b/crates/debug/src/transform/unit.rs index d8711b5f1e..15f165418a 100644 --- a/crates/debug/src/transform/unit.rs +++ b/crates/debug/src/transform/unit.rs @@ -12,7 +12,7 @@ use gimli::{AttributeValue, DebuggingInformationEntry, Unit}; use std::collections::HashSet; use wasmtime_environ::isa::TargetIsa; use wasmtime_environ::wasm::DefinedFuncIndex; -use wasmtime_environ::{ModuleVmctxInfo, ValueLabelsRanges}; +use wasmtime_environ::{CompiledFunctions, ModuleMemoryOffset}; struct InheritedAttr { stack: Vec<(usize, T)>, @@ -246,9 +246,9 @@ pub(crate) fn clone_unit<'a, R>( unit: Unit, context: &DebugInputContext, addr_tr: &'a AddressTransform, - value_ranges: &'a ValueLabelsRanges, + funcs: &'a CompiledFunctions, + memory_offset: &ModuleMemoryOffset, out_encoding: gimli::Encoding, - module_info: &ModuleVmctxInfo, out_units: &mut write::UnitTable, out_strings: &mut write::StringTable, translated: &mut HashSet, @@ -319,7 +319,7 @@ where )?; let (wp_die_id, vmctx_die_id) = - add_internal_types(comp_unit, root_id, out_strings, module_info); + add_internal_types(comp_unit, root_id, out_strings, memory_offset); stack.push(root_id); ( @@ -371,8 +371,7 @@ where let range_builder = RangeInfoBuilder::from_subprogram_die(&unit, entry, context, addr_tr, cu_low_pc)?; if let RangeInfoBuilder::Function(func_index) = range_builder { - if let Some(frame_info) = - get_function_frame_info(module_info, func_index, value_ranges) + if let Some(frame_info) = get_function_frame_info(memory_offset, funcs, func_index) { current_value_range.push(new_stack_len, frame_info); } diff --git a/crates/debug/src/transform/utils.rs b/crates/debug/src/transform/utils.rs index d8ad914290..0ebcba15b6 100644 --- a/crates/debug/src/transform/utils.rs +++ b/crates/debug/src/transform/utils.rs @@ -4,7 +4,7 @@ use anyhow::Error; use gimli::write; use wasmtime_environ::isa::TargetIsa; use wasmtime_environ::wasm::DefinedFuncIndex; -use wasmtime_environ::{ModuleMemoryOffset, ModuleVmctxInfo, ValueLabelsRanges}; +use wasmtime_environ::{CompiledFunctions, ModuleMemoryOffset}; /// Adds internal Wasm utility types DIEs such as WebAssemblyPtr and /// WasmtimeVMContext. @@ -17,7 +17,7 @@ pub(crate) fn add_internal_types( comp_unit: &mut write::Unit, root_id: write::UnitEntryId, out_strings: &mut write::StringTable, - module_info: &ModuleVmctxInfo, + memory_offset: &ModuleMemoryOffset, ) -> (write::UnitEntryId, write::UnitEntryId) { const WASM_PTR_LEN: u8 = 4; @@ -70,7 +70,7 @@ pub(crate) fn add_internal_types( ); // TODO multiple memories - match module_info.memory_offset { + match *memory_offset { ModuleMemoryOffset::Defined(memory_offset) => { // The context has defined memory: extend the WasmtimeVMContext size // past the "memory" field. @@ -165,19 +165,19 @@ pub(crate) fn append_vmctx_info( } pub(crate) fn get_function_frame_info<'a, 'b, 'c>( - module_info: &'b ModuleVmctxInfo, + memory_offset: &ModuleMemoryOffset, + funcs: &'b CompiledFunctions, func_index: DefinedFuncIndex, - value_ranges: &'c ValueLabelsRanges, ) -> Option> where 'b: 'a, 'c: 'a, { - if let Some(value_ranges) = value_ranges.get(func_index) { + if let Some(func) = funcs.get(func_index) { let frame_info = FunctionFrameInfo { - value_ranges, - memory_offset: module_info.memory_offset.clone(), - stack_slots: &module_info.stack_slots[func_index], + value_ranges: &func.value_labels_ranges, + memory_offset: memory_offset.clone(), + stack_slots: &func.stack_slots, }; Some(frame_info) } else { diff --git a/crates/debug/src/write_debuginfo.rs b/crates/debug/src/write_debuginfo.rs index 3292be373a..56c7231db0 100644 --- a/crates/debug/src/write_debuginfo.rs +++ b/crates/debug/src/write_debuginfo.rs @@ -1,11 +1,9 @@ pub use crate::transform::transform_dwarf; use gimli::write::{Address, Dwarf, EndianVec, FrameTable, Result, Sections, Writer}; use gimli::{RunTimeEndian, SectionId}; -use wasmtime_environ::entity::{EntityRef, PrimaryMap}; +use wasmtime_environ::entity::EntityRef; use wasmtime_environ::isa::{unwind::UnwindInfo, TargetIsa}; -use wasmtime_environ::wasm::DefinedFuncIndex; -use wasmtime_environ::DebugInfoData; -use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges}; +use wasmtime_environ::{CompiledFunctions, DebugInfoData, ModuleMemoryOffset}; #[derive(Clone)] pub enum DwarfSectionRelocTarget { @@ -130,16 +128,13 @@ impl Writer for WriterRelocate { } } -fn create_frame_table<'a>( - isa: &dyn TargetIsa, - infos: &PrimaryMap>, -) -> Option { +fn create_frame_table<'a>(isa: &dyn TargetIsa, funcs: &CompiledFunctions) -> Option { let mut table = FrameTable::default(); let cie_id = table.add_cie(isa.create_systemv_cie()?); - for (i, info) in infos { - if let Some(UnwindInfo::SystemV(info)) = info { + for (i, f) in funcs { + if let Some(UnwindInfo::SystemV(info)) = &f.unwind_info { table.add_fde( cie_id, info.to_fde(Address::Symbol { @@ -156,13 +151,11 @@ fn create_frame_table<'a>( pub fn emit_dwarf<'a>( isa: &dyn TargetIsa, debuginfo_data: &DebugInfoData, - at: &ModuleAddressMap, - vmctx_info: &ModuleVmctxInfo, - ranges: &ValueLabelsRanges, - unwind_info: &PrimaryMap>, + funcs: &CompiledFunctions, + memory_offset: &ModuleMemoryOffset, ) -> anyhow::Result> { - let dwarf = transform_dwarf(isa, debuginfo_data, at, vmctx_info, ranges)?; - let frame_table = create_frame_table(isa, unwind_info); + let dwarf = transform_dwarf(isa, debuginfo_data, funcs, memory_offset)?; + let frame_table = create_frame_table(isa, funcs); let sections = emit_dwarf_sections(dwarf, frame_table)?; Ok(sections) } diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml index 3be89c91f5..19b8f08d02 100644 --- a/crates/environ/Cargo.toml +++ b/crates/environ/Cargo.toml @@ -20,7 +20,6 @@ cranelift-wasm = { path = "../../cranelift/wasm", version = "0.66.0", features = wasmparser = "0.59.0" lightbeam = { path = "../lightbeam", optional = true, version = "0.19.0" } indexmap = { version = "1.0.2", features = ["serde-1"] } -rayon = { version = "1.2.1", optional = true } thiserror = "1.0.4" directories = "2.0.1" sha2 = "0.8.0" @@ -48,8 +47,5 @@ pretty_env_logger = "0.4.0" filetime = "0.2.7" lazy_static = "1.3.0" -[features] -parallel-compilation = ["rayon"] - [badges] maintenance = { status = "actively-developed" } diff --git a/crates/environ/src/address_map.rs b/crates/environ/src/address_map.rs index 461f550eb2..4a2f80c90f 100644 --- a/crates/environ/src/address_map.rs +++ b/crates/environ/src/address_map.rs @@ -2,8 +2,6 @@ // addresses of a WebAssembly module into the native code. use cranelift_codegen::ir; -use cranelift_entity::PrimaryMap; -use cranelift_wasm::DefinedFuncIndex; use serde::{Deserialize, Serialize}; /// Single source location to generated address mapping. @@ -20,7 +18,7 @@ pub struct InstructionAddressMap { } /// Function and its instructions addresses mappings. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)] pub struct FunctionAddressMap { /// Instructions maps. /// The array is sorted by the InstructionAddressMap::code_offset field. @@ -39,15 +37,6 @@ pub struct FunctionAddressMap { pub body_len: usize, } -/// Module functions addresses mappings. -pub type ModuleAddressMap = PrimaryMap; - -/// Value ranges for functions. -pub type ValueLabelsRanges = PrimaryMap; - -/// Stack slots for functions. -pub type StackSlots = PrimaryMap; - /// Memory definition offset in the VMContext structure. #[derive(Debug, Clone)] pub enum ModuleMemoryOffset { @@ -58,13 +47,3 @@ pub enum ModuleMemoryOffset { /// Offset to the imported memory. Imported(u32), } - -/// Module `vmctx` related info. -#[derive(Debug, Clone)] -pub struct ModuleVmctxInfo { - /// The memory definition offset in the VMContext structure. - pub memory_offset: ModuleMemoryOffset, - - /// The functions stack slots. - pub stack_slots: StackSlots, -} diff --git a/crates/environ/src/compilation.rs b/crates/environ/src/compilation.rs index 11d987a576..c0b814000f 100644 --- a/crates/environ/src/compilation.rs +++ b/crates/environ/src/compilation.rs @@ -1,19 +1,21 @@ //! A `Compilation` contains the compiled function bodies for a WebAssembly //! module. -use crate::address_map::{ModuleAddressMap, ValueLabelsRanges}; -use crate::ModuleTranslation; +use crate::{FunctionAddressMap, FunctionBodyData, ModuleTranslation}; use cranelift_codegen::{binemit, ir, isa, isa::unwind::UnwindInfo}; use cranelift_entity::PrimaryMap; use cranelift_wasm::{DefinedFuncIndex, FuncIndex, WasmError}; use serde::{Deserialize, Serialize}; -use std::ops::Range; use thiserror::Error; +#[allow(missing_docs)] +pub type CompiledFunctions = PrimaryMap; + /// Compiled function: machine code body, jump table offsets, and unwind information. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)] +#[allow(missing_docs)] pub struct CompiledFunction { - /// The function body. + /// The machine code for this function. pub body: Vec, /// The jump tables offsets (in the body). @@ -21,93 +23,13 @@ pub struct CompiledFunction { /// The unwind information. pub unwind_info: Option, -} -type Functions = PrimaryMap; - -/// The result of compiling a WebAssembly module's functions. -#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)] -pub struct Compilation { - /// Compiled machine code for the function bodies. - functions: Functions, -} - -impl Compilation { - /// Creates a compilation artifact from a contiguous function buffer and a set of ranges - pub fn new(functions: Functions) -> Self { - Self { functions } - } - - /// Allocates the compilation result with the given function bodies. - pub fn from_buffer( - buffer: Vec, - functions: impl IntoIterator, ir::JumpTableOffsets)>, - ) -> Self { - Self::new( - functions - .into_iter() - .map(|(body_range, jt_offsets)| CompiledFunction { - body: buffer[body_range].to_vec(), - jt_offsets, - unwind_info: None, // not implemented for lightbeam currently - }) - .collect(), - ) - } - - /// Gets the bytes of a single function - pub fn get(&self, func: DefinedFuncIndex) -> &CompiledFunction { - &self.functions[func] - } - - /// Gets the number of functions defined. - pub fn len(&self) -> usize { - self.functions.len() - } - - /// Returns whether there are no functions defined. - pub fn is_empty(&self) -> bool { - self.functions.is_empty() - } - - /// Returns unwind info for all defined functions. - pub fn unwind_info(&self) -> PrimaryMap> { - self.functions - .iter() - .map(|(_, func)| &func.unwind_info) - .collect::>() - } - - /// Gets functions jump table offsets. - pub fn get_jt_offsets(&self) -> PrimaryMap { - self.functions - .iter() - .map(|(_, func)| func.jt_offsets.clone()) - .collect::>() - } -} - -impl<'a> IntoIterator for &'a Compilation { - type IntoIter = Iter<'a>; - type Item = ::Item; - - fn into_iter(self) -> Self::IntoIter { - Iter { - iterator: self.functions.iter(), - } - } -} - -pub struct Iter<'a> { - iterator: <&'a Functions as IntoIterator>::IntoIter, -} - -impl<'a> Iterator for Iter<'a> { - type Item = &'a CompiledFunction; - - fn next(&mut self) -> Option { - self.iterator.next().map(|(_, b)| b) - } + pub relocations: Vec, + pub address_map: FunctionAddressMap, + pub value_labels_ranges: cranelift_codegen::ValueLabelsRanges, + pub stack_slots: ir::StackSlots, + pub traps: Vec, + pub stack_maps: Vec, } /// A record of a relocation to perform. @@ -134,9 +56,6 @@ pub enum RelocationTarget { JumpTable(FuncIndex, ir::JumpTable), } -/// Relocations to apply to function bodies. -pub type Relocations = PrimaryMap>; - /// Information about trap. #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub struct TrapInformation { @@ -148,9 +67,6 @@ pub struct TrapInformation { pub trap_code: ir::TrapCode, } -/// Information about traps associated with the functions where the traps are placed. -pub type Traps = PrimaryMap>; - /// The offset within a function of a GC safepoint, and its associated stack /// map. #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] @@ -163,10 +79,6 @@ pub struct StackMapInformation { pub stack_map: binemit::Stackmap, } -/// Information about GC safepoints and their associated stack maps within each -/// function. -pub type StackMaps = PrimaryMap>; - /// An error while compiling WebAssembly to machine code. #[derive(Error, Debug)] pub enum CompileError { @@ -183,22 +95,15 @@ pub enum CompileError { DebugInfoNotSupported, } -/// A type alias for the result of `Compiler::compile_module` -pub type CompileResult = ( - Compilation, - Relocations, - ModuleAddressMap, - ValueLabelsRanges, - PrimaryMap, - Traps, - StackMaps, -); - -/// An implementation of a compiler from parsed WebAssembly module to native code. -pub trait Compiler { - /// Compile a parsed module with the given `TargetIsa`. - fn compile_module( - translation: &ModuleTranslation, +/// An implementation of a compiler from parsed WebAssembly module to native +/// code. +pub trait Compiler: Send + Sync { + /// Compile a function with the given `TargetIsa`. + fn compile_function( + &self, + translation: &ModuleTranslation<'_>, + index: DefinedFuncIndex, + data: &FunctionBodyData<'_>, isa: &dyn isa::TargetIsa, - ) -> Result; + ) -> Result; } diff --git a/crates/environ/src/cranelift.rs b/crates/environ/src/cranelift.rs index 99ea83f075..6dbb1ec1fc 100644 --- a/crates/environ/src/cranelift.rs +++ b/crates/environ/src/cranelift.rs @@ -85,23 +85,21 @@ // also need to actually catch stack overflow, so for now 32k is chosen and it's // assume no valid stack pointer will ever be `usize::max_value() - 32k`. -use crate::address_map::{FunctionAddressMap, InstructionAddressMap}; -use crate::compilation::{ - Compilation, CompileError, CompiledFunction, Relocation, RelocationTarget, StackMapInformation, +use crate::func_environ::{get_func_name, FuncEnvironment}; +use crate::Compiler; +use crate::{ + CompileError, CompiledFunction, Relocation, RelocationTarget, StackMapInformation, TrapInformation, }; -use crate::compilation::{CompileResult, Compiler}; -use crate::func_environ::{get_func_name, FuncEnvironment}; -use crate::{FunctionBodyData, ModuleLocal, ModuleTranslation, Tunables}; +use crate::{FunctionAddressMap, InstructionAddressMap}; +use crate::{FunctionBodyData, ModuleTranslation}; use cranelift_codegen::ir::{self, ExternalName}; use cranelift_codegen::machinst::buffer::MachSrcLoc; use cranelift_codegen::print_errors::pretty_error; use cranelift_codegen::{binemit, isa, Context}; -use cranelift_entity::PrimaryMap; -use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator, ModuleTranslationState}; -#[cfg(feature = "parallel-compilation")] -use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; +use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator}; use std::convert::TryFrom; +use std::sync::Mutex; /// Implementation of a relocation sink that just saves all the information for later pub struct RelocSink { @@ -280,45 +278,33 @@ fn get_function_address_map<'data>( /// A compiler that compiles a WebAssembly module with Cranelift, translating the Wasm to Cranelift IR, /// optimizing it and then translating to assembly. -pub struct Cranelift; +#[derive(Default)] +pub struct Cranelift { + translators: Mutex>, +} -impl Compiler for Cranelift { - /// Compile the module using Cranelift, producing a compilation result with - /// associated relocations. - fn compile_module( - translation: &ModuleTranslation, - isa: &dyn isa::TargetIsa, - ) -> Result { - compile( - isa, - &translation.module.local, - translation.module_translation.as_ref().unwrap(), - &translation.function_body_inputs, - &translation.tunables, - ) +impl Cranelift { + fn take_translator(&self) -> FuncTranslator { + let candidate = self.translators.lock().unwrap().pop(); + candidate.unwrap_or_else(FuncTranslator::new) + } + + fn save_translator(&self, translator: FuncTranslator) { + self.translators.lock().unwrap().push(translator); } } -fn compile( - isa: &dyn isa::TargetIsa, - local: &ModuleLocal, - module_translation: &ModuleTranslationState, - function_body_inputs: &PrimaryMap>, - tunables: &Tunables, -) -> Result { - let mut functions = PrimaryMap::with_capacity(function_body_inputs.len()); - let mut relocations = PrimaryMap::with_capacity(function_body_inputs.len()); - let mut address_transforms = PrimaryMap::with_capacity(function_body_inputs.len()); - let mut value_ranges = PrimaryMap::with_capacity(function_body_inputs.len()); - let mut stack_slots = PrimaryMap::with_capacity(function_body_inputs.len()); - let mut traps = PrimaryMap::with_capacity(function_body_inputs.len()); - let mut stack_maps = PrimaryMap::with_capacity(function_body_inputs.len()); - - type FunctionBodyInput<'a> = (DefinedFuncIndex, &'a FunctionBodyData<'a>); - - let compile_function = |func_translator: &mut FuncTranslator, - (i, input): &FunctionBodyInput| { - let func_index = local.func_index(*i); +impl Compiler for Cranelift { + fn compile_function( + &self, + translation: &ModuleTranslation<'_>, + func_index: DefinedFuncIndex, + input: &FunctionBodyData<'_>, + isa: &dyn isa::TargetIsa, + ) -> Result { + let local = &translation.module.local; + let tunables = &translation.tunables; + let func_index = local.func_index(func_index); let mut context = Context::new(); context.func.name = get_func_name(func_index); context.func.signature = local.native_func_signature(func_index).clone(); @@ -361,13 +347,16 @@ fn compile( readonly: false, }); context.func.stack_limit = Some(stack_limit); - func_translator.translate( - module_translation, + let mut func_translator = self.take_translator(); + let result = func_translator.translate( + translation.module_translation.as_ref().unwrap(), input.data, input.module_offset, &mut context.func, &mut func_env, - )?; + ); + self.save_translator(func_translator); + result?; let mut code_buf: Vec = Vec::new(); let mut reloc_sink = RelocSink::new(func_index); @@ -400,73 +389,16 @@ fn compile( None }; - Ok(( - code_buf, - context.func.jt_offsets, - reloc_sink.func_relocs, - address_transform, - ranges, - context.func.stack_slots, - trap_sink.traps, + Ok(CompiledFunction { + body: code_buf, + jt_offsets: context.func.jt_offsets, + relocations: reloc_sink.func_relocs, + address_map: address_transform, + value_labels_ranges: ranges.unwrap_or(Default::default()), + stack_slots: context.func.stack_slots, + traps: trap_sink.traps, unwind_info, - stack_map_sink.finish(), - )) - }; - - let inputs: Vec = function_body_inputs.into_iter().collect(); - - let results: Result, CompileError> = { - cfg_if::cfg_if! { - if #[cfg(feature = "parallel-compilation")] { - inputs - .par_iter() - .map_init(FuncTranslator::new, compile_function) - .collect() - } else { - let mut func_translator = FuncTranslator::new(); - inputs - .iter() - .map(|input| compile_function(&mut func_translator, input)) - .collect() - } - } - }; - - results?.into_iter().for_each( - |( - function, - func_jt_offsets, - relocs, - address_transform, - ranges, - sss, - function_traps, - unwind_info, - stack_map, - )| { - functions.push(CompiledFunction { - body: function, - jt_offsets: func_jt_offsets, - unwind_info, - }); - relocations.push(relocs); - address_transforms.push(address_transform); - value_ranges.push(ranges.unwrap_or_default()); - stack_slots.push(sss); - traps.push(function_traps); - stack_maps.push(stack_map); - }, - ); - - // TODO: Reorganize where we create the Vec for the resolved imports. - - Ok(( - Compilation::new(functions), - relocations, - address_transforms, - value_ranges, - stack_slots, - traps, - stack_maps, - )) + stack_maps: stack_map_sink.finish(), + }) + } } diff --git a/crates/environ/src/lib.rs b/crates/environ/src/lib.rs index 62c3dae93b..a8d3926d27 100644 --- a/crates/environ/src/lib.rs +++ b/crates/environ/src/lib.rs @@ -39,16 +39,10 @@ pub mod cranelift; #[cfg(feature = "lightbeam")] pub mod lightbeam; -pub use crate::address_map::{ - FunctionAddressMap, InstructionAddressMap, ModuleAddressMap, ModuleMemoryOffset, - ModuleVmctxInfo, ValueLabelsRanges, -}; +pub use crate::address_map::*; pub use crate::cache::create_new_config as cache_create_new_config; pub use crate::cache::{CacheConfig, ModuleCacheEntry}; -pub use crate::compilation::{ - Compilation, CompileError, CompiledFunction, Compiler, Relocation, RelocationTarget, - Relocations, StackMapInformation, StackMaps, TrapInformation, Traps, -}; +pub use crate::compilation::*; pub use crate::cranelift::Cranelift; pub use crate::data_structures::*; pub use crate::func_environ::BuiltinFunctionIndex; diff --git a/crates/environ/src/lightbeam.rs b/crates/environ/src/lightbeam.rs index 057e10b41f..cea6e3cb1d 100644 --- a/crates/environ/src/lightbeam.rs +++ b/crates/environ/src/lightbeam.rs @@ -1,86 +1,71 @@ //! Support for compiling with Lightbeam. -use crate::compilation::{Compilation, CompileError, CompileResult, Compiler}; -use crate::func_environ::FuncEnvironment; -use crate::CacheConfig; -use crate::ModuleTranslation; -// TODO: Put this in `compilation` -use crate::address_map::{ModuleAddressMap, ValueLabelsRanges}; +use crate::compilation::{CompileError, CompiledFunction, Compiler}; use crate::cranelift::{RelocSink, TrapSink}; +use crate::func_environ::FuncEnvironment; +use crate::{FunctionBodyData, ModuleTranslation}; use cranelift_codegen::isa; -use cranelift_entity::{PrimaryMap, SecondaryMap}; +use cranelift_wasm::DefinedFuncIndex; use lightbeam::{CodeGenSession, NullOffsetSink, Sinks}; /// A compiler that compiles a WebAssembly module with Lightbeam, directly translating the Wasm file. pub struct Lightbeam; impl Compiler for Lightbeam { - /// Compile the module using Lightbeam, producing a compilation result with - /// associated relocations. - fn compile_module( + fn compile_function( + &self, translation: &ModuleTranslation, + i: DefinedFuncIndex, + function_body: &FunctionBodyData<'_>, isa: &dyn isa::TargetIsa, - ) -> Result { + ) -> Result { if translation.tunables.debug_info { return Err(CompileError::DebugInfoNotSupported); } + let func_index = translation.module.local.func_index(i); let env = FuncEnvironment::new( isa.frontend_config(), &translation.module.local, &translation.tunables, ); - let mut relocations = PrimaryMap::with_capacity(translation.function_body_inputs.len()); - let mut traps = PrimaryMap::with_capacity(translation.function_body_inputs.len()); - let stack_maps = PrimaryMap::with_capacity(translation.function_body_inputs.len()); - let mut codegen_session: CodeGenSession<_> = CodeGenSession::new( translation.function_body_inputs.len() as u32, &env, lightbeam::microwasm::I32, ); - for (i, function_body) in &translation.function_body_inputs { - let func_index = translation.module.local.func_index(i); - - let mut reloc_sink = RelocSink::new(func_index); - let mut trap_sink = TrapSink::new(); - lightbeam::translate_function( - &mut codegen_session, - Sinks { - relocs: &mut reloc_sink, - traps: &mut trap_sink, - offsets: &mut NullOffsetSink, - }, - i.as_u32(), - wasmparser::FunctionBody::new(0, function_body.data), - ) - .map_err(|e| CompileError::Codegen(format!("Failed to translate function: {}", e)))?; - - relocations.push(reloc_sink.func_relocs); - traps.push(trap_sink.traps); - } + let mut reloc_sink = RelocSink::new(func_index); + let mut trap_sink = TrapSink::new(); + lightbeam::translate_function( + &mut codegen_session, + Sinks { + relocs: &mut reloc_sink, + traps: &mut trap_sink, + offsets: &mut NullOffsetSink, + }, + i.as_u32(), + wasmparser::FunctionBody::new(0, function_body.data), + ) + .map_err(|e| CompileError::Codegen(format!("Failed to translate function: {}", e)))?; let code_section = codegen_session .into_translated_code_section() .map_err(|e| CompileError::Codegen(format!("Failed to generate output code: {}", e)))?; - // TODO pass jump table offsets to Compilation::from_buffer() when they - // are implemented in lightbeam -- using empty set of offsets for now. - // TODO: pass an empty range for the unwind information until lightbeam emits it - let code_section_ranges_and_jt = code_section - .funcs() - .into_iter() - .map(|r| (r, SecondaryMap::new())); + Ok(CompiledFunction { + // TODO: try to remove copy here (?) + body: code_section.buffer().to_vec(), + traps: trap_sink.traps, + relocations: reloc_sink.func_relocs, - Ok(( - Compilation::from_buffer(code_section.buffer().to_vec(), code_section_ranges_and_jt), - relocations, - ModuleAddressMap::new(), - ValueLabelsRanges::new(), - PrimaryMap::new(), - traps, - stack_maps, - )) + // not implemented for lightbeam currently + unwind_info: None, + stack_maps: Default::default(), + stack_slots: Default::default(), + value_labels_ranges: Default::default(), + address_map: Default::default(), + jt_offsets: Default::default(), + }) } } diff --git a/crates/jit/Cargo.toml b/crates/jit/Cargo.toml index 3ba139d6b1..8d9fdc0cd3 100644 --- a/crates/jit/Cargo.toml +++ b/crates/jit/Cargo.toml @@ -22,6 +22,7 @@ wasmtime-runtime = { path = "../runtime", version = "0.19.0" } wasmtime-debug = { path = "../debug", version = "0.19.0" } wasmtime-profiling = { path = "../profiling", version = "0.19.0" } wasmtime-obj = { path = "../obj", version = "0.19.0" } +rayon = { version = "1.0", optional = true } region = "2.1.0" thiserror = "1.0.4" target-lexicon = { version = "0.10.0", default-features = false } @@ -41,6 +42,7 @@ winapi = { version = "0.3.8", features = ["winnt", "impl-default"] } lightbeam = ["wasmtime-environ/lightbeam"] jitdump = ["wasmtime-profiling/jitdump"] vtune = ["wasmtime-profiling/vtune"] +parallel-compilation = ["rayon"] # Try the experimental, work-in-progress new x86_64 backend. This is not stable # as of June 2020. diff --git a/crates/jit/src/code_memory.rs b/crates/jit/src/code_memory.rs index 854564e5c7..a540e3b318 100644 --- a/crates/jit/src/code_memory.rs +++ b/crates/jit/src/code_memory.rs @@ -13,7 +13,7 @@ use std::{cmp, mem}; use wasmtime_environ::{ isa::{unwind::UnwindInfo, TargetIsa}, wasm::{FuncIndex, SignatureIndex}, - Compilation, CompiledFunction, + CompiledFunction, }; use wasmtime_runtime::{Mmap, VMFunctionBody}; @@ -119,31 +119,6 @@ impl CodeMemory { Ok(vmfunc) } - /// Allocate a continuous memory block for a compilation. - pub fn allocate_for_compilation( - &mut self, - compilation: &Compilation, - ) -> Result, String> { - let total_len = compilation - .into_iter() - .fold(0, |acc, func| acc + Self::function_allocation_size(func)); - - let (mut buf, registry, start) = self.allocate(total_len)?; - let mut result = Vec::with_capacity(compilation.len()); - let mut start = start as u32; - - for func in compilation.into_iter() { - let (next_start, next_buf, vmfunc) = Self::copy_function(func, start, buf, registry); - - result.push(vmfunc); - - start = next_start; - buf = next_buf; - } - - Ok(result.into_boxed_slice()) - } - /// Make all allocated memory executable. pub fn publish(&mut self, isa: &dyn TargetIsa) { self.push_current(0) diff --git a/crates/jit/src/compiler.rs b/crates/jit/src/compiler.rs index fa3bbe956b..052af5262e 100644 --- a/crates/jit/src/compiler.rs +++ b/crates/jit/src/compiler.rs @@ -2,16 +2,15 @@ use crate::instantiate::SetupError; use crate::object::{build_object, ObjectUnwindInfo}; -use cranelift_codegen::ir; use object::write::Object; use std::hash::{Hash, Hasher}; use wasmtime_debug::{emit_dwarf, DwarfSection}; -use wasmtime_environ::entity::{EntityRef, PrimaryMap}; -use wasmtime_environ::isa::{unwind::UnwindInfo, TargetFrontendConfig, TargetIsa}; -use wasmtime_environ::wasm::{DefinedFuncIndex, DefinedMemoryIndex, MemoryIndex}; +use wasmtime_environ::entity::EntityRef; +use wasmtime_environ::isa::{TargetFrontendConfig, TargetIsa}; +use wasmtime_environ::wasm::{DefinedMemoryIndex, MemoryIndex}; use wasmtime_environ::{ - Compiler as _C, DebugInfoData, Module, ModuleAddressMap, ModuleMemoryOffset, ModuleTranslation, - ModuleVmctxInfo, StackMaps, Traps, Tunables, VMOffsets, ValueLabelsRanges, + CompiledFunctions, Compiler as EnvCompiler, DebugInfoData, Module, ModuleMemoryOffset, + ModuleTranslation, Tunables, VMOffsets, }; /// Select which kind of compilation to use. @@ -38,6 +37,7 @@ pub enum CompilationStrategy { /// TODO: Consider using cranelift-module. pub struct Compiler { isa: Box, + compiler: Box, strategy: CompilationStrategy, tunables: Tunables, } @@ -48,6 +48,13 @@ impl Compiler { Self { isa, strategy, + compiler: match strategy { + CompilationStrategy::Auto | CompilationStrategy::Cranelift => { + Box::new(wasmtime_environ::cranelift::Cranelift::default()) + } + #[cfg(feature = "lightbeam")] + CompilationStrategy::Lightbeam => Box::new(wasmtime_environ::lightbeam::Lightbeam), + }, tunables, } } @@ -62,46 +69,26 @@ fn transform_dwarf_data( isa: &dyn TargetIsa, module: &Module, debug_data: &DebugInfoData, - address_transform: &ModuleAddressMap, - value_ranges: &ValueLabelsRanges, - stack_slots: PrimaryMap, - unwind_info: PrimaryMap>, + funcs: &CompiledFunctions, ) -> Result, SetupError> { let target_config = isa.frontend_config(); let ofs = VMOffsets::new(target_config.pointer_bytes(), &module.local); - let module_vmctx_info = { - ModuleVmctxInfo { - memory_offset: if ofs.num_imported_memories > 0 { - ModuleMemoryOffset::Imported(ofs.vmctx_vmmemory_import(MemoryIndex::new(0))) - } else if ofs.num_defined_memories > 0 { - ModuleMemoryOffset::Defined( - ofs.vmctx_vmmemory_definition_base(DefinedMemoryIndex::new(0)), - ) - } else { - ModuleMemoryOffset::None - }, - stack_slots, - } + let memory_offset = if ofs.num_imported_memories > 0 { + ModuleMemoryOffset::Imported(ofs.vmctx_vmmemory_import(MemoryIndex::new(0))) + } else if ofs.num_defined_memories > 0 { + ModuleMemoryOffset::Defined(ofs.vmctx_vmmemory_definition_base(DefinedMemoryIndex::new(0))) + } else { + ModuleMemoryOffset::None }; - emit_dwarf( - isa, - debug_data, - &address_transform, - &module_vmctx_info, - &value_ranges, - &unwind_info, - ) - .map_err(SetupError::DebugInfo) + emit_dwarf(isa, debug_data, funcs, &memory_offset).map_err(SetupError::DebugInfo) } #[allow(missing_docs)] pub struct Compilation { pub obj: Object, pub unwind_info: Vec, - pub traps: Traps, - pub stack_maps: StackMaps, - pub address_transform: ModuleAddressMap, + pub funcs: CompiledFunctions, } impl Compiler { @@ -120,66 +107,49 @@ impl Compiler { &self.tunables } - /// Return the compilation strategy. - pub fn strategy(&self) -> CompilationStrategy { - self.strategy - } - /// Compile the given function bodies. - pub(crate) fn compile<'data>( + pub fn compile<'data>( &self, translation: &ModuleTranslation, ) -> Result { - let ( - compilation, - relocations, - address_transform, - value_ranges, - stack_slots, - traps, - stack_maps, - ) = match self.strategy { - // For now, interpret `Auto` as `Cranelift` since that's the most stable - // implementation. - CompilationStrategy::Auto | CompilationStrategy::Cranelift => { - wasmtime_environ::cranelift::Cranelift::compile_module(translation, &*self.isa) - } - #[cfg(feature = "lightbeam")] - CompilationStrategy::Lightbeam => { - wasmtime_environ::lightbeam::Lightbeam::compile_module(translation, &*self.isa) + cfg_if::cfg_if! { + if #[cfg(feature = "parallel-compilation")] { + use rayon::prelude::*; + let iter = translation.function_body_inputs + .iter() + .collect::>() + .into_par_iter(); + } else { + let iter = translation.function_body_inputs.iter(); } } - .map_err(SetupError::Compile)?; + let funcs = iter + .map(|(index, func)| { + self.compiler + .compile_function(translation, index, func, &*self.isa) + }) + .collect::, _>>()? + .into_iter() + .collect::(); - let dwarf_sections = if translation.debuginfo.is_some() && !compilation.is_empty() { - let unwind_info = compilation.unwind_info(); + let dwarf_sections = if translation.debuginfo.is_some() && !funcs.is_empty() { transform_dwarf_data( &*self.isa, &translation.module, translation.debuginfo.as_ref().unwrap(), - &address_transform, - &value_ranges, - stack_slots, - unwind_info, + &funcs, )? } else { vec![] }; - let (obj, unwind_info) = build_object( - &*self.isa, - &translation.module, - compilation, - relocations, - dwarf_sections, - )?; + let (obj, unwind_info) = + build_object(&*self.isa, &translation.module, &funcs, dwarf_sections)?; Ok(Compilation { obj, unwind_info, - traps, - stack_maps, - address_transform, + funcs, }) } } @@ -188,6 +158,7 @@ impl Hash for Compiler { fn hash(&self, hasher: &mut H) { let Compiler { strategy, + compiler: _, isa, tunables, } = self; diff --git a/crates/jit/src/instantiate.rs b/crates/jit/src/instantiate.rs index 65931b364a..bbc202500b 100644 --- a/crates/jit/src/instantiate.rs +++ b/crates/jit/src/instantiate.rs @@ -20,8 +20,8 @@ use wasmtime_environ::entity::{BoxedSlice, PrimaryMap}; use wasmtime_environ::isa::TargetIsa; use wasmtime_environ::wasm::{DefinedFuncIndex, SignatureIndex}; use wasmtime_environ::{ - CompileError, DataInitializer, DataInitializerLocation, Module, ModuleAddressMap, - ModuleEnvironment, ModuleTranslation, StackMaps, Traps, + CompileError, DataInitializer, DataInitializerLocation, FunctionAddressMap, Module, + ModuleEnvironment, ModuleTranslation, StackMapInformation, TrapInformation, }; use wasmtime_profiling::ProfilingAgent; use wasmtime_runtime::VMInterrupts; @@ -67,19 +67,20 @@ pub struct CompilationArtifacts { /// Data initiailizers. data_initializers: Box<[OwnedDataInitializer]>, - /// Traps descriptors. - traps: Traps, - - /// Stack map descriptors. - stack_maps: StackMaps, - - /// Wasm to function code address map. - address_transform: ModuleAddressMap, + /// Descriptions of compiled functions + funcs: PrimaryMap, /// Debug info presence flags. debug_info: bool, } +#[derive(Serialize, Deserialize, Clone)] +struct FunctionInfo { + traps: Vec, + address_map: FunctionAddressMap, + stack_maps: Vec, +} + impl CompilationArtifacts { /// Builds compilation artifacts. pub fn build(compiler: &Compiler, data: &[u8]) -> Result { @@ -92,9 +93,7 @@ impl CompilationArtifacts { let Compilation { obj, unwind_info, - traps, - stack_maps, - address_transform, + funcs, } = compiler.compile(&translation)?; let ModuleTranslation { @@ -120,9 +119,14 @@ impl CompilationArtifacts { obj: obj.into_boxed_slice(), unwind_info: unwind_info.into_boxed_slice(), data_initializers, - traps, - stack_maps, - address_transform, + funcs: funcs + .into_iter() + .map(|(_, func)| FunctionInfo { + stack_maps: func.stack_maps, + traps: func.traps, + address_map: func.address_map, + }) + .collect(), debug_info: compiler.tunables().debug_info, }) } @@ -147,9 +151,7 @@ pub struct CompiledModule { finished_functions: FinishedFunctions, trampolines: PrimaryMap, data_initializers: Box<[OwnedDataInitializer]>, - traps: Traps, - stack_maps: StackMaps, - address_transform: ModuleAddressMap, + funcs: PrimaryMap, obj: Box<[u8]>, unwind_info: Box<[ObjectUnwindInfo]>, } @@ -176,9 +178,7 @@ impl CompiledModule { obj, unwind_info, data_initializers, - traps, - stack_maps, - address_transform, + funcs, debug_info, } = artifacts; @@ -216,9 +216,7 @@ impl CompiledModule { finished_functions, trampolines, data_initializers, - traps, - stack_maps, - address_transform, + funcs, obj, unwind_info, }) @@ -231,9 +229,7 @@ impl CompiledModule { obj: self.obj.clone(), unwind_info: self.unwind_info.clone(), data_initializers: self.data_initializers.clone(), - traps: self.traps.clone(), - stack_maps: self.stack_maps.clone(), - address_transform: self.address_transform.clone(), + funcs: self.funcs.clone(), debug_info: self.code.dbg_jit_registration.is_some(), } } @@ -318,19 +314,36 @@ impl CompiledModule { &self.finished_functions.0 } - /// Returns the map for all traps in this module. - pub fn traps(&self) -> &Traps { - &self.traps + /// Returns the stack map information for all functions defined in this + /// module. + /// + /// The iterator returned iterates over the span of the compiled function in + /// memory with the stack maps associated with those bytes. + pub fn stack_maps( + &self, + ) -> impl Iterator { + self.finished_functions() + .values() + .copied() + .zip(self.funcs.values().map(|f| f.stack_maps.as_slice())) } - /// Returns the map for each of this module's stack maps. - pub fn stack_maps(&self) -> &StackMaps { - &self.stack_maps - } - - /// Returns a map of compiled addresses back to original bytecode offsets. - pub fn address_transform(&self) -> &ModuleAddressMap { - &self.address_transform + /// Iterates over all functions in this module, returning information about + /// how to decode traps which happen in the function. + pub fn trap_information( + &self, + ) -> impl Iterator< + Item = ( + DefinedFuncIndex, + *mut [VMFunctionBody], + &[TrapInformation], + &FunctionAddressMap, + ), + > { + self.finished_functions() + .iter() + .zip(self.funcs.values()) + .map(|((i, alloc), func)| (i, *alloc, func.traps.as_slice(), &func.address_map)) } /// Returns all ranges convered by JIT code. diff --git a/crates/jit/src/object.rs b/crates/jit/src/object.rs index 66e3a35209..18891c7528 100644 --- a/crates/jit/src/object.rs +++ b/crates/jit/src/object.rs @@ -5,10 +5,10 @@ use cranelift_frontend::FunctionBuilderContext; use object::write::Object; use serde::{Deserialize, Serialize}; use wasmtime_debug::DwarfSection; -use wasmtime_environ::entity::{EntityRef, PrimaryMap}; +use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::isa::{unwind::UnwindInfo, TargetIsa}; use wasmtime_environ::wasm::{FuncIndex, SignatureIndex}; -use wasmtime_environ::{Compilation, Module, Relocations}; +use wasmtime_environ::{CompiledFunctions, Module}; use wasmtime_obj::{ObjectBuilder, ObjectBuilderTarget}; pub use wasmtime_obj::utils; @@ -24,8 +24,7 @@ pub enum ObjectUnwindInfo { pub(crate) fn build_object( isa: &dyn TargetIsa, module: &Module, - compilation: Compilation, - relocations: Relocations, + funcs: &CompiledFunctions, dwarf_sections: Vec, ) -> Result<(Object, Vec), anyhow::Error> { const CODE_SECTION_ALIGNMENT: u64 = 0x1000; @@ -37,38 +36,28 @@ pub(crate) fn build_object( let mut unwind_info = Vec::new(); // Preserve function unwind info. - unwind_info.extend( - compilation - .into_iter() - .enumerate() - .filter_map(|(index, func)| { - func.unwind_info.as_ref().map(|info| { - ObjectUnwindInfo::Func( - FuncIndex::new(module.local.num_imported_funcs + index), - info.clone(), - ) - }) - }), - ); + unwind_info.extend(funcs.iter().filter_map(|(index, func)| { + func.unwind_info + .as_ref() + .map(|info| ObjectUnwindInfo::Func(module.local.func_index(index), info.clone())) + })); let mut trampolines = PrimaryMap::with_capacity(module.local.signatures.len()); let mut cx = FunctionBuilderContext::new(); // Build trampolines for every signature. for (i, (_, native_sig)) in module.local.signatures.iter() { - let (func, relocs) = - build_trampoline(isa, &mut cx, native_sig, std::mem::size_of::())?; + let func = build_trampoline(isa, &mut cx, native_sig, std::mem::size_of::())?; // Preserve trampoline function unwind info. if let Some(info) = &func.unwind_info { unwind_info.push(ObjectUnwindInfo::Trampoline(i, info.clone())) } - trampolines.push((func, relocs)); + trampolines.push(func); } let target = ObjectBuilderTarget::new(isa.triple().architecture)?; - let mut builder = ObjectBuilder::new(target, module); + let mut builder = ObjectBuilder::new(target, module, funcs); builder .set_code_alignment(CODE_SECTION_ALIGNMENT) - .set_compilation(compilation, relocations) .set_trampolines(trampolines) .set_dwarf_sections(dwarf_sections); let obj = builder.build()?; diff --git a/crates/jit/src/trampoline.rs b/crates/jit/src/trampoline.rs index a5c97b9332..903118f7b7 100644 --- a/crates/jit/src/trampoline.rs +++ b/crates/jit/src/trampoline.rs @@ -33,9 +33,9 @@ pub fn make_trampoline( signature: &ir::Signature, value_size: usize, ) -> Result { - let (compiled_function, relocs) = build_trampoline(isa, fn_builder_ctx, signature, value_size)?; + let compiled_function = build_trampoline(isa, fn_builder_ctx, signature, value_size)?; - assert!(relocs.is_empty()); + assert!(compiled_function.relocations.is_empty()); let ptr = code_memory .allocate_for_function(&compiled_function) .map_err(|message| SetupError::Instantiate(InstantiationError::Resource(message)))? @@ -48,7 +48,7 @@ pub(crate) fn build_trampoline( fn_builder_ctx: &mut FunctionBuilderContext, signature: &ir::Signature, value_size: usize, -) -> Result<(CompiledFunction, Vec), SetupError> { +) -> Result { let pointer_type = isa.pointer_type(); let mut wrapper_sig = ir::Signature::new(isa.frontend_config().default_call_conv); @@ -155,14 +155,17 @@ pub(crate) fn build_trampoline( ))) })?; - Ok(( - CompiledFunction { - body: code_buf, - jt_offsets: context.func.jt_offsets, - unwind_info, - }, - reloc_sink.relocs, - )) + Ok(CompiledFunction { + body: code_buf, + jt_offsets: context.func.jt_offsets, + unwind_info, + relocations: reloc_sink.relocs, + stack_maps: Default::default(), + stack_slots: Default::default(), + traps: Default::default(), + value_labels_ranges: Default::default(), + address_map: Default::default(), + }) } /// We don't expect trampoline compilation to produce many relocations, so diff --git a/crates/obj/src/builder.rs b/crates/obj/src/builder.rs index bb8197efaf..5ad11fc36c 100644 --- a/crates/obj/src/builder.rs +++ b/crates/obj/src/builder.rs @@ -28,12 +28,10 @@ use std::collections::HashMap; use target_lexicon::Triple; use wasmtime_debug::{DwarfSection, DwarfSectionRelocTarget}; use wasmtime_environ::entity::{EntityRef, PrimaryMap}; -use wasmtime_environ::ir::{JumpTableOffsets, LibCall, Reloc}; +use wasmtime_environ::ir::{LibCall, Reloc}; use wasmtime_environ::isa::unwind::UnwindInfo; use wasmtime_environ::wasm::{DefinedFuncIndex, FuncIndex, SignatureIndex}; -use wasmtime_environ::{ - Compilation, CompiledFunction, Module, Relocation, RelocationTarget, Relocations, -}; +use wasmtime_environ::{CompiledFunction, CompiledFunctions, Module, Relocation, RelocationTarget}; fn to_object_relocations<'a>( it: impl Iterator + 'a, @@ -41,7 +39,7 @@ fn to_object_relocations<'a>( module: &'a Module, funcs: &'a PrimaryMap, libcalls: &'a HashMap, - jt_offsets: &'a PrimaryMap, + compiled_funcs: &'a CompiledFunctions, ) -> impl Iterator + 'a { it.filter_map(move |r| { let (symbol, symbol_offset) = match r.reloc_target { @@ -49,9 +47,9 @@ fn to_object_relocations<'a>( RelocationTarget::LibCall(call) => (libcalls[&call], 0), RelocationTarget::JumpTable(f, jt) => { let df = module.local.defined_func_index(f).unwrap(); - let offset = *jt_offsets + let offset = *compiled_funcs .get(df) - .and_then(|ofs| ofs.get(jt)) + .and_then(|f| f.jt_offsets.get(jt)) .expect("func jump table"); (funcs[f], offset) } @@ -258,20 +256,24 @@ pub struct ObjectBuilder<'a> { target: ObjectBuilderTarget, module: &'a Module, code_alignment: u64, - compilation: Option<(Compilation, Relocations)>, - trampolines: PrimaryMap)>, + compilation: &'a CompiledFunctions, + trampolines: PrimaryMap, dwarf_sections: Vec, } impl<'a> ObjectBuilder<'a> { - pub fn new(target: ObjectBuilderTarget, module: &'a Module) -> Self { + pub fn new( + target: ObjectBuilderTarget, + module: &'a Module, + compilation: &'a CompiledFunctions, + ) -> Self { Self { target, module, code_alignment: 1, - compilation: None, trampolines: PrimaryMap::new(), dwarf_sections: vec![], + compilation, } } @@ -280,18 +282,9 @@ impl<'a> ObjectBuilder<'a> { self } - pub fn set_compilation( - &mut self, - compilation: Compilation, - relocations: Relocations, - ) -> &mut Self { - self.compilation = Some((compilation, relocations)); - self - } - pub fn set_trampolines( &mut self, - trampolines: PrimaryMap)>, + trampolines: PrimaryMap, ) -> &mut Self { self.trampolines = trampolines; self @@ -319,17 +312,8 @@ impl<'a> ObjectBuilder<'a> { SectionKind::Text, ); - let (compilation, jt_offsets, relocations) = self.compilation.map_or_else( - || (None, PrimaryMap::new(), PrimaryMap::new()), - |(c, relocations)| { - let jt_offsets = c.get_jt_offsets(); - (Some(c), jt_offsets, relocations) - }, - ); - // Create symbols for imports -- needed during linking. - let mut func_symbols = - PrimaryMap::with_capacity(compilation.as_ref().map_or_else(|| 0, |c| c.len())); + let mut func_symbols = PrimaryMap::with_capacity(self.compilation.len()); for index in 0..module.local.num_imported_funcs { let symbol_id = obj.add_symbol(Symbol { name: utils::func_symbol_name(FuncIndex::new(index)) @@ -346,38 +330,10 @@ impl<'a> ObjectBuilder<'a> { func_symbols.push(symbol_id); } - if let Some(compilation) = compilation { - // Create symbols and section data for the compiled functions. - for (index, func) in compilation.into_iter().enumerate() { - let off = obj.append_section_data(section_id, &func.body, 1); - let symbol_id = obj.add_symbol(Symbol { - name: utils::func_symbol_name( - module.local.func_index(DefinedFuncIndex::new(index)), - ) - .as_bytes() - .to_vec(), - value: off, - size: func.body.len() as u64, - kind: SymbolKind::Text, - scope: SymbolScope::Compilation, - weak: false, - section: SymbolSection::Section(section_id), - flags: SymbolFlags::None, - }); - func_symbols.push(symbol_id); - // Preserve function unwind info. - if let Some(info) = &func.unwind_info { - process_unwind_info(info, &mut obj, section_id); - } - } - } - - // Create trampoline symbols for every signature. - let mut trampoline_relocs = HashMap::new(); - for (i, (func, relocs)) in self.trampolines.into_iter() { + let mut append_func = |name: Vec, func: &CompiledFunction| { let off = obj.append_section_data(section_id, &func.body, 1); let symbol_id = obj.add_symbol(Symbol { - name: utils::trampoline_symbol_name(i).as_bytes().to_vec(), + name, value: off, size: func.body.len() as u64, kind: SymbolKind::Text, @@ -386,11 +342,25 @@ impl<'a> ObjectBuilder<'a> { section: SymbolSection::Section(section_id), flags: SymbolFlags::None, }); - trampoline_relocs.insert(symbol_id, relocs); - // Preserve trampoline function unwind info. + // Preserve function unwind info. if let Some(info) = &func.unwind_info { process_unwind_info(info, &mut obj, section_id); } + symbol_id + }; + + // Create symbols and section data for the compiled functions. + for (index, func) in self.compilation.iter() { + let name = utils::func_symbol_name(module.local.func_index(index)) + .as_bytes() + .to_vec(); + let symbol_id = append_func(name, func); + func_symbols.push(symbol_id); + } + let mut trampolines = Vec::new(); + for (i, func) in self.trampolines.iter() { + let name = utils::trampoline_symbol_name(i).as_bytes().to_vec(); + trampolines.push(append_func(name, func)); } obj.append_section_data(section_id, &[], self.code_alignment); @@ -412,32 +382,32 @@ impl<'a> ObjectBuilder<'a> { let libcalls = write_libcall_symbols(&mut obj); // Write all functions relocations. - for (index, relocs) in relocations.into_iter() { + for (index, func) in self.compilation.into_iter() { let func_index = module.local.func_index(index); let (_, off) = obj .symbol_section_and_offset(func_symbols[func_index]) .unwrap(); for r in to_object_relocations( - relocs.iter(), + func.relocations.iter(), off, module, &func_symbols, &libcalls, - &jt_offsets, + &self.compilation, ) { obj.add_relocation(section_id, r)?; } } - for (symbol, relocs) in trampoline_relocs { + for (func, symbol) in self.trampolines.values().zip(trampolines) { let (_, off) = obj.symbol_section_and_offset(symbol).unwrap(); for r in to_object_relocations( - relocs.iter(), + func.relocations.iter(), off, module, &func_symbols, &libcalls, - &jt_offsets, + &self.compilation, ) { obj.add_relocation(section_id, r)?; } diff --git a/crates/obj/src/module.rs b/crates/obj/src/module.rs index 652576209d..4137d4a641 100644 --- a/crates/obj/src/module.rs +++ b/crates/obj/src/module.rs @@ -7,7 +7,7 @@ use object::write::{Object, Relocation, StandardSection, Symbol, SymbolSection}; use object::{RelocationEncoding, RelocationKind, SymbolFlags, SymbolKind, SymbolScope}; use wasmtime_debug::DwarfSection; use wasmtime_environ::isa::TargetFrontendConfig; -use wasmtime_environ::{Compilation, DataInitializer, Module, Relocations}; +use wasmtime_environ::{CompiledFunctions, DataInitializer, Module}; fn emit_vmcontext_init( obj: &mut Object, @@ -52,13 +52,11 @@ pub fn emit_module( target: ObjectBuilderTarget, module: &Module, target_config: &TargetFrontendConfig, - compilation: Compilation, - relocations: Relocations, + compilation: CompiledFunctions, dwarf_sections: Vec, data_initializers: &[DataInitializer], ) -> Result { - let mut builder = ObjectBuilder::new(target, module); - builder.set_compilation(compilation, relocations); + let mut builder = ObjectBuilder::new(target, module, &compilation); builder.set_dwarf_sections(dwarf_sections); let mut obj = builder.build()?; diff --git a/crates/wasmtime/Cargo.toml b/crates/wasmtime/Cargo.toml index 935ad6cf82..54a15a42f4 100644 --- a/crates/wasmtime/Cargo.toml +++ b/crates/wasmtime/Cargo.toml @@ -54,4 +54,4 @@ jitdump = ["wasmtime-jit/jitdump"] vtune = ["wasmtime-jit/vtune"] # Enables parallel compilation of WebAssembly code -parallel-compilation = ["wasmtime-environ/parallel-compilation"] +parallel-compilation = ["wasmtime-jit/parallel-compilation"] diff --git a/crates/wasmtime/src/frame_info.rs b/crates/wasmtime/src/frame_info.rs index faf6e00c1c..27d80904bb 100644 --- a/crates/wasmtime/src/frame_info.rs +++ b/crates/wasmtime/src/frame_info.rs @@ -152,15 +152,10 @@ pub fn register(module: &CompiledModule) -> Option let mut min = usize::max_value(); let mut max = 0; let mut functions = BTreeMap::new(); - for (((i, allocated), traps), instrs) in module - .finished_functions() - .iter() - .zip(module.traps().values()) - .zip(module.address_transform().values()) - { + for (i, allocated, traps, address_map) in module.trap_information() { let (start, end) = unsafe { - let ptr = (**allocated).as_ptr(); - let len = (**allocated).len(); + let ptr = (*allocated).as_ptr(); + let len = (*allocated).len(); (ptr as usize, ptr as usize + len) }; min = cmp::min(min, start); @@ -169,7 +164,7 @@ pub fn register(module: &CompiledModule) -> Option start, index: module.module().local.func_index(i), traps: traps.to_vec(), - instr_map: (*instrs).clone(), + instr_map: address_map.clone(), }; assert!(functions.insert(end, func).is_none()); } diff --git a/crates/wasmtime/src/runtime.rs b/crates/wasmtime/src/runtime.rs index 12f2b9445a..8315c9edb2 100644 --- a/crates/wasmtime/src/runtime.rs +++ b/crates/wasmtime/src/runtime.rs @@ -982,20 +982,15 @@ impl Store { pub(crate) fn register_stack_maps(&self, module: &Module) { let module = &module.compiled_module(); - self.stack_map_registry().register_stack_maps( - module - .finished_functions() - .values() - .zip(module.stack_maps().values()) - .map(|(func, stack_maps)| unsafe { - let ptr = (**func).as_ptr(); - let len = (**func).len(); - let start = ptr as usize; - let end = ptr as usize + len; - let range = start..end; - (range, &stack_maps[..]) - }), - ); + self.stack_map_registry() + .register_stack_maps(module.stack_maps().map(|(func, stack_maps)| unsafe { + let ptr = (*func).as_ptr(); + let len = (*func).len(); + let start = ptr as usize; + let end = ptr as usize + len; + let range = start..end; + (range, stack_maps) + })); } pub(crate) unsafe fn add_instance(&self, handle: InstanceHandle) -> StoreInstanceHandle { diff --git a/crates/wasmtime/src/trampoline/func.rs b/crates/wasmtime/src/trampoline/func.rs index 2ba739da5c..03f76bf569 100644 --- a/crates/wasmtime/src/trampoline/func.rs +++ b/crates/wasmtime/src/trampoline/func.rs @@ -197,6 +197,12 @@ fn make_trampoline( body: code_buf, jt_offsets: context.func.jt_offsets, unwind_info, + relocations: Default::default(), + address_map: Default::default(), + stack_maps: Default::default(), + stack_slots: Default::default(), + traps: Default::default(), + value_labels_ranges: Default::default(), }) .expect("allocate_for_function") } diff --git a/src/obj.rs b/src/obj.rs index cce633e928..a9b43fc7ab 100644 --- a/src/obj.rs +++ b/src/obj.rs @@ -1,17 +1,11 @@ -use anyhow::{anyhow, bail, Context as _, Result}; +use anyhow::{bail, Context as _, Result}; use object::write::Object; use target_lexicon::Triple; use wasmtime::Strategy; -use wasmtime_debug::emit_dwarf; #[cfg(feature = "lightbeam")] use wasmtime_environ::Lightbeam; -use wasmtime_environ::{ - entity::EntityRef, settings, settings::Configurable, wasm::DefinedMemoryIndex, - wasm::MemoryIndex, Compiler, Cranelift, ModuleEnvironment, ModuleMemoryOffset, ModuleVmctxInfo, - Tunables, VMOffsets, -}; -use wasmtime_jit::native; -use wasmtime_obj::{emit_module, ObjectBuilderTarget}; +use wasmtime_environ::{settings, settings::Configurable, ModuleEnvironment, Tunables}; +use wasmtime_jit::{native, Compiler}; /// Creates object file from binary wasm data. pub fn compile_to_obj( @@ -49,83 +43,28 @@ pub fn compile_to_obj( let isa = isa_builder.finish(settings::Flags::new(flag_builder)); - let target = ObjectBuilderTarget::from_triple(isa.triple())?; - // TODO: Expose the tunables as command-line flags. let mut tunables = Tunables::default(); tunables.debug_info = debug_info; - let environ = ModuleEnvironment::new(isa.frontend_config(), &tunables); + let compiler = Compiler::new( + isa, + match strategy { + Strategy::Auto => wasmtime_jit::CompilationStrategy::Auto, + Strategy::Cranelift => wasmtime_jit::CompilationStrategy::Cranelift, + #[cfg(feature = "lightbeam")] + Strategy::Lightbeam => wasmtime_jit::CompilationStrategy::Lightbeam, + #[cfg(not(feature = "lightbeam"))] + Strategy::Lightbeam => bail!("lightbeam support not enabled"), + s => bail!("unknown compilation strategy {:?}", s), + }, + tunables.clone(), + ); + let environ = ModuleEnvironment::new(compiler.isa().frontend_config(), &tunables); let translation = environ .translate(wasm) .context("failed to translate module")?; - - // TODO: use the traps and stack maps information. - let ( - compilation, - relocations, - address_transform, - value_ranges, - stack_slots, - _traps, - _stack_maps, - ) = match strategy { - Strategy::Auto | Strategy::Cranelift => Cranelift::compile_module(&translation, &*isa), - #[cfg(feature = "lightbeam")] - Strategy::Lightbeam => Lightbeam::compile_module(&translation, &*isa), - #[cfg(not(feature = "lightbeam"))] - Strategy::Lightbeam => bail!("lightbeam support not enabled"), - other => bail!("unsupported compilation strategy {:?}", other), - } - .context("failed to compile module")?; - - if compilation.is_empty() { - bail!("no functions were found/compiled"); - } - - let module_vmctx_info = { - let ofs = VMOffsets::new( - translation.target_config.pointer_bytes(), - &translation.module.local, - ); - ModuleVmctxInfo { - memory_offset: if ofs.num_imported_memories > 0 { - ModuleMemoryOffset::Imported(ofs.vmctx_vmmemory_import(MemoryIndex::new(0))) - } else if ofs.num_defined_memories > 0 { - ModuleMemoryOffset::Defined( - ofs.vmctx_vmmemory_definition_base(DefinedMemoryIndex::new(0)), - ) - } else { - ModuleMemoryOffset::None - }, - stack_slots, - } - }; - - let dwarf_sections = if let Some(debug_data) = &translation.debuginfo { - emit_dwarf( - &*isa, - &debug_data, - &address_transform, - &module_vmctx_info, - &value_ranges, - &compilation.unwind_info(), - ) - .context("failed to emit debug sections")? - } else { - vec![] - }; - - Ok(emit_module( - target, - &translation.module, - &translation.target_config, - compilation, - relocations, - dwarf_sections, - &translation.data_initializers, - ) - .map_err(|e| anyhow!(e)) - .context("failed to emit module")?) + let compilation = compiler.compile(&translation)?; + Ok(compilation.obj) }