• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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