# 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: ```rust 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: ```rust pub struct VmThread { pub id: ThreadId, pub vm: Arc, pub loader: Arc>, 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: 1. **Method Detection:** When a method has `ACC_NATIVE` flag, `invoke_native()` is called 2. **Symbol Resolution:** Generates JNI symbol name (e.g., `Java_java_lang_String_intern`) 3. **Lookup:** Searches registered native methods or loaded native libraries via `find_native_method()` 4. **FFI Call:** Uses `libffi` to call the native function with constructed arguments ```rust pub fn invoke_native(&self, method: &MethodRef, args: Vec) -> 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::(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: 1. `JNIEnv*` - pointer to the function table 2. `jclass` or `jobject` (receiver) - always an ID (u32) 3. Parameters - converted from VM `Value` types to JNI types ```rust fn build_args(mut params: VecDeque, storage: &mut Vec>, jnienv: *mut JNIEnv) -> Vec { 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: ```rust 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/SetField`, `GetStaticFieldID` | | Method Invocation | `GetMethodID`, `CallMethod`, `CallStaticMethod` | | String Operations | `NewString`, `GetStringLength`, `GetStringChars` | | Array Operations | `NewArray`, `GetArrayLength`, `Get/SetArrayRegion` | | Registration | `RegisterNatives`, `UnregisterNatives` | | Monitors | `MonitorEnter`, `MonitorExit` |