diff --git a/cranelift/codegen/src/isa/mod.rs b/cranelift/codegen/src/isa/mod.rs index 590f59a293..b74cf9f412 100644 --- a/cranelift/codegen/src/isa/mod.rs +++ b/cranelift/codegen/src/isa/mod.rs @@ -64,6 +64,7 @@ use crate::timing; use alloc::borrow::Cow; use alloc::boxed::Box; use core::fmt; +use core::fmt::{Debug, Formatter}; use target_lexicon::{triple, Architecture, PointerWidth, Triple}; use thiserror::Error; @@ -390,3 +391,14 @@ pub trait TargetIsa: fmt::Display + Send + Sync { // No-op by default } } + +impl Debug for &dyn TargetIsa { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "TargetIsa {{ triple: {:?}, pointer_width: {:?}}}", + self.triple(), + self.pointer_width() + ) + } +} diff --git a/crates/debug/src/lib.rs b/crates/debug/src/lib.rs index 67a7bf0460..1d212bdf28 100644 --- a/crates/debug/src/lib.rs +++ b/crates/debug/src/lib.rs @@ -5,8 +5,8 @@ use anyhow::Error; use faerie::{Artifact, Decl}; use more_asserts::assert_gt; -use target_lexicon::{BinaryFormat, Triple}; -use wasmtime_environ::isa::TargetFrontendConfig; +use target_lexicon::BinaryFormat; +use wasmtime_environ::isa::TargetIsa; use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges}; pub use crate::read_debuginfo::{read_debuginfo, DebugInfoData, WasmFileInfo}; @@ -29,13 +29,13 @@ impl SymbolResolver for FunctionRelocResolver { pub fn emit_debugsections( obj: &mut Artifact, vmctx_info: &ModuleVmctxInfo, - target_config: TargetFrontendConfig, + isa: &dyn TargetIsa, debuginfo_data: &DebugInfoData, at: &ModuleAddressMap, ranges: &ValueLabelsRanges, ) -> Result<(), Error> { let resolver = FunctionRelocResolver {}; - let dwarf = transform_dwarf(target_config, debuginfo_data, at, vmctx_info, ranges)?; + let dwarf = transform_dwarf(isa, debuginfo_data, at, vmctx_info, ranges)?; emit_dwarf(obj, dwarf, &resolver)?; Ok(()) } @@ -52,8 +52,7 @@ impl<'a> SymbolResolver for ImageRelocResolver<'a> { } pub fn emit_debugsections_image( - triple: Triple, - target_config: TargetFrontendConfig, + isa: &dyn TargetIsa, debuginfo_data: &DebugInfoData, vmctx_info: &ModuleVmctxInfo, at: &ModuleAddressMap, @@ -64,9 +63,9 @@ pub fn emit_debugsections_image( .iter() .map(|(ptr, _)| *ptr as u64) .collect::>(); - let mut obj = Artifact::new(triple, String::from("module")); + let mut obj = Artifact::new(isa.triple().clone(), String::from("module")); let resolver = ImageRelocResolver { func_offsets }; - let dwarf = transform_dwarf(target_config, debuginfo_data, at, vmctx_info, ranges)?; + let dwarf = transform_dwarf(isa, debuginfo_data, at, vmctx_info, ranges)?; // Assuming all functions in the same code block, looking min/max of its range. assert_gt!(funcs.len(), 0); diff --git a/crates/debug/src/transform/attr.rs b/crates/debug/src/transform/attr.rs index bd0d784479..ef9e430418 100644 --- a/crates/debug/src/transform/attr.rs +++ b/crates/debug/src/transform/attr.rs @@ -5,10 +5,11 @@ use super::refs::{PendingDebugInfoRefs, PendingUnitRefs}; use super::{DebugInputContext, Reader, TransformError}; use anyhow::Error; use gimli::{write, AttributeValue, DebugLineOffset, DebugStr, DebuggingInformationEntry}; +use wasmtime_environ::isa::TargetIsa; pub(crate) enum FileAttributeContext<'a> { Root(Option), - Children(&'a Vec, Option<&'a CompiledExpression>), + Children(&'a Vec, Option<&'a CompiledExpression<'a>>), } fn is_exprloc_to_loclist_allowed(attr_name: gimli::constants::DwAt) -> bool { @@ -41,6 +42,7 @@ pub(crate) fn clone_die_attributes<'a, R>( pending_die_refs: &mut PendingUnitRefs, pending_di_refs: &mut PendingDebugInfoRefs, file_context: FileAttributeContext<'a>, + isa: &dyn TargetIsa, ) -> Result<(), Error> where R: Reader, @@ -130,7 +132,9 @@ where }; let mut result = None; while let Some(loc) = locs.next()? { - if let Some(expr) = compile_expression(&loc.data, unit_encoding, frame_base)? { + if let Some(expr) = + compile_expression(&loc.data, unit_encoding, frame_base, isa)? + { if result.is_none() { result = Some(Vec::new()); } @@ -168,7 +172,7 @@ where } else { None }; - if let Some(expr) = compile_expression(expr, unit_encoding, frame_base)? { + if let Some(expr) = compile_expression(expr, unit_encoding, frame_base, isa)? { if expr.is_simple() { if let Some(expr) = expr.build() { write::AttributeValue::Exprloc(expr) diff --git a/crates/debug/src/transform/expression.rs b/crates/debug/src/transform/expression.rs index 2c3fb72392..277dd6bd97 100644 --- a/crates/debug/src/transform/expression.rs +++ b/crates/debug/src/transform/expression.rs @@ -5,7 +5,7 @@ use more_asserts::{assert_le, assert_lt}; use std::collections::{HashMap, HashSet}; use wasmtime_environ::entity::EntityRef; use wasmtime_environ::ir::{StackSlots, ValueLabel, ValueLabelsRanges, ValueLoc}; -use wasmtime_environ::isa::RegUnit; +use wasmtime_environ::isa::{RegUnit, TargetIsa}; use wasmtime_environ::wasm::{get_vmctx_value_label, DefinedFuncIndex}; use wasmtime_environ::ModuleMemoryOffset; @@ -37,9 +37,10 @@ enum CompiledExpressionPart { } #[derive(Debug)] -pub struct CompiledExpression { +pub struct CompiledExpression<'a> { parts: Vec, need_deref: bool, + isa: &'a dyn TargetIsa, } impl Clone for CompiledExpressionPart { @@ -52,77 +53,87 @@ impl Clone for CompiledExpressionPart { } } -impl CompiledExpression { - pub fn vmctx() -> CompiledExpression { - CompiledExpression::from_label(get_vmctx_value_label()) +impl<'a> CompiledExpression<'a> { + pub fn vmctx(isa: &'a dyn TargetIsa) -> CompiledExpression { + CompiledExpression::from_label(get_vmctx_value_label(), isa) } - pub fn from_label(label: ValueLabel) -> CompiledExpression { + pub fn from_label(label: ValueLabel, isa: &'a dyn TargetIsa) -> CompiledExpression<'a> { CompiledExpression { parts: vec![ CompiledExpressionPart::Local(label), CompiledExpressionPart::Code(vec![gimli::constants::DW_OP_stack_value.0 as u8]), ], need_deref: false, + isa, } } } -fn map_reg(reg: RegUnit) -> Register { - static mut REG_X86_MAP: Option> = None; - // FIXME lazy initialization? - unsafe { - if REG_X86_MAP.is_none() { - REG_X86_MAP = Some(HashMap::new()); +fn map_reg(isa: &dyn TargetIsa, reg: RegUnit) -> Register { + // TODO avoid duplication with fde.rs + assert!(isa.name() == "x86" && isa.pointer_bits() == 64); + // Mapping from https://github.com/bytecodealliance/cranelift/pull/902 by @iximeow + const X86_GP_REG_MAP: [gimli::Register; 16] = [ + X86_64::RAX, + X86_64::RCX, + X86_64::RDX, + X86_64::RBX, + X86_64::RSP, + X86_64::RBP, + X86_64::RSI, + X86_64::RDI, + X86_64::R8, + X86_64::R9, + X86_64::R10, + X86_64::R11, + X86_64::R12, + X86_64::R13, + X86_64::R14, + X86_64::R15, + ]; + const X86_XMM_REG_MAP: [gimli::Register; 16] = [ + X86_64::XMM0, + X86_64::XMM1, + X86_64::XMM2, + X86_64::XMM3, + X86_64::XMM4, + X86_64::XMM5, + X86_64::XMM6, + X86_64::XMM7, + X86_64::XMM8, + X86_64::XMM9, + X86_64::XMM10, + X86_64::XMM11, + X86_64::XMM12, + X86_64::XMM13, + X86_64::XMM14, + X86_64::XMM15, + ]; + let reg_info = isa.register_info(); + let bank = reg_info.bank_containing_regunit(reg).unwrap(); + match bank.name { + "IntRegs" => { + // x86 GP registers have a weird mapping to DWARF registers, so we use a + // lookup table. + X86_GP_REG_MAP[(reg - bank.first_unit) as usize] } - if let Some(val) = REG_X86_MAP.as_mut().unwrap().get(®) { - return *val; + "FloatRegs" => X86_XMM_REG_MAP[(reg - bank.first_unit) as usize], + _ => { + panic!("unsupported register bank: {}", bank.name); } - let result = match reg { - 0 => X86_64::RAX, - 1 => X86_64::RCX, - 2 => X86_64::RDX, - 3 => X86_64::RBX, - 4 => X86_64::RSP, - 5 => X86_64::RBP, - 6 => X86_64::RSI, - 7 => X86_64::RDI, - 8 => X86_64::R8, - 9 => X86_64::R9, - 10 => X86_64::R10, - 11 => X86_64::R11, - 12 => X86_64::R12, - 13 => X86_64::R13, - 14 => X86_64::R14, - 15 => X86_64::R15, - 16 => X86_64::XMM0, - 17 => X86_64::XMM1, - 18 => X86_64::XMM2, - 19 => X86_64::XMM3, - 20 => X86_64::XMM4, - 21 => X86_64::XMM5, - 22 => X86_64::XMM6, - 23 => X86_64::XMM7, - 24 => X86_64::XMM8, - 25 => X86_64::XMM9, - 26 => X86_64::XMM10, - 27 => X86_64::XMM11, - 28 => X86_64::XMM12, - 29 => X86_64::XMM13, - 30 => X86_64::XMM14, - 31 => X86_64::XMM15, - _ => panic!("unknown x86_64 register {}", reg), - }; - REG_X86_MAP.as_mut().unwrap().insert(reg, result); - result } } -fn translate_loc(loc: ValueLoc, frame_info: Option<&FunctionFrameInfo>) -> Option> { +fn translate_loc( + loc: ValueLoc, + frame_info: Option<&FunctionFrameInfo>, + isa: &dyn TargetIsa, +) -> Option> { use gimli::write::Writer; match loc { ValueLoc::Reg(reg) => { - let machine_reg = map_reg(reg).0 as u8; + let machine_reg = map_reg(isa, reg).0 as u8; Some(if machine_reg < 32 { vec![gimli::constants::DW_OP_reg0.0 + machine_reg] } else { @@ -164,13 +175,14 @@ fn append_memory_deref( frame_info: &FunctionFrameInfo, vmctx_loc: ValueLoc, endian: gimli::RunTimeEndian, + isa: &dyn TargetIsa, ) -> write::Result { use gimli::write::Writer; let mut writer = write::EndianVec::new(endian); // FIXME for imported memory match vmctx_loc { ValueLoc::Reg(vmctx_reg) => { - let reg = map_reg(vmctx_reg); + let reg = map_reg(isa, vmctx_reg); writer.write_u8(gimli::constants::DW_OP_breg0.0 + reg.0 as u8)?; let memory_offset = match frame_info.vmctx_memory_offset() { Some(offset) => offset, @@ -213,7 +225,7 @@ fn append_memory_deref( Ok(true) } -impl CompiledExpression { +impl<'a> CompiledExpression<'a> { pub fn is_simple(&self) -> bool { if let [CompiledExpressionPart::Code(_)] = self.parts.as_slice() { true @@ -284,7 +296,7 @@ impl CompiledExpression { CompiledExpressionPart::Code(c) => code_buf.extend_from_slice(c.as_slice()), CompiledExpressionPart::Local(label) => { let loc = *label_location.get(&label).expect("loc"); - if let Some(expr) = translate_loc(loc, frame_info) { + if let Some(expr) = translate_loc(loc, frame_info, self.isa) { code_buf.extend_from_slice(&expr) } else { continue 'range; @@ -294,8 +306,14 @@ impl CompiledExpression { if let (Some(vmctx_loc), Some(frame_info)) = (label_location.get(&vmctx_label), frame_info) { - if !append_memory_deref(&mut code_buf, frame_info, *vmctx_loc, endian) - .expect("append_memory_deref") + if !append_memory_deref( + &mut code_buf, + frame_info, + *vmctx_loc, + endian, + self.isa, + ) + .expect("append_memory_deref") { continue 'range; } @@ -309,7 +327,7 @@ impl CompiledExpression { if let (Some(vmctx_loc), Some(frame_info)) = (label_location.get(&vmctx_label), frame_info) { - if !append_memory_deref(&mut code_buf, frame_info, *vmctx_loc, endian) + if !append_memory_deref(&mut code_buf, frame_info, *vmctx_loc, endian, self.isa) .expect("append_memory_deref") { continue 'range; @@ -342,11 +360,12 @@ fn is_old_expression_format(buf: &[u8]) -> bool { buf.contains(&(gimli::constants::DW_OP_plus_uconst.0 as u8)) } -pub fn compile_expression( +pub fn compile_expression<'a, R>( expr: &Expression, encoding: gimli::Encoding, frame_base: Option<&CompiledExpression>, -) -> Result, Error> + isa: &'a dyn TargetIsa, +) -> Result>, Error> where R: Reader, { @@ -437,7 +456,11 @@ where } } - Ok(Some(CompiledExpression { parts, need_deref })) + Ok(Some(CompiledExpression { + parts, + need_deref, + isa, + })) } #[derive(Debug, Clone)] diff --git a/crates/debug/src/transform/mod.rs b/crates/debug/src/transform/mod.rs index 592fbe2f10..a903ec5fff 100644 --- a/crates/debug/src/transform/mod.rs +++ b/crates/debug/src/transform/mod.rs @@ -10,7 +10,7 @@ use gimli::{ }; use std::collections::HashSet; use thiserror::Error; -use wasmtime_environ::isa::TargetFrontendConfig; +use wasmtime_environ::isa::TargetIsa; use wasmtime_environ::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges}; pub use address_transform::AddressTransform; @@ -47,7 +47,7 @@ where } pub fn transform_dwarf( - target_config: TargetFrontendConfig, + isa: &dyn TargetIsa, di: &DebugInfoData, at: &ModuleAddressMap, vmctx_info: &ModuleVmctxInfo, @@ -71,7 +71,7 @@ pub fn transform_dwarf( // TODO: this should be configurable // macOS doesn't seem to support DWARF > 3 version: 3, - address_size: target_config.pointer_bytes(), + address_size: isa.pointer_bytes(), }; let mut out_strings = write::StringTable::default(); @@ -95,6 +95,7 @@ pub fn transform_dwarf( &mut out_units, &mut out_strings, &mut translated, + isa, )? { di_ref_map.insert(&header, id, ref_map); pending_di_refs.push((id, pending_refs)); @@ -111,6 +112,7 @@ pub fn transform_dwarf( out_encoding, &mut out_units, &mut out_strings, + isa, )?; Ok(write::Dwarf { diff --git a/crates/debug/src/transform/simulate.rs b/crates/debug/src/transform/simulate.rs index b139dead99..f2a6a512b8 100644 --- a/crates/debug/src/transform/simulate.rs +++ b/crates/debug/src/transform/simulate.rs @@ -12,6 +12,7 @@ use wasmtime_environ::wasm::get_vmctx_value_label; use wasmtime_environ::{ModuleVmctxInfo, ValueLabelsRanges}; pub use crate::read_debuginfo::{DebugInfoData, FunctionMetadata, WasmType}; +use wasmtime_environ::isa::TargetIsa; const PRODUCER_NAME: &str = "wasmtime"; @@ -175,6 +176,7 @@ fn generate_vars( func_meta: &FunctionMetadata, locals_names: Option<&HashMap>, out_strings: &mut write::StringTable, + isa: &dyn TargetIsa, ) { let vmctx_label = get_vmctx_value_label(); @@ -192,6 +194,7 @@ fn generate_vars( Some(frame_info), scope_ranges, out_strings, + isa, ) .expect("append_vmctx_info success"); } else { @@ -207,7 +210,7 @@ fn generate_vars( let loc_list_id = { let endian = gimli::RunTimeEndian::Little; - let expr = CompiledExpression::from_label(*label); + let expr = CompiledExpression::from_label(*label, isa); let mut locs = Vec::new(); for (begin, length, data) in expr.build_with_locals(scope_ranges, addr_tr, Some(frame_info), endian) @@ -258,6 +261,7 @@ pub fn generate_simulated_dwarf( out_encoding: gimli::Encoding, out_units: &mut write::UnitTable, out_strings: &mut write::StringTable, + isa: &dyn TargetIsa, ) -> Result<(), Error> { let path = di .wasm_file @@ -365,6 +369,7 @@ pub fn generate_simulated_dwarf( &di.wasm_file.funcs[index], locals_names.and_then(|m| m.get(&(index as u32))), out_strings, + isa, ); } } diff --git a/crates/debug/src/transform/unit.rs b/crates/debug/src/transform/unit.rs index dbd14f641c..56c67f27c7 100644 --- a/crates/debug/src/transform/unit.rs +++ b/crates/debug/src/transform/unit.rs @@ -11,6 +11,7 @@ use gimli::write; use gimli::{AttributeValue, DebuggingInformationEntry, Unit}; use std::collections::HashSet; use wasmtime_environ::entity::EntityRef; +use wasmtime_environ::isa::TargetIsa; use wasmtime_environ::{ModuleVmctxInfo, ValueLabelsRanges}; struct InheritedAttr { @@ -148,6 +149,7 @@ pub(crate) fn clone_unit<'a, R>( out_units: &mut write::UnitTable, out_strings: &mut write::StringTable, translated: &mut HashSet, + isa: &dyn TargetIsa, ) -> Result, Error> where R: Reader, @@ -203,6 +205,7 @@ where &mut pending_die_refs, &mut pending_di_refs, FileAttributeContext::Root(Some(debug_line_offset)), + isa, )?; let (wp_die_id, vmctx_die_id) = @@ -296,7 +299,7 @@ where } if let Some(AttributeValue::Exprloc(expr)) = entry.attr_value(gimli::DW_AT_frame_base)? { - if let Some(expr) = compile_expression(&expr, unit.encoding(), None)? { + if let Some(expr) = compile_expression(&expr, unit.encoding(), None, isa)? { current_frame_base.push(new_stack_len, expr); } } @@ -343,6 +346,7 @@ where &mut pending_die_refs, &mut pending_di_refs, FileAttributeContext::Children(&file_map, current_frame_base.top()), + isa, )?; if entry.tag() == gimli::DW_TAG_subprogram && !current_scope_ranges.is_empty() { @@ -354,6 +358,7 @@ where current_value_range.top(), current_scope_ranges.top().expect("range"), out_strings, + isa, )?; } } diff --git a/crates/debug/src/transform/utils.rs b/crates/debug/src/transform/utils.rs index 2b921581cb..88f0cea491 100644 --- a/crates/debug/src/transform/utils.rs +++ b/crates/debug/src/transform/utils.rs @@ -2,6 +2,7 @@ use super::address_transform::AddressTransform; use super::expression::{CompiledExpression, FunctionFrameInfo}; use anyhow::Error; use gimli::write; +use wasmtime_environ::isa::TargetIsa; use wasmtime_environ::wasm::DefinedFuncIndex; use wasmtime_environ::{ModuleMemoryOffset, ModuleVmctxInfo, ValueLabelsRanges}; @@ -109,11 +110,12 @@ pub(crate) fn append_vmctx_info( frame_info: Option<&FunctionFrameInfo>, scope_ranges: &[(u64, u64)], out_strings: &mut write::StringTable, + isa: &dyn TargetIsa, ) -> Result<(), Error> { let loc = { let endian = gimli::RunTimeEndian::Little; - let expr = CompiledExpression::vmctx(); + let expr = CompiledExpression::vmctx(isa); let mut locs = Vec::new(); for (begin, length, data) in expr.build_with_locals(scope_ranges, addr_tr, frame_info, endian) diff --git a/crates/jit/src/compiler.rs b/crates/jit/src/compiler.rs index 31af40531a..1d264f996f 100644 --- a/crates/jit/src/compiler.rs +++ b/crates/jit/src/compiler.rs @@ -174,8 +174,7 @@ impl Compiler { } }; let bytes = emit_debugsections_image( - self.isa.triple().clone(), - target_config, + &*self.isa, debug_data.as_ref().unwrap(), &module_vmctx_info, &address_transform, diff --git a/src/obj.rs b/src/obj.rs index 95ba2ce05d..0adf4aa3fb 100644 --- a/src/obj.rs +++ b/src/obj.rs @@ -140,7 +140,7 @@ pub fn compile_to_obj( emit_debugsections( &mut obj, &module_vmctx_info, - target_config, + &*isa, &debug_data, &address_transform, &value_ranges,