use std::collections::HashMap;
#[derive(Debug)]
pub struct CompilationJob {
pub module_name: String,
pub dylib_name: String,
pub job_id: u64,
pub high_priority: bool,
}
#[derive(Debug)]
pub enum CompilationResult {
Success,
Failure(String),
}
pub struct ConcurrentCompiler {
pending: Vec<CompilationJob>,
is_running: bool,
completed_jobs: u64,
}
impl ConcurrentCompiler {
pub fn new(_worker_count: usize) -> Self {
Self {
pending: Vec::new(),
is_running: true,
completed_jobs: 0,
}
}
pub fn submit(&mut self, job: CompilationJob) -> Result<(), String> {
if !self.is_running {
return Err("concurrent compiler is shut down".into());
}
self.pending.push(job);
Ok(())
}
pub fn process_all(&mut self) {
let count = self.pending.len();
self.pending.clear();
self.completed_jobs += count as u64;
}
pub fn wait_for_all(&mut self) {
self.process_all();
}
pub fn shutdown(&mut self) {
self.is_running = false;
self.pending.clear();
}
pub fn worker_count(&self) -> usize {
1
}
pub fn pending_jobs(&self) -> u64 {
self.pending.len() as u64
}
pub fn completed_jobs(&self) -> u64 {
self.completed_jobs
}
}
pub struct GDBJITDebugRegistrar {
enabled: bool,
entries: Vec<JITCodeEntry>,
}
#[derive(Debug, Clone)]
pub struct JITCodeEntry {
pub next_entry: usize,
pub prev_entry: usize,
pub symfile_addr: usize,
pub symfile_size: u64,
}
impl GDBJITDebugRegistrar {
pub fn new() -> Self {
Self {
enabled: false,
entries: Vec::new(),
}
}
pub fn enable(&mut self) {
self.enabled = true;
}
pub fn disable(&mut self) {
self.enabled = false;
}
pub fn register_code(&mut self, symfile_addr: usize, symfile_size: u64) {
if !self.enabled {
return;
}
let entry = JITCodeEntry {
next_entry: 0,
prev_entry: self.entries.len().wrapping_sub(1),
symfile_addr,
symfile_size,
};
if let Some(prev) = self.entries.last_mut() {
prev.next_entry = symfile_addr;
}
self.entries.push(entry);
self.notify_gdb();
}
fn notify_gdb(&self) {}
pub fn unregister_all(&mut self) {
self.entries.clear();
}
pub fn is_enabled(&self) -> bool {
self.enabled
}
pub fn entry_count(&self) -> usize {
self.entries.len()
}
pub fn emit_descriptor_ir(&self) -> String {
if !self.enabled {
return String::new();
}
r#"
; GDB JIT Debug Descriptor
@__jit_debug_descriptor = global { i32, ptr, ptr } {
i32 1,
ptr null,
ptr @__jit_debug_register_code
}
declare void @__jit_debug_register_code()
"#
.to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_concurrent_compiler_create() {
let cc = ConcurrentCompiler::new(2);
assert_eq!(cc.worker_count(), 1);
assert!(cc.is_running);
assert_eq!(cc.pending_jobs(), 0);
}
#[test]
fn test_concurrent_compiler_submit() {
let mut cc = ConcurrentCompiler::new(1);
let job = CompilationJob {
module_name: "test".into(),
dylib_name: "main".into(),
job_id: 1,
high_priority: false,
};
assert!(cc.submit(job).is_ok());
assert_eq!(cc.pending_jobs(), 1);
cc.process_all();
assert_eq!(cc.pending_jobs(), 0);
assert_eq!(cc.completed_jobs(), 1);
}
#[test]
fn test_concurrent_compiler_shutdown() {
let mut cc = ConcurrentCompiler::new(1);
cc.shutdown();
assert!(!cc.is_running);
}
#[test]
fn test_gdb_jit_registrar_enable() {
let mut reg = GDBJITDebugRegistrar::new();
assert!(!reg.is_enabled());
reg.enable();
assert!(reg.is_enabled());
}
#[test]
fn test_gdb_jit_register_code() {
let mut reg = GDBJITDebugRegistrar::new();
reg.enable();
reg.register_code(0x1000, 4096);
assert_eq!(reg.entry_count(), 1);
}
#[test]
fn test_gdb_jit_descriptor_ir() {
let mut reg = GDBJITDebugRegistrar::new();
reg.enable();
let ir = reg.emit_descriptor_ir();
assert!(ir.contains("__jit_debug_descriptor"));
}
}