From 65eaca35dd9ab84bf4f9c10600e15895a942b34a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 3 Aug 2020 12:20:51 -0500 Subject: [PATCH] Refactor where results of compilation are stored (#2086) * Refactor where results of compilation are stored This commit refactors the internals of compilation in Wasmtime to change where results of individual function compilation are stored. Previously compilation resulted in many maps being returned, and compilation results generally held all these maps together. This commit instead switches this to have all metadata stored in a `CompiledFunction` instead of having a separate map for each item that can be stored. The motivation for this is primarily to help out with future module-linking-related PRs. What exactly "module level" is depends on how we interpret modules and how many modules are in play, so it's a bit easier for operations in wasmtime to work at the function level where possible. This means that we don't have to pass around multiple different maps and a function index, but instead just one map or just one entry representing a compiled function. Additionally this change updates where the parallelism of compilation happens, pushing it into `wasmtime-jit` instead of `wasmtime-environ`. This is another goal where `wasmtime-jit` will have more knowledge about module-level pieces with module linking in play. User-facing-wise this should be the same in terms of parallel compilation, though. The ultimate goal of this refactoring is to make it easier for the results of compilation to actually be a set of wasm modules. This means we won't be able to have a map-per-metadata where the primary key is the function index, because there will be many modules within one "object file". * Don't clear out fields, just don't store them Persist a smaller set of fields in `CompilationArtifacts` instead of trying to clear fields out and dynamically not accessing them. --- Cargo.lock | 2 +- cranelift/codegen/src/ir/stackslot.rs | 9 +- cranelift/entity/src/iter.rs | 38 ++++ cranelift/entity/src/map.rs | 10 ++ cranelift/entity/src/primary.rs | 23 ++- .../debug/src/transform/address_transform.rs | 26 +-- crates/debug/src/transform/expression.rs | 38 ++-- crates/debug/src/transform/mod.rs | 18 +- crates/debug/src/transform/simulate.rs | 18 +- crates/debug/src/transform/unit.rs | 11 +- crates/debug/src/transform/utils.rs | 18 +- crates/debug/src/write_debuginfo.rs | 25 +-- crates/environ/Cargo.toml | 4 - crates/environ/src/address_map.rs | 23 +-- crates/environ/src/compilation.rs | 141 +++------------ crates/environ/src/cranelift.rs | 164 +++++------------- crates/environ/src/lib.rs | 10 +- crates/environ/src/lightbeam.rs | 87 ++++------ crates/jit/Cargo.toml | 2 + crates/jit/src/code_memory.rs | 27 +-- crates/jit/src/compiler.rs | 121 +++++-------- crates/jit/src/instantiate.rs | 91 +++++----- crates/jit/src/object.rs | 33 ++-- crates/jit/src/trampoline.rs | 25 +-- crates/obj/src/builder.rs | 108 +++++------- crates/obj/src/module.rs | 8 +- crates/wasmtime/Cargo.toml | 2 +- crates/wasmtime/src/frame_info.rs | 13 +- crates/wasmtime/src/runtime.rs | 23 +-- crates/wasmtime/src/trampoline/func.rs | 6 + src/obj.rs | 99 ++--------- 31 files changed, 466 insertions(+), 757 deletions(-) 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) }