Remove CodeSink
This commit is contained in:
@@ -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)]
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
)?,
|
)?,
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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<_>>();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user