Skip to content

Commit f089dea

Browse files
committed
Store java.lang.Class name as byte array and resolve ClassDefinition on demand
1 parent 9a4a05e commit f089dea

2 files changed

Lines changed: 22 additions & 7 deletions

File tree

java_runtime/src/classes/java/lang/class.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ impl Class {
4242
),
4343
],
4444
fields: vec![
45-
JavaFieldProto::new("raw", "[B", Default::default()), // raw rust pointer of Box<dyn Class>
45+
// Stored as raw bytes instead of java/lang/String to avoid circular dependency:
46+
// from_rust_class -> JavaLangString::from_rust_string -> new_class("java/lang/String") -> from_rust_class -> stack overflow
47+
JavaFieldProto::new("nameBytes", "[B", Default::default()),
4648
JavaFieldProto::new("classLoader", "Ljava/lang/ClassLoader;", Default::default()),
4749
],
4850
access_flags: Default::default(),

jvm/src/runtime/java_lang_class.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
1-
use alloc::boxed::Box;
1+
use alloc::{boxed::Box, string::String, vec::Vec};
22

3-
use crate::{Result, class_definition::ClassDefinition, class_instance::ClassInstance, jvm::Jvm};
3+
use bytemuck::cast_vec;
4+
5+
use crate::{Array, ClassInstanceRef, Result, class_definition::ClassDefinition, class_instance::ClassInstance, jvm::Jvm};
46

57
pub struct JavaLangClass;
68

79
impl JavaLangClass {
810
#[allow(clippy::borrowed_box)]
911
pub async fn to_rust_class(jvm: &Jvm, this: &Box<dyn ClassInstance>) -> Result<Box<dyn ClassDefinition>> {
10-
let rust_class = jvm.get_rust_object_field(this, "raw").await?;
11-
12-
Ok(rust_class)
12+
let name_bytes: ClassInstanceRef<Array<i8>> = jvm.get_field(this, "nameBytes", "[B").await?;
13+
let len = jvm.array_length(&name_bytes).await?;
14+
let name_bytes_vec: Vec<i8> = jvm.load_array(&name_bytes, 0, len).await?;
15+
let class_name = String::from_utf8(cast_vec(name_bytes_vec)).unwrap_or_default();
16+
if let Some(class) = jvm.get_class(&class_name) {
17+
Ok(class.definition)
18+
} else {
19+
Err(jvm.exception("java/lang/NoClassDefFoundError", &class_name).await)
20+
}
1321
}
1422

1523
pub async fn from_rust_class(
@@ -19,7 +27,12 @@ impl JavaLangClass {
1927
) -> Result<Box<dyn ClassInstance>> {
2028
let mut java_class = jvm.new_class("java/lang/Class", "()V", ()).await?;
2129

22-
jvm.put_rust_object_field(&mut java_class, "raw", rust_class).await?;
30+
let class_name = rust_class.name();
31+
let mut name_bytes = jvm.instantiate_array("B", class_name.len()).await?;
32+
let bytes: Vec<i8> = cast_vec(class_name.into_bytes());
33+
jvm.store_array(&mut name_bytes, 0, bytes).await?;
34+
jvm.put_field(&mut java_class, "nameBytes", "[B", name_bytes).await?;
35+
2336
jvm.put_field(&mut java_class, "classLoader", "Ljava/lang/ClassLoader;", class_loader)
2437
.await?;
2538

0 commit comments

Comments
 (0)