use std::collections::HashMap;
use std::fmt::Debug;
use std::fmt::Write;
use crate::compiler::code_space::CodeBuffer;
use crate::compiler::compiled_code::Symbol;
use crate::compiler::compiled_code::{CallSite, CompiledCode};
use crate::compiler::graph::Signature;
use crate::rt::Value;
pub(super) struct X64CompiledCode {
symbol: Symbol,
signature: Signature,
buf: CodeBuffer,
call_sites: HashMap<usize, Box<dyn CallSite>>,
}
impl X64CompiledCode {
pub fn new(
symbol: Symbol,
signature: Signature,
buf: CodeBuffer,
call_sites: HashMap<usize, Box<dyn CallSite>>,
) -> Self {
let code = Self {
symbol,
signature,
buf,
call_sites,
};
code
}
pub(super) fn link_lazy_compilation_trampoline(&self, addr: *const u8) {
for (_, call_site) in &self.call_sites {
call_site.patch(addr);
}
}
}
impl Debug for X64CompiledCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "X64CompiledCode[{:?}]", self.signature)
}
}
impl CompiledCode for X64CompiledCode {
fn symbol(&self) -> &Symbol {
&self.symbol
}
fn signature(&self) -> &Signature {
&self.signature
}
fn code_buffer(&self) -> &CodeBuffer {
&self.buf
}
fn entry_offset(&self) -> usize {
0
}
fn get_call_site(&self, return_address: *const u8) -> Option<&dyn CallSite> {
let offset = return_address as usize - self.buf.start() as usize;
self.call_sites.get(&offset).map(|x| x.as_ref())
}
fn link(&self, symbols: &HashMap<Symbol, *const u8>) {
for (_, call_site) in &self.call_sites {
let value = symbols[call_site.symbol()];
call_site.patch(value)
}
}
fn invoke(&self, args: &[Value]) -> Option<Value> {
let entry = self.entry();
super::rt::invoke_compiled_method(&self.signature, entry, args)
}
fn dump(&self) {
if !log_enabled!(target: "asm", log::Level::Trace) {
return;
}
const DUMP_RAW_BINARY: bool = false;
use capstone::prelude::*;
let cs = Capstone::new()
.x86()
.mode(arch::x86::ArchMode::Mode64)
.syntax(arch::x86::ArchSyntax::Intel)
.detail(true)
.build()
.expect("Failed to create Capstone object");
let mut log = String::new();
writeln!(log, "\n{:?}", self).unwrap();
let code: &[u8] = &self.buf;
if DUMP_RAW_BINARY {
for chunk in code.chunks(32) {
write!(log, " ").unwrap();
for byte in chunk {
write!(log, " {:02x?}", byte).unwrap();
}
writeln!(log).unwrap();
}
}
let start = code.as_ptr() as u64;
let insns = cs.disasm_all(code, start).expect("Failed to disassemble");
for i in insns.as_ref() {
writeln!(log, " {}", i).unwrap();
}
trace!(target: "asm", "{}", log);
}
}