diff --git a/cranelift/module/src/backend.rs b/cranelift/module/src/backend.rs index 6602c4cbb7..e20416b920 100644 --- a/cranelift/module/src/backend.rs +++ b/cranelift/module/src/backend.rs @@ -1,6 +1,6 @@ //! Defines the `Backend` trait. -use crate::DataContext; +use crate::{DataContext, FuncOrDataId}; use crate::DataId; use crate::FuncId; use crate::Linkage; @@ -11,7 +11,7 @@ use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::Context; use cranelift_codegen::{binemit, ir}; -use std::borrow::ToOwned; +use std::{borrow::ToOwned, collections::HashMap}; use std::boxed::Box; use std::string::String; @@ -38,14 +38,6 @@ where /// The results of "compiling" a data object. type CompiledData; - /// The completed output artifact for a function, if this is meaningful for - /// the `Backend`. - type FinalizedFunction; - - /// The completed output artifact for a data object, if this is meaningful for - /// the `Backend`. - type FinalizedData; - /// This is an object returned by `Module`'s /// [`finish`](struct.Module.html#method.finish) function, /// if the `Backend` has a purpose for this. @@ -140,10 +132,7 @@ where id: FuncId, func: &Self::CompiledFunction, contents: &ModuleContents, - ) -> Self::FinalizedFunction; - - /// Return the finalized artifact from the backend, if relevant. - fn get_finalized_function(&self, func: &Self::CompiledFunction) -> Self::FinalizedFunction; + ); /// Perform all outstanding relocations on the given data object. This requires all /// `Local` and `Export` entities referenced to be defined. @@ -155,10 +144,7 @@ where id: DataId, data: &Self::CompiledData, contents: &ModuleContents, - ) -> Self::FinalizedData; - - /// Return the finalized artifact from the backend, if relevant. - fn get_finalized_data(&self, data: &Self::CompiledData) -> Self::FinalizedData; + ); /// "Publish" all finalized functions and data objects to their ultimate destinations. /// @@ -168,7 +154,11 @@ where /// Consume this `Backend` and return a result. Some implementations may /// provide additional functionality through this result. - fn finish(self, contents: &ModuleContents) -> Self::Product; + fn finish( + self, + names: HashMap, + contents: ModuleContents, + ) -> Self::Product; } /// Default names for `ir::LibCall`s. A function by this name is imported into the object as diff --git a/cranelift/module/src/module.rs b/cranelift/module/src/module.rs index 4e08afe37e..78a6ae542d 100644 --- a/cranelift/module/src/module.rs +++ b/cranelift/module/src/module.rs @@ -717,34 +717,6 @@ where self.backend.publish(); } - /// Return the finalized artifact from the backend, if it provides one. - pub fn get_finalized_function(&mut self, func: FuncId) -> B::FinalizedFunction { - let info = &self.contents.functions[func]; - debug_assert!( - !self.functions_to_finalize.iter().any(|x| *x == func), - "function not yet finalized" - ); - self.backend.get_finalized_function( - info.compiled - .as_ref() - .expect("function must be compiled before it can be finalized"), - ) - } - - /// Return the finalized artifact from the backend, if it provides one. - pub fn get_finalized_data(&mut self, data: DataId) -> B::FinalizedData { - let info = &self.contents.data_objects[data]; - debug_assert!( - !self.data_objects_to_finalize.iter().any(|x| *x == data), - "data object not yet finalized" - ); - self.backend.get_finalized_data( - info.compiled - .as_ref() - .expect("data object must be compiled before it can be finalized"), - ) - } - /// Return the target isa pub fn isa(&self) -> &dyn isa::TargetIsa { self.backend.isa() @@ -754,6 +726,6 @@ where /// implementations may provide additional functionality available after /// a `Module` is complete. pub fn finish(self) -> B::Product { - self.backend.finish(&self.contents) + self.backend.finish(self.names, self.contents) } } diff --git a/cranelift/object/src/backend.rs b/cranelift/object/src/backend.rs index be247f9cdd..a2db3f99c7 100644 --- a/cranelift/object/src/backend.rs +++ b/cranelift/object/src/backend.rs @@ -8,8 +8,8 @@ use cranelift_codegen::entity::SecondaryMap; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::{self, binemit, ir}; use cranelift_module::{ - Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleError, - ModuleContents, ModuleResult, + Backend, DataContext, DataDescription, DataId, FuncId, FuncOrDataId, Init, Linkage, + ModuleContents, ModuleError, ModuleResult, }; use object::write::{ Object, Relocation, SectionId, StandardSection, Symbol, SymbolId, SymbolSection, @@ -127,11 +127,6 @@ impl Backend for ObjectBackend { type CompiledFunction = ObjectCompiledFunction; type CompiledData = ObjectCompiledData; - // There's no need to return individual artifacts; we're writing them into - // the output file instead. - type FinalizedFunction = (); - type FinalizedData = (); - type Product = ObjectProduct; /// Create a new `ObjectBackend` using the given Cranelift target. @@ -433,10 +428,6 @@ impl Backend for ObjectBackend { // Nothing to do. } - fn get_finalized_function(&self, _func: &ObjectCompiledFunction) { - // Nothing to do. - } - fn finalize_data( &mut self, _id: DataId, @@ -446,15 +437,15 @@ impl Backend for ObjectBackend { // Nothing to do. } - fn get_finalized_data(&self, _data: &ObjectCompiledData) { - // Nothing to do. - } - fn publish(&mut self) { // Nothing to do. } - fn finish(mut self, contents: &ModuleContents) -> ObjectProduct { + fn finish( + mut self, + _names: HashMap, + contents: ModuleContents, + ) -> ObjectProduct { let symbol_relocs = mem::take(&mut self.relocs); for symbol in symbol_relocs { for &RelocRecord { @@ -466,7 +457,7 @@ impl Backend for ObjectBackend { addend, } in &symbol.relocs { - let target_symbol = self.get_symbol(contents, name); + let target_symbol = self.get_symbol(&contents, name); self.object .add_relocation( symbol.section, @@ -503,11 +494,7 @@ 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, contents: &ModuleContents, name: &ir::ExternalName) -> SymbolId { match *name { ir::ExternalName::User { .. } => { if contents.is_function(name) { diff --git a/cranelift/simplejit/src/backend.rs b/cranelift/simplejit/src/backend.rs index c790a6bf01..3a999ef221 100644 --- a/cranelift/simplejit/src/backend.rs +++ b/cranelift/simplejit/src/backend.rs @@ -8,8 +8,8 @@ use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::settings::Configurable; use cranelift_codegen::{self, ir, settings}; use cranelift_module::{ - Backend, DataContext, DataDescription, DataId, FuncId, Init, Linkage, ModuleContents, - ModuleResult, + Backend, DataContext, DataDescription, DataId, FuncId, FuncOrDataId, Init, Linkage, + ModuleContents, ModuleResult, }; use cranelift_native; #[cfg(not(windows))] @@ -154,12 +154,60 @@ pub struct SimpleJITCompiledData { } /// A handle to allow freeing memory allocated by the `Backend`. -pub struct SimpleJITMemoryHandle { +struct SimpleJITMemoryHandle { code: Memory, readonly: Memory, writable: Memory, } +/// A `SimpleJITProduct` allows looking up the addresses of all functions and data objects +/// defined in the original module. +pub struct SimpleJITProduct { + memory: SimpleJITMemoryHandle, + names: HashMap, + contents: ModuleContents, +} + +impl SimpleJITProduct { + /// Free memory allocated for code and data segments of compiled functions. + /// + /// # Safety + /// + /// Because this function invalidates any pointers retrived from the + /// corresponding module, it should only be used when none of the functions + /// from that module are currently executing and none of the `fn` pointers + /// are called afterwards. + pub unsafe fn free_memory(&mut self) { + self.memory.code.free_memory(); + self.memory.readonly.free_memory(); + self.memory.writable.free_memory(); + } + + /// Get the `FuncOrDataId` associated with the given name. + pub fn func_or_data_for_func(&self, name: &str) -> Option { + self.names.get(name).copied() + } + + /// 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 + .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 + .unwrap_or_else(|| panic!("{} is not defined", data_id)); + (data.storage, data.size) + } +} + impl SimpleJITBackend { fn lookup_symbol(&self, name: &str) -> *const u8 { match self.symbols.get(name) { @@ -225,19 +273,11 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { type CompiledFunction = SimpleJITCompiledFunction; type CompiledData = SimpleJITCompiledData; - /// SimpleJIT emits code and data into memory, and provides raw pointers - /// to them. They are valid for the remainder of the program's life, unless - /// [`free_memory`] is used. - /// - /// [`free_memory`]: #method.free_memory - type FinalizedFunction = *const u8; - type FinalizedData = (*mut u8, usize); - /// 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 = SimpleJITMemoryHandle; + type Product = SimpleJITProduct; /// Create a new `SimpleJITBackend`. fn new(builder: SimpleJITBuilder) -> Self { @@ -444,7 +484,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { _id: FuncId, func: &Self::CompiledFunction, contents: &ModuleContents, - ) -> Self::FinalizedFunction { + ) { use std::ptr::write_unaligned; for &RelocRecord { @@ -486,11 +526,6 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { _ => unimplemented!(), } } - func.code - } - - fn get_finalized_function(&self, func: &Self::CompiledFunction) -> Self::FinalizedFunction { - func.code } fn finalize_data( @@ -498,7 +533,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { _id: DataId, data: &Self::CompiledData, contents: &ModuleContents, - ) -> Self::FinalizedData { + ) { use std::ptr::write_unaligned; for &RelocRecord { @@ -535,11 +570,6 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { _ => unimplemented!(), } } - (data.storage, data.size) - } - - fn get_finalized_data(&self, data: &Self::CompiledData) -> Self::FinalizedData { - (data.storage, data.size) } fn publish(&mut self) { @@ -555,8 +585,16 @@ 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(self, _contents: &ModuleContents) -> Self::Product { - self.memory + fn finish( + self, + names: HashMap, + contents: ModuleContents, + ) -> Self::Product { + SimpleJITProduct { + memory: self.memory, + names, + contents, + } } } @@ -603,22 +641,6 @@ fn lookup_with_dlsym(name: &str) -> *const u8 { } } -impl SimpleJITMemoryHandle { - /// Free memory allocated for code and data segments of compiled functions. - /// - /// # Safety - /// - /// Because this function invalidates any pointers retrived from the - /// corresponding module, it should only be used when none of the functions - /// from that module are currently executing and none of the`fn` pointers - /// are called afterwards. - pub unsafe fn free_memory(&mut self) { - self.code.free_memory(); - self.readonly.free_memory(); - self.writable.free_memory(); - } -} - struct SimpleJITRelocSink { pub relocs: Vec, } diff --git a/cranelift/simplejit/src/lib.rs b/cranelift/simplejit/src/lib.rs index d907964cff..705b8decfc 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}; +pub use crate::backend::{SimpleJITBackend, SimpleJITBuilder, SimpleJITProduct}; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION");