< prev index next >
src/share/back/invoker.c
Print this page
@ rev 11911 : 8153711: [REDO] JDWP: Memory Leak: GlobalRefs never deleted when processing invokeMethod command
| Summary: Delete global references in invoker_completeInvokeRequest()
| Reviewed-by: sspitsyn, dsamersoff
*** 209,218 ****
--- 209,274 ----
}
return error;
}
+ /*
+ * Delete saved global references - if any - for:
+ * - a potentially thrown Exception
+ * - a returned refernce/array value
+ * See invoker_doInvoke() and invoke* methods where global references
+ * are being saved.
+ */
+ static void
+ deletePotentiallySavedGlobalRefs(JNIEnv *env, InvokeRequest *request)
+ {
+ /* Delete potentially saved return value */
+ if ((request->invokeType == INVOKE_CONSTRUCTOR) ||
+ (returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT)) ||
+ (returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY))) {
+ if (request->returnValue.l != NULL) {
+ tossGlobalRef(env, &(request->returnValue.l));
+ }
+ }
+ /* Delete potentially saved exception */
+ if (request->exception != NULL) {
+ tossGlobalRef(env, &(request->exception));
+ }
+ }
+
+ /*
+ * Delete global argument references from the request which got put there before a
+ * invoke request was carried out. See fillInvokeRequest().
+ */
+ static void
+ deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request)
+ {
+ void *cursor;
+ jint argIndex = 0;
+ jvalue *argument = request->arguments;
+ jbyte argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
+
+ if (request->clazz != NULL) {
+ tossGlobalRef(env, &(request->clazz));
+ }
+ if (request->instance != NULL) {
+ tossGlobalRef(env, &(request->instance));
+ }
+ /* Delete global argument references */
+ while (argIndex < request->argumentCount) {
+ if ((argumentTag == JDWP_TAG(OBJECT)) ||
+ (argumentTag == JDWP_TAG(ARRAY))) {
+ if (argument->l != NULL) {
+ tossGlobalRef(env, &(argument->l));
+ }
+ }
+ argument++;
+ argIndex++;
+ argumentTag = nextArgumentTypeTag(&cursor);
+ }
+ }
+
static jvmtiError
fillInvokeRequest(JNIEnv *env, InvokeRequest *request,
jbyte invokeType, jbyte options, jint id,
jthread thread, jclass clazz, jmethodID method,
jobject instance,
*** 318,327 ****
--- 374,385 ----
static void
invokeConstructor(JNIEnv *env, InvokeRequest *request)
{
jobject object;
+
+ JDI_ASSERT_MSG(request->clazz, "Request clazz null");
object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
request->method,
request->arguments);
request->returnValue.l = NULL;
if (object != NULL) {
*** 334,343 ****
--- 392,402 ----
{
switch(returnTypeTag(request->methodSignature)) {
case JDWP_TAG(OBJECT):
case JDWP_TAG(ARRAY): {
jobject object;
+ JDI_ASSERT_MSG(request->clazz, "Request clazz null");
object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
request->clazz,
request->method,
request->arguments);
request->returnValue.l = NULL;
*** 422,431 ****
--- 481,491 ----
{
switch(returnTypeTag(request->methodSignature)) {
case JDWP_TAG(OBJECT):
case JDWP_TAG(ARRAY): {
jobject object;
+ JDI_ASSERT_MSG(request->instance, "Request instance null");
object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
request->instance,
request->method,
request->arguments);
request->returnValue.l = NULL;
*** 509,518 ****
--- 569,580 ----
{
switch(returnTypeTag(request->methodSignature)) {
case JDWP_TAG(OBJECT):
case JDWP_TAG(ARRAY): {
jobject object;
+ JDI_ASSERT_MSG(request->clazz, "Request clazz null");
+ JDI_ASSERT_MSG(request->instance, "Request instance null");
object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
request->instance,
request->clazz,
request->method,
request->arguments);
*** 605,614 ****
--- 667,678 ----
invoker_doInvoke(jthread thread)
{
JNIEnv *env;
jboolean startNow;
InvokeRequest *request;
+ jbyte options;
+ jbyte invokeType;
JDI_ASSERT(thread);
debugMonitorEnter(invokerLock);
*** 621,630 ****
--- 685,697 ----
startNow = request->pending && !request->started;
if (startNow) {
request->started = JNI_TRUE;
}
+ options = request->options;
+ invokeType = request->invokeType;
+
debugMonitorExit(invokerLock);
if (!startNow) {
return JNI_FALSE;
}
*** 635,653 ****
jobject exception;
JNI_FUNC_PTR(env,ExceptionClear)(env);
! switch (request->invokeType) {
case INVOKE_CONSTRUCTOR:
invokeConstructor(env, request);
break;
case INVOKE_STATIC:
invokeStatic(env, request);
break;
case INVOKE_INSTANCE:
! if (request->options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
invokeNonvirtual(env, request);
} else {
invokeVirtual(env, request);
}
break;
--- 702,720 ----
jobject exception;
JNI_FUNC_PTR(env,ExceptionClear)(env);
! switch (invokeType) {
case INVOKE_CONSTRUCTOR:
invokeConstructor(env, request);
break;
case INVOKE_STATIC:
invokeStatic(env, request);
break;
case INVOKE_INSTANCE:
! if (options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
invokeNonvirtual(env, request);
} else {
invokeVirtual(env, request);
}
break;
*** 721,743 ****
exc = request->exception;
returnValue = request->returnValue;
}
/*
* Give up the lock before I/O operation
*/
debugMonitorExit(invokerLock);
eventHandler_unlock();
-
if (!detached) {
outStream_initReply(&out, id);
(void)outStream_writeValue(env, &out, tag, returnValue);
(void)outStream_writeObjectTag(env, &out, exc);
(void)outStream_writeObjectRef(env, &out, exc);
outStream_sendReply(&out);
}
}
jboolean
invoker_isPending(jthread thread)
{
--- 788,831 ----
exc = request->exception;
returnValue = request->returnValue;
}
/*
+ * At this time, there's no need to retain global references on
+ * arguments since the reply is processed. No one will deal with
+ * this request ID anymore, so we must call deleteGlobalArgumentRefs().
+ *
+ * We cannot delete saved exception or return value references
+ * since otherwise a deleted handle would escape when writing
+ * the response to the stream. Instead, we clean those refs up
+ * after writing the respone.
+ */
+ deleteGlobalArgumentRefs(env, request);
+
+ /*
* Give up the lock before I/O operation
*/
debugMonitorExit(invokerLock);
eventHandler_unlock();
if (!detached) {
outStream_initReply(&out, id);
(void)outStream_writeValue(env, &out, tag, returnValue);
(void)outStream_writeObjectTag(env, &out, exc);
(void)outStream_writeObjectRef(env, &out, exc);
outStream_sendReply(&out);
}
+
+ /*
+ * Delete potentially saved global references of return value
+ * and exception
+ */
+ eventHandler_lock(); // for proper lock order
+ debugMonitorEnter(invokerLock);
+ deletePotentiallySavedGlobalRefs(env, request);
+ debugMonitorExit(invokerLock);
+ eventHandler_unlock();
}
jboolean
invoker_isPending(jthread thread)
{
< prev index next >