Пример #1
0
        public override void generate_cparameters(Method m, CCodeFile decl_space, Dictionary <int, CCodeParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator vdeclarator = null, Dictionary <int, CCodeExpression> carg_map = null, CCodeFunctionCall vcall = null, int direction = 3)
        {
            if (m.coroutine)
            {
                decl_space.add_include("gio/gio.h");

                if (direction == 1)
                {
                    cparam_map[get_param_pos(-1)]   = new CCodeParameter("_callback_", "GAsyncReadyCallback");
                    cparam_map[get_param_pos(-0.9)] = new CCodeParameter("_user_data_", "gpointer");
                    if (carg_map != null)
                    {
                        carg_map[get_param_pos(-1)]   = new CCodeIdentifier("_callback_");
                        carg_map[get_param_pos(-0.9)] = new CCodeIdentifier("_user_data_");
                    }
                }
                else if (direction == 2)
                {
                    cparam_map[get_param_pos(0.1)] = new CCodeParameter("_res_", "GAsyncResult*");
                    if (carg_map != null)
                    {
                        carg_map[get_param_pos(0.1)] = new CCodeIdentifier("_res_");
                    }
                }
            }
            base.generate_cparameters(m, decl_space, cparam_map, func, vdeclarator, carg_map, vcall, direction);
        }
Пример #2
0
        public override CCodeParameter generate_parameter(Parameter param, CCodeFile decl_space, Dictionary <int, CCodeParameter> cparam_map, Dictionary <int, CCodeExpression> carg_map)
        {
            if (!(param.variable_type is ArrayType))
            {
                return(base.generate_parameter(param, decl_space, cparam_map, carg_map));
            }

            string ctypename = get_ccode_name(param.variable_type);

            if (param.direction != ParameterDirection.IN)
            {
                ctypename += "*";
            }

            var main_cparam = new CCodeParameter(get_variable_cname(param.name), ctypename);

            var array_type = (ArrayType)param.variable_type;

            generate_type_declaration(array_type.element_type, decl_space);

            cparam_map[get_param_pos(get_ccode_pos(param))] = main_cparam;
            if (carg_map != null)
            {
                carg_map[get_param_pos(get_ccode_pos(param))] = get_variable_cexpression(param.name);
            }

            if (get_ccode_array_length(param))
            {
                string length_ctype = "int";
                if (get_ccode_array_length_type(param) != null)
                {
                    length_ctype = get_ccode_array_length_type(param);
                }
                if (param.direction != ParameterDirection.IN)
                {
                    length_ctype = "%s*".printf(length_ctype);
                }

                for (int dim = 1; dim <= array_type.rank; dim++)
                {
                    var cparam = new CCodeParameter(get_parameter_array_length_cname(param, dim), length_ctype);
                    cparam_map[get_param_pos(get_ccode_array_length_pos(param) + 0.01 * dim)] = cparam;
                    if (carg_map != null)
                    {
                        carg_map[get_param_pos(get_ccode_array_length_pos(param) + 0.01 * dim)] = get_variable_cexpression(cparam.name);
                    }
                }
            }

            return(main_cparam);
        }
