use alloc::{
boxed::Box,
string::{String, ToString},
sync::Arc,
vec::Vec,
};
use event_listener::Event;
use crate::{ClassInstance, JavaValue, class_loader::Class, monitor::MonitorWaitTimeout};
#[derive(Clone)]
pub(crate) enum ThreadInterruptWaiter {
Monitor(MonitorWaitTimeout),
Event(Arc<Event>),
}
impl ThreadInterruptWaiter {
pub(crate) fn notify(self) {
match self {
Self::Monitor(waiter) => waiter.notify(),
Self::Event(event) => {
event.notify(1);
}
}
}
}
pub enum StackFrame {
Java(JavaStackFrame),
Native(NativeStackFrame),
}
impl StackFrame {
pub fn local_variables(&self) -> &[Box<dyn ClassInstance>] {
match self {
StackFrame::Java(java_frame) => &java_frame.local_variables,
StackFrame::Native(native_frame) => &native_frame.local_variables,
}
}
pub fn local_variables_mut(&mut self) -> &mut Vec<Box<dyn ClassInstance>> {
match self {
StackFrame::Java(java_frame) => &mut java_frame.local_variables,
StackFrame::Native(native_frame) => &mut native_frame.local_variables,
}
}
}
pub struct JvmThread {
stack: Vec<StackFrame>,
java_thread: Option<Box<dyn ClassInstance>>,
pub(crate) interrupted: bool,
pub(crate) interrupt_waiter: Option<ThreadInterruptWaiter>,
}
impl JvmThread {
pub fn new() -> Self {
Self {
stack: Vec::new(),
java_thread: None,
interrupted: false,
interrupt_waiter: None,
}
}
#[allow(clippy::borrowed_box)] pub fn java_thread(&self) -> Option<&Box<dyn ClassInstance>> {
self.java_thread.as_ref()
}
pub fn set_java_thread(&mut self, java_thread: Box<dyn ClassInstance>) {
self.java_thread = Some(java_thread);
}
pub fn push_java_frame(&mut self, class: &Class, class_instance: Option<Box<dyn ClassInstance>>, method: &str, args: &[JavaValue]) {
self.stack.push(StackFrame::Java(JavaStackFrame {
class: class.clone(),
class_instance,
method: method.to_string(),
local_variables: args
.iter()
.filter_map(|arg| match arg {
JavaValue::Object(Some(instance)) => Some(instance.clone()),
_ => None,
})
.collect(),
}));
}
pub fn push_native_frame(&mut self) {
self.stack.push(StackFrame::Native(NativeStackFrame { local_variables: Vec::new() }));
}
pub fn pop_frame(&mut self) -> Option<StackFrame> {
self.stack.pop()
}
pub fn top_frame_mut(&mut self) -> &mut StackFrame {
self.stack.last_mut().unwrap()
}
pub fn top_java_frame(&self) -> Option<&JavaStackFrame> {
self.stack.iter().rev().find_map(|frame| match frame {
StackFrame::Java(java_frame) => Some(java_frame),
_ => None,
})
}
pub fn iter_java_frame(&self) -> impl DoubleEndedIterator<Item = &JavaStackFrame> {
self.stack.iter().filter_map(|frame| match frame {
StackFrame::Java(java_frame) => Some(java_frame),
_ => None,
})
}
pub fn iter_frame(&self) -> impl DoubleEndedIterator<Item = &StackFrame> {
self.stack.iter()
}
}
pub struct JavaStackFrame {
pub class: Class,
pub class_instance: Option<Box<dyn ClassInstance>>,
pub method: String,
pub local_variables: Vec<Box<dyn ClassInstance>>,
}
pub struct NativeStackFrame {
pub local_variables: Vec<Box<dyn ClassInstance>>,
}