From 5b12e59acb13fb29d5bdb53b73efc8d5fc35f33f Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Sat, 14 Dec 2024 15:50:26 -0500 Subject: [PATCH] wip --- runtime/src/calls/jcall.rs | 2 +- runtime/src/frame.rs | 12 +- runtime/src/initialization.rs | 14 +- runtime/src/interpreter.rs | 14 +- runtime/src/method_invoker.rs | 8 +- runtime/src/native/lookup.rs | 15 +- runtime/src/native/mod.rs | 42 +++--- runtime/src/objects/class/mod.rs | 2 +- runtime/src/objects/class/spec.rs | 8 +- runtime/src/thread.rs | 229 +++++++++++++++++------------- 10 files changed, 189 insertions(+), 157 deletions(-) diff --git a/runtime/src/calls/jcall.rs b/runtime/src/calls/jcall.rs index 1be961a..1755ba5 100644 --- a/runtime/src/calls/jcall.rs +++ b/runtime/src/calls/jcall.rs @@ -4,7 +4,7 @@ /// /// # Parameters /// -/// * `thread` - `&mut JavaThread` +/// * `thread` - `&JavaThread` /// * `method` - `&'static Method` /// * `arg`(s) - `Operand` /// diff --git a/runtime/src/frame.rs b/runtime/src/frame.rs index 506077e..14097a0 100644 --- a/runtime/src/frame.rs +++ b/runtime/src/frame.rs @@ -22,7 +22,7 @@ pub struct Frame { // and a reference to the run-time constant pool (§2.5.5) constant_pool: ConstantPoolRef, method: &'static Method, - thread: UnsafeCell<*mut JavaThread>, + thread: UnsafeCell<*const JavaThread>, // Used to remember the last pc when we return to a frame after a method invocation cached_pc: AtomicIsize, @@ -42,7 +42,7 @@ impl Debug for Frame { impl Frame { /// Create a new `Frame` for a [`Method`] invocation pub fn new( - thread: &mut JavaThread, + thread: &JavaThread, locals: LocalStack, max_stack: u2, constant_pool: ConstantPoolRef, @@ -53,7 +53,7 @@ impl Frame { stack: OperandStack::new(max_stack as usize), constant_pool, method, - thread: UnsafeCell::new(&raw mut *thread), + thread: UnsafeCell::new(&raw const *thread), cached_pc: AtomicIsize::default(), } } @@ -67,12 +67,6 @@ impl Frame { unsafe { &**self.thread.get() } } - /// Get a mutable reference to the associated [`JavaThread`] - #[inline] - pub fn thread_mut(&self) -> &mut JavaThread { - unsafe { &mut **self.thread.get() } - } - /// Get a reference to the constant pool #[inline] pub fn constant_pool(&self) -> ConstantPoolRef { diff --git a/runtime/src/initialization.rs b/runtime/src/initialization.rs index f951171..a260cc6 100644 --- a/runtime/src/initialization.rs +++ b/runtime/src/initialization.rs @@ -20,11 +20,11 @@ pub fn create_java_vm(args: Option<&JavaVMInitArgs>) -> JavaVm { JavaThread::set_current_thread(thread); } - initialize_thread(JavaThread::current_mut()); + initialize_thread(JavaThread::current()); unsafe { main_java_vm() } } -fn initialize_thread(thread: &mut JavaThread) { +fn initialize_thread(thread: &JavaThread) { // Load some important classes first load_global_classes(); @@ -126,7 +126,7 @@ fn load_global_classes() { ) } -fn initialize_global_classes(thread: &mut JavaThread) { +fn initialize_global_classes(thread: &JavaThread) { crate::globals::classes::java_lang_Object().initialize(thread); crate::globals::classes::java_lang_Class().initialize(thread); crate::globals::classes::java_lang_String().initialize(thread); @@ -136,7 +136,7 @@ fn initialize_global_classes(thread: &mut JavaThread) { crate::globals::classes::java_lang_ref_Finalizer().initialize(thread); } -fn create_thread_object(thread: &mut JavaThread) { +fn create_thread_object(thread: &JavaThread) { let thread_group_class = crate::globals::classes::java_lang_ThreadGroup(); let system_thread_group_instance = Reference::class(ClassInstance::new(thread_group_class)); @@ -174,7 +174,7 @@ fn create_thread_object(thread: &mut JavaThread) { /// * Signal handlers /// * OS-specific system settings /// * Thread group of the main thread -fn init_phase_1(thread: &mut JavaThread) { +fn init_phase_1(thread: &JavaThread) { let system_class = ClassLoader::Bootstrap.load(sym!(java_lang_System)).unwrap(); let init_phase_1 = system_class .resolve_method_step_two(sym!(initPhase1_name), sym!(void_method_signature)) @@ -187,7 +187,7 @@ fn init_phase_1(thread: &mut JavaThread) { /// /// This is responsible for initializing the module system. Prior to this point, the only module /// available to us is `java.base`. -fn init_phase_2(thread: &mut JavaThread) { +fn init_phase_2(thread: &JavaThread) { let system_class = ClassLoader::Bootstrap.load(sym!(java_lang_System)).unwrap(); // TODO: Actually set these arguments accordingly @@ -218,7 +218,7 @@ fn init_phase_2(thread: &mut JavaThread) { /// * Initialization of and setting the security manager /// * Setting the system class loader /// * Setting the thread context class loader -fn init_phase_3(thread: &mut JavaThread) { +fn init_phase_3(thread: &JavaThread) { let system_class = ClassLoader::Bootstrap.load(sym!(java_lang_System)).unwrap(); let init_phase_3 = system_class diff --git a/runtime/src/interpreter.rs b/runtime/src/interpreter.rs index 188e225..324e5c0 100644 --- a/runtime/src/interpreter.rs +++ b/runtime/src/interpreter.rs @@ -239,7 +239,7 @@ macro_rules! comparisons { macro_rules! control_return { ($frame:ident, $instruction:ident) => {{ - let thread = $frame.thread_mut(); + let thread = $frame.thread(); thread.drop_to_previous_frame(None); }}; ($frame:ident, $instruction:ident, $return_ty:ident) => {{ @@ -255,7 +255,7 @@ macro_rules! control_return { ); } - let thread = $frame.thread_mut(); + let thread = $frame.thread(); thread.drop_to_previous_frame(Some(value)); }}; } @@ -672,7 +672,7 @@ impl Interpreter { }, OpCode::athrow => { let object_ref = frame.stack_mut().pop_reference(); - let thread = frame.thread_mut(); + let thread = frame.thread(); thread.throw_exception(object_ref); }, OpCode::instanceof => { Self::instanceof_checkcast(frame, opcode) }, @@ -948,7 +948,7 @@ impl Interpreter { let ret = class.resolve_field(constant_pool, field_ref_idx); if ret.is_some() && is_static { - class.initialize(frame.thread_mut()); + class.initialize(frame.thread()); } ret @@ -960,10 +960,10 @@ impl Interpreter { let method = frame.method(); let class = method.class; - let ret = class.resolve_method(frame.thread_mut(), method_ref_idx); + let ret = class.resolve_method(frame.thread(), method_ref_idx); if ret.is_some() && is_static { // On successful resolution of the method, the class or interface that declared the resolved method is initialized if that class or interface has not already been initialized - class.initialize(frame.thread_mut()); + class.initialize(frame.thread()); } ret @@ -983,7 +983,7 @@ impl Interpreter { } // On successful resolution of the class, it is initialized if it has not already been initialized - class.initialize(frame.thread_mut()); + class.initialize(frame.thread()); ClassInstance::new(class) } diff --git a/runtime/src/method_invoker.rs b/runtime/src/method_invoker.rs index 530d8f7..71666c4 100644 --- a/runtime/src/method_invoker.rs +++ b/runtime/src/method_invoker.rs @@ -23,7 +23,7 @@ impl MethodInvoker { /// /// This will not pop anything off of the stack of the current Frame pub fn invoke_with_args( - thread: &mut JavaThread, + thread: &JavaThread, method: &'static Method, args: Vec>, ) { @@ -106,12 +106,12 @@ impl MethodInvoker { local_stack[0] = this; } - Self::invoke0_(frame.thread_mut(), method, local_stack); + Self::invoke0_(frame.thread(), method, local_stack); } - fn invoke0_(thread: &mut JavaThread, method: &'static Method, local_stack: LocalStack) { + fn invoke0_(thread: &JavaThread, method: &'static Method, local_stack: LocalStack) { trace_method!(method); - JavaThread::invoke_method_with_local_stack(thread, method, local_stack); + thread.invoke_method_with_local_stack(method, local_stack); } fn construct_local_stack( diff --git a/runtime/src/native/lookup.rs b/runtime/src/native/lookup.rs index 67f0e8a..df6358b 100644 --- a/runtime/src/native/lookup.rs +++ b/runtime/src/native/lookup.rs @@ -196,7 +196,7 @@ impl<'a> NativeNameConverter<'a> { fn lookup_style( method: &Method, - thread: &mut JavaThread, + thread: &JavaThread, name_converter: &NativeNameConverter<'_>, num_args: usize, include_long: bool, @@ -233,8 +233,9 @@ fn lookup_style( findNative_method, Operand::Reference(Reference::null()), Operand::Reference(Reference::class(name_arg)) - ).unwrap() - .expect_long(); + ) + .unwrap() + .expect_long(); if address == 0 { todo!("Agent library search"); @@ -244,7 +245,7 @@ fn lookup_style( Some(entry) } -fn lookup_entry(method: &Method, thread: &mut JavaThread) -> Option<*const c_void> { +fn lookup_entry(method: &Method, thread: &JavaThread) -> Option<*const c_void> { let mut name_converter = NativeNameConverter::new(method); // Compute pure name @@ -314,11 +315,11 @@ fn lookup_entry(method: &Method, thread: &mut JavaThread) -> Option<*const c_voi } /// Check if there are any JVM TI prefixes which have been applied to the native method name. -fn lookup_entry_prefixed(_method: &Method, _thread: &mut JavaThread) -> Option<*const c_void> { +fn lookup_entry_prefixed(_method: &Method, _thread: &JavaThread) -> Option<*const c_void> { todo!() } -fn lookup_base(method: &Method, thread: &mut JavaThread) -> *const c_void { +fn lookup_base(method: &Method, thread: &JavaThread) -> *const c_void { if let Some(entry) = lookup_entry(method, thread) { return entry; } @@ -331,7 +332,7 @@ fn lookup_base(method: &Method, thread: &mut JavaThread) -> *const c_void { panic!("UnsatisfiedLinkError") } -pub fn lookup_native_method(method: &Method, thread: &mut JavaThread) { +pub fn lookup_native_method(method: &Method, thread: &JavaThread) { let native_method = method.native_method(); if !native_method.is_some() { return; diff --git a/runtime/src/native/mod.rs b/runtime/src/native/mod.rs index e23ad05..819970b 100644 --- a/runtime/src/native/mod.rs +++ b/runtime/src/native/mod.rs @@ -84,27 +84,6 @@ pub(self) fn insert_method((def, ptr): (NativeMethodDef, NativeMethodPtr)) { // Module marker, do not remove -pub(crate) mod jdk { - pub(crate) mod internal { - pub(crate) mod misc { - pub(crate) mod ScopedMemoryAccess; - pub(crate) mod CDS; - pub(crate) mod VM; - pub(crate) mod Unsafe; - pub(crate) mod Signal; - } - pub(crate) mod util { - pub(crate) mod SystemProps; - } - pub(crate) mod loader { - pub(crate) mod NativeLibraries; - } - pub(crate) mod reflect { - pub(crate) mod Reflection; - } - } -} - pub(crate) mod java { pub(crate) mod io { pub(crate) mod FileInputStream; @@ -132,3 +111,24 @@ pub(crate) mod java { } } +pub(crate) mod jdk { + pub(crate) mod internal { + pub(crate) mod misc { + pub(crate) mod ScopedMemoryAccess; + pub(crate) mod CDS; + pub(crate) mod VM; + pub(crate) mod Unsafe; + pub(crate) mod Signal; + } + pub(crate) mod util { + pub(crate) mod SystemProps; + } + pub(crate) mod loader { + pub(crate) mod NativeLibraries; + } + pub(crate) mod reflect { + pub(crate) mod Reflection; + } + } +} + diff --git a/runtime/src/objects/class/mod.rs b/runtime/src/objects/class/mod.rs index 17ac481..479f85b 100644 --- a/runtime/src/objects/class/mod.rs +++ b/runtime/src/objects/class/mod.rs @@ -641,7 +641,7 @@ impl Class { /// Attempt to initialize this class /// /// NOTE: If the class is being initialized by another thread, this will block until it is completed. - pub fn initialize(&self, thread: &mut JavaThread) { + pub fn initialize(&self, thread: &JavaThread) { if self.is_initialized.get() { return; } diff --git a/runtime/src/objects/class/spec.rs b/runtime/src/objects/class/spec.rs index b85ea08..f6d24f6 100644 --- a/runtime/src/objects/class/spec.rs +++ b/runtime/src/objects/class/spec.rs @@ -185,7 +185,7 @@ impl Class { #[tracing::instrument(skip_all)] pub fn resolve_method<'a>( &'a self, - thread: &mut JavaThread, + thread: &JavaThread, method_ref_idx: u2, ) -> Option<&'static Method> { let descriptor = self.unwrap_class_instance(); @@ -365,7 +365,7 @@ impl Class { reason = "We have no way of checking of the executed successfully yet" )] #[tracing::instrument(skip_all)] - pub fn initialization(&self, thread: &mut JavaThread) { + pub fn initialization(&self, thread: &JavaThread) { // 1. Synchronize on the initialization lock, LC, for C. This involves waiting until the current thread can acquire LC. let init = self.initialization_lock(); let mut guard = init.lock(); @@ -527,7 +527,7 @@ impl Class { #[tracing::instrument(skip_all)] pub fn construct( &self, - thread: &mut JavaThread, + thread: &JavaThread, descriptor: Symbol, args: Vec>, ) { @@ -556,7 +556,7 @@ impl Class { // https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-2.html#jvms-2.9.2 #[rustfmt::skip] #[tracing::instrument(skip_all)] - fn clinit(&self, thread: &mut JavaThread) { + fn clinit(&self, thread: &JavaThread) { // A class or interface has at most one class or interface initialization method and is initialized // by the Java Virtual Machine invoking that method (§5.5). diff --git a/runtime/src/thread.rs b/runtime/src/thread.rs index a4d759c..ca240c1 100644 --- a/runtime/src/thread.rs +++ b/runtime/src/thread.rs @@ -8,7 +8,7 @@ use crate::reference::{ClassInstanceRef, Reference}; use crate::stack::local_stack::LocalStack; use crate::string_interner::StringInterner; -use std::cell::SyncUnsafeCell; +use std::cell::{SyncUnsafeCell, UnsafeCell}; use std::ptr::NonNull; use std::sync::atomic::{AtomicIsize, Ordering}; use std::sync::Arc; @@ -21,7 +21,7 @@ use jni::env::JniEnv; use symbols::sym; #[thread_local] -static CURRENT_JAVA_THREAD: Option> = None; +static CURRENT_JAVA_THREAD: SyncUnsafeCell> = SyncUnsafeCell::new(None); pub struct JVMOptions { pub dry_run: bool, @@ -44,19 +44,19 @@ impl StackFrame { #[derive(Debug)] pub struct FrameStack { - inner: Vec, + inner: UnsafeCell>, } impl FrameStack { // TODO fn new() -> Self { FrameStack { - inner: Vec::with_capacity(1024), + inner: UnsafeCell::new(Vec::with_capacity(1024)), } } - fn current(&mut self) -> Option<&mut Frame> { - let current_frame = self.inner.last_mut(); + fn current(&self) -> Option<&mut Frame> { + let current_frame = self.__inner_mut().last_mut(); match current_frame { Some(StackFrame::Real(r)) => Some(r), _ => None, @@ -64,55 +64,63 @@ impl FrameStack { } pub fn depth(&self) -> usize { - self.inner.len() + self.__inner().len() } pub fn iter(&self) -> impl DoubleEndedIterator { - self.inner.iter().filter_map(|frame| match frame { + self.__inner().iter().filter_map(|frame| match frame { StackFrame::Real(frame) => Some(frame), StackFrame::Fake => None, }) } pub fn get(&self, position: usize) -> Option<&Frame> { - match self.inner.get(position) { + match self.__inner().get(position) { Some(StackFrame::Real(frame)) => Some(frame), None => None, _ => unreachable!(), } } - fn push(&mut self, frame: StackFrame) { - self.inner.push(frame); + fn push(&self, frame: StackFrame) { + self.__inner_mut().push(frame); } - fn pop(&mut self) -> Option { - self.inner.pop() + fn pop(&self) -> Option { + self.__inner_mut().pop() } - fn pop_real(&mut self) -> Option { - match self.inner.pop() { + fn pop_real(&self) -> Option { + match self.__inner_mut().pop() { Some(StackFrame::Real(r)) => Some(r), _ => None, } } - fn pop_dummy(&mut self) { - match self.inner.pop() { + fn pop_dummy(&self) { + match self.__inner_mut().pop() { Some(StackFrame::Fake) => return, _ => panic!("Expected a dummy frame!"), } } - fn clear(&mut self) { - self.inner.clear(); + fn clear(&self) { + self.__inner_mut().clear(); + } + + fn __inner(&self) -> &mut Vec { + unsafe { &mut *self.inner.get() } + } + + fn __inner_mut(&self) -> &mut Vec { + unsafe { &mut *self.inner.get() } } } #[repr(C)] pub struct JavaThread { env: JniEnv, - obj: Option, + obj: UnsafeCell>, // https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-2.html#jvms-2.5.1 // Each Java Virtual Machine thread has its own pc (program counter) register [...] @@ -120,8 +128,7 @@ pub struct JavaThread { pub pc: AtomicIsize, frame_stack: FrameStack, - // TODO: HACK!!!! - remaining_operand: Option>, + remaining_operand: UnsafeCell>>, } impl PartialEq for JavaThread { @@ -147,11 +154,13 @@ impl JavaThread { /// Get a pointer to the current `JavaThread` for this thread pub fn current_ptr() -> *const JavaThread { - unsafe { - match &CURRENT_JAVA_THREAD { - None => std::ptr::null(), - Some(thread) => thread.get() as _, - } + let current = CURRENT_JAVA_THREAD.get(); + + // SAFETY: The thread is an `Option`, so it's always initialized with *something* + let opt = unsafe { &*current }; + match opt { + None => std::ptr::null(), + Some(thread) => thread, } } @@ -169,23 +178,11 @@ impl JavaThread { /// /// This will return `None` if there is no `JavaThread` available. pub fn current_opt() -> Option<&'static JavaThread> { - unsafe { - CURRENT_JAVA_THREAD - .as_ref() - .map(|thread| core::mem::transmute(thread.get() as *const _)) - } - } + let current = CURRENT_JAVA_THREAD.get(); - pub fn current_mut() -> &'static mut JavaThread { - Self::current_opt_mut().expect("current JavaThread should be available") - } - - pub fn current_opt_mut() -> Option<&'static mut JavaThread> { - unsafe { - CURRENT_JAVA_THREAD - .as_ref() - .map(|thread| unsafe { &mut *thread.get() }) - } + // SAFETY: The thread is an `Option`, so it's always initialized with *something* + let opt = unsafe { &*current }; + opt.as_ref() } /// Sets the current Java [`JavaThread`] @@ -194,11 +191,18 @@ impl JavaThread { /// /// This will panic if there is already a current thread set pub unsafe fn set_current_thread(thread: JavaThread) { + let current = CURRENT_JAVA_THREAD.get(); + + // SAFETY: The thread is an `Option`, so it's always initialized with *something* + let opt = unsafe { &*current }; assert!( - CURRENT_JAVA_THREAD.is_none(), + opt.is_none(), "attempting to overwrite an existing JavaThread" ); - CURRENT_JAVA_THREAD = Some(SyncUnsafeCell::new(thread)); + + unsafe { + *current = Some(thread); + } } } @@ -272,8 +276,8 @@ impl JavaThread { } } - fn set_field_holder_field(&mut self, offset: usize, value: Operand) { - let obj = self.obj.as_ref().map(Reference::clone).unwrap(); + fn set_field_holder_field(&self, offset: usize, value: Operand) { + let obj = self.obj().unwrap(); let class_instance = obj.extract_class(); let field_holder_offset = crate::globals::field_offsets::thread_holder_field_offset(); @@ -287,54 +291,30 @@ impl JavaThread { .put_field_value0(offset, value); } - fn set_priority(&mut self, _priority: s4) { - assert!(self.obj.is_some()); + fn set_priority(&self, _priority: s4) { + assert!(self.obj().is_some()); todo!() } - fn set_daemon(&mut self, _daemon: bool) { - assert!(self.obj.is_some()); + fn set_daemon(&self, _daemon: bool) { + assert!(self.obj().is_some()); todo!() } - fn set_thread_status(&mut self, thread_status: ThreadStatus) { - assert!(self.obj.is_some()); + fn set_thread_status(&self, thread_status: ThreadStatus) { + assert!(self.obj().is_some()); let offset = crate::globals::field_offsets::field_holder_thread_status_field_offset(); self.set_field_holder_field(offset, Operand::Int(thread_status as s4)); } } +// Actions for the related `java.lang.Thread` instance impl JavaThread { - pub fn new() -> Self { - Self { - env: unsafe { JniEnv::from_raw(new_env()) }, - obj: None, - - pc: AtomicIsize::new(0), - frame_stack: FrameStack::new(), - remaining_operand: None, - } - } - - /// Get a pointer to the associated [`JniEnv`] - pub fn env(&self) -> NonNull { - unsafe { - NonNull::new_unchecked( - std::ptr::from_ref(self).add(core::mem::offset_of!(JavaThread, env)) as _, - ) - } - } - - /// Get the frame stack for this thread - pub fn frame_stack(&self) -> &FrameStack { - &self.frame_stack - } - /// Allocates a new `java.lang.Thread` for this `JavaThread` /// /// This is called from the JNI `AttachCurrentThread`/`AttachCurrentThreadAsDaemon`. - pub fn attach_thread_obj(&mut self, name: Option<&str>, thread_group: Reference, daemon: bool) { - assert!(self.obj.is_none()); + pub fn attach_thread_obj(&self, name: Option<&str>, thread_group: Reference, daemon: bool) { + assert!(self.obj().is_none()); let thread_class = crate::globals::classes::java_lang_Thread(); let thread_instance = ClassInstance::new(thread_class); @@ -378,10 +358,10 @@ impl JavaThread { unimplemented!("jni::AttachCurrentThreadAsDaemon"); } - self.obj = Some(Reference::class(thread_instance)); + self.set_obj(Reference::class(thread_instance)); } - pub fn init_obj(&mut self, thread_group: Reference) { + pub fn init_obj(&self, thread_group: Reference) { let thread_class = crate::globals::classes::java_lang_Thread(); let thread_instance = ClassInstance::new(thread_class); @@ -410,12 +390,68 @@ impl JavaThread { self.set_thread_status(ThreadStatus::Runnable); } - pub fn set_obj(&mut self, obj: Reference) { - self.obj = Some(obj); + pub fn set_obj(&self, obj: Reference) { + let obj_ptr = self.obj.get(); + + // SAFETY: The object is an `Option`, so it's always initialized with *something* + let obj_opt = unsafe { &*obj_ptr }; + assert!(obj_opt.is_none()); + + unsafe { + *obj_ptr = Some(obj); + } } pub fn obj(&self) -> Option { - self.obj.as_ref().map(Reference::clone) + let obj_ptr = self.obj.get(); + + // SAFETY: The object is an `Option`, so it's always initialized with *something* + let obj_opt = unsafe { &*obj_ptr }; + obj_opt.as_ref().map(Reference::clone) + } +} + +impl JavaThread { + pub fn new() -> Self { + Self { + env: unsafe { JniEnv::from_raw(new_env()) }, + obj: UnsafeCell::new(None), + + pc: AtomicIsize::new(0), + frame_stack: FrameStack::new(), + remaining_operand: UnsafeCell::new(None), + } + } + + /// Get a pointer to the associated [`JniEnv`] + pub fn env(&self) -> NonNull { + unsafe { + NonNull::new_unchecked( + std::ptr::from_ref(self).add(core::mem::offset_of!(JavaThread, env)) as _, + ) + } + } + + /// Get the frame stack for this thread + pub fn frame_stack(&self) -> &FrameStack { + &self.frame_stack + } + + fn set_remaining_operand(&self, operand: Option>) { + let remaining_operand_ptr = self.remaining_operand.get(); + + let remaining_operand_opt = unsafe { &*remaining_operand_ptr }; + assert!(remaining_operand_opt.is_none()); + + unsafe { + *remaining_operand_ptr = operand; + } + } + + fn take_remaining_operand(&self) -> Option> { + let remaining_operand_ptr = self.remaining_operand.get(); + let remaining_operand_opt = unsafe { &mut *remaining_operand_ptr }; + remaining_operand_opt.take() } /// Manually invoke a method and get its return value @@ -423,7 +459,7 @@ impl JavaThread { /// This will run the method on the current thread, separate from normal execution. This is used /// by [`java_call!`](crate::java_call) to allow us to manually invoke methods in the runtime. pub fn invoke_method_scoped( - &mut self, + &self, method: &'static Method, locals: LocalStack, ) -> Option> { @@ -437,14 +473,14 @@ impl JavaThread { self.invoke_method_with_local_stack(method, locals); self.run(); - let ret = self.remaining_operand.take(); + let ret = self.take_remaining_operand(); // Will pop the dummy frame for us self.drop_to_previous_frame(None); ret } - pub fn invoke_method_with_local_stack(&mut self, method: &'static Method, locals: LocalStack) { + pub fn invoke_method_with_local_stack(&self, method: &'static Method, locals: LocalStack) { if method.is_native() { self.invoke_native(method, locals); tracing::debug!(target: "JavaThread", "Native method finished"); @@ -462,7 +498,7 @@ impl JavaThread { } // Native methods do not require a stack frame. We just call and leave the stack behind until we return. - fn invoke_native(&mut self, method: &Method, locals: LocalStack) { + fn invoke_native(&self, method: &Method, locals: LocalStack) { // Try to lookup and set the method prior to calling crate::native::lookup::lookup_native_method(method, self); @@ -476,7 +512,7 @@ impl JavaThread { return; } - fn stash_and_reset_pc(&mut self) { + fn stash_and_reset_pc(&self) { if let Some(current_frame) = self.frame_stack.current() { current_frame.stash_pc() } @@ -485,7 +521,7 @@ impl JavaThread { } /// Return from the current frame and drop to the previous one - pub fn drop_to_previous_frame(&mut self, mut return_value: Option>) { + pub fn drop_to_previous_frame(&self, return_value: Option>) { let _ = self.frame_stack.pop(); let Some(current_frame) = self.frame_stack.current() else { @@ -495,7 +531,8 @@ impl JavaThread { // 2. We've reached the end of the program // // Either way, the remaining operand ends up in the hands of the caller. - self.remaining_operand = return_value.take(); + self.set_remaining_operand(return_value); + return; }; @@ -511,7 +548,7 @@ impl JavaThread { } } - pub fn run(&mut self) { + pub fn run(&self) { while let Some(current_frame) = self.frame_stack.current() { Interpreter::instruction(current_frame); } @@ -525,7 +562,7 @@ impl JavaThread { /// /// This will panic if `object_ref` is non-null, but not a subclass of `java/lang/Throwable`. /// This should never occur post-verification. - pub fn throw_exception(&mut self, object_ref: Reference) { + pub fn throw_exception(&self, object_ref: Reference) { // https://docs.oracle.com/javase/specs/jvms/se20/html/jvms-6.html#jvms-6.5.athrow // The objectref must be of type reference and must refer to an object that is an instance of class Throwable or of a subclass of Throwable. if object_ref.is_null() { @@ -553,7 +590,7 @@ impl JavaThread { { // The pc register is reset to that location,the operand stack of the current frame is cleared, objectref // is pushed back onto the operand stack, and execution continues. - self.pc = AtomicIsize::new(handler_pc); + self.pc.store(handler_pc, Ordering::Relaxed); let stack = current_frame.stack_mut(); stack.clear(); @@ -586,7 +623,7 @@ impl JavaThread { } /// Throw a `NullPointerException` on this thread - pub fn throw_npe(&mut self) { + pub fn throw_npe(&self) { todo!() } }