Пример #3
0
        public override CCodeParameter generate_parameter(Parameter param, CCodeFile decl_space, Dictionary <int, CCodeParameter> cparam_map, Dictionary <int, CCodeExpression> carg_map)
        {
            if (!(param.variable_type is DelegateType || param.variable_type is MethodType))
            {
                return(base.generate_parameter(param, decl_space, cparam_map, carg_map));
            }

            string ctypename        = get_ccode_name(param.variable_type);
            string target_ctypename = "void*";
            string target_destroy_notify_ctypename = "GDestroyNotify";

            if (param.parent_symbol is ValaDelegate &&
                get_ccode_name(param.variable_type) == get_ccode_name(param.parent_symbol))
            {
                // recursive delegate
                ctypename = "GCallback";
            }

            if (param.direction != ParameterDirection.IN)
            {
                ctypename        += "*";
                target_ctypename += "*";
                target_destroy_notify_ctypename += "*";
            }

            var main_cparam = new CCodeParameter(get_variable_cname(param.name), ctypename);

            cparam_map[get_param_pos(get_ccode_pos(param))] = main_cparam;
            if (carg_map != null)
            {
                carg_map[get_param_pos(get_ccode_pos(param))] = get_variable_cexpression(param.name);
            }

            if (param.variable_type is DelegateType)
            {
                var deleg_type = (DelegateType)param.variable_type;
                var d          = deleg_type.delegate_symbol;

                generate_delegate_declaration(d, decl_space);

                if (d.has_target)
                {
                    var cparam = new CCodeParameter(get_ccode_delegate_target_name(param), target_ctypename);
                    cparam_map[get_param_pos(get_ccode_delegate_target_pos(param))] = cparam;
                    if (carg_map != null)
                    {
                        carg_map[get_param_pos(get_ccode_delegate_target_pos(param))] = get_variable_cexpression(cparam.name);
                    }
                    if (deleg_type.is_disposable())
                    {
                        cparam = new CCodeParameter(get_delegate_target_destroy_notify_cname(get_variable_cname(param.name)), target_destroy_notify_ctypename);
                        cparam_map[get_param_pos(get_ccode_delegate_target_pos(param) + 0.01)] = cparam;
                        if (carg_map != null)
                        {
                            carg_map[get_param_pos(get_ccode_delegate_target_pos(param) + 0.01)] = get_variable_cexpression(cparam.name);
                        }
                    }
                }
            }
            else if (param.variable_type is MethodType)
            {
                var cparam = new CCodeParameter(get_ccode_delegate_target_name(param), target_ctypename);
                cparam_map[get_param_pos(get_ccode_delegate_target_pos(param))] = cparam;
                if (carg_map != null)
                {
                    carg_map[get_param_pos(get_ccode_delegate_target_pos(param))] = get_variable_cexpression(cparam.name);
                }
            }

            return(main_cparam);
        }
