diff --git a/cranelift/module/src/backend.rs b/cranelift/module/src/backend.rs index 0d4b5e8e5f..32fcd6cf7c 100644 --- a/cranelift/module/src/backend.rs +++ b/cranelift/module/src/backend.rs @@ -1,19 +1,19 @@ //! Defines the `Backend` trait. -use crate::{DataContext, FuncOrDataId}; use crate::DataId; use crate::FuncId; use crate::Linkage; -use crate::ModuleContents; +use crate::ModuleDeclarations; use crate::ModuleResult; +use crate::{DataContext, FuncOrDataId}; use core::marker; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::Context; use cranelift_codegen::{binemit, ir}; -use std::{borrow::ToOwned, collections::HashMap}; use std::boxed::Box; use std::string::String; +use std::{borrow::ToOwned, collections::HashMap}; /// A `Backend` implements the functionality needed to support a `Module`. /// @@ -32,12 +32,6 @@ where /// A builder for constructing `Backend` instances. type Builder; - /// The results of compiling a function. - type CompiledFunction; - - /// The results of "compiling" a data object. - type CompiledData; - /// This is an object returned by `Module`'s /// [`finish`](struct.Module.html#method.finish) function, /// if the `Backend` has a purpose for this. @@ -71,10 +65,10 @@ where id: FuncId, name: &str, ctx: &Context, - contents: &ModuleContents, + declarations: &ModuleDeclarations, code_size: u32, trap_sink: &mut TS, - ) -> ModuleResult + ) -> ModuleResult<()> where TS: binemit::TrapSink; @@ -86,8 +80,8 @@ where id: FuncId, name: &str, bytes: &[u8], - contents: &ModuleContents, - ) -> ModuleResult; + declarations: &ModuleDeclarations, + ) -> ModuleResult<()>; /// Define a zero-initialized data object of the given size. /// @@ -100,15 +94,15 @@ where tls: bool, align: Option, data_ctx: &DataContext, - contents: &ModuleContents, - ) -> ModuleResult; + declarations: &ModuleDeclarations, + ) -> ModuleResult<()>; /// Consume this `Backend` and return a result. Some implementations may /// provide additional functionality through this result. fn finish( self, names: HashMap, - contents: ModuleContents, + declarations: ModuleDeclarations, ) -> Self::Product; } diff --git a/cranelift/module/src/lib.rs b/cranelift/module/src/lib.rs index 6331cfac1f..713739f893 100644 --- a/cranelift/module/src/lib.rs +++ b/cranelift/module/src/lib.rs @@ -40,8 +40,7 @@ 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, ModuleContents, ModuleError, ModuleFunction, - ModuleResult, + DataId, FuncId, FuncOrDataId, Linkage, Module, ModuleDeclarations, ModuleError, ModuleResult, }; pub use crate::traps::TrapSite; diff --git a/cranelift/module/src/module.rs b/cranelift/module/src/module.rs index f95ee5e27e..f83d8f4ef5 100644 --- a/cranelift/module/src/module.rs +++ b/cranelift/module/src/module.rs @@ -15,7 +15,6 @@ use log::info; use std::borrow::ToOwned; use std::convert::TryInto; use std::string::String; -use std::vec::Vec; use thiserror::Error; /// A function identifier for use in the `Module` interface. @@ -132,6 +131,20 @@ pub struct FunctionDeclaration { pub signature: ir::Signature, } +impl FunctionDeclaration { + fn merge(&mut self, linkage: Linkage, sig: &ir::Signature) -> Result<(), ModuleError> { + self.linkage = Linkage::merge(self.linkage, linkage); + if &self.signature != sig { + return Err(ModuleError::IncompatibleSignature( + self.name.clone(), + self.signature.clone(), + sig.clone(), + )); + } + Ok(()) + } +} + /// Error messages for all `Module` and `Backend` methods #[derive(Error, Debug)] pub enum ModuleError { @@ -165,44 +178,6 @@ pub enum ModuleError { /// A convenient alias for a `Result` that uses `ModuleError` as the error type. pub type ModuleResult = Result; -/// A function belonging to a `Module`. -pub struct ModuleFunction -where - B: Backend, -{ - /// The function declaration. - pub decl: FunctionDeclaration, - /// The compiled artifact, once it's available. - pub compiled: Option, -} - -impl ModuleFunction -where - B: Backend, -{ - fn merge(&mut self, linkage: Linkage, sig: &ir::Signature) -> Result<(), ModuleError> { - self.decl.linkage = Linkage::merge(self.decl.linkage, linkage); - if &self.decl.signature != sig { - return Err(ModuleError::IncompatibleSignature( - self.decl.name.clone(), - self.decl.signature.clone(), - sig.clone(), - )); - } - Ok(()) - } - - fn validate_for_define(&self) -> ModuleResult<()> { - if self.compiled.is_some() { - return Err(ModuleError::DuplicateDefinition(self.decl.name.clone())); - } - if !self.decl.linkage.is_definable() { - return Err(ModuleError::InvalidImportDefinition(self.decl.name.clone())); - } - Ok(()) - } -} - /// Information about a data object which can be accessed. pub struct DataDeclaration { pub name: String, @@ -212,56 +187,26 @@ pub struct DataDeclaration { pub align: Option, } -/// A data object belonging to a `Module`. -pub struct ModuleData -where - B: Backend, -{ - /// The data object declaration. - pub decl: DataDeclaration, - /// The "compiled" artifact, once it's available. - pub compiled: Option, -} - -impl ModuleData -where - B: Backend, -{ +impl DataDeclaration { fn merge(&mut self, linkage: Linkage, writable: bool, tls: bool, align: Option) { - self.decl.linkage = Linkage::merge(self.decl.linkage, linkage); - self.decl.writable = self.decl.writable || writable; - self.decl.align = self.decl.align.max(align); + self.linkage = Linkage::merge(self.linkage, linkage); + self.writable = self.writable || writable; + self.align = self.align.max(align); assert_eq!( - self.decl.tls, tls, + self.tls, tls, "Can't change TLS data object to normal or in the opposite way", ); } - - fn validate_for_define(&self) -> ModuleResult<()> { - if self.compiled.is_some() { - return Err(ModuleError::DuplicateDefinition(self.decl.name.clone())); - } - if !self.decl.linkage.is_definable() { - return Err(ModuleError::InvalidImportDefinition(self.decl.name.clone())); - } - Ok(()) - } } /// This provides a view to the state of a module which allows `ir::ExternalName`s to be translated /// into `FunctionDeclaration`s and `DataDeclaration`s. -pub struct ModuleContents -where - B: Backend, -{ - functions: PrimaryMap>, - data_objects: PrimaryMap>, +pub struct ModuleDeclarations { + functions: PrimaryMap, + data_objects: PrimaryMap, } -impl ModuleContents -where - B: Backend, -{ +impl ModuleDeclarations { /// Get the `FuncId` for the function named by `name`. pub fn get_function_id(&self, name: &ir::ExternalName) -> FuncId { if let ir::ExternalName::User { namespace, index } = *name { @@ -282,62 +227,14 @@ where } } - /// Get the `ModuleFunction` for the given function. - pub fn get_function_info(&self, func_id: FuncId) -> &ModuleFunction { + /// Get the `FunctionDeclaration` for the function named by `name`. + pub fn get_function_decl(&self, func_id: FuncId) -> &FunctionDeclaration { &self.functions[func_id] } - /// Get the `FunctionDeclaration` for the function named by `name`. - pub fn get_function_decl(&self, name: &ir::ExternalName) -> &FunctionDeclaration { - &self.functions[self.get_function_id(name)].decl - } - - /// Get the `ModuleData` for the given data object. - pub fn get_data_info(&self, data_id: DataId) -> &ModuleData { - &self.data_objects[data_id] - } - /// Get the `DataDeclaration` for the data object named by `name`. - pub fn get_data_decl(&self, name: &ir::ExternalName) -> &DataDeclaration { - &self.data_objects[self.get_data_id(name)].decl - } - - /// Get the definition for the function named by `name`, along with its name - /// and signature. - pub fn get_function_definition( - &self, - name: &ir::ExternalName, - ) -> (Option<&B::CompiledFunction>, &str, &ir::Signature) { - let info = &self.functions[self.get_function_id(name)]; - debug_assert!( - !info.decl.linkage.is_definable() || info.compiled.is_some(), - "Finalization requires a definition for function {}.", - name, - ); - debug_assert_eq!(info.decl.linkage.is_definable(), info.compiled.is_some()); - - ( - info.compiled.as_ref(), - &info.decl.name, - &info.decl.signature, - ) - } - - /// Get the definition for the data object named by `name`, along with its name - /// and writable flag - pub fn get_data_definition( - &self, - name: &ir::ExternalName, - ) -> (Option<&B::CompiledData>, &str, bool) { - let info = &self.data_objects[self.get_data_id(name)]; - debug_assert!( - !info.decl.linkage.is_definable() || info.compiled.is_some(), - "Finalization requires a definition for data object {}.", - name, - ); - debug_assert_eq!(info.decl.linkage.is_definable(), info.compiled.is_some()); - - (info.compiled.as_ref(), &info.decl.name, info.decl.writable) + pub fn get_data_decl(&self, data_id: DataId) -> &DataDeclaration { + &self.data_objects[data_id] } /// Return whether `name` names a function, rather than a data object. @@ -356,9 +253,7 @@ where B: Backend, { names: HashMap, - contents: ModuleContents, - functions_to_finalize: Vec, - data_objects_to_finalize: Vec, + declarations: ModuleDeclarations, backend: B, } @@ -374,12 +269,10 @@ where pub fn new(backend_builder: B::Builder) -> Self { Self { names: HashMap::new(), - contents: ModuleContents { + declarations: ModuleDeclarations { functions: PrimaryMap::new(), data_objects: PrimaryMap::new(), }, - functions_to_finalize: Vec::new(), - data_objects_to_finalize: Vec::new(), backend: B::new(backend_builder), } } @@ -442,10 +335,9 @@ where match self.names.entry(name.to_owned()) { Occupied(entry) => match *entry.get() { FuncOrDataId::Func(id) => { - let existing = &mut self.contents.functions[id]; + let existing = &mut self.declarations.functions[id]; existing.merge(linkage, signature)?; - self.backend - .declare_function(id, name, existing.decl.linkage); + self.backend.declare_function(id, name, existing.linkage); Ok(id) } FuncOrDataId::Data(..) => { @@ -453,13 +345,10 @@ where } }, Vacant(entry) => { - let id = self.contents.functions.push(ModuleFunction { - decl: FunctionDeclaration { - name: name.to_owned(), - linkage, - signature: signature.clone(), - }, - compiled: None, + let id = self.declarations.functions.push(FunctionDeclaration { + name: name.to_owned(), + linkage, + signature: signature.clone(), }); entry.insert(FuncOrDataId::Func(id)); self.backend.declare_function(id, name, linkage); @@ -469,8 +358,8 @@ where } /// An iterator over functions that have been declared in this module. - pub fn declared_functions(&self) -> core::slice::Iter<'_, ModuleFunction> { - self.contents.functions.values() + pub fn declared_functions(&self) -> core::slice::Iter<'_, FunctionDeclaration> { + self.declarations.functions.values() } /// Declare a data object in this module. @@ -487,15 +376,15 @@ where match self.names.entry(name.to_owned()) { Occupied(entry) => match *entry.get() { FuncOrDataId::Data(id) => { - let existing = &mut self.contents.data_objects[id]; + let existing = &mut self.declarations.data_objects[id]; existing.merge(linkage, writable, tls, align); self.backend.declare_data( id, name, - existing.decl.linkage, - existing.decl.writable, - existing.decl.tls, - existing.decl.align, + existing.linkage, + existing.writable, + existing.tls, + existing.align, ); Ok(id) } @@ -505,15 +394,12 @@ where } }, Vacant(entry) => { - let id = self.contents.data_objects.push(ModuleData { - decl: DataDeclaration { - name: name.to_owned(), - linkage, - writable, - tls, - align, - }, - compiled: None, + let id = self.declarations.data_objects.push(DataDeclaration { + name: name.to_owned(), + linkage, + writable, + tls, + align, }); entry.insert(FuncOrDataId::Data(id)); self.backend @@ -528,7 +414,7 @@ where /// 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.contents.functions[func].decl; + 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 { @@ -542,7 +428,7 @@ where /// /// TODO: Same as above. pub fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalValue { - let decl = &self.contents.data_objects[data].decl; + 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()), @@ -582,20 +468,20 @@ where ctx.func.display(self.backend.isa()) ); let CodeInfo { total_size, .. } = ctx.compile(self.backend.isa())?; - let info = &self.contents.functions[func]; - info.validate_for_define()?; + let decl = &self.declarations.functions[func]; + if !decl.linkage.is_definable() { + return Err(ModuleError::InvalidImportDefinition(decl.name.clone())); + } - let compiled = self.backend.define_function( + self.backend.define_function( func, - &info.decl.name, + &decl.name, ctx, - &self.contents, + &self.declarations, total_size, trap_sink, )?; - self.contents.functions[func].compiled = Some(compiled); - self.functions_to_finalize.push(func); Ok(ModuleCompiledFunction { size: total_size }) } @@ -612,40 +498,38 @@ where bytes: &[u8], ) -> ModuleResult { info!("defining function {} with bytes", func); - let info = &self.contents.functions[func]; - info.validate_for_define()?; + let decl = &self.declarations.functions[func]; + if !decl.linkage.is_definable() { + return Err(ModuleError::InvalidImportDefinition(decl.name.clone())); + } let total_size: u32 = match bytes.len().try_into() { Ok(total_size) => total_size, - _ => Err(ModuleError::FunctionTooLarge(info.decl.name.clone()))?, + _ => Err(ModuleError::FunctionTooLarge(decl.name.clone()))?, }; - let compiled = - self.backend - .define_function_bytes(func, &info.decl.name, bytes, &self.contents)?; + self.backend + .define_function_bytes(func, &decl.name, bytes, &self.declarations)?; - self.contents.functions[func].compiled = Some(compiled); - self.functions_to_finalize.push(func); Ok(ModuleCompiledFunction { size: total_size }) } /// Define a data object, producing the data contents from the given `DataContext`. pub fn define_data(&mut self, data: DataId, data_ctx: &DataContext) -> ModuleResult<()> { - let compiled = { - let info = &self.contents.data_objects[data]; - info.validate_for_define()?; - Some(self.backend.define_data( - data, - &info.decl.name, - info.decl.writable, - info.decl.tls, - info.decl.align, - data_ctx, - &self.contents, - )?) - }; - self.contents.data_objects[data].compiled = compiled; - self.data_objects_to_finalize.push(data); + let decl = &self.declarations.data_objects[data]; + if !decl.linkage.is_definable() { + return Err(ModuleError::InvalidImportDefinition(decl.name.clone())); + } + + self.backend.define_data( + data, + &decl.name, + decl.writable, + decl.tls, + decl.align, + data_ctx, + &self.declarations, + )?; Ok(()) } @@ -658,6 +542,6 @@ where /// implementations may provide additional functionality available after /// a `Module` is complete. pub fn finish(self) -> B::Product { - self.backend.finish(self.names, self.contents) + self.backend.finish(self.names, self.declarations) } } diff --git a/cranelift/object/src/backend.rs b/cranelift/object/src/backend.rs index 64feb15b45..42060a8722 100644 --- a/cranelift/object/src/backend.rs +++ b/cranelift/object/src/backend.rs @@ -9,7 +9,7 @@ use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::{self, ir}; use cranelift_module::{ Backend, DataContext, DataDescription, DataId, FuncId, FuncOrDataId, Init, Linkage, - ModuleContents, ModuleError, ModuleResult, + ModuleDeclarations, ModuleError, ModuleResult, }; use object::write::{ Object, Relocation, SectionId, StandardSection, Symbol, SymbolId, SymbolSection, @@ -112,8 +112,8 @@ impl ObjectBuilder { pub struct ObjectBackend { isa: Box, object: Object, - functions: SecondaryMap>, - data_objects: SecondaryMap>, + functions: SecondaryMap>, + data_objects: SecondaryMap>, relocs: Vec, libcalls: HashMap, libcall_names: Box String>, @@ -124,9 +124,6 @@ pub struct ObjectBackend { impl Backend for ObjectBackend { type Builder = ObjectBuilder; - type CompiledFunction = ObjectCompiledFunction; - type CompiledData = ObjectCompiledData; - type Product = ObjectProduct; /// Create a new `ObjectBackend` using the given Cranelift target. @@ -153,7 +150,7 @@ impl Backend for ObjectBackend { fn declare_function(&mut self, id: FuncId, name: &str, linkage: Linkage) { let (scope, weak) = translate_linkage(linkage); - if let Some(function) = self.functions[id] { + if let Some((function, _defined)) = self.functions[id] { let symbol = self.object.symbol_mut(function); symbol.scope = scope; symbol.weak = weak; @@ -168,7 +165,7 @@ impl Backend for ObjectBackend { section: SymbolSection::Undefined, flags: SymbolFlags::None, }); - self.functions[id] = Some(symbol_id); + self.functions[id] = Some((symbol_id, false)); } } @@ -188,7 +185,7 @@ impl Backend for ObjectBackend { }; let (scope, weak) = translate_linkage(linkage); - if let Some(data) = self.data_objects[id] { + if let Some((data, _defined)) = self.data_objects[id] { let symbol = self.object.symbol_mut(data); symbol.kind = kind; symbol.scope = scope; @@ -204,22 +201,28 @@ impl Backend for ObjectBackend { section: SymbolSection::Undefined, flags: SymbolFlags::None, }); - self.data_objects[id] = Some(symbol_id); + self.data_objects[id] = Some((symbol_id, false)); } } fn define_function( &mut self, func_id: FuncId, - _name: &str, + name: &str, ctx: &cranelift_codegen::Context, - _contents: &ModuleContents, + _declarations: &ModuleDeclarations, code_size: u32, trap_sink: &mut TS, - ) -> ModuleResult + ) -> ModuleResult<()> where TS: TrapSink, { + let &mut (symbol, ref mut defined) = self.functions[func_id].as_mut().unwrap(); + if *defined { + return Err(ModuleError::DuplicateDefinition(name.to_owned())); + } + *defined = true; + let mut code: Vec = vec![0; code_size as usize]; let mut reloc_sink = ObjectRelocSink::new(self.object.format()); let mut stack_map_sink = NullStackMapSink {}; @@ -234,8 +237,6 @@ impl Backend for ObjectBackend { ) }; - let symbol = self.functions[func_id].unwrap(); - let (section, offset) = if self.per_function_section { let symbol_name = self.object.symbol(symbol).name.clone(); let (section, offset) = self.object.add_subsection( @@ -262,17 +263,21 @@ impl Backend for ObjectBackend { relocs: reloc_sink.relocs, }); } - Ok(ObjectCompiledFunction) + Ok(()) } fn define_function_bytes( &mut self, func_id: FuncId, - _name: &str, + name: &str, bytes: &[u8], - _contents: &ModuleContents, - ) -> ModuleResult { - let symbol = self.functions[func_id].unwrap(); + _declarations: &ModuleDeclarations, + ) -> ModuleResult<()> { + let &mut (symbol, ref mut defined) = self.functions[func_id].as_mut().unwrap(); + if *defined { + return Err(ModuleError::DuplicateDefinition(name.to_owned())); + } + *defined = true; if self.per_function_section { let symbol_name = self.object.symbol(symbol).name.clone(); @@ -291,19 +296,25 @@ impl Backend for ObjectBackend { .add_symbol_data(symbol, section, bytes, self.function_alignment); } - Ok(ObjectCompiledFunction) + Ok(()) } fn define_data( &mut self, data_id: DataId, - _name: &str, + name: &str, writable: bool, tls: bool, align: Option, data_ctx: &DataContext, - _contents: &ModuleContents, - ) -> ModuleResult { + _declarations: &ModuleDeclarations, + ) -> ModuleResult<()> { + let &mut (symbol, ref mut defined) = self.data_objects[data_id].as_mut().unwrap(); + if *defined { + return Err(ModuleError::DuplicateDefinition(name.to_owned())); + } + *defined = true; + let &DataDescription { ref init, ref function_decls, @@ -340,7 +351,6 @@ impl Backend for ObjectBackend { }); } - let symbol = self.data_objects[data_id].unwrap(); let section = if custom_segment_section.is_none() { let section_kind = if let Init::Zeros { .. } = *init { if tls { @@ -397,13 +407,13 @@ impl Backend for ObjectBackend { relocs, }); } - Ok(ObjectCompiledData) + Ok(()) } fn finish( mut self, _names: HashMap, - contents: ModuleContents, + declarations: ModuleDeclarations, ) -> ObjectProduct { let symbol_relocs = mem::take(&mut self.relocs); for symbol in symbol_relocs { @@ -416,7 +426,7 @@ impl Backend for ObjectBackend { addend, } in &symbol.relocs { - let target_symbol = self.get_symbol(&contents, name); + let target_symbol = self.get_symbol(&declarations, name); self.object .add_relocation( symbol.section, @@ -453,15 +463,19 @@ impl Backend for ObjectBackend { impl ObjectBackend { // This should only be called during finish because it creates // symbols for missing libcalls. - fn get_symbol(&mut self, contents: &ModuleContents, name: &ir::ExternalName) -> SymbolId { + fn get_symbol( + &mut self, + declarations: &ModuleDeclarations, + name: &ir::ExternalName, + ) -> SymbolId { match *name { ir::ExternalName::User { .. } => { - if contents.is_function(name) { - let id = contents.get_function_id(name); - self.functions[id].unwrap() + if declarations.is_function(name) { + let id = declarations.get_function_id(name); + self.functions[id].unwrap().0 } else { - let id = contents.get_data_id(name); - self.data_objects[id].unwrap() + let id = declarations.get_data_id(name); + self.data_objects[id].unwrap().0 } } ir::ExternalName::LibCall(ref libcall) => { @@ -502,9 +516,6 @@ fn translate_linkage(linkage: Linkage) -> (SymbolScope, bool) { (scope, weak) } -pub struct ObjectCompiledFunction; -pub struct ObjectCompiledData; - /// This is the output of `Module`'s /// [`finish`](../cranelift_module/struct.Module.html#method.finish) function. /// It contains the generated `Object` and other information produced during @@ -513,22 +524,22 @@ pub struct ObjectProduct { /// Object artifact with all functions and data from the module defined. pub object: Object, /// Symbol IDs for functions (both declared and defined). - pub functions: SecondaryMap>, + pub functions: SecondaryMap>, /// Symbol IDs for data objects (both declared and defined). - pub data_objects: SecondaryMap>, + pub data_objects: SecondaryMap>, } impl ObjectProduct { /// Return the `SymbolId` for the given function. #[inline] pub fn function_symbol(&self, id: FuncId) -> SymbolId { - self.functions[id].unwrap() + self.functions[id].unwrap().0 } /// Return the `SymbolId` for the given data object. #[inline] pub fn data_symbol(&self, id: DataId) -> SymbolId { - self.data_objects[id].unwrap() + self.data_objects[id].unwrap().0 } /// Write the object bytes in memory. diff --git a/cranelift/simplejit/Cargo.toml b/cranelift/simplejit/Cargo.toml index 9fe617bd14..dcbdbd7300 100644 --- a/cranelift/simplejit/Cargo.toml +++ b/cranelift/simplejit/Cargo.toml @@ -13,6 +13,7 @@ edition = "2018" cranelift-module = { path = "../module", version = "0.67.0" } cranelift-native = { path = "../native", version = "0.67.0" } cranelift-codegen = { path = "../codegen", version = "0.67.0", default-features = false, features = ["std"] } +cranelift-entity = { path = "../entity", version = "0.67.0" } region = "2.2.0" libc = { version = "0.2.42" } errno = "0.2.4" diff --git a/cranelift/simplejit/src/backend.rs b/cranelift/simplejit/src/backend.rs index 5a97ae8b5e..c0c6dee757 100644 --- a/cranelift/simplejit/src/backend.rs +++ b/cranelift/simplejit/src/backend.rs @@ -7,9 +7,10 @@ use cranelift_codegen::binemit::{ use cranelift_codegen::isa::TargetIsa; 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, - ModuleContents, ModuleResult, + ModuleDeclarations, ModuleError, ModuleResult, }; use cranelift_native; #[cfg(not(windows))] @@ -124,11 +125,14 @@ pub struct SimpleJITBackend { symbols: HashMap, libcall_names: Box String>, memory: SimpleJITMemoryHandle, + functions: SecondaryMap>, + data_objects: SecondaryMap>, functions_to_finalize: Vec, data_objects_to_finalize: Vec, } /// A record of a relocation to perform. +#[derive(Clone)] struct RelocRecord { offset: CodeOffset, reloc: Reloc, @@ -143,12 +147,14 @@ struct StackMapRecord { stack_map: StackMap, } +#[derive(Clone)] pub struct SimpleJITCompiledFunction { code: *mut u8, size: usize, relocs: Vec, } +#[derive(Clone)] pub struct SimpleJITCompiledData { storage: *mut u8, size: usize, @@ -167,7 +173,8 @@ struct SimpleJITMemoryHandle { pub struct SimpleJITProduct { memory: SimpleJITMemoryHandle, names: HashMap, - contents: ModuleContents, + functions: SecondaryMap>, + data_objects: SecondaryMap>, } impl SimpleJITProduct { @@ -192,19 +199,16 @@ impl SimpleJITProduct { /// Return the address of a function. pub fn lookup_func(&self, func_id: FuncId) -> *const u8 { - self.contents - .get_function_definition(&func_id.into()) - .0 + self.functions[func_id] + .as_ref() .unwrap_or_else(|| panic!("{} is not defined", func_id)) .code } /// Return the address and size of a data object. pub fn lookup_data(&self, data_id: DataId) -> (*const u8, usize) { - let data = self - .contents - .get_data_definition(&data_id.into()) - .0 + let data = self.data_objects[data_id] + .as_ref() .unwrap_or_else(|| panic!("{} is not defined", data_id)); (data.storage, data.size) } @@ -220,22 +224,22 @@ impl SimpleJITBackend { fn get_definition( &self, - contents: &ModuleContents, + declarations: &ModuleDeclarations, name: &ir::ExternalName, ) -> *const u8 { match *name { ir::ExternalName::User { .. } => { - if contents.is_function(name) { - let (def, name_str, _signature) = contents.get_function_definition(&name); - match def { + if declarations.is_function(name) { + let func_id = declarations.get_function_id(name); + match &self.functions[func_id] { Some(compiled) => compiled.code, - None => self.lookup_symbol(name_str), + None => self.lookup_symbol(&declarations.get_function_decl(func_id).name), } } else { - let (def, name_str, _writable) = contents.get_data_definition(&name); - match def { + let data_id = declarations.get_data_id(name); + match &self.data_objects[data_id] { Some(compiled) => compiled.storage, - None => self.lookup_symbol(name_str), + None => self.lookup_symbol(&declarations.get_data_decl(data_id).name), } } } @@ -264,15 +268,13 @@ impl SimpleJITBackend { } } - - fn finalize_function( - &mut self, - _id: FuncId, - func: &SimpleJITCompiledFunction, - contents: &ModuleContents, - ) { + fn finalize_function(&mut self, id: FuncId, declarations: &ModuleDeclarations) { use std::ptr::write_unaligned; + let func = self.functions[id] + .as_ref() + .expect("function must be compiled before it can be finalized"); + for &RelocRecord { reloc, offset, @@ -283,7 +285,7 @@ impl SimpleJITBackend { let ptr = func.code; debug_assert!((offset as usize) < func.size); let at = unsafe { ptr.offset(offset as isize) }; - let base = self.get_definition(contents, name); + let base = self.get_definition(declarations, name); // TODO: Handle overflow. let what = unsafe { base.offset(addend as isize) }; match reloc { @@ -314,14 +316,13 @@ impl SimpleJITBackend { } } - fn finalize_data( - &mut self, - _id: DataId, - data: &SimpleJITCompiledData, - contents: &ModuleContents, - ) { + fn finalize_data(&mut self, id: DataId, declarations: &ModuleDeclarations) { use std::ptr::write_unaligned; + let data = self.data_objects[id] + .as_ref() + .expect("data object must be compiled before it can be finalized"); + for &RelocRecord { reloc, offset, @@ -332,7 +333,7 @@ impl SimpleJITBackend { let ptr = data.storage; debug_assert!((offset as usize) < data.size); let at = unsafe { ptr.offset(offset as isize) }; - let base = self.get_definition(contents, name); + let base = self.get_definition(declarations, name); // TODO: Handle overflow. let what = unsafe { base.offset(addend as isize) }; match reloc { @@ -362,13 +363,6 @@ impl SimpleJITBackend { impl<'simple_jit_backend> Backend for SimpleJITBackend { type Builder = SimpleJITBuilder; - /// SimpleJIT compiled function and data objects may have outstanding - /// relocations that need to be performed before the memory can be used. - /// These relocations are performed within `finalize_function` and - /// `finalize_data`. - type CompiledFunction = SimpleJITCompiledFunction; - type CompiledData = SimpleJITCompiledData; - /// 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 @@ -388,6 +382,8 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { symbols: builder.symbols, libcall_names: builder.libcall_names, memory, + functions: SecondaryMap::new(), + data_objects: SecondaryMap::new(), functions_to_finalize: Vec::new(), data_objects_to_finalize: Vec::new(), } @@ -419,13 +415,17 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { id: FuncId, name: &str, ctx: &cranelift_codegen::Context, - _contents: &ModuleContents, + _declarations: &ModuleDeclarations, code_size: u32, trap_sink: &mut TS, - ) -> ModuleResult + ) -> ModuleResult<()> where TS: TrapSink, { + if !self.functions[id].is_none() { + return Err(ModuleError::DuplicateDefinition(name.to_owned())); + } + self.functions_to_finalize.push(id); let size = code_size as usize; let ptr = self @@ -448,11 +448,13 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { ) }; - Ok(Self::CompiledFunction { + self.functions[id] = Some(SimpleJITCompiledFunction { code: ptr, size, relocs: reloc_sink.relocs, - }) + }); + + Ok(()) } fn define_function_bytes( @@ -460,8 +462,12 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { id: FuncId, name: &str, bytes: &[u8], - _contents: &ModuleContents, - ) -> ModuleResult { + _declarations: &ModuleDeclarations, + ) -> ModuleResult<()> { + if !self.functions[id].is_none() { + return Err(ModuleError::DuplicateDefinition(name.to_owned())); + } + self.functions_to_finalize.push(id); let size = bytes.len(); let ptr = self @@ -476,23 +482,29 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, size); } - Ok(Self::CompiledFunction { + self.functions[id] = Some(SimpleJITCompiledFunction { code: ptr, size, relocs: vec![], - }) + }); + + Ok(()) } fn define_data( &mut self, id: DataId, - _name: &str, + name: &str, writable: bool, tls: bool, align: Option, data: &DataContext, - _contents: &ModuleContents, - ) -> ModuleResult { + _declarations: &ModuleDeclarations, + ) -> ModuleResult<()> { + if !self.data_objects[id].is_none() { + return Err(ModuleError::DuplicateDefinition(name.to_owned())); + } + assert!(!tls, "SimpleJIT doesn't yet support TLS"); self.data_objects_to_finalize.push(id); @@ -555,11 +567,13 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { }); } - Ok(Self::CompiledData { + self.data_objects[id] = Some(SimpleJITCompiledData { storage, size, relocs, - }) + }); + + Ok(()) } /// SimpleJIT emits code and data into memory as it processes them. This @@ -572,29 +586,17 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { fn finish( mut self, names: HashMap, - contents: ModuleContents, + declarations: ModuleDeclarations, ) -> Self::Product { for func in std::mem::take(&mut self.functions_to_finalize) { - let info = contents.get_function_info(func); - debug_assert!(info.decl.linkage.is_definable()); - self.finalize_function( - func, - info.compiled - .as_ref() - .expect("function must be compiled before it can be finalized"), - &contents, - ); + let decl = declarations.get_function_decl(func); + debug_assert!(decl.linkage.is_definable()); + self.finalize_function(func, &declarations); } for data in std::mem::take(&mut self.data_objects_to_finalize) { - let info = contents.get_data_info(data); - debug_assert!(info.decl.linkage.is_definable()); - self.finalize_data( - data, - info.compiled - .as_ref() - .expect("data object must be compiled before it can be finalized"), - &contents, - ); + let decl = declarations.get_data_decl(data); + debug_assert!(decl.linkage.is_definable()); + self.finalize_data(data, &declarations); } // Now that we're done patching, prepare the memory for execution! @@ -604,7 +606,8 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { SimpleJITProduct { memory: self.memory, names, - contents, + functions: self.functions, + data_objects: self.data_objects, } } }