1 use std::{convert::From, sync::Arc}; 2 3 use log::{debug, warn}; 4 5 use crate::{errors::Result, objects::JObject, sys, JNIEnv, JavaVM}; 6 7 /// A global JVM reference. These are "pinned" by the garbage collector and are 8 /// guaranteed to not get collected until released. Thus, this is allowed to 9 /// outlive the `JNIEnv` that it came from and can be used in other threads. 10 /// 11 /// `GlobalRef` can be cloned to use _the same_ global reference in different 12 /// contexts. If you want to create yet another global ref to the same java object 13 /// you may call `JNIEnv#new_global_ref` just like you do when create `GlobalRef` 14 /// from a local reference. 15 /// 16 /// Underlying global reference will be dropped, when the last instance 17 /// of `GlobalRef` leaves its scope. 18 /// 19 /// It is _recommended_ that a native thread that drops the global reference is attached 20 /// to the Java thread (i.e., has an instance of `JNIEnv`). If the native thread is *not* attached, 21 /// the `GlobalRef#drop` will print a warning and implicitly `attach` and `detach` it, which 22 /// significantly affects performance. 23 24 #[derive(Clone)] 25 pub struct GlobalRef { 26 inner: Arc<GlobalRefGuard>, 27 } 28 29 struct GlobalRefGuard { 30 obj: JObject<'static>, 31 vm: JavaVM, 32 } 33 34 unsafe impl Send for GlobalRef {} 35 unsafe impl Sync for GlobalRef {} 36 37 impl<'a> From<&'a GlobalRef> for JObject<'a> { from(other: &'a GlobalRef) -> JObject<'a>38 fn from(other: &'a GlobalRef) -> JObject<'a> { 39 other.as_obj() 40 } 41 } 42 43 impl GlobalRef { 44 /// Creates a new wrapper for a global reference. 45 /// 46 /// # Safety 47 /// 48 /// Expects a valid raw global reference that should be created with `NewGlobalRef` JNI function. from_raw(vm: JavaVM, raw_global_ref: sys::jobject) -> Self49 pub(crate) unsafe fn from_raw(vm: JavaVM, raw_global_ref: sys::jobject) -> Self { 50 GlobalRef { 51 inner: Arc::new(GlobalRefGuard::from_raw(vm, raw_global_ref)), 52 } 53 } 54 55 /// Get the object from the global ref 56 /// 57 /// This borrows the ref and prevents it from being dropped as long as the 58 /// JObject sticks around. as_obj(&self) -> JObject59 pub fn as_obj(&self) -> JObject { 60 self.inner.as_obj() 61 } 62 } 63 64 impl GlobalRefGuard { 65 /// Creates a new global reference guard. This assumes that `NewGlobalRef` 66 /// has already been called. from_raw(vm: JavaVM, obj: sys::jobject) -> Self67 unsafe fn from_raw(vm: JavaVM, obj: sys::jobject) -> Self { 68 GlobalRefGuard { 69 obj: JObject::from(obj), 70 vm, 71 } 72 } 73 74 /// Get the object from the global ref 75 /// 76 /// This borrows the ref and prevents it from being dropped as long as the 77 /// JObject sticks around. as_obj(&self) -> JObject78 pub fn as_obj(&self) -> JObject { 79 self.obj 80 } 81 } 82 83 impl Drop for GlobalRefGuard { drop(&mut self)84 fn drop(&mut self) { 85 fn drop_impl(env: &JNIEnv, global_ref: JObject) -> Result<()> { 86 let internal = env.get_native_interface(); 87 // This method is safe to call in case of pending exceptions (see chapter 2 of the spec) 88 jni_unchecked!(internal, DeleteGlobalRef, global_ref.into_inner()); 89 Ok(()) 90 } 91 92 let res = match self.vm.get_env() { 93 Ok(env) => drop_impl(&env, self.as_obj()), 94 Err(_) => { 95 warn!("Dropping a GlobalRef in a detached thread. Fix your code if this message appears frequently (see the GlobalRef docs)."); 96 self.vm 97 .attach_current_thread() 98 .and_then(|env| drop_impl(&env, self.as_obj())) 99 } 100 }; 101 102 if let Err(err) = res { 103 debug!("error dropping global ref: {:#?}", err); 104 } 105 } 106 } 107