Пример #4
0
        public string generate_delegate_wrapper(Method m, DelegateType dt, CodeNode node)
        {
            var    d = dt.delegate_symbol;
            string delegate_name;
            var    sig         = d.parent_symbol as Signal;
            var    dynamic_sig = sig as DynamicSignal;

            if (dynamic_sig != null)
            {
                delegate_name = get_dynamic_signal_cname(dynamic_sig);
            }
            else if (sig != null)
            {
                delegate_name = get_ccode_lower_case_prefix(sig.parent_symbol) + get_ccode_lower_case_name(sig);
            }
            else
            {
                delegate_name = Symbol.camel_case_to_lower_case(get_ccode_name(d));
            }

            string wrapper_name = "_%s_%s".printf(get_ccode_name(m), delegate_name);

            if (!add_wrapper(wrapper_name))
            {
                // wrapper already defined
                return(wrapper_name);
            }

            // declaration

            string return_type_cname = get_ccode_name(d.return_type);

            if (d.return_type.is_real_non_null_struct_type())
            {
                // structs are returned via out parameter
                return_type_cname = "void";
            }

            var function = new CCodeFunction(wrapper_name, return_type_cname);

            function.modifiers = CCodeModifiers.STATIC;

            push_function(function);

            var cparam_map = new Dictionary <int, CCodeParameter>();

            if (d.has_target)
            {
                var cparam = new CCodeParameter("self", "gpointer");
                cparam_map[get_param_pos(get_ccode_instance_pos(d))] = cparam;
            }

            if (d.sender_type != null)
            {
                var param = new Parameter("_sender", d.sender_type);
                generate_parameter(param, cfile, cparam_map, null);
            }

            var d_params = d.get_parameters();

            foreach (Parameter param in d_params)
            {
                if (dynamic_sig != null &&
                    param.variable_type is ArrayType &&
                    ((ArrayType)param.variable_type).element_type.data_type == string_type.data_type)
                {
                    // use null-terminated string arrays for dynamic signals for compatibility reasons
                    param.set_attribute_bool("CCode", "array_length", false);
                    param.set_attribute_bool("CCode", "array_null_terminated", true);
                }

                generate_parameter(param, cfile, cparam_map, null);
            }
            if (get_ccode_array_length(d) && d.return_type is ArrayType)
            {
                // return array length if appropriate
                var array_type        = (ArrayType)d.return_type;
                var array_length_type = get_ccode_array_length_type(d) != null?get_ccode_array_length_type(d) : "int";

                array_length_type += "*";

                for (int dim = 1; dim <= array_type.rank; dim++)
                {
                    var cparam = new CCodeParameter(get_array_length_cname("result", dim), array_length_type);
                    cparam_map[get_param_pos(get_ccode_array_length_pos(d) + 0.01 * dim)] = cparam;
                }
            }
            else if (d.return_type is DelegateType)
            {
                // return delegate target if appropriate
                var deleg_type = (DelegateType)d.return_type;

                if (deleg_type.delegate_symbol.has_target)
                {
                    var cparam = new CCodeParameter(get_delegate_target_cname("result"), "void**");
                    cparam_map[get_param_pos(get_ccode_delegate_target_pos(d))] = cparam;
                    if (deleg_type.is_disposable())
                    {
                        cparam = new CCodeParameter(get_delegate_target_destroy_notify_cname("result"), "GDestroyNotify*");
                        cparam_map[get_param_pos(get_ccode_delegate_target_pos(d) + 0.01)] = cparam;
                    }
                }
            }
            else if (d.return_type.is_real_non_null_struct_type())
            {
                var cparam = new CCodeParameter("result", "%s*".printf(get_ccode_name(d.return_type)));
                cparam_map[get_param_pos(-3)] = cparam;
            }

            if (m.get_error_types().Count > 0)
            {
                var cparam = new CCodeParameter("error", "GError**");
                cparam_map[get_param_pos(-1)] = cparam;
            }

            // append C parameters in the right order
            int last_pos = -1;
            int min_pos;

            while (true)
            {
                min_pos = -1;
                foreach (int pos in cparam_map.Keys)
                {
                    if (pos > last_pos && (min_pos == -1 || pos < min_pos))
                    {
                        min_pos = pos;
                    }
                }
                if (min_pos == -1)
                {
                    break;
                }
                function.add_parameter(cparam_map[min_pos]);
                last_pos = min_pos;
            }


            // definition

            var carg_map = new Dictionary <int, CCodeExpression>();

            int i = 0;

            if (m.binding == MemberBinding.INSTANCE || m.closure)
            {
                CCodeExpression arg;
                if (d.has_target)
                {
                    arg = new CCodeIdentifier("self");
                    if (!m.closure && m.this_parameter != null)
                    {
                        arg = convert_from_generic_pointer(arg, m.this_parameter.variable_type);
                    }
                }
                else
                {
                    // use first delegate parameter as instance
                    if (d_params.Count == 0 || m.closure)
                    {
                        Report.error(node != null ? node.source_reference : null, "Cannot create delegate without target for instance method or closure");
                        arg = new CCodeConstant("NULL");
                    }
                    else
                    {
                        arg = new CCodeIdentifier(get_variable_cname(d_params[0].name));
                        i   = 1;
                    }
                }
                carg_map[get_param_pos(get_ccode_instance_pos(m))] = arg;
            }

            bool first = true;

            foreach (Parameter param in m.get_parameters())
            {
                if (first && d.sender_type != null && m.get_parameters().Count == d.get_parameters().Count + 1)
                {
                    // sender parameter
                    carg_map[get_param_pos(get_ccode_pos(param))] = new CCodeIdentifier("_sender");

                    first = false;
                    continue;
                }

                CCodeExpression arg;
                arg = new CCodeIdentifier(get_variable_cname(d_params[i].name));
                if (d_params[i].variable_type is GenericType)
                {
                    arg = convert_from_generic_pointer(arg, param.variable_type);
                }
                carg_map[get_param_pos(get_ccode_pos(param))] = arg;

                // handle array arguments
                if (get_ccode_array_length(param) && param.variable_type is ArrayType)
                {
                    var array_type = (ArrayType)param.variable_type;
                    for (int dim = 1; dim <= array_type.rank; dim++)
                    {
                        CCodeExpression clength;
                        if (get_ccode_array_null_terminated(d_params[i]))
                        {
                            requires_array_length = true;
                            var len_call = new CCodeFunctionCall(new CCodeIdentifier("_vala_array_length"));
                            len_call.add_argument(new CCodeIdentifier(d_params[i].name));
                            clength = len_call;
                        }
                        else if (!get_ccode_array_length(d_params[i]))
                        {
                            clength = new CCodeConstant("-1");
                        }
                        else
                        {
                            clength = new CCodeIdentifier(get_parameter_array_length_cname(d_params[i], dim));
                        }
                        carg_map[get_param_pos(get_ccode_array_length_pos(param) + 0.01 * dim)] = clength;
                    }
                }
                else if (param.variable_type is DelegateType)
                {
                    var deleg_type = (DelegateType)param.variable_type;

                    if (deleg_type.delegate_symbol.has_target)
                    {
                        var ctarget = new CCodeIdentifier(get_ccode_delegate_target_name(d_params[i]));
                        carg_map[get_param_pos(get_ccode_delegate_target_pos(param))] = ctarget;
                        if (deleg_type.is_disposable())
                        {
                            var ctarget_destroy_notify = new CCodeIdentifier(get_delegate_target_destroy_notify_cname(d_params[i].name));
                            carg_map[get_param_pos(get_ccode_delegate_target_pos(m) + 0.01)] = ctarget_destroy_notify;
                        }
                    }
                }

                i++;
            }
            if (get_ccode_array_length(m) && m.return_type is ArrayType)
            {
                var array_type = (ArrayType)m.return_type;
                for (int dim = 1; dim <= array_type.rank; dim++)
                {
                    CCodeExpression clength;
                    if (!get_ccode_array_length(d))
                    {
                        clength = new CCodeConstant("NULL");
                    }
                    else
                    {
                        clength = new CCodeIdentifier(get_array_length_cname("result", dim));
                    }
                    carg_map[get_param_pos(get_ccode_array_length_pos(m) + 0.01 * dim)] = clength;
                }
            }
            else if (m.return_type is DelegateType)
            {
                var deleg_type = (DelegateType)m.return_type;

                if (deleg_type.delegate_symbol.has_target)
                {
                    var ctarget = new CCodeIdentifier(get_delegate_target_cname("result"));
                    carg_map[get_param_pos(get_ccode_delegate_target_pos(m))] = ctarget;
                    if (deleg_type.is_disposable())
                    {
                        var ctarget_destroy_notify = new CCodeIdentifier(get_delegate_target_destroy_notify_cname("result"));
                        carg_map[get_param_pos(get_ccode_delegate_target_pos(m) + 0.01)] = ctarget_destroy_notify;
                    }
                }
            }
            else if (m.return_type.is_real_non_null_struct_type())
            {
                carg_map[get_param_pos(-3)] = new CCodeIdentifier("result");
            }

            if (m.get_error_types().Count > 0)
            {
                carg_map[get_param_pos(-1)] = new CCodeIdentifier("error");
            }

            var ccall = new CCodeFunctionCall(new CCodeIdentifier(get_ccode_name(m)));

            // append C arguments in the right order
            last_pos = -1;
            while (true)
            {
                min_pos = -1;
                foreach (int pos in carg_map.Keys)
                {
                    if (pos > last_pos && (min_pos == -1 || pos < min_pos))
                    {
                        min_pos = pos;
                    }
                }
                if (min_pos == -1)
                {
                    break;
                }
                ccall.add_argument(carg_map[min_pos]);
                last_pos = min_pos;
            }

            if (m.coroutine)
            {
                ccall.add_argument(new CCodeConstant("NULL"));
                ccall.add_argument(new CCodeConstant("NULL"));
            }

            if (m.return_type is VoidType || m.return_type.is_real_non_null_struct_type())
            {
                ccode.add_expression(ccall);
                if (!(d.return_type is VoidType || d.return_type.is_real_non_null_struct_type()))
                {
                    // return a default value
                    ccode.add_declaration(return_type_cname, new CCodeVariableDeclarator("result", default_value_for_type(d.return_type, true)));
                }
            }
            else
            {
                CCodeExpression result = ccall;
                if (d.return_type is GenericType)
                {
                    result = convert_to_generic_pointer(result, m.return_type);
                }
                ccode.add_declaration(return_type_cname, new CCodeVariableDeclarator("result", result));
            }

            if (d.has_target /* TODO: && dt.value_owned */ && dt.is_called_once)
            {
                // destroy notify "self" after the call
                CCodeExpression destroy_notify = null;
                if (m.closure)
                {
                    int block_id = get_block_id(current_closure_block);
                    destroy_notify = new CCodeIdentifier("block%d_data_unref".printf(block_id));
                }
                else if (get_this_type() != null && m.binding != MemberBinding.STATIC && !m.is_async_callback && is_reference_counting(m.this_parameter.variable_type.data_type))
                {
                    destroy_notify = get_destroy_func_expression(m.this_parameter.variable_type);
                }

                if (destroy_notify != null)
                {
                    var unref_call = new CCodeFunctionCall(destroy_notify);
                    unref_call.add_argument(new CCodeIdentifier("self"));
                    ccode.add_expression(unref_call);
                }
            }

            if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type()) ||
                !(d.return_type is VoidType || d.return_type.is_real_non_null_struct_type()))
            {
                ccode.add_return(new CCodeIdentifier("result"));
            }

            pop_function();

            // append to file
            cfile.add_function_declaration(function);
            cfile.add_function(function);

            return(wrapper_name);
        }
