use lazy_static::lazy_static;
use std::os::raw::c_char;
use std::ptr;
use std::sync::{Arc, Mutex};
#[cfg(not(feature = "generate-debug-information-no-export-symbols"))]
#[no_mangle]
#[inline(never)]
extern "C" fn __jit_debug_register_code() {
let x = 42;
unsafe {
std::ptr::read_volatile(&x);
}
}
#[derive(Debug)]
#[repr(u32)]
enum JitAction {
NoAction = 0,
RegisterFn = 1,
UnregisterFn = 2,
}
#[repr(C)]
struct JitCodeEntry {
next: *mut Self,
prev: *mut Self,
symfile_addr: *const c_char,
symfile_size: u64,
}
impl Default for JitCodeEntry {
fn default() -> Self {
Self {
next: ptr::null_mut(),
prev: ptr::null_mut(),
symfile_addr: ptr::null(),
symfile_size: 0,
}
}
}
#[no_mangle]
#[repr(C)]
struct JitDebugDescriptor {
version: u32,
action_flag: JitAction,
relevant_entry: *mut JitCodeEntry,
first_entry: *mut JitCodeEntry,
}
#[cfg(not(feature = "generate-debug-information-no-export-symbols"))]
#[no_mangle]
#[allow(non_upper_case_globals)]
static mut __jit_debug_descriptor: JitDebugDescriptor = JitDebugDescriptor {
version: 1,
action_flag: JitAction::NoAction,
relevant_entry: ptr::null_mut(),
first_entry: ptr::null_mut(),
};
#[cfg(feature = "generate-debug-information-no-export-symbols")]
extern "C" {
#[no_mangle]
static mut __jit_debug_descriptor: JitDebugDescriptor;
#[no_mangle]
fn __jit_debug_register_code();
}
lazy_static! {
static ref JIT_DEBUG_DESCRIPTOR_LOCK: Mutex<()> = Mutex::new(());
}
unsafe fn push_front(jce: *mut JitCodeEntry) {
if __jit_debug_descriptor.first_entry.is_null() {
__jit_debug_descriptor.first_entry = jce;
} else {
let old_first = __jit_debug_descriptor.first_entry;
assert!((*old_first).prev.is_null());
(*jce).next = old_first;
(*old_first).prev = jce;
__jit_debug_descriptor.first_entry = jce;
}
}
unsafe fn remove_node(jce: *mut JitCodeEntry) {
if __jit_debug_descriptor.first_entry == jce {
assert!((*jce).prev.is_null());
__jit_debug_descriptor.first_entry = (*jce).next;
}
if !(*jce).prev.is_null() {
(*(*jce).prev).next = (*jce).next;
}
if !(*jce).next.is_null() {
(*(*jce).next).prev = (*jce).prev;
}
}
#[derive(Debug)]
struct JitCodeDebugInfoEntryHandleInner(*mut JitCodeEntry);
unsafe impl Send for JitCodeDebugInfoEntryHandleInner {}
unsafe impl Sync for JitCodeDebugInfoEntryHandleInner {}
#[derive(Debug, Clone)]
pub(crate) struct JitCodeDebugInfoEntryHandle(Arc<JitCodeDebugInfoEntryHandleInner>);
impl Drop for JitCodeDebugInfoEntryHandleInner {
fn drop(&mut self) {
let _guard = JIT_DEBUG_DESCRIPTOR_LOCK.lock().unwrap();
unsafe {
__jit_debug_descriptor.relevant_entry = self.0;
__jit_debug_descriptor.action_flag = JitAction::UnregisterFn;
__jit_debug_register_code();
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
__jit_debug_descriptor.action_flag = JitAction::NoAction;
remove_node(self.0);
let entry: Box<JitCodeEntry> = Box::from_raw(self.0);
Vec::from_raw_parts(
entry.symfile_addr as *mut u8,
entry.symfile_size as _,
entry.symfile_size as _,
);
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct JitCodeDebugInfoManager {
inner: Vec<JitCodeDebugInfoEntryHandle>,
}
impl Default for JitCodeDebugInfoManager {
fn default() -> Self {
Self::new()
}
}
impl JitCodeDebugInfoManager {
pub(crate) fn new() -> Self {
unsafe {
__jit_debug_descriptor.version = 1;
}
Self { inner: vec![] }
}
pub(crate) fn register_new_jit_code_entry(
&mut self,
bytes: &[u8],
) -> JitCodeDebugInfoEntryHandle {
let mut owned_bytes = bytes.iter().cloned().collect::<Vec<u8>>();
owned_bytes.shrink_to_fit();
let ptr = owned_bytes.as_mut_ptr();
let len = owned_bytes.len();
std::mem::forget(owned_bytes);
let entry: *mut JitCodeEntry = Box::into_raw(Box::new(JitCodeEntry {
symfile_addr: ptr as *const _,
symfile_size: len as _,
..JitCodeEntry::default()
}));
unsafe {
let _guard = JIT_DEBUG_DESCRIPTOR_LOCK.lock().unwrap();
push_front(entry);
__jit_debug_descriptor.relevant_entry = entry;
__jit_debug_descriptor.action_flag = JitAction::RegisterFn;
__jit_debug_register_code();
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
__jit_debug_descriptor.action_flag = JitAction::NoAction;
}
let handle = JitCodeDebugInfoEntryHandle(Arc::new(JitCodeDebugInfoEntryHandleInner(entry)));
self.inner.push(handle.clone());
handle
}
}