Skip to content

Commit 1045cbe

Browse files
Merge pull request #546 from theseus-rs/optimize-register-primitives
refactor: reduce memory allocations and locks when registering primitives with the boot class loader
2 parents 2a3f8d4 + 523f571 commit 1045cbe

File tree

2 files changed

+47
-21
lines changed

2 files changed

+47
-21
lines changed

ristretto_classloader/src/class_loader.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,23 @@ impl ClassLoader {
159159
Ok(())
160160
}
161161

162+
/// Register all classes with the class loader.
163+
///
164+
/// # Errors
165+
///
166+
/// if the class cannot be registered.
167+
pub async fn register_all<I>(&self, class: I) -> Result<()>
168+
where
169+
I: IntoIterator<Item = Arc<Class>>,
170+
{
171+
let mut classes = self.classes.write().await;
172+
for class in class {
173+
let class_name = class.name().to_string();
174+
classes.entry(class_name).or_insert_with(|| class);
175+
}
176+
Ok(())
177+
}
178+
162179
/// Get the object for the class loader.
163180
pub async fn object(&self) -> Option<Value> {
164181
let object_guard = self.object.read().await;

ristretto_classloader/src/runtime/bootstrap.rs

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,23 @@ use flate2::bufread::GzDecoder;
44
use ristretto_classfile::Error::IoError;
55
use ristretto_classfile::{ClassAccessFlags, ClassFile, ConstantPool, JAVA_1_0_2};
66
use std::path::{Path, PathBuf};
7-
use std::sync::Arc;
7+
use std::sync::{Arc, Weak};
88
use std::{env, io};
99
use tar::Archive;
1010
use tracing::{debug, warn};
1111

12+
/// The default Java version used by the class loader. This is the version that will be used if no
13+
/// version is specified when creating a class loader.
1214
pub const DEFAULT_JAVA_VERSION: &str = "21.0.8.9.1";
1315

16+
/// The access flags for primitive classes in the Java runtime. These classes are public, final, and
17+
/// abstract, meaning they cannot be instantiated and do not have any methods or fields.
18+
const PRIMITIVE_CLASS_ACCESS_FLAGS: ClassAccessFlags = ClassAccessFlags::from_bits_retain(
19+
ClassAccessFlags::PUBLIC.bits()
20+
| ClassAccessFlags::FINAL.bits()
21+
| ClassAccessFlags::ABSTRACT.bits(),
22+
);
23+
1424
/// Get a class loader for the default Java runtime version. If the version is not installed, the
1525
/// archive will be downloaded and extracted.
1626
///
@@ -85,8 +95,7 @@ pub async fn version_class_loader(version: &str) -> Result<(PathBuf, String, Arc
8595
let mut installation_dir = base_path.join(&version);
8696
if !installation_dir.exists() {
8797
let (extracted_version, file_name, archive) = util::get_runtime_archive(&version).await?;
88-
installation_dir =
89-
extract_archive(version.as_str(), file_name.as_str(), &archive, &base_path).await?;
98+
installation_dir = extract_archive(&version, &file_name, &archive, &base_path).await?;
9099
version = extracted_version;
91100
}
92101

@@ -101,35 +110,35 @@ pub async fn version_class_loader(version: &str) -> Result<(PathBuf, String, Arc
101110

102111
/// Register all primitive classes in the class loader.
103112
async fn register_primitives(class_loader: &Arc<ClassLoader>) -> Result<()> {
104-
register_primitive(class_loader, "boolean").await?;
105-
register_primitive(class_loader, "byte").await?;
106-
register_primitive(class_loader, "char").await?;
107-
register_primitive(class_loader, "double").await?;
108-
register_primitive(class_loader, "float").await?;
109-
register_primitive(class_loader, "int").await?;
110-
register_primitive(class_loader, "long").await?;
111-
register_primitive(class_loader, "short").await?;
112-
register_primitive(class_loader, "void").await?;
113+
let class_loader_weak_ref = Arc::downgrade(class_loader);
114+
let classes = [
115+
create_primitive_class(&class_loader_weak_ref, "boolean")?,
116+
create_primitive_class(&class_loader_weak_ref, "byte")?,
117+
create_primitive_class(&class_loader_weak_ref, "char")?,
118+
create_primitive_class(&class_loader_weak_ref, "double")?,
119+
create_primitive_class(&class_loader_weak_ref, "float")?,
120+
create_primitive_class(&class_loader_weak_ref, "int")?,
121+
create_primitive_class(&class_loader_weak_ref, "long")?,
122+
create_primitive_class(&class_loader_weak_ref, "short")?,
123+
create_primitive_class(&class_loader_weak_ref, "void")?,
124+
];
125+
class_loader.register_all(classes).await?;
113126
Ok(())
114127
}
115128

116-
/// Register a primitive class in the class loader.
117-
async fn register_primitive(class_loader: &Arc<ClassLoader>, primitive: &str) -> Result<()> {
129+
/// Creates a primitive class in the class loader.
130+
fn create_primitive_class(class_loader: &Weak<ClassLoader>, primitive: &str) -> Result<Arc<Class>> {
118131
let mut constant_pool = ConstantPool::new();
119132
let this_class_index = constant_pool.add_class(primitive)?;
120133
let class_file = ClassFile {
121134
version: JAVA_1_0_2,
122135
constant_pool,
123-
access_flags: ClassAccessFlags::PUBLIC
124-
| ClassAccessFlags::FINAL
125-
| ClassAccessFlags::ABSTRACT,
136+
access_flags: PRIMITIVE_CLASS_ACCESS_FLAGS,
126137
this_class: this_class_index,
127138
..Default::default()
128139
};
129-
130-
let class = Class::from(Some(Arc::downgrade(class_loader)), class_file)?;
131-
class_loader.register(class).await?;
132-
Ok(())
140+
let class = Class::from(Some(class_loader.clone()), class_file)?;
141+
Ok(class)
133142
}
134143

135144
/// Get the class path for the given version.

0 commit comments

Comments
 (0)