5.0 KiB
5.0 KiB
JNI Implementation
Location: crates/core/src/native/jni.rs
JNIEnv Structure
The JNIEnv is created as a function table (JNINativeInterface_ from the jni crate) with 250+ function pointers:
pub fn create_jni_function_table(thread: *const VmThread) -> JNIEnv {
Box::into_raw(Box::new(JNINativeInterface_ {
reserved0: thread as *mut _, // Stores pointer to VmThread for context
reserved1: std::ptr::null_mut(),
reserved2: std::ptr::null_mut(),
reserved3: std::ptr::null_mut(),
GetVersion: Some(jni_get_version),
FindClass: Some(find_class),
RegisterNatives: Some(register_natives),
GetMethodID: Some(get_method_id),
// ... 240+ more function pointers
}))
}
Key Feature: The reserved0 field stores a pointer to the VmThread, allowing each JNI function to access thread
context via get_thread(env).
VmThread's JNIEnv Storage
Location: crates/core/src/thread.rs
Each thread owns its JNIEnv:
pub struct VmThread {
pub id: ThreadId,
pub vm: Arc<Vm>,
pub loader: Arc<Mutex<ClassLoader>>,
pub jni_env: JNIEnv, // Stored per-thread
// ... other fields
}
// Created during VmThread initialization:
let jni_env = create_jni_function_table(weak_self.as_ptr() as * mut VmThread);
Native Method Invocation
Location: crates/core/src/thread.rs (lines 340-428)
The flow is:
- Method Detection: When a method has
ACC_NATIVEflag,invoke_native()is called - Symbol Resolution: Generates JNI symbol name (e.g.,
Java_java_lang_String_intern) - Lookup: Searches registered native methods or loaded native libraries via
find_native_method() - FFI Call: Uses
libffito call the native function with constructed arguments
pub fn invoke_native(&self, method: &MethodRef, args: Vec<Value>) -> MethodCallResult {
let symbol_name = generate_jni_method_name(method, false);
// Find the function pointer
let p = self.vm.find_native_method(&symbol_name)
.ok_or(VmError::NativeError(...))?;
// Build Call Interface (CIF) for FFI
let cp = CodePtr::from_ptr(p);
let built_args = build_args(args, &mut storage, &self.jni_env as *mut JNIEnv);
let cif = method.build_cif();
// Invoke with type-specific call
match &method.desc.return_type {
None => {
cif.call::<()>(cp, built_args.as_ref());
Ok(None)
}
Some(FieldType::Base(BaseType::Int)) => {
let v = cif.call::<jint>(cp, built_args.as_ref());
Ok(Some(v.into()))
}
// ... handle other return types
}
}
Argument Marshalling
Location: crates/core/src/thread.rs (lines 509-548)
Native functions receive:
JNIEnv*- pointer to the function tablejclassorjobject(receiver) - always an ID (u32)- Parameters - converted from VM
Valuetypes to JNI types
fn build_args(mut params: VecDeque<Value>, storage: &mut Vec<Box<dyn Any>>,
jnienv: *mut JNIEnv) -> Vec<Arg> {
storage.push(Box::new(jnienv)); // Slot 0: JNIEnv*
let receiver_id = params.pop_front().map(...);
storage.push(Box::new(receiver_id as jobject)); // Slot 1: this/class
for value in params {
match value {
Value::Primitive(Primitive::Int(x)) => storage.push(Box::new(x)),
Value::Reference(Some(ref_kind)) => {
storage.push(Box::new(ref_kind.id() as jobject)) // References as IDs
}
// ... other types
}
}
storage.iter().map(|boxed| arg(&**boxed)).collect()
}
Native Method Registration
Location: crates/core/src/native/jni.rs (lines 381-442)
Java code calls RegisterNatives() JNI function, which stores pointers:
unsafe extern "system" fn register_natives(
env: *mut JNIEnv,
clazz: jclass,
methods: *const JNINativeMethod,
n_methods: jint,
) -> jint {
let thread = &*get_thread(env);
for i in 0..n_methods as usize {
let native_method = &*methods.add(i);
let full_name = generate_jni_short_name(&class_name, name);
thread.vm.native_methods.insert(full_name, native_method.fnPtr);
}
JNI_OK
}
Implemented JNI Functions
| Category | Functions |
|---|---|
| Version | GetVersion |
| Class Operations | FindClass, GetSuperclass, IsAssignableFrom |
| Exceptions | Throw, ThrowNew, ExceptionOccurred, ExceptionClear |
| References | NewGlobalRef, DeleteGlobalRef, NewLocalRef |
| Object Operations | AllocObject, NewObject, GetObjectClass, IsInstanceOf |
| Field Access | GetFieldID, Get/Set<Type>Field, GetStaticFieldID |
| Method Invocation | GetMethodID, Call<Type>Method, CallStatic<Type>Method |
| String Operations | NewString, GetStringLength, GetStringChars |
| Array Operations | NewArray, GetArrayLength, Get/Set<Type>ArrayRegion |
| Registration | RegisterNatives, UnregisterNatives |
| Monitors | MonitorEnter, MonitorExit |