From 1f0dd7a0664bc217b7d69773574ac7eae3813bd7 Mon Sep 17 00:00:00 2001 From: Michal Cmarada Date: Thu, 6 Dec 2018 10:17:39 +0100 Subject: [PATCH] Update japi to support type aliases Change-Id: I6d6068d641d4c91e5c5b52eefb898affc5c0d2c0 Signed-off-by: Michal Cmarada --- .../japi/java/jvpp/gen/jvppgen/jni_common_gen.py | 87 ++++++++++++++++------ extras/japi/java/jvpp/gen/jvppgen/jni_impl_gen.py | 2 +- .../java/jvpp/gen/jvppgen/jni_msg_handlers_gen.py | 2 +- .../java/jvpp/gen/jvppgen/jni_type_handlers_gen.py | 21 +++++- extras/japi/java/jvpp/gen/jvppgen/jvpp_model.py | 46 +++++++++++- 5 files changed, 126 insertions(+), 32 deletions(-) diff --git a/extras/japi/java/jvpp/gen/jvppgen/jni_common_gen.py b/extras/japi/java/jvpp/gen/jvppgen/jni_common_gen.py index 397b92b528f..708cc1cba81 100755 --- a/extras/japi/java/jvpp/gen/jvppgen/jni_common_gen.py +++ b/extras/japi/java/jvpp/gen/jvppgen/jni_common_gen.py @@ -39,21 +39,21 @@ _REQUEST_FIELD_IDENTIFIER_TEMPLATE = Template(""" # TODO(VPP-1187): do not inline JNI object creation inside message handlers to reduce number of special cases -def generate_j2c_swap(element, struct_ref_name): +def generate_j2c_swap(element, struct_ref_name, is_alias): initialization = [] for field in element.fields: - initialization.append(generate_j2c_field_swap(field, struct_ref_name)) + initialization.append(generate_j2c_field_swap(field, struct_ref_name, is_alias)) return "\n".join(initialization) -def generate_j2c_field_swap(field, struct_ref_name): +def generate_j2c_field_swap(field, struct_ref_name, is_alias): if is_array(field): - return _generate_j2c_array_swap(field, struct_ref_name) + return _generate_j2c_array_swap(field, struct_ref_name, is_alias) else: - return _generate_j2c_scalar_swap(field, struct_ref_name) + return _generate_j2c_scalar_swap(field, struct_ref_name, is_alias) -def _generate_j2c_array_swap(field, struct_ref_name): +def _generate_j2c_array_swap(field, struct_ref_name, is_alias): # TODO(VPP-1186): move the logic to JNI generators base_type = field.type.base_type if isinstance(base_type, (Class, Enum, Union)): @@ -61,7 +61,7 @@ def _generate_j2c_array_swap(field, struct_ref_name): elif base_type.is_swap_needed: return _generate_j2c_primitive_type_array_swap(field, struct_ref_name) else: - return _generate_j2c_primitive_type_array_no_swap(field, struct_ref_name) + return _generate_j2c_primitive_type_array_no_swap(field, struct_ref_name, is_alias) def _generate_j2c_object_array_swap(field, struct_ref_name): @@ -119,9 +119,14 @@ _J2C_PRIMITIVE_TYPE_ARRAY_SWAP_TEMPLATE = Template(""" """) -def _generate_j2c_primitive_type_array_no_swap(field, struct_ref_name): +def _generate_j2c_primitive_type_array_no_swap(field, struct_ref_name, is_alias): field_type = field.type - return _J2C_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE.substitute( + if not is_alias: + template = _J2C_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE + else: + template = _J2C_ALIAS_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE + + return template.substitute( field_reference_name=field.java_name, field_length_check=_generate_field_length_check(field), base_type=field_type.base_type.jni_accessor, @@ -139,6 +144,15 @@ _J2C_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE = Template(""" """) +_J2C_ALIAS_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE = Template(""" + if (${field_reference_name}) { + jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name}); + ${field_length_check} + (*env)->Get${base_type}ArrayRegion(env, ${field_reference_name}, 0, cnt, (${jni_base_type} *)${struct_reference_name}); + } +""") + + def _generate_field_length_check(field): # Enforce max length if array has fixed length or uses variable length syntax field_length = str(field.array_len) @@ -157,17 +171,21 @@ _FIELD_LENGTH_CHECK = Template(""" if (cnt > max_size) cnt = max_size;""") -def _generate_j2c_scalar_swap(field, struct_ref_name): +def _generate_j2c_scalar_swap(field, struct_ref_name, is_alias): field_type = field.type if field_type.is_swap_needed: host = field.java_name - net = "%s->%s" % (struct_ref_name, field.name) - return " %s;" % field_type.get_host_to_net_function(host, net) + if not is_alias: + net = "%s->%s" % (struct_ref_name, field.name) + return " %s;" % field_type.get_host_to_net_function(host, net) + else: + net = "%s" % (struct_ref_name) + return " *%s;" % field_type.get_host_to_net_function(host, net) else: return " %s->%s = %s;" % (struct_ref_name, field.name, field.java_name) -def generate_c2j_swap(element, object_ref_name, struct_ref_name): +def generate_c2j_swap(element, object_ref_name, struct_ref_name, is_alias): msg_java_name = element.java_name_lower initialization = [] for field in element.fields: @@ -175,13 +193,13 @@ def generate_c2j_swap(element, object_ref_name, struct_ref_name): # For retval don't generate setters and generate retval check continue elif is_array(field): - initialization.append(_generate_c2j_array_swap(msg_java_name, field, object_ref_name, struct_ref_name)) + initialization.append(_generate_c2j_array_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias)) else: - initialization.append(_generate_c2j_scalar_swap(msg_java_name, field, object_ref_name, struct_ref_name)) + initialization.append(_generate_c2j_scalar_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias)) return "".join(initialization) -def _generate_c2j_array_swap(msg_java_name, field, object_ref_name, struct_ref_name): +def _generate_c2j_array_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias): # TODO(VPP-1186): move the logic to JNI generators base_type = field.type.base_type if isinstance(base_type, (Class, Union)): @@ -191,7 +209,7 @@ def _generate_c2j_array_swap(msg_java_name, field, object_ref_name, struct_ref_n elif base_type.is_swap_needed: return _generate_c2j_primitive_type_array_swap(msg_java_name, field, object_ref_name, struct_ref_name) else: - return _generate_c2j_primitive_type_array_no_swap(msg_java_name, field, object_ref_name, struct_ref_name) + return _generate_c2j_primitive_type_array_no_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias) def _generate_c2j_object_array_swap(msg_java_name, field, object_ref_name, struct_ref_name): @@ -294,9 +312,13 @@ _C2J_PRIMITIVE_TYPE_ARRAY_SWAP_TEMPLATE = Template(""" """) -def _generate_c2j_primitive_type_array_no_swap(msg_java_name, field, object_ref_name, struct_ref_name): +def _generate_c2j_primitive_type_array_no_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias): field_type = field.type - return _C2J_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE.substitute( + if not is_alias: + template = _C2J_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE + else: + template = _C2J_ALIAS_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE + return template.substitute( field_reference_name=field.java_name, class_ref_name=msg_java_name, jni_signature=field_type.jni_signature, @@ -318,6 +340,15 @@ _C2J_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE = Template(""" """) +_C2J_ALIAS_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE = Template(""" + jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}"); + ${jni_type} ${field_reference_name} = (*env)->New${base_type}Array(env, ${field_length}); + (*env)->Set${base_type}ArrayRegion(env, ${field_reference_name}, 0, ${field_length}, (const ${jni_base_type}*)${struct_ref_name}); + (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name}); + (*env)->DeleteLocalRef(env, ${field_reference_name}); +""") + + def _generate_array_length(field, struct_ref_name): if field.array_len_field: len_field = field.array_len_field @@ -328,7 +359,7 @@ def _generate_array_length(field, struct_ref_name): return field.array_len -def _generate_c2j_scalar_swap(msg_java_name, field, object_ref_name, struct_ref_name): +def _generate_c2j_scalar_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias): field_type = field.type if field_type.is_swap_needed: # TODO(VPP-1186): move the logic to JNI generators @@ -337,7 +368,7 @@ def _generate_c2j_scalar_swap(msg_java_name, field, object_ref_name, struct_ref_ elif isinstance(field_type, Enum): return _generate_c2j_enum_swap(msg_java_name, field, object_ref_name, struct_ref_name) else: - return _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, struct_ref_name) + return _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias) else: return _generate_c2j_primitive_type_no_swap(msg_java_name, field, object_ref_name, struct_ref_name) @@ -390,9 +421,13 @@ _C2J_ENUM_SWAP_TEMPLATE = Template(""" """) -def _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, struct_ref_name): +def _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias): field_type = field.type - return _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE.substitute( + if not is_alias: + template = _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE + else: + template = _C2J_ALIAS_PRIMITIVE_TYPE_SWAP_TEMPLATE + return template.substitute( java_name=field.java_name, class_ref_name=msg_java_name, jni_signature=field_type.jni_signature, @@ -409,6 +444,12 @@ _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE = Template(""" """) +_C2J_ALIAS_PRIMITIVE_TYPE_SWAP_TEMPLATE = Template(""" + jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}"); + (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${net_to_host_function}(*${struct_ref_name})); +""") + + def _generate_c2j_primitive_type_no_swap(msg_java_name, field, object_ref_name, struct_ref_name): field_type = field.type return _C2J_PRIMITIVE_TYPE_NO_SWAP_TEMPLATE.substitute( diff --git a/extras/japi/java/jvpp/gen/jvppgen/jni_impl_gen.py b/extras/japi/java/jvpp/gen/jvppgen/jni_impl_gen.py index bf7523670a4..717a42c452a 100755 --- a/extras/japi/java/jvpp/gen/jvppgen/jni_impl_gen.py +++ b/extras/japi/java/jvpp/gen/jvppgen/jni_impl_gen.py @@ -43,7 +43,7 @@ def generate_jni_impl(model): java_dto_name=msg.java_name_upper ) jni_identifiers = generate_j2c_identifiers(msg, class_ref_name="requestClass", object_ref_name="request") - msg_initialization = generate_j2c_swap(msg, struct_ref_name="mp") + msg_initialization = generate_j2c_swap(msg, struct_ref_name="mp", is_alias=False) jni_impl.append(_JNI_IMPL_TEMPLATE.substitute( c_name=msg.name, diff --git a/extras/japi/java/jvpp/gen/jvppgen/jni_msg_handlers_gen.py b/extras/japi/java/jvpp/gen/jvppgen/jni_msg_handlers_gen.py index 8f6410f1af2..5f274a3e1dd 100755 --- a/extras/japi/java/jvpp/gen/jvppgen/jni_msg_handlers_gen.py +++ b/extras/japi/java/jvpp/gen/jvppgen/jni_msg_handlers_gen.py @@ -41,7 +41,7 @@ def generate_jni_handlers(model): err_handler=_generate_error_handler(msg), class_ref_name=msg.java_name_lower, dto_name=msg.java_name_upper, - dto_setters=generate_c2j_swap(msg, object_ref_name="dto", struct_ref_name="mp") + dto_setters=generate_c2j_swap(msg, object_ref_name="dto", struct_ref_name="mp", is_alias=False) )) return "".join(jni_impl) diff --git a/extras/japi/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py b/extras/japi/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py index 2447974d878..59aaf95065a 100755 --- a/extras/japi/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py +++ b/extras/japi/java/jvpp/gen/jvppgen/jni_type_handlers_gen.py @@ -42,6 +42,11 @@ def generate_type_handlers(model, logger): def _generate_class(model, t, type_handlers): ref_name = t.java_name_lower + if t.name in model._aliases: + is_alias = True + else: + is_alias = False + type_handlers.append(_TYPE_HOST_TO_NET_TEMPLATE.substitute( c_name=t.name, json_filename=model.json_api_files, @@ -49,7 +54,7 @@ def _generate_class(model, t, type_handlers): type_reference_name=ref_name, class_FQN=t.jni_name, jni_identifiers=generate_j2c_identifiers(t, class_ref_name="%sClass" % ref_name, object_ref_name="_host"), - type_swap=generate_j2c_swap(t, struct_ref_name="_net") + type_swap=generate_j2c_swap(t, struct_ref_name="_net", is_alias=is_alias) )) type_handlers.append(_TYPE_NET_TO_HOST_TEMPLATE.substitute( c_name=t.name, @@ -57,7 +62,7 @@ def _generate_class(model, t, type_handlers): json_definition=t.doc, type_reference_name=ref_name, class_FQN=t.jni_name, - type_swap=generate_c2j_swap(t, object_ref_name="_host", struct_ref_name="_net") + type_swap=generate_c2j_swap(t, object_ref_name="_host", struct_ref_name="_net", is_alias=is_alias) )) _TYPE_HOST_TO_NET_TEMPLATE = Template(""" @@ -159,13 +164,17 @@ def _generate_union_host_to_net(model, t): swap = [] for i, field in enumerate(t.fields): field_type = field.type + if t.name in model._aliases: + is_alias = True + else: + is_alias = False swap.append(_UNION_FIELD_HOST_TO_NET_TEMPLATE.substitute( field_index=i, java_name=field.java_name, jni_signature=field_type.jni_signature, jni_type=field_type.jni_type, jni_accessor=field_type.jni_accessor, - swap=generate_j2c_field_swap(field, struct_ref_name="_net") + swap=generate_j2c_field_swap(field, struct_ref_name="_net", is_alias=is_alias) )) return _UNION_HOST_TO_NET_TEMPLATE.substitute( @@ -200,13 +209,17 @@ $swap def _generate_union_net_to_host(model, t): + if t.name in model._aliases: + is_alias = True + else: + is_alias = False return _UNION_NET_TO_HOST_TEMPLATE.substitute( c_name=t.name, json_filename=model.json_api_files, json_definition=t.doc, type_reference_name=t.java_name_lower, class_FQN=t.jni_name, - swap=generate_c2j_swap(t, object_ref_name="_host", struct_ref_name="_net") + swap=generate_c2j_swap(t, object_ref_name="_host", struct_ref_name="_net", is_alias=is_alias) ) _UNION_NET_TO_HOST_TEMPLATE = Template(""" diff --git a/extras/japi/java/jvpp/gen/jvppgen/jvpp_model.py b/extras/japi/java/jvpp/gen/jvppgen/jvpp_model.py index 3c2db15d176..16099689880 100755 --- a/extras/japi/java/jvpp/gen/jvppgen/jvpp_model.py +++ b/extras/japi/java/jvpp/gen/jvppgen/jvpp_model.py @@ -17,6 +17,8 @@ import json import pprint from collections import OrderedDict +import binascii + BASE_PACKAGE = "io.fd.vpp.jvpp" @@ -303,6 +305,11 @@ def is_control_ping_reply(msg): return msg.name == u'control_ping_reply' +def crc(block): + s = str(block).encode() + return binascii.crc32(s) & 0xffffffff + + class JVppModel(object): def __init__(self, logger, json_api_files, plugin_name): self.logger = logger @@ -333,8 +340,43 @@ class JVppModel(object): self._parse_types(types) + def _parse_aliases(self, types): + for alias_name in self._aliases: + alias = self._aliases[alias_name] + alias_type = {"type": "type"} + java_name_lower = _underscore_to_camelcase_lower(alias_name) + vpp_type = alias["type"] + crc_value = '0x%08x' % crc(alias_name) + if "length" in alias: + length = alias["length"] + alias_type["data"] = [ + alias_name, + [ + vpp_type, + java_name_lower, + length + ], + { + "crc": crc_value + } + ] + else: + alias_type["data"] = [ + alias_name, + [ + vpp_type, + java_name_lower + ], + { + "crc": crc_value + } + ] + + types[alias_name] = alias_type + def _parse_types(self, types): self._parse_simple_types() + self._parse_aliases(types) i = 0 while True: unresolved = {} @@ -484,9 +526,6 @@ class JVppModel(object): def _parse_field(self, field, fields): type_name = _extract_type_name(field[0]) - if type_name in self._aliases and type_name not in self._types_by_name: - aliased_type = self._types_by_name.get(self._aliases.get(type_name).get("type")) - self._types_by_name[type_name] = aliased_type if type_name in self._types_by_name: if len(field) > 2: @@ -524,6 +563,7 @@ class JVppModel(object): self.messages = self._messages_by_name.values() + _ARRAY_SUFFIX = '[]' -- 2.16.6