182 lines
4.9 KiB
Rust
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)
|
|
}
|
|
}
|