diff --git a/wpilibj/src/athena/cpp/lib/HAL.cpp b/wpilibj/src/athena/cpp/lib/HAL.cpp index 881303d936..d7659783b7 100644 --- a/wpilibj/src/athena/cpp/lib/HAL.cpp +++ b/wpilibj/src/athena/cpp/lib/HAL.cpp @@ -15,8 +15,10 @@ #include "HAL/DriverStation.h" #include "edu_wpi_first_wpilibj_hal_HAL.h" #include "HALUtil.h" +#include "support/jni_util.h" using namespace frc; +using namespace wpi::java; // set the logging level static TLogLevel netCommLogLevel = logWARNING; @@ -99,15 +101,14 @@ JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_HAL_report( JNIEnv* paramEnv, jclass, jint paramResource, jint paramInstanceNumber, jint paramContext, jstring paramFeature) { - const char *featureStr = paramEnv->GetStringUTFChars(paramFeature, nullptr); + JStringRef featureStr{paramEnv, paramFeature}; NETCOMM_LOG(logDEBUG) << "Calling HAL report " << "res:" << paramResource << " instance:" << paramInstanceNumber << " context:" << paramContext - << " feature:" << featureStr; + << " feature:" << featureStr.c_str(); jint returnValue = - HAL_Report(paramResource, paramInstanceNumber, paramContext, featureStr); - paramEnv->ReleaseStringUTFChars(paramFeature, featureStr); + HAL_Report(paramResource, paramInstanceNumber, paramContext, featureStr.c_str()); return returnValue; } @@ -257,7 +258,7 @@ Java_edu_wpi_first_wpilibj_hal_HAL_getJoystickName(JNIEnv* env, jclass, jbyte port) { NETCOMM_LOG(logDEBUG) << "Calling HAL_GetJoystickName"; char *joystickName = HAL_GetJoystickName(port); - jstring str = env->NewStringUTF(joystickName); + jstring str = MakeJString(env, joystickName); std::free(joystickName); return str; } @@ -330,13 +331,11 @@ Java_edu_wpi_first_wpilibj_hal_HAL_getBrownedOut(JNIEnv* env, jclass) { JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_HAL_setErrorData(JNIEnv* env, jclass, jstring error) { - const char *errorStr = env->GetStringUTFChars(error, nullptr); - jsize length = env->GetStringUTFLength(error); + JStringRef errorStr{env, error}; - NETCOMM_LOG(logDEBUG) << "Set Error: " << errorStr; - NETCOMM_LOG(logDEBUG) << "Length: " << length; - jint returnValue = HAL_SetErrorData(errorStr, (jint)length, 0); - env->ReleaseStringUTFChars(error, errorStr); + NETCOMM_LOG(logDEBUG) << "Set Error: " << errorStr.c_str(); + NETCOMM_LOG(logDEBUG) << "Length: " << errorStr.size(); + jint returnValue = HAL_SetErrorData(errorStr.c_str(), (int32_t)errorStr.size(), 0); return returnValue; } @@ -352,18 +351,15 @@ Java_edu_wpi_first_wpilibj_hal_HAL_sendError(JNIEnv* env, jclass, jstring location, jstring callStack, jboolean printMsg) { - const char *detailsStr = env->GetStringUTFChars(details, nullptr); - const char *locationStr = env->GetStringUTFChars(location, nullptr); - const char *callStackStr = env->GetStringUTFChars(callStack, nullptr); + JStringRef detailsStr{env, details}; + JStringRef locationStr{env, location}; + JStringRef callStackStr{env, callStack}; - NETCOMM_LOG(logDEBUG) << "Send Error: " << detailsStr; - NETCOMM_LOG(logDEBUG) << "Location: " << locationStr; - NETCOMM_LOG(logDEBUG) << "Call Stack: " << callStackStr; - jint returnValue = HAL_SendError(isError, errorCode, isLVCode, detailsStr, - locationStr, callStackStr, printMsg); - env->ReleaseStringUTFChars(details, detailsStr); - env->ReleaseStringUTFChars(location, locationStr); - env->ReleaseStringUTFChars(callStack, callStackStr); + NETCOMM_LOG(logDEBUG) << "Send Error: " << detailsStr.c_str(); + NETCOMM_LOG(logDEBUG) << "Location: " << locationStr.c_str(); + NETCOMM_LOG(logDEBUG) << "Call Stack: " << callStackStr.c_str(); + jint returnValue = HAL_SendError(isError, errorCode, isLVCode, detailsStr.c_str(), + locationStr.c_str(), callStackStr.c_str(), printMsg); return returnValue; } diff --git a/wpilibj/src/athena/cpp/lib/HALUtil.cpp b/wpilibj/src/athena/cpp/lib/HALUtil.cpp index e6079059cc..a06daeb8c8 100644 --- a/wpilibj/src/athena/cpp/lib/HALUtil.cpp +++ b/wpilibj/src/athena/cpp/lib/HALUtil.cpp @@ -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, "", "()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(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(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(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(&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(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(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(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(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(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(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(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(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(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(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(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(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(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(&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" diff --git a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANInvalidBufferException.java b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANInvalidBufferException.java index 0c4064abfc..5437fe83a6 100644 --- a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANInvalidBufferException.java +++ b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANInvalidBufferException.java @@ -15,4 +15,8 @@ public class CANInvalidBufferException extends RuntimeException { public CANInvalidBufferException() { super(); } + + public CANInvalidBufferException(String msg) { + super(msg); + } } diff --git a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANMessageNotFoundException.java b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANMessageNotFoundException.java index 37a5a10811..d1a61f30eb 100644 --- a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANMessageNotFoundException.java +++ b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANMessageNotFoundException.java @@ -15,4 +15,8 @@ public class CANMessageNotFoundException extends RuntimeException { public CANMessageNotFoundException() { super(); } + + public CANMessageNotFoundException(String msg) { + super(msg); + } } diff --git a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANNotInitializedException.java b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANNotInitializedException.java index 0c3b8fca0f..64f45009a6 100644 --- a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANNotInitializedException.java +++ b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/can/CANNotInitializedException.java @@ -15,4 +15,8 @@ public class CANNotInitializedException extends RuntimeException { public CANNotInitializedException() { super(); } + + public CANNotInitializedException(String msg) { + super(msg); + } }