use alloc::{boxed::Box, sync::Arc};
use event_listener::{Event, EventListener};
use parking_lot::{Mutex, RwLock};
use crate::{
ClassDefinition, ClassInstance, Jvm, Result,
runtime::{JavaLangClass, JavaLangClassLoader},
};
#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) enum InitState {
NotInitialized,
InProgress,
Initialized,
Erroneous,
}
pub(crate) enum InitializationAction {
Initialize,
Recursive,
Wait(EventListener),
Initialized,
Erroneous,
}
struct ClassInitializationState {
status: InitState,
owner: Option<u64>,
}
struct ClassInitialization {
state: Mutex<ClassInitializationState>,
completed: Event,
}
#[derive(Clone)]
pub struct Class {
pub definition: Box<dyn ClassDefinition>,
java_class: Arc<RwLock<Option<Box<dyn ClassInstance>>>>,
defining_loader: Option<Box<dyn ClassInstance>>,
initialization: Arc<ClassInitialization>,
}
impl Class {
pub fn new(
definition: Box<dyn ClassDefinition>,
java_class: Option<Box<dyn ClassInstance>>,
defining_loader: Option<Box<dyn ClassInstance>>,
) -> Self {
Self {
definition,
java_class: Arc::new(RwLock::new(java_class)),
defining_loader,
initialization: Arc::new(ClassInitialization {
state: Mutex::new(ClassInitializationState {
status: InitState::NotInitialized,
owner: None,
}),
completed: Event::new(),
}),
}
}
pub(crate) fn initialization_action(&self, thread_id: u64) -> InitializationAction {
let listener = self.initialization.completed.listen();
let mut state = self.initialization.state.lock();
match state.status {
InitState::NotInitialized => {
state.status = InitState::InProgress;
state.owner = Some(thread_id);
InitializationAction::Initialize
}
InitState::InProgress if state.owner == Some(thread_id) => InitializationAction::Recursive,
InitState::InProgress => InitializationAction::Wait(listener),
InitState::Initialized => InitializationAction::Initialized,
InitState::Erroneous => InitializationAction::Erroneous,
}
}
pub(crate) fn finish_initialization(&self, status: InitState) {
{
let mut state = self.initialization.state.lock();
state.status = status;
state.owner = None;
}
self.initialization.completed.notify(usize::MAX);
}
pub fn set_java_class(&self, java_class: Box<dyn ClassInstance>) {
*self.java_class.write() = Some(java_class);
}
pub fn java_class(&self) -> Box<dyn ClassInstance> {
self.java_class.read().clone().unwrap()
}
pub(crate) fn is_same_runtime_package(&self, other: &Self) -> bool {
let package = self.definition.name();
let other_package = other.definition.name();
if package.rsplit_once('/').map_or("", |(package, _)| package) != other_package.rsplit_once('/').map_or("", |(package, _)| package) {
return false;
}
match (&self.defining_loader, &other.defining_loader) {
(None, None) => true,
(Some(loader), Some(other_loader)) => loader.identity() == other_loader.identity(),
_ => false,
}
}
}
#[async_trait::async_trait]
pub trait BootstrapClassLoader: Sync + Send {
async fn load_class(&self, jvm: &Jvm, name: &str) -> Result<Option<Box<dyn ClassDefinition>>>;
}
#[async_trait::async_trait]
pub trait ClassLoaderWrapper: Sync + Send {
async fn load_class(&self, jvm: &Jvm, name: &str) -> Result<Option<Class>>;
}
pub struct BootstrapClassLoaderWrapper<'a> {
bootstrap_class_loader: &'a dyn BootstrapClassLoader,
}
impl<'a> BootstrapClassLoaderWrapper<'a> {
pub fn new(bootstrap_class_loader: &'a dyn BootstrapClassLoader) -> Self {
Self { bootstrap_class_loader }
}
}
#[async_trait::async_trait]
impl ClassLoaderWrapper for BootstrapClassLoaderWrapper<'_> {
async fn load_class(&self, jvm: &Jvm, name: &str) -> Result<Option<Class>> {
let definition = self.bootstrap_class_loader.load_class(jvm, name).await?;
if let Some(definition) = definition {
let java_class = JavaLangClass::from_rust_class(jvm, definition.clone(), None).await?;
let class = Class::new(definition, Some(java_class), None);
jvm.register_class_internal(class.clone(), Some(self)).await?;
Ok(Some(class))
} else {
Ok(None)
}
}
}
pub struct JavaClassLoaderWrapper {
class_loader: Box<dyn ClassInstance>,
}
impl JavaClassLoaderWrapper {
pub fn new(class_loader: Box<dyn ClassInstance>) -> Self {
Self { class_loader }
}
}
#[async_trait::async_trait]
impl ClassLoaderWrapper for JavaClassLoaderWrapper {
async fn load_class(&self, jvm: &Jvm, name: &str) -> Result<Option<Class>> {
let class = JavaLangClassLoader::load_class(jvm, &self.class_loader, name).await?;
if let Some(class) = class {
let definition = JavaLangClass::to_rust_class(jvm, &class).await?;
let defining_loader = JavaLangClass::class_loader(jvm, &class).await?;
Ok(Some(Class::new(definition, Some(class), defining_loader)))
} else {
Ok(None)
}
}
}