From 3b5246d547d26d8b994851ab19ef1755b53b5e03 Mon Sep 17 00:00:00 2001 From: fur Date: Sun, 28 Jun 1998 07:53:04 +0000 Subject: [PATCH] Aggressively track and release JNI local references to constructed Java objects, because otherwise at least one JVM is reticent about GC'ing them. --- js/ref/liveconnect/jsj_JSObject.c | 30 ++++++++++++++--- js/ref/liveconnect/jsj_array.c | 5 ++- js/ref/liveconnect/jsj_field.c | 7 ++-- js/ref/liveconnect/jsj_method.c | 54 +++++++++++++++++++++++++------ js/ref/liveconnect/jsj_private.h | 4 +-- 5 files changed, 81 insertions(+), 19 deletions(-) diff --git a/js/ref/liveconnect/jsj_JSObject.c b/js/ref/liveconnect/jsj_JSObject.c index 975c6ce90fe7..91dd69a7f375 100644 --- a/js/ref/liveconnect/jsj_JSObject.c +++ b/js/ref/liveconnect/jsj_JSObject.c @@ -146,6 +146,12 @@ jsj_WrapJSObject(JSContext *cx, JNIEnv *jEnv, JSObject *js_obj) java_wrapper_obj = NULL; } + /* + * Release local reference to wrapper object, since some JVMs seem reticent + * about collecting it otherwise. + */ + (*jEnv)->DeleteLocalRef(jEnv, java_wrapper_obj); + done: #ifdef JS_THREADSAFE PR_ExitMonitor(js_obj_reflections_monitor); @@ -389,6 +395,15 @@ throw_any_pending_js_error_as_a_java_exception(JSJavaThreadState *jsj_env) goto done; } + /* + * Release local references to Java objects, since some JVMs seem reticent + * about collecting them otherwise. + */ + (*jEnv)->DeleteLocalRef(jEnv, message_jstr); + (*jEnv)->DeleteLocalRef(jEnv, filename_jstr); + (*jEnv)->DeleteLocalRef(jEnv, linebuf_jstr); + (*jEnv)->DeleteLocalRef(jEnv, java_exception); + goto done; out_of_memory: @@ -639,6 +654,7 @@ Java_netscape_javascript_JSObject_getMember(JNIEnv *jEnv, JSObject *js_obj; jsval js_val; int dummy_cost; + JSBool dummy_bool; const jchar *property_name_ucs2; jsize property_name_len; JSErrorReporter saved_reporter; @@ -669,7 +685,7 @@ Java_netscape_javascript_JSObject_getMember(JNIEnv *jEnv, goto done; jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, get_jlObject_descriptor(cx, jEnv), - &dummy_cost, &member); + &dummy_cost, &member, &dummy_bool); done: if (property_name_ucs2) @@ -694,6 +710,7 @@ Java_netscape_javascript_JSObject_getSlot(JNIEnv *jEnv, JSObject *js_obj; jsval js_val; int dummy_cost; + JSBool dummy_bool; JSErrorReporter saved_reporter; jobject member; JSJavaThreadState *jsj_env; @@ -706,7 +723,7 @@ Java_netscape_javascript_JSObject_getSlot(JNIEnv *jEnv, if (!JS_GetElement(cx, js_obj, slot, &js_val)) goto done; if (!jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, get_jlObject_descriptor(cx, jEnv), - &dummy_cost, &member)) + &dummy_cost, &member, &dummy_bool)) goto done; done: @@ -854,6 +871,7 @@ Java_netscape_javascript_JSObject_call(JNIEnv *jEnv, jobject java_wrapper_obj, JSObject *js_obj; jsval js_val, function_val; int dummy_cost; + JSBool dummy_bool; const jchar *function_name_ucs2; jsize function_name_len; JSErrorReporter saved_reporter; @@ -908,7 +926,7 @@ Java_netscape_javascript_JSObject_call(JNIEnv *jEnv, jobject java_wrapper_obj, goto cleanup_argv; jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, get_jlObject_descriptor(cx, jEnv), - &dummy_cost, &result); + &dummy_cost, &result, &dummy_bool); cleanup_argv: if (argv) { @@ -943,6 +961,7 @@ Java_netscape_javascript_JSObject_eval(JNIEnv *jEnv, JSObject *js_obj; jsval js_val; int dummy_cost; + JSBool dummy_bool; const jchar *eval_ucs2; jsize eval_len; JSErrorReporter saved_reporter; @@ -984,7 +1003,7 @@ Java_netscape_javascript_JSObject_eval(JNIEnv *jEnv, /* Convert result to a subclass of java.lang.Object */ jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, get_jlObject_descriptor(cx, jEnv), - &dummy_cost, &result); + &dummy_cost, &result, &dummy_bool); done: if (eval_ucs2) @@ -1043,6 +1062,7 @@ Java_netscape_javascript_JSObject_getWindow(JNIEnv *jEnv, JSObject *js_obj; jsval js_val; int dummy_cost; + JSBool dummy_bool; JSErrorReporter saved_reporter; jobject java_obj; JSJavaThreadState *jsj_env; @@ -1063,7 +1083,7 @@ Java_netscape_javascript_JSObject_getWindow(JNIEnv *jEnv, } js_val = OBJECT_TO_JSVAL(js_obj); jsj_ConvertJSValueToJavaObject(cx, jEnv, js_val, get_jlObject_descriptor(cx, jEnv), - &dummy_cost, &java_obj); + &dummy_cost, &java_obj, &dummy_bool); done: if (!exit_js(cx, jsj_env, saved_reporter)) return NULL; diff --git a/js/ref/liveconnect/jsj_array.c b/js/ref/liveconnect/jsj_array.c index fa6eac66c4ed..82af588e160d 100644 --- a/js/ref/liveconnect/jsj_array.c +++ b/js/ref/liveconnect/jsj_array.c @@ -112,9 +112,10 @@ jsj_SetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array, jsize in int dummy_cost; jvalue java_value; JavaSignatureChar component_type; + JSBool is_local_ref; if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, array_component_signature, - &dummy_cost, &java_value)) + &dummy_cost, &java_value, &is_local_ref)) return JS_FALSE; #define SET_ELEMENT_FROM_PRIMITIVE_JAVA_ARRAY(Type,member) \ @@ -163,6 +164,8 @@ jsj_SetJavaArrayElement(JSContext *cx, JNIEnv *jEnv, jarray java_array, jsize in case JAVA_SIGNATURE_CLASS: case JAVA_SIGNATURE_ARRAY: (*jEnv)->SetObjectArrayElement(jEnv, java_array, index, java_value.l); + if (is_local_ref) \ + (*jEnv)->DeleteLocalRef(jEnv, java_value.l); if ((*jEnv)->ExceptionOccurred(jEnv)) { jsj_ReportJavaError(cx, jEnv, "Error assigning to Java object array"); return JS_FALSE; diff --git a/js/ref/liveconnect/jsj_field.c b/js/ref/liveconnect/jsj_field.c index e2aee419c9e1..ee3670c5cddc 100644 --- a/js/ref/liveconnect/jsj_field.c +++ b/js/ref/liveconnect/jsj_field.c @@ -307,7 +307,7 @@ JSBool jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec, jclass java_obj, jsval js_val) { - JSBool is_static_field; + JSBool is_static_field, is_local_ref; int dummy_cost; jvalue java_value; JavaSignature *signature; @@ -331,7 +331,8 @@ jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec, PR_END_MACRO signature = field_spec->signature; - if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, signature, &dummy_cost, &java_value)) + if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, js_val, signature, &dummy_cost, + &java_value, &is_local_ref)) return JS_FALSE; field_type = signature->type; @@ -371,6 +372,8 @@ jsj_SetJavaFieldValue(JSContext *cx, JNIEnv *jEnv, JavaFieldSpec *field_spec, case JAVA_SIGNATURE_CLASS: case JAVA_SIGNATURE_ARRAY: SET_JAVA_FIELD(Object,l); + if (is_local_ref) \ + (*jEnv)->DeleteLocalRef(jEnv, java_value.l); break; #undef SET_JAVA_FIELD diff --git a/js/ref/liveconnect/jsj_method.c b/js/ref/liveconnect/jsj_method.c index a9cb1fbc15ae..9ac35968856d 100644 --- a/js/ref/liveconnect/jsj_method.c +++ b/js/ref/liveconnect/jsj_method.c @@ -548,13 +548,15 @@ method_signature_matches_JS_args(JSContext *cx, JNIEnv *jEnv, uintN argc, jsval { uintN i; JavaSignature *arg_signature; + JSBool dummy_bool; if (argc != (uintN)method_signature->num_args) return JS_FALSE; for (i = 0; i < argc; i++) { arg_signature = method_signature->arg_signatures[i]; - if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, argv[i], arg_signature, cost, NULL)) + if (!jsj_ConvertJSValueToJavaValue(cx, jEnv, argv[i], arg_signature, cost, + NULL, &dummy_bool)) return JS_FALSE; } return JS_TRUE; @@ -678,7 +680,7 @@ resolve_overloaded_method(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *mem if (!method_signature_matches_JS_args(cx, jEnv, argc, argv, &method->signature, &cost)) continue; -#ifdef LIVECONNECT_IMPROVEMENTS +#if 1 if (cost < lowest_cost) { lowest_cost = cost; best_method_match = method; @@ -708,10 +710,10 @@ resolve_overloaded_method(JSContext *cx, JNIEnv *jEnv, JavaMemberDescriptor *mem static jvalue * convert_JS_method_args_to_java_argv(JSContext *cx, JNIEnv *jEnv, jsval *argv, - JavaMethodSpec *method) + JavaMethodSpec *method, JSBool **localvp) { jvalue *jargv; - JSBool ok; + JSBool ok, *localv; uintN i, argc; JavaSignature **arg_signatures; JavaMethodSignature *signature; @@ -726,15 +728,28 @@ convert_JS_method_args_to_java_argv(JSContext *cx, JNIEnv *jEnv, jsval *argv, if (!jargv) return NULL; + + /* + * Allocate an array that contains a flag for each argument, indicating whether + * or not the conversion from a JS value to a Java value resulted in a new + * JNI local reference. + */ + localv = (JSBool *)JS_malloc(cx, sizeof(JSBool) * argc); + if (!localv) { + JS_free(cx, jargv); + return NULL; + } + *localvp = localv; for (i = 0; i < argc; i++) { int dummy_cost; ok = jsj_ConvertJSValueToJavaValue(cx, jEnv, argv[i], arg_signatures[i], - &dummy_cost, &jargv[i]); + &dummy_cost, &jargv[i], &localv[i]); if (!ok) { JS_ReportError(cx, "Internal error: can't convert JS value to Java value"); JS_free(cx, jargv); + JS_free(cx, localv); return NULL; } } @@ -752,7 +767,7 @@ invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env, { jvalue java_value; jvalue *jargv; - uintN argc; + uintN argc, i; jobject java_object; jclass java_class; jmethodID methodID; @@ -760,6 +775,7 @@ invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env, JavaSignature *return_val_signature; JSContext *old_cx; JNIEnv *jEnv; + JSBool *localv; methodID = method->methodID; signature = &method->signature; @@ -777,7 +793,7 @@ invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env, jargv = NULL; if (argc) { - jargv = convert_JS_method_args_to_java_argv(cx, jEnv, argv, method); + jargv = convert_JS_method_args_to_java_argv(cx, jEnv, argv, method, &localv); if (!jargv) return JS_FALSE; } @@ -858,12 +874,22 @@ invoke_java_method(JSContext *cx, JSJavaThreadState *jsj_env, return JS_FALSE; } + for (i = 0; i < argc; i++) { + if (localv[i]) + (*jEnv)->DeleteLocalRef(jEnv, jargv[i].l); + } if (jargv) JS_free(cx, jargv); + JSJ_SetDefaultJSContextForJavaThread(old_cx, jsj_env); return jsj_ConvertJavaValueToJSValue(cx, jEnv, return_val_signature, &java_value, vp); + error: + for (i = 0; i < argc; i++) { + if (localv[i]) + (*jEnv)->DeleteLocalRef(jEnv, jargv[i].l); + } if (jargv) JS_free(cx, jargv); JSJ_SetDefaultJSContextForJavaThread(old_cx, jsj_env); @@ -987,12 +1013,13 @@ invoke_java_constructor(JSContext *cx, jsval *argv, jsval *vp) { jvalue *jargv; - uintN argc; + uintN argc, i; jobject java_object; jmethodID methodID; JavaMethodSignature *signature; JSContext *old_cx; JNIEnv *jEnv; + JSBool *localv; methodID = method->methodID; signature = &method->signature; @@ -1002,7 +1029,7 @@ invoke_java_constructor(JSContext *cx, jargv = NULL; if (argc) { - jargv = convert_JS_method_args_to_java_argv(cx, jEnv, argv, method); + jargv = convert_JS_method_args_to_java_argv(cx, jEnv, argv, method, &localv); if (!jargv) return JS_FALSE; } @@ -1013,6 +1040,7 @@ invoke_java_constructor(JSContext *cx, "one JSContext ?"); } + /* Call the constructor */ java_object = (*jEnv)->NewObjectA(jEnv, java_class, methodID, jargv); JSJ_SetDefaultJSContextForJavaThread(old_cx, jsj_env); @@ -1023,12 +1051,20 @@ invoke_java_constructor(JSContext *cx, goto error; } + for (i = 0; i < argc; i++) { + if (localv[i]) + (*jEnv)->DeleteLocalRef(jEnv, jargv[i].l); + } if (jargv) JS_free(cx, jargv); return jsj_ConvertJavaObjectToJSValue(cx, jEnv, java_object, vp); error: + for (i = 0; i < argc; i++) { + if (localv[i]) + (*jEnv)->DeleteLocalRef(jEnv, jargv[i].l); + } if (jargv) JS_free(cx, jargv); return JS_FALSE; diff --git a/js/ref/liveconnect/jsj_private.h b/js/ref/liveconnect/jsj_private.h index 8d98e06280a6..01bae47c4ae3 100644 --- a/js/ref/liveconnect/jsj_private.h +++ b/js/ref/liveconnect/jsj_private.h @@ -268,10 +268,10 @@ jsj_PurgeJavaMethodSignature(JSContext *cx, JNIEnv *jEnv, JavaMethodSignature *s extern JSBool jsj_ConvertJSValueToJavaValue(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature, - int *cost, jvalue *java_value); + int *cost, jvalue *java_value, JSBool *is_local_refp); extern JSBool jsj_ConvertJSValueToJavaObject(JSContext *cx, JNIEnv *jEnv, jsval v, JavaSignature *signature, - int *cost, jobject *java_value); + int *cost, jobject *java_value, JSBool *is_local_refp); extern jstring jsj_ConvertJSStringToJavaString(JSContext *cx, JNIEnv *jEnv, JSString *js_str);