5#ifndef WPIUTIL_WPI_JNI_UTIL_H_
6#define WPIUTIL_WPI_JNI_UTIL_H_
21#include "wpi/SmallVector.h"
22#include "wpi/StringExtras.h"
25#include "wpi/raw_ostream.h"
44 std::string_view excludeFuncPrefix = {});
56 JClass(JNIEnv* env,
const char* name) {
57 jclass local = env->FindClass(name);
61 m_cls =
static_cast<jclass
>(env->NewGlobalRef(local));
62 env->DeleteLocalRef(local);
67 env->DeleteGlobalRef(
m_cls);
72 explicit operator bool()
const {
return m_cls; }
74 operator jclass()
const {
return m_cls; }
91 m_cls =
static_cast<T
>(env->NewGlobalRef(obj));
96 env->DeleteGlobalRef(
m_cls);
101 explicit operator bool()
const {
return m_cls; }
103 operator T()
const {
return m_cls; }
131 m_env->DeleteLocalRef(m_obj);
134 operator T() {
return m_obj; }
156 jsize size = env->GetStringLength(
str);
157 const jchar* chars = env->GetStringCritical(
str,
nullptr);
160 env->ReleaseStringCritical(
str, chars);
163 wpi::print(stderr,
"JStringRef was passed a null pointer at\n",
167 m_str.push_back(
'\0');
171 operator std::string_view()
const {
return m_str.
str(); }
172 std::string_view
str()
const {
return m_str.
str(); }
173 const char*
c_str()
const {
return m_str.data(); }
174 size_t size()
const {
return m_str.size(); }
186#define WPI_JNI_ARRAYHELPER(T, F) \
188 struct ArrayHelper<T> { \
189 using jarray_type = T##Array; \
190 static T* GetArrayElements(JNIEnv* env, jarray_type jarr) { \
191 return env->Get##F##ArrayElements(jarr, nullptr); \
193 static void ReleaseArrayElements(JNIEnv* env, jarray_type jarr, T* elems, \
195 env->Release##F##ArrayElements(jarr, elems, mode); \
207#undef WPI_JNI_ARRAYHELPER
211 requires {
typename ArrayHelper<std::remove_cv_t<T>>::jarray_type; };
213template <
typename CvSrc,
typename Dest>
216 using U0 = std::remove_cv_t<Dest>;
217 using U1 = std::conditional_t<std::is_const_v<CvSrc>,
const U0, U0>;
218 using U2 = std::conditional_t<std::is_volatile_v<CvSrc>,
volatile U1, U1>;
224template <
typename CvSrc,
typename Dest>
227template <
typename From,
typename To>
229 !(std::is_const_v<From> && !std::is_const_v<To>) &&
230 !(std::is_volatile_v<From> && !std::is_volatile_v<To>);
247template <JArrayType T,
bool IsCritical,
size_t Size = std::dynamic_extent>
250 using jarray_type =
typename ArrHelper::jarray_type;
257 : m_valid{other.m_valid},
259 m_jarr{other.m_jarr},
260 m_size{other.m_size},
261 m_elements{other.m_elements} {
262 other.m_jarr =
nullptr;
263 other.m_elements =
nullptr;
267 m_valid = other.m_valid;
269 m_jarr = other.m_jarr;
270 m_size = other.m_size;
271 m_elements = other.m_elements;
272 other.m_valid =
false;
273 other.m_jarr =
nullptr;
274 other.m_elements =
nullptr;
279 requires(!IsCritical)
280 : m_valid{Size ==
std::dynamic_extent || size == Size},
284 m_elements{static_cast<
std::remove_cv_t<T>*>(
285 bb ? env->GetDirectBufferAddress(bb) : nullptr)} {
287 wpi::print(stderr,
"JSpan was passed a null pointer at\n",
293 : m_valid{Size ==
std::dynamic_extent || size == Size},
297 m_elements{nullptr} {
299 if constexpr (IsCritical) {
300 m_elements =
static_cast<std::remove_cv_t<T>*
>(
301 env->GetPrimitiveArrayCritical(jarr,
nullptr));
303 m_elements = ArrHelper::GetArrayElements(env, jarr);
306 wpi::print(stderr,
"JSpan was passed a null pointer at\n",
312 :
JSpanBase(env, jarr, jarr ? env->GetArrayLength(jarr) : 0) {}
315 if (m_jarr && m_elements) {
316 constexpr jint mode = std::is_const_v<T> ? JNI_ABORT : 0;
317 if constexpr (IsCritical) {
318 m_env->ReleasePrimitiveArrayCritical(m_jarr, m_elements, mode);
320 ArrHelper::ReleaseArrayElements(m_env, m_jarr, m_elements, mode);
326 operator std::span<T, Size>()
const {
return array(); }
332 if constexpr (Size == std::dynamic_extent) {
337 return std::span<T, Size>{m_elements, m_size};
340 T*
begin()
const {
return m_elements; }
342 T*
end()
const {
return m_elements + m_size; }
344 bool is_valid()
const {
return m_valid && m_elements !=
nullptr; }
346 explicit operator bool()
const {
return is_valid(); }
348 T*
data()
const {
return m_elements; }
350 size_t size()
const {
return m_size; }
352 const T&
operator[](
size_t i)
const {
return m_elements[i]; }
355 requires(!std::is_const_v<T>)
357 return m_elements[i];
362 operator std::string_view() const
363 requires
std::is_same_v<
std::remove_cv_t<T>, jbyte>
368 std::string_view
str() const
369 requires
std::is_same_v<
std::remove_cv_t<T>, jbyte>
375 return {
reinterpret_cast<const char*
>(arr.data()), arr.size()};
378 std::span<copy_cv_t<T, uint8_t>, Size>
uarray() const
379 requires
std::is_same_v<
std::remove_cv_t<T>, jbyte>
385 return {
reinterpret_cast<const uint8_t*
>(arr.data()), arr.size()};
390 template <
typename U>
391 requires(
sizeof(U) ==
sizeof(jlong) && std::integral<U> &&
393 operator std::span<U, Size>()
const
394 requires std::is_same_v<std::remove_cv_t<T>, jlong>
400 return {
reinterpret_cast<U*
>(arr.data()), arr.size()};
408 jarray_type m_jarr =
nullptr;
410 std::remove_cv_t<T>* m_elements;
416template <
typename T,
size_t Extent = std::dynamic_extent>
419template <
typename T,
size_t Extent = std::dynamic_extent>
433 SmallVector<UTF16, 128> chars;
435 return env->NewString(chars.begin(), chars.size());
443 static jintArray
ToJava(JNIEnv* env, std::span<const T> arr) {
444 if constexpr (
sizeof(T) ==
sizeof(jint) && std::integral<T>) {
446 jintArray jarr = env->NewIntArray(arr.size());
450 env->SetIntArrayRegion(jarr, 0, arr.size(),
451 reinterpret_cast<const jint*
>(arr.data()));
458 jintArray jarr = env->NewIntArray(arr.size());
463 static_cast<jint*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
467 for (
size_t i = 0; i < arr.size(); ++i) {
468 elements[i] =
static_cast<jint
>(arr[i]);
470 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
496inline jintArray
MakeJIntArray(JNIEnv* env, std::span<T> arr) {
535 jbyteArray jarr = env->NewByteArray(str.size());
539 env->SetByteArrayRegion(jarr, 0, str.size(),
540 reinterpret_cast<const jbyte*
>(str.data()));
551 jbooleanArray jarr = env->NewBooleanArray(arr.size());
556 static_cast<jboolean*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
560 for (
size_t i = 0; i < arr.size(); ++i) {
561 elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
563 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
574 jbooleanArray jarr = env->NewBooleanArray(arr.size());
579 static_cast<jboolean*
>(env->GetPrimitiveArrayCritical(jarr,
nullptr));
583 for (
size_t i = 0; i < arr.size(); ++i) {
584 elements[i] = arr[i] ? JNI_TRUE : JNI_FALSE;
586 env->ReleasePrimitiveArrayCritical(jarr, elements, 0);
592#define WPI_JNI_MAKEJARRAY(T, F) \
593 inline T##Array MakeJ##F##Array(JNIEnv* env, std::span<const T> arr) { \
594 T##Array jarr = env->New##F##Array(arr.size()); \
598 env->Set##F##ArrayRegion(jarr, 0, arr.size(), arr.data()); \
608#undef WPI_JNI_MAKEJARRAY
611 requires(
sizeof(
typename T::value_type) ==
sizeof(jlong) &&
612 std::integral<typename T::value_type>)
614 jlongArray jarr = env->NewLongArray(arr.size());
618 env->SetLongArrayRegion(jarr, 0, arr.size(),
619 reinterpret_cast<const jlong*
>(arr.data()));
630 std::span<const std::string> arr) {
631 static JClass stringCls{env,
"java/lang/String"};
635 jobjectArray jarr = env->NewObjectArray(arr.size(), stringCls,
nullptr);
639 for (
size_t i = 0; i < arr.size(); ++i) {
641 env->SetObjectArrayElement(jarr, i, elem.obj());
653 std::span<std::string_view> arr) {
654 static JClass stringCls{env,
"java/lang/String"};
658 jobjectArray jarr = env->NewObjectArray(arr.size(), stringCls,
nullptr);
662 for (
size_t i = 0; i < arr.size(); ++i) {
664 env->SetObjectArrayElement(jarr, i, elem.obj());
689 void Main()
override;
700 void SetFunc(JNIEnv* env, jobject func, jmethodID mid);
702 template <
typename... Args>
703 void Send(Args&&... args);
708 auto thr = this->GetThread();
714 env->DeleteGlobalRef(thr->m_func);
717 thr->m_func = env->NewGlobalRef(func);
722template <
typename... Args>
724 auto thr = this->GetThread();
728 thr->m_queue.emplace(std::forward<Args>(args)...);
729 thr->m_cond.notify_one();
735 JavaVMAttachArgs args;
736 args.version = JNI_VERSION_1_2;
737 args.name =
const_cast<char*
>(T::GetName());
738 args.group =
nullptr;
739 jint rs = T::GetJVM()->AttachCurrentThreadAsDaemon(
740 reinterpret_cast<void**
>(&env), &args);
745 std::unique_lock lock(m_mutex);
747 m_cond.wait(lock, [&] {
return !(m_active && m_queue.empty()); });
751 while (!m_queue.empty()) {
755 auto item = std::move(m_queue.front());
760 item.CallJava(env, func, mid);
761 if (env->ExceptionCheck()) {
762 env->ExceptionDescribe();
763 env->ExceptionClear();
769 JavaVM* jvm = T::GetJVM();
771 jvm->DetachCurrentThread();
786 static JClass throwableCls(env,
"java/lang/Throwable");
790 static jmethodID constructorId =
nullptr;
791 if (!constructorId) {
792 constructorId = env->GetMethodID(throwableCls,
"<init>",
"()V");
794 JLocal<jobject> throwable(env, env->NewObject(throwableCls, constructorId));
799 static jmethodID getStackTraceId =
nullptr;
800 if (!getStackTraceId) {
801 getStackTraceId = env->GetMethodID(throwableCls,
"getStackTrace",
802 "()[Ljava/lang/StackTraceElement;");
807 env,
static_cast<jobjectArray
>(
808 env->CallObjectMethod(throwable, getStackTraceId)));
815 jsize stackTraceLength = env->GetArrayLength(stackTrace);
818 static JClass stackTraceElementCls(env,
"java/lang/StackTraceElement");
819 if (!stackTraceElementCls) {
822 static jmethodID toStringId =
nullptr;
824 toStringId = env->GetMethodID(stackTraceElementCls,
"toString",
825 "()Ljava/lang/String;");
828 bool foundFirst =
false;
830 raw_string_ostream oss(buf);
831 for (jsize i = 0; i < stackTraceLength; i++) {
834 env, env->GetObjectArrayElement(stackTrace, i));
838 env,
static_cast<jstring
>(
839 env->CallObjectMethod(curStackTraceElement, toStringId)));
841 if (!stackElementString) {
848 if (wpi::starts_with(elem, skipPrefix)) {
853 oss <<
"\tat " << elem <<
'\n';
860 std::string_view excludeFuncPrefix) {
862 static JClass throwableCls(env,
"java/lang/Throwable");
866 static jmethodID constructorId =
nullptr;
867 if (!constructorId) {
868 constructorId = env->GetMethodID(throwableCls,
"<init>",
"()V");
870 JLocal<jobject> throwable(env, env->NewObject(throwableCls, constructorId));
875 static jmethodID getStackTraceId =
nullptr;
876 if (!getStackTraceId) {
877 getStackTraceId = env->GetMethodID(throwableCls,
"getStackTrace",
878 "()[Ljava/lang/StackTraceElement;");
883 env,
static_cast<jobjectArray
>(
884 env->CallObjectMethod(throwable, getStackTraceId)));
891 jsize stackTraceLength = env->GetArrayLength(stackTrace);
894 static JClass stackTraceElementCls(env,
"java/lang/StackTraceElement");
895 if (!stackTraceElementCls) {
898 static jmethodID toStringId =
nullptr;
900 toStringId = env->GetMethodID(stackTraceElementCls,
"toString",
901 "()Ljava/lang/String;");
904 bool haveLoc =
false;
906 raw_string_ostream oss(buf);
907 for (jsize i = 0; i < stackTraceLength; i++) {
910 env, env->GetObjectArrayElement(stackTrace, i));
914 env,
static_cast<jstring
>(
915 env->CallObjectMethod(curStackTraceElement, toStringId)));
917 if (!stackElementString) {
930 }
else if (i > 1 && !haveLoc && !excludeFuncPrefix.empty() &&
931 !wpi::starts_with(elem, excludeFuncPrefix)) {
954 env->GetMethodID(
m_cls,
"<init>",
"(Ljava/lang/String;)V");
958 void Throw(JNIEnv* env, jstring msg) {
960 env->Throw(
static_cast<jthrowable
>(
exception));
963 void Throw(JNIEnv* env, std::string_view msg) {
967 explicit operator bool()
const {
return m_constructor; }
970 jmethodID m_constructor =
nullptr;
This file defines the SmallString class.
you may not use this file except in compliance with the License You may obtain a copy of the License at software distributed under the License is distributed on an AS IS WITHOUT WARRANTIES OR CONDITIONS OF ANY either express or implied See the License for the specific language governing permissions and limitations under the License LLVM Exceptions to the Apache License As an exception
Definition ThirdPartyNotices.txt:301
Definition SafeThread.h:33
Definition SafeThread.h:124
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:27
std::string_view str() const
Explicit conversion to std::string_view.
Definition SmallString.h:186
void SetJoinAtExit(bool joinAtExit)
Definition SafeThread.h:106
Definition jni_util.h:697
JCallbackManager()
Definition jni_util.h:699
void SetFunc(JNIEnv *env, jobject func, jmethodID mid)
Definition jni_util.h:707
void Send(Args &&... args)
Definition jni_util.h:723
Generic callback thread implementation.
Definition jni_util.h:687
jmethodID m_mid
Definition jni_util.h:693
jobject m_func
Definition jni_util.h:692
std::queue< T > m_queue
Definition jni_util.h:691
void Main() override
Definition jni_util.h:733
Finds a class and keeps it as a global reference.
Definition jni_util.h:52
JClass(JNIEnv *env, const char *name)
Definition jni_util.h:56
jclass m_cls
Definition jni_util.h:77
void free(JNIEnv *env)
Definition jni_util.h:65
Finds an exception class and keep it as a global reference.
Definition jni_util.h:948
void Throw(JNIEnv *env, std::string_view msg)
Definition jni_util.h:963
JException(JNIEnv *env, const char *name)
Definition jni_util.h:951
void Throw(JNIEnv *env, jstring msg)
Definition jni_util.h:958
JGlobal(JNIEnv *env, T obj)
Definition jni_util.h:90
void free(JNIEnv *env)
Definition jni_util.h:94
T m_cls
Definition jni_util.h:106
Container class for cleaning up Java local references.
Definition jni_util.h:115
JLocal & operator=(const JLocal &)=delete
~JLocal()
Definition jni_util.h:129
JLocal(JLocal &&oth)
Definition jni_util.h:119
JLocal & operator=(JLocal &&oth)
Definition jni_util.h:123
T obj()
Definition jni_util.h:135
JLocal(JNIEnv *env, T obj)
Definition jni_util.h:117
JLocal(const JLocal &)=delete
Definition jni_util.h:776
static JSingletonCallbackManager< T > & GetInstance()
Definition jni_util.h:778
Java string (jstring) reference.
Definition jni_util.h:152
std::string_view str() const
Definition jni_util.h:172
WPI_String wpi_str() const
Definition jni_util.h:175
const char * c_str() const
Definition jni_util.h:173
size_t size() const
Definition jni_util.h:174
JStringRef(JNIEnv *env, jstring str)
Definition jni_util.h:154
Helper class for working with JNI arrays.
Definition jni_util.h:248
JSpanBase(const JSpanBase &)=delete
T & operator[](size_t i)
Definition jni_util.h:354
JSpanBase(JNIEnv *env, jarray_type jarr)
Definition jni_util.h:311
bool is_valid() const
Definition jni_util.h:344
T * end() const
Definition jni_util.h:342
JSpanBase & operator=(JSpanBase &&other)
Definition jni_util.h:266
JSpanBase(JNIEnv *env, jarray_type jarr, size_t size)
Definition jni_util.h:292
std::span< copy_cv_t< T, uint8_t >, Size > uarray() const
Definition jni_util.h:378
T * begin() const
Definition jni_util.h:340
const T & operator[](size_t i) const
Definition jni_util.h:352
size_t size() const
Definition jni_util.h:350
T * data() const
Definition jni_util.h:348
JSpanBase(JNIEnv *env, jobject bb, size_t size)
Definition jni_util.h:278
std::string_view str() const
Definition jni_util.h:368
JSpanBase(JSpanBase &&other)
Definition jni_util.h:256
std::span< T, Size > array() const
Definition jni_util.h:328
JSpanBase & operator=(const JSpanBase &)=delete
~JSpanBase()
Definition jni_util.h:314
Definition jni_util.h:210
#define WPI_JNI_MAKEJARRAY(T, F)
Definition jni_util.h:592
#define WPI_JNI_ARRAYHELPER(T, F)
Definition jni_util.h:186
Converts a string literal into a format string that will be parsed at compile time and converted into...
Definition printf.h:50
Definition PointerIntPair.h:280
constexpr bool is_qualification_convertible_v
Definition jni_util.h:228
typename copy_cv< CvSrc, Dest >::type copy_cv_t
Definition jni_util.h:225
Java Native Interface (JNI) utility functions.
Definition jni_util.h:29
jlongArray MakeJLongArray(JNIEnv *env, const T &arr)
Definition jni_util.h:613
jintArray MakeJIntArray(JNIEnv *env, std::span< const T > arr)
Convert a span to a jintArray.
Definition jni_util.h:485
jstring MakeJString(JNIEnv *env, std::string_view str)
Convert a UTF8 string into a jstring.
Definition jni_util.h:432
std::string GetJavaStackTrace(JNIEnv *env, std::string *func=nullptr, std::string_view excludeFuncPrefix={})
Gets a Java stack trace.
Definition jni_util.h:859
jbooleanArray MakeJBooleanArray(JNIEnv *env, std::span< const int > arr)
Convert an array of integers into a jbooleanArray.
Definition jni_util.h:550
jobjectArray MakeJStringArray(JNIEnv *env, std::span< const std::string > arr)
Convert an array of std::string into a jarray of jstring.
Definition jni_util.h:629
jbyteArray MakeJByteArray(JNIEnv *env, std::span< const uint8_t > str)
Convert a span into a jbyteArray.
Definition jni_util.h:534
bool convertUTF8ToUTF16String(std::string_view SrcUTF8, SmallVectorImpl< UTF16 > &DstUTF16)
Converts a UTF-8 string into a UTF-16 string with native endianness.
void print(wpi::raw_ostream &os, const S &format_str, Args &&... args)
Prints formatted data to the stream os.
Definition raw_ostream.h:25
constexpr WPI_String make_string(std::string_view view)
Converts a string_view to a WPI_String.
Definition string.h:34
bool Boolean
Definition ConvertUTF.h:130
bool convertUTF16ToUTF8String(std::span< const char > SrcBytes, SmallVectorImpl< char > &Out)
Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
A const UTF8 string.
Definition string.h:15
const char * name
Definition jni_util.h:81
JClass * cls
Definition jni_util.h:82
Definition jni_util.h:973
JException * cls
Definition jni_util.h:975
const char * name
Definition jni_util.h:974
Definition jni_util.h:184
Definition jni_util.h:442
static jintArray ToJava(JNIEnv *env, std::span< const T > arr)
Definition jni_util.h:443
Definition jni_util.h:214
U2 type
Definition jni_util.h:221