1 // A JNI call that is expected to return a non-null pointer when successful. 2 // If a null pointer is returned, it is converted to an Err. 3 // Returns Err if there is a pending exception after the call. 4 macro_rules! jni_non_null_call { 5 ( $jnienv:expr, $name:tt $(, $args:expr )* ) => ({ 6 let res = jni_non_void_call!($jnienv, $name $(, $args)*); 7 non_null!(res, concat!(stringify!($name), " result")) 8 }) 9 } 10 11 // A non-void JNI call. May return anything — primitives, references, error codes. 12 // Returns Err if there is a pending exception after the call. 13 macro_rules! jni_non_void_call { 14 ( $jnienv:expr, $name:tt $(, $args:expr )* ) => ({ 15 log::trace!("calling checked jni method: {}", stringify!($name)); 16 17 #[allow(unused_unsafe)] 18 let res = unsafe { 19 jni_method!($jnienv, $name)($jnienv, $($args),*) 20 }; 21 22 check_exception!($jnienv); 23 res 24 }) 25 } 26 27 macro_rules! non_null { 28 ( $obj:expr, $ctx:expr ) => { 29 if $obj.is_null() { 30 return Err($crate::errors::Error::NullPtr($ctx)); 31 } else { 32 $obj 33 } 34 }; 35 } 36 37 // A void JNI call. 38 // Returns Err if there is a pending exception after the call. 39 macro_rules! jni_void_call { 40 ( $jnienv:expr, $name:tt $(, $args:expr )* ) => ({ 41 log::trace!("calling checked jni method: {}", stringify!($name)); 42 43 #[allow(unused_unsafe)] 44 unsafe { 45 jni_method!($jnienv, $name)($jnienv, $($args),*) 46 }; 47 48 check_exception!($jnienv); 49 }) 50 } 51 52 // A JNI call that does not check for exceptions or verify 53 // error codes (if any). 54 macro_rules! jni_unchecked { 55 ( $jnienv:expr, $name:tt $(, $args:expr )* ) => ({ 56 log::trace!("calling unchecked jni method: {}", stringify!($name)); 57 58 #[allow(unused_unsafe)] 59 unsafe { 60 jni_method!($jnienv, $name)($jnienv, $($args),*) 61 } 62 }) 63 } 64 65 macro_rules! jni_method { 66 ( $jnienv:expr, $name:tt ) => {{ 67 log::trace!("looking up jni method {}", stringify!($name)); 68 let env = $jnienv; 69 match deref!(deref!(env, "JNIEnv"), "*JNIEnv").$name { 70 Some(method) => { 71 log::trace!("found jni method"); 72 method 73 } 74 None => { 75 log::trace!("jnienv method not defined, returning error"); 76 return Err($crate::errors::Error::JNIEnvMethodNotFound(stringify!( 77 $name 78 ))); 79 } 80 } 81 }}; 82 } 83 84 macro_rules! check_exception { 85 ( $jnienv:expr ) => { 86 log::trace!("checking for exception"); 87 let check = { jni_unchecked!($jnienv, ExceptionCheck) } == $crate::sys::JNI_TRUE; 88 if check { 89 log::trace!("exception found, returning error"); 90 return Err($crate::errors::Error::JavaException); 91 } 92 log::trace!("no exception found"); 93 }; 94 } 95 96 macro_rules! catch { 97 ( move $b:block ) => { 98 (move || $b)() 99 }; 100 ( $b:block ) => { 101 (|| $b)() 102 }; 103 } 104 105 macro_rules! java_vm_unchecked { 106 ( $java_vm:expr, $name:tt $(, $args:expr )* ) => ({ 107 log::trace!("calling unchecked JavaVM method: {}", stringify!($name)); 108 java_vm_method!($java_vm, $name)($java_vm, $($args),*) 109 }) 110 } 111 112 macro_rules! java_vm_method { 113 ( $jnienv:expr, $name:tt ) => {{ 114 log::trace!("looking up JavaVM method {}", stringify!($name)); 115 let env = $jnienv; 116 match deref!(deref!(env, "JavaVM"), "*JavaVM").$name { 117 Some(meth) => { 118 log::trace!("found JavaVM method"); 119 meth 120 } 121 None => { 122 log::trace!("JavaVM method not defined, returning error"); 123 return Err($crate::errors::Error::JavaVMMethodNotFound(stringify!( 124 $name 125 ))); 126 } 127 } 128 }}; 129 } 130 131 macro_rules! deref { 132 ( $obj:expr, $ctx:expr ) => { 133 if $obj.is_null() { 134 return Err($crate::errors::Error::NullDeref($ctx)); 135 } else { 136 #[allow(unused_unsafe)] 137 unsafe { 138 *$obj 139 } 140 } 141 }; 142 } 143