Fix ref_sink of Gtk.Window created with GLib.Object.new
[vala-lang.git] / codegen / valaccodemethodcallmodule.vala
blobad262fa9f72ad54a69c832c166c7e68d8fa5e470
1 /* valaccodemethodcallmodule.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
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.
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.
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
28 public override void visit_method_call (MethodCall expr) {
29 // the bare function call
30 var ccall = new CCodeFunctionCall ((CCodeExpression) expr.call.ccodenode);
32 CCodeFunctionCall async_call = null;
34 Method m = null;
35 Delegate deleg = null;
36 List<FormalParameter> params;
38 var ma = expr.call as MemberAccess;
40 var itype = expr.call.value_type;
41 params = itype.get_parameters ();
43 if (itype is MethodType) {
44 assert (ma != null);
45 m = ((MethodType) itype).method_symbol;
46 } else if (itype is SignalType) {
47 var sig_type = (SignalType) itype;
48 if (ma != null && ma.inner is BaseAccess && sig_type.signal_symbol.is_virtual) {
49 m = sig_type.signal_symbol.default_handler;
50 } else {
51 ccall = (CCodeFunctionCall) expr.call.ccodenode;
53 } else if (itype is ObjectType) {
54 // constructor
55 var cl = (Class) ((ObjectType) itype).type_symbol;
56 m = cl.default_construction_method;
57 generate_method_declaration (m, source_declarations);
58 ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
59 } else if (itype is StructValueType) {
60 // constructor
61 var st = (Struct) ((StructValueType) itype).type_symbol;
62 m = st.default_construction_method;
63 generate_method_declaration (m, source_declarations);
64 ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
65 } else if (itype is DelegateType) {
66 deleg = ((DelegateType) itype).delegate_symbol;
69 var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
70 var out_arg_map = in_arg_map;
72 if (m != null && m.coroutine) {
73 // async call
75 async_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
76 var finish_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_finish_cname ()));
78 if (ma.inner is BaseAccess) {
79 if (m.base_method != null) {
80 var base_class = (Class) m.base_method.parent_symbol;
81 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
82 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
84 async_call.call = new CCodeMemberAccess.pointer (vcast, m.vfunc_name);
85 finish_call.call = new CCodeMemberAccess.pointer (vcast, m.get_finish_vfunc_name ());
86 } else if (m.base_interface_method != null) {
87 var base_iface = (Interface) m.base_interface_method.parent_symbol;
88 string parent_iface_var = "%s_%s_parent_iface".printf (current_class.get_lower_case_cname (null), base_iface.get_lower_case_cname (null));
90 async_call.call = new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), m.vfunc_name);
91 finish_call.call = new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), m.get_finish_vfunc_name ());
95 if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
96 // no finish call
97 ccall = async_call;
98 params = m.get_async_begin_parameters ();
99 } else if (ma.member_name == "end" && ma.inner.symbol_reference == ma.symbol_reference) {
100 // no async call
101 ccall = finish_call;
102 params = m.get_async_end_parameters ();
103 } else if (!expr.is_yield_expression) {
104 // same as .begin, backwards compatible to bindings without async methods
105 ccall = async_call;
106 params = m.get_async_begin_parameters ();
107 } else {
108 ccall = finish_call;
110 // output arguments used separately
111 out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
112 // pass GAsyncResult stored in closure to finish function
113 out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_res_"));
117 if (m is CreationMethod && m.parent_symbol is Class) {
118 if (context.profile == Profile.GOBJECT) {
119 if (!((Class) m.parent_symbol).is_compact) {
120 ccall.add_argument (new CCodeIdentifier ("object_type"));
122 } else {
123 ccall.add_argument (new CCodeIdentifier ("self"));
126 if (!current_class.is_compact) {
127 if (current_class != m.parent_symbol) {
128 // chain up to base class
129 foreach (DataType base_type in current_class.get_base_types ()) {
130 if (base_type.data_type is Class) {
131 add_generic_type_arguments (in_arg_map, base_type.get_type_arguments (), expr, true);
132 break;
135 } else {
136 // chain up to other constructor in same class
137 int type_param_index = 0;
138 var cl = (Class) m.parent_symbol;
139 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
140 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier ("%s_type".printf (type_param.name.down ())));
141 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ())));
142 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ())));
143 type_param_index++;
147 } else if (m is CreationMethod && m.parent_symbol is Struct) {
148 ccall.add_argument (new CCodeIdentifier ("self"));
149 } else if (m != null && m.get_type_parameters ().size > 0 && !m.has_generic_type_parameter && !m.simple_generics) {
150 // generic method
151 add_generic_type_arguments (in_arg_map, ma.get_type_arguments (), expr);
154 // the complete call expression, might include casts, comma expressions, and/or assignments
155 CCodeExpression ccall_expr = ccall;
157 if (m is ArrayResizeMethod) {
158 var array_type = (ArrayType) ma.inner.value_type;
159 in_arg_map.set (get_param_pos (0), new CCodeIdentifier (array_type.element_type.get_cname ()));
160 } else if (m is ArrayMoveMethod) {
161 requires_array_move = true;
164 CCodeExpression instance = null;
165 if (m != null && m.is_async_callback) {
166 if (current_method.closure) {
167 var block = ((Method) m.parent_symbol).body;
168 instance = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_");
169 } else {
170 instance = new CCodeIdentifier ("data");
173 in_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
174 out_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
175 } else if (m != null && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) {
176 instance = (CCodeExpression) ma.inner.ccodenode;
178 if ((ma.member_name == "begin" || ma.member_name == "end") && ma.inner.symbol_reference == ma.symbol_reference) {
179 var inner_ma = (MemberAccess) ma.inner;
180 instance = (CCodeExpression) inner_ma.inner.ccodenode;
183 var st = m.parent_symbol as Struct;
184 if (st != null && !st.is_simple_type ()) {
185 // we need to pass struct instance by reference
186 var unary = instance as CCodeUnaryExpression;
187 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
188 // *expr => expr
189 instance = unary.inner;
190 } else if (instance is CCodeIdentifier || instance is CCodeMemberAccess) {
191 instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance);
192 } else {
193 // if instance is e.g. a function call, we can't take the address of the expression
194 // (tmp = expr, &tmp)
195 var ccomma = new CCodeCommaExpression ();
197 var temp_var = get_temp_variable (ma.inner.target_type, true, null, false);
198 temp_vars.add (temp_var);
199 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), instance));
200 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name)));
202 instance = ccomma;
206 in_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
207 out_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
208 } else if (m != null && m.binding == MemberBinding.CLASS) {
209 var cl = (Class) m.parent_symbol;
210 var cast = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null) + "_CLASS"));
212 CCodeExpression klass;
213 if (ma.inner == null) {
214 if (in_static_or_class_context) {
215 // Accessing the method from a static or class constructor
216 klass = new CCodeIdentifier ("klass");
217 } else {
218 // Accessing the method from within an instance method
219 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
220 k.add_argument (new CCodeIdentifier ("self"));
221 klass = k;
223 } else {
224 // Accessing the method of an instance
225 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
226 k.add_argument ((CCodeExpression) ma.inner.ccodenode);
227 klass = k;
230 cast.add_argument (klass);
231 in_arg_map.set (get_param_pos (m.cinstance_parameter_position), cast);
232 out_arg_map.set (get_param_pos (m.cinstance_parameter_position), cast);
235 if (m != null && m.has_generic_type_parameter) {
236 // insert type argument for macros
237 if (m.get_type_parameters ().size > 0) {
238 // generic method
239 int type_param_index = 0;
240 foreach (var type_arg in ma.get_type_arguments ()) {
241 in_arg_map.set (get_param_pos (m.generic_type_parameter_position + 0.01 * type_param_index), new CCodeIdentifier (type_arg.get_cname ()));
242 type_param_index++;
244 } else {
245 // method in generic type
246 int type_param_index = 0;
247 foreach (var type_arg in ma.inner.value_type.get_type_arguments ()) {
248 in_arg_map.set (get_param_pos (m.generic_type_parameter_position + 0.01 * type_param_index), new CCodeIdentifier (type_arg.get_cname ()));
249 type_param_index++;
254 if (m is ArrayMoveMethod) {
255 var array_type = (ArrayType) ma.inner.value_type;
256 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
257 csizeof.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
258 in_arg_map.set (get_param_pos (0.1), csizeof);
259 } else if (m is DynamicMethod) {
260 m.clear_parameters ();
261 int param_nr = 1;
262 foreach (Expression arg in expr.get_argument_list ()) {
263 var unary = arg as UnaryExpression;
264 if (unary != null && unary.operator == UnaryOperator.OUT) {
265 // out argument
266 var param = new FormalParameter ("param%d".printf (param_nr), unary.inner.value_type);
267 param.direction = ParameterDirection.OUT;
268 m.add_parameter (param);
269 } else if (unary != null && unary.operator == UnaryOperator.REF) {
270 // ref argument
271 var param = new FormalParameter ("param%d".printf (param_nr), unary.inner.value_type);
272 param.direction = ParameterDirection.REF;
273 m.add_parameter (param);
274 } else {
275 // in argument
276 m.add_parameter (new FormalParameter ("param%d".printf (param_nr), arg.value_type));
278 param_nr++;
280 foreach (FormalParameter param in m.get_parameters ()) {
281 param.accept (this);
283 generate_dynamic_method_wrapper ((DynamicMethod) m);
284 } else if (m is CreationMethod && context.profile == Profile.GOBJECT && m.parent_symbol is Class) {
285 ccall_expr = new CCodeAssignment (new CCodeIdentifier ("self"), new CCodeCastExpression (ccall, current_class.get_cname () + "*"));
287 if (current_method.body.captured) {
288 // capture self after setting it
289 var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), expr.source_reference));
290 ref_call.add_argument (ccall_expr);
292 ccall_expr = new CCodeAssignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (current_method.body))), "self"), ref_call);
295 if (!current_class.is_compact && current_class.get_type_parameters ().size > 0) {
296 var ccomma = new CCodeCommaExpression ();
297 ccomma.append_expression (ccall_expr);
299 /* type, dup func, and destroy func fields for generic types */
300 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
301 CCodeIdentifier param_name;
303 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
305 param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.down ()));
306 ccomma.append_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name));
308 param_name = new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ()));
309 ccomma.append_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name));
311 param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ()));
312 ccomma.append_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name));
315 ccall_expr = ccomma;
319 bool ellipsis = false;
321 int i = 1;
322 int arg_pos;
323 Iterator<FormalParameter> params_it = params.iterator ();
324 foreach (Expression arg in expr.get_argument_list ()) {
325 CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
327 var carg_map = in_arg_map;
329 if (params_it.next ()) {
330 var param = params_it.get ();
331 ellipsis = param.params_array || param.ellipsis;
332 if (!ellipsis) {
333 // if the vala argument expands to multiple C arguments,
334 // we have to make sure that the C arguments don't depend
335 // on each other as there is no guaranteed argument
336 // evaluation order
337 // http://bugzilla.gnome.org/show_bug.cgi?id=519597
338 bool multiple_cargs = false;
340 if (param.direction == ParameterDirection.OUT) {
341 carg_map = out_arg_map;
344 if (!param.no_array_length && param.variable_type is ArrayType) {
345 var array_type = (ArrayType) param.variable_type;
346 for (int dim = 1; dim <= array_type.rank; dim++) {
347 CCodeExpression? array_length_expr = null;
348 if (param.array_length_type != null) {
349 if (param.direction == ParameterDirection.OUT) {
350 var temp_array_length = get_temp_variable (new CType (param.array_length_type));
351 temp_vars.add (temp_array_length);
352 array_length_expr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_array_length.name));
354 var comma = new CCodeCommaExpression ();
355 LocalVariable? temp_result = null;
356 if (!(m.return_type is VoidType)) {
357 temp_result = get_temp_variable (m.return_type);
358 temp_vars.add (temp_result);
359 ccall_expr = new CCodeAssignment (get_variable_cexpression (temp_result.name), ccall_expr);
362 comma.append_expression (ccall_expr);
363 comma.append_expression (new CCodeAssignment (get_variable_cexpression (get_array_length_cname (((UnaryExpression) arg).inner.to_string (), dim)), new CCodeCastExpression (get_variable_cexpression (temp_array_length.name), int_type.get_cname ())));
365 if (temp_result != null) {
366 comma.append_expression (get_variable_cexpression (temp_result.name));
368 ccall_expr = comma;
369 } else {
370 array_length_expr = new CCodeCastExpression (get_array_length_cexpression (arg, dim), param.array_length_type);
372 } else {
373 array_length_expr = get_array_length_cexpression (arg, dim);
375 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), array_length_expr);
377 multiple_cargs = true;
378 } else if (param.variable_type is DelegateType) {
379 var deleg_type = (DelegateType) param.variable_type;
380 var d = deleg_type.delegate_symbol;
381 if (d.has_target) {
382 CCodeExpression delegate_target_destroy_notify;
383 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
384 if (param.ctype == "GClosure*") {
385 // one single GClosure parameter
386 var closure_new = new CCodeFunctionCall (new CCodeIdentifier ("g_cclosure_new"));
387 closure_new.add_argument (new CCodeCastExpression (cexpr, "GCallback"));
388 closure_new.add_argument (delegate_target);
389 closure_new.add_argument (delegate_target_destroy_notify);
390 cexpr = closure_new;
391 } else {
392 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), delegate_target);
393 if (deleg_type.value_owned) {
394 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), delegate_target_destroy_notify);
396 multiple_cargs = true;
399 } else if (param.variable_type is MethodType) {
400 // callbacks in dynamic method calls
401 CCodeExpression delegate_target_destroy_notify;
402 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), get_delegate_target_cexpression (arg, out delegate_target_destroy_notify));
403 multiple_cargs = true;
404 } else if (param.variable_type is GenericType) {
405 if (m != null && m.simple_generics) {
406 var generic_type = (GenericType) param.variable_type;
407 int type_param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
408 var type_arg = ma.get_type_arguments ().get (type_param_index);
409 if (requires_copy (type_arg)) {
410 carg_map.set (get_param_pos (param.cdestroy_notify_parameter_position), get_destroy_func_expression (type_arg));
411 } else {
412 carg_map.set (get_param_pos (param.cdestroy_notify_parameter_position), new CCodeConstant ("NULL"));
417 cexpr = handle_struct_argument (param, arg, cexpr);
419 if (multiple_cargs && arg is MethodCall) {
420 // if vala argument is invocation expression
421 // the auxiliary C argument(s) will depend on the main C argument
423 // (tmp = arg1, call (tmp, arg2, arg3,...))
425 var ccomma = new CCodeCommaExpression ();
427 var temp_decl = get_temp_variable (arg.value_type, true, null, false);
428 temp_vars.add (temp_decl);
429 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_decl.name), cexpr));
431 cexpr = get_variable_cexpression (temp_decl.name);
433 ccomma.append_expression (ccall_expr);
435 ccall_expr = ccomma;
438 // unref old value for non-null non-weak ref/out arguments
439 // disabled for arrays for now as that requires special handling
440 // (ret_tmp = call (&tmp), var1 = (assign_tmp = dup (tmp), free (var1), assign_tmp), ret_tmp)
441 if (param.direction != ParameterDirection.IN && requires_destroy (arg.value_type)
442 && (param.direction == ParameterDirection.OUT || !param.variable_type.value_owned)
443 && !(param.variable_type is ArrayType) && !(param.variable_type is DelegateType)) {
444 var unary = (UnaryExpression) arg;
446 var ccomma = new CCodeCommaExpression ();
448 var temp_var = get_temp_variable (param.variable_type, param.variable_type.value_owned);
449 temp_vars.add (temp_var);
450 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name));
452 if (param.direction == ParameterDirection.REF) {
453 var crefcomma = new CCodeCommaExpression ();
454 crefcomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), (CCodeExpression) unary.inner.ccodenode));
455 crefcomma.append_expression (cexpr);
456 cexpr = crefcomma;
459 // call function
460 LocalVariable ret_temp_var = null;
461 if (itype.get_return_type () is VoidType || itype.get_return_type ().is_real_struct_type () ||
462 (expr.parent_node is ExpressionStatement && !requires_destroy (itype.get_return_type ()))) {
463 ccomma.append_expression (ccall_expr);
464 } else {
465 ret_temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
466 temp_vars.add (ret_temp_var);
467 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (ret_temp_var.name), ccall_expr));
470 var cassign_comma = new CCodeCommaExpression ();
472 var assign_temp_var = get_temp_variable (unary.inner.value_type, unary.inner.value_type.value_owned, null, false);
473 temp_vars.add (assign_temp_var);
475 cassign_comma.append_expression (new CCodeAssignment (get_variable_cexpression (assign_temp_var.name), transform_expression (get_variable_cexpression (temp_var.name), param.variable_type, unary.inner.value_type, arg)));
477 // unref old value
478 cassign_comma.append_expression (get_unref_expression ((CCodeExpression) unary.inner.ccodenode, arg.value_type, arg));
480 cassign_comma.append_expression (get_variable_cexpression (assign_temp_var.name));
482 // assign new value
483 ccomma.append_expression (new CCodeAssignment ((CCodeExpression) unary.inner.ccodenode, cassign_comma));
485 // return value
486 if (ret_temp_var != null) {
487 ccomma.append_expression (get_variable_cexpression (ret_temp_var.name));
490 ccall_expr = ccomma;
493 if (param.ctype != null) {
494 cexpr = new CCodeCastExpression (cexpr, param.ctype);
496 } else {
497 cexpr = handle_struct_argument (null, arg, cexpr);
499 arg_pos = get_param_pos (param.cparameter_position, ellipsis);
500 } else {
501 // default argument position
502 cexpr = handle_struct_argument (null, arg, cexpr);
503 arg_pos = get_param_pos (i, ellipsis);
506 carg_map.set (arg_pos, cexpr);
508 if (arg is NamedArgument && ellipsis) {
509 var named_arg = (NamedArgument) arg;
510 string name = string.joinv ("-", named_arg.name.split ("_"));
511 carg_map.set (get_param_pos (i - 0.1, ellipsis), new CCodeConstant ("\"%s\"".printf (name)));
514 i++;
516 if (params_it.next ()) {
517 var param = params_it.get ();
519 /* if there are more parameters than arguments,
520 * the additional parameter is an ellipsis parameter
521 * otherwise there is a bug in the semantic analyzer
523 assert (param.params_array || param.ellipsis);
524 ellipsis = true;
527 /* add length argument for methods returning arrays */
528 if (m != null && m.return_type is ArrayType && async_call != ccall) {
529 var array_type = (ArrayType) m.return_type;
530 for (int dim = 1; dim <= array_type.rank; dim++) {
531 if (m.array_null_terminated) {
532 // handle calls to methods returning null-terminated arrays
533 var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
534 var temp_ref = get_variable_cexpression (temp_var.name);
536 temp_vars.add (temp_var);
538 ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
540 requires_array_length = true;
541 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
542 len_call.add_argument (temp_ref);
544 expr.append_array_size (len_call);
545 } else if (!m.no_array_length) {
546 LocalVariable temp_var;
548 if (m.array_length_type == null) {
549 temp_var = get_temp_variable (int_type);
550 } else {
551 temp_var = get_temp_variable (new CType (m.array_length_type));
553 var temp_ref = get_variable_cexpression (temp_var.name);
555 temp_vars.add (temp_var);
557 out_arg_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
559 expr.append_array_size (temp_ref);
560 } else {
561 expr.append_array_size (new CCodeConstant ("-1"));
564 } else if (m != null && m.return_type is DelegateType && async_call != ccall) {
565 var deleg_type = (DelegateType) m.return_type;
566 var d = deleg_type.delegate_symbol;
567 if (d.has_target) {
568 var temp_var = get_temp_variable (new PointerType (new VoidType ()));
569 var temp_ref = get_variable_cexpression (temp_var.name);
571 temp_vars.add (temp_var);
573 out_arg_map.set (get_param_pos (m.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
575 expr.delegate_target = temp_ref;
577 if (deleg_type.value_owned) {
578 temp_var = get_temp_variable (new DelegateType ((Delegate) context.root.scope.lookup ("GLib").scope.lookup ("DestroyNotify")));
579 temp_ref = get_variable_cexpression (temp_var.name);
581 temp_vars.add (temp_var);
583 out_arg_map.set (get_param_pos (m.cdelegate_target_parameter_position + 0.01), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
585 expr.delegate_target_destroy_notify = temp_ref;
590 // add length argument for delegates returning arrays
591 // TODO: avoid code duplication with methods returning arrays, see above
592 if (deleg != null && deleg.return_type is ArrayType) {
593 var array_type = (ArrayType) deleg.return_type;
594 for (int dim = 1; dim <= array_type.rank; dim++) {
595 if (deleg.array_null_terminated) {
596 // handle calls to methods returning null-terminated arrays
597 var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
598 var temp_ref = get_variable_cexpression (temp_var.name);
600 temp_vars.add (temp_var);
602 ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
604 requires_array_length = true;
605 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
606 len_call.add_argument (temp_ref);
608 expr.append_array_size (len_call);
609 } else if (!deleg.no_array_length) {
610 var temp_var = get_temp_variable (int_type);
611 var temp_ref = get_variable_cexpression (temp_var.name);
613 temp_vars.add (temp_var);
615 out_arg_map.set (get_param_pos (deleg.carray_length_parameter_position + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
617 expr.append_array_size (temp_ref);
618 } else {
619 expr.append_array_size (new CCodeConstant ("-1"));
622 } else if (deleg != null && deleg.return_type is DelegateType) {
623 var deleg_type = (DelegateType) deleg.return_type;
624 var d = deleg_type.delegate_symbol;
625 if (d.has_target) {
626 var temp_var = get_temp_variable (new PointerType (new VoidType ()));
627 var temp_ref = get_variable_cexpression (temp_var.name);
629 temp_vars.add (temp_var);
631 out_arg_map.set (get_param_pos (deleg.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
633 expr.delegate_target = temp_ref;
637 if (m != null && m.coroutine) {
638 if (expr.is_yield_expression) {
639 // asynchronous call
640 in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (current_method.get_cname () + "_ready"));
641 in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("data"));
645 if (expr.tree_can_fail) {
646 // method can fail
647 current_method_inner_error = true;
648 // add &inner_error before the ellipsis arguments
649 out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
652 if (ellipsis) {
653 /* ensure variable argument list ends with NULL
654 * except when using printf-style arguments */
655 if (!m.printf_format && !m.scanf_format && m.sentinel != "") {
656 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (m.sentinel));
658 } else if (itype is DelegateType) {
659 var deleg_type = (DelegateType) itype;
660 var d = deleg_type.delegate_symbol;
661 if (d.has_target) {
662 CCodeExpression delegate_target_destroy_notify;
663 in_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
664 out_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
668 // structs are returned via out parameter
669 bool return_result_via_out_param = itype.get_return_type ().is_real_non_null_struct_type ();
671 // pass address for the return value of non-void signals without emitter functions
672 if (itype is SignalType && !(itype.get_return_type () is VoidType)) {
673 var sig = ((SignalType) itype).signal_symbol;
675 if (ma != null && ma.inner is BaseAccess && sig.is_virtual) {
676 // normal return value for base access
677 } else if (!sig.has_emitter) {
678 return_result_via_out_param = true;
682 if (return_result_via_out_param) {
683 var temp_var = get_temp_variable (itype.get_return_type ());
684 var temp_ref = get_variable_cexpression (temp_var.name);
686 temp_vars.add (temp_var);
688 out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
690 var ccomma = new CCodeCommaExpression ();
691 ccomma.append_expression ((CCodeExpression) ccall_expr);
692 ccomma.append_expression ((CCodeExpression) temp_ref);
694 ccall_expr = ccomma;
697 // append C arguments in the right order
699 int last_pos;
700 int min_pos;
702 if (async_call != ccall) {
703 // don't append out arguments for .begin() calls
704 last_pos = -1;
705 while (true) {
706 min_pos = -1;
707 foreach (int pos in out_arg_map.get_keys ()) {
708 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
709 min_pos = pos;
712 if (min_pos == -1) {
713 break;
715 ccall.add_argument (out_arg_map.get (min_pos));
716 last_pos = min_pos;
720 if (async_call != null) {
721 last_pos = -1;
722 while (true) {
723 min_pos = -1;
724 foreach (int pos in in_arg_map.get_keys ()) {
725 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
726 min_pos = pos;
729 if (min_pos == -1) {
730 break;
732 async_call.add_argument (in_arg_map.get (min_pos));
733 last_pos = min_pos;
737 if (m != null && m.binding == MemberBinding.INSTANCE && m.returns_modified_pointer) {
738 expr.ccodenode = new CCodeAssignment (instance, ccall_expr);
739 } else {
740 expr.ccodenode = ccall_expr;
743 if (expr.is_yield_expression) {
744 if (pre_statement_fragment == null) {
745 pre_statement_fragment = new CCodeFragment ();
748 // set state before calling async function to support immediate callbacks
749 int state = next_coroutine_state++;
751 state_switch_statement.add_statement (new CCodeCaseStatement (new CCodeConstant (state.to_string ())));
752 state_switch_statement.add_statement (new CCodeGotoStatement ("_state_%d".printf (state)));
754 pre_statement_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "_state_"), new CCodeConstant (state.to_string ()))));
755 pre_statement_fragment.append (new CCodeExpressionStatement (async_call));
756 pre_statement_fragment.append (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
757 pre_statement_fragment.append (new CCodeLabel ("_state_%d".printf (state)));
760 if (m is ArrayResizeMethod) {
761 // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
762 Iterator<Expression> arg_it = expr.get_argument_list ().iterator ();
763 arg_it.next ();
764 var new_size = (CCodeExpression) arg_it.get ().ccodenode;
766 var temp_decl = get_temp_variable (int_type);
767 var temp_ref = get_variable_cexpression (temp_decl.name);
769 temp_vars.add (temp_decl);
771 /* memset needs string.h */
772 source_declarations.add_include ("string.h");
774 var clen = get_array_length_cexpression (ma.inner, 1);
775 var celems = (CCodeExpression) ma.inner.ccodenode;
776 var array_type = (ArrayType) ma.inner.value_type;
777 var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (array_type.element_type.get_cname ()));
778 var cdelta = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, temp_ref, clen);
779 var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, temp_ref, clen);
781 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
782 czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, celems, clen));
783 czero.add_argument (new CCodeConstant ("0"));
784 czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cdelta));
786 var ccomma = new CCodeCommaExpression ();
787 ccomma.append_expression (new CCodeAssignment (temp_ref, new_size));
788 ccomma.append_expression ((CCodeExpression) expr.ccodenode);
789 ccomma.append_expression (new CCodeConditionalExpression (ccheck, czero, new CCodeConstant ("NULL")));
790 ccomma.append_expression (new CCodeAssignment (get_array_length_cexpression (ma.inner, 1), temp_ref));
792 expr.ccodenode = ccomma;