3.8 KiB
3.8 KiB
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 methodsjvm- Java virtual machine standard libraryjava- 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:
- Java code calls
RegisterNatives()with method names, signatures, and function pointers - VM generates JNI-formatted symbol names using
generate_jni_method_name() - Function pointers are stored in
Vm::native_methods: DashMap<String, *const c_void> - Filters prevent registration of certain methods (e.g., Thread operations)
- Java code calls
Native Method Dispatch
When a native method is invoked:
- Detection:
MethodData::ACC_NATIVEflag identifies native methods - Location:
crates/core/src/thread.rs - Flow:
execute_method()checks if method hasACC_NATIVEflag- If static, adds class reference to args; otherwise adds instance reference
- 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
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
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
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, orMutex - JNI environment: Created per-thread, stored in
VmThread::jni_env - Symbol lookup: Two-pass search (without params, then with params)
- Error handling: Returns
VmError::NativeErrorif symbols not found - Tracking: Maintains statistics on library resolution counts