Switches JNI to use new jni_util methods (#404)

* Uses WPIUtil string objects in JNI

* Switches JNI to use new jni_util classes
This commit is contained in:
Thad House
2016-12-23 11:13:17 -08:00
committed by Peter Johnson
parent bf9f0a9e6d
commit cc246bb9ac
5 changed files with 82 additions and 197 deletions

View File

@@ -20,6 +20,10 @@
#include "HAL/Errors.h"
#include "HAL/cpp/Log.h"
#include "edu_wpi_first_wpilibj_hal_HALUtil.h"
#include "llvm/SmallString.h"
#include "support/jni_util.h"
using namespace wpi::java;
// set the logging level
TLogLevel halUtilLogLevel = logWARNING;
@@ -38,94 +42,20 @@ TLogLevel halUtilLogLevel = logWARNING;
#define kRIOStatusResourceNotInitialized -52010
JavaVM *jvm = nullptr;
static jclass throwableCls = nullptr;
static jclass stackTraceElementCls = nullptr;
static jclass runtimeExCls = nullptr;
static jclass illegalArgExCls = nullptr;
static jclass boundaryExCls = nullptr;
static jclass allocationExCls = nullptr;
static jclass halHandleExCls = nullptr;
static jclass canInvalidBufferExCls = nullptr;
static jclass canMessageNotFoundExCls = nullptr;
static jclass canMessageNotAllowedExCls = nullptr;
static jclass canNotInitializedExCls = nullptr;
static jclass uncleanStatusExCls = nullptr;
static jclass pwmConfigDataResultCls = nullptr;
static JException runtimeExCls;
static JException illegalArgExCls;
static JException boundaryExCls;
static JException allocationExCls;
static JException halHandleExCls;
static JException canInvalidBufferExCls;
static JException canMessageNotFoundExCls;
static JException canMessageNotAllowedExCls;
static JException canNotInitializedExCls;
static JException uncleanStatusExCls;
static JClass pwmConfigDataResultCls;
namespace frc {
static void GetStackTrace(JNIEnv *env, std::string &res, std::string &func) {
// create a throwable
static jmethodID constructorId = nullptr;
if (!constructorId)
constructorId = env->GetMethodID(throwableCls, "<init>", "()V");
jobject throwable = env->NewObject(throwableCls, constructorId);
// retrieve information from the exception.
// get method id
// getStackTrace returns an array of StackTraceElement
static jmethodID getStackTraceId = nullptr;
if (!getStackTraceId)
getStackTraceId = env->GetMethodID(throwableCls, "getStackTrace",
"()[Ljava/lang/StackTraceElement;");
// call getStackTrace
jobjectArray stackTrace =
static_cast<jobjectArray>(env->CallObjectMethod(throwable,
getStackTraceId));
if (!stackTrace) return;
// get length of the array
jsize stackTraceLength = env->GetArrayLength(stackTrace);
// get toString methodId of StackTraceElement class
static jmethodID toStringId = nullptr;
if (!toStringId)
toStringId = env->GetMethodID(stackTraceElementCls, "toString",
"()Ljava/lang/String;");
bool haveLoc = false;
for (jsize i = 0; i < stackTraceLength; i++) {
// add the result of toString method of each element in the result
jobject curStackTraceElement = env->GetObjectArrayElement(stackTrace, i);
// call to string on the object
jstring stackElementString =
static_cast<jstring>(env->CallObjectMethod(curStackTraceElement,
toStringId));
if (!stackElementString) {
env->DeleteLocalRef(stackTrace);
env->DeleteLocalRef(curStackTraceElement);
return;
}
// add a line to res
// res += " at ";
const char *tmp = env->GetStringUTFChars(stackElementString, nullptr);
res += tmp;
res += '\n';
// func is caller of immediate caller (if there was one)
// or, if we see it, the first user function
if (i == 1)
func = tmp;
else if (i > 1 && !haveLoc &&
std::strncmp(tmp, "edu.wpi.first.wpilibj", 21) != 0) {
func = tmp;
haveLoc = true;
}
env->ReleaseStringUTFChars(stackElementString, tmp);
env->DeleteLocalRef(curStackTraceElement);
env->DeleteLocalRef(stackElementString);
}
// release java resources
env->DeleteLocalRef(stackTrace);
}
void ThrowAllocationException(JNIEnv *env, int32_t minRange, int32_t maxRange,
int32_t requestedValue, int32_t status) {
const char *message = HAL_GetErrorMessage(status);
@@ -133,7 +63,7 @@ void ThrowAllocationException(JNIEnv *env, int32_t minRange, int32_t maxRange,
sprintf(buf,
" Code: $%d. %s, Minimum Value: %d, Maximum Value: %d, Requested Value: %d",
status, message, minRange, maxRange, requestedValue);
env->ThrowNew(allocationExCls, buf);
allocationExCls.Throw(env, buf);
delete[] buf;
}
@@ -141,10 +71,12 @@ void ThrowHalHandleException(JNIEnv *env, int32_t status) {
const char *message = HAL_GetErrorMessage(status);
char *buf = new char[strlen(message) + 30];
sprintf(buf, " Code: $%d. %s", status, message);
env->ThrowNew(halHandleExCls, buf);
halHandleExCls.Throw(env, buf);
delete[] buf;
}
constexpr const char wpilibjPrefix[] = "edu.wpi.first.wpilibj";
void ReportError(JNIEnv *env, int32_t status, bool do_throw) {
if (status == 0) return;
if (status == HAL_HANDLE_ERROR) {
@@ -154,12 +86,11 @@ void ReportError(JNIEnv *env, int32_t status, bool do_throw) {
if (do_throw && status < 0) {
char *buf = new char[strlen(message) + 30];
sprintf(buf, " Code: %d. %s", status, message);
env->ThrowNew(runtimeExCls, buf);
runtimeExCls.Throw(env, buf);
delete[] buf;
} else {
std::string stack = " at ";
std::string func;
GetStackTrace(env, stack, func);
auto stack = GetJavaStackTrace<wpilibjPrefix>(env, &func);
HAL_SendError(1, status, 0, message, func.c_str(), stack.c_str(), 1);
}
}
@@ -178,7 +109,7 @@ void ThrowError(JNIEnv *env, int32_t status, int32_t minRange, int32_t maxRange,
const char *message = HAL_GetErrorMessage(status);
char *buf = new char[strlen(message) + 30];
sprintf(buf, " Code: %d. %s", status, message);
env->ThrowNew(runtimeExCls, buf);
runtimeExCls.Throw(env, buf);
delete[] buf;
}
@@ -214,7 +145,7 @@ void ReportCANError(JNIEnv *env, int32_t status, int message_id) {
case kRIOStatusFeatureNotSupported: {
char buf[100];
sprintf(buf, "MessageID = %d", message_id);
env->ThrowNew(canMessageNotAllowedExCls, buf);
canMessageNotAllowedExCls.Throw(env, buf);
break;
}
case ERR_CANSessionMux_NotInitialized:
@@ -231,14 +162,14 @@ void ReportCANError(JNIEnv *env, int32_t status, int message_id) {
default: {
char buf[100];
sprintf(buf, "Fatal status code detected: %d", status);
env->ThrowNew(uncleanStatusExCls, buf);
uncleanStatusExCls.Throw(env, buf);
break;
}
}
}
void ThrowIllegalArgumentException(JNIEnv *env, const char *msg) {
env->ThrowNew(illegalArgExCls, msg);
illegalArgExCls.Throw(env, msg);
}
void ThrowBoundaryException(JNIEnv *env, double value, double lower,
@@ -292,89 +223,38 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK)
return JNI_ERR;
// Cache references to classes
jclass local;
local = env->FindClass("java/lang/Throwable");
if (!local) return JNI_ERR;
throwableCls = static_cast<jclass>(env->NewGlobalRef(local));
if (!throwableCls) return JNI_ERR;
env->DeleteLocalRef(local);
local = env->FindClass("java/lang/StackTraceElement");
if (!local) return JNI_ERR;
stackTraceElementCls = static_cast<jclass>(env->NewGlobalRef(local));
if (!stackTraceElementCls) return JNI_ERR;
env->DeleteLocalRef(local);
local = env->FindClass("java/lang/RuntimeException");
if (!local) return JNI_ERR;
runtimeExCls = static_cast<jclass>(env->NewGlobalRef(local));
runtimeExCls = JException(env, "java/lang/RuntimeException");
if (!runtimeExCls) return JNI_ERR;
env->DeleteLocalRef(local);
local = env->FindClass("java/lang/IllegalArgumentException");
if (!local) return JNI_ERR;
illegalArgExCls = static_cast<jclass>(env->NewGlobalRef(local));
illegalArgExCls = JException(env, "java/lang/IllegalArgumentException");
if (!illegalArgExCls) return JNI_ERR;
env->DeleteLocalRef(local);
local = env->FindClass("edu/wpi/first/wpilibj/util/BoundaryException");
if (!local) return JNI_ERR;
boundaryExCls = static_cast<jclass>(env->NewGlobalRef(local));
boundaryExCls = JException(env, "edu/wpi/first/wpilibj/util/BoundaryException");
if (!boundaryExCls) return JNI_ERR;
env->DeleteLocalRef(local);
local = env->FindClass("edu/wpi/first/wpilibj/util/AllocationException");
if (!local) return JNI_ERR;
allocationExCls = static_cast<jclass>(env->NewGlobalRef(local));
allocationExCls = JException(env, "edu/wpi/first/wpilibj/util/AllocationException");
if (!allocationExCls) return JNI_ERR;
env->DeleteLocalRef(local);
local = env->FindClass("edu/wpi/first/wpilibj/util/HalHandleException");
if (!local) return JNI_ERR;
halHandleExCls = static_cast<jclass>(env->NewGlobalRef(local));
halHandleExCls = JException(env, "edu/wpi/first/wpilibj/util/HalHandleException");
if (!halHandleExCls) return JNI_ERR;
env->DeleteLocalRef(local);
local = env->FindClass("edu/wpi/first/wpilibj/can/CANInvalidBufferException");
if (!local) return JNI_ERR;
canInvalidBufferExCls = static_cast<jclass>(env->NewGlobalRef(local));
canInvalidBufferExCls = JException(env, "edu/wpi/first/wpilibj/can/CANInvalidBufferException");
if (!canInvalidBufferExCls) return JNI_ERR;
env->DeleteLocalRef(local);
local =
env->FindClass("edu/wpi/first/wpilibj/can/CANMessageNotFoundException");
if (!local) return JNI_ERR;
canMessageNotFoundExCls = static_cast<jclass>(env->NewGlobalRef(local));
canMessageNotFoundExCls = JException(env, "edu/wpi/first/wpilibj/can/CANMessageNotFoundException");
if (!canMessageNotFoundExCls) return JNI_ERR;
env->DeleteLocalRef(local);
local =
env->FindClass("edu/wpi/first/wpilibj/can/CANMessageNotAllowedException");
if (!local) return JNI_ERR;
canMessageNotAllowedExCls = static_cast<jclass>(env->NewGlobalRef(local));
canMessageNotAllowedExCls = JException(env, "edu/wpi/first/wpilibj/can/CANMessageNotAllowedException");
if (!canMessageNotAllowedExCls) return JNI_ERR;
env->DeleteLocalRef(local);
local =
env->FindClass("edu/wpi/first/wpilibj/can/CANNotInitializedException");
if (!local) return JNI_ERR;
canNotInitializedExCls = static_cast<jclass>(env->NewGlobalRef(local));
canNotInitializedExCls = JException(env, "edu/wpi/first/wpilibj/can/CANNotInitializedException");
if (!canNotInitializedExCls) return JNI_ERR;
env->DeleteLocalRef(local);
local = env->FindClass("edu/wpi/first/wpilibj/util/UncleanStatusException");
if (!local) return JNI_ERR;
uncleanStatusExCls = static_cast<jclass>(env->NewGlobalRef(local));
uncleanStatusExCls = JException(env,"edu/wpi/first/wpilibj/util/UncleanStatusException");
if (!uncleanStatusExCls) return JNI_ERR;
env->DeleteLocalRef(local);
local = env->FindClass("edu/wpi/first/wpilibj/PWMConfigDataResult");
if (!local) return JNI_ERR;
pwmConfigDataResultCls = static_cast<jclass>(env->NewGlobalRef(local));
pwmConfigDataResultCls = JClass(env, "edu/wpi/first/wpilibj/PWMConfigDataResult");
if (!pwmConfigDataResultCls) return JNI_ERR;
env->DeleteLocalRef(local);
return JNI_VERSION_1_6;
}
@@ -384,20 +264,17 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK)
return;
// Delete global references
if (throwableCls) env->DeleteGlobalRef(throwableCls);
if (stackTraceElementCls) env->DeleteGlobalRef(stackTraceElementCls);
if (runtimeExCls) env->DeleteGlobalRef(runtimeExCls);
if (illegalArgExCls) env->DeleteGlobalRef(illegalArgExCls);
if (boundaryExCls) env->DeleteGlobalRef(boundaryExCls);
if (allocationExCls) env->DeleteGlobalRef(allocationExCls);
if (halHandleExCls) env->DeleteGlobalRef(halHandleExCls);
if (canInvalidBufferExCls) env->DeleteGlobalRef(canInvalidBufferExCls);
if (canMessageNotFoundExCls) env->DeleteGlobalRef(canMessageNotFoundExCls);
if (canMessageNotAllowedExCls)
env->DeleteGlobalRef(canMessageNotAllowedExCls);
if (canNotInitializedExCls) env->DeleteGlobalRef(canNotInitializedExCls);
if (uncleanStatusExCls) env->DeleteGlobalRef(uncleanStatusExCls);
if (pwmConfigDataResultCls) env->DeleteGlobalRef(pwmConfigDataResultCls);
runtimeExCls.free(env);
illegalArgExCls.free(env);
boundaryExCls.free(env);
allocationExCls.free(env);
halHandleExCls.free(env);
canInvalidBufferExCls.free(env);
canMessageNotFoundExCls.free(env);
canMessageNotAllowedExCls.free(env);
canNotInitializedExCls.free(env);
uncleanStatusExCls.free(env);
pwmConfigDataResultCls.free(env);
jvm = nullptr;
}
@@ -489,7 +366,7 @@ Java_edu_wpi_first_wpilibj_hal_HALUtil_getHALErrorMessage(
const char *msg = HAL_GetErrorMessage(paramId);
HALUTIL_LOG(logDEBUG) << "Calling HALUtil HAL_GetErrorMessage id=" << paramId
<< " msg=" << msg;
return paramEnv->NewStringUTF(msg);
return MakeJString(paramEnv, msg);
}
/*
@@ -512,7 +389,7 @@ JNIEXPORT jstring JNICALL Java_edu_wpi_first_wpilibj_hal_HALUtil_getHALstrerror(
const char *msg = strerror(errno);
HALUTIL_LOG(logDEBUG) << "Calling HALUtil getHALstrerror errorCode="
<< errorCode << " msg=" << msg;
return env->NewStringUTF(msg);
return MakeJString(env, msg);
}
} // extern "C"