From 405b9e28753db5d5681ddf6fb9099612ff64621e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 30 Sep 2020 14:20:39 +0200 Subject: [PATCH] Remove finalize_* from the Backend trait Instead let the `finish` method perform finalization --- cranelift/module/src/backend.rs | 24 ---- cranelift/module/src/module.rs | 40 ++---- cranelift/object/src/backend.rs | 18 --- cranelift/simplejit/src/backend.rs | 224 ++++++++++++++++------------- 4 files changed, 142 insertions(+), 164 deletions(-) diff --git a/cranelift/module/src/backend.rs b/cranelift/module/src/backend.rs index bf4f593a42..0d4b5e8e5f 100644 --- a/cranelift/module/src/backend.rs +++ b/cranelift/module/src/backend.rs @@ -103,30 +103,6 @@ where contents: &ModuleContents, ) -> ModuleResult; - /// Perform all outstanding relocations on the given function. This requires all `Local` - /// and `Export` entities referenced to be defined. - /// - /// This method is not relevant for `Backend` implementations that do not provide - /// `Backend::FinalizedFunction`. - fn finalize_function( - &mut self, - id: FuncId, - func: &Self::CompiledFunction, - contents: &ModuleContents, - ); - - /// Perform all outstanding relocations on the given data object. This requires all - /// `Local` and `Export` entities referenced to be defined. - /// - /// This method is not relevant for `Backend` implementations that do not provide - /// `Backend::FinalizedData`. - fn finalize_data( - &mut self, - id: DataId, - data: &Self::CompiledData, - contents: &ModuleContents, - ); - /// Consume this `Backend` and return a result. Some implementations may /// provide additional functionality through this result. fn finish( diff --git a/cranelift/module/src/module.rs b/cranelift/module/src/module.rs index 600cff9ec8..f95ee5e27e 100644 --- a/cranelift/module/src/module.rs +++ b/cranelift/module/src/module.rs @@ -213,14 +213,14 @@ pub struct DataDeclaration { } /// A data object belonging to a `Module`. -struct ModuleData +pub struct ModuleData where B: Backend, { /// The data object declaration. - decl: DataDeclaration, + pub decl: DataDeclaration, /// The "compiled" artifact, once it's available. - compiled: Option, + pub compiled: Option, } impl ModuleData @@ -282,11 +282,21 @@ where } } + /// Get the `ModuleFunction` for the given function. + pub fn get_function_info(&self, func_id: FuncId) -> &ModuleFunction { + &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 @@ -647,29 +657,7 @@ where /// Consume the module and return the resulting `Product`. Some `Backend` /// implementations may provide additional functionality available after /// a `Module` is complete. - pub fn finish(mut self) -> B::Product { - for func in self.functions_to_finalize.drain(..) { - let info = &self.contents.functions[func]; - debug_assert!(info.decl.linkage.is_definable()); - self.backend.finalize_function( - func, - info.compiled - .as_ref() - .expect("function must be compiled before it can be finalized"), - &self.contents, - ); - } - for data in self.data_objects_to_finalize.drain(..) { - let info = &self.contents.data_objects[data]; - debug_assert!(info.decl.linkage.is_definable()); - self.backend.finalize_data( - data, - info.compiled - .as_ref() - .expect("data object must be compiled before it can be finalized"), - &self.contents, - ); - } + pub fn finish(self) -> B::Product { self.backend.finish(self.names, self.contents) } } diff --git a/cranelift/object/src/backend.rs b/cranelift/object/src/backend.rs index 2177f81c27..64feb15b45 100644 --- a/cranelift/object/src/backend.rs +++ b/cranelift/object/src/backend.rs @@ -400,24 +400,6 @@ impl Backend for ObjectBackend { Ok(ObjectCompiledData) } - fn finalize_function( - &mut self, - _id: FuncId, - _func: &ObjectCompiledFunction, - _contents: &ModuleContents, - ) { - // Nothing to do. - } - - fn finalize_data( - &mut self, - _id: DataId, - _data: &ObjectCompiledData, - _contents: &ModuleContents, - ) { - // Nothing to do. - } - fn finish( mut self, _names: HashMap, diff --git a/cranelift/simplejit/src/backend.rs b/cranelift/simplejit/src/backend.rs index 222cb81494..5a97ae8b5e 100644 --- a/cranelift/simplejit/src/backend.rs +++ b/cranelift/simplejit/src/backend.rs @@ -124,6 +124,8 @@ pub struct SimpleJITBackend { symbols: HashMap, libcall_names: Box String>, memory: SimpleJITMemoryHandle, + functions_to_finalize: Vec, + data_objects_to_finalize: Vec, } /// A record of a relocation to perform. @@ -261,6 +263,100 @@ impl SimpleJITBackend { let _ = writeln!(map_file, "{:x} {:x} {}", ptr as usize, size, name); } } + + + fn finalize_function( + &mut self, + _id: FuncId, + func: &SimpleJITCompiledFunction, + contents: &ModuleContents, + ) { + use std::ptr::write_unaligned; + + for &RelocRecord { + reloc, + offset, + ref name, + addend, + } in &func.relocs + { + 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); + // TODO: Handle overflow. + let what = unsafe { base.offset(addend as isize) }; + match reloc { + Reloc::Abs4 => { + // TODO: Handle overflow. + #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] + unsafe { + write_unaligned(at as *mut u32, what as u32) + }; + } + Reloc::Abs8 => { + #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] + unsafe { + write_unaligned(at as *mut u64, what as u64) + }; + } + Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => { + // TODO: Handle overflow. + let pcrel = ((what as isize) - (at as isize)) as i32; + #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] + unsafe { + write_unaligned(at as *mut i32, pcrel) + }; + } + Reloc::X86GOTPCRel4 | Reloc::X86CallPLTRel4 => panic!("unexpected PIC relocation"), + _ => unimplemented!(), + } + } + } + + fn finalize_data( + &mut self, + _id: DataId, + data: &SimpleJITCompiledData, + contents: &ModuleContents, + ) { + use std::ptr::write_unaligned; + + for &RelocRecord { + reloc, + offset, + ref name, + addend, + } in &data.relocs + { + 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); + // TODO: Handle overflow. + let what = unsafe { base.offset(addend as isize) }; + match reloc { + Reloc::Abs4 => { + // TODO: Handle overflow. + #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] + unsafe { + write_unaligned(at as *mut u32, what as u32) + }; + } + Reloc::Abs8 => { + #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] + unsafe { + write_unaligned(at as *mut u64, what as u64) + }; + } + Reloc::X86PCRel4 + | Reloc::X86CallPCRel4 + | Reloc::X86GOTPCRel4 + | Reloc::X86CallPLTRel4 => panic!("unexpected text relocation in data"), + _ => unimplemented!(), + } + } + } } impl<'simple_jit_backend> Backend for SimpleJITBackend { @@ -292,6 +388,8 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { symbols: builder.symbols, libcall_names: builder.libcall_names, memory, + functions_to_finalize: Vec::new(), + data_objects_to_finalize: Vec::new(), } } @@ -318,7 +416,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { fn define_function( &mut self, - _id: FuncId, + id: FuncId, name: &str, ctx: &cranelift_codegen::Context, _contents: &ModuleContents, @@ -328,6 +426,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { where TS: TrapSink, { + self.functions_to_finalize.push(id); let size = code_size as usize; let ptr = self .memory @@ -358,11 +457,12 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { fn define_function_bytes( &mut self, - _id: FuncId, + id: FuncId, name: &str, bytes: &[u8], _contents: &ModuleContents, ) -> ModuleResult { + self.functions_to_finalize.push(id); let size = bytes.len(); let ptr = self .memory @@ -385,7 +485,7 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { fn define_data( &mut self, - _id: DataId, + id: DataId, _name: &str, writable: bool, tls: bool, @@ -395,6 +495,8 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { ) -> ModuleResult { assert!(!tls, "SimpleJIT doesn't yet support TLS"); + self.data_objects_to_finalize.push(id); + let &DataDescription { ref init, ref function_decls, @@ -460,99 +562,6 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { }) } - fn finalize_function( - &mut self, - _id: FuncId, - func: &Self::CompiledFunction, - contents: &ModuleContents, - ) { - use std::ptr::write_unaligned; - - for &RelocRecord { - reloc, - offset, - ref name, - addend, - } in &func.relocs - { - 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); - // TODO: Handle overflow. - let what = unsafe { base.offset(addend as isize) }; - match reloc { - Reloc::Abs4 => { - // TODO: Handle overflow. - #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] - unsafe { - write_unaligned(at as *mut u32, what as u32) - }; - } - Reloc::Abs8 => { - #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] - unsafe { - write_unaligned(at as *mut u64, what as u64) - }; - } - Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => { - // TODO: Handle overflow. - let pcrel = ((what as isize) - (at as isize)) as i32; - #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] - unsafe { - write_unaligned(at as *mut i32, pcrel) - }; - } - Reloc::X86GOTPCRel4 | Reloc::X86CallPLTRel4 => panic!("unexpected PIC relocation"), - _ => unimplemented!(), - } - } - } - - fn finalize_data( - &mut self, - _id: DataId, - data: &Self::CompiledData, - contents: &ModuleContents, - ) { - use std::ptr::write_unaligned; - - for &RelocRecord { - reloc, - offset, - ref name, - addend, - } in &data.relocs - { - 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); - // TODO: Handle overflow. - let what = unsafe { base.offset(addend as isize) }; - match reloc { - Reloc::Abs4 => { - // TODO: Handle overflow. - #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] - unsafe { - write_unaligned(at as *mut u32, what as u32) - }; - } - Reloc::Abs8 => { - #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))] - unsafe { - write_unaligned(at as *mut u64, what as u64) - }; - } - Reloc::X86PCRel4 - | Reloc::X86CallPCRel4 - | Reloc::X86GOTPCRel4 - | Reloc::X86CallPLTRel4 => panic!("unexpected text relocation in data"), - _ => unimplemented!(), - } - } - } - /// 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 @@ -565,6 +574,29 @@ impl<'simple_jit_backend> Backend for SimpleJITBackend { names: HashMap, contents: ModuleContents, ) -> 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, + ); + } + 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, + ); + } + // Now that we're done patching, prepare the memory for execution! self.memory.readonly.set_readonly(); self.memory.code.set_readable_and_executable();