Remove CodeSink

This commit is contained in:
bjorn3
2022-01-11 17:10:37 +01:00
parent a48a60f958
commit 55d722db05
8 changed files with 23 additions and 103 deletions

View File

@@ -13,47 +13,9 @@
//! that a `MemoryCodeSink` will always write binary machine code to raw memory. It forwards any //! 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 //! 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. //! `CodeSink::put*` methods, so the performance impact of the virtual callbacks is less severe.
use super::{Addend, CodeInfo, CodeOffset, CodeSink, Reloc}; use super::{Addend, CodeOffset, Reloc};
use crate::binemit::stack_map::StackMap; use crate::binemit::stack_map::StackMap;
use crate::ir::{ExternalName, SourceLoc, TrapCode}; use crate::ir::{ExternalName, SourceLoc, TrapCode};
use core::ptr::write_unaligned;
/// A `CodeSink` that writes binary machine code directly into memory.
///
/// A `MemoryCodeSink` object should be used when emitting a Cranelift IR function into executable
/// memory. It writes machine code directly to a raw pointer without any bounds checking, so make
/// sure to allocate enough memory for the whole function. The number of bytes required is returned
/// by the `Context::compile()` function.
///
/// Any relocations in the function are forwarded to the `RelocSink` trait object.
///
/// Note that `MemoryCodeSink` writes multi-byte values in the native byte order of the host. This
/// is not the right thing to do for cross compilation.
pub struct MemoryCodeSink {
/// Pointer to start of sink's preallocated memory.
data: *mut u8,
/// Offset is isize because its major consumer needs it in that form.
offset: isize,
}
impl<'a> MemoryCodeSink {
/// Create a new memory code sink that writes a function to the memory pointed to by `data`.
///
/// # Safety
///
/// This function is unsafe since `MemoryCodeSink` does not perform bounds checking on the
/// memory buffer, and it can't guarantee that the `data` pointer is valid.
pub unsafe fn new(data: *mut u8) -> Self {
Self { data, offset: 0 }
}
/// Information about the generated code and read-only data.
pub fn info(&self) -> CodeInfo {
CodeInfo {
total_size: self.offset as CodeOffset,
}
}
}
/// A trait for receiving relocations for code that is emitted directly into memory. /// A trait for receiving relocations for code that is emitted directly into memory.
pub trait RelocSink { pub trait RelocSink {
@@ -77,15 +39,6 @@ pub trait TrapSink {
fn trap(&mut self, _: CodeOffset, _: SourceLoc, _: TrapCode); fn trap(&mut self, _: CodeOffset, _: SourceLoc, _: TrapCode);
} }
impl CodeSink for MemoryCodeSink {
fn put1(&mut self, x: u8) {
unsafe {
write_unaligned(self.data.offset(self.offset), x);
self.offset += 1;
}
}
}
/// A `RelocSink` implementation that does nothing, which is convenient when /// A `RelocSink` implementation that does nothing, which is convenient when
/// compiling code that does not relocate anything. /// compiling code that does not relocate anything.
#[derive(Default)] #[derive(Default)]

View File

@@ -7,8 +7,7 @@ mod memorysink;
mod stack_map; mod stack_map;
pub use self::memorysink::{ pub use self::memorysink::{
MemoryCodeSink, NullRelocSink, NullStackMapSink, NullTrapSink, RelocSink, StackMapSink, NullRelocSink, NullStackMapSink, NullTrapSink, RelocSink, StackMapSink, TrapSink,
TrapSink,
}; };
pub use self::stack_map::StackMap; pub use self::stack_map::StackMap;
use core::fmt; use core::fmt;
@@ -98,12 +97,3 @@ pub struct CodeInfo {
/// Number of bytes in total. /// Number of bytes in total.
pub total_size: CodeOffset, pub total_size: CodeOffset,
} }
/// Abstract interface for adding bytes to the code segment.
///
/// A `CodeSink` will receive all of the machine code for a function. It also accepts relocations
/// which are locations in the code section that need to be fixed up when linking.
pub trait CodeSink {
/// Add 1 byte to the code section.
fn put1(&mut self, _: u8);
}

View File

