Skip to content

Commit

Permalink
Merge pull request #215 from theseus-rs/impl-class-get-declared-const…
Browse files Browse the repository at this point in the history
…ructors

fix: implement java.lang.Class.getDeclaredConstructors0(Z)[Ljava/lang/reflect/Constructor;
  • Loading branch information
brianheineman authored Jan 12, 2025
2 parents 8f50a29 + 0ced304 commit 3e08b88
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 6 deletions.
9 changes: 9 additions & 0 deletions ristretto_classloader/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct Method {
code: Vec<Instruction>,
line_numbers: Vec<LineNumber>,
exception_table: Vec<ExceptionTableEntry>,
attributes: Vec<Attribute>,
}

impl Method {
Expand Down Expand Up @@ -73,6 +74,7 @@ impl Method {
code,
line_numbers,
exception_table,
attributes: definition.attributes.clone(),
})
}

Expand Down Expand Up @@ -166,6 +168,12 @@ impl Method {
&self.exception_table
}

/// Get the attributes.
#[must_use]
pub fn attributes(&self) -> &Vec<Attribute> {
&self.attributes
}

/// Parse the method descriptor. The descriptor is a string representing the method signature.
/// The descriptor has the following format:
///
Expand Down Expand Up @@ -405,6 +413,7 @@ mod tests {
code: Vec::new(),
line_numbers: Vec::new(),
exception_table: Vec::new(),
attributes: Vec::new(),
};
assert_eq!("test() -> void", method.to_string());
}
Expand Down
95 changes: 89 additions & 6 deletions ristretto_vm/src/native_methods/java/lang/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::JavaError::NullPointerException;
use crate::Result;
use async_recursion::async_recursion;
use ristretto_classfile::attributes::{Attribute, InnerClass};
use ristretto_classfile::{ClassAccessFlags, FieldAccessFlags, Version};
use ristretto_classloader::{Class, Object, Reference, Value};
use ristretto_classfile::{ClassAccessFlags, FieldAccessFlags, MethodAccessFlags, Version};
use ristretto_classloader::{Class, Method, Object, Reference, Value};
use std::sync::Arc;

const JAVA_8: Version = Version::Java8 { minor: 0 };
Expand Down Expand Up @@ -377,12 +377,95 @@ async fn get_declared_classes_0(
Ok(Some(declared_classes))
}

/// Get the exceptions declared by a method.
async fn get_exceptions(
thread: &Arc<Thread>,
class: &Arc<Class>,
method: &Arc<Method>,
) -> Result<Value> {
let vm = thread.vm()?;
let constant_pool = class.constant_pool();
let class_array = thread.class("[Ljava/lang/Class;").await?;
let mut exceptions = Vec::new();
for attribute in method.attributes() {
if let Attribute::Exceptions {
exception_indexes, ..
} = attribute
{
for exception_index in exception_indexes {
let class_name = constant_pool.try_get_class(*exception_index)?;
let exception = thread.class(class_name).await?;
let exception = exception.to_object(&vm).await?;
exceptions.push(exception);
}
break;
}
}
let exceptions = Value::try_from((class_array, exceptions))?;
Ok(exceptions)
}

#[async_recursion(?Send)]
async fn get_declared_constructors_0(
_thread: Arc<Thread>,
_arguments: Arguments,
thread: Arc<Thread>,
mut arguments: Arguments,
) -> Result<Option<Value>> {
todo!("java.lang.Class.getDeclaredConstructors0(Z)[Ljava/lang/reflect/Constructor;")
let public_only = arguments.pop_int()? != 0;
let object = arguments.pop_object()?;
let vm = thread.vm()?;
let class = get_class(&thread, &object).await?;
let class_object = class.to_object(&vm).await?;

let class_array = thread.class("[Ljava/lang/Class;").await?;
let mut constructors = Vec::new();
for (slot, method) in class.methods().iter().enumerate() {
if method.name() != "<init>" {
continue;
}

let access_flags = method.access_flags();
if public_only && !access_flags.contains(MethodAccessFlags::PUBLIC) {
continue;
}

let mut parameters = Vec::new();
for parameter in method.parameters() {
let class_name = parameter.class_name();
let class = thread.class(class_name).await?;
parameters.push(class.to_object(&vm).await?);
}
let parameter_types = Value::try_from((class_array.clone(), parameters))?;
let checked_exceptions = get_exceptions(&thread, &class, method).await?;
let modifiers = Value::Int(i32::from(access_flags.bits()));
let slot = Value::Int(i32::try_from(slot)?);
// TODO: Add support for generic signature
let signature = Value::Object(None);
// TODO: Add support for annotations
let annotations = Value::from(Vec::<i8>::new());
// TODO: Add support for parameter_annotations
let parameter_annotations = Value::from(Vec::<i8>::new());

let constructor = thread
.object(
"java/lang/reflect/Constructor",
"Ljava/lang/Class;[Ljava/lang/Class;[Ljava/lang/Class;IILjava/lang/String;[B[B",
vec![
class_object.clone(),
parameter_types,
checked_exceptions,
modifiers,
slot,
signature,
annotations,
parameter_annotations,
],
)
.await?;
constructors.push(constructor);
}
let constructors_array_class = thread.class("[Ljava/lang/reflect/Constructor;").await?;
let constructors = Value::try_from((constructors_array_class, constructors))?;
Ok(Some(constructors))
}

#[async_recursion(?Send)]
Expand Down Expand Up @@ -414,7 +497,7 @@ async fn get_declared_fields_0(
// TODO: Add support for generic signature
let signature = Value::Object(None);
// TODO: Add support for annotations
let annotations = Value::Object(None);
let annotations = Value::from(Vec::<i8>::new());
let (descriptor, arguments) = if vm.java_class_file_version() <= &JAVA_11 {
(
"Ljava/lang/Class;Ljava/lang/String;Ljava/lang/Class;IILjava/lang/String;[B",
Expand Down

0 comments on commit 3e08b88

Please sign in to comment.