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;
230 this->m_elements =
nullptr;
234 :
JArrayRefBase(env, jarr, jarr ? env->GetArrayLength(jarr) : 0) {}
237 jarray m_jarr =
nullptr;
246 #define WPI_JNI_JARRAYREF(T, F) \
247 class J##F##ArrayRef : public detail::JArrayRefBase<T> { \
249 J##F##ArrayRef(JNIEnv* env, jobject bb, int len) \
250 : detail::JArrayRefBase<T>( \
252 static_cast<T*>(bb ? env->GetDirectBufferAddress(bb) : nullptr), \
255 errs() << "JArrayRef was passed a null pointer at \n" \
256 << GetJavaStackTrace(env); \
258 J##F##ArrayRef(JNIEnv* env, T##Array jarr, int len) \
259 : detail::JArrayRefBase<T>(env, jarr, len) { \
261 m_elements = env->Get##F##ArrayElements(jarr, nullptr); \
263 errs() << "JArrayRef was passed a null pointer at \n" \
264 << GetJavaStackTrace(env); \
266 J##F##ArrayRef(JNIEnv* env, T##Array jarr) \
267 : detail::JArrayRefBase<T>(env, jarr) { \
269 m_elements = env->Get##F##ArrayElements(jarr, nullptr); \
271 errs() << "JArrayRef was passed a null pointer at \n" \
272 << GetJavaStackTrace(env); \
274 ~J##F##ArrayRef() { \
275 if (m_jarr && m_elements) \
276 m_env->Release##F##ArrayElements(static_cast<T##Array>(m_jarr), \
277 m_elements, JNI_ABORT); \
281 class CriticalJ##F##ArrayRef : public detail::JArrayRefBase<T> { \
283 CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr, int len) \
284 : detail::JArrayRefBase<T>(env, jarr, len) { \
287 static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr)); \
289 errs() << "JArrayRef was passed a null pointer at \n" \
290 << GetJavaStackTrace(env); \
292 CriticalJ##F##ArrayRef(JNIEnv* env, T##Array jarr) \
293 : detail::JArrayRefBase<T>(env, jarr) { \
296 static_cast<T*>(env->GetPrimitiveArrayCritical(jarr, nullptr)); \
298 errs() << "JArrayRef was passed a null pointer at \n" \
299 << GetJavaStackTrace(env); \
301 ~CriticalJ##F##ArrayRef() { \
302 if (m_jarr && m_elements) \
303 m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, JNI_ABORT); \
307 WPI_JNI_JARRAYREF(jboolean, Boolean)
308 WPI_JNI_JARRAYREF(jbyte, Byte)
309 WPI_JNI_JARRAYREF(jshort, Short)
310 WPI_JNI_JARRAYREF(jint, Int)
311 WPI_JNI_JARRAYREF(jlong, Long)
312 WPI_JNI_JARRAYREF(jfloat, Float)
313 WPI_JNI_JARRAYREF(jdouble, Double)
315 #undef WPI_JNI_JARRAYREF
322 inline jstring MakeJString(JNIEnv* env,
StringRef str) {
325 return env->NewString(chars.begin(), chars.size());
334 template <
typename T,
335 bool = (std::is_integral<T>::value &&
sizeof(jint) ==
sizeof(T))>
337 static jintArray ToJava(JNIEnv* env,
ArrayRef<T> arr) {
338 jintArray jarr = env->NewIntArray(arr.
size());
339 if (!jarr)
return nullptr;
341 static_cast<jint*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
342 if (!elements)
return nullptr;
343 for (
size_t i = 0; i < arr.
size(); ++i)
344 elements[i] = static_cast<jint>(arr[i]);
345 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
351 template <
typename T>
353 static jintArray ToJava(JNIEnv* env,
ArrayRef<T> arr) {
354 jintArray jarr = env->NewIntArray(arr.
size());
355 if (!jarr)
return nullptr;
356 env->SetIntArrayRegion(jarr, 0, arr.
size(),
357 reinterpret_cast<const jint*
>(arr.data()));
365 template <
typename T>
366 inline jintArray MakeJIntArray(JNIEnv* env,
ArrayRef<T> arr) {
372 template <
typename T>
374 return detail::ConvertIntArray<T>::ToJava(env, arr);
379 template <
typename T>
380 inline jintArray MakeJIntArray(JNIEnv* env,
const std::vector<T>& arr) {
381 return detail::ConvertIntArray<T>::ToJava(env, arr);
385 inline jbyteArray MakeJByteArray(JNIEnv* env, StringRef str) {
386 jbyteArray jarr = env->NewByteArray(str.size());
387 if (!jarr)
return nullptr;
388 env->SetByteArrayRegion(jarr, 0, str.size(),
389 reinterpret_cast<const jbyte*
>(str.data()));
394 inline jbooleanArray MakeJBooleanArray(JNIEnv* env, ArrayRef<int> arr) {
395 jbooleanArray jarr = env->NewBooleanArray(arr.size());
396 if (!jarr)
return nullptr;
398 static_cast<jboolean*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
399 if (!elements)
return nullptr;
400 for (
size_t i = 0; i < arr.size(); ++i)
401 elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
402 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
407 inline jbooleanArray MakeJBooleanArray(JNIEnv* env, ArrayRef<bool> arr) {
408 jbooleanArray jarr = env->NewBooleanArray(arr.size());
409 if (!jarr)
return nullptr;
411 static_cast<jboolean*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
412 if (!elements)
return nullptr;
413 for (
size_t i = 0; i < arr.size(); ++i)
414 elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
415 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
421 #define WPI_JNI_MAKEJARRAY(T, F) \
422 inline T##Array MakeJ##F##Array(JNIEnv* env, ArrayRef<T> arr) { \
423 T##Array jarr = env->New##F##Array(arr.size()); \
424 if (!jarr) return nullptr; \
425 env->Set##F##ArrayRegion(jarr, 0, arr.size(), arr.data()); \
429 WPI_JNI_MAKEJARRAY(jboolean, Boolean)
430 WPI_JNI_MAKEJARRAY(jbyte, Byte)
431 WPI_JNI_MAKEJARRAY(jshort, Short)
432 WPI_JNI_MAKEJARRAY(jlong, Long)
433 WPI_JNI_MAKEJARRAY(jfloat, Float)
434 WPI_JNI_MAKEJARRAY(jdouble, Double)
436 #undef WPI_JNI_MAKEJARRAY
439 inline jobjectArray MakeJStringArray(JNIEnv* env, ArrayRef<std::string> arr) {
440 static JClass stringCls{env,
"java/lang/String"};
441 if (!stringCls)
return nullptr;
442 jobjectArray jarr = env->NewObjectArray(arr.size(), stringCls,
nullptr);
443 if (!jarr)
return nullptr;
444 for (
size_t i = 0; i < arr.size(); ++i) {
445 JLocal<jstring> elem{env, MakeJString(env, arr[i])};
446 env->SetObjectArrayElement(jarr, i, elem.obj());
466 template <
typename T>
471 std::queue<T> m_queue;
472 jobject m_func =
nullptr;
476 template <
typename T>
479 void SetFunc(JNIEnv* env, jobject func, jmethodID mid);
481 template <
typename... Args>
482 void Send(Args&&... args);
485 template <
typename T>
487 auto thr = this->GetThread();
490 if (thr->m_func) env->DeleteGlobalRef(thr->m_func);
492 thr->m_func = env->NewGlobalRef(func);
496 template <
typename T>
497 template <
typename... Args>
498 void JCallbackManager<T>::Send(Args&&... args) {
499 auto thr = this->GetThread();
501 thr->m_queue.emplace(std::forward<Args>(args)...);
502 thr->m_cond.notify_one();
505 template <
typename T>
506 void JCallbackThread<T>::Main() {
508 JavaVMAttachArgs args;
509 args.version = JNI_VERSION_1_2;
510 args.name =
const_cast<char*
>(T::GetName());
511 args.group =
nullptr;
512 jint rs = T::GetJVM()->AttachCurrentThreadAsDaemon(
513 reinterpret_cast<void**>(&env), &args);
514 if (rs != JNI_OK)
return;
516 std::unique_lock<wpi::mutex> lock(m_mutex);
518 m_cond.wait(lock, [&] {
return !(m_active && m_queue.empty()); });
519 if (!m_active)
break;
520 while (!m_queue.empty()) {
521 if (!m_active)
break;
522 auto item = std::move(m_queue.front());
527 item.CallJava(env, func, mid);
528 if (env->ExceptionCheck()) {
529 env->ExceptionDescribe();
530 env->ExceptionClear();
536 JavaVM* jvm = T::GetJVM();
537 if (jvm) jvm->DetachCurrentThread();
540 template <
typename T>
549 inline std::string GetJavaStackTrace(JNIEnv* env, std::string* func,
552 static JClass throwableCls(env,
"java/lang/Throwable");
553 if (!throwableCls)
return "";
554 static jmethodID constructorId =
nullptr;
556 constructorId = env->GetMethodID(throwableCls,
"<init>",
"()V");
557 JLocal<jobject> throwable(env, env->NewObject(throwableCls, constructorId));
562 static jmethodID getStackTraceId =
nullptr;
563 if (!getStackTraceId)
564 getStackTraceId = env->GetMethodID(throwableCls,
"getStackTrace",
565 "()[Ljava/lang/StackTraceElement;");
569 env, static_cast<jobjectArray>(
570 env->CallObjectMethod(throwable, getStackTraceId)));
572 if (!stackTrace)
return "";
575 jsize stackTraceLength = env->GetArrayLength(stackTrace);
578 static JClass stackTraceElementCls(env,
"java/lang/StackTraceElement");
579 if (!stackTraceElementCls)
return "";
580 static jmethodID toStringId =
nullptr;
582 toStringId = env->GetMethodID(stackTraceElementCls,
"toString",
583 "()Ljava/lang/String;");
585 bool haveLoc =
false;
588 for (jsize i = 0; i < stackTraceLength; i++) {
591 env, env->GetObjectArrayElement(stackTrace, i));
595 env, static_cast<jstring>(
596 env->CallObjectMethod(curStackTraceElement, toStringId)));
598 if (!stackElementString)
return "";
609 }
else if (i > 1 && !haveLoc && !excludeFuncPrefix.
empty() &&
610 !elem.str().startswith(excludeFuncPrefix)) {
630 env->GetMethodID(m_cls,
"<init>",
"(Ljava/lang/String;)V");
633 void Throw(JNIEnv* env, jstring msg) {
634 jobject exception = env->NewObject(m_cls, m_constructor, msg);
635 env->Throw(static_cast<jthrowable>(exception));
638 void Throw(JNIEnv* env,
StringRef msg) { Throw(env, MakeJString(env, msg)); }
640 explicit operator bool()
const {
return m_constructor; }
643 jmethodID m_constructor =
nullptr;
654 #endif // WPIUTIL_WPI_JNI_UTIL_H_
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: hostname.h:17
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:646
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
Definition: jni_util.h:352
Definition: SafeThread.h:120
namespace to hold default to_json function
Definition: SmallString.h:21
Definition: jni_util.h:80
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:482
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:451
Definition: jni_util.h:467
bool convertUTF8ToUTF16String(StringRef SrcUTF8, SmallVectorImpl< UTF16 > &DstUTF16)
Converts a UTF-8 string into a UTF-16 string with native endianness.
Definition: jni_util.h:336
Definition: jni_util.h:541
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.
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
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
Definition: jni_util.h:477
pointer data()
Return a pointer to the vector's buffer, even if empty().
Definition: SmallVector.h:151
Definition: jni_util.h:624
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:149