Line data Source code
1 : /* valaccodemethodcallmodule.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : * Copyright (C) 2006-2008 Raffaele Sandrini
5 : *
6 : * This library is free software; you can redistribute it and/or
7 : * modify it under the terms of the GNU Lesser General Public
8 : * License as published by the Free Software Foundation; either
9 : * version 2.1 of the License, or (at your option) any later version.
10 :
11 : * This library is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 :
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this library; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 : *
20 : * Author:
21 : * Jürg Billeter <j@bitron.ch>
22 : * Raffaele Sandrini <raffaele@sandrini.ch>
23 : */
24 :
25 : using GLib;
26 :
27 2930 : public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
28 35129 : public override void visit_method_call (MethodCall expr) {
29 : // the bare function call
30 17572 : var ccall = new CCodeFunctionCall (get_cvalue (expr.call));
31 :
32 17572 : CCodeFunctionCall async_call = null;
33 17572 : CCodeFunctionCall finish_call = null;
34 :
35 17572 : Method m = null;
36 17572 : Delegate deleg = null;
37 : List<Parameter> params;
38 :
39 63042 : var ma = expr.call as MemberAccess;
40 :
41 17572 : var itype = expr.call.value_type;
42 17958 : params = itype.get_parameters ();
43 :
44 17572 : if (itype is MethodType) {
45 16799 : assert (ma != null);
46 16799 : m = ((MethodType) itype).method_symbol;
47 :
48 16799 : if (!get_ccode_simple_generics (m)) {
49 16763 : context.analyzer.check_type_arguments (ma);
50 : }
51 :
52 16799 : if (ma.inner != null && ma.inner.value_type is EnumValueType && ((EnumValueType) ma.inner.value_type).get_to_string_method() == m) {
53 : // Enum.VALUE.to_string()
54 5 : unowned Enum en = (Enum) ma.inner.value_type.type_symbol;
55 5 : ccall.call = new CCodeIdentifier (generate_enum_to_string_function (en));
56 16794 : } else if (context.profile == Profile.POSIX && ma.inner != null && ma.inner.value_type != null && ma.inner.value_type.type_symbol == string_type.type_symbol && ma.member_name == "printf") {
57 1 : ccall.call = new CCodeIdentifier (generate_string_printf_function ());
58 16793 : } else if (expr.is_constructv_chainup) {
59 2 : ccall.call = new CCodeIdentifier (get_ccode_constructv_name ((CreationMethod) m));
60 : }
61 869 : } else if (itype is SignalType) {
62 96 : var sig_type = (SignalType) itype;
63 96 : if (ma != null && ma.inner is BaseAccess && sig_type.signal_symbol.is_virtual) {
64 97 : m = sig_type.signal_symbol.default_handler;
65 : } else {
66 47973 : ccall = (CCodeFunctionCall) get_cvalue (expr.call);
67 : }
68 1185 : } else if (itype is ObjectType) {
69 : // constructor
70 508 : var cl = (Class) ((ObjectType) itype).type_symbol;
71 508 : m = cl.default_construction_method;
72 508 : generate_method_declaration (m, cfile);
73 508 : var real_name = get_ccode_real_name (m);
74 508 : if (expr.is_constructv_chainup) {
75 2 : real_name = get_ccode_constructv_name ((CreationMethod) m);
76 : }
77 508 : ccall = new CCodeFunctionCall (new CCodeIdentifier (real_name));
78 171 : } else if (itype is StructValueType) {
79 : // constructor
80 2 : var st = (Struct) ((StructValueType) itype).type_symbol;
81 2 : m = st.default_construction_method;
82 2 : generate_method_declaration (m, cfile);
83 2 : ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
84 167 : } else if (itype is DelegateType) {
85 167 : deleg = ((DelegateType) itype).delegate_symbol;
86 : }
87 :
88 17572 : var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
89 37982 : var out_arg_map = in_arg_map;
90 :
91 17572 : if (m != null && m.coroutine) {
92 : // async call
93 :
94 113 : async_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
95 113 : finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
96 :
97 113 : if (ma.inner is BaseAccess) {
98 2 : CCodeExpression? vcast = null;
99 2 : if (m.base_method != null) {
100 1 : unowned Class base_class = (Class) m.base_method.parent_symbol;
101 1 : vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
102 1 : ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
103 1 : } else if (m.base_interface_method != null) {
104 1 : unowned Interface base_iface = (Interface) m.base_interface_method.parent_symbol;
105 1 : vcast = get_this_interface_cexpression (base_iface);
106 : }
107 2 : if (vcast != null) {
108 2 : async_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m));
109 2 : finish_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_finish_vfunc_name (m));
110 : }
111 115 : } else if (m != null && get_ccode_no_wrapper (m) && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) {
112 10009 : var instance_value = ma.inner.target_value;
113 8 : if ((ma.member_name == "begin" || ma.member_name == "end") && ma.inner.symbol_reference == ma.symbol_reference) {
114 4 : var inner_ma = (MemberAccess) ma.inner;
115 8 : instance_value = inner_ma.inner.target_value;
116 : }
117 :
118 4 : CCodeExpression? vcast = null;
119 4 : if (m.parent_symbol is Class) {
120 2 : unowned Class base_class = (Class) m.parent_symbol;
121 2 : vcast = get_this_class_cexpression (base_class, instance_value);
122 2 : } else if (m.parent_symbol is Interface) {
123 2 : unowned Interface base_iface = (Interface) m.parent_symbol;
124 2 : vcast = get_this_interface_cexpression (base_iface, instance_value);
125 : }
126 8 : if (vcast != null) {
127 4 : async_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m));
128 4 : finish_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_finish_vfunc_name (m));
129 : }
130 : }
131 :
132 113 : if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
133 : // no finish call
134 98 : ccall = async_call;
135 98 : params = m.get_async_begin_parameters ();
136 64 : } else if (ma.member_name == "end" && ma.inner.symbol_reference == ma.symbol_reference) {
137 : // no async call
138 40 : ccall = finish_call;
139 40 : params = m.get_async_end_parameters ();
140 44 : } else if (!expr.is_yield_expression) {
141 : // same as .begin, backwards compatible to bindings without async methods
142 10 : ccall = async_call;
143 10 : params = m.get_async_begin_parameters ();
144 : } else {
145 78 : ccall = finish_call;
146 : // output arguments used separately
147 39 : out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
148 : // pass GAsyncResult stored in closure to finish function
149 39 : out_arg_map.set (get_param_pos (get_ccode_async_result_pos (m)), get_variable_cexpression ("_res_"));
150 : }
151 : }
152 :
153 17572 : if (m is CreationMethod && m.parent_symbol is Class) {
154 513 : if (context.profile == Profile.GOBJECT) {
155 513 : if (!((Class) m.parent_symbol).is_compact) {
156 500 : ccall.add_argument (get_variable_cexpression ("object_type"));
157 : }
158 : } else {
159 0 : ccall.add_argument (get_this_cexpression ());
160 : }
161 :
162 513 : if (!current_class.is_compact) {
163 500 : int type_param_index = 0;
164 505 : if (current_class != m.parent_symbol) {
165 : // chain up to base class
166 497 : foreach (DataType base_type in current_class.get_base_types ()) {
167 496 : if (base_type.type_symbol is Class) {
168 495 : List<TypeParameter> type_parameters = null;
169 495 : if (get_ccode_real_name (m) == "g_object_new") {
170 : // gobject-style chainup
171 312 : type_parameters = ((Class) base_type.type_symbol).get_type_parameters ();
172 312 : type_param_index += type_parameters.size;
173 : }
174 495 : add_generic_type_arguments (m, in_arg_map, base_type.get_type_arguments (), expr, true, type_parameters);
175 495 : break;
176 : }
177 : }
178 : } else {
179 : // chain up to other constructor in same class
180 10 : var cl = (Class) m.parent_symbol;
181 7 : foreach (TypeParameter type_param in cl.get_type_parameters ()) {
182 1 : in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier (get_ccode_type_id (type_param)));
183 1 : in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier (get_ccode_copy_function (type_param)));
184 1 : in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier (get_ccode_destroy_function (type_param)));
185 1 : type_param_index++;
186 : }
187 : }
188 500 : if (current_class.has_type_parameters () && get_ccode_real_name (m) == "g_object_new") {
189 : // gobject-style construction
190 49 : foreach (var type_param in current_class.get_type_parameters ()) {
191 17 : var type_param_name = type_param.name.ascii_down ().replace ("_", "-");
192 17 : in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeConstant ("\"%s-type\"".printf (type_param_name)));
193 17 : in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier (get_ccode_type_id (type_param)));
194 17 : in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("\"%s-dup-func\"".printf (type_param_name)));
195 17 : in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeIdentifier (get_ccode_copy_function (type_param)));
196 17 : in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.05), new CCodeConstant ("\"%s-destroy-func\"".printf (type_param_name)));
197 17 : in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeIdentifier (get_ccode_destroy_function (type_param)));
198 17 : type_param_index++;
199 : }
200 : }
201 16 : } else if (current_class.is_subtype_of (gsource_type)) {
202 : // g_source_new
203 :
204 3 : string class_prefix = get_ccode_lower_case_name (current_class);
205 3 : string prepare_func = "NULL";
206 3 : string check_func = "NULL";
207 20 : foreach (Method impl in current_class.get_methods ()) {
208 10 : if (!impl.overrides) {
209 3 : continue;
210 : }
211 22 : switch (impl.name) {
212 : case "prepare":
213 2 : prepare_func = "%s_real_prepare".printf (class_prefix);
214 2 : break;
215 : case "check":
216 2 : check_func = "%s_real_check".printf (class_prefix);
217 2 : break;
218 : default:
219 : break;
220 : }
221 : }
222 :
223 3 : var funcs = new CCodeDeclaration ("const GSourceFuncs");
224 3 : funcs.modifiers = CCodeModifiers.STATIC;
225 3 : funcs.add_declarator (new CCodeVariableDeclarator ("_source_funcs", new CCodeConstant ("{ %s, %s, %s_real_dispatch, %s_finalize, NULL, NULL}".printf (prepare_func, check_func, class_prefix, class_prefix))));
226 3 : ccode.add_statement (funcs);
227 :
228 3 : ccall.add_argument (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_source_funcs")), "GSourceFuncs *"));
229 :
230 3 : var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
231 3 : csizeof.add_argument (new CCodeIdentifier (get_ccode_name (current_class)));
232 3 : ccall.add_argument (csizeof);
233 10 : } else if (current_class.base_class != null && get_ccode_simple_generics (m)) {
234 3 : if (current_class != m.parent_symbol) {
235 3 : foreach (DataType base_type in current_class.get_base_types ()) {
236 3 : if (base_type.type_symbol is Class) {
237 3 : add_generic_type_arguments (m, in_arg_map, base_type.get_type_arguments (), expr);
238 3 : break;
239 : }
240 : }
241 : } else {
242 : // TODO: simple generics are only supported in bindings.
243 : }
244 : }
245 17059 : } else if (m is CreationMethod && m.parent_symbol is Struct) {
246 2 : ccall.add_argument (get_this_cexpression ());
247 17057 : } else if (m != null && m.has_type_parameters () && !get_ccode_has_generic_type_parameter (m) && !get_ccode_simple_generics (m) && (ccall != finish_call || expr.is_yield_expression)) {
248 : // generic method
249 : // don't add generic arguments for .end() calls
250 77 : add_generic_type_arguments (m, in_arg_map, ma.get_type_arguments (), expr);
251 : }
252 :
253 : // the complete call expression, might include casts, comma expressions, and/or assignments
254 17572 : CCodeExpression ccall_expr = ccall;
255 :
256 17584 : if (m is ArrayResizeMethod && context.profile != Profile.POSIX) {
257 12 : var array_type = (ArrayType) ma.inner.value_type;
258 12 : in_arg_map.set (get_param_pos (0), new CCodeIdentifier (get_ccode_name (array_type.element_type)));
259 17560 : } else if (m is ArrayMoveMethod) {
260 2 : requires_array_move = true;
261 17558 : } else if (m is ArrayCopyMethod) {
262 2 : expr.target_value = copy_value (ma.inner.target_value, expr);
263 2 : return;
264 : }
265 :
266 17570 : CCodeExpression instance = null;
267 17570 : if (m != null && m.is_async_callback) {
268 6 : if (current_method.closure) {
269 2 : var block = ((Method) m.parent_symbol).body;
270 2 : instance = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_");
271 : } else {
272 2 : instance = new CCodeIdentifier ("_data_");
273 : }
274 :
275 4 : in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
276 4 : out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
277 27537 : } else if (m != null && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) {
278 9971 : var instance_value = ma.inner.target_value;
279 10001 : if ((ma.member_name == "begin" || ma.member_name == "end") && ma.inner.symbol_reference == ma.symbol_reference) {
280 30 : var inner_ma = (MemberAccess) ma.inner;
281 60 : instance_value = inner_ma.inner.target_value;
282 : }
283 9971 : instance = get_cvalue_ (instance_value);
284 :
285 9971 : var st = m.parent_symbol as Struct;
286 209 : if (st != null && !st.is_simple_type ()) {
287 : // we need to pass struct instance by reference
288 48 : if (!get_lvalue (instance_value)) {
289 1 : instance_value = store_temp_value (instance_value, expr);
290 : }
291 48 : instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance_value));
292 : }
293 :
294 9971 : if (!m.coroutine) {
295 9915 : in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
296 56 : } else if (expr.is_yield_expression) {
297 24 : in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
298 24 : if (get_ccode_finish_instance (m)) {
299 24 : out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
300 : }
301 32 : } else if (ma.member_name != "end" || get_ccode_finish_instance (m)) {
302 30 : out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
303 30 : in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
304 : }
305 7599 : } else if (m != null && m.binding == MemberBinding.CLASS) {
306 4 : unowned Class cl = (Class) m.parent_symbol;
307 4 : var cast = get_this_class_cexpression (cl, ma.inner != null ? ma.inner.target_value : null);
308 4 : in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), cast);
309 4 : out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), cast);
310 : }
311 :
312 17570 : if (m != null && get_ccode_has_generic_type_parameter (m)) {
313 : // insert type argument for macros
314 50 : if (m.has_type_parameters ()) {
315 : // generic method
316 35 : int type_param_index = 0;
317 105 : foreach (var type_arg in ma.get_type_arguments ()) {
318 : // real structs are passed by reference for simple generics
319 35 : if (get_ccode_simple_generics (m) && type_arg.is_real_struct_type () && !type_arg.nullable && !(type_arg is PointerType)) {
320 2 : type_arg = new PointerType (type_arg);
321 : }
322 35 : in_arg_map.set (get_param_pos (get_ccode_generic_type_pos (m) + 0.01 * type_param_index), new CCodeIdentifier (get_ccode_name (type_arg)));
323 35 : type_param_index++;
324 : }
325 : } else {
326 : // method in generic type
327 15 : int type_param_index = 0;
328 45 : foreach (var type_arg in ma.inner.value_type.get_type_arguments ()) {
329 15 : in_arg_map.set (get_param_pos (get_ccode_generic_type_pos (m) + 0.01 * type_param_index), new CCodeIdentifier (get_ccode_name (type_arg)));
330 15 : type_param_index++;
331 : }
332 : }
333 : }
334 :
335 17572 : if (m is ArrayMoveMethod) {
336 2 : var array_type = (ArrayType) ma.inner.value_type;
337 2 : var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
338 2 : csizeof.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
339 2 : in_arg_map.set (get_param_pos (0.1), csizeof);
340 17568 : } else if (m is DynamicMethod) {
341 1 : emit_context.push_symbol (m);
342 1 : m.clear_parameters ();
343 1 : int param_nr = 1;
344 5 : foreach (Expression arg in expr.get_argument_list ()) {
345 2 : var unary = arg as UnaryExpression;
346 3 : if (unary != null && unary.operator == UnaryOperator.OUT) {
347 : // out argument
348 1 : var param = new Parameter ("param%d".printf (param_nr), unary.inner.value_type);
349 1 : param.direction = ParameterDirection.OUT;
350 1 : m.add_parameter (param);
351 1 : } else if (unary != null && unary.operator == UnaryOperator.REF) {
352 : // ref argument
353 0 : var param = new Parameter ("param%d".printf (param_nr), unary.inner.value_type);
354 0 : param.direction = ParameterDirection.REF;
355 0 : m.add_parameter (param);
356 : } else {
357 : // in argument
358 1 : m.add_parameter (new Parameter ("param%d".printf (param_nr), arg.value_type));
359 : }
360 2 : param_nr++;
361 : }
362 5 : foreach (Parameter param in m.get_parameters ()) {
363 2 : param.accept (this);
364 : }
365 1 : generate_dynamic_method_wrapper ((DynamicMethod) m);
366 1 : emit_context.pop_symbol ();
367 17567 : } else if (m is CreationMethod && context.profile == Profile.GOBJECT && m.parent_symbol is Class) {
368 513 : ccode.add_assignment (get_this_cexpression (), new CCodeCastExpression (ccall, get_ccode_name (current_class) + "*"));
369 :
370 518 : if (current_method.body.captured) {
371 : // capture self after setting it
372 5 : var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), expr.source_reference));
373 5 : ref_call.add_argument (get_this_cexpression ());
374 :
375 5 : ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (current_method.body))), "self"), ref_call);
376 : }
377 :
378 : //FIXME Only needed for non-"g_object_new" calls, if there is no property clash
379 532 : if (!current_class.is_compact && current_class.has_type_parameters ()) {
380 : /* type, dup func, and destroy func fields for generic types */
381 19 : var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
382 61 : foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
383 21 : var type = get_ccode_type_id (type_param);
384 21 : var dup_func = get_ccode_copy_function (type_param);
385 21 : var destroy_func = get_ccode_destroy_function (type_param);
386 21 : ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, type), new CCodeIdentifier (type));
387 21 : ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, dup_func), new CCodeIdentifier (dup_func));
388 21 : ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, destroy_func), new CCodeIdentifier (destroy_func));
389 : }
390 : }
391 : // object chainup can't be used as expression
392 513 : ccall_expr = null;
393 : }
394 :
395 17570 : bool ellipsis = false;
396 :
397 17570 : int i = 1;
398 : int arg_pos;
399 17570 : Iterator<Parameter> params_it = params.iterator ();
400 57828 : foreach (Expression arg in expr.get_argument_list ()) {
401 20129 : CCodeExpression cexpr = get_cvalue (arg);
402 :
403 20129 : var carg_map = in_arg_map;
404 :
405 20129 : Parameter? param = null;
406 20129 : if (params_it.next ()) {
407 19822 : param = params_it.get ();
408 19822 : ellipsis = param.params_array || param.ellipsis;
409 : }
410 :
411 40258 : if (param != null && !ellipsis) {
412 19087 : if (param.direction == ParameterDirection.OUT) {
413 512 : carg_map = out_arg_map;
414 : }
415 :
416 19087 : var unary = arg as UnaryExpression;
417 19275 : if (unary == null || unary.operator != UnaryOperator.OUT) {
418 19527 : if (get_ccode_array_length (param) && param.variable_type is ArrayType && !((ArrayType) param.variable_type).fixed_length) {
419 628 : var array_type = (ArrayType) param.variable_type;
420 628 : var length_ctype = get_ccode_array_length_type (param);
421 628 : if (unary != null && unary.operator == UnaryOperator.REF) {
422 13 : length_ctype = "%s*".printf (length_ctype);
423 : }
424 1896 : for (int dim = 1; dim <= array_type.rank; dim++) {
425 634 : var array_length_expr = new CCodeCastExpression (get_array_length_cexpression (arg, dim), length_ctype);
426 634 : carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), array_length_expr);
427 : }
428 18685 : } else if (get_ccode_delegate_target (param) && param.variable_type is DelegateType) {
429 414 : var deleg_type = (DelegateType) param.variable_type;
430 828 : if (deleg_type.delegate_symbol.has_target) {
431 : CCodeExpression delegate_target_destroy_notify;
432 414 : var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
433 414 : assert (delegate_target != null);
434 828 : if (get_ccode_type (param) == "GClosure*") {
435 : // one single GClosure parameter
436 2 : var closure_new = new CCodeFunctionCall (new CCodeIdentifier ("g_cclosure_new"));
437 2 : closure_new.add_argument (new CCodeCastExpression (cexpr, "GCallback"));
438 2 : closure_new.add_argument (delegate_target);
439 2 : closure_new.add_argument (new CCodeCastExpression (delegate_target_destroy_notify, "GClosureNotify"));
440 : //TODO Use get_non_null (arg.target_value)
441 2 : if (arg.is_non_null ()) {
442 2 : cexpr = closure_new;
443 : } else {
444 1 : cexpr = new CCodeConditionalExpression (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cexpr, new CCodeConstant ("NULL")), new CCodeConstant ("NULL"), closure_new);
445 : }
446 : } else {
447 : // Override previously given target/destroy only if it was NULL
448 : // TODO https://gitlab.gnome.org/GNOME/vala/issues/59
449 412 : var node = carg_map.get (get_param_pos (get_ccode_delegate_target_pos (param)));
450 412 : if (node == null || (node is CCodeConstant && ((CCodeConstant) node).name == "NULL")) {
451 408 : carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
452 408 : if (deleg_type.is_disposable ()) {
453 73 : assert (delegate_target_destroy_notify != null);
454 73 : carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), delegate_target_destroy_notify);
455 : }
456 : }
457 : }
458 : }
459 17857 : } else if (param.variable_type is MethodType) {
460 : // callbacks in dynamic method calls
461 : CCodeExpression delegate_target_destroy_notify;
462 0 : carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), get_delegate_target_cexpression (arg, out delegate_target_destroy_notify));
463 17857 : } else if (param.variable_type is GenericType) {
464 1009 : if (m != null && get_ccode_simple_generics (m)) {
465 1 : var generic_type = (GenericType) param.variable_type;
466 1 : int type_param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
467 1 : var type_arg = ma.get_type_arguments ().get (type_param_index);
468 1 : if (param.variable_type.value_owned) {
469 1 : if (requires_copy (type_arg)) {
470 1 : carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), get_destroy_func_expression (type_arg));
471 : } else {
472 0 : carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), new CCodeConstant ("NULL"));
473 : }
474 : }
475 : }
476 : }
477 :
478 18899 : cexpr = handle_struct_argument (param, arg, cexpr);
479 : } else {
480 188 : arg.target_value = null;
481 :
482 188 : var temp_var = get_temp_variable (param.variable_type, param.variable_type.value_owned, null, true);
483 188 : emit_temp_var (temp_var);
484 188 : set_cvalue (arg, get_variable_cexpression (temp_var.name));
485 188 : arg.target_value.value_type = arg.target_type;
486 :
487 188 : cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (arg));
488 :
489 203 : if (get_ccode_array_length (param) && param.variable_type is ArrayType && !((ArrayType) param.variable_type).fixed_length) {
490 15 : var array_type = (ArrayType) param.variable_type;
491 15 : var length_ctype = get_ccode_array_length_type (param);
492 53 : for (int dim = 1; dim <= array_type.rank; dim++) {
493 19 : var temp_array_length = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
494 19 : emit_temp_var (temp_array_length);
495 19 : append_array_length (arg, get_variable_cexpression (temp_array_length.name));
496 19 : carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_lengths (arg).get (dim - 1)));
497 : }
498 174 : } else if (get_ccode_delegate_target (param) && param.variable_type is DelegateType) {
499 1 : var deleg_type = (DelegateType) param.variable_type;
500 1 : if (deleg_type.delegate_symbol.has_target) {
501 1 : temp_var = get_temp_variable (delegate_target_type, true, null, true);
502 1 : emit_temp_var (temp_var);
503 1 : set_delegate_target (arg, get_variable_cexpression (temp_var.name));
504 1 : carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target (arg)));
505 1 : if (deleg_type.is_disposable ()) {
506 1 : temp_var = get_temp_variable (delegate_target_destroy_type, true, null, true);
507 1 : emit_temp_var (temp_var);
508 1 : set_delegate_target_destroy_notify (arg, get_variable_cexpression (temp_var.name));
509 1 : carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_destroy_notify (arg)));
510 : }
511 : }
512 172 : } else if (param.variable_type is GenericType) {
513 4 : set_cvalue (arg, convert_from_generic_pointer (get_cvalue (arg), arg.target_type));
514 : }
515 : }
516 :
517 19087 : if (get_ccode_type (param) != null) {
518 39 : cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
519 : }
520 : } else {
521 : // ellipsis arguments
522 1042 : var unary = arg as UnaryExpression;
523 1067 : if (ellipsis && unary != null && unary.operator == UnaryOperator.OUT) {
524 50 : carg_map = out_arg_map;
525 :
526 25 : arg.target_value = null;
527 :
528 : // infer type and ownership from argument expression
529 25 : var temp_var = get_temp_variable (arg.value_type, arg.value_type.value_owned, null, true);
530 25 : emit_temp_var (temp_var);
531 25 : set_cvalue (arg, get_variable_cexpression (temp_var.name));
532 25 : arg.target_value.value_type = arg.value_type;
533 :
534 25 : if (arg.value_type is DelegateType && ((DelegateType) arg.value_type).delegate_symbol.has_target) {
535 : // Initialize target/destroy cvalues to allow assignment of delegates from varargs
536 3 : unowned GLibValue arg_value = (GLibValue) arg.target_value;
537 3 : if (arg_value.delegate_target_cvalue == null) {
538 3 : arg_value.delegate_target_cvalue = new CCodeConstant ("NULL");
539 : }
540 3 : if (arg_value.delegate_target_destroy_notify_cvalue == null) {
541 3 : arg_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
542 : }
543 : }
544 :
545 25 : cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (arg));
546 : } else {
547 1017 : cexpr = handle_struct_argument (null, arg, cexpr);
548 : }
549 : }
550 :
551 20129 : if (itype is SignalType && ((SignalType) itype).signal_symbol is DynamicSignal) {
552 4 : arg_pos = get_param_pos (i, false);
553 : } else {
554 20125 : arg_pos = get_param_pos (param != null && !ellipsis ? get_ccode_pos (param) : i, ellipsis);
555 : }
556 20129 : carg_map.set (arg_pos, cexpr);
557 :
558 20130 : if (m is ArrayResizeMethod && context.profile == Profile.POSIX) {
559 1 : var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (((ArrayType) ma.inner.value_type).element_type)));
560 1 : carg_map.set (arg_pos, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cexpr));
561 : } else {
562 20128 : carg_map.set (arg_pos, cexpr);
563 : }
564 :
565 20141 : if (arg is NamedArgument && ellipsis) {
566 12 : var named_arg = (NamedArgument) arg;
567 36 : string name = string.joinv ("-", named_arg.name.split ("_"));
568 12 : carg_map.set (get_param_pos (i - 0.1, ellipsis), new CCodeConstant ("\"%s\"".printf (name)));
569 : }
570 :
571 20129 : i++;
572 : }
573 18083 : if (params_it.next ()) {
574 513 : var param = params_it.get ();
575 :
576 : /* if there are more parameters than arguments,
577 : * the additional parameter is an ellipsis parameter
578 : * otherwise there is a bug in the semantic analyzer
579 : */
580 513 : assert (param.params_array || param.ellipsis);
581 513 : ellipsis = true;
582 : }
583 :
584 : /* add length argument for methods returning arrays */
585 17756 : if (m != null && m.return_type is ArrayType && async_call != ccall) {
586 372 : var array_type = (ArrayType) m.return_type;
587 379 : for (int dim = 1; dim <= array_type.rank; dim++) {
588 260 : if (get_ccode_array_null_terminated (m) && !get_ccode_array_length (m)) {
589 : // handle calls to methods returning null-terminated arrays
590 67 : var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
591 67 : var temp_ref = get_variable_cexpression (temp_var.name);
592 :
593 67 : emit_temp_var (temp_var);
594 :
595 67 : ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
596 :
597 67 : requires_array_length = true;
598 67 : var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
599 67 : len_call.add_argument (temp_ref);
600 :
601 67 : append_array_length (expr, len_call);
602 246 : } else if (get_ccode_array_length (m)) {
603 120 : var length_ctype = get_ccode_array_length_type (m);
604 120 : var temp_var = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
605 120 : var temp_ref = get_variable_cexpression (temp_var.name);
606 :
607 120 : emit_temp_var (temp_var);
608 :
609 120 : out_arg_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
610 :
611 120 : append_array_length (expr, temp_ref);
612 6 : } else if (get_ccode_array_length_expr (m) != null) {
613 1 : append_array_length (expr, new CCodeConstant (get_ccode_array_length_expr (m)));
614 : } else {
615 5 : append_array_length (expr, new CCodeConstant ("-1"));
616 : }
617 : }
618 17397 : } else if (m != null && m.return_type is DelegateType && async_call != ccall) {
619 13 : var deleg_type = (DelegateType) m.return_type;
620 21 : if (get_ccode_delegate_target (m) && deleg_type.delegate_symbol.has_target) {
621 8 : var temp_var = get_temp_variable (delegate_target_type, true, null, true);
622 8 : var temp_ref = get_variable_cexpression (temp_var.name);
623 :
624 8 : emit_temp_var (temp_var);
625 :
626 8 : out_arg_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
627 :
628 8 : set_delegate_target (expr, temp_ref);
629 :
630 8 : if (deleg_type.is_disposable ()) {
631 6 : temp_var = get_temp_variable (delegate_target_destroy_type, true, null, true);
632 6 : temp_ref = get_variable_cexpression (temp_var.name);
633 :
634 6 : emit_temp_var (temp_var);
635 :
636 6 : out_arg_map.set (get_param_pos (get_ccode_destroy_notify_pos (m)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
637 :
638 6 : set_delegate_target_destroy_notify (expr, temp_ref);
639 : } else {
640 2 : set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
641 : }
642 : } else {
643 5 : set_delegate_target (expr, new CCodeConstant ("NULL"));
644 5 : if (deleg_type.delegate_symbol.has_target) {
645 4 : set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
646 : }
647 : }
648 : }
649 :
650 : // add length argument for delegates returning arrays
651 : // TODO: avoid code duplication with methods returning arrays, see above
652 17576 : if (deleg != null && deleg.return_type is ArrayType) {
653 12 : var array_type = (ArrayType) deleg.return_type;
654 12 : for (int dim = 1; dim <= array_type.rank; dim++) {
655 7 : if (get_ccode_array_null_terminated (deleg) && !get_ccode_array_length (deleg)) {
656 : // handle calls to methods returning null-terminated arrays
657 1 : var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
658 1 : var temp_ref = get_variable_cexpression (temp_var.name);
659 :
660 1 : emit_temp_var (temp_var);
661 :
662 1 : ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
663 :
664 1 : requires_array_length = true;
665 1 : var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
666 1 : len_call.add_argument (temp_ref);
667 :
668 1 : append_array_length (expr, len_call);
669 9 : } else if (get_ccode_array_length (deleg)) {
670 4 : var length_ctype = get_ccode_array_length_type (deleg);
671 4 : var temp_var = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
672 4 : var temp_ref = get_variable_cexpression (temp_var.name);
673 :
674 4 : emit_temp_var (temp_var);
675 :
676 4 : out_arg_map.set (get_param_pos (get_ccode_array_length_pos (deleg) + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
677 :
678 4 : append_array_length (expr, temp_ref);
679 : } else {
680 1 : append_array_length (expr, new CCodeConstant ("-1"));
681 : }
682 : }
683 17565 : } else if (deleg != null && deleg.return_type is DelegateType && get_ccode_delegate_target (deleg)) {
684 1 : var deleg_type = (DelegateType) deleg.return_type;
685 2 : if (deleg_type.delegate_symbol.has_target) {
686 1 : var temp_var = get_temp_variable (delegate_target_type, true, null, true);
687 1 : var temp_ref = get_variable_cexpression (temp_var.name);
688 :
689 1 : emit_temp_var (temp_var);
690 :
691 1 : out_arg_map.set (get_param_pos (get_ccode_delegate_target_pos (deleg)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
692 :
693 1 : set_delegate_target (expr, temp_ref);
694 :
695 1 : if (deleg_type.is_disposable ()) {
696 1 : temp_var = get_temp_variable (delegate_target_destroy_type, true, null, true);
697 1 : temp_ref = get_variable_cexpression (temp_var.name);
698 :
699 1 : emit_temp_var (temp_var);
700 :
701 1 : out_arg_map.set (get_param_pos (get_ccode_destroy_notify_pos (deleg)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
702 :
703 1 : set_delegate_target_destroy_notify (expr, temp_ref);
704 : }
705 : }
706 : }
707 :
708 17570 : if (m != null && m.coroutine) {
709 113 : if (expr.is_yield_expression) {
710 : // asynchronous call
711 39 : in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
712 39 : in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_data_"));
713 : }
714 : }
715 :
716 17570 : if (expr.tree_can_fail) {
717 : // method can fail
718 428 : current_method_inner_error = true;
719 : // add &inner_error before the ellipsis arguments
720 428 : out_arg_map.set (get_param_pos (get_ccode_error_pos ((Callable) m ?? deleg)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
721 17142 : } else if (m != null && m.has_error_type_parameter () && async_call != ccall) {
722 : // inferred error argument from base method
723 5 : out_arg_map.set (get_param_pos (get_ccode_error_pos (m)), new CCodeConstant ("NULL"));
724 : }
725 :
726 17570 : if (ellipsis) {
727 : /* ensure variable argument list ends with NULL
728 : * except when using printf-style arguments */
729 1248 : if (itype is SignalType) {
730 : // g_signal_emit*() does not require more
731 1246 : } else if (m == null) {
732 11 : in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
733 1235 : } else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "" && !expr.is_constructv_chainup) {
734 458 : in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
735 : }
736 : }
737 :
738 17694 : if (deleg != null && deleg.has_target) {
739 : CCodeExpression delegate_target_destroy_notify;
740 124 : in_arg_map.set (get_param_pos (get_ccode_instance_pos (deleg)), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
741 124 : out_arg_map.set (get_param_pos (get_ccode_instance_pos (deleg)), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
742 : }
743 :
744 : // structs are returned via out parameter
745 17570 : bool return_result_via_out_param = itype.get_return_type ().is_real_non_null_struct_type ();
746 :
747 : // pass address for the return value of non-void signals without emitter functions
748 17609 : if (itype is SignalType && !(itype.get_return_type () is VoidType)) {
749 39 : var sig = ((SignalType) itype).signal_symbol;
750 :
751 39 : if (ma != null && ma.inner is BaseAccess && sig.is_virtual) {
752 : // normal return value for base access
753 39 : } else if (!get_ccode_has_emitter (sig) || ma.source_reference.file == sig.source_reference.file) {
754 : return_result_via_out_param = true;
755 : }
756 : }
757 :
758 17570 : if (async_call == ccall) {
759 : // skip out parameter for .begin() calls
760 : return_result_via_out_param = false;
761 : }
762 :
763 17516 : CCodeExpression out_param_ref = null;
764 :
765 17582 : if (return_result_via_out_param) {
766 66 : var out_param_var = get_temp_variable (itype.get_return_type (), true, null, true);
767 66 : out_param_ref = get_variable_cexpression (out_param_var.name);
768 66 : emit_temp_var (out_param_var);
769 66 : out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, out_param_ref));
770 : }
771 :
772 : // append C arguments in the right order
773 :
774 : int last_pos;
775 : int min_pos;
776 :
777 17570 : if (async_call != ccall) {
778 : // don't append out arguments for .begin() calls
779 : last_pos = -1;
780 50316 : while (true) {
781 50316 : min_pos = -1;
782 223954 : foreach (int pos in out_arg_map.get_keys ()) {
783 123322 : if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
784 46228 : min_pos = pos;
785 : }
786 : }
787 50316 : if (min_pos == -1) {
788 : break;
789 : }
790 32800 : ccall.add_argument (out_arg_map.get (min_pos));
791 : last_pos = min_pos;
792 : }
793 : }
794 :
795 17570 : if (async_call != null) {
796 : last_pos = -1;
797 429 : while (true) {
798 429 : min_pos = -1;
799 2208 : foreach (int pos in in_arg_map.get_keys ()) {
800 1350 : if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
801 419 : min_pos = pos;
802 : }
803 : }
804 429 : if (min_pos == -1) {
805 : break;
806 : }
807 316 : async_call.add_argument (in_arg_map.get (min_pos));
808 : last_pos = min_pos;
809 : }
810 : }
811 :
812 17570 : if (expr.is_yield_expression) {
813 : // set state before calling async function to support immediate callbacks
814 39 : int state = emit_context.next_coroutine_state++;
815 :
816 39 : ccode.add_assignment (get_variable_cexpression ("_state_"), new CCodeConstant (state.to_string ()));
817 39 : ccode.add_expression (async_call);
818 39 : ccode.add_return (new CCodeConstant ("FALSE"));
819 39 : ccode.add_label ("_state_%d".printf (state));
820 : }
821 :
822 22004 : if (expr.is_assert) {
823 4434 : string message = ((string) expr.source_reference.begin.pos).substring (0, (int) (expr.source_reference.end.pos - expr.source_reference.begin.pos));
824 4434 : ccall.call = new CCodeIdentifier ("_vala_assert");
825 4434 : ccall.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
826 4434 : requires_assert = true;
827 :
828 : }
829 :
830 : // Transform and add free function argument to GLib.[List,Queue,SList].remove[_all] calls
831 17570 : unowned DataType? collection_type = null;
832 17570 : if (ma != null && ma.inner != null) {
833 16033 : collection_type = ma.inner.value_type;
834 : }
835 16057 : if (collection_type != null
836 10138 : && (collection_type.type_symbol == glist_type || collection_type.type_symbol == gslist_type || collection_type.type_symbol == gqueue_type)
837 112 : && (ma.member_name == "remove" || ma.member_name == "remove_all")
838 : //FIXME Perform stricter type argument check earlier
839 12 : && collection_type.check_type_arguments (context)) {
840 12 : var remove_method = (Method) collection_type.type_symbol.scope.lookup (ma.member_name + "_full");
841 12 : var type_arg = collection_type.get_type_arguments ()[0];
842 12 : if (remove_method != null && requires_destroy (type_arg)) {
843 : // only add them once per source file
844 6 : if (add_generated_external_symbol (remove_method)) {
845 6 : visit_method (remove_method);
846 : }
847 6 : ccall.call = new CCodeIdentifier (get_ccode_name (remove_method));
848 6 : ccall.add_argument (get_destroy0_func_expression (type_arg));
849 : }
850 : }
851 :
852 17570 : if (return_result_via_out_param) {
853 66 : ccode.add_expression (ccall_expr);
854 132 : ccall_expr = out_param_ref;
855 : }
856 :
857 17570 : if (m != null && m.binding == MemberBinding.INSTANCE && m.returns_modified_pointer) {
858 55 : if (ma != null && ma.inner.symbol_reference is Property && ma.inner is MemberAccess) {
859 1 : var prop = (Property) ma.inner.symbol_reference;
860 1 : store_property (prop, ((MemberAccess) ma.inner).inner, new GLibValue (expr.value_type, ccall_expr));
861 1 : ccall_expr = null;
862 : } else {
863 53 : ccall_expr = new CCodeAssignment (instance, ccall_expr);
864 : }
865 : }
866 :
867 : // real structs are passed by reference for simple generics
868 17605 : if (m != null && get_ccode_simple_generics (m) && m.return_type is GenericType
869 38 : && expr.value_type.is_real_struct_type () && !expr.value_type.nullable && !(expr.value_type is PointerType)) {
870 2 : ccall_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeParenthesizedExpression (ccall_expr));
871 : }
872 :
873 17570 : if (m != null && get_ccode_type (m) != null && get_ccode_type (m) != get_ccode_name (m.return_type)) {
874 : // Bug 699956: Implement cast for method return type if [CCode type=] annotation is specified
875 1 : ccall_expr = new CCodeCastExpression (ccall_expr, get_ccode_name (m.return_type));
876 : }
877 :
878 17570 : if (m is ArrayResizeMethod) {
879 : // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
880 13 : Iterator<Expression> arg_it = expr.get_argument_list ().iterator ();
881 13 : arg_it.next ();
882 26 : var new_size = get_cvalue (arg_it.get ());
883 :
884 13 : var array_type = (ArrayType) ma.inner.value_type;
885 13 : var temp_decl = get_temp_variable (array_type.length_type);
886 13 : var temp_ref = get_variable_cexpression (temp_decl.name);
887 :
888 13 : emit_temp_var (temp_decl);
889 :
890 : /* memset needs string.h */
891 13 : cfile.add_include ("string.h");
892 :
893 13 : var clen = get_array_length_cexpression (ma.inner, 1);
894 13 : var celems = get_cvalue (ma.inner);
895 13 : var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (array_type.element_type)));
896 13 : var cdelta = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, temp_ref, clen);
897 13 : var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, temp_ref, clen);
898 :
899 13 : var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
900 13 : czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, celems, clen));
901 13 : czero.add_argument (new CCodeConstant ("0"));
902 13 : czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cdelta));
903 :
904 13 : ccode.add_assignment (temp_ref, new_size);
905 13 : ccode.add_expression (ccall_expr);
906 13 : ccode.add_expression (new CCodeConditionalExpression (ccheck, czero, new CCodeConstant ("NULL")));
907 13 : ccode.add_assignment (get_array_length_cexpression (ma.inner, 1), temp_ref);
908 :
909 13 : var array_var = ma.inner.symbol_reference;
910 13 : if (array_var != null && array_var.is_internal_symbol ()
911 13 : && (array_var is LocalVariable || array_var is Field)) {
912 11 : ccode.add_assignment (get_array_size_cvalue (ma.inner.target_value), temp_ref);
913 : }
914 :
915 13 : return;
916 : }
917 :
918 24435 : if (expr.parent_node is ExpressionStatement && !expr.value_type.is_disposable ()) {
919 10679 : if (ccall_expr != null && !return_result_via_out_param) {
920 10164 : ccode.add_expression (ccall_expr);
921 : }
922 : } else {
923 6878 : var result_type = itype.get_return_type ();
924 :
925 7384 : if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
926 506 : var type_parameter = ((GenericType) expr.formal_value_type).type_parameter;
927 506 : var st = type_parameter.parent_symbol.parent_symbol as Struct;
928 506 : if (type_parameter.parent_symbol == garray_type ||
929 489 : (st != null && get_ccode_name (st) == "va_list")) {
930 : // GArray and va_list don't use pointer-based generics
931 : // above logic copied from visit_expression ()
932 : // TODO avoid code duplication
933 104 : result_type = expr.value_type;
934 : }
935 506 : if (st != null && get_ccode_name (st) == "va_list" && ma.member_name == "arg") {
936 35 : if (result_type is DelegateType && ((DelegateType) result_type).delegate_symbol.has_target) {
937 1 : set_cvalue (expr, null);
938 : // Initialize target/destroy cvalues to allow assignment of delegates from varargs
939 1 : unowned GLibValue arg_value = (GLibValue) expr.target_value;
940 1 : if (arg_value.delegate_target_cvalue == null) {
941 1 : arg_value.delegate_target_cvalue = new CCodeConstant ("NULL");
942 : }
943 1 : if (arg_value.delegate_target_destroy_notify_cvalue == null) {
944 1 : arg_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
945 : }
946 : }
947 : }
948 : }
949 :
950 6878 : if (m != null && m.get_format_arg_index () >= 0) {
951 27 : set_cvalue (expr, ccall_expr);
952 6851 : } else if (m != null && m.get_attribute_bool ("CCode", "use_inplace", false)) {
953 0 : set_cvalue (expr, ccall_expr);
954 6851 : } else if (!return_result_via_out_param
955 6786 : && !has_ref_out_argument (expr)
956 6700 : && (result_type is ValueType && !result_type.is_disposable ())) {
957 1445 : set_cvalue (expr, ccall_expr);
958 10747 : } else if (!return_result_via_out_param) {
959 5341 : var temp_var = get_temp_variable (result_type, result_type.value_owned, null, false);
960 5341 : var temp_ref = get_variable_cexpression (temp_var.name);
961 :
962 5341 : emit_temp_var (temp_var);
963 :
964 5341 : ccode.add_assignment (temp_ref, ccall_expr);
965 5341 : set_cvalue (expr, temp_ref);
966 5341 : ((GLibValue) expr.target_value).lvalue = true;
967 : } else {
968 65 : set_cvalue (expr, ccall_expr);
969 65 : ((GLibValue) expr.target_value).lvalue = true;
970 : }
971 : }
972 :
973 17557 : params_it = params.iterator ();
974 37886 : foreach (Expression arg in expr.get_argument_list ()) {
975 20116 : Parameter param = null;
976 :
977 20116 : if (params_it.next ()) {
978 19809 : param = params_it.get ();
979 : }
980 :
981 20116 : var unary = arg as UnaryExpression;
982 :
983 : // handle ref null terminated arrays
984 439 : if (unary != null && unary.operator == UnaryOperator.REF
985 72 : && unary.inner.symbol_reference != null && get_ccode_array_length (unary.inner.symbol_reference)) {
986 71 : if (param != null && get_ccode_array_null_terminated (param) && !get_ccode_array_length (param)
987 2 : && param.variable_type is ArrayType && ((ArrayType) param.variable_type).rank == 1) {
988 2 : requires_array_length = true;
989 2 : var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
990 2 : len_call.add_argument (get_cvalue_ (unary.inner.target_value));
991 2 : ccode.add_assignment (get_array_length_cvalue (unary.inner.target_value, 1), len_call);
992 : }
993 : }
994 :
995 : // update possible stale _*_size_ variable
996 20187 : if (unary != null && unary.operator == UnaryOperator.REF
997 72 : && unary.inner.symbol_reference != null && get_ccode_array_length (unary.inner.symbol_reference)) {
998 69 : if (param != null && param.variable_type is ArrayType
999 17 : && !((ArrayType) param.variable_type).fixed_length && ((ArrayType) param.variable_type).rank == 1) {
1000 15 : unowned Variable? array_var = unary.inner.symbol_reference as Variable;
1001 15 : if ((array_var is LocalVariable || array_var is Field) && array_var.is_internal_symbol ()
1002 11 : && array_var.variable_type is ArrayType && !((ArrayType) array_var.variable_type).fixed_length) {
1003 11 : ccode.add_assignment (get_array_size_cvalue (unary.inner.target_value), get_array_length_cvalue (unary.inner.target_value, 1));
1004 : }
1005 : }
1006 : }
1007 :
1008 20116 : if (unary == null || unary.operator != UnaryOperator.OUT) {
1009 19903 : continue;
1010 : }
1011 :
1012 213 : if (requires_destroy (unary.inner.value_type)) {
1013 : // unref old value
1014 83 : ccode.add_expression (destroy_value (unary.inner.target_value));
1015 : }
1016 :
1017 : // infer type of out-parameter from argument
1018 213 : if (ma.symbol_reference is DynamicMethod && unary.target_value.value_type == null) {
1019 1 : unary.target_value.value_type = unary.inner.value_type.copy ();
1020 : }
1021 :
1022 : // assign new value
1023 213 : store_value (unary.inner.target_value, transform_value (unary.target_value, unary.inner.value_type, arg), expr.source_reference);
1024 :
1025 : // handle out null terminated arrays
1026 220 : if (param != null && get_ccode_array_null_terminated (param) && !get_ccode_array_length (param)
1027 4 : && unary.inner.symbol_reference != null && get_ccode_array_length (unary.inner.symbol_reference)) {
1028 3 : requires_array_length = true;
1029 3 : var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1030 3 : len_call.add_argument (get_cvalue_ (unary.inner.target_value));
1031 :
1032 3 : ccode.add_assignment (get_array_length_cvalue (unary.inner.target_value, 1), len_call);
1033 : }
1034 : }
1035 :
1036 17569 : if (m is CreationMethod && m.parent_symbol is Class && ((current_class.is_compact && current_class.base_class != null) || current_class.is_subtype_of (gsource_type))) {
1037 12 : var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (current_class, null))));
1038 12 : cinitcall.add_argument (get_this_cexpression ());
1039 12 : if (!current_class.is_compact) {
1040 0 : cinitcall.add_argument (new CCodeConstant ("NULL"));
1041 : }
1042 12 : ccode.add_expression (cinitcall);
1043 : }
1044 : }
1045 :
1046 5 : private string generate_enum_to_string_function (Enum en) {
1047 5 : var to_string_func = "_%s_to_string".printf (get_ccode_lower_case_name (en));
1048 :
1049 5 : if (!add_wrapper (to_string_func)) {
1050 : // wrapper already defined
1051 5 : return to_string_func;
1052 : }
1053 : // declaration
1054 :
1055 3 : var function = new CCodeFunction (to_string_func, "const char*");
1056 3 : function.modifiers = CCodeModifiers.STATIC;
1057 :
1058 3 : function.add_parameter (new CCodeParameter ("value", get_ccode_name (en)));
1059 :
1060 : // definition
1061 3 : push_context (new EmitContext ());
1062 3 : push_function (function);
1063 :
1064 3 : ccode.open_switch (new CCodeConstant ("value"));
1065 19 : foreach (var enum_value in en.get_values ()) {
1066 8 : ccode.add_case (new CCodeIdentifier (get_ccode_name (enum_value)));
1067 8 : ccode.add_return (new CCodeConstant ("\""+get_ccode_name (enum_value)+"\""));
1068 : }
1069 3 : ccode.close ();
1070 3 : ccode.add_return (new CCodeConstant ("NULL"));
1071 :
1072 : // append to file
1073 3 : cfile.add_function_declaration (function);
1074 3 : cfile.add_function (function);
1075 :
1076 3 : pop_context ();
1077 :
1078 3 : return to_string_func;
1079 : }
1080 :
1081 6786 : bool has_ref_out_argument (MethodCall c) {
1082 20600 : foreach (var arg in c.get_argument_list ()) {
1083 6993 : unowned UnaryExpression? unary = arg as UnaryExpression;
1084 6993 : if (unary != null && (unary.operator == UnaryOperator.OUT || unary.operator == UnaryOperator.REF)) {
1085 86 : return true;
1086 : }
1087 : }
1088 6786 : return false;
1089 : }
1090 :
1091 1 : string generate_string_printf_function () {
1092 1 : if (!add_wrapper ("string_printf")) {
1093 : // wrapper already defined
1094 0 : return "string_printf";
1095 : }
1096 :
1097 : // declaration
1098 1 : var function = new CCodeFunction ("string_printf", "char*");
1099 1 : function.add_parameter (new CCodeParameter ("format", "const char*"));
1100 1 : function.add_parameter (new CCodeParameter.with_ellipsis ());
1101 1 : function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.PRINTF;
1102 :
1103 : // definition
1104 1 : push_context (new EmitContext ());
1105 1 : push_function (function);
1106 :
1107 1 : ccode.add_declaration ("int", new CCodeVariableDeclarator ("length"));
1108 1 : ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("ap"));
1109 1 : ccode.add_declaration ("char*", new CCodeVariableDeclarator ("result"));
1110 :
1111 1 : var vastart = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
1112 1 : vastart.add_argument (new CCodeIdentifier ("ap"));
1113 1 : vastart.add_argument (new CCodeIdentifier ("format"));
1114 :
1115 1 : ccode.add_expression (vastart);
1116 :
1117 1 : if (context.profile == Profile.POSIX) {
1118 1 : cfile.add_include ("stdio.h");
1119 : }
1120 :
1121 1 : var vsnprintf = new CCodeFunctionCall (new CCodeIdentifier ("vsnprintf"));
1122 1 : vsnprintf.add_argument (new CCodeConstant ("NULL"));
1123 1 : vsnprintf.add_argument (new CCodeConstant ("0"));
1124 1 : vsnprintf.add_argument (new CCodeIdentifier ("format"));
1125 1 : vsnprintf.add_argument (new CCodeIdentifier ("ap"));
1126 :
1127 1 : ccode.add_assignment (new CCodeIdentifier ("length"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, vsnprintf, new CCodeConstant ("1")));
1128 :
1129 1 : var va_end = new CCodeFunctionCall (new CCodeIdentifier ("va_end"));
1130 1 : va_end.add_argument (new CCodeIdentifier ("ap"));
1131 :
1132 1 : ccode.add_expression (va_end);
1133 :
1134 1 : var malloc = new CCodeFunctionCall (new CCodeIdentifier ("malloc"));
1135 1 : malloc.add_argument (new CCodeIdentifier ("length"));
1136 :
1137 1 : ccode.add_assignment (new CCodeIdentifier ("result"), malloc);
1138 :
1139 1 : vastart = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
1140 1 : vastart.add_argument (new CCodeIdentifier ("ap"));
1141 1 : vastart.add_argument (new CCodeIdentifier ("format"));
1142 :
1143 1 : ccode.add_expression (vastart);
1144 :
1145 1 : vsnprintf = new CCodeFunctionCall (new CCodeIdentifier ("vsnprintf"));
1146 1 : vsnprintf.add_argument (new CCodeIdentifier ("result"));
1147 1 : vsnprintf.add_argument (new CCodeIdentifier ("length"));
1148 1 : vsnprintf.add_argument (new CCodeIdentifier ("format"));
1149 1 : vsnprintf.add_argument (new CCodeIdentifier ("ap"));
1150 :
1151 1 : ccode.add_expression (vsnprintf);
1152 :
1153 1 : va_end = new CCodeFunctionCall (new CCodeIdentifier ("va_end"));
1154 1 : va_end.add_argument (new CCodeIdentifier ("ap"));
1155 :
1156 1 : ccode.add_expression (va_end);
1157 :
1158 1 : ccode.add_return (new CCodeIdentifier ("result"));
1159 :
1160 : // append to file
1161 1 : cfile.add_include ("stdarg.h");
1162 1 : cfile.add_function_declaration (function);
1163 1 : cfile.add_function (function);
1164 :
1165 1 : pop_context ();
1166 :
1167 1 : return "string_printf";
1168 : }
1169 : }
1170 :
|