Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Serial-ATA committed Dec 27, 2024
1 parent e06556d commit e774ab4
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 47 deletions.
8 changes: 2 additions & 6 deletions instructions/src/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,15 +253,13 @@ impl<Reference: Debug + Clone> Operand<Reference> {

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;
}

Expand Down Expand Up @@ -311,15 +309,13 @@ impl<Reference: Debug + Clone> Operand<Reference> {
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;
}

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;
}
Expand Down
15 changes: 7 additions & 8 deletions runtime/src/classpath/classloader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand Down Expand Up @@ -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();
}
}

Expand All @@ -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();
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions runtime/src/initialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 2 additions & 4 deletions runtime/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<cp_types::FieldRef>(field_ref_idx);
if is_static {
class.initialize(frame.thread());
ret.class.initialize(frame.thread());
}

ret
Expand All @@ -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::<cp_types::MethodRef>(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
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/method_invoker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
38 changes: 34 additions & 4 deletions runtime/src/native/java/lang/Class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,41 @@ pub fn initClassName(

pub fn getSuperclass(
_env: NonNull<JniEnv>,
_this: Reference, // java.lang.Class
this: Reference, // java.lang.Class
) -> Reference /* Class<? super T> */
{
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<JniEnv>,
Expand Down Expand Up @@ -146,8 +177,7 @@ pub fn getPrimitiveClass(_env: NonNull<JniEnv>, 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()));
}
}

Expand Down
45 changes: 33 additions & 12 deletions runtime/src/native/jdk/internal/misc/Unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,12 +503,32 @@ pub fn getReference(

pub fn putReference(
_env: NonNull<JniEnv>,
_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(
Expand All @@ -523,12 +543,13 @@ pub fn getReferenceVolatile(

pub fn putReferenceVolatile(
_env: NonNull<JniEnv>,
_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
Expand Down
6 changes: 3 additions & 3 deletions runtime/src/objects/class/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
10 changes: 6 additions & 4 deletions runtime/src/objects/mirror.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down
35 changes: 34 additions & 1 deletion runtime/src/objects/reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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(),
Expand All @@ -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),
Expand Down
25 changes: 23 additions & 2 deletions runtime/src/thread/frame/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -43,11 +59,16 @@ impl<'a> From<&'a NativeFrame> for VisibleStackFrame<'a> {
}
}

#[derive(Debug)]
pub struct FrameStack {
inner: UnsafeCell<Vec<StackFrame>>,
}

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 {
Expand Down
Loading

0 comments on commit e774ab4

Please sign in to comment.