use crate::class_file::{ClassFile, MethodInfo};
use crate::error::{JvmError, RuntimeError};
use crate::memory::{Memory, StackFrame, Value};
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::Arc;
pub trait BytecodeExecutor {
fn execute_method(
&mut self,
class: &ClassFile,
method: &MethodInfo,
frame: &mut StackFrame,
) -> Result<(), JvmError>;
fn dispatch_instruction(
&mut self,
class: &ClassFile,
bytecode: &[u8],
frame: &mut StackFrame,
opcode: u8,
) -> Result<(), JvmError>;
fn resolve_method(
&mut self,
class_name: &str,
method_name: &str,
descriptor: &str,
) -> Result<(String, MethodInfo), JvmError>;
}
pub trait MemoryManager {
fn new_instance(&mut self, class_name: &str) -> Result<Value, JvmError>;
fn allocate_array(&mut self, array_type: &str, length: i32) -> Result<Value, JvmError>;
fn get_field_value(&mut self, obj: &Value, field_name: &str) -> Result<Value, JvmError>;
fn set_field_value(&mut self, obj: &Value, field_name: &str, value: Value) -> Result<(), JvmError>;
fn get_memory_stats(&self) -> HashMap<String, usize>;
}
pub trait ClassManager {
fn load_class<P: AsRef<Path>>(&mut self, path: P) -> Result<(), JvmError>;
fn load_class_by_name(&mut self, class_name: &str) -> Result<(), JvmError>;
fn get_class(&self, name: &str) -> Option<&ClassFile>;
fn is_class_loaded(&self, name: &str) -> bool;
fn get_loaded_classes(&self) -> Vec<String>;
}
pub trait JitManagerProvider {
fn is_jit_enabled(&self) -> bool;
fn set_jit_enabled(&mut self, enabled: bool);
fn jit_manager(&mut self) -> Option<&mut crate::jit::JitManager>;
fn configure_jit(&mut self, config: crate::jit::TieredCompilationConfig);
}
pub trait DebugProvider {
fn set_debugger(&mut self, debugger: crate::debug::JvmDebugger);
fn set_trace_recorder(&mut self, recorder: Option<crate::trace::TraceRecorder>);
fn memory(&self) -> &Memory;
fn memory_mut(&mut self) -> &mut Memory;
fn get_reflection_api(&self) -> &crate::reflection::ReflectionApi;
}
pub trait NativeMethodHandler {
fn register_native_method(
&mut self,
class_name: &str,
method_name: &str,
signature: &str,
function: Box<dyn Fn(&[Value], &mut Memory) -> Result<Value, JvmError> + Send + Sync>,
) -> Result<(), JvmError>;
fn invoke_native_method(
&mut self,
class_name: &str,
method_name: &str,
signature: &str,
args: &[Value],
) -> Result<Value, JvmError>;
fn has_native_method(&self, class_name: &str, method_name: &str, signature: &str) -> bool;
}
pub trait RuntimeConfig {
fn set_deterministic(&mut self, config: Option<crate::deterministic::DeterministicConfig>);
fn set_profiler(&mut self, profiler: Option<Arc<crate::profiler::Profiler>>);
fn set_sanitizer(&mut self, sanitizer: Option<Arc<crate::security::Sanitizer>>);
fn set_class_cache_dir(&mut self, path: Option<PathBuf>);
fn set_classpath(&mut self, classpath: Vec<PathBuf>);
}
pub trait JvmInterpreter:
BytecodeExecutor +
MemoryManager +
ClassManager +
JitManagerProvider +
DebugProvider +
NativeMethodHandler +
RuntimeConfig
{
fn new() -> Self;
fn with_classpath(classpath: Vec<PathBuf>) -> Self;
fn with_jit(config: crate::jit::TieredCompilationConfig) -> Self;
fn run_main(&mut self, class_name: &str) -> Result<(), JvmError>;
fn get_loaded_class_count(&self) -> usize;
fn get_memory_usage(&self) -> usize;
fn get_gc_count(&self) -> usize;
}
pub struct DefaultInterpreterDelegate {
pub interpreter: crate::interpreter::Interpreter,
}
impl BytecodeExecutor for DefaultInterpreterDelegate {
fn execute_method(
&mut self,
class: &ClassFile,
method: &MethodInfo,
frame: &mut StackFrame,
) -> Result<(), JvmError> {
self.interpreter.execute_method(class, method, frame)
}
fn dispatch_instruction(
&mut self,
class: &ClassFile,
bytecode: &[u8],
frame: &mut StackFrame,
opcode: u8,
) -> Result<(), JvmError> {
Ok(())
}
fn resolve_method(
&mut self,
class_name: &str,
method_name: &str,
descriptor: &str,
) -> Result<(String, MethodInfo), JvmError> {
Err(JvmError::RuntimeError(RuntimeError::Unimplemented("Method resolution not implemented".to_string())))
}
}
impl MemoryManager for DefaultInterpreterDelegate {
fn new_instance(&mut self, class_name: &str) -> Result<Value, JvmError> {
self.interpreter.new_instance(class_name, &[])
}
fn allocate_array(&mut self, array_type: &str, length: i32) -> Result<Value, JvmError> {
match array_type {
"I" => Ok(Value::ArrayRef(self.interpreter.new_array_int(length)?)),
"B" => Ok(Value::ArrayRef(self.interpreter.new_array_byte(length)?)),
"C" => Ok(Value::ArrayRef(self.interpreter.new_array_char(length)?)),
"S" => Ok(Value::ArrayRef(self.interpreter.new_array_short(length)?)),
"J" => Ok(Value::ArrayRef(self.interpreter.new_array_long(length)?)),
"F" => Ok(Value::ArrayRef(self.interpreter.new_array_float(length)?)),
"D" => Ok(Value::ArrayRef(self.interpreter.new_array_double(length)?)),
"Z" => Ok(Value::ArrayRef(self.interpreter.new_array_bool(length)?)),
_ => Err(JvmError::RuntimeError(RuntimeError::InvalidArrayType(array_type.to_string()))),
}
}
fn get_field_value(&mut self, obj: &Value, field_name: &str) -> Result<Value, JvmError> {
self.interpreter.get_field_value(obj, field_name)
}
fn set_field_value(&mut self, obj: &Value, field_name: &str, value: Value) -> Result<(), JvmError> {
self.interpreter.set_field_value(obj, field_name, value)
}
fn get_memory_stats(&self) -> HashMap<String, usize> {
let mut stats = HashMap::new();
stats.insert("objects".to_string(), self.interpreter.memory.heap.object_count());
stats.insert("arrays".to_string(), self.interpreter.memory.heap.array_count());
stats.insert("memory_used".to_string(), self.interpreter.memory.heap.memory_used());
stats
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_trait_bounds() {
fn test_executor<T: BytecodeExecutor + ?Sized>(t: &mut T) {}
fn test_memory_manager<T: MemoryManager + ?Sized>(t: &mut T) {}
fn test_class_manager<T: ClassManager + ?Sized>(t: &mut T) {}
let mut delegate = DefaultInterpreterDelegate {
interpreter: crate::interpreter::Interpreter::new(),
};
test_executor(&mut delegate);
test_memory_manager(&mut delegate);
}
}