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