8 #ifndef WPIUTIL_SUPPORT_JNI_UTIL_H_ 9 #define WPIUTIL_SUPPORT_JNI_UTIL_H_ 15 #include <type_traits> 19 #include "llvm/ArrayRef.h" 20 #include "llvm/ConvertUTF.h" 21 #include "llvm/SmallString.h" 22 #include "llvm/SmallVector.h" 23 #include "llvm/StringRef.h" 24 #include "llvm/raw_ostream.h" 25 #include "support/SafeThread.h" 26 #include "support/atomic_static.h" 27 #include "support/deprecated.h" 28 #include "support/mutex.h" 36 std::string GetJavaStackTrace(
37 JNIEnv* env, std::string* func =
nullptr,
41 template <const
char* excludeFuncPrefix>
42 WPI_DEPRECATED(
"use StringRef function instead")
43 std::
string GetJavaStackTrace(JNIEnv* env,
std::
string* func) {
44 return GetJavaStackTrace(
56 JClass(JNIEnv* env,
const char* name) {
57 jclass local = env->FindClass(name);
59 m_cls =
static_cast<jclass
>(env->NewGlobalRef(local));
60 env->DeleteLocalRef(local);
63 void free(JNIEnv* env) {
64 if (m_cls) env->DeleteGlobalRef(m_cls);
68 explicit operator bool()
const {
return m_cls; }
70 operator jclass()
const {
return m_cls; }
73 jclass m_cls =
nullptr;
81 JLocal(JNIEnv* env, T obj) : m_env(env), m_obj(obj) {}
83 JLocal(
JLocal&& oth) : m_env(oth.m_env), m_obj(oth.m_obj) {
94 if (m_obj) m_env->DeleteLocalRef(m_obj);
96 operator T() {
return m_obj; }
97 T obj() {
return m_obj; }
115 jsize size = env->GetStringLength(str);
116 const jchar* chars = env->GetStringCritical(str,
nullptr);
118 llvm::convertUTF16ToUTF8String(llvm::makeArrayRef(chars, size), m_str);
119 env->ReleaseStringCritical(str, chars);
122 llvm::errs() <<
"JStringRef was passed a null pointer at \n" 123 << GetJavaStackTrace(env);
126 m_str.push_back(
'\0');
132 const char* c_str()
const {
return m_str.data(); }
133 size_t size()
const {
return m_str.size(); }
142 template <
typename C,
typename T>
146 template <
typename C>
152 auto arr =
static_cast<const C*
>(
this)->array();
160 template <
typename T>
163 explicit operator bool()
const {
return this->m_elements !=
nullptr; }
179 m_elements(oth.m_elements) {
180 oth.m_jarr =
nullptr;
181 oth.m_elements =
nullptr;
185 this->m_env = oth.m_env;
186 this->m_jarr = oth.m_jarr;
187 this->m_size = oth.m_size;
188 this->m_elements = oth.m_elements;
189 oth.m_jarr =
nullptr;
190 oth.m_elements =
nullptr;
197 this->m_jarr =
nullptr;
199 this->m_elements = elements;
205 this->m_size = jarr ? env->GetArrayLength(jarr) : 0;
206 this->m_elements =
nullptr;
210 jarray m_jarr =
nullptr;
219 #define WPI_JNI_JARRAYREF(T, F) \ 220 class J##F##ArrayRef : public detail::JArrayRefBase<T> { \ 222 J##F##ArrayRef(JNIEnv* env, jobject bb, int len) \ 223 : detail::JArrayRefBase<T>( \ 225 static_cast<T*>(bb ? env->GetDirectBufferAddress(bb) : nullptr), \ 228 llvm::errs() << "JArrayRef was passed a null pointer at \n" \ 229 << GetJavaStackTrace(env); \ 231 J##F##ArrayRef(JNIEnv* env, T##Array jarr) \ 232 : detail::JArrayRefBase<T>(env, jarr) { \ 234 m_elements = env->Get##F##ArrayElements(jarr, nullptr); \ 236 llvm::errs() << "JArrayRef was passed a null pointer at \n" \ 237 << GetJavaStackTrace(env); \ 239 ~J##F##ArrayRef() { \ 240 if (m_jarr && m_elements) \ 241 m_env->Release##F##ArrayElements(static_cast<T##Array>(m_jarr), \ 242 m_elements, JNI_ABORT); \ 246 class CriticalJ##F##ArrayRef : public detail::JArrayRefBase<T> { \ 248 CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr) \ 249 : detail::JArrayRefBase<T>(env, jarr) { \ 252 static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr)); \ 254 llvm::errs() << "JArrayRef was passed a null pointer at \n" \ 255 << GetJavaStackTrace(env); \ 257 ~CriticalJ##F##ArrayRef() { \ 258 if (m_jarr && m_elements) \ 259 m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, JNI_ABORT); \ 263 WPI_JNI_JARRAYREF(jboolean, Boolean)
264 WPI_JNI_JARRAYREF(jbyte, Byte)
265 WPI_JNI_JARRAYREF(jshort, Short)
266 WPI_JNI_JARRAYREF(jint, Int)
267 WPI_JNI_JARRAYREF(jlong, Long)
268 WPI_JNI_JARRAYREF(jfloat, Float)
269 WPI_JNI_JARRAYREF(jdouble, Double)
271 #undef WPI_JNI_JARRAYREF 280 llvm::convertUTF8ToUTF16String(str, chars);
281 return env->NewString(chars.begin(), chars.size());
290 template <
typename T,
291 bool = (std::is_integral<T>::value &&
sizeof(jint) ==
sizeof(T))>
294 jintArray jarr = env->NewIntArray(arr.
size());
295 if (!jarr)
return nullptr;
297 static_cast<jint*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
298 if (!elements)
return nullptr;
299 for (
size_t i = 0; i < arr.
size(); ++i)
300 elements[i] = static_cast<jint>(arr[i]);
301 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
307 template <
typename T>
310 jintArray jarr = env->NewIntArray(arr.
size());
311 if (!jarr)
return nullptr;
312 env->SetIntArrayRegion(jarr, 0, arr.
size(),
313 reinterpret_cast<const jint*
>(arr.data()));
321 template <
typename T>
328 template <
typename T>
329 inline jintArray MakeJIntArray(JNIEnv* env,
336 template <
typename T>
337 inline jintArray MakeJIntArray(JNIEnv* env,
const std::vector<T>& arr) {
343 jbyteArray jarr = env->NewByteArray(str.
size());
344 if (!jarr)
return nullptr;
345 env->SetByteArrayRegion(jarr, 0, str.
size(),
346 reinterpret_cast<const jbyte*
>(str.
data()));
352 jbooleanArray jarr = env->NewBooleanArray(arr.
size());
353 if (!jarr)
return nullptr;
355 static_cast<jboolean*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
356 if (!elements)
return nullptr;
357 for (
size_t i = 0; i < arr.
size(); ++i)
358 elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
359 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 (
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(
474 reinterpret_cast<void**>(&env), &args);
475 if (rs != JNI_OK)
return;
477 std::unique_lock<wpi::mutex> lock(m_mutex);
479 m_cond.wait(lock, [&] {
return !(m_active && m_queue.empty()); });
480 if (!m_active)
break;
481 while (!m_queue.empty()) {
482 if (!m_active)
break;
483 auto item = std::move(m_queue.front());
488 item.CallJava(env, func, mid);
489 if (env->ExceptionCheck()) {
490 env->ExceptionDescribe();
491 env->ExceptionClear();
497 JavaVM* jvm = T::GetJVM();
498 if (jvm) jvm->DetachCurrentThread();
501 template <
typename T>
513 inline std::string GetJavaStackTrace(JNIEnv* env, std::string* func,
516 static JClass throwableCls(env,
"java/lang/Throwable");
517 if (!throwableCls)
return "";
518 static jmethodID constructorId =
nullptr;
520 constructorId = env->GetMethodID(throwableCls,
"<init>",
"()V");
521 JLocal<jobject> throwable(env, env->NewObject(throwableCls, constructorId));
526 static jmethodID getStackTraceId =
nullptr;
527 if (!getStackTraceId)
528 getStackTraceId = env->GetMethodID(throwableCls,
"getStackTrace",
529 "()[Ljava/lang/StackTraceElement;");
533 env, static_cast<jobjectArray>(
534 env->CallObjectMethod(throwable, getStackTraceId)));
536 if (!stackTrace)
return "";
539 jsize stackTraceLength = env->GetArrayLength(stackTrace);
542 static JClass stackTraceElementCls(env,
"java/lang/StackTraceElement");
543 if (!stackTraceElementCls)
return "";
544 static jmethodID toStringId =
nullptr;
546 toStringId = env->GetMethodID(stackTraceElementCls,
"toString",
547 "()Ljava/lang/String;");
549 bool haveLoc =
false;
552 for (jsize i = 0; i < stackTraceLength; i++) {
555 env, env->GetObjectArrayElement(stackTrace, i));
559 env, static_cast<jstring>(
560 env->CallObjectMethod(curStackTraceElement, toStringId)));
562 if (!stackElementString)
return "";
573 }
else if (i > 1 && !haveLoc && !excludeFuncPrefix.
empty() &&
574 !elem.str().startswith(excludeFuncPrefix)) {
594 env->GetMethodID(m_cls,
"<init>",
"(Ljava/lang/String;)V");
597 void Throw(JNIEnv* env, jstring msg) {
598 jobject exception = env->NewObject(m_cls, m_constructor, msg);
599 env->Throw(static_cast<jthrowable>(exception));
603 Throw(env, MakeJString(env, msg));
606 explicit operator bool()
const {
return m_constructor; }
609 jmethodID m_constructor =
nullptr;
615 #endif // WPIUTIL_SUPPORT_JNI_UTIL_H_ size_t size() const
size - Get the string size.
Definition: StringRef.h:149
Definition: SafeThread.h:20
Definition: jni_util.h:161
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:214
Definition: jni_util.h:143
Definition: jni_util.h:52
Definition: json.cpp:1170
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: WindowsSupport.h:184
Definition: jni_util.h:308
Definition: SafeThread.h:120
Definition: SocketError.cpp:17
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:292
Definition: jni_util.h:502
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:111
Definition: jni_util.h:79
Definition: jni_util.h:438
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:435
Definition: jni_util.h:588
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