@@ -9,7 +9,7 @@
//! contexts concurrently. Typically, you would have one context per compilation thread and only a //! contexts concurrently. Typically, you would have one context per compilation thread and only a
//! single ISA instance. //! single ISA instance.
use crate::binemit::{CodeInfo, MemoryCodeSink, RelocSink, StackMapSink, TrapSink}; use crate::binemit::{CodeInfo, RelocSink, StackMapSink, TrapSink};
use crate::dce::do_dce; use crate::dce::do_dce;
use crate::dominator_tree::DominatorTree; use crate::dominator_tree::DominatorTree;
use crate::flowgraph::ControlFlowGraph; use crate::flowgraph::ControlFlowGraph;
@@ -186,6 +186,7 @@ impl Context {
/// and it can't guarantee that the `mem` pointer is valid. /// and it can't guarantee that the `mem` pointer is valid.
/// ///
/// Returns information about the emitted code and data. /// Returns information about the emitted code and data.
#[deny(unsafe_op_in_unsafe_fn)]
pub unsafe fn emit_to_memory( pub unsafe fn emit_to_memory(
&self, &self,
mem: *mut u8, mem: *mut u8,
@@ -194,13 +195,15 @@ impl Context {
stack_maps: &mut dyn StackMapSink, stack_maps: &mut dyn StackMapSink,
) -> CodeInfo { ) -> CodeInfo {
let _tt = timing::binemit(); let _tt = timing::binemit();
let mut sink = MemoryCodeSink::new(mem);
let result = self let result = self
.mach_compile_result .mach_compile_result
.as_ref() .as_ref()
.expect("only using mach backend now"); .expect("only using mach backend now");
result.buffer.emit(&mut sink); let info = result.code_info();
let info = sink.info();
let mem = unsafe { std::slice::from_raw_parts_mut(mem, info.total_size as usize) };
mem.copy_from_slice(result.buffer.data());
for &MachReloc { for &MachReloc {
offset, offset,
srcloc, srcloc,

View File

@@ -130,7 +130,7 @@ impl TargetIsa for AArch64Backend {
Some(UnwindInfo::SystemV( Some(UnwindInfo::SystemV(
crate::isa::unwind::systemv::create_unwind_info_from_insts( crate::isa::unwind::systemv::create_unwind_info_from_insts(
&result.buffer.unwind_info[..], &result.buffer.unwind_info[..],
result.buffer.data.len(), result.buffer.data().len(),
&mapper, &mapper,
)?, )?,
)) ))
@@ -216,7 +216,7 @@ mod test {
isa_flags, isa_flags,
); );
let buffer = backend.compile_function(&mut func, false).unwrap().buffer; let buffer = backend.compile_function(&mut func, false).unwrap().buffer;
let code = &buffer.data[..]; let code = buffer.data();
// mov x1, #0x1234 // mov x1, #0x1234
// add w0, w0, w1 // add w0, w0, w1
@@ -271,7 +271,7 @@ mod test {
let result = backend let result = backend
.compile_function(&mut func, /* want_disasm = */ false) .compile_function(&mut func, /* want_disasm = */ false)
.unwrap(); .unwrap();
let code = &result.buffer.data[..]; let code = result.buffer.data();
// mov x1, #0x1234 // #4660 // mov x1, #0x1234 // #4660
// add w0, w0, w1 // add w0, w0, w1

View File

@@ -136,7 +136,7 @@ impl TargetIsa for S390xBackend {
Some(UnwindInfo::SystemV( Some(UnwindInfo::SystemV(
crate::isa::unwind::systemv::create_unwind_info_from_insts( crate::isa::unwind::systemv::create_unwind_info_from_insts(
&result.buffer.unwind_info[..], &result.buffer.unwind_info[..],
result.buffer.data.len(), result.buffer.data().len(),
&mapper, &mapper,
)?, )?,
)) ))
@@ -225,7 +225,7 @@ mod test {
let result = backend let result = backend
.compile_function(&mut func, /* want_disasm = */ false) .compile_function(&mut func, /* want_disasm = */ false)
.unwrap(); .unwrap();
let code = &result.buffer.data[..]; let code = result.buffer.data();
// ahi %r2, 0x1234 // ahi %r2, 0x1234
// br %r14 // br %r14
@@ -277,7 +277,7 @@ mod test {
let result = backend let result = backend
.compile_function(&mut func, /* want_disasm = */ false) .compile_function(&mut func, /* want_disasm = */ false)
.unwrap(); .unwrap();
let code = &result.buffer.data[..]; let code = result.buffer.data();
// FIXME: the branching logic should be optimized more // FIXME: the branching logic should be optimized more

View File

@@ -122,7 +122,7 @@ impl TargetIsa for X64Backend {
Some(UnwindInfo::SystemV( Some(UnwindInfo::SystemV(
crate::isa::unwind::systemv::create_unwind_info_from_insts( crate::isa::unwind::systemv::create_unwind_info_from_insts(
&result.buffer.unwind_info[..], &result.buffer.unwind_info[..],
result.buffer.data.len(), result.buffer.data().len(),
&mapper, &mapper,
)?, )?,
)) ))

View File

@@ -140,7 +140,7 @@
//! Given these invariants, we argue why each optimization preserves execution //! Given these invariants, we argue why each optimization preserves execution
//! semantics below (grep for "Preserves execution semantics"). //! semantics below (grep for "Preserves execution semantics").
use crate::binemit::{Addend, CodeOffset, CodeSink, Reloc, StackMap}; use crate::binemit::{Addend, CodeOffset, Reloc, StackMap};
use crate::ir::{ExternalName, Opcode, SourceLoc, TrapCode}; use crate::ir::{ExternalName, Opcode, SourceLoc, TrapCode};
use crate::isa::unwind::UnwindInst; use crate::isa::unwind::UnwindInst;
use crate::machinst::{ use crate::machinst::{
@@ -233,7 +233,7 @@ pub struct MachBuffer<I: VCodeInst> {
/// without fixups. This allows the type to be independent of the backend. /// without fixups. This allows the type to be independent of the backend.
pub struct MachBufferFinalized { pub struct MachBufferFinalized {
/// The buffer contents, as raw bytes. /// The buffer contents, as raw bytes.
pub data: SmallVec<[u8; 1024]>, data: SmallVec<[u8; 1024]>,
/// Any relocations referring to this code. Note that only *external* /// Any relocations referring to this code. Note that only *external*
/// relocations are tracked here; references to labels within the buffer are /// relocations are tracked here; references to labels within the buffer are
/// resolved before emission. /// resolved before emission.
@@ -1435,8 +1435,8 @@ impl MachBufferFinalized {
s s
} }
/// Emit this buffer to the given CodeSink. /// Get the code bytes.
pub fn emit<CS: CodeSink>(&self, sink: &mut CS) { pub fn data(&self) -> &[u8] {
// N.B.: we emit every section into the .text section as far as // N.B.: we emit every section into the .text section as far as
// the `CodeSink` is concerned; we do not bother to segregate // the `CodeSink` is concerned; we do not bother to segregate
// the contents into the actual program text, the jumptable and the // the contents into the actual program text, the jumptable and the
@@ -1448,9 +1448,7 @@ impl MachBufferFinalized {
// add this designation and segregate the output; take care, however, // add this designation and segregate the output; take care, however,
// to add the appropriate relocations in this case. // to add the appropriate relocations in this case.
for &byte in self.data.iter() { &self.data[..]
sink.put1(byte);
}
} }
/// Get the list of external relocations for this code. /// Get the list of external relocations for this code.
@@ -2066,20 +2064,7 @@ mod test {
let buf = buf.finish(); let buf = buf.finish();
#[derive(Default)] assert_eq!(buf.data(), &[1, 2, 3, 4]);
struct TestCodeSink {
offset: CodeOffset,
}
impl CodeSink for TestCodeSink {
fn put1(&mut self, _: u8) {
self.offset += 1;
}
}
let mut sink = TestCodeSink::default();
buf.emit(&mut sink);
assert_eq!(sink.offset, 4);
assert_eq!( assert_eq!(
buf.traps() buf.traps()
.iter() .iter()

View File

@@ -4,7 +4,7 @@
use crate::subtest::{run_filecheck, Context, SubTest}; use crate::subtest::{run_filecheck, Context, SubTest};
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use cranelift_codegen::binemit::{self, CodeInfo}; use cranelift_codegen::binemit::CodeInfo;
use cranelift_codegen::ir; use cranelift_codegen::ir;
use cranelift_reader::{TestCommand, TestOption}; use cranelift_reader::{TestCommand, TestOption};
use log::info; use log::info;
@@ -75,17 +75,6 @@ impl SubTest for TestCompile {
} }
} }
/// Code sink that simply counts bytes.
struct SizeSink {
offset: binemit::CodeOffset,
}
impl binemit::CodeSink for SizeSink {
fn put1(&mut self, _: u8) {
self.offset += 1;
}
}
fn check_precise_output(text: &str, context: &Context) -> Result<()> { fn check_precise_output(text: &str, context: &Context) -> Result<()> {
let actual = text.lines().collect::<Vec<_>>(); let actual = text.lines().collect::<Vec<_>>();