use std::{
cmp::Ordering,
collections::{BinaryHeap, HashMap},
rc::Rc,
time::{Duration, Instant},
};
use typescript_types::{TsError, TsValue};
use crate::codegen::Instruction;
use super::optimizer::{JITOptimizer, OptimizationLevel};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum JITEvent {
CompilationStarted {
function_name: String,
complexity: usize,
reason: CompilationReason,
},
CompilationCompleted {
function_name: String,
duration: Duration,
optimization_level: String,
},
CompilationFailed {
function_name: String,
error: String,
},
HotFunctionDetected {
function_name: String,
call_count: usize,
avg_time: u64,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CompilationReason {
CallCountThreshold,
TimeThreshold,
WindowAverageThreshold,
PriorityScheduled,
}
pub trait JITEventCallback {
fn on_event(&self, event: &JITEvent);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompileStatus {
NotCompiled,
Compiling,
Compiled,
Failed,
}
#[derive(Debug, Clone)]
pub struct HotFunctionInfo {
pub call_count: usize,
pub total_time: u64,
pub avg_time: u64,
pub last_time: u64,
pub time_window: Vec<u64>,
pub complexity: usize,
pub execution_frequency: f64,
pub avg_call_depth: f64,
pub instruction_density: f64,
pub branch_prediction_success: f64,
pub memory_access_frequency: usize,
pub compile_status: CompileStatus,
pub compile_error: Option<String>,
pub compiled_at: Option<Instant>,
pub compile_duration: Option<Duration>,
pub optimization_level: Option<OptimizationLevel>,
}
impl Default for HotFunctionInfo {
fn default() -> Self {
Self {
call_count: 0,
total_time: 0,
avg_time: 0,
last_time: 0,
time_window: Vec::with_capacity(10),
complexity: 1,
execution_frequency: 0.0,
avg_call_depth: 0.0,
instruction_density: 0.0,
branch_prediction_success: 0.0,
memory_access_frequency: 0,
compile_status: CompileStatus::NotCompiled,
compile_error: None,
compiled_at: None,
compile_duration: None,
optimization_level: None,
}
}
}
#[derive(Debug, Clone)]
pub struct PriorityEntry {
pub function_name: String,
pub priority_score: f64,
pub call_count: usize,
pub avg_time: u64,
pub complexity: usize,
pub execution_frequency: f64,
pub instruction_density: f64,
pub memory_access_frequency: usize,
}
impl PartialEq for PriorityEntry {
fn eq(&self, other: &Self) -> bool {
self.priority_score == other.priority_score
}
}
impl Eq for PriorityEntry {}
impl PartialOrd for PriorityEntry {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for PriorityEntry {
fn cmp(&self, other: &Self) -> Ordering {
let score_cmp = self.priority_score.partial_cmp(&other.priority_score).unwrap_or(Ordering::Equal);
if score_cmp != Ordering::Equal {
return score_cmp;
}
let call_cmp = other.call_count.cmp(&self.call_count);
if call_cmp != Ordering::Equal {
return call_cmp;
}
let time_cmp = other.avg_time.cmp(&self.avg_time);
if time_cmp != Ordering::Equal {
return time_cmp;
}
other.complexity.cmp(&self.complexity)
}
}
#[derive(Debug)]
pub struct HotFunctionPriorityQueue {
heap: BinaryHeap<PriorityEntry>,
queued_functions: HashMap<String, f64>,
last_updated: HashMap<String, Instant>,
}
impl HotFunctionPriorityQueue {
pub fn new() -> Self {
Self { heap: BinaryHeap::new(), queued_functions: HashMap::new(), last_updated: HashMap::new() }
}
pub fn push(&mut self, entry: PriorityEntry) {
if let Some(&existing_score) = self.queued_functions.get(&entry.function_name) {
if entry.priority_score <= existing_score {
return;
}
}
self.queued_functions.insert(entry.function_name.clone(), entry.priority_score);
self.last_updated.insert(entry.function_name.clone(), Instant::now());
self.heap.push(entry);
}
pub fn pop(&mut self) -> Option<PriorityEntry> {
loop {
let entry = self.heap.pop()?;
if let Some(&score) = self.queued_functions.get(&entry.function_name) {
if (score - entry.priority_score).abs() < f64::EPSILON {
self.queued_functions.remove(&entry.function_name);
self.last_updated.remove(&entry.function_name);
return Some(entry);
}
}
}
}
pub fn peek(&self) -> Option<&PriorityEntry> {
self.heap.peek()
}
pub fn is_empty(&self) -> bool {
self.heap.is_empty()
}
pub fn len(&self) -> usize {
self.heap.len()
}
pub fn clear(&mut self) {
self.heap.clear();
self.queued_functions.clear();
self.last_updated.clear();
}
pub fn contains(&self, function_name: &str) -> bool {
self.queued_functions.contains_key(function_name)
}
pub fn remove(&mut self, function_name: &str) {
self.queued_functions.remove(function_name);
self.last_updated.remove(function_name);
}
pub fn update_priority(&mut self, entry: PriorityEntry) {
self.push(entry);
}
pub fn cleanup_expired(&mut self, max_age: Duration) {
let now = Instant::now();
let expired: Vec<String> = self
.last_updated
.iter()
.filter(|&(_, time)| now.duration_since(*time) > max_age)
.map(|(name, _)| name.clone())
.collect();
for name in expired {
self.remove(&name);
}
}
pub fn get_all_functions(&self) -> Vec<String> {
self.queued_functions.keys().cloned().collect()
}
}
impl Default for HotFunctionPriorityQueue {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Default)]
pub struct JITStatistics {
pub total_compilations: usize,
pub successful_compilations: usize,
pub failed_compilations: usize,
pub total_compile_time: Duration,
pub hot_function_count: usize,
pub compiled_function_count: usize,
pub total_calls: usize,
pub total_execution_time: Duration,
pub cache_hits: usize,
pub cache_misses: usize,
}
impl JITStatistics {
pub fn new() -> Self {
Self::default()
}
pub fn cache_hit_rate(&self) -> f64 {
let total = self.cache_hits + self.cache_misses;
if total == 0 {
return 0.0;
}
self.cache_hits as f64 / total as f64
}
pub fn avg_compile_time(&self) -> Duration {
if self.total_compilations == 0 {
return Duration::ZERO;
}
self.total_compile_time / self.total_compilations as u32
}
pub fn success_rate(&self) -> f64 {
if self.total_compilations == 0 {
return 0.0;
}
self.successful_compilations as f64 / self.total_compilations as f64
}
}
#[derive(Debug, Clone)]
pub struct AdaptiveThresholdConfig {
pub base_call_threshold: usize,
pub base_time_threshold: u64,
pub complexity_weight: f64,
pub time_weight: f64,
pub call_weight: f64,
pub frequency_weight: f64,
pub density_weight: f64,
pub memory_weight: f64,
pub min_threshold: usize,
pub max_threshold: usize,
pub high_complexity_threshold: usize,
pub low_complexity_threshold: usize,
}
impl Default for AdaptiveThresholdConfig {
fn default() -> Self {
Self {
base_call_threshold: 100,
base_time_threshold: 100,
complexity_weight: 0.25,
time_weight: 0.3,
call_weight: 0.2,
frequency_weight: 0.1,
density_weight: 0.1,
memory_weight: 0.05,
min_threshold: 10,
max_threshold: 1000,
high_complexity_threshold: 50,
low_complexity_threshold: 10,
}
}
}
impl AdaptiveThresholdConfig {
pub fn new() -> Self {
Self::default()
}
pub fn calculate_call_threshold(&self, complexity: usize, execution_frequency: f64, instruction_density: f64) -> usize {
let complexity_factor = if complexity > self.high_complexity_threshold {
0.5
}
else if complexity < self.low_complexity_threshold {
1.5
}
else {
let complexity_ratio = (complexity - self.low_complexity_threshold) as f64
/ (self.high_complexity_threshold - self.low_complexity_threshold) as f64;
1.5 - complexity_ratio
};
let frequency_factor = if execution_frequency > 10.0 {
0.8
}
else if execution_frequency < 1.0 {
1.2
}
else {
1.0
};
let density_factor = if instruction_density > 100.0 {
0.9
}
else if instruction_density < 10.0 {
1.1
}
else {
1.0
};
let threshold = (self.base_call_threshold as f64 * complexity_factor * frequency_factor * density_factor) as usize;
threshold.clamp(self.min_threshold, self.max_threshold)
}
pub fn calculate_time_threshold(
&self,
complexity: usize,
memory_access_frequency: usize,
branch_prediction_success: f64,
) -> u64 {
let complexity_factor = if complexity > self.high_complexity_threshold {
0.5
}
else if complexity < self.low_complexity_threshold {
1.5
}
else {
let complexity_ratio = (complexity - self.low_complexity_threshold) as f64
/ (self.high_complexity_threshold - self.low_complexity_threshold) as f64;
1.5 - complexity_ratio
};
let memory_factor = if memory_access_frequency > 100 {
0.8
}
else if memory_access_frequency < 10 {
1.2
}
else {
1.0
};
let branch_factor = if branch_prediction_success < 0.5 {
0.9
}
else if branch_prediction_success > 0.9 {
1.1
}
else {
1.0
};
(self.base_time_threshold as f64 * complexity_factor * memory_factor * branch_factor) as u64
}
pub fn calculate_priority_score(&self, info: &HotFunctionInfo) -> f64 {
let call_score = (info.call_count as f64).ln() * self.call_weight;
let time_score = (info.avg_time as f64 + 1.0).ln() * self.time_weight;
let complexity_score = (info.complexity as f64).ln() * self.complexity_weight;
let frequency_score = (info.execution_frequency + 1.0).ln() * self.frequency_weight;
let density_score = (info.instruction_density + 1.0).ln() * self.density_weight;
let memory_score = (info.memory_access_frequency as f64 + 1.0).ln() * self.memory_weight;
call_score + time_score + complexity_score + frequency_score + density_score + memory_score
}
}
pub struct JITCompiler {
compiled_functions: HashMap<String, Rc<dyn Fn(&[TsValue]) -> TsValue>>,
hot_functions: HashMap<String, HotFunctionInfo>,
priority_queue: HotFunctionPriorityQueue,
threshold_config: AdaptiveThresholdConfig,
statistics: JITStatistics,
event_callbacks: Vec<Rc<dyn JITEventCallback>>,
default_optimization_level: OptimizationLevel,
compilation_tasks: std::sync::Arc<std::sync::Mutex<std::collections::VecDeque<(String, Vec<Instruction>)>>>,
background_thread: Option<std::thread::JoinHandle<()>>,
terminate_signal: std::sync::Arc<std::sync::atomic::AtomicBool>,
warmup_functions: Vec<(String, Vec<Instruction>)>,
cache_size_limit: usize,
cache_access_times: HashMap<String, Instant>,
cache_usage_counts: HashMap<String, usize>,
}
impl JITCompiler {
pub fn new() -> Self {
let compilation_tasks = std::sync::Arc::new(std::sync::Mutex::new(std::collections::VecDeque::new()));
let terminate_signal = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let tasks_clone = compilation_tasks.clone();
let signal_clone = terminate_signal.clone();
let background_thread = std::thread::spawn(move || {
while !signal_clone.load(std::sync::atomic::Ordering::Relaxed) {
if let Ok(mut tasks) = tasks_clone.lock() {
if let Some((_function_name, _instructions)) = tasks.pop_front() {
drop(tasks);
std::thread::sleep(std::time::Duration::from_millis(10));
}
else {
drop(tasks);
std::thread::sleep(std::time::Duration::from_millis(50));
}
}
}
});
Self {
compiled_functions: HashMap::new(),
hot_functions: HashMap::new(),
priority_queue: HotFunctionPriorityQueue::new(),
threshold_config: AdaptiveThresholdConfig::new(),
statistics: JITStatistics::new(),
event_callbacks: Vec::new(),
default_optimization_level: OptimizationLevel::High,
compilation_tasks,
background_thread: Some(background_thread),
terminate_signal,
warmup_functions: Vec::new(),
cache_size_limit: 1000,
cache_access_times: HashMap::new(),
cache_usage_counts: HashMap::new(),
}
}
pub fn with_config(config: AdaptiveThresholdConfig) -> Self {
let compilation_tasks = std::sync::Arc::new(std::sync::Mutex::new(std::collections::VecDeque::new()));
let terminate_signal = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let tasks_clone = compilation_tasks.clone();
let signal_clone = terminate_signal.clone();
let background_thread = std::thread::spawn(move || {
while !signal_clone.load(std::sync::atomic::Ordering::Relaxed) {
if let Ok(mut tasks) = tasks_clone.lock() {
if let Some((_function_name, _instructions)) = tasks.pop_front() {
drop(tasks);
std::thread::sleep(std::time::Duration::from_millis(10));
}
else {
drop(tasks);
std::thread::sleep(std::time::Duration::from_millis(50));
}
}
}
});
Self {
compiled_functions: HashMap::new(),
hot_functions: HashMap::new(),
priority_queue: HotFunctionPriorityQueue::new(),
threshold_config: config,
statistics: JITStatistics::new(),
event_callbacks: Vec::new(),
default_optimization_level: OptimizationLevel::High,
compilation_tasks,
background_thread: Some(background_thread),
terminate_signal,
warmup_functions: Vec::new(),
cache_size_limit: 1000,
cache_access_times: HashMap::new(),
cache_usage_counts: HashMap::new(),
}
}
pub fn register_callback(&mut self, callback: Rc<dyn JITEventCallback>) {
self.event_callbacks.push(callback);
}
pub fn clear_callbacks(&mut self) {
self.event_callbacks.clear();
}
fn emit_event(&self, event: JITEvent) {
for callback in &self.event_callbacks {
callback.on_event(&event);
}
}
pub fn get_adaptive_call_threshold(&self, complexity: usize, execution_frequency: f64, instruction_density: f64) -> usize {
self.threshold_config.calculate_call_threshold(complexity, execution_frequency, instruction_density)
}
pub fn get_adaptive_time_threshold(
&self,
complexity: usize,
memory_access_frequency: usize,
branch_prediction_success: f64,
) -> u64 {
self.threshold_config.calculate_time_threshold(complexity, memory_access_frequency, branch_prediction_success)
}
pub fn should_compile(&mut self, function_name: &str) -> bool {
let (
call_count,
avg_time,
complexity,
execution_frequency,
instruction_density,
memory_access_frequency,
branch_prediction_success,
compile_status,
time_window,
) = {
let info = self.hot_functions.entry(function_name.to_string()).or_insert_with(HotFunctionInfo::default);
info.call_count += 1;
self.statistics.total_calls += 1;
(
info.call_count,
info.avg_time,
info.complexity,
info.execution_frequency,
info.instruction_density,
info.memory_access_frequency,
info.branch_prediction_success,
info.compile_status,
info.time_window.clone(),
)
};
if compile_status == CompileStatus::Compiled {
self.statistics.cache_hits += 1;
return false;
}
self.statistics.cache_misses += 1;
let adaptive_call_threshold = self.get_adaptive_call_threshold(complexity, execution_frequency, instruction_density);
let adaptive_time_threshold =
self.get_adaptive_time_threshold(complexity, memory_access_frequency, branch_prediction_success);
let window_avg = if !time_window.is_empty() { time_window.iter().sum::<u64>() / time_window.len() as u64 } else { 0 };
let should_compile = (call_count >= adaptive_call_threshold
|| avg_time >= adaptive_time_threshold
|| window_avg >= adaptive_time_threshold)
&& compile_status != CompileStatus::Compiling
&& compile_status != CompileStatus::Compiled;
if should_compile {
let reason = if call_count >= adaptive_call_threshold {
CompilationReason::CallCountThreshold
}
else if avg_time >= adaptive_time_threshold {
CompilationReason::TimeThreshold
}
else {
CompilationReason::WindowAverageThreshold
};
self.emit_event(JITEvent::HotFunctionDetected { function_name: function_name.to_string(), call_count, avg_time });
self.emit_event(JITEvent::CompilationStarted { function_name: function_name.to_string(), complexity, reason });
}
should_compile
}
pub fn record_execution_time(&mut self, function_name: &str, execution_time: u64) {
if let Some(info) = self.hot_functions.get_mut(function_name) {
info.total_time += execution_time;
info.avg_time = info.total_time / info.call_count as u64;
info.last_time = execution_time;
info.time_window.push(execution_time);
if info.time_window.len() > 10 {
info.time_window.remove(0);
}
self.statistics.total_execution_time += Duration::from_micros(execution_time);
}
}
pub fn set_function_complexity(&mut self, function_name: &str, complexity: usize) {
let info = self.hot_functions.entry(function_name.to_string()).or_insert_with(HotFunctionInfo::default);
info.complexity = complexity;
}
pub fn enqueue_for_compilation(&mut self, function_name: &str) {
if let Some(info) = self.hot_functions.get(function_name) {
if info.compile_status == CompileStatus::NotCompiled || info.compile_status == CompileStatus::Failed {
let priority_score = self.threshold_config.calculate_priority_score(info);
let entry = PriorityEntry {
function_name: function_name.to_string(),
priority_score,
call_count: info.call_count,
avg_time: info.avg_time,
complexity: info.complexity,
execution_frequency: info.execution_frequency,
instruction_density: info.instruction_density,
memory_access_frequency: info.memory_access_frequency,
};
self.priority_queue.push(entry);
}
}
}
pub fn get_next_compilation_target(&mut self) -> Option<String> {
while let Some(entry) = self.priority_queue.pop() {
if let Some(info) = self.hot_functions.get(&entry.function_name) {
if info.compile_status == CompileStatus::NotCompiled || info.compile_status == CompileStatus::Failed {
return Some(entry.function_name);
}
}
}
None
}
pub fn get_compile_status(&self, function_name: &str) -> CompileStatus {
self.hot_functions.get(function_name).map(|info| info.compile_status).unwrap_or(CompileStatus::NotCompiled)
}
fn set_compile_status(&mut self, function_name: &str, status: CompileStatus) {
if let Some(info) = self.hot_functions.get_mut(function_name) {
info.compile_status = status;
}
}
pub fn compile_function(
&mut self,
function_name: &str,
instructions: &[Instruction],
) -> Result<Rc<dyn Fn(&[TsValue]) -> TsValue>, TsError> {
if let Some(compiled) = self.compiled_functions.get(function_name) {
return Ok(compiled.clone());
}
self.set_compile_status(function_name, CompileStatus::Compiling);
self.statistics.total_compilations += 1;
let start_time = Instant::now();
let optimization_level = self.select_optimization_level(function_name);
let result = self.compile_to_machine_code(function_name, instructions, &optimization_level);
let duration = start_time.elapsed();
self.statistics.total_compile_time += duration;
match result {
Ok(compiled_fn) => {
self.compiled_functions.insert(function_name.to_string(), compiled_fn.clone());
if let Some(info) = self.hot_functions.get_mut(function_name) {
info.compile_status = CompileStatus::Compiled;
info.compiled_at = Some(Instant::now());
info.compile_duration = Some(duration);
info.optimization_level = Some(optimization_level.clone());
}
self.update_cache_info(function_name);
self.cleanup_cache();
self.statistics.successful_compilations += 1;
self.statistics.compiled_function_count += 1;
self.emit_event(JITEvent::CompilationCompleted {
function_name: function_name.to_string(),
duration,
optimization_level: format!("{:?}", optimization_level),
});
Ok(compiled_fn)
}
Err(ref err) => {
if let Some(info) = self.hot_functions.get_mut(function_name) {
info.compile_status = CompileStatus::Failed;
info.compile_error = Some(err.to_string());
}
self.statistics.failed_compilations += 1;
self.emit_event(JITEvent::CompilationFailed {
function_name: function_name.to_string(),
error: err.to_string(),
});
result
}
}
}
fn select_optimization_level(&self, function_name: &str) -> OptimizationLevel {
if let Some(info) = self.hot_functions.get(function_name) {
if info.call_count > 1000 && info.avg_time > 500 {
OptimizationLevel::High
}
else if info.call_count > 500 || (info.avg_time > 200 && info.complexity > 20) {
OptimizationLevel::Medium
}
else if info.call_count > 100 || info.complexity > 10 {
OptimizationLevel::Basic
}
else {
OptimizationLevel::None
}
}
else {
OptimizationLevel::Basic
}
}
fn compile_to_machine_code(
&self,
function_name: &str,
instructions: &[Instruction],
optimization_level: &OptimizationLevel,
) -> Result<Rc<dyn Fn(&[TsValue]) -> TsValue + 'static>, TsError> {
let optimized_instructions = self.optimize_instructions_for_jit(instructions, optimization_level);
let function_name = function_name.to_string();
let optimized_instructions = optimized_instructions;
let compiled_fn = Rc::new(move |args: &[TsValue]| {
println!("JIT executing function: {}", function_name);
let mut vm = crate::vm::VM::new(vec![]);
for (i, arg) in args.iter().enumerate() {
vm.set_local(i, arg.clone());
}
match vm.execute_instructions(&optimized_instructions) {
Ok(result) => result,
Err(_) => TsValue::Undefined,
}
});
Ok(compiled_fn)
}
fn optimize_instructions_for_jit(
&self,
instructions: &[Instruction],
optimization_level: &OptimizationLevel,
) -> Vec<Instruction> {
let mut optimizer = JITOptimizer::new(optimization_level.clone());
optimizer.optimize_instructions(instructions)
}
pub fn get_compiled_function(&mut self, function_name: &str) -> Option<Rc<dyn Fn(&[TsValue]) -> TsValue>> {
let result = self.compiled_functions.get(function_name).cloned();
if result.is_some() {
self.statistics.cache_hits += 1;
self.update_cache_info(function_name);
}
else {
self.statistics.cache_misses += 1;
}
result
}
fn update_cache_info(&mut self, function_name: &str) {
self.cache_access_times.insert(function_name.to_string(), Instant::now());
*self.cache_usage_counts.entry(function_name.to_string()).or_insert(0) += 1;
}
pub fn cleanup_cache(&mut self) {
if self.compiled_functions.len() > self.cache_size_limit {
let mut cache_items: Vec<(String, usize, Instant)> = self
.cache_usage_counts
.iter()
.filter_map(|(name, count)| self.cache_access_times.get(name).map(|time| (name.clone(), *count, *time)))
.collect();
cache_items.sort_by(|a, b| if a.1 != b.1 { a.1.cmp(&b.1) } else { a.2.cmp(&b.2) });
let items_to_remove = cache_items.len() - self.cache_size_limit;
for item in cache_items.iter().take(items_to_remove) {
self.compiled_functions.remove(&item.0);
self.cache_access_times.remove(&item.0);
self.cache_usage_counts.remove(&item.0);
if let Some(info) = self.hot_functions.get_mut(&item.0) {
info.compile_status = CompileStatus::NotCompiled;
info.compiled_at = None;
info.compile_duration = None;
}
}
}
}
pub fn set_cache_size_limit(&mut self, limit: usize) {
self.cache_size_limit = limit;
self.cleanup_cache();
}
pub fn get_cache_size_limit(&self) -> usize {
self.cache_size_limit
}
pub fn get_current_cache_size(&self) -> usize {
self.compiled_functions.len()
}
pub fn get_hot_function_info(&self, function_name: &str) -> Option<&HotFunctionInfo> {
self.hot_functions.get(function_name)
}
pub fn get_hot_function_names(&self) -> Vec<String> {
self.hot_functions.keys().cloned().collect()
}
pub fn get_statistics(&self) -> &JITStatistics {
&self.statistics
}
pub fn reset_statistics(&mut self) {
self.statistics = JITStatistics::new();
}
pub fn pending_compilation_count(&self) -> usize {
self.priority_queue.len()
}
pub fn is_queued_for_compilation(&self, function_name: &str) -> bool {
self.priority_queue.contains(function_name)
}
pub fn clear_cache(&mut self) {
self.compiled_functions.clear();
for info in self.hot_functions.values_mut() {
info.compile_status = CompileStatus::NotCompiled;
info.compiled_at = None;
info.compile_duration = None;
info.compile_error = None;
}
self.statistics.compiled_function_count = 0;
}
pub fn set_optimization_level(&mut self, level: OptimizationLevel) {
self.default_optimization_level = level;
}
pub fn get_optimization_level(&self) -> &OptimizationLevel {
&self.default_optimization_level
}
pub fn get_threshold_config(&self) -> &AdaptiveThresholdConfig {
&self.threshold_config
}
pub fn set_threshold_config(&mut self, config: AdaptiveThresholdConfig) {
self.threshold_config = config;
}
pub fn update_priorities(&mut self) {
for (function_name, info) in &self.hot_functions {
if info.compile_status == CompileStatus::NotCompiled || info.compile_status == CompileStatus::Failed {
let priority_score = self.threshold_config.calculate_priority_score(info);
let entry = PriorityEntry {
function_name: function_name.clone(),
priority_score,
call_count: info.call_count,
avg_time: info.avg_time,
complexity: info.complexity,
execution_frequency: info.execution_frequency,
instruction_density: info.instruction_density,
memory_access_frequency: info.memory_access_frequency,
};
self.priority_queue.push(entry);
}
}
}
pub fn add_background_compilation_task(&mut self, function_name: &str, instructions: &[Instruction]) {
let task = (function_name.to_string(), instructions.to_vec());
if let Ok(mut tasks) = self.compilation_tasks.lock() {
tasks.push_back(task);
}
}
pub fn add_warmup_function(&mut self, function_name: &str, instructions: &[Instruction]) {
self.warmup_functions.push((function_name.to_string(), instructions.to_vec()));
}
pub fn run_warmup(&mut self) {
let warmup_functions = self.warmup_functions.clone();
for (function_name, instructions) in warmup_functions {
self.set_function_complexity(&function_name, instructions.len());
self.add_background_compilation_task(&function_name, &instructions);
}
}
pub fn execute_function(
&mut self,
function_name: &str,
args: &[TsValue],
instructions: &[Instruction],
) -> Result<TsValue, TsError> {
if let Some(compiled_fn) = self.get_compiled_function(function_name) {
return Ok(compiled_fn(args));
}
let compiled_fn = self.compile_function(function_name, instructions)?;
Ok(compiled_fn(args))
}
pub fn shutdown(&mut self) {
self.terminate_signal.store(true, std::sync::atomic::Ordering::Relaxed);
if let Some(thread) = self.background_thread.take() {
let _ = thread.join();
}
}
pub fn hot_function_count(&self) -> usize {
self.hot_functions.len()
}
pub fn compiled_function_count(&self) -> usize {
self.compiled_functions.len()
}
}
impl Default for JITCompiler {
fn default() -> Self {
Self::new()
}
}