3 # Copyright (c) 2018 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 from string import Template
18 from jvpp_model import is_array, is_retval, Class, Enum, Union
21 def generate_j2c_identifiers(element, class_ref_name, object_ref_name):
23 for field in element.fields:
24 field_type = field.type
25 identifiers.append(_REQUEST_FIELD_IDENTIFIER_TEMPLATE.substitute(
26 java_name=field.java_name,
27 class_ref_name=class_ref_name,
28 jni_signature=field_type.jni_signature,
29 jni_type=field_type.jni_type,
30 jni_accessor=field_type.jni_accessor,
31 object_ref_name=object_ref_name
33 return "".join(identifiers)
35 _REQUEST_FIELD_IDENTIFIER_TEMPLATE = Template("""
36 jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}, "${java_name}", "${jni_signature}");
37 ${jni_type} ${java_name} = (*env)->Get${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId);
41 # TODO(VPP-1187): do not inline JNI object creation inside message handlers to reduce number of special cases
42 def generate_j2c_swap(element, struct_ref_name, is_alias):
44 for field in element.fields:
45 initialization.append(generate_j2c_field_swap(field, struct_ref_name, is_alias))
46 return "\n".join(initialization)
49 def generate_j2c_field_swap(field, struct_ref_name, is_alias):
51 return _generate_j2c_array_swap(field, struct_ref_name, is_alias)
53 return _generate_j2c_scalar_swap(field, struct_ref_name, is_alias)
56 def _generate_j2c_array_swap(field, struct_ref_name, is_alias):
57 # TODO(VPP-1186): move the logic to JNI generators
58 base_type = field.type.base_type
59 if isinstance(base_type, (Class, Enum, Union)):
60 return _generate_j2c_object_array_swap(field, struct_ref_name)
61 elif base_type.is_swap_needed:
62 return _generate_j2c_primitive_type_array_swap(field, struct_ref_name)
64 return _generate_j2c_primitive_type_array_no_swap(field, struct_ref_name, is_alias)
67 def _generate_j2c_object_array_swap(field, struct_ref_name):
68 field_type = field.type
69 field_reference_name = field.java_name
71 host = "%sArrayElement" % field_reference_name
72 net = "%s->%s[_i]" % (struct_ref_name, c_name)
73 swap_elements = field_type.get_host_to_net_function(host, net)
74 return _J2C_OBJECT_ARRAY_SWAP_TEMPLATE.substitute(
75 field_reference_name=field_reference_name,
76 field_length_check=_generate_field_length_check(field),
77 swap_elements=swap_elements)
79 _J2C_OBJECT_ARRAY_SWAP_TEMPLATE = Template("""
81 if (${field_reference_name}) {
83 jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
85 for (_i = 0; _i < cnt; _i++) {
86 jobject ${field_reference_name}ArrayElement = (*env)->GetObjectArrayElement(env, ${field_reference_name}, _i);
94 def _generate_j2c_primitive_type_array_swap(field, struct_ref_name):
95 field_reference_name = field.java_name
96 field_type = field.type
97 host = "%sArrayElements[_i]" % field_reference_name
98 net = "%s->%s[_i]" % (struct_ref_name, field.name)
99 swap_elements = field_type.get_host_to_net_function(host, net)
100 return _J2C_PRIMITIVE_TYPE_ARRAY_SWAP_TEMPLATE.substitute(
101 field_reference_name=field_reference_name,
102 field_length_check=_generate_field_length_check(field),
103 base_type=field_type.base_type.jni_accessor,
104 jni_base_type=field_type.base_type.jni_type,
105 swap_elements=swap_elements
108 _J2C_PRIMITIVE_TYPE_ARRAY_SWAP_TEMPLATE = Template("""
109 if (${field_reference_name}) {
110 ${jni_base_type} * ${field_reference_name}ArrayElements = (*env)->Get${base_type}ArrayElements(env, ${field_reference_name}, NULL);
112 jsize cnt = (*env)->GetArrayLength(env, ${field_reference_name});
113 ${field_length_check}
114 for (_i = 0; _i < cnt; _i++) {
117 (*env)->Release${base_type}ArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
122 def _generate_j2c_primitive_type_array_no_swap(field, struct_ref_name, is_alias):
123 field_type = field.type
125 template = _J2C_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE
127 template = _J2C_ALIAS_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE
129 return template.substitute(
130 field_reference_name=field.java_name,
131 field_length_check=_generate_field_length_check(field),
132 base_type=field_type.base_type.jni_accessor,
133 jni_base_type=field_type.base_type.jni_type,
134 struct_reference_name=struct_ref_name,
138 _J2C_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE = Template("""
139 if (${field_reference_name}) {
140 jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
141 ${field_length_check}
142 (*env)->Get${base_type}ArrayRegion(env, ${field_reference_name}, 0, cnt, (${jni_base_type} *)${struct_reference_name}->${c_name});
147 _J2C_ALIAS_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE = Template("""
148 if (${field_reference_name}) {
149 jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
150 ${field_length_check}
151 (*env)->Get${base_type}ArrayRegion(env, ${field_reference_name}, 0, cnt, (${jni_base_type} *)${struct_reference_name});
156 def _generate_field_length_check(field):
157 # Enforce max length if array has fixed length or uses variable length syntax
158 field_length = str(field.array_len)
159 if field.array_len_field:
160 field_length = field.array_len_field.java_name
162 # TODO: remove when ZLAs without length field are disabled
163 if field_length != "0":
164 return _FIELD_LENGTH_CHECK.substitute(field_length=field_length)
169 # Make sure we do not write more elements that are expected
170 _FIELD_LENGTH_CHECK = Template("""
171 size_t max_size = ${field_length};
172 if (cnt > max_size) cnt = max_size;""")
175 def _generate_j2c_scalar_swap(field, struct_ref_name, is_alias):
176 field_type = field.type
177 if field_type.is_swap_needed:
178 host = field.java_name
180 net = "%s->%s" % (struct_ref_name, field.name)
181 if field_type.name == "string":
182 net = "%s->%s" % (struct_ref_name, field.name)
183 return " _host_to_net_%s(env, %s, (vl_api_string_t *) &%s);" % (field_type.name, host, net)
185 return " %s;" % field_type.get_host_to_net_function(host, net)
187 net = "%s" % struct_ref_name
188 return " *%s;" % field_type.get_host_to_net_function(host, net)
190 return " %s->%s = %s;" % (struct_ref_name, field.name, field.java_name)
193 def generate_c2j_swap(element, object_ref_name, struct_ref_name, is_alias):
194 msg_java_name = element.java_name_lower
196 for field in element.fields:
198 # For retval don't generate setters and generate retval check
200 elif is_array(field):
201 initialization.append(_generate_c2j_array_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias))
203 initialization.append(_generate_c2j_scalar_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias))
204 return "".join(initialization)
207 def _generate_c2j_array_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias):
208 # TODO(VPP-1186): move the logic to JNI generators
209 base_type = field.type.base_type
210 if isinstance(base_type, (Class, Union)):
211 return _generate_c2j_object_array_swap(msg_java_name, field, object_ref_name, struct_ref_name)
212 elif isinstance(base_type, Enum):
213 return _generate_c2j_enum_array_swap(msg_java_name, field, object_ref_name, struct_ref_name)
214 elif base_type.is_swap_needed:
215 return _generate_c2j_primitive_type_array_swap(msg_java_name, field, object_ref_name, struct_ref_name)
217 return _generate_c2j_primitive_type_array_no_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias)
220 def _generate_c2j_object_array_swap(msg_java_name, field, object_ref_name, struct_ref_name):
221 field_type = field.type
222 return _C2J_OBJECT_ARRAY_SWAP_TEMPLATE.substitute(
223 field_reference_name=field.java_name,
224 class_ref_name=msg_java_name,
225 jni_signature=field_type.jni_signature,
226 jni_name=field_type.base_type.jni_name,
227 field_length=_generate_array_length(field, struct_ref_name),
228 net_to_host_function=field_type.net_to_host_function,
229 struct_ref_name=struct_ref_name,
230 object_ref_name=object_ref_name,
234 _C2J_OBJECT_ARRAY_SWAP_TEMPLATE = Template("""
235 jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
237 jclass ${field_reference_name}Class = (*env)->FindClass(env, "${jni_name}");
238 jobjectArray ${field_reference_name} = (*env)->NewObjectArray(env, ${field_length}, ${field_reference_name}Class, 0);
239 jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "<init>", "()V");
241 for (_i = 0; _i < ${field_length}; _i++) {
242 jobject ${field_reference_name}ArrayElement = (*env)->NewObject(env, ${field_reference_name}Class, ${field_reference_name}Constructor);
243 ${net_to_host_function}(env, &(${struct_ref_name}->${c_name}[_i]), ${field_reference_name}ArrayElement);
244 (*env)->SetObjectArrayElement(env, ${field_reference_name}, _i, ${field_reference_name}ArrayElement);
245 (*env)->DeleteLocalRef(env, ${field_reference_name}ArrayElement);
247 (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
248 (*env)->DeleteLocalRef(env, ${field_reference_name});
253 def _generate_c2j_enum_array_swap(msg_java_name, field, object_ref_name, struct_ref_name):
254 field_type = field.type
255 base_type = field_type.base_type
256 return _C2J_ENUM_ARRAY_SWAP_TEMPLATE.substitute(
257 field_reference_name=field.java_name,
258 class_ref_name=msg_java_name,
259 jni_signature=field_type.jni_signature,
260 jni_name=base_type.jni_name,
261 field_length=_generate_array_length(field, struct_ref_name),
262 net_to_host_function=field_type.net_to_host_function,
263 jni_signature_enum_value=base_type.value.type.jni_signature,
264 struct_ref_name=struct_ref_name,
265 object_ref_name=object_ref_name,
269 _C2J_ENUM_ARRAY_SWAP_TEMPLATE = Template("""
270 jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
272 jclass ${field_reference_name}Class = (*env)->FindClass(env, "${jni_name}");
273 jobjectArray ${field_reference_name} = (*env)->NewObjectArray(env, ${field_length}, ${field_reference_name}Class, 0);
274 jmethodID ${field_reference_name}Constructor = (*env)->GetStaticMethodID(env, ${field_reference_name}Class, "forValue", "(${jni_signature_enum_value})${jni_signature}");
276 for (_i = 0; _i < ${field_length}; _i++) {
277 jobject ${field_reference_name}ArrayElement = (*env)->CallStaticObjectMethod(env, ${field_reference_name}Class, ${field_reference_name}Constructor, ${net_to_host_function}(${struct_ref_name}->${c_name}[_i]));
278 (*env)->SetObjectArrayElement(env, ${field_reference_name}, _i, ${field_reference_name}ArrayElement);
279 (*env)->DeleteLocalRef(env, ${field_reference_name}ArrayElement);
281 (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
282 (*env)->DeleteLocalRef(env, ${field_reference_name});
287 def _generate_c2j_primitive_type_array_swap(msg_java_name, field, object_ref_name, struct_ref_name):
288 field_type = field.type
289 return _C2J_PRIMITIVE_TYPE_ARRAY_SWAP_TEMPLATE.substitute(
290 field_reference_name=field.java_name,
291 class_ref_name=msg_java_name,
292 jni_signature=field_type.jni_signature,
293 jni_type=field_type.jni_type,
294 base_type=field_type.base_type.jni_accessor,
295 field_length=_generate_array_length(field, struct_ref_name),
296 jni_base_type=field_type.base_type.jni_type,
297 object_ref_name=object_ref_name,
298 struct_ref_name=struct_ref_name,
299 net_to_host_function=field_type.net_to_host_function,
303 _C2J_PRIMITIVE_TYPE_ARRAY_SWAP_TEMPLATE = Template("""
304 jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
306 ${jni_type} ${field_reference_name} = (*env)->New${base_type}Array(env, ${field_length});
307 ${jni_base_type} * ${field_reference_name}ArrayElements = (*env)->Get${base_type}ArrayElements(env, ${field_reference_name}, NULL);
309 for (_i = 0; _i < ${field_length}; _i++) {
310 ${field_reference_name}ArrayElements[_i] = ${net_to_host_function}(${struct_ref_name}->${c_name}[_i]);
313 (*env)->Release${base_type}ArrayElements(env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
314 (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
315 (*env)->DeleteLocalRef(env, ${field_reference_name});
320 def _generate_c2j_primitive_type_array_no_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias):
321 field_type = field.type
323 template = _C2J_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE
325 template = _C2J_ALIAS_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE
326 return template.substitute(
327 field_reference_name=field.java_name,
328 class_ref_name=msg_java_name,
329 jni_signature=field_type.jni_signature,
330 jni_type=field_type.jni_type,
331 base_type=field_type.base_type.jni_accessor,
332 field_length=_generate_array_length(field, struct_ref_name),
333 jni_base_type=field_type.base_type.jni_type,
334 object_ref_name=object_ref_name,
335 struct_ref_name=struct_ref_name,
339 _C2J_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE = Template("""
340 jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
341 ${jni_type} ${field_reference_name} = (*env)->New${base_type}Array(env, ${field_length});
342 (*env)->Set${base_type}ArrayRegion(env, ${field_reference_name}, 0, ${field_length}, (const ${jni_base_type}*)${struct_ref_name}->${c_name});
343 (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
344 (*env)->DeleteLocalRef(env, ${field_reference_name});
348 _C2J_ALIAS_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE = Template("""
349 jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
350 ${jni_type} ${field_reference_name} = (*env)->New${base_type}Array(env, ${field_length});
351 (*env)->Set${base_type}ArrayRegion(env, ${field_reference_name}, 0, ${field_length}, (const ${jni_base_type}*)${struct_ref_name});
352 (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
353 (*env)->DeleteLocalRef(env, ${field_reference_name});
357 def _generate_array_length(field, struct_ref_name):
358 if field.array_len_field:
359 len_field = field.array_len_field
360 if len_field.type.is_swap_needed:
361 return "%s(%s->%s)" % (len_field.type.host_to_net_function, struct_ref_name, len_field.name)
363 return "%s->%s" % (struct_ref_name, len_field.name)
364 return field.array_len
367 def _generate_c2j_scalar_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias):
368 field_type = field.type
369 if field_type.is_swap_needed:
370 # TODO(VPP-1186): move the logic to JNI generators
371 if isinstance(field_type, (Class, Union)):
372 return _generate_c2j_object_swap(msg_java_name, field, object_ref_name, struct_ref_name)
373 elif isinstance(field_type, Enum):
374 return _generate_c2j_enum_swap(msg_java_name, field, object_ref_name, struct_ref_name)
376 return _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias)
378 return _generate_c2j_primitive_type_no_swap(msg_java_name, field, object_ref_name, struct_ref_name)
381 def _generate_c2j_object_swap(msg_java_name, field, object_ref_name, struct_ref_name):
382 field_type = field.type
383 return _C2J_OBJECT_SWAP_TEMPLATE.substitute(
384 java_name=field.java_name,
385 class_ref_name=msg_java_name,
386 jni_signature=field_type.jni_signature,
387 jni_name=field_type.jni_name,
388 jni_accessor=field_type.jni_accessor,
389 object_ref_name=object_ref_name,
390 struct_ref_name=struct_ref_name,
391 net_to_host_function=field_type.net_to_host_function,
394 _C2J_OBJECT_SWAP_TEMPLATE = Template("""
395 jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
396 jclass ${java_name}Class = (*env)->FindClass(env, "${jni_name}");
397 jmethodID ${java_name}Constructor = (*env)->GetMethodID(env, ${java_name}Class, "<init>", "()V");
398 jobject ${java_name} = (*env)->NewObject(env, ${java_name}Class, ${java_name}Constructor);
399 ${net_to_host_function}(env, &(${struct_ref_name}->${c_name}), ${java_name});
400 (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${java_name});
401 (*env)->DeleteLocalRef(env, ${java_name});
405 def _generate_c2j_enum_swap(msg_java_name, field, object_ref_name, struct_ref_name):
406 field_type = field.type
407 return _C2J_ENUM_SWAP_TEMPLATE.substitute(
408 java_name=field.java_name,
409 class_ref_name=msg_java_name,
410 jni_signature=field_type.jni_signature,
411 jni_signature_enum_value=field_type.value.type.jni_signature,
412 jni_name=field_type.jni_name,
413 jni_accessor=field_type.jni_accessor,
414 object_ref_name=object_ref_name,
415 struct_ref_name=struct_ref_name,
416 net_to_host_function=field_type.net_to_host_function,
419 _C2J_ENUM_SWAP_TEMPLATE = Template("""
420 jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
421 jclass ${java_name}Class = (*env)->FindClass(env, "${jni_name}");
422 jmethodID ${java_name}Constructor = (*env)->GetStaticMethodID(env, ${java_name}Class, "forValue", "(${jni_signature_enum_value})${jni_signature}");
423 jobject ${java_name} = (*env)->CallStaticObjectMethod(env, ${java_name}Class, ${java_name}Constructor, ${net_to_host_function}(${struct_ref_name}->${c_name}));
424 (*env)->SetObjectField(env, ${object_ref_name}, ${java_name}FieldId, ${java_name});
425 (*env)->DeleteLocalRef(env, ${java_name});
429 def _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, struct_ref_name, is_alias):
430 field_type = field.type
432 if field_type.name == "string":
433 template = _C2J_STRING_TYPE_SWAP_TEMPLATE
435 template = _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE
437 template = _C2J_ALIAS_PRIMITIVE_TYPE_SWAP_TEMPLATE
438 return template.substitute(
439 java_name=field.java_name,
440 class_ref_name=msg_java_name,
441 jni_signature=field_type.jni_signature,
442 jni_accessor=field_type.jni_accessor,
443 object_ref_name=object_ref_name,
444 net_to_host_function=field_type.net_to_host_function,
445 struct_ref_name=struct_ref_name,
449 _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE = Template("""
450 jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
451 (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${net_to_host_function}(${struct_ref_name}->${c_name}));
455 _C2J_STRING_TYPE_SWAP_TEMPLATE = Template("""
456 jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
457 (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${net_to_host_function}(env, (const vl_api_string_t *) &${struct_ref_name}->${c_name}));
461 _C2J_ALIAS_PRIMITIVE_TYPE_SWAP_TEMPLATE = Template("""
462 jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
463 (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${net_to_host_function}(*${struct_ref_name}));
467 def _generate_c2j_primitive_type_no_swap(msg_java_name, field, object_ref_name, struct_ref_name):
468 field_type = field.type
469 return _C2J_PRIMITIVE_TYPE_NO_SWAP_TEMPLATE.substitute(
470 java_name=field.java_name,
471 class_ref_name=msg_java_name,
472 jni_signature=field_type.jni_signature,
473 jni_accessor=field_type.jni_accessor,
474 object_ref_name=object_ref_name,
475 struct_ref_name=struct_ref_name,
479 _C2J_PRIMITIVE_TYPE_NO_SWAP_TEMPLATE = Template("""
480 jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
481 (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${struct_ref_name}->${c_name});