GAsync: Another temp variable fix
[vala-lang.git] / codegen / valaccodemethodcallmodule.vala
blobf11b279bebf64349b48a5e13ba2accfbca732089
1 /* valaccodemethodcallmodule.vala
3 * Copyright (C) 2006-2009 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;
26 using Gee;
28 internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
29 public CCodeMethodCallModule (CCodeGenerator codegen, CCodeModule? next) {
30 base (codegen, next);
33 public override void visit_method_call (MethodCall expr) {
34 expr.accept_children (codegen);
36 // the bare function call
37 var ccall = new CCodeFunctionCall ((CCodeExpression) expr.call.ccodenode);
39 CCodeFunctionCall async_call = null;
41 Method m = null;
42 Delegate deleg = null;
43 Gee.List<FormalParameter> params;
45 var ma = expr.call as MemberAccess;
47 var itype = expr.call.value_type;
48 params = itype.get_parameters ();
50 if (itype is MethodType) {
51 assert (ma != null);
52 m = ((MethodType) itype).method_symbol;
53 } else if (itype is SignalType) {
54 var sig_type = (SignalType) itype;
55 if (ma != null && ma.inner is BaseAccess && sig_type.signal_symbol.is_virtual) {
56 m = sig_type.signal_symbol.default_handler;
57 } else {
58 ccall = (CCodeFunctionCall) expr.call.ccodenode;
60 } else if (itype is ObjectType) {
61 // constructor
62 var cl = (Class) ((ObjectType) itype).type_symbol;
63 m = cl.default_construction_method;
64 generate_method_declaration (m, source_declarations);
65 ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_real_cname ()));
66 } else if (itype is DelegateType) {
67 deleg = ((DelegateType) itype).delegate_symbol;
70 var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
71 var out_arg_map = in_arg_map;
73 if (m != null && m.coroutine) {
74 // async call
76 async_call = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
78 if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
79 // no finish call
80 ccall = async_call;
81 params = m.get_async_begin_parameters ();
82 } else if (ma.member_name == "end" && ma.inner.symbol_reference == ma.symbol_reference) {
83 // no async call
84 ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_finish_cname ()));
85 params = m.get_async_end_parameters ();
86 } else if (!expr.is_yield_expression) {
87 // same as .begin, backwards compatible to bindings without async methods
88 ccall = async_call;
89 params = m.get_async_begin_parameters ();
90 } else {
91 ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_finish_cname ()));
93 // output arguments used separately
94 out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
95 // pass GAsyncResult stored in closure to finish function
96 out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "res"));
100 if (m is CreationMethod) {
101 if (context.profile == Profile.GOBJECT) {
102 if (!((Class) m.parent_symbol).is_compact) {
103 ccall.add_argument (new CCodeIdentifier ("object_type"));
105 } else {
106 ccall.add_argument (new CCodeIdentifier ("self"));
109 foreach (DataType base_type in current_class.get_base_types ()) {
110 if (base_type.data_type is Class) {
111 add_generic_type_arguments (ccall, base_type.get_type_arguments (), expr, true);
112 break;
115 } else if (m != null && m.get_type_parameters ().size > 0) {
116 // generic method
117 add_generic_type_arguments (ccall, ma.get_type_arguments (), expr);
120 // the complete call expression, might include casts, comma expressions, and/or assignments
121 CCodeExpression ccall_expr = ccall;
123 if (m is ArrayResizeMethod) {
124 var array_type = (ArrayType) ma.inner.value_type;
125 in_arg_map.set (get_param_pos (0), new CCodeIdentifier (array_type.element_type.get_cname ()));
126 } else if (m is ArrayMoveMethod) {
127 requires_array_move = true;
130 CCodeExpression instance = null;
131 if (m != null && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) {
132 instance = (CCodeExpression) ma.inner.ccodenode;
134 if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
135 var inner_ma = (MemberAccess) ma.inner;
136 instance = (CCodeExpression) inner_ma.inner.ccodenode;
139 var st = m.parent_symbol as Struct;
140 if (st != null && !st.is_simple_type ()) {
141 // we need to pass struct instance by reference
142 var unary = instance as CCodeUnaryExpression;
143 if (unary != null && unary.operator == CCodeUnaryOperator.POINTER_INDIRECTION) {
144 // *expr => expr
145 instance = unary.inner;
146 } else if (instance is CCodeIdentifier || instance is CCodeMemberAccess) {
147 instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance);
148 } else {
149 // if instance is e.g. a function call, we can't take the address of the expression
150 // (tmp = expr, &tmp)
151 var ccomma = new CCodeCommaExpression ();
153 var temp_var = get_temp_variable (ma.inner.target_type);
154 temp_vars.insert (0, temp_var);
155 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), instance));
156 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name)));
158 instance = ccomma;
162 in_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
163 out_arg_map.set (get_param_pos (m.cinstance_parameter_position), instance);
164 } else if (m != null && m.binding == MemberBinding.CLASS) {
165 var cl = (Class) m.parent_symbol;
166 var cast = new CCodeFunctionCall (new CCodeIdentifier (cl.get_upper_case_cname (null) + "_CLASS"));
168 CCodeExpression klass;
169 if (ma.inner == null) {
170 if (in_static_or_class_context) {
171 // Accessing the method from a static or class constructor
172 klass = new CCodeIdentifier ("klass");
173 } else {
174 // Accessing the method from within an instance method
175 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
176 k.add_argument (new CCodeIdentifier ("self"));
177 klass = k;
179 } else {
180 // Accessing the method of an instance
181 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
182 k.add_argument ((CCodeExpression) ma.inner.ccodenode);
183 klass = k;
186 cast.add_argument (klass);
187 in_arg_map.set (get_param_pos (m.cinstance_parameter_position), cast);
188 out_arg_map.set (get_param_pos (m.cinstance_parameter_position), cast);
191 if (m != null && m.has_generic_type_parameter) {
192 // insert type argument for macros
193 int type_param_index = 0;
194 foreach (var type_arg in ma.inner.value_type.get_type_arguments ()) {
195 in_arg_map.set (get_param_pos (m.generic_type_parameter_position + 0.01 * type_param_index), new CCodeIdentifier (type_arg.get_cname ()));
196 type_param_index++;
200 if (m is ArrayMoveMethod) {
201 var array_type = (ArrayType) ma.inner.value_type;
202 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
203 csizeof.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
204 in_arg_map.set (get_param_pos (0.1), csizeof);
205 } else if (m is DynamicMethod) {
206 m.clear_parameters ();
207 int param_nr = 1;
208 foreach (Expression arg in expr.get_argument_list ()) {
209 var unary = arg as UnaryExpression;
210 if (unary != null && unary.operator == UnaryOperator.OUT) {
211 // out argument
212 var param = new FormalParameter ("param%d".printf (param_nr), unary.inner.value_type);
213 param.direction = ParameterDirection.OUT;
214 m.add_parameter (param);
215 } else if (unary != null && unary.operator == UnaryOperator.REF) {
216 // ref argument
217 var param = new FormalParameter ("param%d".printf (param_nr), unary.inner.value_type);
218 param.direction = ParameterDirection.REF;
219 m.add_parameter (param);
220 } else {
221 // in argument
222 m.add_parameter (new FormalParameter ("param%d".printf (param_nr), arg.value_type));
224 param_nr++;
226 foreach (FormalParameter param in m.get_parameters ()) {
227 param.accept (codegen);
229 head.generate_dynamic_method_wrapper ((DynamicMethod) m);
230 } else if (m is CreationMethod && context.profile == Profile.GOBJECT) {
231 ccall_expr = new CCodeAssignment (new CCodeIdentifier ("self"), new CCodeCastExpression (ccall, current_class.get_cname () + "*"));
233 if (!current_class.is_compact && current_class.get_type_parameters ().size > 0) {
234 var ccomma = new CCodeCommaExpression ();
235 ccomma.append_expression (ccall_expr);
237 /* type, dup func, and destroy func fields for generic types */
238 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
239 CCodeIdentifier param_name;
241 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
243 param_name = new CCodeIdentifier ("%s_type".printf (type_param.name.down ()));
244 ccomma.append_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name));
246 param_name = new CCodeIdentifier ("%s_dup_func".printf (type_param.name.down ()));
247 ccomma.append_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name));
249 param_name = new CCodeIdentifier ("%s_destroy_func".printf (type_param.name.down ()));
250 ccomma.append_expression (new CCodeAssignment (new CCodeMemberAccess.pointer (priv_access, param_name.name), param_name));
253 ccall_expr = ccomma;
257 bool ellipsis = false;
259 int i = 1;
260 int arg_pos;
261 Iterator<FormalParameter> params_it = params.iterator ();
262 foreach (Expression arg in expr.get_argument_list ()) {
263 CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
265 var carg_map = in_arg_map;
267 if (params_it.next ()) {
268 var param = params_it.get ();
269 ellipsis = param.params_array || param.ellipsis;
270 if (!ellipsis) {
271 // if the vala argument expands to multiple C arguments,
272 // we have to make sure that the C arguments don't depend
273 // on each other as there is no guaranteed argument
274 // evaluation order
275 // http://bugzilla.gnome.org/show_bug.cgi?id=519597
276 bool multiple_cargs = false;
278 if (param.direction == ParameterDirection.OUT) {
279 carg_map = out_arg_map;
282 if (!param.no_array_length && param.parameter_type is ArrayType) {
283 var array_type = (ArrayType) param.parameter_type;
284 for (int dim = 1; dim <= array_type.rank; dim++) {
285 carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), head.get_array_length_cexpression (arg, dim));
287 multiple_cargs = true;
288 } else if (param.parameter_type is DelegateType) {
289 var deleg_type = (DelegateType) param.parameter_type;
290 var d = deleg_type.delegate_symbol;
291 if (d.has_target) {
292 var delegate_target = get_delegate_target_cexpression (arg);
293 if (deleg_type.value_owned) {
294 CCodeExpression delegate_target_destroy_notify;
295 var delegate_method = arg.symbol_reference as Method;
296 var lambda = arg as LambdaExpression;
297 var arg_ma = arg as MemberAccess;
298 if (lambda != null) {
299 if (delegate_method.closure) {
300 var closure_block = current_symbol as Block;
301 while (closure_block != null && !closure_block.captured) {
302 closure_block = closure_block.parent_symbol as Block;
304 int block_id = get_block_id (closure_block);
305 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("block%d_data_ref".printf (block_id)));
306 ref_call.add_argument (delegate_target);
307 delegate_target = ref_call;
308 delegate_target_destroy_notify = new CCodeIdentifier ("block%d_data_unref".printf (block_id));
309 } else if (get_this_type () != null) {
310 // type of delegate target is same as `this'
311 // for lambda expressions in instance methods
312 var ref_call = new CCodeFunctionCall (get_dup_func_expression (get_this_type (), arg.source_reference));
313 ref_call.add_argument (delegate_target);
314 delegate_target = ref_call;
315 delegate_target_destroy_notify = get_destroy_func_expression (get_this_type ());
316 } else {
317 delegate_target_destroy_notify = new CCodeConstant ("NULL");
319 } else if (delegate_method != null && delegate_method.binding == MemberBinding.INSTANCE
320 && arg_ma != null && arg_ma.inner != null && arg_ma.inner.value_type.data_type != null
321 && arg_ma.inner.value_type.data_type.is_reference_counting ()) {
322 var ref_call = new CCodeFunctionCall (get_dup_func_expression (arg_ma.inner.value_type, arg.source_reference));
323 ref_call.add_argument (delegate_target);
324 delegate_target = ref_call;
325 delegate_target_destroy_notify = get_destroy_func_expression (arg_ma.inner.value_type);
326 } else {
327 delegate_target_destroy_notify = new CCodeConstant ("NULL");
329 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position + 0.01), delegate_target_destroy_notify);
331 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), delegate_target);
332 multiple_cargs = true;
334 } else if (param.parameter_type is MethodType) {
335 carg_map.set (get_param_pos (param.cdelegate_target_parameter_position), get_delegate_target_cexpression (arg));
336 multiple_cargs = true;
339 cexpr = handle_struct_argument (param, arg, cexpr);
341 if (multiple_cargs && arg is MethodCall) {
342 // if vala argument is invocation expression
343 // the auxiliary C argument(s) will depend on the main C argument
345 // (tmp = arg1, call (tmp, arg2, arg3,...))
347 var ccomma = new CCodeCommaExpression ();
349 var temp_decl = get_temp_variable (arg.value_type);
350 temp_vars.insert (0, temp_decl);
351 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_decl.name), cexpr));
353 cexpr = get_variable_cexpression (temp_decl.name);
355 ccomma.append_expression (ccall_expr);
357 ccall_expr = ccomma;
360 // unref old value for non-null non-weak ref/out arguments
361 // disabled for arrays for now as that requires special handling
362 // (ret_tmp = call (&tmp), var1 = (assign_tmp = dup (tmp), free (var1), assign_tmp), ret_tmp)
363 if (param.direction != ParameterDirection.IN && requires_destroy (arg.value_type)
364 && (param.direction == ParameterDirection.OUT || !param.parameter_type.value_owned)
365 && !(param.parameter_type is ArrayType)) {
366 var unary = (UnaryExpression) arg;
368 var ccomma = new CCodeCommaExpression ();
370 var temp_var = get_temp_variable (param.parameter_type, param.parameter_type.value_owned);
371 temp_vars.insert (0, temp_var);
372 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_var.name));
374 if (param.direction == ParameterDirection.REF) {
375 var crefcomma = new CCodeCommaExpression ();
376 crefcomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), (CCodeExpression) unary.inner.ccodenode));
377 crefcomma.append_expression (cexpr);
378 cexpr = crefcomma;
381 // call function
382 LocalVariable ret_temp_var = null;
383 if (itype.get_return_type () is VoidType) {
384 ccomma.append_expression (ccall_expr);
385 } else {
386 ret_temp_var = get_temp_variable (itype.get_return_type ());
387 temp_vars.insert (0, ret_temp_var);
388 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (ret_temp_var.name), ccall_expr));
391 var cassign_comma = new CCodeCommaExpression ();
393 var assign_temp_var = get_temp_variable (unary.inner.value_type, unary.inner.value_type.value_owned);
394 temp_vars.insert (0, assign_temp_var);
396 cassign_comma.append_expression (new CCodeAssignment (get_variable_cexpression (assign_temp_var.name), transform_expression (get_variable_cexpression (temp_var.name), param.parameter_type, unary.inner.value_type, arg)));
398 // unref old value
399 cassign_comma.append_expression (get_unref_expression ((CCodeExpression) unary.inner.ccodenode, arg.value_type, arg));
401 cassign_comma.append_expression (get_variable_cexpression (assign_temp_var.name));
403 // assign new value
404 ccomma.append_expression (new CCodeAssignment ((CCodeExpression) unary.inner.ccodenode, cassign_comma));
406 // return value
407 if (!(itype.get_return_type () is VoidType)) {
408 ccomma.append_expression (get_variable_cexpression (ret_temp_var.name));
411 ccall_expr = ccomma;
414 if (param.ctype != null) {
415 cexpr = new CCodeCastExpression (cexpr, param.ctype);
418 arg_pos = get_param_pos (param.cparameter_position, ellipsis);
419 } else {
420 // default argument position
421 arg_pos = get_param_pos (i, ellipsis);
424 carg_map.set (arg_pos, cexpr);
426 i++;
428 if (params_it.next ()) {
429 var param = params_it.get ();
431 /* if there are more parameters than arguments,
432 * the additional parameter is an ellipsis parameter
433 * otherwise there is a bug in the semantic analyzer
435 assert (param.params_array || param.ellipsis);
436 ellipsis = true;
439 /* add length argument for methods returning arrays */
440 if (m != null && m.return_type is ArrayType) {
441 var array_type = (ArrayType) m.return_type;
442 for (int dim = 1; dim <= array_type.rank; dim++) {
443 if (m.array_null_terminated) {
444 // handle calls to methods returning null-terminated arrays
445 var temp_var = get_temp_variable (itype.get_return_type ());
446 var temp_ref = get_variable_cexpression (temp_var.name);
448 temp_vars.insert (0, temp_var);
450 ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
452 requires_array_length = true;
453 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
454 len_call.add_argument (temp_ref);
456 expr.append_array_size (len_call);
457 } else if (!m.no_array_length) {
458 LocalVariable temp_var;
460 if (m.array_length_type == null) {
461 temp_var = get_temp_variable (int_type);
462 } else {
463 temp_var = get_temp_variable (new CType (m.array_length_type));
465 var temp_ref = get_variable_cexpression (temp_var.name);
467 temp_vars.insert (0, temp_var);
469 out_arg_map.set (get_param_pos (m.carray_length_parameter_position + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
471 expr.append_array_size (temp_ref);
472 } else {
473 expr.append_array_size (new CCodeConstant ("-1"));
476 } else if (m != null && m.return_type is DelegateType) {
477 var deleg_type = (DelegateType) m.return_type;
478 var d = deleg_type.delegate_symbol;
479 if (d.has_target) {
480 var temp_var = get_temp_variable (new PointerType (new VoidType ()));
481 var temp_ref = get_variable_cexpression (temp_var.name);
483 temp_vars.insert (0, temp_var);
485 out_arg_map.set (get_param_pos (m.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
487 expr.delegate_target = temp_ref;
491 // add length argument for delegates returning arrays
492 // TODO: avoid code duplication with methods returning arrays, see above
493 if (deleg != null && deleg.return_type is ArrayType) {
494 var array_type = (ArrayType) deleg.return_type;
495 for (int dim = 1; dim <= array_type.rank; dim++) {
496 if (deleg.array_null_terminated) {
497 // handle calls to methods returning null-terminated arrays
498 var temp_var = get_temp_variable (itype.get_return_type ());
499 var temp_ref = get_variable_cexpression (temp_var.name);
501 temp_vars.insert (0, temp_var);
503 ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
505 requires_array_length = true;
506 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
507 len_call.add_argument (temp_ref);
509 expr.append_array_size (len_call);
510 } else if (!deleg.no_array_length) {
511 var temp_var = get_temp_variable (int_type);
512 var temp_ref = get_variable_cexpression (temp_var.name);
514 temp_vars.insert (0, temp_var);
516 out_arg_map.set (get_param_pos (deleg.carray_length_parameter_position + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
518 expr.append_array_size (temp_ref);
519 } else {
520 expr.append_array_size (new CCodeConstant ("-1"));
523 } else if (deleg != null && deleg.return_type is DelegateType) {
524 var deleg_type = (DelegateType) deleg.return_type;
525 var d = deleg_type.delegate_symbol;
526 if (d.has_target) {
527 var temp_var = get_temp_variable (new PointerType (new VoidType ()));
528 var temp_ref = get_variable_cexpression (temp_var.name);
530 temp_vars.insert (0, temp_var);
532 out_arg_map.set (get_param_pos (deleg.cdelegate_target_parameter_position), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
534 expr.delegate_target = temp_ref;
538 if (m != null && m.coroutine) {
539 if (expr.is_yield_expression) {
540 // asynchronous call
541 in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (current_method.get_cname () + "_ready"));
542 in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("data"));
546 if (m is CreationMethod && m.get_error_types ().size > 0) {
547 out_arg_map.set (get_param_pos (-1), new CCodeIdentifier ("error"));
548 } else if (expr.tree_can_fail) {
549 // method can fail
550 current_method_inner_error = true;
551 // add &inner_error before the ellipsis arguments
552 out_arg_map.set (get_param_pos (-1), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
555 if (ellipsis) {
556 /* ensure variable argument list ends with NULL
557 * except when using printf-style arguments */
558 if (!m.printf_format && !m.scanf_format && m.sentinel != "") {
559 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (m.sentinel));
561 } else if (itype is DelegateType) {
562 var deleg_type = (DelegateType) itype;
563 var d = deleg_type.delegate_symbol;
564 if (d.has_target) {
565 in_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call));
566 out_arg_map.set (get_param_pos (d.cinstance_parameter_position), get_delegate_target_cexpression (expr.call));
570 // structs are returned via out parameter
571 bool return_result_via_out_param = itype.get_return_type ().is_real_struct_type ();
573 // pass address for the return value of non-void signals without emitter functions
574 if (itype is SignalType && !(itype.get_return_type () is VoidType)) {
575 var sig = ((SignalType) itype).signal_symbol;
577 if (ma != null && ma.inner is BaseAccess && sig.is_virtual) {
578 // normal return value for base access
579 } else if (!sig.has_emitter) {
580 return_result_via_out_param = true;
584 if (return_result_via_out_param) {
585 var temp_var = get_temp_variable (itype.get_return_type ());
586 var temp_ref = get_variable_cexpression (temp_var.name);
588 temp_vars.insert (0, temp_var);
590 out_arg_map.set (get_param_pos (-3, true), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
592 var ccomma = new CCodeCommaExpression ();
593 ccomma.append_expression ((CCodeExpression) ccall_expr);
594 ccomma.append_expression ((CCodeExpression) temp_ref);
596 ccall_expr = ccomma;
599 // append C arguments in the right order
601 int last_pos;
602 int min_pos;
604 if (async_call != ccall) {
605 // don't append out arguments for .begin() calls
606 last_pos = -1;
607 while (true) {
608 min_pos = -1;
609 foreach (int pos in out_arg_map.get_keys ()) {
610 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
611 min_pos = pos;
614 if (min_pos == -1) {
615 break;
617 ccall.add_argument (out_arg_map.get (min_pos));
618 last_pos = min_pos;
622 if (async_call != null) {
623 last_pos = -1;
624 while (true) {
625 min_pos = -1;
626 foreach (int pos in in_arg_map.get_keys ()) {
627 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
628 min_pos = pos;
631 if (min_pos == -1) {
632 break;
634 async_call.add_argument (in_arg_map.get (min_pos));
635 last_pos = min_pos;
639 if (m != null && m.binding == MemberBinding.INSTANCE && m.returns_modified_pointer) {
640 expr.ccodenode = new CCodeAssignment (instance, ccall_expr);
641 } else {
642 expr.ccodenode = ccall_expr;
645 if (m != null && m.coroutine && current_method != null && current_method.coroutine) {
646 if (ma.member_name != "begin" || ma.inner.symbol_reference != ma.symbol_reference) {
647 if (pre_statement_fragment == null) {
648 pre_statement_fragment = new CCodeFragment ();
650 pre_statement_fragment.append (new CCodeExpressionStatement (async_call));
652 int state = next_coroutine_state++;
653 pre_statement_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "state"), new CCodeConstant (state.to_string ()))));
654 pre_statement_fragment.append (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
655 pre_statement_fragment.append (new CCodeCaseStatement (new CCodeConstant (state.to_string ())));
659 if (m is ArrayResizeMethod) {
660 // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
661 Iterator<Expression> arg_it = expr.get_argument_list ().iterator ();
662 arg_it.next ();
663 var new_size = (CCodeExpression) arg_it.get ().ccodenode;
665 var temp_decl = get_temp_variable (int_type);
666 var temp_ref = get_variable_cexpression (temp_decl.name);
668 temp_vars.insert (0, temp_decl);
670 /* memset needs string.h */
671 source_declarations.add_include ("string.h");
673 var clen = head.get_array_length_cexpression (ma.inner, 1);
674 var celems = (CCodeExpression) ma.inner.ccodenode;
675 var array_type = (ArrayType) ma.inner.value_type;
676 var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (array_type.element_type.get_cname ()));
677 var cdelta = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, temp_ref, clen);
678 var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, temp_ref, clen);
680 var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
681 czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, celems, clen));
682 czero.add_argument (new CCodeConstant ("0"));
683 czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cdelta));
685 var ccomma = new CCodeCommaExpression ();
686 ccomma.append_expression (new CCodeAssignment (temp_ref, new_size));
687 ccomma.append_expression ((CCodeExpression) expr.ccodenode);
688 ccomma.append_expression (new CCodeConditionalExpression (ccheck, czero, new CCodeConstant ("NULL")));
689 ccomma.append_expression (new CCodeAssignment (head.get_array_length_cexpression (ma.inner, 1), temp_ref));
691 expr.ccodenode = ccomma;