134 lines
3.8 KiB
Markdown
134 lines
3.8 KiB
Markdown
# Class Loading and Boot Image
|
|
|
|
**Location**: `crates/core/src/class_loader.rs`, `crates/core/src/bimage.rs`
|
|
|
|
## Boot Image (Bimage)
|
|
|
|
A 7z archive containing precompiled Java standard library classes.
|
|
|
|
### Structure
|
|
|
|
```rust
|
|
pub struct Bimage {
|
|
image: ArchiveReader<File>, // 7z archive reader
|
|
modules: Vec<String>, // Available modules
|
|
packages: HashMap<String, String>, // Package -> Module mapping
|
|
pub total_access_time: Duration, // Performance tracking
|
|
}
|
|
```
|
|
|
|
- **Default Location**: `./lib/modules`
|
|
- **Format**: 7z compressed archive
|
|
- **Structure**: `<module>/classes/<class>.class`
|
|
- **Default Module**: `java.base` (used when no module is specified)
|
|
|
|
## Class Loading Flow
|
|
|
|
The `ClassLoader` manages class resolution with a two-tier fallback mechanism:
|
|
|
|
### Process
|
|
|
|
1. **Check Cache**: Look in `DashMap<(String, LoaderId), Arc<RuntimeClass>>` for already-loaded classes
|
|
2. **Try Bimage**: Attempt to load from boot image via `bimage.get_class(module, class_fqn)`
|
|
3. **Fallback to Disk**: If not in bimage, load from filesystem at `{CLASSPATH}/{class_name}.class`
|
|
4. **Parse & Cache**: Parse ClassFile using deku, create RuntimeClass, store in cache
|
|
|
|
### Key Method
|
|
|
|
```rust
|
|
pub fn load_class(&mut self, what: &str, loader: LoaderId) -> Result<Arc<RuntimeClass>, VmError> {
|
|
let bytes = self.bimage
|
|
.and_then(|b| b.get_class("", what).ok())
|
|
.or_else(|_| Self::load_class_from_disk(what))
|
|
.map_err(|_| VmError::LoaderError(...))?;
|
|
|
|
let (_, cf) = ClassFile::from_bytes(bytes.as_ref())?;
|
|
let runtime = self.runtime_class(cf);
|
|
|
|
// Store with loader ID for multi-loader support
|
|
self.classes.insert((class_fqn, loader), Arc::new(runtime));
|
|
}
|
|
```
|
|
|
|
## Classpath Handling
|
|
|
|
### Resolution Priority
|
|
|
|
1. **Bimage (boot image)** - Primary source for standard library
|
|
2. **Command-line argument (arg[1])** - User-provided classpath
|
|
3. **Default `./data` directory** - Fallback location
|
|
|
|
### Implementation
|
|
|
|
```rust
|
|
fn load_class_from_disk(what: &str) -> Result<Vec<u8>, String> {
|
|
let class_path = std::env::args()
|
|
.nth(1)
|
|
.unwrap_or("./data".to_string())
|
|
.replace("\\", "/");
|
|
|
|
let path = format!("{class_path}/{what}.class");
|
|
// Load file from disk
|
|
}
|
|
```
|
|
|
|
## Bootstrap Process
|
|
|
|
**Location**: `crates/core/src/vm.rs` - `boot_strap()` method
|
|
|
|
### Steps
|
|
|
|
1. **Create VM**: `ClassLoader::with_bimage()` - initializes with boot image
|
|
2. **Load Core Classes**: Preloads essential VM classes
|
|
3. **Create Primitive Classes**: Synthetic class objects for primitive types
|
|
4. **Initialize Classes**: Run static initializers (`<clinit>`)
|
|
|
|
### Core Classes Loaded
|
|
|
|
```rust
|
|
let classes = vec![
|
|
"java/lang/String",
|
|
"java/lang/System",
|
|
"java/lang/Class",
|
|
"java/lang/Object",
|
|
"java/lang/Thread",
|
|
"java/lang/ThreadGroup",
|
|
"java/lang/Module",
|
|
"java/lang/reflect/Method",
|
|
// ...
|
|
];
|
|
```
|
|
|
|
## RuntimeClass
|
|
|
|
Runtime representation of a loaded class:
|
|
|
|
### Cached Data
|
|
|
|
- **Superclass Chain**: `super_classes: Vec<Arc<RuntimeClass>>`
|
|
- **Interface Hierarchy**: `super_interfaces: Vec<Arc<RuntimeClass>>`
|
|
- **Component Type**: For array classes, reference to element type
|
|
- **Initialization State**: Thread-safe `InitState` enum
|
|
|
|
### Initialization States
|
|
|
|
```rust
|
|
pub enum InitState {
|
|
NotInitialized,
|
|
Initializing(ThreadId), // Track which thread is initializing
|
|
Initialized,
|
|
}
|
|
```
|
|
|
|
### Method/Field Resolution
|
|
|
|
- `find_method()` - Searches class then walks up superclass chain
|
|
- `find_field()` - Same recursive behavior for fields
|
|
- `is_assignable_into()` - Checks type compatibility with array covariance
|
|
|
|
## Multi-Loader Support
|
|
|
|
Classes are keyed by `(class_name, LoaderId)` tuple to support:
|
|
- Different class loaders loading same-named classes
|
|
- Isolation between class loader namespaces
|
|
- Proper class identity checks |