diff --git a/instructions/src/operand.rs b/instructions/src/operand.rs index 1275a8f..dbba0a2 100644 --- a/instructions/src/operand.rs +++ b/instructions/src/operand.rs @@ -253,15 +253,13 @@ impl Operand { if self.is_int() { let lhs = self.expect_int(); - assert!((0..32).contains(&rhs)); - *self = Operand::Int(lhs >> rhs); + *self = Operand::Int(lhs >> (rhs & 0x1F)); return; } if self.is_long() { let lhs = self.expect_long(); - assert!((0..64).contains(&rhs)); - *self = Operand::Long(lhs >> s8::from(rhs)); + *self = Operand::Long(lhs >> s8::from(rhs & 0x3F)); return; } @@ -311,7 +309,6 @@ impl Operand { if self.is_int() { let lhs = self.expect_int(); let rhs = rhs.expect_int(); - assert!((0..32).contains(&rhs)); *self = Operand::Int(((lhs as u4) >> (rhs & 0x1F) as u4) as s4); return; } @@ -319,7 +316,6 @@ impl Operand { if self.is_long() { let lhs = self.expect_long(); let rhs = rhs.expect_int(); - assert!((0..64).contains(&rhs)); *self = Operand::Long(((lhs as u8) >> (rhs & 0x3F) as u8) as s8); return; } diff --git a/runtime/src/classpath/classloader.rs b/runtime/src/classpath/classloader.rs index c2188af..8178a99 100644 --- a/runtime/src/classpath/classloader.rs +++ b/runtime/src/classpath/classloader.rs @@ -133,11 +133,11 @@ impl ClassLoader { // "Preparation may occur at any time following creation but must be completed prior to initialization." class.prepare(); - // Set the mirror - if let Some(mirror_class) = Self::lookup_class(sym!(java_lang_Class)) { + // Set the mirror if `java.lang.Class` is loaded + if Self::lookup_class(sym!(java_lang_Class)).is_some() { // SAFETY: The only condition of `set_mirror` is that the class isn't in use yet. unsafe { - class.set_mirror(mirror_class); + class.set_mirror(); } } @@ -231,11 +231,11 @@ impl ClassLoader { // If the component type is a reference type, the accessibility of the array class is determined by the accessibility of its component type (ยง5.4.4). // Otherwise, the array class is accessible to all classes and interfaces. - // Set the mirror - if let Some(mirror_class) = Self::lookup_class(sym!(java_lang_Class)) { + // Set the mirror if `java.lang.Class` is loaded + if Self::lookup_class(sym!(java_lang_Class)).is_some() { // SAFETY: The only condition of `set_mirror` is that the class isn't in use yet. unsafe { - array_class.set_mirror(mirror_class); + array_class.set_mirror(); } } @@ -245,11 +245,10 @@ impl ClassLoader { /// Recreate mirrors for all loaded classes pub fn fixup_mirrors() { - let java_lang_class = crate::globals::classes::java_lang_Class(); for (_, class) in BOOTSTRAP_LOADED_CLASSES.lock().unwrap().iter() { // SAFETY: The only condition of `set_mirror` is that the class isn't in use yet. unsafe { - class.set_mirror(java_lang_class); + class.set_mirror(); } } } diff --git a/runtime/src/initialization.rs b/runtime/src/initialization.rs index ba83ef7..69e2890 100644 --- a/runtime/src/initialization.rs +++ b/runtime/src/initialization.rs @@ -200,6 +200,8 @@ fn initialize_global_classes(thread: &JavaThread) { crate::globals::classes::java_lang_Class().initialize(thread); crate::globals::classes::java_lang_String().initialize(thread); + crate::globals::classes::java_lang_Character().initialize(thread); + crate::globals::classes::java_lang_Thread().initialize(thread); crate::globals::classes::java_lang_ThreadGroup().initialize(thread); crate::globals::classes::java_lang_ref_Finalizer().initialize(thread); diff --git a/runtime/src/interpreter.rs b/runtime/src/interpreter.rs index baa5bde..682961c 100644 --- a/runtime/src/interpreter.rs +++ b/runtime/src/interpreter.rs @@ -911,12 +911,11 @@ impl Interpreter { fn fetch_field(frame: &mut Frame, is_static: bool) -> &'static Field { let field_ref_idx = frame.read_byte2(); - let class = frame.method().class(); let constant_pool = frame.constant_pool(); let ret = constant_pool.get::(field_ref_idx); if is_static { - class.initialize(frame.thread()); + ret.class.initialize(frame.thread()); } ret @@ -925,13 +924,12 @@ impl Interpreter { fn fetch_method(frame: &mut Frame, is_static: bool) -> &'static Method { let method_ref_idx = frame.read_byte2(); - let class = frame.method().class(); let constant_pool = frame.constant_pool(); let ret = constant_pool.get::(method_ref_idx); if 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()); + ret.class().initialize(frame.thread()); } ret diff --git a/runtime/src/method_invoker.rs b/runtime/src/method_invoker.rs index e379542..09e45f5 100644 --- a/runtime/src/method_invoker.rs +++ b/runtime/src/method_invoker.rs @@ -87,7 +87,7 @@ impl MethodInvoker { } if reresolve_method { - let class = this.extract_target_class(); + let class = this.extract_instance_class(); method = class.map_interface_method(method); max_locals = method.code.max_locals; } diff --git a/runtime/src/native/java/lang/Class.rs b/runtime/src/native/java/lang/Class.rs index 9f0dee8..af701ac 100644 --- a/runtime/src/native/java/lang/Class.rs +++ b/runtime/src/native/java/lang/Class.rs @@ -85,10 +85,41 @@ pub fn initClassName( pub fn getSuperclass( _env: NonNull, - _this: Reference, // java.lang.Class + this: Reference, // java.lang.Class ) -> Reference /* Class */ { - unimplemented!("Class#getSuperclass"); + // Comments from https://github.com/openjdk/jdk/blob/6c59185475eeca83153f085eba27cc0b3acf9bb4/src/java.base/share/classes/java/lang/Class.java#L1034-L1044 + + let this = this.extract_mirror(); + + let instance = this.get(); + let target_class = instance.target_class(); + + // If this `Class` represents either: + // * the `Object` class + if target_class == crate::globals::classes::java_lang_Object() + // * an interface + || target_class.is_interface() + // * a primitive type, or void + || instance.is_primitive() + { + // then null is returned + return Reference::null(); + } + + // If this `Class` object represents an array class + if instance.is_array() { + // then the `Class` object representing the `Object` class is returned + return Reference::mirror(MirrorInstance::new( + crate::globals::classes::java_lang_Object(), + )); + } + + if let Some(super_class) = target_class.super_class { + return Reference::mirror(MirrorInstance::new(super_class)); + } + + Reference::null() } pub fn getInterfaces0( _env: NonNull, @@ -146,8 +177,7 @@ pub fn getPrimitiveClass(_env: NonNull, name: Reference /* String */) -> for (name, ty) in crate::globals::TYPES { if &name_string == name { - let java_lang_class = crate::globals::classes::java_lang_Class(); - return Reference::mirror(MirrorInstance::new_primitive(java_lang_class, ty.clone())); + return Reference::mirror(MirrorInstance::new_primitive(ty.clone())); } } diff --git a/runtime/src/native/jdk/internal/misc/Unsafe.rs b/runtime/src/native/jdk/internal/misc/Unsafe.rs index 346134e..9f3e3fc 100644 --- a/runtime/src/native/jdk/internal/misc/Unsafe.rs +++ b/runtime/src/native/jdk/internal/misc/Unsafe.rs @@ -503,12 +503,32 @@ pub fn getReference( pub fn putReference( _env: NonNull, - _this: Reference, // jdk.internal.misc.Unsafe - _object: Reference, // Object - _offset: jlong, - _value: Reference, // Object -) -> Reference /* Object */ { - unimplemented!("jdk.internal.misc.Unsafe#putReference") + _this: Reference, // jdk.internal.misc.Unsafe + object: Reference, // Object + offset: jlong, + value: Reference, // Object +) { + if object.is_array() { + let instance = object.extract_array(); + unsafe { + let array_mut = instance.get_mut(); + let mut current_field_value = array_mut + .get_content_mut() + .get_reference_raw(offset as usize); + *current_field_value.as_mut() = Reference::clone(&value); + } + + return; + } + + let instance = object.extract_class(); + unsafe { + let field_value = instance + .get_mut() + .get_field_value_raw(offset as usize) + .as_ptr(); + *field_value = Operand::Reference(Reference::clone(&value)); + } } pub fn getReferenceVolatile( @@ -523,12 +543,13 @@ pub fn getReferenceVolatile( pub fn putReferenceVolatile( _env: NonNull, - _this: Reference, // jdk.internal.misc.Unsafe - _object: Reference, // java.lang.Object - _offset: jlong, - _value: Reference, // java.lang.Object -) -> Reference /* java.lang.Object */ { - unimplemented!("jdk.internal.misc.Unsafe#putReferenceVolatile") + _this: Reference, // jdk.internal.misc.Unsafe + object: Reference, // java.lang.Object + offset: jlong, + value: Reference, // java.lang.Object +) { + tracing::warn!("(!!!) Unsafe#putReferenceVolatile not actually volatile"); + putReference(_env, _this, object, offset, value) } /// Creates the many `{get, put}Ty` and `{get, put}TyVolatile` methods diff --git a/runtime/src/objects/class/mod.rs b/runtime/src/objects/class/mod.rs index 95c3d1d..0cbe84e 100644 --- a/runtime/src/objects/class/mod.rs +++ b/runtime/src/objects/class/mod.rs @@ -670,10 +670,10 @@ impl Class { /// /// This is only safe to call *before* the class is in use. It should never be used outside of /// class loading. - pub unsafe fn set_mirror(&'static self, mirror_class: &'static Class) { + pub unsafe fn set_mirror(&'static self) { let mirror = match self.class_ty() { - ClassType::Instance(_) => MirrorInstance::new(mirror_class, self), - ClassType::Array(_) => MirrorInstance::new_array(mirror_class, self), + ClassType::Instance(_) => MirrorInstance::new(self), + ClassType::Array(_) => MirrorInstance::new_array(self), }; unsafe { diff --git a/runtime/src/objects/mirror.rs b/runtime/src/objects/mirror.rs index dfd5874..dd99a27 100644 --- a/runtime/src/objects/mirror.rs +++ b/runtime/src/objects/mirror.rs @@ -46,8 +46,8 @@ impl Debug for MirrorInstance { } impl MirrorInstance { - // TODO: Remove the `mirror_class` parameter? It's always `java.lang.Class` - pub fn new(mirror_class: &'static Class, target: &'static Class) -> MirrorInstanceRef { + pub fn new(target: &'static Class) -> MirrorInstanceRef { + let mirror_class = crate::globals::classes::java_lang_Class(); let fields = Self::initialize_fields(mirror_class); MirrorInstancePtr::new(Self { class: mirror_class, @@ -56,7 +56,8 @@ impl MirrorInstance { }) } - pub fn new_array(mirror_class: &'static Class, target: &'static Class) -> MirrorInstanceRef { + pub fn new_array(target: &'static Class) -> MirrorInstanceRef { + let mirror_class = crate::globals::classes::java_lang_Class(); let fields = Self::initialize_fields(mirror_class); MirrorInstancePtr::new(Self { class: mirror_class, @@ -65,12 +66,13 @@ impl MirrorInstance { }) } - pub fn new_primitive(mirror_class: &'static Class, target: FieldType) -> MirrorInstanceRef { + pub fn new_primitive(target: FieldType) -> MirrorInstanceRef { assert!( !matches!(target, FieldType::Array(_) | FieldType::Object(_)), "`Array` and `Object` field types are incompatible with the primitive mirror" ); + let mirror_class = crate::globals::classes::java_lang_Class(); let fields = Self::initialize_fields(mirror_class); MirrorInstancePtr::new(Self { class: mirror_class, diff --git a/runtime/src/objects/reference.rs b/runtime/src/objects/reference.rs index d4e4b94..52f98f1 100644 --- a/runtime/src/objects/reference.rs +++ b/runtime/src/objects/reference.rs @@ -109,7 +109,7 @@ impl Reference { impl Reference { pub fn is_instance_of(&self, other: &'static Class) -> bool { - self.extract_target_class().can_cast_to(other) + self.extract_instance_class().can_cast_to(other) } pub fn class_name(&self) -> Symbol { @@ -137,6 +137,21 @@ impl Reference { } } + /// Get the class that this reference targets + /// + /// This has a subtle difference from [`Reference::extract_instance_class`] in the case of `mirror` instances. + /// This will return the class that `mirror` instance is targeting, while `extract_instance_class` will return + /// `java.lang.Class`. + /// + /// This is a very important distinction to make when dealing with things such as method resolution. + /// + /// See also: + /// * [`Reference::extract_instance_class`] + /// * [`MirrorInstance::target_class`] + /// + /// For references other than `mirror`, this will return the same as `extract_instance_class`. + /// + /// [`MirrorInstance::target_class`]: crate::objects::mirror::MirrorInstance::target_class pub fn extract_target_class(&self) -> &'static Class { match &self.instance { ReferenceInstance::Class(class) => class.get().class(), @@ -146,6 +161,24 @@ impl Reference { } } + /// Get the class of the instance + /// + /// This has a subtle difference from [`Reference::extract_target_class`] in the case of `mirror` instances. + /// This will return `java.lang.Class` for `mirror` instances, while `extract_target_class` will return the class + /// the mirror is targeting. + /// + /// This is a very important distinction to make when dealing with things such as method resolution. + /// + /// For references other than `mirror`, this will return the same as `extract_target_class`. + pub fn extract_instance_class(&self) -> &'static Class { + match &self.instance { + ReferenceInstance::Class(class) => class.get().class(), + ReferenceInstance::Mirror(mirror) => &mirror.get().class(), + ReferenceInstance::Array(arr) => &arr.get().class, + ReferenceInstance::Null => panic!("NullPointerException"), + } + } + pub fn extract_mirror(&self) -> MirrorInstanceRef { match &self.instance { ReferenceInstance::Mirror(mirror) => Arc::clone(mirror), diff --git a/runtime/src/thread/frame/stack.rs b/runtime/src/thread/frame/stack.rs index 8f20fe2..4ddd3fb 100644 --- a/runtime/src/thread/frame/stack.rs +++ b/runtime/src/thread/frame/stack.rs @@ -3,14 +3,30 @@ use super::Frame; use crate::objects::method::Method; use std::cell::UnsafeCell; +use std::fmt::Debug; -#[derive(Debug)] pub enum StackFrame { Real(Frame), Native(NativeFrame), Fake, } +impl Debug for StackFrame { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + StackFrame::Real(frame) => write!( + f, + "(Real) {:?} (code len: {}, cached pc: {})", + frame.method(), + frame.method().code.code.len(), + frame.cached_pc.load(std::sync::atomic::Ordering::Acquire) + ), + StackFrame::Native(frame) => write!(f, "(Native) {:?}", frame.method()), + StackFrame::Fake => write!(f, "Fake"), + } + } +} + impl StackFrame { fn is_fake(&self) -> bool { matches!(self, StackFrame::Fake) @@ -43,11 +59,16 @@ impl<'a> From<&'a NativeFrame> for VisibleStackFrame<'a> { } } -#[derive(Debug)] pub struct FrameStack { inner: UnsafeCell>, } +impl Debug for FrameStack { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_list().entries(self.__inner().iter()).finish() + } +} + impl FrameStack { // TODO pub fn new() -> Self { diff --git a/runtime/src/thread/mod.rs b/runtime/src/thread/mod.rs index e680983..759b316 100644 --- a/runtime/src/thread/mod.rs +++ b/runtime/src/thread/mod.rs @@ -442,6 +442,8 @@ impl JavaThread { let fn_ptr = super::native::lookup_method(method); + self.stash_and_reset_pc(); + // See comments on `NativeFrame` self.frame_stack .push(StackFrame::Native(NativeFrame { method })); @@ -457,6 +459,8 @@ impl JavaThread { self.frame_stack.current().unwrap().stack_mut().push_op(ret); } + self.restore_pc(); + return; } @@ -468,6 +472,13 @@ impl JavaThread { self.pc.store(0, Ordering::Relaxed); } + fn restore_pc(&self) { + if let Some(current_frame) = self.frame_stack.current() { + let pc = current_frame.stashed_pc(); + self.pc.store(pc, Ordering::Relaxed); + } + } + /// Return from the current frame and drop to the previous one pub fn drop_to_previous_frame(&self, return_value: Option>) { let _ = self.frame_stack.pop(); @@ -487,8 +498,7 @@ impl JavaThread { tracing::debug!(target: "JavaThread", "Dropping back to frame for method `{:?}`", current_frame.method()); // Restore the pc of the frame - let previous_pc = current_frame.stashed_pc(); - self.pc.store(previous_pc, Ordering::Relaxed); + self.restore_pc(); // Push the return value of the previous frame if there is one if let Some(return_value) = return_value {