8 #ifndef WPIUTIL_WPI_JNI_UTIL_H_ 9 #define WPIUTIL_WPI_JNI_UTIL_H_ 15 #include <type_traits> 19 #include "wpi/ArrayRef.h" 20 #include "wpi/ConvertUTF.h" 21 #include "wpi/SafeThread.h" 22 #include "wpi/SmallString.h" 23 #include "wpi/SmallVector.h" 24 #include "wpi/StringRef.h" 25 #include "wpi/deprecated.h" 26 #include "wpi/mutex.h" 27 #include "wpi/raw_ostream.h" 35 std::string GetJavaStackTrace(JNIEnv* env, std::string* func =
nullptr,
36 StringRef excludeFuncPrefix = StringRef());
39 template <const
char* excludeFuncPrefix>
40 WPI_DEPRECATED(
"use StringRef function instead")
41 std::
string GetJavaStackTrace(JNIEnv* env,
std::
string* func) {
42 return GetJavaStackTrace(
44 excludeFuncPrefix ==
nullptr ? StringRef() : excludeFuncPrefix);
54 JClass(JNIEnv* env,
const char* name) {
55 jclass local = env->FindClass(name);
57 m_cls =
static_cast<jclass
>(env->NewGlobalRef(local));
58 env->DeleteLocalRef(local);
61 void free(JNIEnv* env) {
62 if (m_cls) env->DeleteGlobalRef(m_cls);
66 explicit operator bool()
const {
return m_cls; }
68 operator jclass()
const {
return m_cls; }
71 jclass m_cls =
nullptr;
85 m_cls =
static_cast<T
>(env->NewGlobalRef(obj));
88 void free(JNIEnv* env) {
89 if (m_cls) env->DeleteGlobalRef(m_cls);
93 explicit operator bool()
const {
return m_cls; }
95 operator T()
const {
return m_cls; }
103 template <
typename T>
106 JLocal(JNIEnv* env, T obj) : m_env(env), m_obj(obj) {}
108 JLocal(
JLocal&& oth) : m_env(oth.m_env), m_obj(oth.m_obj) {
119 if (m_obj) m_env->DeleteLocalRef(m_obj);
121 operator T() {
return m_obj; }
122 T obj() {
return m_obj; }
140 jsize
size = env->GetStringLength(str);
141 const jchar* chars = env->GetStringCritical(str,
nullptr);
144 env->ReleaseStringCritical(str, chars);
147 errs() <<
"JStringRef was passed a null pointer at \n" 148 << GetJavaStackTrace(env);
151 m_str.push_back(
'\0');
155 operator StringRef()
const {
return m_str; }
157 const char* c_str()
const {
return m_str.data(); }
158 size_t size()
const {
return m_str.size(); }
167 template <
typename C,
typename T>
171 template <
typename C>
174 operator StringRef()
const {
return str(); }
177 auto arr =
static_cast<const C*
>(
this)->array();
179 return StringRef{
reinterpret_cast<const char*
>(arr.data()), arr.
size()};
184 template <
typename T>
187 explicit operator bool()
const {
return this->m_elements !=
nullptr; }
193 return ArrayRef<T>{this->m_elements, this->m_size};
203 m_elements(oth.m_elements) {
204 oth.m_jarr =
nullptr;
205 oth.m_elements =
nullptr;
209 this->m_env = oth.m_env;
210 this->m_jarr = oth.m_jarr;
211 this->m_size = oth.m_size;
212 this->m_elements = oth.m_elements;
213 oth.m_jarr =
nullptr;
214 oth.m_elements =
nullptr;
221 this->m_jarr =
nullptr;
223 this->m_elements = elements;
229 this->m_size = jarr ? env->GetArrayLength(jarr) : 0;
230 this->m_elements =
nullptr;
234 jarray m_jarr =
nullptr;
243 #define WPI_JNI_JARRAYREF(T, F) \ 244 class J##F##ArrayRef : public detail::JArrayRefBase<T> { \ 246 J##F##ArrayRef(JNIEnv* env, jobject bb, int len) \ 247 : detail::JArrayRefBase<T>( \ 249 static_cast<T*>(bb ? env->GetDirectBufferAddress(bb) : nullptr), \ 252 errs() << "JArrayRef was passed a null pointer at \n" \ 253 << GetJavaStackTrace(env); \ 255 J##F##ArrayRef(JNIEnv* env, T##Array jarr) \ 256 : detail::JArrayRefBase<T>(env, jarr) { \ 258 m_elements = env->Get##F##ArrayElements(jarr, nullptr); \ 260 errs() << "JArrayRef was passed a null pointer at \n" \ 261 << GetJavaStackTrace(env); \ 263 ~J##F##ArrayRef() { \ 264 if (m_jarr && m_elements) \ 265 m_env->Release##F##ArrayElements(static_cast<T##Array>(m_jarr), \ 266 m_elements, JNI_ABORT); \ 270 class CriticalJ##F##ArrayRef : public detail::JArrayRefBase<T> { \ 272 CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr) \ 273 : detail::JArrayRefBase<T>(env, jarr) { \ 276 static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr)); \ 278 errs() << "JArrayRef was passed a null pointer at \n" \ 279 << GetJavaStackTrace(env); \ 281 ~CriticalJ##F##ArrayRef() { \ 282 if (m_jarr && m_elements) \ 283 m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, JNI_ABORT); \ 287 WPI_JNI_JARRAYREF(jboolean, Boolean)
288 WPI_JNI_JARRAYREF(jbyte, Byte)
289 WPI_JNI_JARRAYREF(jshort, Short)
290 WPI_JNI_JARRAYREF(jint, Int)
291 WPI_JNI_JARRAYREF(jlong, Long)
292 WPI_JNI_JARRAYREF(jfloat, Float)
293 WPI_JNI_JARRAYREF(jdouble, Double)
295 #undef WPI_JNI_JARRAYREF 302 inline jstring MakeJString(JNIEnv* env,
StringRef str) {
305 return env->NewString(chars.begin(), chars.size());
314 template <
typename T,
315 bool = (std::is_integral<T>::value &&
sizeof(jint) ==
sizeof(T))>
317 static jintArray ToJava(JNIEnv* env,
ArrayRef<T> arr) {
318 jintArray jarr = env->NewIntArray(arr.
size());
319 if (!jarr)
return nullptr;
321 static_cast<jint*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
322 if (!elements)
return nullptr;
323 for (
size_t i = 0; i < arr.
size(); ++i)
324 elements[i] = static_cast<jint>(arr[i]);
325 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
331 template <
typename T>
333 static jintArray ToJava(JNIEnv* env,
ArrayRef<T> arr) {
334 jintArray jarr = env->NewIntArray(arr.
size());
335 if (!jarr)
return nullptr;
336 env->SetIntArrayRegion(jarr, 0, arr.
size(),
337 reinterpret_cast<const jint*
>(arr.data()));
345 template <
typename T>
346 inline jintArray MakeJIntArray(JNIEnv* env,
ArrayRef<T> arr) {
352 template <
typename T>
359 template <
typename T>
360 inline jintArray MakeJIntArray(JNIEnv* env,
const std::vector<T>& arr) {
365 inline jbyteArray MakeJByteArray(JNIEnv* env,
StringRef str) {
366 jbyteArray jarr = env->NewByteArray(str.
size());
367 if (!jarr)
return nullptr;
368 env->SetByteArrayRegion(jarr, 0, str.
size(),
369 reinterpret_cast<const jbyte*
>(str.
data()));
374 inline jbooleanArray MakeJBooleanArray(JNIEnv* env,
ArrayRef<int> arr) {
375 jbooleanArray jarr = env->NewBooleanArray(arr.
size());
376 if (!jarr)
return nullptr;
378 static_cast<jboolean*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
379 if (!elements)
return nullptr;
380 for (
size_t i = 0; i < arr.
size(); ++i)
381 elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
382 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
387 inline jbooleanArray MakeJBooleanArray(JNIEnv* env,
ArrayRef<bool> arr) {
388 jbooleanArray jarr = env->NewBooleanArray(arr.
size());
389 if (!jarr)
return nullptr;
391 static_cast<jboolean*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
392 if (!elements)
return nullptr;
393 for (
size_t i = 0; i < arr.
size(); ++i)
394 elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
395 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
401 #define WPI_JNI_MAKEJARRAY(T, F) \ 402 inline T##Array MakeJ##F##Array(JNIEnv* env, ArrayRef<T> arr) { \ 403 T##Array jarr = env->New##F##Array(arr.size()); \ 404 if (!jarr) return nullptr; \ 405 env->Set##F##ArrayRegion(jarr, 0, arr.size(), arr.data()); \ 409 WPI_JNI_MAKEJARRAY(jboolean, Boolean)
410 WPI_JNI_MAKEJARRAY(jbyte, Byte)
411 WPI_JNI_MAKEJARRAY(jshort, Short)
412 WPI_JNI_MAKEJARRAY(jlong, Long)
413 WPI_JNI_MAKEJARRAY(jfloat, Float)
414 WPI_JNI_MAKEJARRAY(jdouble, Double)
416 #undef WPI_JNI_MAKEJARRAY 420 static JClass stringCls{env,
"java/lang/String"};
421 if (!stringCls)
return nullptr;
422 jobjectArray jarr = env->NewObjectArray(arr.
size(), stringCls,
nullptr);
423 if (!jarr)
return nullptr;
424 for (
size_t i = 0; i < arr.
size(); ++i) {
426 env->SetObjectArrayElement(jarr, i, elem.obj());
446 template <
typename T>
451 std::queue<T> m_queue;
452 jobject m_func =
nullptr;
456 template <
typename T>
459 void SetFunc(JNIEnv* env, jobject func, jmethodID mid);
461 template <
typename... Args>
462 void Send(Args&&... args);
465 template <
typename T>
467 auto thr = this->GetThread();
470 if (thr->m_func) env->DeleteGlobalRef(thr->m_func);
472 thr->m_func = env->NewGlobalRef(func);
476 template <
typename T>
477 template <
typename... Args>
479 auto thr = this->GetThread();
481 thr->m_queue.emplace(std::forward<Args>(args)...);
482 thr->m_cond.notify_one();
485 template <
typename T>
488 JavaVMAttachArgs args;
489 args.version = JNI_VERSION_1_2;
490 args.name =
const_cast<char*
>(T::GetName());
491 args.group =
nullptr;
492 jint rs = T::GetJVM()->AttachCurrentThreadAsDaemon(
493 reinterpret_cast<void**>(&env), &args);
494 if (rs != JNI_OK)
return;
496 std::unique_lock<wpi::mutex> lock(m_mutex);
498 m_cond.wait(lock, [&] {
return !(m_active && m_queue.empty()); });
499 if (!m_active)
break;
500 while (!m_queue.empty()) {
501 if (!m_active)
break;
502 auto item = std::move(m_queue.front());
507 item.CallJava(env, func, mid);
508 if (env->ExceptionCheck()) {
509 env->ExceptionDescribe();
510 env->ExceptionClear();
516 JavaVM* jvm = T::GetJVM();
517 if (jvm) jvm->DetachCurrentThread();
520 template <
typename T>
529 inline std::string GetJavaStackTrace(JNIEnv* env, std::string* func,
532 static JClass throwableCls(env,
"java/lang/Throwable");
533 if (!throwableCls)
return "";
534 static jmethodID constructorId =
nullptr;
536 constructorId = env->GetMethodID(throwableCls,
"<init>",
"()V");
537 JLocal<jobject> throwable(env, env->NewObject(throwableCls, constructorId));
542 static jmethodID getStackTraceId =
nullptr;
543 if (!getStackTraceId)
544 getStackTraceId = env->GetMethodID(throwableCls,
"getStackTrace",
545 "()[Ljava/lang/StackTraceElement;");
549 env, static_cast<jobjectArray>(
550 env->CallObjectMethod(throwable, getStackTraceId)));
552 if (!stackTrace)
return "";
555 jsize stackTraceLength = env->GetArrayLength(stackTrace);
558 static JClass stackTraceElementCls(env,
"java/lang/StackTraceElement");
559 if (!stackTraceElementCls)
return "";
560 static jmethodID toStringId =
nullptr;
562 toStringId = env->GetMethodID(stackTraceElementCls,
"toString",
563 "()Ljava/lang/String;");
565 bool haveLoc =
false;
568 for (jsize i = 0; i < stackTraceLength; i++) {
571 env, env->GetObjectArrayElement(stackTrace, i));
575 env, static_cast<jstring>(
576 env->CallObjectMethod(curStackTraceElement, toStringId)));
578 if (!stackElementString)
return "";
589 }
else if (i > 1 && !haveLoc && !excludeFuncPrefix.
empty() &&
590 !elem.str().startswith(excludeFuncPrefix)) {
610 env->GetMethodID(m_cls,
"<init>",
"(Ljava/lang/String;)V");
613 void Throw(JNIEnv* env, jstring msg) {
614 jobject exception = env->NewObject(m_cls, m_constructor, msg);
615 env->Throw(static_cast<jthrowable>(exception));
618 void Throw(JNIEnv* env,
StringRef msg) { Throw(env, MakeJString(env, msg)); }
620 explicit operator bool()
const {
return m_constructor; }
623 jmethodID m_constructor =
nullptr;
634 #endif // WPIUTIL_WPI_JNI_UTIL_H_ Definition: SafeThread.h:20
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:868
Definition: jni_util.h:185
Definition: jni_util.h:626
Definition: jni_util.h:168
Definition: jni_util.h:50
Definition: SmallVector.h:946
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: ArrayRef.h:41
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE const char * data() const noexcept
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:128
Definition: jni_util.h:332
Definition: SafeThread.h:120
namespace to hold default to_json function
Definition: json_binary_writer.cpp:39
Definition: jni_util.h:80
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:482
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
Definition: raw_ostream.cpp:685
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:451
Definition: jni_util.h:447
bool convertUTF8ToUTF16String(StringRef SrcUTF8, SmallVectorImpl< UTF16 > &DstUTF16)
Converts a UTF-8 string into a UTF-16 string with native endianness.
Definition: ConvertUTFWrapper.cpp:83
Definition: jni_util.h:316
Definition: jni_util.h:521
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool empty() const noexcept
empty - Check if the string is empty.
Definition: StringRef.h:133
bool convertUTF16ToUTF8String(ArrayRef< UTF16 > SrcUTF16, SmallVectorImpl< char > &DstUTF8)
Converts a UTF-16 string into a UTF-8 string.
Definition: ConvertUTFWrapper.cpp:37
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: WindowsSupport.h:184
auto size(R &&Range, typename std::enable_if< std::is_same< typename std::iterator_traits< decltype(Range.begin())>::iterator_category, std::random_access_iterator_tag >::value, void >::type *=nullptr) -> decltype(std::distance(Range.begin(), Range.end()))
Get the size of a range.
Definition: STLExtras.h:999
Definition: jni_util.h:136
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
Definition: jni_util.h:74
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE size_t size() const noexcept
size - Get the string size.
Definition: StringRef.h:138
Definition: jni_util.h:104
std::string & str()
Flushes the stream contents to the target string and returns the string's reference.
Definition: raw_ostream.h:498
Definition: jni_util.h:457
Definition: jni_util.h:604
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:149
LLVM_NODISCARD std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:206