Пример #5
0
        public override void generate_delegate_declaration(ValaDelegate d, CCodeFile decl_space)
        {
            if (add_symbol_declaration(decl_space, d, get_ccode_name(d)))
            {
                return;
            }

            string return_type_cname = get_ccode_name(d.return_type);

            if (d.return_type.is_real_non_null_struct_type())
            {
                // structs are returned via out parameter
                return_type_cname = "void";
            }

            if (return_type_cname == get_ccode_name(d))
            {
                // recursive delegate
                return_type_cname = "GCallback";
            }
            else
            {
                generate_type_declaration(d.return_type, decl_space);
            }

            var cfundecl = new CCodeFunctionDeclarator(get_ccode_name(d));

            foreach (Parameter param in d.get_parameters())
            {
                var cparam = generate_parameter(param, decl_space, new Dictionary <int, CCodeParameter>(), null);

                cfundecl.add_parameter(cparam);

                // handle array parameters
                if (get_ccode_array_length(param) && param.variable_type is ArrayType)
                {
                    var array_type = (ArrayType)param.variable_type;

                    var length_ctype = "int";
                    if (param.direction != ParameterDirection.IN)
                    {
                        length_ctype = "int*";
                    }

                    for (int dim = 1; dim <= array_type.rank; dim++)
                    {
                        cparam = new CCodeParameter(get_parameter_array_length_cname(param, dim), length_ctype);
                        cfundecl.add_parameter(cparam);
                    }
                }
                // handle delegate parameters
                if (param.variable_type is DelegateType)
                {
                    var deleg_type = (DelegateType)param.variable_type;
                    var param_d    = deleg_type.delegate_symbol;
                    if (param_d.has_target)
                    {
                        cparam = new CCodeParameter(get_delegate_target_cname(get_variable_cname(param.name)), "void*");
                        cfundecl.add_parameter(cparam);
                        if (deleg_type.is_disposable())
                        {
                            cparam = new CCodeParameter(get_delegate_target_destroy_notify_cname(get_variable_cname(param.name)), "GDestroyNotify*");
                            cfundecl.add_parameter(cparam);
                        }
                    }
                }
            }
            if (get_ccode_array_length(d) && d.return_type is ArrayType)
            {
                // return array length if appropriate
                var array_type        = (ArrayType)d.return_type;
                var array_length_type = get_ccode_array_length_type(d) != null?get_ccode_array_length_type(d) : "int";

                array_length_type += "*";

                for (int dim = 1; dim <= array_type.rank; dim++)
                {
                    var cparam = new CCodeParameter(get_array_length_cname("result", dim), array_length_type);
                    cfundecl.add_parameter(cparam);
                }
            }
            else if (d.return_type is DelegateType)
            {
                // return delegate target if appropriate
                var deleg_type = (DelegateType)d.return_type;
                var result_d   = deleg_type.delegate_symbol;
                if (result_d.has_target)
                {
                    var cparam = new CCodeParameter(get_delegate_target_cname("result"), "void**");
                    cfundecl.add_parameter(cparam);
                    if (deleg_type.is_disposable())
                    {
                        cparam = new CCodeParameter(get_delegate_target_destroy_notify_cname("result"), "GDestroyNotify*");
                        cfundecl.add_parameter(cparam);
                    }
                }
            }
            else if (d.return_type.is_real_non_null_struct_type())
            {
                var cparam = new CCodeParameter("result", "%s*".printf(get_ccode_name(d.return_type)));
                cfundecl.add_parameter(cparam);
            }
            if (d.has_target)
            {
                var cparam = new CCodeParameter("user_data", "void*");
                cfundecl.add_parameter(cparam);
            }
            if (d.get_error_types().Count > 0)
            {
                var cparam = new CCodeParameter("error", "GError**");
                cfundecl.add_parameter(cparam);
            }

            var ctypedef = new CCodeTypeDefinition(return_type_cname, cfundecl);

            ctypedef.modifiers |= (d.version.deprecated ? CCodeModifiers.DEPRECATED : 0);

            decl_space.add_type_definition(ctypedef);
        }
