Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
267 changes: 120 additions & 147 deletions ristretto_classloader/src/object.rs

Large diffs are not rendered by default.

363 changes: 189 additions & 174 deletions ristretto_classloader/src/reference.rs

Large diffs are not rendered by default.

67 changes: 43 additions & 24 deletions ristretto_classloader/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,11 +429,21 @@ impl Value {
/// # Errors
///
/// if the value is not an Object.
pub fn as_object_ref(&self) -> Result<&Object> {
pub fn as_object_ref(&self) -> Result<RwLockReadGuard<'_, Object>> {
let reference = self.as_reference()?;
reference.as_object_ref()
}

/// Returns a mutable reference to an `Object`.
///
/// # Errors
///
/// if the value is not an Object.
pub fn as_object_mut(&self) -> Result<RwLockWriteGuard<'_, Object>> {
let reference = self.as_reference()?;
reference.as_object_mut()
}

/// Returns a reference to a `String`.
///
/// # Errors
Expand Down Expand Up @@ -831,7 +841,7 @@ mod tests {
async fn test_string_format() -> Result<()> {
let (_java_home, _java_version, class_loader) = runtime::default_class_loader().await?;
let class = class_loader.load("java.lang.String").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
let string_bytes: Vec<i8> = "foo".as_bytes().to_vec().iter().map(|&b| b as i8).collect();
let string_value = Value::from(string_bytes);
assert!(!string_value.is_null());
Expand Down Expand Up @@ -1022,9 +1032,8 @@ mod tests {
let class = load_class(class_name).await?;
let object = Object::new(class)?;
let value1 = Value::from(object);
if let Value::Object(Some(Reference::Object(ref obj))) = value1 {
obj.set_value("value", value1.clone())?;
}
let mut object = value1.as_object_mut()?;
object.set_value("value", value1.clone())?;
let value2 = value1.clone();
assert_eq!(value1, value2);
Ok(())
Expand Down Expand Up @@ -1259,7 +1268,7 @@ mod tests {
let original_class = load_class("[Ljava/lang/Object;").await?;
let class_name = "java.lang.Integer";
let class = load_class(class_name).await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Int(42))?;
let value = Value::from(object);
let original_values = vec![value];
Expand Down Expand Up @@ -1317,7 +1326,7 @@ mod tests {
#[tokio::test]
async fn test_as_bool_object() -> Result<()> {
let class = load_class("java.lang.Boolean").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Int(1))?;
let value = Value::from(object);
let value = value.as_bool()?;
Expand All @@ -1335,7 +1344,7 @@ mod tests {
#[tokio::test]
async fn test_as_char_object() -> Result<()> {
let class = load_class("java.lang.Character").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Int(42))?;
let value = Value::from(object);
let value = value.as_char()?;
Expand All @@ -1353,7 +1362,7 @@ mod tests {
#[tokio::test]
async fn test_as_i8_object() -> Result<()> {
let class = load_class("java.lang.Byte").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Int(42))?;
let value = Value::from(object);
let value = value.as_i8()?;
Expand All @@ -1371,7 +1380,7 @@ mod tests {
#[tokio::test]
async fn test_as_u8_object() -> Result<()> {
let class = load_class("java.lang.Byte").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Int(42))?;
let value = Value::from(object);
let value = value.as_u8()?;
Expand All @@ -1389,7 +1398,7 @@ mod tests {
#[tokio::test]
async fn test_as_i16_object() -> Result<()> {
let class = load_class("java.lang.Short").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Int(42))?;
let value = Value::from(object);
let value = value.as_i16()?;
Expand All @@ -1407,7 +1416,7 @@ mod tests {
#[tokio::test]
async fn test_as_u16_object() -> Result<()> {
let class = load_class("java.lang.Short").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Int(42))?;
let value = Value::from(object);
let value = value.as_u16()?;
Expand All @@ -1425,7 +1434,7 @@ mod tests {
#[tokio::test]
async fn test_as_i32_object() -> Result<()> {
let class = load_class("java.lang.Integer").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Int(42))?;
let value = Value::from(object);
let value = value.as_i32()?;
Expand All @@ -1443,7 +1452,7 @@ mod tests {
#[tokio::test]
async fn test_as_u32_object() -> Result<()> {
let class = load_class("java.lang.Integer").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Int(42))?;
let value = Value::from(object);
let value = value.as_u32()?;
Expand All @@ -1461,7 +1470,7 @@ mod tests {
#[tokio::test]
async fn test_as_i64_object() -> Result<()> {
let class = load_class("java.lang.Long").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Long(42))?;
let value = Value::from(object);
let value = value.as_i64()?;
Expand All @@ -1479,7 +1488,7 @@ mod tests {
#[tokio::test]
async fn test_as_u64_object() -> Result<()> {
let class = load_class("java.lang.Long").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Long(42))?;
let value = Value::from(object);
let value = value.as_u64()?;
Expand All @@ -1497,7 +1506,7 @@ mod tests {
#[tokio::test]
async fn test_as_isize_object() -> Result<()> {
let class = load_class("java.lang.Long").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Long(42))?;
let value = Value::from(object);
let value = value.as_isize()?;
Expand All @@ -1515,7 +1524,7 @@ mod tests {
#[tokio::test]
async fn test_as_usize_object() -> Result<()> {
let class = load_class("java.lang.Long").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Long(42))?;
let value = Value::from(object);
let value = value.as_usize()?;
Expand All @@ -1526,7 +1535,7 @@ mod tests {
#[tokio::test]
async fn test_as_f32() -> Result<()> {
let class = load_class("java.lang.Float").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Float(42.1))?;
let value = Value::from(object);
let value = value.as_f32()?;
Expand Down Expand Up @@ -1554,7 +1563,7 @@ mod tests {
#[tokio::test]
async fn test_as_f64_object() -> Result<()> {
let class = load_class("java.lang.Double").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
object.set_value("value", Value::Double(42.1))?;
let value = Value::from(object);
let value = value.as_f64()?;
Expand All @@ -1568,7 +1577,7 @@ mod tests {
let original_class = load_class("[Ljava/lang/Object;").await?;
let class_name = "java/lang/Integer";
let class = load_class(class_name).await?;
let object = Object::new(class.clone())?;
let mut object = Object::new(class.clone())?;
object.set_value("value", Value::Int(42))?;
let value = Value::from(object);
let original_values = vec![value];
Expand Down Expand Up @@ -1838,17 +1847,27 @@ mod tests {
let class = load_class("java.lang.Object").await?;
let object = Object::new(class)?;
let value = Value::from(object.clone());
let result = value.as_object_ref()?;
assert_eq!(&object, result);
let result = value.as_object_ref()?.clone();
assert_eq!(object, result);
assert_eq!("java/lang/Object", object.class().name());
Ok(())
}

#[tokio::test]
async fn test_as_object_mut() -> Result<()> {
let class = load_class("java.lang.Integer").await?;
let object = Object::new(class)?;
let value = Value::from(object.clone());
let mut result = value.as_object_mut()?;
result.set_value("value", Value::Int(42))?;
Ok(())
}

#[expect(clippy::cast_possible_wrap)]
#[tokio::test]
async fn test_as_string() -> Result<()> {
let class = load_class("java.lang.String").await?;
let object = Object::new(class)?;
let mut object = Object::new(class)?;
let string_bytes: Vec<i8> = "foo".as_bytes().to_vec().iter().map(|&b| b as i8).collect();
let string_value = Value::from(string_bytes);
object.set_value("value", string_value)?;
Expand Down
8 changes: 4 additions & 4 deletions ristretto_gc/src/pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ impl TracePtr {
// 3. T implements Trace so the cast is valid
// 4. We only call this during controlled GC phases
unsafe {
let obj = &*ptr.cast::<T>();
obj.trace(collector);
let object = &*ptr.cast::<T>();
object.trace(collector);
}
}

Expand Down Expand Up @@ -102,8 +102,8 @@ impl TracePtr {
// 3. T implements Trace so the cast is valid
// 4. The object is managed by the GC and should be alive during tracing
unsafe {
let obj = &*ptr.cast::<T>();
obj.trace(collector);
let object = &*ptr.cast::<T>();
object.trace(collector);
}
}

Expand Down
14 changes: 7 additions & 7 deletions ristretto_gc/tests/cycles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ fn test_self_referencing_object() {
}

{
let mut obj = Gc::with_collector(
let mut object = Gc::with_collector(
&collector,
SelfRef {
value: 42,
Expand All @@ -173,24 +173,24 @@ fn test_self_referencing_object() {

// Create self-reference using a scope to avoid borrow checker issues
{
let obj_clone = obj.clone();
let obj_clone = object.clone();
// Safety: This is safe because:
// 1. We have exclusive access to the test environment
// 2. No other threads are accessing this object
// 3. This is a controlled test for self-referencing objects
// 4. The mutation happens in a single-threaded test context
unsafe {
let obj_mut = obj.get_mut_unchecked();
let obj_mut = object.get_mut_unchecked();
obj_mut.myself = Some(obj_clone);
}
}

// Verify the self-reference works
assert_eq!(obj.value, 42);
assert!(obj.myself.is_some());
if let Some(ref myself) = obj.myself {
assert_eq!(object.value, 42);
assert!(object.myself.is_some());
if let Some(ref myself) = object.myself {
assert_eq!(myself.value, 42);
assert!(Gc::ptr_eq(&obj, myself));
assert!(Gc::ptr_eq(&object, myself));
}
}

Expand Down
16 changes: 8 additions & 8 deletions ristretto_gc/tests/drop_mechanism.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ struct TestObject {
impl TestObject {
fn new(id: usize) -> (Self, Arc<AtomicBool>) {
let dropped = Arc::new(AtomicBool::new(false));
let obj = Self {
let object = Self {
id,
dropped: dropped.clone(),
};
(obj, dropped)
(object, dropped)
}
}

Expand Down Expand Up @@ -45,12 +45,12 @@ impl TestObjectWithFinalizer {
fn new(id: usize) -> (Self, Arc<AtomicBool>, Arc<AtomicBool>) {
let finalized = Arc::new(AtomicBool::new(false));
let dropped = Arc::new(AtomicBool::new(false));
let obj = Self {
let object = Self {
id,
finalized: finalized.clone(),
dropped: dropped.clone(),
};
(obj, finalized, dropped)
(object, finalized, dropped)
}
}

Expand Down Expand Up @@ -81,13 +81,13 @@ fn test_basic_drop_mechanism() {
let (obj, dropped_flag) = TestObject::new(1);

// Create a Gc object
let gc_obj = Gc::new(obj);
let gc_object = Gc::new(obj);

// Verify the object is not dropped yet
assert!(!dropped_flag.load(Ordering::Acquire));

// Drop the Gc reference
drop(gc_obj);
drop(gc_object);

// Force garbage collection
GC.collect();
Expand All @@ -108,14 +108,14 @@ fn test_finalizer_mechanism() {
let (obj, finalized_flag, dropped_flag) = TestObjectWithFinalizer::new(2);

// Create a Gc object with finalizer
let gc_obj = Gc::new_with_finalizer(obj);
let gc_object = Gc::new_with_finalizer(obj);

// Verify the object is not finalized or dropped yet
assert!(!finalized_flag.load(Ordering::Acquire));
assert!(!dropped_flag.load(Ordering::Acquire));

// Drop the Gc reference
drop(gc_obj);
drop(gc_object);

// Force garbage collection
GC.collect();
Expand Down
4 changes: 2 additions & 2 deletions ristretto_gc/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ fn test_stress_test_rapid_allocation() {

for i in 0..1000 {
let data = vec![i; 100]; // Each object contains 100 elements
let gc_obj = Gc::with_collector(&collector, data);
objects.push(gc_obj);
let gc_object = Gc::with_collector(&collector, data);
objects.push(gc_object);

// Trigger collection periodically
if i % 100 == 0 {
Expand Down
6 changes: 3 additions & 3 deletions ristretto_vm/src/instruction/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ mod tests {
let Value::Object(Some(reference)) = stack.pop()? else {
panic!("expected reference");
};
assert_eq!("[Ljava/lang/Object;", reference.class_name());
assert_eq!("[Ljava/lang/Object;", reference.class_name()?);
Ok(())
}

Expand Down Expand Up @@ -493,7 +493,7 @@ mod tests {
let object = stack.pop()?;
assert!(matches!(
object,
Value::Object(Some(ref reference)) if reference.class_name() == class_name
Value::Object(Some(ref reference)) if reference.class_name()? == class_name
));
Ok(())
}
Expand Down Expand Up @@ -556,7 +556,7 @@ mod tests {
let object = stack.pop()?;
assert!(matches!(
object,
Value::Object(Some(ref reference)) if reference.class_name() == class_name
Value::Object(Some(ref reference)) if reference.class_name()? == class_name
));
Ok(())
}
Expand Down
Loading