LCOV - code coverage report
Current view: top level - codegen - valagasyncmodule.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 97.1 % 483 469
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

            Line data    Source code
       1              : /* valagasyncmodule.vala
       2              :  *
       3              :  * Copyright (C) 2008-2012  Jürg Billeter
       4              :  *
       5              :  * This library is free software; you can redistribute it and/or
       6              :  * modify it under the terms of the GNU Lesser General Public
       7              :  * License as published by the Free Software Foundation; either
       8              :  * version 2.1 of the License, or (at your option) any later version.
       9              : 
      10              :  * This library is distributed in the hope that it will be useful,
      11              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13              :  * Lesser General Public License for more details.
      14              : 
      15              :  * You should have received a copy of the GNU Lesser General Public
      16              :  * License along with this library; if not, write to the Free Software
      17              :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
      18              :  *
      19              :  * Author:
      20              :  *      Jürg Billeter <j@bitron.ch>
      21              :  */
      22              : 
      23              : using GLib;
      24              : 
      25         2914 : public class Vala.GAsyncModule : GtkModule {
      26          127 :         CCodeStruct generate_data_struct (Method m) {
      27          127 :                 string dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
      28          127 :                 var data = new CCodeStruct ("_" + dataname);
      29              : 
      30          127 :                 data.add_field ("int", "_state_");
      31          127 :                 data.add_field ("GObject*", "_source_object_");
      32          127 :                 data.add_field ("GAsyncResult*", "_res_");
      33          127 :                 data.add_field ("GTask*", "_async_result");
      34              : 
      35          127 :                 if (m is CreationMethod) {
      36            9 :                         data.add_field ("GType", "object_type");
      37              :                 }
      38              : 
      39          196 :                 if (m.binding == MemberBinding.INSTANCE) {
      40          436 :                         var type_sym = (TypeSymbol) m.parent_symbol;
      41           69 :                         if (type_sym is ObjectTypeSymbol) {
      42           69 :                                 data.add_field (get_ccode_name (type_sym) + "*", "self");
      43              :                         } else {
      44            0 :                                 data.add_field (get_ccode_name (type_sym), "self");
      45              :                         }
      46              :                 }
      47              : 
      48          219 :                 foreach (Parameter param in m.get_parameters ()) {
      49           46 :                         var param_type = param.variable_type.copy ();
      50           46 :                         param_type.value_owned = true;
      51           46 :                         data.add_field (get_ccode_name (param_type), get_ccode_name (param), 0, get_ccode_declarator_suffix (param_type));
      52              : 
      53           53 :                         if (param.variable_type is ArrayType) {
      54            7 :                                 var array_type = (ArrayType) param.variable_type;
      55           12 :                                 if (get_ccode_array_length (param) && !((ArrayType) array_type).fixed_length) {
      56            5 :                                         var length_ctype = get_ccode_array_length_type (param);
      57           10 :                                         for (int dim = 1; dim <= array_type.rank; dim++) {
      58            5 :                                                 data.add_field (length_ctype, get_variable_array_length_cname (param, dim));
      59              :                                         }
      60              :                                 }
      61           41 :                         } else if (param.variable_type is DelegateType) {
      62            2 :                                 var deleg_type = (DelegateType) param.variable_type;
      63            2 :                                 if (deleg_type.delegate_symbol.has_target) {
      64            2 :                                         data.add_field (get_ccode_name (delegate_target_type), get_ccode_delegate_target_name (param));
      65            2 :                                         if (deleg_type.is_disposable ()) {
      66            2 :                                                 data.add_field (get_ccode_name (delegate_target_destroy_type), get_ccode_delegate_target_destroy_notify_name (param));
      67              :                                         }
      68              :                                 }
      69              :                         }
      70              :                 }
      71              : 
      72          137 :                 foreach (var type_param in m.get_type_parameters ()) {
      73            5 :                         data.add_field ("GType", get_ccode_type_id (type_param));
      74            5 :                         data.add_field ("GBoxedCopyFunc", get_ccode_copy_function (type_param));
      75            5 :                         data.add_field ("GDestroyNotify", get_ccode_destroy_function (type_param));
      76              :                 }
      77              : 
      78          127 :                 if (!(m.return_type is VoidType)) {
      79           31 :                         data.add_field (get_ccode_name (m.return_type), "result");
      80           34 :                         if (m.return_type is ArrayType) {
      81            3 :                                 var array_type = (ArrayType) m.return_type;
      82            5 :                                 if (get_ccode_array_length (m)) {
      83            2 :                                         var length_ctype = get_ccode_array_length_type (m);
      84            4 :                                         for (int dim = 1; dim <= array_type.rank; dim++) {
      85            2 :                                                 data.add_field (length_ctype, get_array_length_cname ("result", dim));
      86              :                                         }
      87              :                                 }
      88           29 :                         } else if (m.return_type is DelegateType) {
      89            1 :                                 var deleg_type = (DelegateType) m.return_type;
      90            1 :                                 if (deleg_type.delegate_symbol.has_target) {
      91            1 :                                         data.add_field (get_ccode_name (delegate_target_type), get_delegate_target_cname ("result"));
      92            1 :                                         data.add_field (get_ccode_name (delegate_target_destroy_type), get_delegate_target_destroy_notify_cname ("result"));
      93              :                                 }
      94              :                         }
      95              :                 }
      96              : 
      97          127 :                 return data;
      98              :         }
      99              : 
     100          127 :         CCodeFunction generate_free_function (Method m) {
     101          127 :                 var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
     102              : 
     103          127 :                 var freefunc = new CCodeFunction (get_ccode_real_name (m) + "_data_free", "void");
     104          127 :                 freefunc.modifiers = CCodeModifiers.STATIC;
     105          127 :                 freefunc.add_parameter (new CCodeParameter ("_data", "gpointer"));
     106              : 
     107          127 :                 push_context (new EmitContext (m));
     108          127 :                 push_function (freefunc);
     109              : 
     110          127 :                 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_", new CCodeIdentifier ("_data")));
     111              : 
     112          219 :                 foreach (Parameter param in m.get_parameters ()) {
     113           77 :                         if (!param.captured && param.direction != ParameterDirection.OUT) {
     114           31 :                                 var param_type = param.variable_type.copy ();
     115           31 :                                 if (!param_type.value_owned) {
     116           29 :                                         param_type.value_owned = !no_implicit_copy (param_type);
     117              :                                 }
     118              : 
     119           31 :                                 if (requires_destroy (param_type)) {
     120           15 :                                         ccode.add_expression (destroy_parameter (param));
     121              :                                 }
     122              :                         }
     123              :                 }
     124              : 
     125          127 :                 if (requires_destroy (m.return_type)) {
     126           36 :                         if (get_ccode_array_length (m) || !(m.return_type is ArrayType)) {
     127              :                                 /* this is very evil. */
     128           17 :                                 var v = new LocalVariable (m.return_type, ".result");
     129           17 :                                 ccode.add_expression (destroy_local (v));
     130              :                         } else {
     131            1 :                                 var v = new GLibValue (m.return_type, new CCodeIdentifier ("_data_->result"), true);
     132            1 :                                 v.array_null_terminated = get_ccode_array_null_terminated (m);
     133            1 :                                 ccode.add_expression (destroy_value (v));
     134              :                         }
     135              :                 }
     136              : 
     137          196 :                 if (m.binding == MemberBinding.INSTANCE) {
     138           69 :                         var this_type = m.this_parameter.variable_type.copy ();
     139           69 :                         this_type.value_owned = true;
     140              : 
     141           69 :                         if (requires_destroy (this_type)) {
     142           69 :                                 ccode.add_expression (destroy_parameter (m.this_parameter));
     143              :                         }
     144              :                 }
     145              : 
     146          127 :                 var freecall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
     147          127 :                 freecall.add_argument (new CCodeIdentifier (dataname));
     148          127 :                 freecall.add_argument (new CCodeIdentifier ("_data_"));
     149          127 :                 ccode.add_expression (freecall);
     150              : 
     151          127 :                 pop_context ();
     152              : 
     153          127 :                 cfile.add_function_declaration (freefunc);
     154          127 :                 cfile.add_function (freefunc);
     155              : 
     156          127 :                 return freefunc;
     157              :         }
     158              : 
     159          254 :         void generate_async_function (Method m) {
     160          127 :                 push_context (new EmitContext ());
     161              : 
     162          127 :                 var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
     163          127 :                 var asyncfunc = new CCodeFunction (get_ccode_real_name (m), "void");
     164          127 :                 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     165              : 
     166          127 :                 cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
     167          127 :                 cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
     168              : 
     169          127 :                 generate_cparameters (m, cfile, cparam_map, asyncfunc, null, null, null, 1);
     170              : 
     171          127 :                 if (m.base_method != null || m.base_interface_method != null) {
     172              :                         // declare *_real_* function
     173           30 :                         asyncfunc.modifiers |= CCodeModifiers.STATIC;
     174           30 :                         cfile.add_function_declaration (asyncfunc);
     175           97 :                 } else if (m.is_private_symbol ()) {
     176            5 :                         asyncfunc.modifiers |= CCodeModifiers.STATIC;
     177           92 :                 } else if (context.hide_internal && m.is_internal_symbol ()) {
     178            0 :                         asyncfunc.modifiers |= CCodeModifiers.INTERNAL;
     179              :                 }
     180              : 
     181          127 :                 push_function (asyncfunc);
     182              : 
     183              :                 // FIXME partial code duplication with CCodeMethodModule.visit_method
     184          127 :                 unowned Class? cl = m.parent_symbol as Class;
     185          190 :                 if (cl != null) {
     186           63 :                         if (m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)
     187           53 :                             && m.base_method == null && m.base_interface_method == null) {
     188           29 :                                 create_type_check_statement (m, new VoidType (), cl, true, "self");
     189              :                         }
     190              :                 }
     191          219 :                 foreach (Parameter param in m.get_parameters ()) {
     192           46 :                         if (param.ellipsis || param.params_array) {
     193            0 :                                 break;
     194              :                         }
     195              : 
     196           46 :                         if (param.direction == ParameterDirection.IN) {
     197           36 :                                 unowned TypeSymbol? t = param.variable_type.type_symbol;
     198           36 :                                 if (t != null && (t.is_reference_type () || param.variable_type.is_real_struct_type ())) {
     199           12 :                                         create_type_check_statement (m, new VoidType (), t, !param.variable_type.nullable, get_ccode_name (param));
     200              :                                 }
     201              :                         }
     202              :                 }
     203              : 
     204              :                 // logic copied from valaccodemethodmodule
     205          142 :                 if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
     206              :                         Method base_method;
     207              : 
     208           15 :                         if (m.overrides && m.base_method != null) {
     209           10 :                                 base_method = m.base_method;
     210              :                         } else {
     211            5 :                                 base_method = m.base_interface_method;
     212              :                         }
     213              : 
     214           15 :                         var base_expression_type = new ObjectType ((ObjectTypeSymbol) base_method.parent_symbol);
     215           15 :                         var type_symbol = m.parent_symbol as ObjectTypeSymbol;
     216              : 
     217           15 :                         var self_target_type = new ObjectType (type_symbol);
     218          202 :                         var cself = get_cvalue_ (transform_value (new GLibValue (base_expression_type, new CCodeIdentifier ("base"), true), self_target_type, m));
     219           15 :                         ccode.add_declaration ("%s *".printf (get_ccode_name (type_symbol)), new CCodeVariableDeclarator ("self"));
     220           15 :                         ccode.add_assignment (new CCodeIdentifier ("self"), cself);
     221              :                 }
     222              : 
     223          127 :                 var dataalloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
     224          127 :                 dataalloc.add_argument (new CCodeIdentifier (dataname));
     225              : 
     226          127 :                 var data_var = new CCodeIdentifier ("_data_");
     227              : 
     228          127 :                 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
     229          127 :                 ccode.add_assignment (data_var, dataalloc);
     230              : 
     231          127 :                 var create_result = new CCodeFunctionCall (new CCodeIdentifier ("g_task_new"));
     232              : 
     233          127 :                 var t = m.parent_symbol as TypeSymbol;
     234          229 :                 if (!(m is CreationMethod) && m.binding == MemberBinding.INSTANCE &&
     235           60 :                     t != null && t.is_subtype_of (gobject_type)) {
     236           42 :                         var gobject_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
     237           42 :                         gobject_cast.add_argument (new CCodeIdentifier ("self"));
     238              : 
     239           42 :                         create_result.add_argument (gobject_cast);
     240              :                 } else {
     241           85 :                         create_result.add_argument (new CCodeConstant ("NULL"));
     242              :                 }
     243              : 
     244          127 :                 Parameter cancellable_param = null;
     245              : 
     246          217 :                 foreach (Parameter param in m.get_parameters ()) {
     247           46 :                         if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.Cancellable") {
     248            1 :                                 cancellable_param = param;
     249            1 :                                 break;
     250              :                         }
     251              :                 }
     252              : 
     253          127 :                 if (cancellable_param == null) {
     254          126 :                         create_result.add_argument (new CCodeConstant ("NULL"));
     255              :                 } else {
     256            1 :                         create_result.add_argument (new CCodeIdentifier (get_ccode_name (cancellable_param)));
     257              :                 }
     258              : 
     259          127 :                 create_result.add_argument (new CCodeIdentifier ("_callback_"));
     260          127 :                 create_result.add_argument (new CCodeIdentifier ("_user_data_"));
     261              : 
     262          127 :                 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_async_result"), create_result);
     263              : 
     264          127 :                 var attach_data_call = new CCodeFunctionCall (new CCodeIdentifier ("g_task_set_task_data"));
     265              : 
     266          127 :                 attach_data_call.add_argument (new CCodeMemberAccess.pointer (data_var, "_async_result"));
     267          127 :                 attach_data_call.add_argument (data_var);
     268          127 :                 attach_data_call.add_argument (new CCodeIdentifier (get_ccode_real_name (m) + "_data_free"));
     269          127 :                 ccode.add_expression (attach_data_call);
     270              : 
     271          127 :                 if (m is CreationMethod) {
     272            9 :                         ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "object_type"), new CCodeIdentifier ("object_type"));
     273          178 :                 } else if (m.binding == MemberBinding.INSTANCE) {
     274           60 :                         var this_type = m.this_parameter.variable_type.copy ();
     275           60 :                         this_type.value_owned = true;
     276              : 
     277              :                         // create copy if necessary as variables in async methods may need to be kept alive
     278           60 :                         CCodeExpression cself = new CCodeIdentifier ("self");
     279           60 :                         if (this_type.is_real_non_null_struct_type ()) {
     280            0 :                                 cself = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cself);
     281              :                         }
     282           60 :                         if (requires_copy (this_type))  {
     283          120 :                                 cself = get_cvalue_ (copy_value (new GLibValue (m.this_parameter.variable_type, cself, true), m.this_parameter));
     284              :                         }
     285              : 
     286           60 :                         ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "self"), cself);
     287              :                 }
     288              : 
     289          127 :                 emit_context.push_symbol (m);
     290          219 :                 foreach (Parameter param in m.get_parameters ()) {
     291           82 :                         if (param.direction != ParameterDirection.OUT) {
     292              :                                 // create copy if necessary as variables in async methods may need to be kept alive
     293           36 :                                 var old_captured = param.captured;
     294           36 :                                 param.captured = false;
     295           36 :                                 current_method.coroutine = false;
     296              : 
     297              :                                 TargetValue value;
     298           36 :                                 if (param.variable_type.value_owned) {
     299              :                                         // do not use load_parameter for reference/ownership transfer
     300              :                                         // otherwise delegate destroy notify will not be moved
     301            3 :                                         value = get_parameter_cvalue (param);
     302              :                                 } else  {
     303           33 :                                         value = load_parameter (param);
     304              :                                 }
     305              : 
     306           36 :                                 current_method.coroutine = true;
     307              : 
     308           36 :                                 store_parameter (param, value);
     309              : 
     310           36 :                                 param.captured = old_captured;
     311              :                         }
     312              :                 }
     313          127 :                 emit_context.pop_symbol ();
     314              : 
     315          137 :                 foreach (var type_param in m.get_type_parameters ()) {
     316            5 :                         var type = get_ccode_type_id (type_param);
     317            5 :                         var dup_func = get_ccode_copy_function (type_param);
     318            5 :                         var destroy_func = get_ccode_destroy_function (type_param);
     319            5 :                         ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, type), new CCodeIdentifier (type));
     320            5 :                         ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, dup_func), new CCodeIdentifier (dup_func));
     321            5 :                         ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, destroy_func), new CCodeIdentifier (destroy_func));
     322              :                 }
     323              : 
     324          127 :                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m) + "_co"));
     325          127 :                 ccall.add_argument (data_var);
     326          127 :                 ccode.add_expression (ccall);
     327              : 
     328          127 :                 cfile.add_function (asyncfunc);
     329              : 
     330          127 :                 pop_context ();
     331              :         }
     332              : 
     333          302 :         public void append_struct (CCodeStruct structure) {
     334          151 :                 var typename = new CCodeVariableDeclarator (structure.name.substring (1));
     335          151 :                 var typedef = new CCodeTypeDefinition ("struct " + structure.name, typename);
     336          151 :                 cfile.add_type_declaration (typedef);
     337          151 :                 cfile.add_type_definition (structure);
     338              :         }
     339              : 
     340        28825 :         public override bool generate_method_declaration (Method m, CCodeFile decl_space) {
     341        28825 :                 if (m.coroutine) {
     342          549 :                         if ((m.is_abstract || m.is_virtual) && get_ccode_no_wrapper (m)) {
     343          262 :                                 return false;
     344              :                         }
     345          525 :                         if (add_symbol_declaration (decl_space, m, get_ccode_name (m))) {
     346          262 :                                 return false;
     347              :                         }
     348              : 
     349          287 :                         generate_type_declaration (new MethodType (m), decl_space);
     350              : 
     351          287 :                         var cl = m.parent_symbol as Class;
     352              : 
     353          287 :                         var asyncfunc = new CCodeFunction (get_ccode_name (m), "void");
     354          287 :                         var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     355          287 :                         var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
     356              : 
     357          287 :                         if (m.is_private_symbol () || m.entry_point) {
     358           18 :                                 asyncfunc.modifiers |= CCodeModifiers.STATIC;
     359          269 :                         } else if (context.hide_internal && m.is_internal_symbol ()) {
     360            0 :                                 asyncfunc.modifiers |= CCodeModifiers.INTERNAL;
     361              :                         } else {
     362          269 :                                 asyncfunc.modifiers |= CCodeModifiers.EXTERN;
     363          269 :                                 requires_vala_extern = true;
     364              :                         }
     365              : 
     366              :                         // do not generate _new functions for creation methods of abstract classes
     367          287 :                         if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
     368          284 :                                 generate_cparameters (m, decl_space, cparam_map, asyncfunc, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")), 1);
     369              : 
     370          284 :                                 decl_space.add_function_declaration (asyncfunc);
     371              :                         }
     372              : 
     373          287 :                         var finishfunc = new CCodeFunction (get_ccode_finish_name (m));
     374          287 :                         cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     375          287 :                         carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
     376              : 
     377          287 :                         if (m.is_private_symbol () || m.entry_point) {
     378           18 :                                 finishfunc.modifiers |= CCodeModifiers.STATIC;
     379          269 :                         } else if (context.hide_internal && m.is_internal_symbol ()) {
     380            0 :                                 finishfunc.modifiers |= CCodeModifiers.INTERNAL;
     381              :                         } else {
     382          269 :                                 finishfunc.modifiers |= CCodeModifiers.EXTERN;
     383          269 :                                 requires_vala_extern = true;
     384              :                         }
     385              : 
     386              :                         // do not generate _new functions for creation methods of abstract classes
     387          287 :                         if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
     388          284 :                                 generate_cparameters (m, decl_space, cparam_map, finishfunc, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")), 2);
     389              : 
     390          284 :                                 decl_space.add_function_declaration (finishfunc);
     391              :                         }
     392              : 
     393          307 :                         if (m is CreationMethod && cl != null) {
     394              :                                 // _construct function
     395           20 :                                 var function = new CCodeFunction (get_ccode_real_name (m));
     396              : 
     397           20 :                                 if (m.is_private_symbol ()) {
     398            0 :                                         function.modifiers |= CCodeModifiers.STATIC;
     399           20 :                                 } else if (context.hide_internal && m.is_internal_symbol ()) {
     400            0 :                                         function.modifiers |= CCodeModifiers.INTERNAL;
     401              :                                 } else {
     402           20 :                                         function.modifiers |= CCodeModifiers.EXTERN;
     403           20 :                                         requires_vala_extern = true;
     404              :                                 }
     405              : 
     406           20 :                                 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     407           20 :                                 generate_cparameters (m, decl_space, cparam_map, function, null, null, null, 1);
     408              : 
     409           20 :                                 decl_space.add_function_declaration (function);
     410              : 
     411           20 :                                 function = new CCodeFunction (get_ccode_finish_real_name (m));
     412              : 
     413           20 :                                 if (m.is_private_symbol ()) {
     414            0 :                                         function.modifiers |= CCodeModifiers.STATIC;
     415           20 :                                 } else if (context.hide_internal && m.is_internal_symbol ()) {
     416            0 :                                         function.modifiers |= CCodeModifiers.INTERNAL;
     417              :                                 } else {
     418           20 :                                         function.modifiers |= CCodeModifiers.EXTERN;
     419           20 :                                         requires_vala_extern = true;
     420              :                                 }
     421              : 
     422           20 :                                 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     423           20 :                                 generate_cparameters (m, decl_space, cparam_map, function, null, null, null, 2);
     424              : 
     425           20 :                                 decl_space.add_function_declaration (function);
     426              :                         }
     427              : 
     428          287 :                         return true;
     429              :                 } else {
     430        28276 :                         return base.generate_method_declaration (m, decl_space);
     431              :                 }
     432              :         }
     433              : 
     434         5094 :         public override void visit_method (Method m) {
     435         5094 :                 if (m.coroutine) {
     436          153 :                         cfile.add_include ("gio/gio.h");
     437          153 :                         if (!m.is_internal_symbol ()) {
     438           32 :                                 header_file.add_include ("gio/gio.h");
     439              :                         }
     440              : 
     441          280 :                         if (!m.is_abstract && m.body != null) {
     442          127 :                                 var data = generate_data_struct (m);
     443              : 
     444          254 :                                 closure_struct = data;
     445              : 
     446          127 :                                 generate_free_function (m);
     447          127 :                                 generate_async_function (m);
     448          127 :                                 generate_finish_function (m);
     449              : 
     450              :                                 // append the _co function
     451          127 :                                 base.visit_method (m);
     452          127 :                                 closure_struct = null;
     453              : 
     454              :                                 // only append data struct here to make sure all struct member
     455              :                                 // types are declared before the struct definition
     456          127 :                                 append_struct (data);
     457              :                         } else {
     458           26 :                                 generate_method_declaration (m, cfile);
     459              : 
     460           26 :                                 if (!m.is_internal_symbol ()) {
     461            7 :                                         generate_method_declaration (m, header_file);
     462              :                                 }
     463           26 :                                 if (!m.is_private_symbol ()) {
     464           26 :                                         generate_method_declaration (m, internal_header_file);
     465              :                                 }
     466              :                         }
     467              : 
     468          189 :                         if ((m.is_abstract || m.is_virtual) && !get_ccode_no_wrapper (m)) {
     469              :                                 // generate virtual function wrappers
     470           36 :                                 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     471           36 :                                 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
     472           36 :                                 generate_vfunc (m, new VoidType (), cparam_map, carg_map, "", 1);
     473              : 
     474           36 :                                 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     475           36 :                                 carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
     476           36 :                                 generate_vfunc (m, m.return_type, cparam_map, carg_map, "_finish", 2);
     477              :                         }
     478              :                 } else {
     479         4941 :                         base.visit_method (m);
     480              :                 }
     481              :         }
     482              : 
     483          845 :         public override void visit_creation_method (CreationMethod m) {
     484          845 :                 if (!m.coroutine) {
     485          836 :                         base.visit_creation_method (m);
     486              :                 } else {
     487            9 :                         push_line (m.source_reference);
     488              : 
     489            9 :                         bool visible = !m.is_private_symbol ();
     490              : 
     491            9 :                         visit_method (m);
     492              : 
     493            9 :                         if (m.source_type == SourceFileType.FAST) {
     494              :                                 return;
     495              :                         }
     496              : 
     497              :                         // do not generate _new functions for creation methods of abstract classes
     498           17 :                         if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
     499            8 :                                 var vfunc = new CCodeFunction (get_ccode_name (m));
     500              : 
     501            8 :                                 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     502            8 :                                 var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
     503              : 
     504            8 :                                 push_function (vfunc);
     505              : 
     506            8 :                                 var vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
     507            8 :                                 vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
     508              : 
     509            8 :                                 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, 1);
     510            8 :                                 ccode.add_expression (vcall);
     511              : 
     512            8 :                                 if (!visible) {
     513            0 :                                         vfunc.modifiers |= CCodeModifiers.STATIC;
     514              :                                 }
     515              : 
     516            8 :                                 pop_function ();
     517              : 
     518            8 :                                 cfile.add_function (vfunc);
     519              : 
     520              : 
     521            8 :                                 vfunc = new CCodeFunction (get_ccode_finish_name (m));
     522              : 
     523            8 :                                 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     524            8 :                                 carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
     525              : 
     526            8 :                                 push_function (vfunc);
     527              : 
     528            8 :                                 vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_real_name (m)));
     529              : 
     530            8 :                                 generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall, 2);
     531            8 :                                 ccode.add_return (vcall);
     532              : 
     533            8 :                                 if (!visible) {
     534            0 :                                         vfunc.modifiers |= CCodeModifiers.STATIC;
     535              :                                 }
     536              : 
     537            8 :                                 pop_function ();
     538              : 
     539            8 :                                 cfile.add_function (vfunc);
     540              :                         }
     541              : 
     542            9 :                         pop_line ();
     543              :                 }
     544              :         }
     545              : 
     546          254 :         void generate_finish_function (Method m) {
     547          127 :                 push_context (new EmitContext ());
     548              : 
     549          127 :                 string dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
     550              : 
     551          127 :                 var finishfunc = new CCodeFunction (get_ccode_finish_real_name (m));
     552              : 
     553          127 :                 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     554              : 
     555          127 :                 cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*"));
     556              : 
     557          127 :                 generate_cparameters (m, cfile, cparam_map, finishfunc, null, null, null, 2);
     558              : 
     559          127 :                 if (m.is_private_symbol () || m.base_method != null || m.base_interface_method != null) {
     560           35 :                         finishfunc.modifiers |= CCodeModifiers.STATIC;
     561           92 :                 } else if (context.hide_internal && m.is_internal_symbol ()) {
     562            0 :                         finishfunc.modifiers |= CCodeModifiers.INTERNAL;
     563              :                 }
     564              : 
     565          127 :                 push_function (finishfunc);
     566              : 
     567          127 :                 var return_type = m.return_type;
     568          136 :                 if (m is CreationMethod) {
     569            9 :                         var type_sym = (TypeSymbol) m.parent_symbol;
     570            9 :                         if (type_sym is ObjectTypeSymbol) {
     571            9 :                                 ccode.add_declaration (get_ccode_name (type_sym) + "*", new CCodeVariableDeclarator ("result"));
     572            9 :                                 return_type = SemanticAnalyzer.get_this_type (m, type_sym);
     573              :                         }
     574          118 :                 } else if (!(return_type is VoidType) && !return_type.is_real_non_null_struct_type ()) {
     575           30 :                         ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator ("result"));
     576              :                 }
     577              : 
     578          127 :                 var data_var = new CCodeIdentifier ("_data_");
     579              : 
     580          127 :                 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
     581              : 
     582          127 :                 var async_result_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_TASK"));
     583          127 :                 async_result_cast.add_argument (new CCodeIdentifier ("_res_"));
     584              : 
     585          127 :                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_task_propagate_pointer"));
     586          127 :                 ccall.add_argument (async_result_cast);
     587              : 
     588          127 :                 if (m.tree_can_fail) {
     589           22 :                         ccall.add_argument (new CCodeIdentifier ("error"));
     590              :                 } else {
     591          105 :                         ccall.add_argument (new CCodeConstant ("NULL"));
     592              :                 }
     593              : 
     594          127 :                 ccode.add_assignment (data_var, ccall);
     595              : 
     596          127 :                 bool has_cancellable = false;
     597              : 
     598          217 :                 foreach (Parameter param in m.get_parameters ()) {
     599           46 :                         if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.Cancellable") {
     600            1 :                                 has_cancellable = true;
     601            1 :                                 break;
     602              :                         }
     603              :                 }
     604              : 
     605              :                 // If a task is cancelled, g_task_propagate_pointer returns NULL
     606          149 :                 if (m.tree_can_fail || has_cancellable) {
     607           22 :                         var is_null = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeConstant ("NULL"), data_var);
     608              : 
     609           22 :                         ccode.open_if (is_null);
     610           22 :                         return_default_value (return_type);
     611           22 :                         ccode.close ();
     612              :                 }
     613              : 
     614          127 :                 emit_context.push_symbol (m);
     615          219 :                 foreach (Parameter param in m.get_parameters ()) {
     616           46 :                         if (param.direction != ParameterDirection.IN) {
     617           10 :                                 return_out_parameter (param);
     618           10 :                                 if (!(param.variable_type is ValueType) || param.variable_type.nullable) {
     619            4 :                                         ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, get_ccode_name (param)), new CCodeConstant ("NULL"));
     620              :                                 }
     621              :                         }
     622              :                 }
     623          127 :                 emit_context.pop_symbol ();
     624              : 
     625          127 :                 if (m is CreationMethod) {
     626            9 :                         ccode.add_assignment (new CCodeIdentifier ("result"), new CCodeMemberAccess.pointer (data_var, "self"));
     627            9 :                         ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "self"), new CCodeConstant ("NULL"));
     628            9 :                         ccode.add_return (new CCodeIdentifier ("result"));
     629          119 :                 } else if (return_type.is_real_non_null_struct_type ()) {
     630              :                         // structs are returned via out parameter
     631            1 :                         CCodeExpression cexpr = new CCodeMemberAccess.pointer (data_var, "result");
     632            1 :                         if (requires_copy (return_type)) {
     633            0 :                                 cexpr = get_cvalue_ (copy_value (new GLibValue (return_type, cexpr, true), return_type));
     634              :                         }
     635            1 :                         ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result")), cexpr);
     636          117 :                 } else if (!(return_type is VoidType)) {
     637           30 :                         ccode.add_assignment (new CCodeIdentifier ("result"), new CCodeMemberAccess.pointer (data_var, "result"));
     638           33 :                         if (return_type is ArrayType) {
     639            3 :                                 var array_type = (ArrayType) return_type;
     640            3 :                                 if (get_ccode_array_length (m)) {
     641            4 :                                         for (int dim = 1; dim <= array_type.rank; dim++) {
     642            2 :                                                 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_array_length_cname ("result", dim))), new CCodeMemberAccess.pointer (data_var, get_array_length_cname ("result", dim)));
     643              :                                         }
     644              :                                 }
     645           27 :                         } else if (return_type is DelegateType && ((DelegateType) return_type).delegate_symbol.has_target) {
     646            1 :                                 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_delegate_target_cname ("result"))), new CCodeMemberAccess.pointer (data_var, get_delegate_target_cname ("result")));
     647              :                         }
     648           30 :                         if (!(return_type is ValueType) || return_type.nullable) {
     649           18 :                                 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "result"), new CCodeConstant ("NULL"));
     650              :                         }
     651           30 :                         ccode.add_return (new CCodeIdentifier ("result"));
     652              :                 }
     653              : 
     654          127 :                 pop_function ();
     655              : 
     656          127 :                 cfile.add_function (finishfunc);
     657              : 
     658          127 :                 pop_context ();
     659              :         }
     660              : 
     661           52 :         public override string generate_ready_function (Method m) {
     662              :                 // generate ready callback handler
     663              : 
     664           52 :                 var dataname = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "Data";
     665              : 
     666           52 :                 var readyfunc = new CCodeFunction (get_ccode_name (m) + "_ready", "void");
     667              : 
     668           52 :                 if (!add_wrapper (readyfunc.name)) {
     669              :                         // wrapper already defined
     670           48 :                         return readyfunc.name;
     671              :                 }
     672              : 
     673           28 :                 readyfunc.add_parameter (new CCodeParameter ("source_object", "GObject*"));
     674           28 :                 readyfunc.add_parameter (new CCodeParameter ("_res_", "GAsyncResult*"));
     675           28 :                 readyfunc.add_parameter (new CCodeParameter ("_user_data_", "gpointer"));
     676              : 
     677           28 :                 push_function (readyfunc);
     678              : 
     679           28 :                 var data_var = new CCodeIdentifier ("_data_");
     680              : 
     681           28 :                 ccode.add_declaration (dataname + "*", new CCodeVariableDeclarator ("_data_"));
     682           28 :                 ccode.add_assignment (data_var, new CCodeIdentifier ("_user_data_"));
     683           28 :                 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_source_object_"), new CCodeIdentifier ("source_object"));
     684           28 :                 ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, "_res_"), new CCodeIdentifier ("_res_"));
     685              : 
     686           28 :                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m) + "_co"));
     687           28 :                 ccall.add_argument (data_var);
     688           28 :                 ccode.add_expression (ccall);
     689              : 
     690           28 :                 readyfunc.modifiers |= CCodeModifiers.STATIC;
     691              : 
     692           28 :                 pop_function ();
     693              : 
     694           28 :                 cfile.add_function_declaration (readyfunc);
     695           28 :                 cfile.add_function (readyfunc);
     696              : 
     697           56 :                 return readyfunc.name;
     698              :         }
     699              : 
     700         5598 :         public override void generate_virtual_method_declaration (Method m, CCodeFile decl_space, CCodeStruct type_struct) {
     701         5500 :                 if (!m.coroutine) {
     702         5286 :                         base.generate_virtual_method_declaration (m, decl_space, type_struct);
     703         5286 :                         return;
     704              :                 }
     705              : 
     706          214 :                 if (!m.is_abstract && !m.is_virtual) {
     707              :                         return;
     708              :                 }
     709              : 
     710           98 :                 var creturn_type = get_callable_creturn_type (m);
     711              : 
     712              :                 // add vfunc field to the type struct
     713           98 :                 var vdeclarator = new CCodeFunctionDeclarator (get_ccode_vfunc_name (m));
     714           98 :                 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     715              : 
     716           98 :                 generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator, null, null, 1);
     717              : 
     718           98 :                 var vdecl = new CCodeDeclaration ("void");
     719           98 :                 vdecl.add_declarator (vdeclarator);
     720           98 :                 type_struct.add_declaration (vdecl);
     721              : 
     722              :                 // add vfunc field to the type struct
     723           98 :                 vdeclarator = new CCodeFunctionDeclarator (get_ccode_finish_vfunc_name (m));
     724           98 :                 cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
     725              : 
     726           98 :                 generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator, null, null, 2);
     727              : 
     728           98 :                 vdecl = new CCodeDeclaration (get_ccode_name (creturn_type));
     729           98 :                 vdecl.add_declarator (vdeclarator);
     730           98 :                 type_struct.add_declaration (vdecl);
     731              :         }
     732              : 
     733           17 :         public override void visit_yield_statement (YieldStatement stmt) {
     734           17 :                 if (!is_in_coroutine ()) {
     735              :                         return;
     736              :                 }
     737              : 
     738           17 :                 int state = emit_context.next_coroutine_state++;
     739              : 
     740           17 :                 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
     741           17 :                 ccode.add_return (new CCodeConstant ("FALSE"));
     742           17 :                 ccode.add_label ("_state_%d".printf (state));
     743           17 :                 ccode.add_statement (new CCodeEmptyStatement ());
     744              :         }
     745              : 
     746          244 :         public override void return_with_exception (CCodeExpression error_expr)
     747              :         {
     748          227 :                 if (!is_in_coroutine ()) {
     749          210 :                         base.return_with_exception (error_expr);
     750          210 :                         return;
     751              :                 }
     752              : 
     753           17 :                 var async_result_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_async_result");
     754           17 :                 CCodeFunctionCall set_error = null;
     755              : 
     756           17 :                 set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_error"));
     757           17 :                 set_error.add_argument (async_result_expr);
     758           17 :                 set_error.add_argument (error_expr);
     759           17 :                 ccode.add_expression (set_error);
     760              : 
     761              :                 // free local variables
     762           17 :                 append_local_free (current_symbol);
     763              : 
     764              :                 // free possibly already assigned out-parameter
     765           17 :                 append_out_param_free (current_method);
     766              : 
     767              :                 // We already returned the error above, we must not return anything else here.
     768           17 :                 var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
     769           17 :                 unref.add_argument (async_result_expr);
     770           17 :                 ccode.add_expression (unref);
     771              : 
     772           17 :                 ccode.add_return (new CCodeConstant ("FALSE"));
     773              :         }
     774              : 
     775         2842 :         public override void visit_return_statement (ReturnStatement stmt) {
     776         2842 :                 base.visit_return_statement (stmt);
     777              : 
     778         2842 :                 if (!is_in_coroutine ()) {
     779              :                         return;
     780              :                 }
     781              : 
     782           30 :                 complete_async ();
     783              :         }
     784              : 
     785        17597 :         public override void generate_cparameters (Method m, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
     786        17597 :                 if (m.coroutine) {
     787         1351 :                         decl_space.add_include ("gio/gio.h");
     788              : 
     789         1351 :                         if (direction == 1) {
     790          612 :                                 cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
     791          612 :                                 cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
     792          612 :                                 if (carg_map != null) {
     793          328 :                                         carg_map.set (get_param_pos (-1), new CCodeIdentifier ("_callback_"));
     794          328 :                                         carg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_user_data_"));
     795              :                                 }
     796          739 :                         } else if (direction == 2) {
     797          612 :                                 cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*"));
     798          612 :                                 if (carg_map != null) {
     799          328 :                                         carg_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeIdentifier ("_res_"));
     800              :                                 }
     801              :                         }
     802              :                 }
     803        17597 :                 base.generate_cparameters (m, decl_space, cparam_map, func, vdeclarator, carg_map, vcall, direction);
     804              :         }
     805              : 
     806           13 :         public string generate_async_callback_wrapper () {
     807           13 :                 string async_callback_wrapper_func = "_vala_g_async_ready_callback";
     808              : 
     809           13 :                 if (!add_wrapper (async_callback_wrapper_func)) {
     810           13 :                         return async_callback_wrapper_func;
     811              :                 }
     812              : 
     813            6 :                 var function = new CCodeFunction (async_callback_wrapper_func, "void");
     814            6 :                 function.modifiers = CCodeModifiers.STATIC;
     815              : 
     816            6 :                 function.add_parameter (new CCodeParameter ("*source_object", "GObject"));
     817            6 :                 function.add_parameter (new CCodeParameter ("*res", "GAsyncResult"));
     818            6 :                 function.add_parameter (new CCodeParameter ("*user_data", "void"));
     819              : 
     820            6 :                 push_function (function);
     821              : 
     822            6 :                 var res_ref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
     823            6 :                 res_ref.add_argument (new CCodeIdentifier ("res"));
     824              : 
     825            6 :                 CCodeFunctionCall ccall = null;
     826              : 
     827              :                 // store reference to async result of inner async function in out async result
     828            6 :                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_task_return_pointer"));
     829            6 :                 ccall.add_argument (new CCodeIdentifier ("user_data"));
     830            6 :                 ccall.add_argument (res_ref);
     831            6 :                 ccall.add_argument (new CCodeIdentifier ("g_object_unref"));
     832            6 :                 ccode.add_expression (ccall);
     833              : 
     834              :                 // free async result
     835            6 :                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
     836            6 :                 ccall.add_argument (new CCodeIdentifier ("user_data"));
     837            6 :                 ccode.add_expression (ccall);
     838              : 
     839            6 :                 pop_function ();
     840              : 
     841            6 :                 cfile.add_function_declaration (function);
     842            6 :                 cfile.add_function (function);
     843              : 
     844            6 :                 return async_callback_wrapper_func;
     845              :         }
     846              : }
        

Generated by: LCOV version 2.0-1