src/share/vm/prims/jniCheck.cpp
Print this page
rev 6562 : 8043224: -Xcheck:jni improvements to exception checking and excessive local refs
Summary: Warning when not checking exceptions from function that require so, also when local refs expand beyond capacity.
Reviewed-by: zgu, coleenp, hseigel
@@ -51,10 +51,12 @@
#endif
#ifdef TARGET_ARCH_ppc
# include "jniTypes_ppc.hpp"
#endif
+// Complain every extra number of unplanned local refs
+#define CHECK_JNI_LOCAL_REF_CAP_WARN_THRESHOLD 32
// Heap objects are allowed to be directly referenced only in VM code,
// not in native code.
#define ASSERT_OOPS_ALLOWED \
@@ -166,16 +168,46 @@
/*
* SUPPORT FUNCTIONS
*/
+/**
+ * Check whether or not a programmer has actually checked for exceptions. According
+ * to the JNI Specification ("jni/spec/design.html#java_exceptions"):
+ *
+ * There are two cases where the programmer needs to check for exceptions without
+ * being able to first check an error code:
+ *
+ * - The JNI functions that invoke a Java method return the result of the Java method.
+ * The programmer must call ExceptionOccurred() to check for possible exceptions
+ * that occurred during the execution of the Java method.
+ *
+ * - Some of the JNI array access functions do not return an error code, but may
+ * throw an ArrayIndexOutOfBoundsException or ArrayStoreException.
+ *
+ * In all other cases, a non-error return value guarantees that no exceptions have been thrown.
+ */
static inline void
-functionEnterCritical(JavaThread* thr)
-{
+check_pending_exception(JavaThread* thr) {
if (thr->has_pending_exception()) {
NativeReportJNIWarning(thr, "JNI call made with exception pending");
}
+ if (thr->is_pending_jni_exception_check()) {
+ IN_VM(
+ tty->print_cr("WARNING in native method: JNI call made without checking exceptions when required to from %s",
+ thr->get_pending_jni_exception_check());
+ thr->print_stack();
+ )
+ thr->clear_pending_jni_exception_check(); // Just complain once
+ }
+}
+
+
+static inline void
+functionEnterCritical(JavaThread* thr)
+{
+ check_pending_exception(thr);
}
static inline void
functionEnterCriticalExceptionAllowed(JavaThread* thr)
{
@@ -185,13 +217,11 @@
functionEnter(JavaThread* thr)
{
if (thr->in_critical()) {
tty->print_cr("%s", warn_other_function_in_critical);
}
- if (thr->has_pending_exception()) {
- NativeReportJNIWarning(thr, "JNI call made with exception pending");
- }
+ check_pending_exception(thr);
}
static inline void
functionEnterExceptionAllowed(JavaThread* thr)
{
@@ -199,13 +229,24 @@
tty->print_cr("%s", warn_other_function_in_critical);
}
}
static inline void
-functionExit(JNIEnv *env)
+functionExit(JavaThread* thr)
{
- /* nothing to do at this time */
+ JNIHandleBlock* handles = thr->active_handles();
+ size_t planned_capacity = handles->get_planned_capacity();
+ size_t live_handles = handles->get_number_of_live_handles();
+ if (live_handles > planned_capacity) {
+ IN_VM(
+ tty->print_cr("WARNING: JNI local refs: %zu, exceeds capacity: %zu",
+ live_handles, planned_capacity);
+ thr->print_stack();
+ )
+ // Complain just the once, reset to current + warn threshold
+ handles->set_planned_capacity(live_handles + CHECK_JNI_LOCAL_REF_CAP_WARN_THRESHOLD);
+ }
}
static inline void
checkStaticFieldID(JavaThread* thr, jfieldID fid, jclass cls, int ftype)
{
@@ -506,11 +547,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_object(thr, loader);
)
jclass result = UNCHECKED()->DefineClass(env, name, loader, buf, len);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jclass,
checked_jni_FindClass(JNIEnv *env,
@@ -518,11 +559,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_class_descriptor(thr, name);
)
jclass result = UNCHECKED()->FindClass(env, name);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jmethodID,
checked_jni_FromReflectedMethod(JNIEnv *env,
@@ -530,11 +571,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_object(thr, method);
)
jmethodID result = UNCHECKED()->FromReflectedMethod(env, method);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jfieldID,
checked_jni_FromReflectedField(JNIEnv *env,
@@ -542,11 +583,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_object(thr, field);
)
jfieldID result = UNCHECKED()->FromReflectedField(env, field);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobject,
checked_jni_ToReflectedMethod(JNIEnv *env,
@@ -558,11 +599,11 @@
jniCheck::validate_class(thr, cls, false);
jniCheck::validate_jmethod_id(thr, methodID);
)
jobject result = UNCHECKED()->ToReflectedMethod(env, cls, methodID,
isStatic);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jclass,
checked_jni_GetSuperclass(JNIEnv *env,
@@ -570,11 +611,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_class(thr, sub, true);
)
jclass result = UNCHECKED()->GetSuperclass(env, sub);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jboolean,
checked_jni_IsAssignableFrom(JNIEnv *env,
@@ -584,11 +625,11 @@
IN_VM(
jniCheck::validate_class(thr, sub, true);
jniCheck::validate_class(thr, sup, true);
)
jboolean result = UNCHECKED()->IsAssignableFrom(env, sub, sup);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobject,
checked_jni_ToReflectedField(JNIEnv *env,
@@ -599,11 +640,11 @@
IN_VM(
jniCheck::validate_class(thr, cls, false);
)
jobject result = UNCHECKED()->ToReflectedField(env, cls, fieldID,
isStatic);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jint,
checked_jni_Throw(JNIEnv *env,
@@ -617,11 +658,11 @@
} else {
jniCheck::validate_throwable_klass(thr, oopObj->klass());
}
)
jint result = UNCHECKED()->Throw(env, obj);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jint,
checked_jni_ThrowNew(JNIEnv *env,
@@ -632,61 +673,67 @@
Klass* k = jniCheck::validate_class(thr, clazz, false);
assert(k != NULL, "validate_class shouldn't return NULL Klass*");
jniCheck::validate_throwable_klass(thr, k);
)
jint result = UNCHECKED()->ThrowNew(env, clazz, msg);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jthrowable,
checked_jni_ExceptionOccurred(JNIEnv *env))
+ thr->clear_pending_jni_exception_check();
functionEnterExceptionAllowed(thr);
jthrowable result = UNCHECKED()->ExceptionOccurred(env);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_ExceptionDescribe(JNIEnv *env))
functionEnterExceptionAllowed(thr);
UNCHECKED()->ExceptionDescribe(env);
- functionExit(env);
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_ExceptionClear(JNIEnv *env))
+ thr->clear_pending_jni_exception_check();
functionEnterExceptionAllowed(thr);
UNCHECKED()->ExceptionClear(env);
- functionExit(env);
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_FatalError(JNIEnv *env,
const char *msg))
+ thr->clear_pending_jni_exception_check();
functionEnter(thr);
UNCHECKED()->FatalError(env, msg);
- functionExit(env);
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(jint,
checked_jni_PushLocalFrame(JNIEnv *env,
jint capacity))
functionEnterExceptionAllowed(thr);
if (capacity < 0)
NativeReportJNIFatalError(thr, "negative capacity");
jint result = UNCHECKED()->PushLocalFrame(env, capacity);
- functionExit(env);
+ if (result == JNI_OK) {
+ thr->active_handles()->set_planned_capacity(capacity + CHECK_JNI_LOCAL_REF_CAP_WARN_THRESHOLD);
+ }
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobject,
checked_jni_PopLocalFrame(JNIEnv *env,
jobject result))
functionEnterExceptionAllowed(thr);
jobject res = UNCHECKED()->PopLocalFrame(env, result);
- functionExit(env);
+ functionExit(thr);
return res;
JNI_END
JNI_ENTRY_CHECKED(jobject,
checked_jni_NewGlobalRef(JNIEnv *env,
@@ -696,11 +743,11 @@
if (lobj != NULL) {
jniCheck::validate_handle(thr, lobj);
}
)
jobject result = UNCHECKED()->NewGlobalRef(env,lobj);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_DeleteGlobalRef(JNIEnv *env,
@@ -712,11 +759,11 @@
ReportJNIFatalError(thr,
"Invalid global JNI handle passed to DeleteGlobalRef");
}
)
UNCHECKED()->DeleteGlobalRef(env,gref);
- functionExit(env);
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_DeleteLocalRef(JNIEnv *env,
jobject obj))
@@ -727,11 +774,11 @@
JNIHandles::is_frame_handle(thr, obj)))
ReportJNIFatalError(thr,
"Invalid local JNI handle passed to DeleteLocalRef");
)
UNCHECKED()->DeleteLocalRef(env, obj);
- functionExit(env);
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(jboolean,
checked_jni_IsSameObject(JNIEnv *env,
jobject obj1,
@@ -748,11 +795,11 @@
if (obj2 != NULL && jniCheck::validate_handle(thr, obj2) != NULL) {
jniCheck::validate_object(thr, obj2);
}
)
jboolean result = UNCHECKED()->IsSameObject(env,obj1,obj2);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobject,
checked_jni_NewLocalRef(JNIEnv *env,
@@ -762,11 +809,11 @@
if (ref != NULL) {
jniCheck::validate_handle(thr, ref);
}
)
jobject result = UNCHECKED()->NewLocalRef(env, ref);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jint,
checked_jni_EnsureLocalCapacity(JNIEnv *env,
@@ -774,11 +821,14 @@
functionEnter(thr);
if (capacity < 0) {
NativeReportJNIFatalError(thr, "negative capacity");
}
jint result = UNCHECKED()->EnsureLocalCapacity(env, capacity);
- functionExit(env);
+ if (result == JNI_OK) {
+ thr->active_handles()->set_planned_capacity(capacity + CHECK_JNI_LOCAL_REF_CAP_WARN_THRESHOLD);
+ }
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobject,
checked_jni_AllocObject(JNIEnv *env,
@@ -786,11 +836,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_class(thr, clazz, false);
)
jobject result = UNCHECKED()->AllocObject(env,clazz);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobject,
checked_jni_NewObject(JNIEnv *env,
@@ -804,11 +854,11 @@
jniCheck::validate_jmethod_id(thr, methodID);
)
va_start(args, methodID);
jobject result = UNCHECKED()->NewObjectV(env,clazz,methodID,args);
va_end(args);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobject,
checked_jni_NewObjectV(JNIEnv *env,
@@ -819,11 +869,11 @@
IN_VM(
jniCheck::validate_class(thr, clazz, false);
jniCheck::validate_jmethod_id(thr, methodID);
)
jobject result = UNCHECKED()->NewObjectV(env,clazz,methodID,args);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobject,
checked_jni_NewObjectA(JNIEnv *env,
@@ -834,11 +884,11 @@
IN_VM(
jniCheck::validate_class(thr, clazz, false);
jniCheck::validate_jmethod_id(thr, methodID);
)
jobject result = UNCHECKED()->NewObjectA(env,clazz,methodID,args);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jclass,
checked_jni_GetObjectClass(JNIEnv *env,
@@ -846,11 +896,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_object(thr, obj);
)
jclass result = UNCHECKED()->GetObjectClass(env,obj);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jboolean,
checked_jni_IsInstanceOf(JNIEnv *env,
@@ -860,11 +910,11 @@
IN_VM(
jniCheck::validate_object(thr, obj);
jniCheck::validate_class(thr, clazz, true);
)
jboolean result = UNCHECKED()->IsInstanceOf(env,obj,clazz);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jmethodID,
checked_jni_GetMethodID(JNIEnv *env,
@@ -874,11 +924,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_class(thr, clazz, false);
)
jmethodID result = UNCHECKED()->GetMethodID(env,clazz,name,sig);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
#define WRAPPER_CallMethod(ResultType, Result) \
JNI_ENTRY_CHECKED(ResultType, \
@@ -893,11 +943,12 @@
) \
va_start(args,methodID); \
ResultType result =UNCHECKED()->Call##Result##MethodV(env, obj, methodID, \
args); \
va_end(args); \
- functionExit(env); \
+ thr->set_pending_jni_exception_check("Call"#Result"Method"); \
+ functionExit(thr); \
return result; \
JNI_END \
\
JNI_ENTRY_CHECKED(ResultType, \
checked_jni_Call##Result##MethodV(JNIEnv *env, \
@@ -908,11 +959,12 @@
IN_VM(\
jniCheck::validate_call_object(thr, obj, methodID); \
) \
ResultType result = UNCHECKED()->Call##Result##MethodV(env, obj, methodID,\
args); \
- functionExit(env); \
+ thr->set_pending_jni_exception_check("Call"#Result"MethodV"); \
+ functionExit(thr); \
return result; \
JNI_END \
\
JNI_ENTRY_CHECKED(ResultType, \
checked_jni_Call##Result##MethodA(JNIEnv *env, \
@@ -923,11 +975,12 @@
IN_VM( \
jniCheck::validate_call_object(thr, obj, methodID); \
) \
ResultType result = UNCHECKED()->Call##Result##MethodA(env, obj, methodID,\
args); \
- functionExit(env); \
+ thr->set_pending_jni_exception_check("Call"#Result"MethodA"); \
+ functionExit(thr); \
return result; \
JNI_END
WRAPPER_CallMethod(jobject,Object)
WRAPPER_CallMethod(jboolean,Boolean)
@@ -950,11 +1003,12 @@
jniCheck::validate_call_object(thr, obj, methodID);
)
va_start(args,methodID);
UNCHECKED()->CallVoidMethodV(env,obj,methodID,args);
va_end(args);
- functionExit(env);
+ thr->set_pending_jni_exception_check("CallVoidMethod");
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_CallVoidMethodV(JNIEnv *env,
jobject obj,
@@ -963,11 +1017,12 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_call_object(thr, obj, methodID);
)
UNCHECKED()->CallVoidMethodV(env,obj,methodID,args);
- functionExit(env);
+ thr->set_pending_jni_exception_check("CallVoidMethodV");
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_CallVoidMethodA(JNIEnv *env,
jobject obj,
@@ -976,11 +1031,12 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_call_object(thr, obj, methodID);
)
UNCHECKED()->CallVoidMethodA(env,obj,methodID,args);
- functionExit(env);
+ thr->set_pending_jni_exception_check("CallVoidMethodA");
+ functionExit(thr);
JNI_END
#define WRAPPER_CallNonvirtualMethod(ResultType, Result) \
JNI_ENTRY_CHECKED(ResultType, \
checked_jni_CallNonvirtual##Result##Method(JNIEnv *env, \
@@ -999,11 +1055,12 @@
obj, \
clazz, \
methodID,\
args); \
va_end(args); \
- functionExit(env); \
+ thr->set_pending_jni_exception_check("CallNonvirtual"#Result"Method"); \
+ functionExit(thr); \
return result; \
JNI_END \
\
JNI_ENTRY_CHECKED(ResultType, \
checked_jni_CallNonvirtual##Result##MethodV(JNIEnv *env, \
@@ -1019,11 +1076,12 @@
ResultType result = UNCHECKED()->CallNonvirtual##Result##MethodV(env, \
obj, \
clazz, \
methodID,\
args); \
- functionExit(env); \
+ thr->set_pending_jni_exception_check("CallNonvirtual"#Result"MethodV"); \
+ functionExit(thr); \
return result; \
JNI_END \
\
JNI_ENTRY_CHECKED(ResultType, \
checked_jni_CallNonvirtual##Result##MethodA(JNIEnv *env, \
@@ -1039,11 +1097,12 @@
ResultType result = UNCHECKED()->CallNonvirtual##Result##MethodA(env, \
obj, \
clazz, \
methodID,\
args); \
- functionExit(env); \
+ thr->set_pending_jni_exception_check("CallNonvirtual"#Result"MethodA"); \
+ functionExit(thr); \
return result; \
JNI_END
WRAPPER_CallNonvirtualMethod(jobject,Object)
WRAPPER_CallNonvirtualMethod(jboolean,Boolean)
@@ -1068,11 +1127,12 @@
jniCheck::validate_call_class(thr, clazz, methodID);
)
va_start(args,methodID);
UNCHECKED()->CallNonvirtualVoidMethodV(env,obj,clazz,methodID,args);
va_end(args);
- functionExit(env);
+ thr->set_pending_jni_exception_check("CallNonvirtualVoidMethod");
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_CallNonvirtualVoidMethodV(JNIEnv *env,
jobject obj,
@@ -1083,11 +1143,12 @@
IN_VM(
jniCheck::validate_call_object(thr, obj, methodID);
jniCheck::validate_call_class(thr, clazz, methodID);
)
UNCHECKED()->CallNonvirtualVoidMethodV(env,obj,clazz,methodID,args);
- functionExit(env);
+ thr->set_pending_jni_exception_check("CallNonvirtualVoidMethodV");
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_CallNonvirtualVoidMethodA(JNIEnv *env,
jobject obj,
@@ -1098,11 +1159,12 @@
IN_VM(
jniCheck::validate_call_object(thr, obj, methodID);
jniCheck::validate_call_class(thr, clazz, methodID);
)
UNCHECKED()->CallNonvirtualVoidMethodA(env,obj,clazz,methodID,args);
- functionExit(env);
+ thr->set_pending_jni_exception_check("CallNonvirtualVoidMethodA");
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(jfieldID,
checked_jni_GetFieldID(JNIEnv *env,
jclass clazz,
@@ -1111,11 +1173,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_class(thr, clazz, false);
)
jfieldID result = UNCHECKED()->GetFieldID(env,clazz,name,sig);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
#define WRAPPER_GetField(ReturnType,Result,FieldType) \
JNI_ENTRY_CHECKED(ReturnType, \
@@ -1125,11 +1187,11 @@
functionEnter(thr); \
IN_VM( \
checkInstanceFieldID(thr, fieldID, obj, FieldType); \
) \
ReturnType result = UNCHECKED()->Get##Result##Field(env,obj,fieldID); \
- functionExit(env); \
+ functionExit(thr); \
return result; \
JNI_END
WRAPPER_GetField(jobject, Object, T_OBJECT)
WRAPPER_GetField(jboolean, Boolean, T_BOOLEAN)
@@ -1150,11 +1212,11 @@
functionEnter(thr); \
IN_VM( \
checkInstanceFieldID(thr, fieldID, obj, FieldType); \
) \
UNCHECKED()->Set##Result##Field(env,obj,fieldID,val); \
- functionExit(env); \
+ functionExit(thr); \
JNI_END
WRAPPER_SetField(jobject, Object, T_OBJECT)
WRAPPER_SetField(jboolean, Boolean, T_BOOLEAN)
WRAPPER_SetField(jbyte, Byte, T_BYTE)
@@ -1174,11 +1236,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_class(thr, clazz, false);
)
jmethodID result = UNCHECKED()->GetStaticMethodID(env,clazz,name,sig);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
#define WRAPPER_CallStaticMethod(ReturnType,Result) \
JNI_ENTRY_CHECKED(ReturnType, \
@@ -1196,11 +1258,12 @@
ReturnType result = UNCHECKED()->CallStatic##Result##MethodV(env, \
clazz, \
methodID, \
args); \
va_end(args); \
- functionExit(env); \
+ thr->set_pending_jni_exception_check("CallStatic"#Result"Method"); \
+ functionExit(thr); \
return result; \
JNI_END \
\
JNI_ENTRY_CHECKED(ReturnType, \
checked_jni_CallStatic##Result##MethodV(JNIEnv *env, \
@@ -1214,11 +1277,12 @@
) \
ReturnType result = UNCHECKED()->CallStatic##Result##MethodV(env, \
clazz, \
methodID, \
args); \
- functionExit(env); \
+ thr->set_pending_jni_exception_check("CallStatic"#Result"MethodV"); \
+ functionExit(thr); \
return result; \
JNI_END \
\
JNI_ENTRY_CHECKED(ReturnType, \
checked_jni_CallStatic##Result##MethodA(JNIEnv *env, \
@@ -1232,11 +1296,12 @@
) \
ReturnType result = UNCHECKED()->CallStatic##Result##MethodA(env, \
clazz, \
methodID, \
args); \
- functionExit(env); \
+ thr->set_pending_jni_exception_check("CallStatic"#Result"MethodA"); \
+ functionExit(thr); \
return result; \
JNI_END
WRAPPER_CallStaticMethod(jobject,Object)
WRAPPER_CallStaticMethod(jboolean,Boolean)
@@ -1260,11 +1325,12 @@
jniCheck::validate_class(thr, cls, false);
)
va_start(args,methodID);
UNCHECKED()->CallStaticVoidMethodV(env,cls,methodID,args);
va_end(args);
- functionExit(env);
+ thr->set_pending_jni_exception_check("CallStaticVoidMethod");
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_CallStaticVoidMethodV(JNIEnv *env,
jclass cls,
@@ -1274,11 +1340,12 @@
IN_VM(
jniCheck::validate_jmethod_id(thr, methodID);
jniCheck::validate_class(thr, cls, false);
)
UNCHECKED()->CallStaticVoidMethodV(env,cls,methodID,args);
- functionExit(env);
+ thr->set_pending_jni_exception_check("CallStaticVoidMethodV");
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_CallStaticVoidMethodA(JNIEnv *env,
jclass cls,
@@ -1288,11 +1355,12 @@
IN_VM(
jniCheck::validate_jmethod_id(thr, methodID);
jniCheck::validate_class(thr, cls, false);
)
UNCHECKED()->CallStaticVoidMethodA(env,cls,methodID,args);
- functionExit(env);
+ thr->set_pending_jni_exception_check("CallStaticVoidMethodA");
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(jfieldID,
checked_jni_GetStaticFieldID(JNIEnv *env,
jclass clazz,
@@ -1301,11 +1369,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_class(thr, clazz, false);
)
jfieldID result = UNCHECKED()->GetStaticFieldID(env,clazz,name,sig);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
#define WRAPPER_GetStaticField(ReturnType,Result,FieldType) \
JNI_ENTRY_CHECKED(ReturnType, \
@@ -1318,11 +1386,11 @@
checkStaticFieldID(thr, fieldID, clazz, FieldType); \
) \
ReturnType result = UNCHECKED()->GetStatic##Result##Field(env, \
clazz, \
fieldID); \
- functionExit(env); \
+ functionExit(thr); \
return result; \
JNI_END
WRAPPER_GetStaticField(jobject, Object, T_OBJECT)
WRAPPER_GetStaticField(jboolean, Boolean, T_BOOLEAN)
@@ -1344,11 +1412,11 @@
IN_VM( \
jniCheck::validate_class(thr, clazz, false); \
checkStaticFieldID(thr, fieldID, clazz, FieldType); \
) \
UNCHECKED()->SetStatic##Result##Field(env,clazz,fieldID,value); \
- functionExit(env); \
+ functionExit(thr); \
JNI_END
WRAPPER_SetStaticField(jobject, Object, T_OBJECT)
WRAPPER_SetStaticField(jboolean, Boolean, T_BOOLEAN)
WRAPPER_SetStaticField(jbyte, Byte, T_BYTE)
@@ -1364,11 +1432,11 @@
checked_jni_NewString(JNIEnv *env,
const jchar *unicode,
jsize len))
functionEnter(thr);
jstring result = UNCHECKED()->NewString(env,unicode,len);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jsize,
checked_jni_GetStringLength(JNIEnv *env,
@@ -1376,11 +1444,11 @@
functionEnter(thr);
IN_VM(
checkString(thr, str);
)
jsize result = UNCHECKED()->GetStringLength(env,str);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
// Arbitrary (but well-known) tag
const void* STRING_TAG = (void*)0x47114711;
@@ -1405,11 +1473,11 @@
}
// Avoiding call to UNCHECKED()->ReleaseStringChars() since that will fire unexpected dtrace probes
// Note that the dtrace arguments for the allocated memory will not match up with this solution.
FreeHeap((char*)result);
}
- functionExit(env);
+ functionExit(thr);
return new_result;
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_ReleaseStringChars(JNIEnv *env,
@@ -1440,19 +1508,19 @@
"not allocated by GetStringChars");
}
UNCHECKED()->ReleaseStringChars(env, str,
(const jchar*) guarded.release_for_freeing());
}
- functionExit(env);
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(jstring,
checked_jni_NewStringUTF(JNIEnv *env,
const char *utf))
functionEnter(thr);
jstring result = UNCHECKED()->NewStringUTF(env,utf);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jsize,
checked_jni_GetStringUTFLength(JNIEnv *env,
@@ -1460,11 +1528,11 @@
functionEnter(thr);
IN_VM(
checkString(thr, str);
)
jsize result = UNCHECKED()->GetStringUTFLength(env,str);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
// Arbitrary (but well-known) tag - different than GetStringChars
const void* STRING_UTF_TAG = (void*) 0x48124812;
@@ -1488,11 +1556,11 @@
}
// Avoiding call to UNCHECKED()->ReleaseStringUTFChars() since that will fire unexpected dtrace probes
// Note that the dtrace arguments for the allocated memory will not match up with this solution.
FreeHeap((char*)result, mtInternal);
}
- functionExit(env);
+ functionExit(thr);
return new_result;
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_ReleaseStringUTFChars(JNIEnv *env,
@@ -1523,33 +1591,33 @@
"called on something not allocated by GetStringUTFChars");
}
UNCHECKED()->ReleaseStringUTFChars(env, str,
(const char*) guarded.release_for_freeing());
}
- functionExit(env);
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(jsize,
checked_jni_GetArrayLength(JNIEnv *env,
jarray array))
functionEnter(thr);
IN_VM(
check_is_array(thr, array);
)
jsize result = UNCHECKED()->GetArrayLength(env,array);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobjectArray,
checked_jni_NewObjectArray(JNIEnv *env,
jsize len,
jclass clazz,
jobject init))
functionEnter(thr);
jobjectArray result = UNCHECKED()->NewObjectArray(env,len,clazz,init);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobject,
checked_jni_GetObjectArrayElement(JNIEnv *env,
@@ -1558,11 +1626,12 @@
functionEnter(thr);
IN_VM(
check_is_obj_array(thr, array);
)
jobject result = UNCHECKED()->GetObjectArrayElement(env,array,index);
- functionExit(env);
+ thr->set_pending_jni_exception_check("GetObjectArrayElement");
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_SetObjectArrayElement(JNIEnv *env,
@@ -1572,20 +1641,21 @@
functionEnter(thr);
IN_VM(
check_is_obj_array(thr, array);
)
UNCHECKED()->SetObjectArrayElement(env,array,index,val);
- functionExit(env);
+ thr->set_pending_jni_exception_check("SetObjectArrayElement");
+ functionExit(thr);
JNI_END
#define WRAPPER_NewScalarArray(Return, Result) \
JNI_ENTRY_CHECKED(Return, \
checked_jni_New##Result##Array(JNIEnv *env, \
jsize len)) \
functionEnter(thr); \
Return result = UNCHECKED()->New##Result##Array(env,len); \
- functionExit(env); \
+ functionExit(thr); \
return (Return) result; \
JNI_END
WRAPPER_NewScalarArray(jbooleanArray, Boolean)
WRAPPER_NewScalarArray(jbyteArray, Byte)
@@ -1609,11 +1679,11 @@
array, \
isCopy); \
if (result != NULL) { \
result = (ElementType *) check_jni_wrap_copy_array(thr, array, result); \
} \
- functionExit(env); \
+ functionExit(thr); \
return result; \
JNI_END
WRAPPER_GetScalarArrayElements(T_BOOLEAN, jboolean, Boolean)
WRAPPER_GetScalarArrayElements(T_BYTE, jbyte, Byte)
@@ -1637,11 +1707,11 @@
typeArrayOop a = typeArrayOop(JNIHandles::resolve_non_null(array)); \
) \
ElementType* orig_result = (ElementType *) check_wrapped_array_release( \
thr, "checked_jni_Release"#Result"ArrayElements", array, elems, mode); \
UNCHECKED()->Release##Result##ArrayElements(env, array, orig_result, mode); \
- functionExit(env); \
+ functionExit(thr); \
JNI_END
WRAPPER_ReleaseScalarArrayElements(T_BOOLEAN,jboolean, Boolean, bool)
WRAPPER_ReleaseScalarArrayElements(T_BYTE, jbyte, Byte, byte)
WRAPPER_ReleaseScalarArrayElements(T_SHORT, jshort, Short, short)
@@ -1661,11 +1731,12 @@
functionEnter(thr); \
IN_VM( \
check_primitive_array_type(thr, array, ElementTag); \
) \
UNCHECKED()->Get##Result##ArrayRegion(env,array,start,len,buf); \
- functionExit(env); \
+ thr->set_pending_jni_exception_check("Get"#Result"ArrayRegion"); \
+ functionExit(thr); \
JNI_END
WRAPPER_GetScalarArrayRegion(T_BOOLEAN, jboolean, Boolean)
WRAPPER_GetScalarArrayRegion(T_BYTE, jbyte, Byte)
WRAPPER_GetScalarArrayRegion(T_SHORT, jshort, Short)
@@ -1685,11 +1756,12 @@
functionEnter(thr); \
IN_VM( \
check_primitive_array_type(thr, array, ElementTag); \
) \
UNCHECKED()->Set##Result##ArrayRegion(env,array,start,len,buf); \
- functionExit(env); \
+ thr->set_pending_jni_exception_check("Set"#Result"ArrayRegion"); \
+ functionExit(thr); \
JNI_END
WRAPPER_SetScalarArrayRegion(T_BOOLEAN, jboolean, Boolean)
WRAPPER_SetScalarArrayRegion(T_BYTE, jbyte, Byte)
WRAPPER_SetScalarArrayRegion(T_SHORT, jshort, Short)
@@ -1704,20 +1776,20 @@
jclass clazz,
const JNINativeMethod *methods,
jint nMethods))
functionEnter(thr);
jint result = UNCHECKED()->RegisterNatives(env,clazz,methods,nMethods);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jint,
checked_jni_UnregisterNatives(JNIEnv *env,
jclass clazz))
functionEnter(thr);
jint result = UNCHECKED()->UnregisterNatives(env,clazz);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jint,
checked_jni_MonitorEnter(JNIEnv *env,
@@ -1725,11 +1797,11 @@
functionEnter(thr);
IN_VM(
jniCheck::validate_object(thr, obj);
)
jint result = UNCHECKED()->MonitorEnter(env,obj);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jint,
checked_jni_MonitorExit(JNIEnv *env,
@@ -1737,20 +1809,20 @@
functionEnterExceptionAllowed(thr);
IN_VM(
jniCheck::validate_object(thr, obj);
)
jint result = UNCHECKED()->MonitorExit(env,obj);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jint,
checked_jni_GetJavaVM(JNIEnv *env,
JavaVM **vm))
functionEnter(thr);
jint result = UNCHECKED()->GetJavaVM(env,vm);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_GetStringRegion(JNIEnv *env,
@@ -1761,11 +1833,12 @@
functionEnter(thr);
IN_VM(
checkString(thr, str);
)
UNCHECKED()->GetStringRegion(env, str, start, len, buf);
- functionExit(env);
+ thr->set_pending_jni_exception_check("GetStringRegion");
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_GetStringUTFRegion(JNIEnv *env,
jstring str,
@@ -1775,11 +1848,12 @@
functionEnter(thr);
IN_VM(
checkString(thr, str);
)
UNCHECKED()->GetStringUTFRegion(env, str, start, len, buf);
- functionExit(env);
+ thr->set_pending_jni_exception_check("GetStringUTFRegion");
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(void *,
checked_jni_GetPrimitiveArrayCritical(JNIEnv *env,
jarray array,
@@ -1790,11 +1864,11 @@
)
void *result = UNCHECKED()->GetPrimitiveArrayCritical(env, array, isCopy);
if (result != NULL) {
result = check_jni_wrap_copy_array(thr, array, result);
}
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_ReleasePrimitiveArrayCritical(JNIEnv *env,
@@ -1806,11 +1880,11 @@
check_is_primitive_array(thr, array);
)
// Check the element array...
void* orig_result = check_wrapped_array_release(thr, "ReleasePrimitiveArrayCritical", array, carray, mode);
UNCHECKED()->ReleasePrimitiveArrayCritical(env, array, orig_result, mode);
- functionExit(env);
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(const jchar*,
checked_jni_GetStringCritical(JNIEnv *env,
jstring string,
@@ -1818,11 +1892,11 @@
functionEnterCritical(thr);
IN_VM(
checkString(thr, string);
)
const jchar *result = UNCHECKED()->GetStringCritical(env, string, isCopy);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_ReleaseStringCritical(JNIEnv *env,
@@ -1834,11 +1908,11 @@
)
/* The Hotspot JNI code does not use the parameters, so just check the
* string parameter as a minor sanity check
*/
UNCHECKED()->ReleaseStringCritical(env, str, chars);
- functionExit(env);
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(jweak,
checked_jni_NewWeakGlobalRef(JNIEnv *env,
jobject obj))
@@ -1847,55 +1921,56 @@
if (obj != NULL) {
jniCheck::validate_handle(thr, obj);
}
)
jweak result = UNCHECKED()->NewWeakGlobalRef(env, obj);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(void,
checked_jni_DeleteWeakGlobalRef(JNIEnv *env,
jweak ref))
functionEnterExceptionAllowed(thr);
UNCHECKED()->DeleteWeakGlobalRef(env, ref);
- functionExit(env);
+ functionExit(thr);
JNI_END
JNI_ENTRY_CHECKED(jboolean,
checked_jni_ExceptionCheck(JNIEnv *env))
+ thr->clear_pending_jni_exception_check();
functionEnterExceptionAllowed(thr);
jboolean result = UNCHECKED()->ExceptionCheck(env);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobject,
checked_jni_NewDirectByteBuffer(JNIEnv *env,
void *address,
jlong capacity))
functionEnter(thr);
jobject result = UNCHECKED()->NewDirectByteBuffer(env, address, capacity);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(void *,
checked_jni_GetDirectBufferAddress(JNIEnv *env,
jobject buf))
functionEnter(thr);
void* result = UNCHECKED()->GetDirectBufferAddress(env, buf);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jlong,
checked_jni_GetDirectBufferCapacity(JNIEnv *env,
jobject buf))
functionEnter(thr);
jlong result = UNCHECKED()->GetDirectBufferCapacity(env, buf);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jobjectRefType,
checked_jni_GetObjectRefType(JNIEnv *env,
@@ -1904,20 +1979,20 @@
/* validate the object being passed */
IN_VM(
jniCheck::validate_object(thr, obj);
)
jobjectRefType result = UNCHECKED()->GetObjectRefType(env, obj);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END
JNI_ENTRY_CHECKED(jint,
checked_jni_GetVersion(JNIEnv *env))
functionEnter(thr);
jint result = UNCHECKED()->GetVersion(env);
- functionExit(env);
+ functionExit(thr);
return result;
JNI_END