Пример #6
0
        void generate_async_function(Method m)
        {
            push_context(new EmitContext());

            string callback_wrapper = null;

            if (!context.require_glib_version(2, 44))
            {
                callback_wrapper = get_ccode_real_name(m) + "_async_ready_wrapper";
                generate_async_ready_callback_wrapper(m, callback_wrapper);
            }

            var dataname   = Symbol.lower_case_to_camel_case(get_ccode_name(m)) + "Data";
            var asyncfunc  = new CCodeFunction(get_ccode_real_name(m), "void");
            var cparam_map = new Dictionary <int, CCodeParameter>();

            cparam_map[get_param_pos(-1)]   = new CCodeParameter("_callback_", "GAsyncReadyCallback");
            cparam_map[get_param_pos(-0.9)] = new CCodeParameter("_user_data_", "gpointer");

            generate_cparameters(m, cfile, cparam_map, asyncfunc, null, null, null, 1);

            if (m.base_method != null || m.base_interface_method != null)
            {
                // declare *_real_* function
                asyncfunc.modifiers |= CCodeModifiers.STATIC;
                cfile.add_function_declaration(asyncfunc);
            }
            else if (m.is_private_symbol())
            {
                asyncfunc.modifiers |= CCodeModifiers.STATIC;
            }
            else if (context.hide_internal && m.is_internal_symbol())
            {
                asyncfunc.modifiers |= CCodeModifiers.INTERNAL;
            }

            push_function(asyncfunc);

            // logic copied from valaccodemethodmodule
            if (m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual))
            {
                Method base_method;

                if (m.overrides)
                {
                    base_method = m.base_method;
                }
                else
                {
                    base_method = m.base_interface_method;
                }

                var base_expression_type = new ObjectType((ObjectTypeSymbol)base_method.parent_symbol);
                var type_symbol          = m.parent_symbol as ObjectTypeSymbol;

                var self_target_type = new ObjectType(type_symbol);
                var cself            = get_cvalue_(transform_value(new GLibValue(base_expression_type, new CCodeIdentifier("base"), true), self_target_type, m));
                ccode.add_declaration("%s *".printf(get_ccode_name(type_symbol)), new CCodeVariableDeclarator("self"));
                ccode.add_assignment(new CCodeIdentifier("self"), cself);
            }

            var dataalloc = new CCodeFunctionCall(new CCodeIdentifier("g_slice_new0"));

            dataalloc.add_argument(new CCodeIdentifier(dataname));

            var data_var = new CCodeIdentifier("_data_");

            ccode.add_declaration(dataname + "*", new CCodeVariableDeclarator("_data_"));
            ccode.add_assignment(data_var, dataalloc);

            if (!context.require_glib_version(2, 44))
            {
                ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "_callback_"), new CCodeConstant("_callback_"));
            }

            var create_result = new CCodeFunctionCall(new CCodeIdentifier("g_task_new"));

            var t = m.parent_symbol as TypeSymbol;

            if (!(m is CreationMethod) && m.binding == MemberBinding.INSTANCE &&
                t != null && t.is_subtype_of(gobject_type))
            {
                var gobject_cast = new CCodeFunctionCall(new CCodeIdentifier("G_OBJECT"));
                gobject_cast.add_argument(new CCodeIdentifier("self"));

                create_result.add_argument(gobject_cast);
            }
            else
            {
                create_result.add_argument(new CCodeConstant("NULL"));
            }

            Parameter cancellable_param = null;

            foreach (Parameter param in m.get_parameters())
            {
                if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name() == "GLib.Cancellable")
                {
                    cancellable_param = param;
                    break;
                }
            }

            if (cancellable_param == null)
            {
                create_result.add_argument(new CCodeConstant("NULL"));
            }
            else
            {
                create_result.add_argument(new CCodeIdentifier(get_variable_cname(cancellable_param.name)));
            }

            if (context.require_glib_version(2, 44))
            {
                create_result.add_argument(new CCodeIdentifier("_callback_"));
            }
            else
            {
                create_result.add_argument(new CCodeIdentifier(callback_wrapper));
            }
            create_result.add_argument(new CCodeIdentifier("_user_data_"));

            ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "_async_result"), create_result);

            if (!context.require_glib_version(2, 44))
            {
                var task_completed_var = CCodeMemberAccess.pointer(data_var, "_task_complete_");
                var callback           = new CCodeIdentifier("_callback_");
                var callback_is_null   = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, callback, new CCodeConstant("NULL"));

                ccode.open_if(callback_is_null);
                ccode.add_assignment(task_completed_var, new CCodeConstant("TRUE"));
                ccode.close();
            }

            var attach_data_call = new CCodeFunctionCall(new CCodeIdentifier("g_task_set_task_data"));

            attach_data_call.add_argument(CCodeMemberAccess.pointer(data_var, "_async_result"));
            attach_data_call.add_argument(data_var);
            attach_data_call.add_argument(new CCodeIdentifier(get_ccode_real_name(m) + "_data_free"));
            ccode.add_expression(attach_data_call);

            if (m is CreationMethod)
            {
                ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "object_type"), new CCodeIdentifier("object_type"));
            }
            else if (m.binding == MemberBinding.INSTANCE)
            {
                var this_type = m.this_parameter.variable_type.copy();
                this_type.value_owned = true;

                // create copy if necessary as variables in async methods may need to be kept alive
                CCodeExpression cself = new CCodeIdentifier("self");
                if (this_type.is_real_non_null_struct_type())
                {
                    cself = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, cself);
                }
                if (requires_copy(this_type))
                {
                    cself = get_cvalue_(copy_value(new GLibValue(m.this_parameter.variable_type, cself, true), m.this_parameter));
                }

                ccode.add_assignment(CCodeMemberAccess.pointer(data_var, "self"), cself);
            }

            emit_context.push_symbol(m);
            foreach (Parameter param in m.get_parameters())
            {
                if (param.direction != ParameterDirection.OUT)
                {
                    // create copy if necessary as variables in async methods may need to be kept alive
                    var old_captured = param.captured;
                    param.captured           = false;
                    current_method.coroutine = false;

                    TargetValue value;
                    if (param.variable_type.value_owned)
                    {
                        // do not use load_parameter for reference/ownership transfer
                        // otherwise delegate destroy notify will not be moved
                        value = get_parameter_cvalue(param);
                    }
                    else
                    {
                        value = load_parameter(param);
                    }

                    current_method.coroutine = true;

                    store_parameter(param, value);

                    param.captured = old_captured;
                }
            }
            emit_context.pop_symbol();

            foreach (var type_param in m.get_type_parameters())
            {
                var type         = "%s_type".printf(type_param.name.ToLower());
                var dup_func     = "%s_dup_func".printf(type_param.name.ToLower());
                var destroy_func = "%s_destroy_func".printf(type_param.name.ToLower());
                ccode.add_assignment(CCodeMemberAccess.pointer(data_var, type), new CCodeIdentifier(type));
                ccode.add_assignment(CCodeMemberAccess.pointer(data_var, dup_func), new CCodeIdentifier(dup_func));
                ccode.add_assignment(CCodeMemberAccess.pointer(data_var, destroy_func), new CCodeIdentifier(destroy_func));
            }

            var ccall = new CCodeFunctionCall(new CCodeIdentifier(get_ccode_real_name(m) + "_co"));

            ccall.add_argument(data_var);
            ccode.add_expression(ccall);

            cfile.add_function(asyncfunc);

            pop_context();
        }