jvm-rs/docs/native-ffi.md

125 lines
3.8 KiB
Markdown

# Native Methods and FFI System
**Location**: `crates/core/src/thread.rs`, `crates/core/src/native/`
## Library Loading
Native libraries are loaded dynamically using `libloading`:
- **Location**: `crates/core/src/main.rs`
- **Supported platforms**: Windows (.dll), Linux (.so)
- **Libraries loaded**:
- `roast_vm` - VM-specific native methods
- `jvm` - Java virtual machine standard library
- `java` - Java standard library
Libraries are registered with the VM via `Vm::load_native_library()` and stored in `native_libraries: Arc<RwLock<Vec<(String, Library)>>>`.
## Native Method Registration
Native methods are registered through JNI's `RegisterNatives` function:
- **Location**: `crates/core/src/native/jni.rs`
- **Process**:
1. Java code calls `RegisterNatives()` with method names, signatures, and function pointers
2. VM generates JNI-formatted symbol names using `generate_jni_method_name()`
3. Function pointers are stored in `Vm::native_methods: DashMap<String, *const c_void>`
4. Filters prevent registration of certain methods (e.g., Thread operations)
## Native Method Dispatch
When a native method is invoked:
- **Detection**: `MethodData::ACC_NATIVE` flag identifies native methods
- **Location**: `crates/core/src/thread.rs`
- **Flow**:
1. `execute_method()` checks if method has `ACC_NATIVE` flag
2. If static, adds class reference to args; otherwise adds instance reference
3. Calls `invoke_native()` with method reference and arguments
## FFI System - libffi Integration
libffi is used to call native functions with correct calling conventions:
### Call Interface Building
```rust
fn build_cif(&self) -> Cif {
let mut args = vec![
Type::pointer(), // JNIEnv*
Type::pointer(), // jclass/jobject
];
for v in self.desc.parameters {
args.push(v.into())
}
let return_type = ...;
Builder::new().args(args).res(return_type).into_cif()
}
```
- Constructs a Call Interface (Cif) from method signature
- Maps Java types to FFI types
- Always adds JNIEnv* and jclass/jobject as first two parameters
### Argument Marshalling
```rust
fn build_args(params, storage, jnienv) -> Vec<Arg>
```
- Marshals Java values to native format
- Converts references to object IDs (u32)
- Boxes primitives for FFI passing
- Stores all values in a temporary vector
### Function Invocation
```rust
let cp = CodePtr::from_ptr(p);
cif.call::<ReturnType>(cp, built_args.as_ref());
```
- Converts function pointer to CodePtr
- Calls through libffi with correct return type handling
## Type Mapping
| Java Type | FFI Type |
|-----------|----------|
| byte | i8 |
| char | u16 |
| short | i16 |
| int | i32 |
| long | i64 |
| float | f32 |
| double | f64 |
| boolean | i8 |
| Object/Array | pointer |
## JNI Function Table
A complete JNI function table is created and passed to native code:
- **Location**: `crates/core/src/native/jni.rs`
- **Implementation**:
- 250+ JNI functions defined as unsafe extern "system" functions
- Covers class operations, method invocation, field access, array operations, string handling
- Many functions are stubs returning `todo!()` for unimplemented features
## Unsafe Support (sun.misc.Unsafe)
Low-level unsafe operations are tracked:
- **Location**: `crates/core/src/native/unsafe.rs`
- **Features**:
- Field offset registry mapping to class/field pairs
- Off-heap memory allocation tracking
- Base offset constant: `0x1_0000_0000`
## Key Implementation Characteristics
- **Thread-safe**: All structures use `DashMap`, `RwLock`, or `Mutex`
- **JNI environment**: Created per-thread, stored in `VmThread::jni_env`
- **Symbol lookup**: Two-pass search (without params, then with params)
- **Error handling**: Returns `VmError::NativeError` if symbols not found
- **Tracking**: Maintains statistics on library resolution counts