From 0aaf92ffbb8dd19f903c0784ea4ea6584ad6d0ee Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Tue, 3 May 2016 17:05:27 +0200 Subject: HONEYCOMB-10: fix issues with FindClass in multithreaded environments Added jclass reference caching and updated JNI version to 1.8 Change-Id: Ie8dbbd4b91b90bf9e4e9a6148313e46056b0d67e Signed-off-by: Marek Gradzki --- vpp-api/java/jvpp/gen/jvpp_c_gen.py | 63 ++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 8 deletions(-) (limited to 'vpp-api/java/jvpp/gen/jvpp_c_gen.py') diff --git a/vpp-api/java/jvpp/gen/jvpp_c_gen.py b/vpp-api/java/jvpp/gen/jvpp_c_gen.py index c0efed81d30..e277976c720 100644 --- a/vpp-api/java/jvpp/gen/jvpp_c_gen.py +++ b/vpp-api/java/jvpp/gen/jvpp_c_gen.py @@ -20,7 +20,48 @@ from string import Template def is_manually_generated(f_name): return f_name in {'control_ping_reply'} -# TODO: cache class/method/field identifiers to achieve better performance + +class_reference_template = Template("""jclass ${ref_name}Class; +""") + +find_class_invocation_template = Template(""" + ${ref_name}Class = (jclass)(*env)->NewGlobalRef(env, (*env)->FindClass(env, "org/openvpp/jvpp/dto/${class_name}")); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionDescribe(env); + return JNI_ERR; + }""") + +class_cache_template = Template(""" +$class_references +static int cache_class_references(JNIEnv* env) { + $find_class_invocations + return 0; +}""") + +def generate_class_cache(func_list): + class_references = [] + find_class_invocations = [] + for f in func_list: + c_name = f['name'] + class_name = util.underscore_to_camelcase_upper(c_name) + ref_name = util.underscore_to_camelcase(c_name) + + if not util.is_reply(class_name) or util.is_ignored(c_name) or util.is_notification(c_name): + # TODO handle notifications + continue + + class_references.append(class_reference_template.substitute( + ref_name=ref_name)) + + find_class_invocations.append(find_class_invocation_template.substitute( + ref_name=ref_name, + class_name=class_name)) + + return class_cache_template.substitute( + class_references="".join(class_references), find_class_invocations="".join(find_class_invocations)) + + +# TODO: cache method and field identifiers to achieve better performance # https://jira.fd.io/browse/HONEYCOMB-42 request_class_template = Template(""" jclass requestClass = (*env)->FindClass(env, "org/openvpp/jvpp/dto/${java_name_upper}");""") @@ -165,7 +206,7 @@ def generate_jni_impl(func_list, inputfile): dto_field_id_template = Template(""" - jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, dtoClass, "${java_name}", "${jni_signature}");""") + jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");""") default_dto_field_setter_template = Template(""" (*env)->Set${jni_setter}(env, dto, ${java_name}FieldId, mp->${c_name}); @@ -220,12 +261,10 @@ static void vl_api_${handler_name}_t_handler (vl_api_${handler_name}_t * mp) vppjni_main_t * jm = &vppjni_main; JNIEnv *env = jm->jenv; - jclass dtoClass = (*env)->FindClass(env, "org/openvpp/jvpp/dto/${dto_name}"); - - jmethodID constructor = (*env)->GetMethodID(env, dtoClass, "", "()V"); + jmethodID constructor = (*env)->GetMethodID(env, ${class_ref_name}Class, "", "()V"); jmethodID callbackMethod = (*env)->GetMethodID(env, jm->callbackClass, "on${dto_name}", "(Lorg/openvpp/jvpp/dto/${dto_name};)V"); - jobject dto = (*env)->NewObject(env, dtoClass, constructor); + jobject dto = (*env)->NewObject(env, ${class_ref_name}Class, constructor); $dto_setters (*env)->CallVoidMethod(env, jm->callback, callbackMethod, dto); }""") @@ -235,6 +274,7 @@ def generate_msg_handlers(func_list, inputfile): for f in func_list: handler_name = f['name'] dto_name = util.underscore_to_camelcase_upper(handler_name) + ref_name = util.underscore_to_camelcase(handler_name) if is_manually_generated(handler_name) or not util.is_reply(dto_name) or util.is_ignored(handler_name) or util.is_notification(handler_name): # TODO handle notifications @@ -253,6 +293,7 @@ def generate_msg_handlers(func_list, inputfile): dto_setters += dto_field_id_template.substitute( java_name=java_field_name, + class_ref_name=ref_name, jni_signature=jni_signature) dto_setter_template = dto_field_setter_templates[c_type] @@ -268,6 +309,7 @@ def generate_msg_handlers(func_list, inputfile): api_data=util.api_message_to_javadoc(f), handler_name=handler_name, dto_name=dto_name, + class_ref_name=ref_name, dto_setters=dto_setters)) return "\n".join(handlers) @@ -293,13 +335,16 @@ def generate_handler_registration(func_list): return "".join(handler_registration) -jvpp_c_template = Template(""" -/** + +jvpp_c_template = Template("""/** * This file contains JNI bindings for jvpp Java API. * It was generated by jvpp_c_gen.py based on $inputfile * (python representation of vpe.api generated by vppapigen). */ +// JAVA class reference cache +$class_cache + // JNI bindings $jni_implementations @@ -314,6 +359,7 @@ def generate_jvpp(func_list, inputfile): """ Generates jvpp C file """ print "Generating jvpp C" + class_cache = generate_class_cache(func_list) jni_impl = generate_jni_impl(func_list, inputfile) msg_handlers = generate_msg_handlers(func_list, inputfile) handler_registration = generate_handler_registration(func_list) @@ -321,6 +367,7 @@ def generate_jvpp(func_list, inputfile): jvpp_c_file = open("jvpp_gen.h", 'w') jvpp_c_file.write(jvpp_c_template.substitute( inputfile=inputfile, + class_cache=class_cache, jni_implementations=jni_impl, msg_handlers=msg_handlers, handler_registration=handler_registration)) -- cgit 1.2.3-korg