diff --git a/cranelift/module/src/backend.rs b/cranelift/module/src/backend.rs deleted file mode 100644 index 9b9df893b2..0000000000 --- a/cranelift/module/src/backend.rs +++ /dev/null @@ -1,128 +0,0 @@ -//! Defines the `Backend` trait. - -use crate::module::ModuleCompiledFunction; -use crate::DataContext; -use crate::DataId; -use crate::FuncId; -use crate::Linkage; -use crate::ModuleDeclarations; -use crate::ModuleResult; -use core::marker; -use cranelift_codegen::isa::TargetIsa; -use cranelift_codegen::Context; -use cranelift_codegen::{binemit, ir}; - -use std::borrow::ToOwned; -use std::boxed::Box; -use std::string::String; - -/// A `Backend` implements the functionality needed to support a `Module`. -/// -/// Three notable implementations of this trait are: -/// - `SimpleJITBackend`, defined in [cranelift-simplejit], which JITs -/// the contents of a `Module` to memory which can be directly executed. -/// - `ObjectBackend`, defined in [cranelift-object], which writes the -/// contents of a `Module` out as a native object file. -/// -/// [cranelift-simplejit]: https://docs.rs/cranelift-simplejit/ -/// [cranelift-object]: https://docs.rs/cranelift-object/ -pub trait Backend -where - Self: marker::Sized, -{ - /// A builder for constructing `Backend` instances. - type Builder; - - /// This is an object returned by `Module`'s - /// [`finish`](struct.Module.html#method.finish) function, - /// if the `Backend` has a purpose for this. - type Product; - - /// Create a new `Backend` instance. - fn new(_: Self::Builder) -> Self; - - /// Return the `TargetIsa` to compile for. - fn isa(&self) -> &dyn TargetIsa; - - /// Get all declarations in this module. - fn declarations(&self) -> &ModuleDeclarations; - - /// Declare a function. - fn declare_function( - &mut self, - name: &str, - linkage: Linkage, - signature: &ir::Signature, - ) -> ModuleResult; - - /// Declare a data object. - fn declare_data( - &mut self, - name: &str, - linkage: Linkage, - writable: bool, - tls: bool, - ) -> ModuleResult; - - /// Define a function, producing the function body from the given `Context`. - /// - /// Functions must be declared before being defined. - fn define_function( - &mut self, - func: FuncId, - ctx: &mut Context, - trap_sink: &mut TS, - ) -> ModuleResult - where - TS: binemit::TrapSink; - - /// Define a function, taking the function body from the given `bytes`. - /// - /// Functions must be declared before being defined. - fn define_function_bytes( - &mut self, - id: FuncId, - bytes: &[u8], - ) -> ModuleResult; - - /// Define a zero-initialized data object of the given size. - /// - /// Data objects must be declared before being defined. - fn define_data( - &mut self, - id: DataId, - data_ctx: &DataContext, - ) -> ModuleResult<()>; - - /// Consume this `Backend` and return a result. Some implementations may - /// provide additional functionality through this result. - fn finish(self) -> Self::Product; -} - -/// Default names for `ir::LibCall`s. A function by this name is imported into the object as -/// part of the translation of a `ir::ExternalName::LibCall` variant. -pub fn default_libcall_names() -> Box String> { - Box::new(move |libcall| match libcall { - ir::LibCall::Probestack => "__cranelift_probestack".to_owned(), - ir::LibCall::UdivI64 => "__udivdi3".to_owned(), - ir::LibCall::SdivI64 => "__divdi3".to_owned(), - ir::LibCall::UremI64 => "__umoddi3".to_owned(), - ir::LibCall::SremI64 => "__moddi3".to_owned(), - ir::LibCall::IshlI64 => "__ashldi3".to_owned(), - ir::LibCall::UshrI64 => "__lshrdi3".to_owned(), - ir::LibCall::SshrI64 => "__ashrdi3".to_owned(), - ir::LibCall::CeilF32 => "ceilf".to_owned(), - ir::LibCall::CeilF64 => "ceil".to_owned(), - ir::LibCall::FloorF32 => "floorf".to_owned(), - ir::LibCall::FloorF64 => "floor".to_owned(), - ir::LibCall::TruncF32 => "truncf".to_owned(), - ir::LibCall::TruncF64 => "trunc".to_owned(), - ir::LibCall::NearestF32 => "nearbyintf".to_owned(), - ir::LibCall::NearestF64 => "nearbyint".to_owned(), - ir::LibCall::Memcpy => "memcpy".to_owned(), - ir::LibCall::Memset => "memset".to_owned(), - ir::LibCall::Memmove => "memmove".to_owned(), - - ir::LibCall::ElfTlsGetAddr => "__tls_get_addr".to_owned(), - }) -} diff --git a/cranelift/module/src/lib.rs b/cranelift/module/src/lib.rs index b04d29b87c..9292a9b188 100644 --- a/cranelift/module/src/lib.rs +++ b/cranelift/module/src/lib.rs @@ -29,15 +29,18 @@ extern crate std; #[cfg(not(feature = "std"))] use hashbrown::{hash_map, HashMap}; +use std::borrow::ToOwned; +use std::boxed::Box; #[cfg(feature = "std")] use std::collections::{hash_map, HashMap}; +use std::string::String; + +use cranelift_codegen::ir; -mod backend; mod data_context; mod module; mod traps; -pub use crate::backend::{default_libcall_names, Backend}; pub use crate::data_context::{DataContext, DataDescription, Init}; pub use crate::module::{ DataId, FuncId, FuncOrDataId, Linkage, Module, ModuleCompiledFunction, ModuleDeclarations, @@ -47,3 +50,31 @@ pub use crate::traps::TrapSite; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +/// Default names for `ir::LibCall`s. A function by this name is imported into the object as +/// part of the translation of a `ir::ExternalName::LibCall` variant. +pub fn default_libcall_names() -> Box String> { + Box::new(move |libcall| match libcall { + ir::LibCall::Probestack => "__cranelift_probestack".to_owned(), + ir::LibCall::UdivI64 => "__udivdi3".to_owned(), + ir::LibCall::SdivI64 => "__divdi3".to_owned(), + ir::LibCall::UremI64 => "__umoddi3".to_owned(), + ir::LibCall::SremI64 => "__moddi3".to_owned(), + ir::LibCall::IshlI64 => "__ashldi3".to_owned(), + ir::LibCall::UshrI64 => "__lshrdi3".to_owned(), + ir::LibCall::SshrI64 => "__ashrdi3".to_owned(), + ir::LibCall::CeilF32 => "ceilf".to_owned(), + ir::LibCall::CeilF64 => "ceil".to_owned(), + ir::LibCall::FloorF32 => "floorf".to_owned(), + ir::LibCall::FloorF64 => "floor".to_owned(), + ir::LibCall::TruncF32 => "truncf".to_owned(), + ir::LibCall::TruncF64 => "trunc".to_owned(), + ir::LibCall::NearestF32 => "nearbyintf".to_owned(), + ir::LibCall::NearestF64 => "nearbyint".to_owned(), + ir::LibCall::Memcpy => "memcpy".to_owned(), + ir::LibCall::Memset => "memset".to_owned(), + ir::LibCall::Memmove => "memmove".to_owned(), + + ir::LibCall::ElfTlsGetAddr => "__tls_get_addr".to_owned(), + }) +} diff --git a/cranelift/module/src/module.rs b/cranelift/module/src/module.rs index bc1d0ac2f8..84fc19c96f 100644 --- a/cranelift/module/src/module.rs +++ b/cranelift/module/src/module.rs @@ -7,7 +7,6 @@ use super::HashMap; use crate::data_context::DataContext; -use crate::Backend; use cranelift_codegen::binemit; use cranelift_codegen::entity::{entity_impl, PrimaryMap}; use cranelift_codegen::{ir, isa, CodegenError, Context}; @@ -318,40 +317,29 @@ impl ModuleDeclarations { } } -/// A `Module` is a utility for collecting functions and data objects, and linking them together. -pub struct Module -where - B: Backend, -{ - backend: B, -} - /// Information about the compiled function. pub struct ModuleCompiledFunction { /// The size of the compiled function. pub size: binemit::CodeOffset, } -impl Module -where - B: Backend, -{ - /// Create a new `Module`. - pub fn new(backend_builder: B::Builder) -> Self { - Self { - backend: B::new(backend_builder), - } - } +/// A `Module` is a utility for collecting functions and data objects, and linking them together. +pub trait Module { + /// Return the `TargetIsa` to compile for. + fn isa(&self) -> &dyn isa::TargetIsa; + + /// Get all declarations in this module. + fn declarations(&self) -> &ModuleDeclarations; /// Get the module identifier for a given name, if that name /// has been declared. - pub fn get_name(&self, name: &str) -> Option { - self.backend.declarations().get_name(name) + fn get_name(&self, name: &str) -> Option { + self.declarations().get_name(name) } /// Return the target information needed by frontends to produce Cranelift IR /// for the current target. - pub fn target_config(&self) -> isa::TargetFrontendConfig { + fn target_config(&self) -> isa::TargetFrontendConfig { self.isa().frontend_config() } @@ -359,7 +347,7 @@ where /// /// This ensures that the `Context` is initialized with the default calling /// convention for the `TargetIsa`. - pub fn make_context(&self) -> Context { + fn make_context(&self) -> Context { let mut ctx = Context::new(); ctx.func.signature.call_conv = self.isa().default_call_conv(); ctx @@ -369,7 +357,7 @@ where /// /// This ensures that the `Context` is initialized with the default calling /// convention for the `TargetIsa`. - pub fn clear_context(&self, ctx: &mut Context) { + fn clear_context(&self, ctx: &mut Context) { ctx.clear(); ctx.func.signature.call_conv = self.isa().default_call_conv(); } @@ -377,7 +365,7 @@ where /// Create a new empty `Signature` with the default calling convention for /// the `TargetIsa`, to which parameter and return types can be added for /// declaring a function to be called by this `Module`. - pub fn make_signature(&self) -> ir::Signature { + fn make_signature(&self) -> ir::Signature { ir::Signature::new(self.isa().default_call_conv()) } @@ -385,38 +373,33 @@ where /// /// This ensures that the `Signature` is initialized with the default /// calling convention for the `TargetIsa`. - pub fn clear_signature(&self, sig: &mut ir::Signature) { + fn clear_signature(&self, sig: &mut ir::Signature) { sig.clear(self.isa().default_call_conv()); } /// Declare a function in this module. - pub fn declare_function( + fn declare_function( &mut self, name: &str, linkage: Linkage, signature: &ir::Signature, - ) -> ModuleResult { - self.backend.declare_function(name, linkage, signature) - } + ) -> ModuleResult; /// Declare a data object in this module. - pub fn declare_data( + fn declare_data( &mut self, name: &str, linkage: Linkage, writable: bool, tls: bool, - ) -> ModuleResult { - self.backend - .declare_data(name, linkage, writable, tls) - } + ) -> ModuleResult; /// Use this when you're building the IR of a function to reference a function. /// /// TODO: Coalesce redundant decls and signatures. /// TODO: Look into ways to reduce the risk of using a FuncRef in the wrong function. - pub fn declare_func_in_func(&self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef { - let decl = &self.backend.declarations().functions[func]; + fn declare_func_in_func(&self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef { + let decl = &self.declarations().functions[func]; let signature = in_func.import_signature(decl.signature.clone()); let colocated = decl.linkage.is_final(); in_func.import_function(ir::ExtFuncData { @@ -429,8 +412,8 @@ where /// Use this when you're building the IR of a function to reference a data object. /// /// TODO: Same as above. - pub fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { - let decl = &self.backend.declarations().data_objects[data]; + fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { + let decl = &self.declarations().data_objects[data]; let colocated = decl.linkage.is_final(); func.create_global_value(ir::GlobalValueData::Symbol { name: ir::ExternalName::user(1, data.as_u32()), @@ -441,12 +424,12 @@ where } /// TODO: Same as above. - pub fn declare_func_in_data(&self, func: FuncId, ctx: &mut DataContext) -> ir::FuncRef { + fn declare_func_in_data(&self, func: FuncId, ctx: &mut DataContext) -> ir::FuncRef { ctx.import_function(ir::ExternalName::user(0, func.as_u32())) } /// TODO: Same as above. - pub fn declare_data_in_data(&self, data: DataId, ctx: &mut DataContext) -> ir::GlobalValue { + fn declare_data_in_data(&self, data: DataId, ctx: &mut DataContext) -> ir::GlobalValue { ctx.import_global_value(ir::ExternalName::user(1, data.as_u32())) } @@ -455,17 +438,14 @@ where /// Returns the size of the function's code and constant data. /// /// Note: After calling this function the given `Context` will contain the compiled function. - pub fn define_function( + fn define_function( &mut self, func: FuncId, ctx: &mut Context, trap_sink: &mut TS, ) -> ModuleResult where - TS: binemit::TrapSink, - { - self.backend.define_function(func, ctx, trap_sink) - } + TS: binemit::TrapSink; /// Define a function, taking the function body from the given `bytes`. /// @@ -474,28 +454,12 @@ where /// `define_function`. /// /// Returns the size of the function's code. - pub fn define_function_bytes( + fn define_function_bytes( &mut self, func: FuncId, bytes: &[u8], - ) -> ModuleResult { - self.backend.define_function_bytes(func, bytes) - } + ) -> ModuleResult; /// Define a data object, producing the data contents from the given `DataContext`. - pub fn define_data(&mut self, data: DataId, data_ctx: &DataContext) -> ModuleResult<()> { - self.backend.define_data(data, data_ctx) - } - - /// Return the target isa - pub fn isa(&self) -> &dyn isa::TargetIsa { - self.backend.isa() - } - - /// Consume the module and return the resulting `Product`. Some `Backend` - /// implementations may provide additional functionality available after - /// a `Module` is complete. - pub fn finish(self) -> B::Product { - self.backend.finish() - } + fn define_data(&mut self, data: DataId, data_ctx: &DataContext) -> ModuleResult<()>; } diff --git a/cranelift/object/src/backend.rs b/cranelift/object/src/backend.rs index e4faed3e4a..a0c964cd09 100644 --- a/cranelift/object/src/backend.rs +++ b/cranelift/object/src/backend.rs @@ -8,7 +8,7 @@ use cranelift_codegen::entity::SecondaryMap; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::{self, ir}; use cranelift_module::{ - Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleCompiledFunction, + DataContext, DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleCompiledFunction, ModuleDeclarations, ModuleError, ModuleResult, }; use log::info; @@ -108,10 +108,10 @@ impl ObjectBuilder { } } -/// A `ObjectBackend` implements `Backend` and emits ".o" files using the `object` library. +/// An `ObjectModule` implements `Module` and emits ".o" files using the `object` library. /// -/// See the `ObjectBuilder` for a convenient way to construct `ObjectBackend` instances. -pub struct ObjectBackend { +/// See the `ObjectBuilder` for a convenient way to construct `ObjectModule` instances. +pub struct ObjectModule { isa: Box, object: Object, declarations: ModuleDeclarations, @@ -124,13 +124,9 @@ pub struct ObjectBackend { per_function_section: bool, } -impl Backend for ObjectBackend { - type Builder = ObjectBuilder; - - type Product = ObjectProduct; - - /// Create a new `ObjectBackend` using the given Cranelift target. - fn new(builder: ObjectBuilder) -> Self { +impl ObjectModule { + /// Create a new `ObjectModule` using the given Cranelift target. + pub fn new(builder: ObjectBuilder) -> Self { let mut object = Object::new(builder.binary_format, builder.architecture, builder.endian); object.add_file_symbol(builder.name); Self { @@ -146,7 +142,9 @@ impl Backend for ObjectBackend { per_function_section: builder.per_function_section, } } +} +impl Module for ObjectModule { fn isa(&self) -> &dyn TargetIsa { &*self.isa } @@ -452,8 +450,11 @@ impl Backend for ObjectBackend { } Ok(()) } +} - fn finish(mut self) -> ObjectProduct { +impl ObjectModule { + /// Finalize all relocations and output an object. + pub fn finish(mut self) -> ObjectProduct { let symbol_relocs = mem::take(&mut self.relocs); for symbol in symbol_relocs { for &RelocRecord { @@ -497,11 +498,9 @@ impl Backend for ObjectBackend { data_objects: self.data_objects, } } -} -impl ObjectBackend { - // This should only be called during finish because it creates - // symbols for missing libcalls. + /// This should only be called during finish because it creates + /// symbols for missing libcalls. fn get_symbol(&mut self, name: &ir::ExternalName) -> SymbolId { match *name { ir::ExternalName::User { .. } => { diff --git a/cranelift/object/src/lib.rs b/cranelift/object/src/lib.rs index 0eeaec1484..12ca1d7aca 100644 --- a/cranelift/object/src/lib.rs +++ b/cranelift/object/src/lib.rs @@ -27,7 +27,7 @@ mod backend; -pub use crate::backend::{ObjectBackend, ObjectBuilder, ObjectProduct}; +pub use crate::backend::{ObjectModule, ObjectBuilder, ObjectProduct}; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/cranelift/simplejit/src/backend.rs b/cranelift/simplejit/src/backend.rs index 9910fdc625..5d42be75fe 100644 --- a/cranelift/simplejit/src/backend.rs +++ b/cranelift/simplejit/src/backend.rs @@ -1,4 +1,4 @@ -//! Defines `SimpleJITBackend`. +//! Defines `SimpleJITModule`. use crate::memory::Memory; use cranelift_codegen::binemit::{ @@ -9,7 +9,7 @@ use cranelift_codegen::settings::Configurable; use cranelift_codegen::{self, ir, settings}; use cranelift_entity::SecondaryMap; use cranelift_module::{ - Backend, DataContext, DataDescription, DataId, FuncId, FuncOrDataId, Init, Linkage, + DataContext, DataDescription, DataId, FuncId, FuncOrDataId, Init, Linkage, Module, ModuleCompiledFunction, ModuleDeclarations, ModuleError, ModuleResult, }; use cranelift_native; @@ -29,7 +29,7 @@ const EXECUTABLE_DATA_ALIGNMENT: u64 = 0x10; const WRITABLE_DATA_ALIGNMENT: u64 = 0x8; const READONLY_DATA_ALIGNMENT: u64 = 0x1; -/// A builder for `SimpleJITBackend`. +/// A builder for `SimpleJITModule`. pub struct SimpleJITBuilder { isa: Box, symbols: HashMap, @@ -118,11 +118,11 @@ impl SimpleJITBuilder { } } -/// A `SimpleJITBackend` implements `Backend` and emits code and data into memory where it can be +/// A `SimpleJITModule` implements `Module` and emits code and data into memory where it can be /// directly called and accessed. /// -/// See the `SimpleJITBuilder` for a convenient way to construct `SimpleJITBackend` instances. -pub struct SimpleJITBackend { +/// See the `SimpleJITBuilder` for a convenient way to construct `SimpleJITModule` instances. +pub struct SimpleJITModule { isa: Box, symbols: HashMap, libcall_names: Box String>, @@ -217,7 +217,7 @@ impl SimpleJITProduct { } } -impl SimpleJITBackend { +impl SimpleJITModule { fn lookup_symbol(&self, name: &str) -> *const u8 { match self.symbols.get(name) { Some(&ptr) => ptr, @@ -232,7 +232,9 @@ impl SimpleJITBackend { let func_id = self.declarations.get_function_id(name); match &self.functions[func_id] { Some(compiled) => compiled.code, - None => self.lookup_symbol(&self.declarations.get_function_decl(func_id).name), + None => { + self.lookup_symbol(&self.declarations.get_function_decl(func_id).name) + } } } else { let data_id = self.declarations.get_data_id(name); @@ -357,19 +359,9 @@ impl SimpleJITBackend { } } } -} - -impl<'simple_jit_backend> Backend for SimpleJITBackend { - type Builder = SimpleJITBuilder; - - /// SimpleJIT emits code and data into memory as it processes them, so it - /// doesn't need to provide anything after the `Module` is complete. - /// The handle object that is returned can optionally be used to free - /// allocated memory if required. - type Product = SimpleJITProduct; /// Create a new `SimpleJITBackend`. - fn new(builder: SimpleJITBuilder) -> Self { + pub fn new(builder: SimpleJITBuilder) -> Self { let memory = SimpleJITMemoryHandle { code: Memory::new(), readonly: Memory::new(), @@ -388,7 +380,9 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { data_objects_to_finalize: Vec::new(), } } +} +impl<'simple_jit_backend> Module for SimpleJITModule { fn isa(&self) -> &dyn TargetIsa { &*self.isa } @@ -601,7 +595,9 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { Ok(()) } +} +impl SimpleJITModule { /// SimpleJIT emits code and data into memory as it processes them. This /// method performs no additional processing, but returns a handle which /// allows freeing the allocated memory. Otherwise said memory is leaked @@ -609,7 +605,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { /// /// This method does not need to be called when access to the memory /// handle is not required. - fn finish(mut self) -> Self::Product { + pub fn finish(mut self) -> SimpleJITProduct { for func in std::mem::take(&mut self.functions_to_finalize) { let decl = self.declarations.get_function_decl(func); debug_assert!(decl.linkage.is_definable()); diff --git a/cranelift/simplejit/src/lib.rs b/cranelift/simplejit/src/lib.rs index 705b8decfc..831dc751b2 100644 --- a/cranelift/simplejit/src/lib.rs +++ b/cranelift/simplejit/src/lib.rs @@ -26,7 +26,7 @@ mod backend; mod memory; -pub use crate::backend::{SimpleJITBackend, SimpleJITBuilder, SimpleJITProduct}; +pub use crate::backend::{SimpleJITModule, SimpleJITBuilder, SimpleJITProduct}; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION");