use super::{Addend, CodeInfo, CodeOffset, CodeSink, Reloc};
use crate::binemit::stack_map::StackMap;
use crate::ir::{ExternalName, Opcode, SourceLoc, TrapCode};
use core::ptr::write_unaligned;
pub struct MemoryCodeSink<'a> {
data: *mut u8,
offset: isize,
relocs: &'a mut dyn RelocSink,
traps: &'a mut dyn TrapSink,
pub info: CodeInfo,
}
impl<'a> MemoryCodeSink<'a> {
pub unsafe fn new(
data: *mut u8,
relocs: &'a mut dyn RelocSink,
traps: &'a mut dyn TrapSink,
) -> Self {
Self {
data,
offset: 0,
info: CodeInfo {
code_size: 0,
jumptables_size: 0,
rodata_size: 0,
total_size: 0,
},
relocs,
traps,
}
}
}
pub trait RelocSink {
fn reloc_external(
&mut self,
_: CodeOffset,
_: SourceLoc,
_: Reloc,
_: &ExternalName,
_: Addend,
);
fn add_call_site(&mut self, _: Opcode, _: CodeOffset, _: SourceLoc) {}
}
pub trait TrapSink {
fn trap(&mut self, _: CodeOffset, _: SourceLoc, _: TrapCode);
}
impl<'a> MemoryCodeSink<'a> {
fn write<T>(&mut self, x: T) {
unsafe {
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
write_unaligned(self.data.offset(self.offset) as *mut T, x);
self.offset += core::mem::size_of::<T>() as isize;
}
}
}
impl<'a> CodeSink for MemoryCodeSink<'a> {
fn offset(&self) -> CodeOffset {
self.offset as CodeOffset
}
fn put1(&mut self, x: u8) {
self.write(x);
}
fn put2(&mut self, x: u16) {
self.write(x);
}
fn put4(&mut self, x: u32) {
self.write(x);
}
fn put8(&mut self, x: u64) {
self.write(x);
}
fn reloc_external(
&mut self,
srcloc: SourceLoc,
rel: Reloc,
name: &ExternalName,
addend: Addend,
) {
let ofs = self.offset();
self.relocs.reloc_external(ofs, srcloc, rel, name, addend);
}
fn trap(&mut self, code: TrapCode, srcloc: SourceLoc) {
let ofs = self.offset();
self.traps.trap(ofs, srcloc, code);
}
fn begin_jumptables(&mut self) {
self.info.code_size = self.offset();
}
fn begin_rodata(&mut self) {
self.info.jumptables_size = self.offset() - self.info.code_size;
}
fn end_codegen(&mut self) {
self.info.rodata_size = self.offset() - (self.info.jumptables_size + self.info.code_size);
self.info.total_size = self.offset();
}
fn add_call_site(&mut self, opcode: Opcode, loc: SourceLoc) {
debug_assert!(
opcode.is_call(),
"adding call site info for a non-call instruction."
);
let ret_addr = self.offset();
self.relocs.add_call_site(opcode, ret_addr, loc);
}
}
#[derive(Default)]
pub struct NullRelocSink {}
impl RelocSink for NullRelocSink {
fn reloc_external(
&mut self,
_: CodeOffset,
_: SourceLoc,
_: Reloc,
_: &ExternalName,
_: Addend,
) {
}
}
#[derive(Default)]
pub struct NullTrapSink {}
impl TrapSink for NullTrapSink {
fn trap(&mut self, _offset: CodeOffset, _srcloc: SourceLoc, _code: TrapCode) {}
}
pub trait StackMapSink {
fn add_stack_map(&mut self, _: CodeOffset, _: StackMap);
}
pub struct NullStackMapSink {}
impl StackMapSink for NullStackMapSink {
fn add_stack_map(&mut self, _: CodeOffset, _: StackMap) {}
}