diff --git a/cranelift/codegen/src/binemit/memorysink.rs b/cranelift/codegen/src/binemit/memorysink.rs deleted file mode 100644 index 149fed67bb..0000000000 --- a/cranelift/codegen/src/binemit/memorysink.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! Code sink that writes binary machine code into contiguous memory. -//! -//! The `CodeSink` trait is the most general way of extracting binary machine code from Cranelift, -//! and it is implemented by things like the `test binemit` file test driver to generate -//! hexadecimal machine code. The `CodeSink` has some undesirable performance properties because of -//! the dual abstraction: `TargetIsa` is a trait object implemented by each supported ISA, so it -//! can't have any generic functions that could be specialized for each `CodeSink` implementation. -//! This results in many virtual function callbacks (one per `put*` call) when -//! `TargetIsa::emit_inst()` is used. -//! -//! The `MemoryCodeSink` type fixes the performance problem because it is a type known to -//! `TargetIsa` so it can specialize its machine code generation for the type. The trade-off is -//! that a `MemoryCodeSink` will always write binary machine code to raw memory. It forwards any -//! relocations to a `RelocSink` trait object. Relocations are less frequent than the -//! `CodeSink::put*` methods, so the performance impact of the virtual callbacks is less severe. -use super::{Addend, CodeOffset, Reloc}; -use crate::binemit::stack_map::StackMap; -use crate::ir::{ExternalName, SourceLoc, TrapCode}; - -/// A trait for receiving relocations for code that is emitted directly into memory. -pub trait RelocSink { - /// Add a relocation referencing an external symbol at the current offset. - fn reloc_external( - &mut self, - _: CodeOffset, - _: SourceLoc, - _: Reloc, - _: &ExternalName, - _: Addend, - ); -} - -/// A trait for receiving trap codes and offsets. -/// -/// If you don't need information about possible traps, you can use the -/// [`NullTrapSink`](NullTrapSink) implementation. -pub trait TrapSink { - /// Add trap information for a specific offset. - fn trap(&mut self, _: CodeOffset, _: SourceLoc, _: TrapCode); -} - -/// A `RelocSink` implementation that does nothing, which is convenient when -/// compiling code that does not relocate anything. -#[derive(Default)] -pub struct NullRelocSink {} - -impl RelocSink for NullRelocSink { - fn reloc_external( - &mut self, - _: CodeOffset, - _: SourceLoc, - _: Reloc, - _: &ExternalName, - _: Addend, - ) { - } -} - -/// A `TrapSink` implementation that does nothing, which is convenient when -/// compiling code that does not rely on trapping semantics. -#[derive(Default)] -pub struct NullTrapSink {} - -impl TrapSink for NullTrapSink { - fn trap(&mut self, _offset: CodeOffset, _srcloc: SourceLoc, _code: TrapCode) {} -} - -/// A trait for emitting stack maps. -pub trait StackMapSink { - /// Output a bitmap of the stack representing the live reference variables at this code offset. - fn add_stack_map(&mut self, _: CodeOffset, _: StackMap); -} - -/// Placeholder StackMapSink that does nothing. -pub struct NullStackMapSink {} - -impl StackMapSink for NullStackMapSink { - fn add_stack_map(&mut self, _: CodeOffset, _: StackMap) {} -} diff --git a/cranelift/codegen/src/binemit/mod.rs b/cranelift/codegen/src/binemit/mod.rs index 0c634b27af..750eaa2a21 100644 --- a/cranelift/codegen/src/binemit/mod.rs +++ b/cranelift/codegen/src/binemit/mod.rs @@ -3,12 +3,8 @@ //! The `binemit` module contains code for translating Cranelift's intermediate representation into //! binary machine code. -mod memorysink; mod stack_map; -pub use self::memorysink::{ - NullRelocSink, NullStackMapSink, NullTrapSink, RelocSink, StackMapSink, TrapSink, -}; pub use self::stack_map::StackMap; use core::fmt; #[cfg(feature = "enable-serde")] diff --git a/cranelift/codegen/src/machinst/buffer.rs b/cranelift/codegen/src/machinst/buffer.rs index 2eeab23f33..7091d880dc 100644 --- a/cranelift/codegen/src/machinst/buffer.rs +++ b/cranelift/codegen/src/machinst/buffer.rs @@ -1499,6 +1499,7 @@ struct MachLabelFixup { } /// A relocation resulting from a compilation. +#[derive(Clone, Debug)] pub struct MachReloc { /// The offset at which the relocation applies, *relative to the /// containing section*. @@ -1514,6 +1515,7 @@ pub struct MachReloc { } /// A trap record resulting from a compilation. +#[derive(Clone, Debug)] pub struct MachTrap { /// The offset at which the trap instruction occurs, *relative to the /// containing section*. diff --git a/cranelift/jit/src/backend.rs b/cranelift/jit/src/backend.rs index 660758b25b..ed45734136 100644 --- a/cranelift/jit/src/backend.rs +++ b/cranelift/jit/src/backend.rs @@ -5,13 +5,13 @@ use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::Configurable; use cranelift_codegen::{self, ir, settings, MachReloc}; use cranelift_codegen::{ - binemit::{Addend, CodeInfo, CodeOffset, Reloc, RelocSink}, + binemit::{CodeInfo, Reloc}, CodegenError, }; use cranelift_entity::SecondaryMap; use cranelift_module::{ DataContext, DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleCompiledFunction, - ModuleDeclarations, ModuleError, ModuleResult, RelocRecord, + ModuleDeclarations, ModuleError, ModuleResult, }; use log::info; use std::collections::HashMap; @@ -671,25 +671,17 @@ impl Module for JITModule { .allocate(size, EXECUTABLE_DATA_ALIGNMENT) .expect("TODO: handle OOM etc."); - let mut reloc_sink = JITRelocSink::default(); unsafe { ctx.emit_to_memory(ptr) }; - for &MachReloc { - offset, - srcloc, - kind, - ref name, - addend, - } in ctx.mach_compile_result.as_ref().unwrap().buffer.relocs() - { - reloc_sink.reloc_external(offset, srcloc, kind, name, addend); - } + let relocs = ctx + .mach_compile_result + .as_ref() + .unwrap() + .buffer + .relocs() + .to_vec(); self.record_function_for_perf(ptr, size, &decl.name); - self.compiled_functions[id] = Some(CompiledBlob { - ptr, - size, - relocs: reloc_sink.relocs, - }); + self.compiled_functions[id] = Some(CompiledBlob { ptr, size, relocs }); if self.isa.flags().is_pic() { self.pending_got_updates.push(GotUpdate { @@ -729,7 +721,7 @@ impl Module for JITModule { &mut self, id: FuncId, bytes: &[u8], - relocs: &[RelocRecord], + relocs: &[MachReloc], ) -> ModuleResult { info!("defining function {} with bytes", id); let total_size: u32 = match bytes.len().try_into() { @@ -896,26 +888,3 @@ fn lookup_with_dlsym(name: &str) -> Option<*const u8> { None } } - -#[derive(Default)] -struct JITRelocSink { - relocs: Vec, -} - -impl RelocSink for JITRelocSink { - fn reloc_external( - &mut self, - offset: CodeOffset, - _srcloc: ir::SourceLoc, - reloc: Reloc, - name: &ir::ExternalName, - addend: Addend, - ) { - self.relocs.push(RelocRecord { - offset, - reloc, - name: name.clone(), - addend, - }); - } -} diff --git a/cranelift/jit/src/compiled_blob.rs b/cranelift/jit/src/compiled_blob.rs index 5af0067422..c5a62701f8 100644 --- a/cranelift/jit/src/compiled_blob.rs +++ b/cranelift/jit/src/compiled_blob.rs @@ -1,13 +1,13 @@ use cranelift_codegen::binemit::Reloc; use cranelift_codegen::ir::ExternalName; -use cranelift_module::RelocRecord; +use cranelift_codegen::MachReloc; use std::convert::TryFrom; #[derive(Clone)] pub(crate) struct CompiledBlob { pub(crate) ptr: *mut u8, pub(crate) size: usize, - pub(crate) relocs: Vec, + pub(crate) relocs: Vec, } impl CompiledBlob { @@ -19,16 +19,17 @@ impl CompiledBlob { ) { use std::ptr::write_unaligned; - for &RelocRecord { - reloc, + for &MachReloc { + kind, offset, + srcloc: _, ref name, addend, } in &self.relocs { debug_assert!((offset as usize) < self.size); let at = unsafe { self.ptr.offset(isize::try_from(offset).unwrap()) }; - match reloc { + match kind { Reloc::Abs4 => { let base = get_address(name); let what = unsafe { base.offset(isize::try_from(addend).unwrap()) }; diff --git a/cranelift/module/src/data_context.rs b/cranelift/module/src/data_context.rs index ce9536b1b0..d872819b9e 100644 --- a/cranelift/module/src/data_context.rs +++ b/cranelift/module/src/data_context.rs @@ -2,14 +2,13 @@ use cranelift_codegen::binemit::{Addend, CodeOffset, Reloc}; use cranelift_codegen::entity::PrimaryMap; -use cranelift_codegen::ir; +use cranelift_codegen::ir::{self, SourceLoc}; +use cranelift_codegen::MachReloc; use std::borrow::ToOwned; use std::boxed::Box; use std::string::String; use std::vec::Vec; -use crate::RelocRecord; - /// This specifies how data is to be initialized. #[derive(PartialEq, Eq, Debug)] pub enum Init { @@ -59,25 +58,24 @@ pub struct DataDescription { impl DataDescription { /// An iterator over all relocations of the data object. - pub fn all_relocs<'a>( - &'a self, - pointer_reloc: Reloc, - ) -> impl Iterator + 'a { + pub fn all_relocs<'a>(&'a self, pointer_reloc: Reloc) -> impl Iterator + 'a { let func_relocs = self .function_relocs .iter() - .map(move |&(offset, id)| RelocRecord { - reloc: pointer_reloc, + .map(move |&(offset, id)| MachReloc { + kind: pointer_reloc, offset, + srcloc: SourceLoc::default(), name: self.function_decls[id].clone(), addend: 0, }); let data_relocs = self .data_relocs .iter() - .map(move |&(offset, id, addend)| RelocRecord { - reloc: pointer_reloc, + .map(move |&(offset, id, addend)| MachReloc { + kind: pointer_reloc, offset, + srcloc: SourceLoc::default(), name: self.data_decls[id].clone(), addend, }); diff --git a/cranelift/module/src/lib.rs b/cranelift/module/src/lib.rs index 21d1c9df27..82562ae5df 100644 --- a/cranelift/module/src/lib.rs +++ b/cranelift/module/src/lib.rs @@ -43,7 +43,7 @@ mod traps; pub use crate::data_context::{DataContext, DataDescription, Init}; pub use crate::module::{ DataId, FuncId, FuncOrDataId, Linkage, Module, ModuleCompiledFunction, ModuleDeclarations, - ModuleError, ModuleResult, RelocRecord, + ModuleError, ModuleResult, }; pub use crate::traps::TrapSite; diff --git a/cranelift/module/src/module.rs b/cranelift/module/src/module.rs index 3d5816973f..336307a3a2 100644 --- a/cranelift/module/src/module.rs +++ b/cranelift/module/src/module.rs @@ -7,8 +7,8 @@ use super::HashMap; use crate::data_context::DataContext; -use cranelift_codegen::binemit; use cranelift_codegen::entity::{entity_impl, PrimaryMap}; +use cranelift_codegen::{binemit, MachReloc}; use cranelift_codegen::{ir, isa, CodegenError, Context}; use std::borrow::ToOwned; use std::string::String; @@ -416,19 +416,6 @@ pub struct ModuleCompiledFunction { pub size: binemit::CodeOffset, } -/// A record of a relocation to perform. -#[derive(Clone)] -pub struct RelocRecord { - /// Where in the generated code this relocation is to be applied. - pub offset: binemit::CodeOffset, - /// The kind of relocation this represents. - pub reloc: binemit::Reloc, - /// What symbol we're relocating against. - pub name: ir::ExternalName, - /// The offset to add to the relocation. - pub addend: binemit::Addend, -} - /// A `Module` is a utility for collecting functions and data objects, and linking them together. pub trait Module { /// Return the `TargetIsa` to compile for. @@ -567,7 +554,7 @@ pub trait Module { &mut self, func: FuncId, bytes: &[u8], - relocs: &[RelocRecord], + relocs: &[MachReloc], ) -> ModuleResult; /// Define a data object, producing the data contents from the given `DataContext`. @@ -662,7 +649,7 @@ impl Module for &mut M { &mut self, func: FuncId, bytes: &[u8], - relocs: &[RelocRecord], + relocs: &[MachReloc], ) -> ModuleResult { (**self).define_function_bytes(func, bytes, relocs) } diff --git a/cranelift/object/src/backend.rs b/cranelift/object/src/backend.rs index d3eea47fae..0998d829ee 100644 --- a/cranelift/object/src/backend.rs +++ b/cranelift/object/src/backend.rs @@ -5,12 +5,12 @@ use cranelift_codegen::entity::SecondaryMap; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::{self, ir, MachReloc}; use cranelift_codegen::{ - binemit::{Addend, CodeOffset, Reloc, RelocSink}, + binemit::{Addend, CodeOffset, Reloc}, CodegenError, }; use cranelift_module::{ DataContext, DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleCompiledFunction, - ModuleDeclarations, ModuleError, ModuleResult, RelocRecord, + ModuleDeclarations, ModuleError, ModuleResult, }; use log::info; use object::write::{ @@ -310,29 +310,21 @@ impl Module for ObjectModule { ) -> ModuleResult { info!("defining function {}: {}", func_id, ctx.func.display()); let mut code: Vec = Vec::new(); - let mut reloc_sink = ObjectRelocSink::default(); ctx.compile_and_emit(self.isa(), &mut code)?; - for &MachReloc { - offset, - srcloc, - kind, - ref name, - addend, - } in ctx.mach_compile_result.as_ref().unwrap().buffer.relocs() - { - reloc_sink.reloc_external(offset, srcloc, kind, name, addend); - } - - self.define_function_bytes(func_id, &code, &reloc_sink.relocs) + self.define_function_bytes( + func_id, + &code, + ctx.mach_compile_result.as_ref().unwrap().buffer.relocs(), + ) } fn define_function_bytes( &mut self, func_id: FuncId, bytes: &[u8], - relocs: &[RelocRecord], + relocs: &[MachReloc], ) -> ModuleResult { info!("defining function {} with bytes", func_id); let total_size: u32 = match bytes.len().try_into() { @@ -563,9 +555,9 @@ impl ObjectModule { } } - fn process_reloc(&self, record: &RelocRecord) -> ObjectRelocRecord { + fn process_reloc(&self, record: &MachReloc) -> ObjectRelocRecord { let mut addend = record.addend; - let (kind, encoding, size) = match record.reloc { + let (kind, encoding, size) = match record.kind { Reloc::Abs4 => (RelocationKind::Absolute, RelocationEncoding::Generic, 32), Reloc::Abs8 => (RelocationKind::Absolute, RelocationEncoding::Generic, 64), Reloc::X86PCRel4 => (RelocationKind::Relative, RelocationEncoding::Generic, 32), @@ -710,26 +702,3 @@ struct ObjectRelocRecord { size: u8, addend: Addend, } - -#[derive(Default)] -struct ObjectRelocSink { - relocs: Vec, -} - -impl RelocSink for ObjectRelocSink { - fn reloc_external( - &mut self, - offset: CodeOffset, - _srcloc: ir::SourceLoc, - reloc: Reloc, - name: &ir::ExternalName, - addend: Addend, - ) { - self.relocs.push(RelocRecord { - offset, - reloc, - addend, - name: name.clone(), - }) - } -} diff --git a/cranelift/src/compile.rs b/cranelift/src/compile.rs index abada4ea34..be1d1f3d51 100644 --- a/cranelift/src/compile.rs +++ b/cranelift/src/compile.rs @@ -1,13 +1,12 @@ //! CLI tool to read Cranelift IR files and compile them into native code. -use crate::disasm::{print_all, PrintRelocs, PrintStackMaps, PrintTraps}; +use crate::disasm::print_all; use crate::utils::{parse_sets_and_triple, read_to_string}; use anyhow::{Context as _, Result}; -use cranelift_codegen::binemit::{RelocSink, StackMapSink, TrapSink}; use cranelift_codegen::print_errors::pretty_error; use cranelift_codegen::settings::FlagsOrIsa; +use cranelift_codegen::timing; use cranelift_codegen::Context; -use cranelift_codegen::{timing, MachReloc, MachStackMap, MachTrap}; use cranelift_reader::{parse_test, ParseOptions}; use std::path::Path; use std::path::PathBuf; @@ -69,10 +68,6 @@ fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) - }; for (func, _) in test_file.functions { - let mut relocs = PrintRelocs::new(options.print); - let mut traps = PrintTraps::new(options.print); - let mut stack_maps = PrintStackMaps::new(options.print); - if let Some(isa) = isa { let mut context = Context::new(); context.func = func; @@ -84,32 +79,6 @@ fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) - .map_err(|err| anyhow::anyhow!("{}", pretty_error(&context.func, err)))?; let result = context.mach_compile_result.as_ref().unwrap(); let code_info = result.code_info(); - for &MachReloc { - offset, - srcloc, - kind, - ref name, - addend, - } in result.buffer.relocs() - { - relocs.reloc_external(offset, srcloc, kind, name, addend); - } - for &MachTrap { - offset, - srcloc, - code, - } in result.buffer.traps() - { - traps.trap(offset, srcloc, code); - } - for &MachStackMap { - offset_end, - ref stack_map, - .. - } in result.buffer.stack_maps() - { - stack_maps.add_stack_map(offset_end, stack_map.clone()); - } if options.print { println!("{}", context.func.display()); @@ -120,9 +89,10 @@ fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) - isa, &mem, code_info.total_size, - &relocs, - &traps, - &stack_maps, + options.print, + result.buffer.relocs(), + result.buffer.traps(), + result.buffer.stack_maps(), )?; } } diff --git a/cranelift/src/disasm.rs b/cranelift/src/disasm.rs index 7a108c5d80..174fb88651 100644 --- a/cranelift/src/disasm.rs +++ b/cranelift/src/disasm.rs @@ -1,85 +1,53 @@ use anyhow::Result; use cfg_if::cfg_if; use cranelift_codegen::isa::TargetIsa; -use cranelift_codegen::{binemit, ir}; +use cranelift_codegen::{MachReloc, MachStackMap, MachTrap}; use std::fmt::Write; -pub struct PrintRelocs { - pub flag_print: bool, - pub text: String, -} - -impl PrintRelocs { - pub fn new(flag_print: bool) -> Self { - Self { - flag_print, - text: String::new(), - } +pub fn print_relocs(relocs: &[MachReloc]) -> String { + let mut text = String::new(); + for &MachReloc { + kind, + offset, + srcloc: _, + ref name, + addend, + } in relocs + { + writeln!( + text, + "reloc_external: {} {} {} at {}", + kind, name, addend, offset + ) + .unwrap(); } + text } -impl binemit::RelocSink for PrintRelocs { - fn reloc_external( - &mut self, - where_: binemit::CodeOffset, - _srcloc: ir::SourceLoc, - r: binemit::Reloc, - name: &ir::ExternalName, - addend: binemit::Addend, - ) { - if self.flag_print { - writeln!( - &mut self.text, - "reloc_external: {} {} {} at {}", - r, name, addend, where_ - ) - .unwrap(); - } +pub fn print_traps(traps: &[MachTrap]) -> String { + let mut text = String::new(); + for &MachTrap { + offset, + srcloc: _, + code, + } in traps + { + writeln!(text, "trap: {} at {}", code, offset).unwrap(); } + text } -pub struct PrintTraps { - pub flag_print: bool, - pub text: String, -} - -impl PrintTraps { - pub fn new(flag_print: bool) -> Self { - Self { - flag_print, - text: String::new(), - } - } -} - -impl binemit::TrapSink for PrintTraps { - fn trap(&mut self, offset: binemit::CodeOffset, _srcloc: ir::SourceLoc, code: ir::TrapCode) { - if self.flag_print { - writeln!(&mut self.text, "trap: {} at {}", code, offset).unwrap(); - } - } -} - -pub struct PrintStackMaps { - pub flag_print: bool, - pub text: String, -} - -impl PrintStackMaps { - pub fn new(flag_print: bool) -> Self { - Self { - flag_print, - text: String::new(), - } - } -} - -impl binemit::StackMapSink for PrintStackMaps { - fn add_stack_map(&mut self, offset: binemit::CodeOffset, _: binemit::StackMap) { - if self.flag_print { - writeln!(&mut self.text, "add_stack_map at {}", offset).unwrap(); - } +pub fn print_stack_maps(traps: &[MachStackMap]) -> String { + let mut text = String::new(); + for &MachStackMap { + offset, + offset_end: _, + stack_map: _, + } in traps + { + writeln!(text, "add_stack_map at {}", offset).unwrap(); } + text } cfg_if! { @@ -193,13 +161,21 @@ pub fn print_all( isa: &dyn TargetIsa, mem: &[u8], code_size: u32, - relocs: &PrintRelocs, - traps: &PrintTraps, - stack_maps: &PrintStackMaps, + print: bool, + relocs: &[MachReloc], + traps: &[MachTrap], + stack_maps: &[MachStackMap], ) -> Result<()> { print_bytes(&mem); print_disassembly(isa, &mem[0..code_size as usize])?; - println!("\n{}\n{}\n{}", &relocs.text, &traps.text, &stack_maps.text); + if print { + println!( + "\n{}\n{}\n{}", + print_relocs(relocs), + print_traps(traps), + print_stack_maps(stack_maps) + ); + } Ok(()) } diff --git a/cranelift/src/wasm.rs b/cranelift/src/wasm.rs index d377858f5b..4fd83992b7 100644 --- a/cranelift/src/wasm.rs +++ b/cranelift/src/wasm.rs @@ -7,15 +7,14 @@ allow(clippy::too_many_arguments, clippy::cognitive_complexity) )] -use crate::disasm::{print_all, PrintRelocs, PrintStackMaps, PrintTraps}; +use crate::disasm::print_all; use crate::utils::parse_sets_and_triple; use anyhow::{Context as _, Result}; -use cranelift_codegen::binemit::{RelocSink, StackMapSink, TrapSink}; use cranelift_codegen::ir::DisplayFunctionAnnotations; use cranelift_codegen::print_errors::{pretty_error, pretty_verifier_error}; use cranelift_codegen::settings::FlagsOrIsa; +use cranelift_codegen::timing; use cranelift_codegen::Context; -use cranelift_codegen::{timing, MachReloc, MachStackMap, MachTrap}; use cranelift_entity::EntityRef; use cranelift_wasm::{translate_module, DummyEnvironment, FuncIndex, ReturnMode}; use std::io::Read; @@ -259,45 +258,17 @@ fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) - let mut saved_size = None; let func_index = num_func_imports + def_index.index(); let mut mem = vec![]; - let mut relocs = PrintRelocs::new(options.print); - let mut traps = PrintTraps::new(options.print); - let mut stack_maps = PrintStackMaps::new(options.print); - if options.check_translation { + let (relocs, traps, stack_maps) = if options.check_translation { if let Err(errors) = context.verify(fisa) { anyhow::bail!("{}", pretty_verifier_error(&context.func, None, errors)); } + (vec![], vec![], vec![]) } else { context .compile_and_emit(isa, &mut mem) .map_err(|err| anyhow::anyhow!("{}", pretty_error(&context.func, err)))?; let result = context.mach_compile_result.as_ref().unwrap(); let code_info = result.code_info(); - for &MachReloc { - offset, - srcloc, - kind, - ref name, - addend, - } in result.buffer.relocs() - { - relocs.reloc_external(offset, srcloc, kind, name, addend); - } - for &MachTrap { - offset, - srcloc, - code, - } in result.buffer.traps() - { - traps.trap(offset, srcloc, code); - } - for &MachStackMap { - offset_end, - ref stack_map, - .. - } in result.buffer.stack_maps() - { - stack_maps.add_stack_map(offset_end, stack_map.clone()); - } if options.print_size { println!( @@ -315,7 +286,12 @@ fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) - if options.disasm { saved_size = Some(code_info.total_size); } - } + ( + result.buffer.relocs().to_vec(), + result.buffer.traps().to_vec(), + result.buffer.stack_maps().to_vec(), + ) + }; if options.print { vprintln!(options.verbose, ""); @@ -351,7 +327,15 @@ fn handle_module(options: &Options, path: &Path, name: &str, fisa: FlagsOrIsa) - } if let Some(total_size) = saved_size { - print_all(isa, &mem, total_size, &relocs, &traps, &stack_maps)?; + print_all( + isa, + &mem, + total_size, + options.print, + &relocs, + &traps, + &stack_maps, + )?; } context.clear(); diff --git a/crates/cranelift/src/compiler.rs b/crates/cranelift/src/compiler.rs index 278aeabbed..5adcce21e2 100644 --- a/crates/cranelift/src/compiler.rs +++ b/crates/cranelift/src/compiler.rs @@ -7,11 +7,10 @@ use crate::{ CompiledFunction, FunctionAddressMap, Relocation, RelocationTarget, }; use anyhow::{Context as _, Result}; -use cranelift_codegen::binemit::{RelocSink as _, StackMapSink as _, TrapSink as _}; use cranelift_codegen::ir::{self, ExternalName, InstBuilder, MemFlags}; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::print_errors::pretty_error; -use cranelift_codegen::{binemit, Context}; +use cranelift_codegen::Context; use cranelift_codegen::{settings, MachReloc, MachTrap}; use cranelift_codegen::{MachSrcLoc, MachStackMap}; use cranelift_entity::{EntityRef, PrimaryMap}; @@ -167,40 +166,85 @@ impl wasmtime_environ::Compiler for Compiler { self.save_translator(func_translator); let mut code_buf: Vec = Vec::new(); - let mut reloc_sink = RelocSink::new(); - let mut trap_sink = TrapSink::new(); - let mut stack_map_sink = StackMapSink::default(); context .compile_and_emit(isa, &mut code_buf) .map_err(|error| CompileError::Codegen(pretty_error(&context.func, error)))?; let result = context.mach_compile_result.as_ref().unwrap(); + + let mut func_relocs = Vec::new(); for &MachReloc { offset, - srcloc, + srcloc: _, kind, ref name, addend, } in result.buffer.relocs() { - reloc_sink.reloc_external(offset, srcloc, kind, name, addend); + let reloc_target = if let ExternalName::User { namespace, index } = *name { + debug_assert_eq!(namespace, 0); + RelocationTarget::UserFunc(FuncIndex::from_u32(index)) + } else if let ExternalName::LibCall(libcall) = *name { + RelocationTarget::LibCall(libcall) + } else { + panic!("unrecognized external name") + }; + func_relocs.push(Relocation { + reloc: kind, + reloc_target, + offset, + addend, + }); } + + let mut traps = Vec::new(); for &MachTrap { offset, - srcloc, + srcloc: _, code, } in result.buffer.traps() { - trap_sink.trap(offset, srcloc, code); + traps.push(TrapInformation { + code_offset: offset, + trap_code: match code { + ir::TrapCode::StackOverflow => TrapCode::StackOverflow, + ir::TrapCode::HeapOutOfBounds => TrapCode::HeapOutOfBounds, + ir::TrapCode::HeapMisaligned => TrapCode::HeapMisaligned, + ir::TrapCode::TableOutOfBounds => TrapCode::TableOutOfBounds, + ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull, + ir::TrapCode::BadSignature => TrapCode::BadSignature, + ir::TrapCode::IntegerOverflow => TrapCode::IntegerOverflow, + ir::TrapCode::IntegerDivisionByZero => TrapCode::IntegerDivisionByZero, + ir::TrapCode::BadConversionToInteger => TrapCode::BadConversionToInteger, + ir::TrapCode::UnreachableCodeReached => TrapCode::UnreachableCodeReached, + ir::TrapCode::Interrupt => TrapCode::Interrupt, + + // these should never be emitted by wasmtime-cranelift + ir::TrapCode::User(_) => unreachable!(), + }, + }); } + + // This is converting from Cranelift's representation of a stack map to + // Wasmtime's representation. They happen to align today but that may + // not always be true in the future. + let mut stack_maps = Vec::new(); for &MachStackMap { offset_end, ref stack_map, .. } in result.buffer.stack_maps() { - stack_map_sink.add_stack_map(offset_end, stack_map.clone()); + let stack_map = wasmtime_environ::StackMap::new( + stack_map.mapped_words(), + stack_map.as_slice().iter().map(|a| a.0), + ); + stack_maps.push(StackMapInformation { + code_offset: offset_end, + stack_map, + }); } + stack_maps.sort_unstable_by_key(|info| info.code_offset); let unwind_info = context .create_unwind_info(isa) @@ -229,14 +273,14 @@ impl wasmtime_environ::Compiler for Compiler { let length = u32::try_from(code_buf.len()).unwrap(); Ok(Box::new(CompiledFunction { body: code_buf, - relocations: reloc_sink.func_relocs, + relocations: func_relocs, value_labels_ranges: ranges.unwrap_or(Default::default()), stack_slots: context.func.stack_slots, unwind_info, - traps: trap_sink.traps, + traps, info: FunctionInfo { start_srcloc: address_transform.start_srcloc, - stack_maps: stack_map_sink.finish(), + stack_maps, start: 0, length, }, @@ -557,14 +601,14 @@ impl Compiler { isa: &dyn TargetIsa, ) -> Result { let mut code_buf = Vec::new(); - let mut reloc_sink = TrampolineRelocSink::default(); + let mut relocs = Vec::new(); context .compile_and_emit(isa, &mut code_buf) .map_err(|error| CompileError::Codegen(pretty_error(&context.func, error)))?; for &MachReloc { offset, - srcloc, + srcloc: _, kind, ref name, addend, @@ -575,7 +619,17 @@ impl Compiler { .buffer .relocs() { - reloc_sink.reloc_external(offset, srcloc, kind, name, addend); + let reloc_target = if let ir::ExternalName::LibCall(libcall) = *name { + RelocationTarget::LibCall(libcall) + } else { + panic!("unrecognized external name") + }; + relocs.push(Relocation { + reloc: kind, + reloc_target, + offset, + addend, + }); } let unwind_info = context @@ -585,7 +639,7 @@ impl Compiler { Ok(CompiledFunction { body: code_buf, unwind_info, - relocations: reloc_sink.relocs, + relocations: relocs, stack_slots: Default::default(), value_labels_ranges: Default::default(), info: Default::default(), @@ -657,146 +711,3 @@ fn collect_address_maps( } } } - -/// Implementation of a relocation sink that just saves all the information for later -struct RelocSink { - /// Relocations recorded for the function. - func_relocs: Vec, -} - -impl binemit::RelocSink for RelocSink { - fn reloc_external( - &mut self, - offset: binemit::CodeOffset, - _srcloc: ir::SourceLoc, - reloc: binemit::Reloc, - name: &ExternalName, - addend: binemit::Addend, - ) { - let reloc_target = if let ExternalName::User { namespace, index } = *name { - debug_assert_eq!(namespace, 0); - RelocationTarget::UserFunc(FuncIndex::from_u32(index)) - } else if let ExternalName::LibCall(libcall) = *name { - RelocationTarget::LibCall(libcall) - } else { - panic!("unrecognized external name") - }; - self.func_relocs.push(Relocation { - reloc, - reloc_target, - offset, - addend, - }); - } -} - -impl RelocSink { - /// Return a new `RelocSink` instance. - fn new() -> Self { - Self { - func_relocs: Vec::new(), - } - } -} - -/// Implementation of a trap sink that simply stores all trap info in-memory -#[derive(Default)] -struct TrapSink { - /// The in-memory vector of trap info - traps: Vec, -} - -impl TrapSink { - /// Create a new `TrapSink` - fn new() -> Self { - Self::default() - } -} - -impl binemit::TrapSink for TrapSink { - fn trap( - &mut self, - code_offset: binemit::CodeOffset, - _source_loc: ir::SourceLoc, - trap_code: ir::TrapCode, - ) { - self.traps.push(TrapInformation { - code_offset, - trap_code: match trap_code { - ir::TrapCode::StackOverflow => TrapCode::StackOverflow, - ir::TrapCode::HeapOutOfBounds => TrapCode::HeapOutOfBounds, - ir::TrapCode::HeapMisaligned => TrapCode::HeapMisaligned, - ir::TrapCode::TableOutOfBounds => TrapCode::TableOutOfBounds, - ir::TrapCode::IndirectCallToNull => TrapCode::IndirectCallToNull, - ir::TrapCode::BadSignature => TrapCode::BadSignature, - ir::TrapCode::IntegerOverflow => TrapCode::IntegerOverflow, - ir::TrapCode::IntegerDivisionByZero => TrapCode::IntegerDivisionByZero, - ir::TrapCode::BadConversionToInteger => TrapCode::BadConversionToInteger, - ir::TrapCode::UnreachableCodeReached => TrapCode::UnreachableCodeReached, - ir::TrapCode::Interrupt => TrapCode::Interrupt, - - // these should never be emitted by wasmtime-cranelift - ir::TrapCode::User(_) => unreachable!(), - }, - }); - } -} - -#[derive(Default)] -struct StackMapSink { - infos: Vec, -} - -impl binemit::StackMapSink for StackMapSink { - fn add_stack_map(&mut self, code_offset: binemit::CodeOffset, stack_map: binemit::StackMap) { - // This is converting from Cranelift's representation of a stack map to - // Wasmtime's representation. They happen to align today but that may - // not always be true in the future. - let stack_map = wasmtime_environ::StackMap::new( - stack_map.mapped_words(), - stack_map.as_slice().iter().map(|a| a.0), - ); - self.infos.push(StackMapInformation { - code_offset, - stack_map, - }); - } -} - -impl StackMapSink { - fn finish(mut self) -> Vec { - self.infos.sort_unstable_by_key(|info| info.code_offset); - self.infos - } -} - -/// We don't expect trampoline compilation to produce many relocations, so -/// this `RelocSink` just asserts that it doesn't recieve most of them, but -/// handles libcall ones. -#[derive(Default)] -struct TrampolineRelocSink { - relocs: Vec, -} - -impl binemit::RelocSink for TrampolineRelocSink { - fn reloc_external( - &mut self, - offset: binemit::CodeOffset, - _srcloc: ir::SourceLoc, - reloc: binemit::Reloc, - name: &ir::ExternalName, - addend: binemit::Addend, - ) { - let reloc_target = if let ir::ExternalName::LibCall(libcall) = *name { - RelocationTarget::LibCall(libcall) - } else { - panic!("unrecognized external name") - }; - self.relocs.push(Relocation { - reloc, - reloc_target, - offset, - addend, - }); - } -}