6f2995d4f8cd48dee0803e2c7242f8da4387aabe
[vpp.git] / src / vpp-api / java / jvpp / gen / jvppgen / jni_common_gen.py
1 #!/usr/bin/env python2
2 #
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:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
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.
15 #
16 from string import Template
17
18 from jvpp_model import is_array, Class, is_retval
19
20
21 def generate_j2c_identifiers(element, class_ref_name, object_ref_name):
22     identifiers = []
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
32         ))
33     return "".join(identifiers)
34
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);
38 """)
39
40
41 # TODO(VPP-1185): introduce host_to_net functions wrappers and simplify j2c and c2j swap generation
42 def generate_j2c_swap(element, struct_ref_name):
43     initialization = []
44     for field in element.fields:
45         field_type = field.type
46         if is_array(field):
47             template = _ARRAY_J2C_NO_SWAP_TEMPLATE
48             field_reference_name = field.java_name
49             c_name = field.name
50             swap_elements = None
51             jni_name = None
52             if field_type.is_swap_needed:
53                 template = _ARRAY_J2C_SWAP_TEMPLATE
54                 host = "%sArrayElements[_i]" % field_reference_name
55                 net = "%s->%s[_i]" % (struct_ref_name, c_name)
56                 swap_elements = field_type.get_host_to_net_function(host, net)
57             if isinstance(field_type.base_type, Class):
58                 jni_name = field_type.base_type.jni_name
59                 host = "%sArrayElement" % field_reference_name
60                 net = "%s->%s[_i]" % (struct_ref_name, c_name)
61                 swap_elements = field_type.get_host_to_net_function(host, net)
62                 template = _CLASS_ARRAY_J2C_TEMPLATE
63
64             initialization.append(template.substitute(
65                 field_reference_name=field_reference_name,
66                 field_length_check=_generate_field_length_check(field),
67                 base_type=field_type.base_type.jni_accessor,
68                 jni_base_type=field_type.base_type.jni_type,
69                 struct_reference_name=struct_ref_name,
70                 jni_name=jni_name,
71                 c_name=c_name,
72                 swap_elements=swap_elements
73             ))
74         else:
75             if field_type.is_swap_needed:
76                 host = field.java_name
77                 net = "%s->%s" % (struct_ref_name, field.name)
78                 initialization.append("    %s;" % field_type.get_host_to_net_function(host, net))
79             else:
80                 initialization.append("    %s->%s = %s;" % (struct_ref_name, field.name, field.java_name))
81
82     return "\n".join(initialization)
83
84 _ARRAY_J2C_NO_SWAP_TEMPLATE = Template("""
85     if (${field_reference_name}) {
86         jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
87         ${field_length_check}
88         (*env)->Get${base_type}ArrayRegion(env, ${field_reference_name}, 0, cnt, (${jni_base_type} *)${struct_reference_name}->${c_name});
89     }
90 """)
91
92 _ARRAY_J2C_SWAP_TEMPLATE = Template("""
93     if (${field_reference_name}) {
94         ${jni_base_type} * ${field_reference_name}ArrayElements = (*env)->Get${base_type}ArrayElements(env, ${field_reference_name}, NULL);
95         size_t _i;
96         jsize cnt = (*env)->GetArrayLength(env, ${field_reference_name});
97         ${field_length_check}
98         for (_i = 0; _i < cnt; _i++) {
99             ${swap_elements};
100         }
101         (*env)->Release${base_type}ArrayElements (env, ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
102     }
103     """)
104
105 _CLASS_ARRAY_J2C_TEMPLATE = Template("""
106     {
107         if (${field_reference_name}) {
108             size_t _i;
109             jsize cnt = (*env)->GetArrayLength (env, ${field_reference_name});
110             ${field_length_check}
111             for (_i = 0; _i < cnt; _i++) {
112                 jobject ${field_reference_name}ArrayElement = (*env)->GetObjectArrayElement(env, ${field_reference_name}, _i);
113                 ${swap_elements};
114             }
115         }
116     }
117 """)
118
119
120 def _generate_field_length_check(field):
121     # Enforce max length if array has fixed length or uses variable length syntax
122     field_length = str(field.array_len)
123     if field.array_len_field:
124         field_length = field.array_len_field.java_name
125
126     # TODO: remove when ZLAs without length field are disabled
127     if field_length != "0":
128         return _FIELD_LENGTH_CHECK.substitute(field_length=field_length)
129     else:
130         return ""
131
132 # Make sure we do not write more elements that are expected
133 _FIELD_LENGTH_CHECK = Template("""
134         size_t max_size = ${field_length};
135         if (cnt > max_size) cnt = max_size;""")
136
137
138 def generate_c2j_swap(element, object_ref_name, struct_ref_name):
139     msg_java_name = element.java_name_lower
140     setters = []
141     for field in element.fields:
142         field_type = field.type
143         if is_retval(field):
144             # For retval don't generate setters and generate retval check
145             continue
146         elif is_array(field):
147             jni_name = ""
148             template = _ARRAY_C2J_SWAP_TEMPLATE if field_type.is_swap_needed else _ARRAY_C2J_NO_SWAP_TEMPLATE
149             if isinstance(field_type.base_type, Class):
150                 template = _ARRAY_C2J_CLASS_SWAP_TEMPLATE
151                 jni_name = field_type.base_type.jni_name
152             setters.append(template.substitute(
153                 field_reference_name=field.java_name,
154                 class_ref_name=msg_java_name,
155                 jni_signature=field_type.jni_signature,
156                 jni_type=field_type.jni_type,
157                 jni_name=jni_name,
158                 base_type=field_type.base_type.jni_accessor,
159                 field_length=_generate_array_length(field, struct_ref_name),
160                 jni_base_type=field_type.base_type.jni_type,
161                 object_ref_name=object_ref_name,
162                 struct_ref_name=struct_ref_name,
163                 net_to_host_function=field_type.net_to_host_function,
164                 c_name=field.name
165             ))
166         else:
167             if field_type.is_swap_needed:
168                 template = _SIMPLE_TYPE_FIELD_SETTER_TEMPLATE
169                 jni_name = ""
170                 if isinstance(field_type, Class):
171                     template = _STRUCT_SETTER_TEMPLATE
172                     jni_name = field_type.jni_name
173                 setters.append(template.substitute(
174                     java_name=field.java_name,
175                     class_ref_name=msg_java_name,
176                     jni_signature=field_type.jni_signature,
177                     jni_name=jni_name,
178                     jni_accessor=field_type.jni_accessor,
179                     object_ref_name=object_ref_name,
180                     struct_ref_name=struct_ref_name,
181                     net_to_host_function=field_type.net_to_host_function,
182                     c_name=field.name
183                 ))
184             else:
185                 setters.append(_SIMPLE_TYPE_NO_SWAP_FIELD_SETTER_TEMPLATE.substitute(
186                     java_name=field.java_name,
187                     class_ref_name=msg_java_name,
188                     jni_signature=field_type.jni_signature,
189                     jni_accessor=field_type.jni_accessor,
190                     object_ref_name=object_ref_name,
191                     struct_ref_name=struct_ref_name,
192                     c_name=field.name
193                 ))
194     return "".join(setters)
195
196
197 _SIMPLE_TYPE_FIELD_SETTER_TEMPLATE = Template("""
198     jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
199     (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${net_to_host_function}(${struct_ref_name}->${c_name}));
200 """)
201
202 _STRUCT_SETTER_TEMPLATE = Template("""
203     jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
204     jclass ${java_name}Class = (*env)->FindClass(env, "${jni_name}");
205     jmethodID ${java_name}Constructor = (*env)->GetMethodID(env, ${java_name}Class, "<init>", "()V");
206     jobject ${java_name} = (*env)->NewObject(env, ${java_name}Class,  ${java_name}Constructor);
207     ${net_to_host_function}(env, &(${struct_ref_name}->${c_name}), ${java_name});
208     (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${java_name});
209     (*env)->DeleteLocalRef(env, ${java_name});
210 """)
211
212 _SIMPLE_TYPE_NO_SWAP_FIELD_SETTER_TEMPLATE = Template("""
213     jfieldID ${java_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${java_name}", "${jni_signature}");
214     (*env)->Set${jni_accessor}Field(env, ${object_ref_name}, ${java_name}FieldId, ${struct_ref_name}->${c_name});
215 """)
216
217 _ARRAY_C2J_NO_SWAP_TEMPLATE = Template("""
218     jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
219     ${jni_type} ${field_reference_name} = (*env)->New${base_type}Array(env, ${field_length});
220     (*env)->Set${base_type}ArrayRegion(env, ${field_reference_name}, 0, ${field_length}, (const ${jni_base_type}*)${struct_ref_name}->${c_name});
221     (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
222     (*env)->DeleteLocalRef(env, ${field_reference_name});
223 """)
224
225 _ARRAY_C2J_SWAP_TEMPLATE = Template("""
226     jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
227     {
228         ${jni_type} ${field_reference_name} = (*env)->New${base_type}Array(env, ${field_length});
229         ${jni_base_type} * ${field_reference_name}ArrayElements = (*env)->Get${base_type}ArrayElements(env, ${field_reference_name}, NULL);
230         unsigned int _i;
231         for (_i = 0; _i < ${field_length}; _i++) {
232             ${field_reference_name}ArrayElements[_i] = ${net_to_host_function}(${struct_ref_name}->${c_name}[_i]);
233         }
234
235         (*env)->Release${base_type}ArrayElements(env,  ${field_reference_name}, ${field_reference_name}ArrayElements, 0);
236         (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
237         (*env)->DeleteLocalRef(env, ${field_reference_name});
238     }
239 """)
240
241 _ARRAY_C2J_CLASS_SWAP_TEMPLATE = Template("""
242     jfieldID ${field_reference_name}FieldId = (*env)->GetFieldID(env, ${class_ref_name}Class, "${field_reference_name}", "${jni_signature}");
243     {
244         jclass ${field_reference_name}Class = (*env)->FindClass(env, "${jni_name}");
245         jobjectArray ${field_reference_name} = (*env)->NewObjectArray(env, ${field_length}, ${field_reference_name}Class, 0);
246         jmethodID ${field_reference_name}Constructor = (*env)->GetMethodID(env, ${field_reference_name}Class, "<init>", "()V");
247         unsigned int _i;
248         for (_i = 0; _i < ${field_length}; _i++) {
249             jobject ${field_reference_name}ArrayElement = (*env)->NewObject(env, ${field_reference_name}Class,  ${field_reference_name}Constructor);
250             ${net_to_host_function}(env, &(${struct_ref_name}->${c_name}[_i]), ${field_reference_name}ArrayElement);
251             (*env)->SetObjectArrayElement(env, ${field_reference_name}, _i, ${field_reference_name}ArrayElement);
252             (*env)->DeleteLocalRef(env, ${field_reference_name}ArrayElement);
253         }
254         (*env)->SetObjectField(env, ${object_ref_name}, ${field_reference_name}FieldId, ${field_reference_name});
255         (*env)->DeleteLocalRef(env, ${field_reference_name});
256     }
257 """)
258
259
260 def _generate_array_length(field, struct_ref_name):
261     if field.array_len_field:
262         len_field = field.array_len_field
263         if len_field.type.is_swap_needed:
264             return "%s(%s->%s)" % (len_field.type.host_to_net_function, struct_ref_name, len_field.name)
265         else:
266             return "%s->%s" % (struct_ref_name, len_field.name)
267     return field.array_len