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
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):
44 for field in element.fields:
46 initialization.append(_generate_j2c_array_swap(field, struct_ref_name))
48 initialization.append(_generate_j2c_scalar_swap(field, struct_ref_name))
50 return "\n".join(initialization)
53 def _generate_j2c_array_swap(field, struct_ref_name):
54 # TODO(VPP-1186): move the logic to JNI generators
55 base_type = field.type.base_type
56 if isinstance(base_type, Class) or isinstance(base_type, Enum):
57 return _generate_j2c_object_array_swap(field, struct_ref_name)
58 elif base_type.is_swap_needed:
59 return _generate_j2c_primitive_type_array_swap(field, struct_ref_name)
61 return _generate_j2c_primitive_type_array_no_swap(field, struct_ref_name)
64 def _generate_j2c_object_array_swap(field, struct_ref_name):
65 field_type = field.type
66 field_reference_name = field.java_name
68 host = "%sArrayElement" % field_reference_name
69 net = "%s->%s[_i]" % (struct_ref_name, c_name)
70 swap_elements = field_type.get_host_to_net_function(host, net)
71 return _J2C_OBJECT_ARRAY_SWAP_TEMPLATE.substitute(
72 field_reference_name=field_reference_name,
73 field_length_check=_generate_field_length_check(field),
74 swap_elements=swap_elements)
76 _J2C_OBJECT_ARRAY_SWAP_TEMPLATE = Template("""
78 if (${field_reference_name}) {
80 jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
82 for (_i = 0; _i < cnt; _i++) {
83 jobject ${field_reference_name}ArrayElement = (*env)->GetObjectArrayElement(env, ${field_reference_name}, _i);
91 def _generate_j2c_primitive_type_array_swap(field, struct_ref_name):
92 field_reference_name = field.java_name
93 field_type = field.type
94 host = "%sArrayElements[_i]" % field_reference_name
95 net = "%s->%s[_i]" % (struct_ref_name, field.name)
96 swap_elements = field_type.get_host_to_net_function(host, net)
97 return _J2C_PRIMITIVE_TYPE_ARRAY_SWAP_TEMPLATE.substitute(
98 field_reference_name=field_reference_name,
99 field_length_check=_generate_field_length_check(field),
100 base_type=field_type.base_type.jni_accessor,
101 jni_base_type=field_type.base_type.jni_type,
102 swap_elements=swap_elements
105 _J2C_PRIMITIVE_TYPE_ARRAY_SWAP_TEMPLATE = Template("""
106 if (${field_reference_name}) {
107 ${jni_base_type} * ${field_reference_name}ArrayElements = (*env)->Get${base_type}ArrayElements(env, ${field_reference_name}, NULL);
109 jsize cnt = (*env)->GetArrayLength(env, ${field_reference_name});
110 ${field_length_check}
111 for (_i = 0; _i < cnt; _i++) {
114 (*env)->Release${base_type}ArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
119 def _generate_j2c_primitive_type_array_no_swap(field, struct_ref_name):
120 field_type = field.type
121 return _J2C_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE.substitute(
122 field_reference_name=field.java_name,
123 field_length_check=_generate_field_length_check(field),
124 base_type=field_type.base_type.jni_accessor,
125 jni_base_type=field_type.base_type.jni_type,
126 struct_reference_name=struct_ref_name,
130 _J2C_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE = Template("""
131 if (${field_reference_name}) {
132 jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
133 ${field_length_check}
134 (*env)->Get${base_type}ArrayRegion(env, ${field_reference_name}, 0, cnt, (${jni_base_type} *)${struct_reference_name}->${c_name});
139 def _generate_field_length_check(field):
140 # Enforce max length if array has fixed length or uses variable length syntax
141 field_length = str(field.array_len)
142 if field.array_len_field:
143 field_length = field.array_len_field.java_name
145 # TODO: remove when ZLAs without length field are disabled
146 if field_length != "0":
147 return _FIELD_LENGTH_CHECK.substitute(field_length=field_length)
151 # Make sure we do not write more elements that are expected
152 _FIELD_LENGTH_CHECK = Template("""
153 size_t max_size = ${field_length};
154 if (cnt > max_size) cnt = max_size;""")
157 def _generate_j2c_scalar_swap(field, struct_ref_name):
158 field_type = field.type
159 if field_type.is_swap_needed:
160 host = field.java_name
161 net = "%s->%s" % (struct_ref_name, field.name)
162 return " %s;" % field_type.get_host_to_net_function(host, net)
164 return " %s->%s = %s;" % (struct_ref_name, field.name, field.java_name)
167 def generate_c2j_swap(element, object_ref_name, struct_ref_name):
168 msg_java_name = element.java_name_lower
170 for field in element.fields:
172 # For retval don't generate setters and generate retval check
174 elif is_array(field):
175 initialization.append(_generate_c2j_array_swap(msg_java_name, field, object_ref_name, struct_ref_name))
177 initialization.append(_generate_c2j_scalar_swap(msg_java_name, field, object_ref_name, struct_ref_name))
178 return "".join(initialization)
181 def _generate_c2j_array_swap(msg_java_name, field, object_ref_name, struct_ref_name):
182 # TODO(VPP-1186): move the logic to JNI generators
183 base_type = field.type.base_type
184 if isinstance(base_type, Class):
185 return _generate_c2j_class_array_swap(msg_java_name, field, object_ref_name, struct_ref_name)
186 elif isinstance(base_type, Enum):
187 return _generate_c2j_enum_array_swap(msg_java_name, field, object_ref_name, struct_ref_name)
188 elif base_type.is_swap_needed:
189 return _generate_c2j_primitive_type_array_swap(msg_java_name, field, object_ref_name, struct_ref_name)
191 return _generate_c2j_primitive_type_array_no_swap(msg_java_name, field, object_ref_name, struct_ref_name)
194 def _generate_c2j_class_array_swap(msg_java_name, field, object_ref_name, struct_ref_name):
195 field_type = field.type
196 return _C2J_CLASS_ARRAY_SWAP_TEMPLATE.substitute(
197 field_reference_name=field.java_name,
198 class_ref_name=msg_java_name,
199 jni_signature=field_type.jni_signature,
200 jni_name=field_type.base_type.jni_name,
201 field_length=_generate_array_length(field, struct_ref_name),
202 net_to_host_function=field_type.net_to_host_function,
203 struct_ref_name=struct_ref_name,
204 object_ref_name=object_ref_name,
208 _C2J_CLASS_ARRAY_SWAP_TEMPLATE = Template("""
209 jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
211 jclass ${field_reference_name}Class = (*env)->FindClass(env, "${jni_name}");
212 jobjectArray ${field_reference_name} = (*env)->NewObjectArray(env, ${field_length}, ${field_reference_name}Class, 0);
213 jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "<init>", "()V");
215 for (_i = 0; _i < ${field_length}; _i++) {
216 jobject ${field_reference_name}ArrayElement = (*env)->NewObject(env, ${field_reference_name}Class, ${field_reference_name}Constructor);
217 ${net_to_host_function}(env, &(${struct_ref_name}->${c_name}[_i]), ${field_reference_name}ArrayElement);
218 (*env)->SetObjectArrayElement(env, ${field_reference_name}, _i, ${field_reference_name}ArrayElement);
219 (*env)->DeleteLocalRef(env, ${field_reference_name}ArrayElement);
221 (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
222 (*env)->DeleteLocalRef(env, ${field_reference_name});
227 def _generate_c2j_enum_array_swap(msg_java_name, field, object_ref_name, struct_ref_name):
228 field_type = field.type
229 base_type = field_type.base_type
230 return _C2J_ENUM_ARRAY_SWAP_TEMPLATE.substitute(
231 field_reference_name=field.java_name,
232 class_ref_name=msg_java_name,
233 jni_signature=field_type.jni_signature,
234 jni_name=base_type.jni_name,
235 field_length=_generate_array_length(field, struct_ref_name),
236 net_to_host_function=field_type.net_to_host_function,
237 jni_signature_enum_value=base_type.value.type.jni_signature,
238 struct_ref_name=struct_ref_name,
239 object_ref_name=object_ref_name,
243 _C2J_ENUM_ARRAY_SWAP_TEMPLATE = Template("""
244 jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
246 jclass ${field_reference_name}Class = (*env)->FindClass(env, "${jni_name}");
247 jobjectArray ${field_reference_name} = (*env)->NewObjectArray(env, ${field_length}, ${field_reference_name}Class, 0);
248 jmethodID ${field_reference_name}Constructor = (*env)->GetStaticMethodID(env, ${field_reference_name}Class, "forValue", "(${jni_signature_enum_value})${jni_signature}");
250 for (_i = 0; _i < ${field_length}; _i++) {
251 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]));
252 (*env)->SetObjectArrayElement(env, ${field_reference_name}, _i, ${field_reference_name}ArrayElement);
253 (*env)->DeleteLocalRef(env, ${field_reference_name}ArrayElement);
255 (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
256 (*env)->DeleteLocalRef(env, ${field_reference_name});
261 def _generate_c2j_primitive_type_array_swap(msg_java_name, field, object_ref_name, struct_ref_name):
262 field_type = field.type
263 return _C2J_PRIMITIVE_TYPE_ARRAY_SWAP_TEMPLATE.substitute(
264 field_reference_name=field.java_name,
265 class_ref_name=msg_java_name,
266 jni_signature=field_type.jni_signature,
267 jni_type=field_type.jni_type,
268 base_type=field_type.base_type.jni_accessor,
269 field_length=_generate_array_length(field, struct_ref_name),
270 jni_base_type=field_type.base_type.jni_type,
271 object_ref_name=object_ref_name,
272 struct_ref_name=struct_ref_name,
273 net_to_host_function=field_type.net_to_host_function,
277 _C2J_PRIMITIVE_TYPE_ARRAY_SWAP_TEMPLATE = Template("""
278 jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
280 ${jni_type} ${field_reference_name} = (*env)->New${base_type}Array(env, ${field_length});
281 ${jni_base_type} * ${field_reference_name}ArrayElements = (*env)->Get${base_type}ArrayElements(env, ${field_reference_name}, NULL);
283 for (_i = 0; _i < ${field_length}; _i++) {
284 ${field_reference_name}ArrayElements[_i] = ${net_to_host_function}(${struct_ref_name}->${c_name}[_i]);
287 (*env)->Release${base_type}ArrayElements(env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
288 (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
289 (*env)->DeleteLocalRef(env, ${field_reference_name});
294 def _generate_c2j_primitive_type_array_no_swap(msg_java_name, field, object_ref_name, struct_ref_name):
295 field_type = field.type
296 return _C2J_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE.substitute(
297 field_reference_name=field.java_name,
298 class_ref_name=msg_java_name,
299 jni_signature=field_type.jni_signature,
300 jni_type=field_type.jni_type,
301 base_type=field_type.base_type.jni_accessor,
302 field_length=_generate_array_length(field, struct_ref_name),
303 jni_base_type=field_type.base_type.jni_type,
304 object_ref_name=object_ref_name,
305 struct_ref_name=struct_ref_name,
309 _C2J_PRIMITIVE_TYPE_ARRAY_NO_SWAP_TEMPLATE = Template("""
310 jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
311 ${jni_type} ${field_reference_name} = (*env)->New${base_type}Array(env, ${field_length});
312 (*env)->Set${base_type}ArrayRegion(env, ${field_reference_name}, 0, ${field_length}, (const ${jni_base_type}*)${struct_ref_name}->${c_name});
313 (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
314 (*env)->DeleteLocalRef(env, ${field_reference_name});
318 def _generate_array_length(field, struct_ref_name):
319 if field.array_len_field:
320 len_field = field.array_len_field
321 if len_field.type.is_swap_needed:
322 return "%s(%s->%s)" % (len_field.type.host_to_net_function, struct_ref_name, len_field.name)
324 return "%s->%s" % (struct_ref_name, len_field.name)
325 return field.array_len
328 def _generate_c2j_scalar_swap(msg_java_name, field, object_ref_name, struct_ref_name):
329 field_type = field.type
330 if field_type.is_swap_needed:
331 # TODO(VPP-1186): move the logic to JNI generators
332 if isinstance(field_type, Class):
333 return _generate_c2j_class_swap(msg_java_name, field, object_ref_name, struct_ref_name)
334 elif isinstance(field_type, Enum):
335 return _generate_c2j_enum_swap(msg_java_name, field, object_ref_name, struct_ref_name)
337 return _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, struct_ref_name)
339 return _generate_c2j_primitive_type_no_swap(msg_java_name, field, object_ref_name, struct_ref_name)
342 def _generate_c2j_class_swap(msg_java_name, field, object_ref_name, struct_ref_name):
343 field_type = field.type
344 return _C2J_CLASS_SWAP_TEMPLATE.substitute(
345 java_name=field.java_name,
346 class_ref_name=msg_java_name,
347 jni_signature=field_type.jni_signature,
348 jni_name=field_type.jni_name,
349 jni_accessor=field_type.jni_accessor,
350 object_ref_name=object_ref_name,
351 struct_ref_name=struct_ref_name,
352 net_to_host_function=field_type.net_to_host_function,
355 _C2J_CLASS_SWAP_TEMPLATE = Template("""
356 jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
357 jclass ${java_name}Class = (*env)->FindClass(env, "${jni_name}");
358 jmethodID ${java_name}Constructor = (*env)->GetMethodID(env, ${java_name}Class, "<init>", "()V");
359 jobject ${java_name} = (*env)->NewObject(env, ${java_name}Class, ${java_name}Constructor);
360 ${net_to_host_function}(env, &(${struct_ref_name}->${c_name}), ${java_name});
361 (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${java_name});
362 (*env)->DeleteLocalRef(env, ${java_name});
366 def _generate_c2j_enum_swap(msg_java_name, field, object_ref_name, struct_ref_name):
367 field_type = field.type
368 return _C2J_ENUM_SWAP_TEMPLATE.substitute(
369 java_name=field.java_name,
370 class_ref_name=msg_java_name,
371 jni_signature=field_type.jni_signature,
372 jni_signature_enum_value=field_type.value.type.jni_signature,
373 jni_name=field_type.jni_name,
374 jni_accessor=field_type.jni_accessor,
375 object_ref_name=object_ref_name,
376 struct_ref_name=struct_ref_name,
377 net_to_host_function=field_type.net_to_host_function,
380 _C2J_ENUM_SWAP_TEMPLATE = Template("""
381 jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
382 jclass ${java_name}Class = (*env)->FindClass(env, "${jni_name}");
383 jmethodID ${java_name}Constructor = (*env)->GetStaticMethodID(env, ${java_name}Class, "forValue", "(${jni_signature_enum_value})${jni_signature}");
384 jobject ${java_name} = (*env)->CallStaticObjectMethod(env, ${java_name}Class, ${java_name}Constructor, ${net_to_host_function}(${struct_ref_name}->${c_name}));
385 (*env)->SetObjectField(env, ${object_ref_name}, ${java_name}FieldId, ${java_name});
386 (*env)->DeleteLocalRef(env, ${java_name});
390 def _generate_c2j_primitive_type_swap(msg_java_name, field, object_ref_name, struct_ref_name):
391 field_type = field.type
392 return _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE.substitute(
393 java_name=field.java_name,
394 class_ref_name=msg_java_name,
395 jni_signature=field_type.jni_signature,
396 jni_accessor=field_type.jni_accessor,
397 object_ref_name=object_ref_name,
398 net_to_host_function=field_type.net_to_host_function,
399 struct_ref_name=struct_ref_name,
403 _C2J_PRIMITIVE_TYPE_SWAP_TEMPLATE = Template("""
404 jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
405 (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${net_to_host_function}(${struct_ref_name}->${c_name}));
409 def _generate_c2j_primitive_type_no_swap(msg_java_name, field, object_ref_name, struct_ref_name):
410 field_type = field.type
411 return _C2J_PRIMITIVE_TYPE_NO_SWAP_TEMPLATE.substitute(
412 java_name=field.java_name,
413 class_ref_name=msg_java_name,
414 jni_signature=field_type.jni_signature,
415 jni_accessor=field_type.jni_accessor,
416 object_ref_name=object_ref_name,
417 struct_ref_name=struct_ref_name,
421 _C2J_PRIMITIVE_TYPE_NO_SWAP_TEMPLATE = Template("""
422 jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
423 (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${struct_ref_name}->${c_name});