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, Debug)] 25 pub struct GlobalRef { 26 inner: Arc<GlobalRefGuard>, 27 } 28 29 #[derive(Debug)] 30 struct GlobalRefGuard { 31 obj: JObject<'static>, 32 vm: JavaVM, 33 } 34 35 unsafe impl Send for GlobalRef {} 36 unsafe impl Sync for GlobalRef {} 37 38 impl<'a> From<&'a GlobalRef> for JObject<'a> { from(other: &'a GlobalRef) -> JObject<'a>39 fn from(other: &'a GlobalRef) -> JObject<'a> { 40 other.as_obj() 41 } 42 } 43 44 impl GlobalRef { 45 /// Creates a new wrapper for a global reference. 46 /// 47 /// # Safety 48 /// 49 /// Expects a valid raw global reference that should be created with `NewGlobalRef` JNI function. from_raw(vm: JavaVM, raw_global_ref: sys::jobject) -> Self50 pub(crate) unsafe fn from_raw(vm: JavaVM, raw_global_ref: sys::jobject) -> Self { 51 GlobalRef { 52 inner: Arc::new(GlobalRefGuard::from_raw(vm, raw_global_ref)), 53 } 54 } 55 56 /// Get the object from the global ref 57 /// 58 /// This borrows the ref and prevents it from being dropped as long as the 59 /// JObject sticks around. as_obj(&self) -> JObject60 pub fn as_obj(&self) -> JObject { 61 self.inner.as_obj() 62 } 63 } 64 65 impl GlobalRefGuard { 66 /// Creates a new global reference guard. This assumes that `NewGlobalRef` 67 /// has already been called. from_raw(vm: JavaVM, obj: sys::jobject) -> Self68 unsafe fn from_raw(vm: JavaVM, obj: sys::jobject) -> Self { 69 GlobalRefGuard { 70 obj: JObject::from_raw(obj), 71 vm, 72 } 73 } 74 75 /// Get the object from the global ref 76 /// 77 /// This borrows the ref and prevents it from being dropped as long as the 78 /// JObject sticks around. as_obj(&self) -> JObject79 pub fn as_obj(&self) -> JObject { 80 self.obj 81 } 82 } 83 84 impl Drop for GlobalRefGuard { drop(&mut self)85 fn drop(&mut self) { 86 fn drop_impl(env: &JNIEnv, global_ref: JObject) -> Result<()> { 87 let internal = env.get_native_interface(); 88 // This method is safe to call in case of pending exceptions (see chapter 2 of the spec) 89 jni_unchecked!(internal, DeleteGlobalRef, global_ref.into_raw()); 90 Ok(()) 91 } 92 93 let res = match self.vm.get_env() { 94 Ok(env) => drop_impl(&env, self.as_obj()), 95 Err(_) => { 96 warn!("Dropping a GlobalRef in a detached thread. Fix your code if this message appears frequently (see the GlobalRef docs)."); 97 self.vm 98 .attach_current_thread() 99 .and_then(|env| drop_impl(&env, self.as_obj())) 100 } 101 }; 102 103 if let Err(err) = res { 104 debug!("error dropping global ref: {:#?}", err); 105 } 106 } 107 } 108