8 #ifndef WPIUTIL_SUPPORT_JNI_UTIL_H_ 9 #define WPIUTIL_SUPPORT_JNI_UTIL_H_ 13 #include <type_traits> 19 #include "llvm/ArrayRef.h" 20 #include "llvm/ConvertUTF.h" 21 #include "llvm/raw_ostream.h" 22 #include "llvm/SmallString.h" 23 #include "llvm/SmallVector.h" 24 #include "llvm/StringRef.h" 25 #include "support/atomic_static.h" 26 #include "support/deprecated.h" 27 #include "support/SafeThread.h" 35 std::string GetJavaStackTrace(
36 JNIEnv* env, std::string* func =
nullptr,
40 template<const
char* excludeFuncPrefix>
41 WPI_DEPRECATED(
"use StringRef function instead")
42 std::
string GetJavaStackTrace(JNIEnv* env,
std::
string* func) {
43 return GetJavaStackTrace(env, func, excludeFuncPrefix ==
nullptr 55 JClass(JNIEnv* env,
const char* name) {
56 jclass local = env->FindClass(name);
58 m_cls =
static_cast<jclass
>(env->NewGlobalRef(local));
59 env->DeleteLocalRef(local);
62 void free(JNIEnv *env) {
63 if (m_cls) env->DeleteGlobalRef(m_cls);
67 explicit operator bool()
const {
return m_cls; }
69 operator jclass()
const {
return m_cls; }
72 jclass m_cls =
nullptr;
80 JLocal(JNIEnv *env, T obj) : m_env(env), m_obj(obj) {}
82 JLocal(
JLocal&& oth) : m_env(oth.m_env), m_obj(oth.m_obj) {
93 if (m_obj) m_env->DeleteLocalRef(m_obj);
95 operator T() {
return m_obj; }
96 T obj() {
return m_obj; }
114 jsize size = env->GetStringLength(str);
115 const jchar *chars = env->GetStringCritical(str,
nullptr);
117 llvm::convertUTF16ToUTF8String(llvm::makeArrayRef(chars, size), m_str);
118 env->ReleaseStringCritical(str, chars);
121 llvm::errs() <<
"JStringRef was passed a null pointer at \n" 122 << GetJavaStackTrace(env);
125 m_str.push_back(
'\0');
131 const char* c_str()
const {
return m_str.
data(); }
132 size_t size()
const {
return m_str.size(); }
141 template <
typename C,
typename T>
145 template <
typename C>
151 auto arr =
static_cast<const C *
>(
this)->array();
159 template <
typename T>
162 explicit operator bool()
const {
return this->m_elements !=
nullptr; }
178 m_elements(oth.m_elements) {
179 oth.m_jarr =
nullptr;
180 oth.m_elements =
nullptr;
184 this->m_env = oth.m_env;
185 this->m_jarr = oth.m_jarr;
186 this->m_size = oth.m_size;
187 this->m_elements = oth.m_elements;
188 oth.m_jarr =
nullptr;
189 oth.m_elements =
nullptr;
195 this->m_jarr =
nullptr;
197 this->m_elements = elements;
203 this->m_size = jarr ? env->GetArrayLength(jarr) : 0;
204 this->m_elements =
nullptr;
208 jarray m_jarr =
nullptr;
217 #define WPI_JNI_JARRAYREF(T, F) \ 218 class J##F##ArrayRef : public detail::JArrayRefBase<T> { \ 220 J##F##ArrayRef(JNIEnv* env, jobject bb, int len) \ 221 : detail::JArrayRefBase<T>( \ 223 static_cast<T*>(bb ? env->GetDirectBufferAddress(bb) : nullptr), \ 226 llvm::errs() << "JArrayRef was passed a null pointer at \n" \ 227 << GetJavaStackTrace(env); \ 229 J##F##ArrayRef(JNIEnv* env, T##Array jarr) \ 230 : detail::JArrayRefBase<T>(env, jarr) { \ 232 m_elements = env->Get##F##ArrayElements(jarr, nullptr); \ 234 llvm::errs() << "JArrayRef was passed a null pointer at \n" \ 235 << GetJavaStackTrace(env); \ 237 ~J##F##ArrayRef() { \ 238 if (m_jarr && m_elements) \ 239 m_env->Release##F##ArrayElements(static_cast<T##Array>(m_jarr), \ 240 m_elements, JNI_ABORT); \ 244 class CriticalJ##F##ArrayRef : public detail::JArrayRefBase<T> { \ 246 CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr) \ 247 : detail::JArrayRefBase<T>(env, jarr) { \ 250 static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr)); \ 252 llvm::errs() << "JArrayRef was passed a null pointer at \n" \ 253 << GetJavaStackTrace(env); \ 255 ~CriticalJ##F##ArrayRef() { \ 256 if (m_jarr && m_elements) \ 257 m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, JNI_ABORT); \ 261 WPI_JNI_JARRAYREF(jboolean, Boolean)
262 WPI_JNI_JARRAYREF(jbyte, Byte)
263 WPI_JNI_JARRAYREF(jshort, Short)
264 WPI_JNI_JARRAYREF(jint, Int)
265 WPI_JNI_JARRAYREF(jlong, Long)
266 WPI_JNI_JARRAYREF(jfloat, Float)
267 WPI_JNI_JARRAYREF(jdouble, Double)
269 #undef WPI_JNI_JARRAYREF 278 llvm::convertUTF8ToUTF16String(str, chars);
279 return env->NewString(chars.begin(), chars.size());
288 template <
typename T,
289 bool = (std::is_integral<T>::value &&
sizeof(jint) ==
sizeof(T))>
292 jintArray jarr = env->NewIntArray(arr.
size());
293 if (!jarr)
return nullptr;
295 static_cast<jint *
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
296 if (!elements)
return nullptr;
297 for (
size_t i = 0; i < arr.
size(); ++i)
298 elements[i] = static_cast<jint>(arr[i]);
299 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
305 template <
typename T>
308 jintArray jarr = env->NewIntArray(arr.
size());
309 if (!jarr)
return nullptr;
310 env->SetIntArrayRegion(jarr, 0, arr.
size(),
311 reinterpret_cast<const jint*
>(arr.data()));
319 template <
typename T>
326 template <
typename T>
327 inline jintArray MakeJIntArray(JNIEnv *env,
334 template <
typename T>
335 inline jintArray MakeJIntArray(JNIEnv *env,
const std::vector<T> &arr) {
341 jbyteArray jarr = env->NewByteArray(str.
size());
342 if (!jarr)
return nullptr;
343 env->SetByteArrayRegion(jarr, 0, str.
size(),
344 reinterpret_cast<const jbyte *
>(str.
data()));
351 jbooleanArray jarr = env->NewBooleanArray(arr.
size());
352 if (!jarr)
return nullptr;
354 static_cast<jboolean*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
355 if (!elements)
return nullptr;
356 for (
size_t i = 0; i < arr.
size(); ++i)
357 elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
358 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
365 jbooleanArray jarr = env->NewBooleanArray(arr.
size());
366 if (!jarr)
return nullptr;
368 static_cast<jboolean*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
369 if (!elements)
return nullptr;
370 for (
size_t i = 0; i < arr.
size(); ++i)
371 elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
372 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
378 #define WPI_JNI_MAKEJARRAY(T, F) \ 379 inline T##Array MakeJ##F##Array(JNIEnv *env, llvm::ArrayRef<T> arr) { \ 380 T##Array jarr = env->New##F##Array(arr.size()); \ 381 if (!jarr) return nullptr; \ 382 env->Set##F##ArrayRegion(jarr, 0, arr.size(), arr.data()); \ 386 WPI_JNI_MAKEJARRAY(jboolean, Boolean)
387 WPI_JNI_MAKEJARRAY(jbyte, Byte)
388 WPI_JNI_MAKEJARRAY(jshort, Short)
389 WPI_JNI_MAKEJARRAY(jlong, Long)
390 WPI_JNI_MAKEJARRAY(jfloat, Float)
391 WPI_JNI_MAKEJARRAY(jdouble, Double)
393 #undef WPI_JNI_MAKEJARRAY 396 inline jobjectArray MakeJStringArray(JNIEnv *env,
398 static JClass stringCls{env,
"java/lang/String"};
399 if (!stringCls)
return nullptr;
400 jobjectArray jarr = env->NewObjectArray(arr.
size(), stringCls,
nullptr);
401 if (!jarr)
return nullptr;
402 for (std::size_t i = 0; i < arr.
size(); ++i) {
404 env->SetObjectArrayElement(jarr, i, elem.obj());
427 template <
typename T>
432 std::queue<T> m_queue;
433 jobject m_func =
nullptr;
437 template <
typename T>
440 void SetFunc(JNIEnv* env, jobject func, jmethodID mid);
442 template <
typename... Args>
443 void Send(Args&&... args);
446 template <
typename T>
448 auto thr = this->GetThread();
451 if (thr->m_func) env->DeleteGlobalRef(thr->m_func);
453 thr->m_func = env->NewGlobalRef(func);
457 template <
typename T>
458 template <
typename... Args>
460 auto thr = this->GetThread();
462 thr->m_queue.emplace(std::forward<Args>(args)...);
463 thr->m_cond.notify_one();
466 template <
typename T>
469 JavaVMAttachArgs args;
470 args.version = JNI_VERSION_1_2;
471 args.name =
const_cast<char*
>(T::GetName());
472 args.group =
nullptr;
473 jint rs = T::GetJVM()->AttachCurrentThreadAsDaemon((
void**)&env, &args);
474 if (rs != JNI_OK)
return;
476 std::unique_lock<std::mutex> lock(m_mutex);
478 m_cond.wait(lock, [&] {
return !(m_active && m_queue.empty()); });
479 if (!m_active)
break;
480 while (!m_queue.empty()) {
481 if (!m_active)
break;
482 auto item = std::move(m_queue.front());
487 item.CallJava(env, func, mid);
488 if (env->ExceptionCheck()) {
489 env->ExceptionDescribe();
490 env->ExceptionClear();
496 JavaVM* jvm = T::GetJVM();
497 if (jvm) jvm->DetachCurrentThread();
500 template <
typename T>
512 inline std::string GetJavaStackTrace(JNIEnv* env, std::string* func,
515 static JClass throwableCls(env,
"java/lang/Throwable");
516 if (!throwableCls)
return "";
517 static jmethodID constructorId =
nullptr;
519 constructorId = env->GetMethodID(throwableCls,
"<init>",
"()V");
520 JLocal<jobject> throwable(env, env->NewObject(throwableCls, constructorId));
525 static jmethodID getStackTraceId =
nullptr;
526 if (!getStackTraceId)
527 getStackTraceId = env->GetMethodID(throwableCls,
"getStackTrace",
528 "()[Ljava/lang/StackTraceElement;");
532 env, static_cast<jobjectArray>(
533 env->CallObjectMethod(throwable, getStackTraceId)));
535 if (!stackTrace)
return "";
538 jsize stackTraceLength = env->GetArrayLength(stackTrace);
541 static JClass stackTraceElementCls(env,
"java/lang/StackTraceElement");
542 if (!stackTraceElementCls)
return "";
543 static jmethodID toStringId =
nullptr;
545 toStringId = env->GetMethodID(stackTraceElementCls,
"toString",
546 "()Ljava/lang/String;");
548 bool haveLoc =
false;
551 for (jsize i = 0; i < stackTraceLength; i++) {
554 env, env->GetObjectArrayElement(stackTrace, i));
558 env, static_cast<jstring>(
559 env->CallObjectMethod(curStackTraceElement, toStringId)));
561 if (!stackElementString)
return "";
572 else if (i > 1 && !haveLoc && !excludeFuncPrefix.
empty() &&
573 !elem.str().startswith(excludeFuncPrefix)) {
593 env->GetMethodID(m_cls,
"<init>",
"(Ljava/lang/String;)V");
596 void Throw(JNIEnv* env, jstring msg) {
597 jobject exception = env->NewObject(m_cls, m_constructor, msg);
598 env->Throw(static_cast<jthrowable>(exception));
602 Throw(env, MakeJString(env, msg));
605 explicit operator bool()
const {
return m_constructor; }
608 jmethodID m_constructor =
nullptr;
614 #endif // WPIUTIL_SUPPORT_JNI_UTIL_H_ size_t size() const
size - Get the string size.
Definition: StringRef.h:149
Definition: SafeThread.h:19
Definition: jni_util.h:160
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:214
Definition: jni_util.h:142
Definition: jni_util.h:51
Definition: json.cpp:1170
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: StringExtras.h:22
Definition: jni_util.h:306
Definition: SafeThread.h:119
Definition: SocketError.cpp:18
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:139
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: ArrayRef.h:32
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:136
Definition: jni_util.h:428
std::string & str()
Flushes the stream contents to the target string and returns the string's reference.
Definition: raw_ostream.h:451
Definition: jni_util.h:290
Definition: jni_util.h:501
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:834
Definition: jni_util.h:110
Definition: jni_util.h:78
Definition: jni_util.h:438
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:435
Definition: jni_util.h:587
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:42
bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:146