182 lines
4.9 KiB
Rust

#[cfg(libloading_docs)]
use super::os::unix as imp;
use std::collections::HashMap;
use std::ffi::c_void;
// the implementation used here doesn't matter particularly much...
#[cfg(all(not(libloading_docs), unix))]
use libloading::os::unix as imp;
#[cfg(all(not(libloading_docs), windows))]
use libloading::os::windows as imp;
use crate::class_file::{ClassFlags, MethodRef};
use crate::class_loader::ClassLoader;
use crate::error::VmError;
use crate::native::r#unsafe::UnsafeSupport;
use crate::objects::object::ReferenceKind;
use crate::objects::object_manager::ObjectManager;
use crate::thread::VmThread;
use crate::{MethodDescriptor, ThreadId};
use dashmap::DashMap;
use imp::Library;
use log::trace;
use parking_lot::{Mutex, RwLock};
use std::sync::Arc;
use std::sync::atomic::AtomicU64;
type NativeLibraries = Arc<RwLock<Vec<(String, Library)>>>;
// struct AbstractObject<'a> {}
pub struct Vm {
// Thread registry - maps ThreadId to VmThread
pub threads: DashMap<ThreadId, Arc<VmThread>>,
pub main_thread_id: ThreadId,
pub loader: Arc<Mutex<ClassLoader>>,
pub native_methods: DashMap<String, *const c_void>,
pub native_libraries: NativeLibraries,
pub gc: Arc<RwLock<ObjectManager>>,
pub safent: RwLock<UnsafeSupport>,
pub NEXT_ID: AtomicU64,
}
impl Vm {
// start vm, loading main from classfile
pub fn new() -> Arc<Self> {
let vm = Arc::new(Self {
threads: DashMap::new(),
main_thread_id: ThreadId(0),
loader: Arc::new(Mutex::from(ClassLoader::default())),
native_methods: DashMap::new(),
native_libraries: Arc::new(RwLock::new(Vec::new())),
gc: Default::default(),
safent: Default::default(),
NEXT_ID: AtomicU64::new(0),
});
// Create main thread
let thread = VmThread::new(vm.clone(), None);
let thread_id = thread.id;
// Store in VM
vm.threads.insert(thread_id, thread.clone());
// Set as current thread
VmThread::set_current(thread_id);
vm
}
pub fn load_native_library(&self, name: &str, lib: Library) {
self.native_libraries.write().push((name.to_string(), lib));
}
pub fn find_native_method(&self, name: &str) -> Option<*const c_void> {
if let Some(registered) = self.native_methods.get(name) {
trace!("native {} was already registered", name);
return Some(registered.clone());
}
for (lib_name, lib) in self.native_libraries.read().iter() {
let res = unsafe { lib.get::<unsafe extern "system" fn()>(name.as_bytes()) };
if res.is_ok() {
println!(
"Invoke native for native symbol: {} out of: {}",
&name, lib_name
);
let symbol = res.unwrap();
let ptr = *symbol as *const c_void;
self.native_methods.insert(name.to_string(), ptr);
return Some(ptr);
}
}
None
}
pub fn boot_strap(&self) -> Result<(), VmError> {
let thread = self.threads.get(&self.main_thread_id).unwrap();
let classes = vec![
"java/lang/String",
"java/lang/System",
"java/lang/Class",
"java/lang/ThreadGroup",
"java/lang/Thread",
"java/lang/Module",
//unsafe internal?
"jdk/internal/misc/UnsafeConstants",
"java/lang/reflect/Method",
"java/lang/ref/Finalizer",
];
let mut loaded = Vec::new();
for name in classes {
let class = thread.loader.lock().get_or_load(name, None)?;
loaded.push(class);
}
let prims = vec![
("byte", "B"),
("char", "C"),
("double", "D"),
("float", "F"),
("int", "I"),
("long", "J"),
("short", "S"),
("boolean", "Z"),
("void", "V"),
];
let thread = self.threads.get(&self.main_thread_id).unwrap();
for prim in prims {
let klass = self.loader.lock().primitive_class(prim.0);
let class_class = thread.get_class("java/lang/Class")?;
let name_obj = thread.intern_string(&prim.0);
let flags = ClassFlags::from(1041u16);
let class_obj = self.gc.write().new_class(
class_class.clone(),
Some(ReferenceKind::ObjectReference(name_obj)),
None,
flags,
true,
);
klass.mirror.set(class_obj.lock().id).unwrap();
let prim_array_klass = self.loader.lock().create_array_class(klass.clone());
let arr_name_obj = thread.intern_string(&prim_array_klass.this_class);
let arr_class_obj = self.gc.write().new_class(
class_class,
Some(ReferenceKind::ObjectReference(arr_name_obj)),
None,
flags,
false,
);
prim_array_klass
.mirror
.set(arr_class_obj.lock().id)
.unwrap();
}
//woops forgot to init
for class in loaded {
println!("bootstrap init {}", class.this_class);
thread.ensure_initialised(&class)?;
}
let phase1ref = MethodRef {
class: "java/lang/System".to_string(),
name: "initPhase1".to_string(),
desc: MethodDescriptor::void(),
};
self.threads
.get(&self.main_thread_id)
.unwrap()
.bootstrap_mirror();
thread.invoke(phase1ref, Vec::new())?;
panic!("HOLY FUCKING SHIT, DID WE PHASE 1!?");
Ok(())
}
pub fn run(&self, what: &str) -> Result<(), VmError> {
self.boot_strap()?;
// Get main thread from DashMap
let thread = self.threads.get(&self.main_thread_id).unwrap().clone();
thread.invoke_main(what)
}
}