예제 #1
0
        CCodeExpression serialize_array_dim(ArrayType array_type, int dim, CCodeExpression array_expr, CCodeExpression array_iter_expr)
        {
            string builder_name = "_tmp%d_".printf(next_temp_var_id++);
            string index_name   = "_tmp%d_".printf(next_temp_var_id++);

            ccode.add_declaration("GVariantBuilder", new CCodeVariableDeclarator(builder_name));
            ccode.add_declaration("int", new CCodeVariableDeclarator(index_name));

            var gvariant_type = new CCodeFunctionCall(new CCodeIdentifier("G_VARIANT_TYPE"));

            gvariant_type.add_argument(new CCodeConstant("\"%s\"".printf(get_type_signature(array_type))));

            var builder_init = new CCodeFunctionCall(new CCodeIdentifier("g_variant_builder_init"));

            builder_init.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier(builder_name)));
            builder_init.add_argument(gvariant_type);
            ccode.add_expression(builder_init);

            var cforinit = new CCodeAssignment(new CCodeIdentifier(index_name), new CCodeConstant("0"));
            var cforcond = new CCodeBinaryExpression(CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier(index_name), get_array_length(array_expr, dim));
            var cforiter = new CCodeUnaryExpression(CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier(index_name));

            ccode.open_for(cforinit, cforcond, cforiter);

            CCodeExpression element_variant;

            if (dim < array_type.rank)
            {
                element_variant = serialize_array_dim(array_type, dim + 1, array_expr, array_iter_expr);
            }
            else
            {
                var element_expr = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, array_iter_expr);
                element_variant = serialize_expression(array_type.element_type, element_expr);
            }

            var builder_add = new CCodeFunctionCall(new CCodeIdentifier("g_variant_builder_add_value"));

            builder_add.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier(builder_name)));
            builder_add.add_argument(element_variant);
            ccode.add_expression(builder_add);

            if (dim == array_type.rank)
            {
                var array_iter_incr = new CCodeUnaryExpression(CCodeUnaryOperator.POSTFIX_INCREMENT, array_iter_expr);
                ccode.add_expression(array_iter_incr);
            }

            ccode.close();

            var builder_end = new CCodeFunctionCall(new CCodeIdentifier("g_variant_builder_end"));

            builder_end.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier(builder_name)));
            return(builder_end);
        }
예제 #2
0
        public override CCodeExpression serialize_expression(DataType type, CCodeExpression expr)
        {
            BasicTypeInfo   basic_type;
            CCodeExpression result = null;

            if (is_string_marshalled_enum(type.data_type))
            {
                get_basic_type_info("s", out basic_type);
                result = generate_enum_value_to_string(type as EnumValueType, expr);
                result = serialize_basic(basic_type, result);
            }
            else if (get_basic_type_info(get_type_signature(type), out basic_type))
            {
                result = serialize_basic(basic_type, expr);
            }
            else if (type is ArrayType)
            {
                result = serialize_array((ArrayType)type, expr);
            }
            else if (type.data_type is Struct)
            {
                var st_expr = expr;
                if (type.nullable)
                {
                    st_expr = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, st_expr);
                }
                result = serialize_struct((Struct)type.data_type, st_expr);
            }
            else if (type is ObjectType)
            {
                if (type.data_type.get_full_name() == "GLib.Variant")
                {
                    var variant_new = new CCodeFunctionCall(new CCodeIdentifier("g_variant_new_variant"));
                    variant_new.add_argument(expr);
                    result = variant_new;
                }
                else if (type.data_type.get_full_name() == "GLib.HashTable")
                {
                    result = serialize_hash_table((ObjectType)type, expr);
                }
            }

            if (result == null)
            {
                Report.error(type.source_reference, "GVariant serialization of type `%s' is not supported".printf(type.ToString()));
            }

            return(result);
        }
예제 #3
0
        string generate_array_add_wrapper(ArrayType array_type)
        {
            string add_func = "_vala_array_add%d".printf(++next_array_add_id);

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

            var function = new CCodeFunction(add_func, "void");

            function.modifiers = CCodeModifiers.STATIC;

            function.add_parameter(new CCodeParameter("array", "%s *".printf(get_ccode_name(array_type))));
            function.add_parameter(new CCodeParameter("length", "int*"));
            function.add_parameter(new CCodeParameter("size", "int*"));

            push_function(function);

            string          typename = get_ccode_name(array_type.element_type);
            CCodeExpression value    = new CCodeIdentifier("value");

            if (array_type.element_type.is_real_struct_type())
            {
                if (!array_type.element_type.nullable || !array_type.element_type.value_owned)
                {
                    typename = "const " + typename;
                }
                if (!array_type.element_type.nullable)
                {
                    typename += "*";
                    value     = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, value);
                }
            }
            function.add_parameter(new CCodeParameter("value", typename));

            var array  = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier("array"));
            var length = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier("length"));
            var size   = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier("size"));

            var renew_call = new CCodeFunctionCall(new CCodeIdentifier("g_renew"));

            renew_call.add_argument(new CCodeIdentifier(get_ccode_name(array_type.element_type)));
            renew_call.add_argument(array);
            if (array_type.element_type.is_reference_type_or_type_parameter())
            {
                // NULL terminate array
                renew_call.add_argument(new CCodeBinaryExpression(CCodeBinaryOperator.PLUS, size, new CCodeConstant("1")));
            }
            else
            {
                renew_call.add_argument(size);
            }

            var csizecheck = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, length, size);

            ccode.open_if(csizecheck);
            ccode.add_assignment(size, new CCodeConditionalExpression(size, new CCodeBinaryExpression(CCodeBinaryOperator.MUL, new CCodeConstant("2"), size), new CCodeConstant("4")));
            ccode.add_assignment(array, renew_call);
            ccode.close();

            ccode.add_assignment(new CCodeElementAccess(array, new CCodeUnaryExpression(CCodeUnaryOperator.POSTFIX_INCREMENT, length)), value);

            if (array_type.element_type.is_reference_type_or_type_parameter())
            {
                // NULL terminate array
                ccode.add_assignment(new CCodeElementAccess(array, length), new CCodeConstant("NULL"));
            }

            pop_function();

            cfile.add_function_declaration(function);
            cfile.add_function(function);

            return(add_func);
        }
예제 #4
0
        void deserialize_array_dim(ArrayType array_type, int dim, string temp_name, CCodeExpression variant_expr, CCodeExpression expr)
        {
            string subiter_name = "_tmp%d_".printf(next_temp_var_id++);
            string element_name = "_tmp%d_".printf(next_temp_var_id++);

            ccode.add_declaration("int", new CCodeVariableDeclarator("%s_length%d".printf(temp_name, dim), new CCodeConstant("0")));
            ccode.add_declaration("GVariantIter", new CCodeVariableDeclarator(subiter_name));
            ccode.add_declaration("GVariant*", new CCodeVariableDeclarator(element_name));

            var iter_call = new CCodeFunctionCall(new CCodeIdentifier("g_variant_iter_init"));

            iter_call.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier(subiter_name)));
            iter_call.add_argument(variant_expr);
            ccode.add_expression(iter_call);

            iter_call = new CCodeFunctionCall(new CCodeIdentifier("g_variant_iter_next_value"));
            iter_call.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier(subiter_name)));

            var cforcond = new CCodeBinaryExpression(CCodeBinaryOperator.INEQUALITY, new CCodeAssignment(new CCodeIdentifier(element_name), iter_call), new CCodeConstant("NULL"));
            var cforiter = new CCodeUnaryExpression(CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier("%s_length%d".printf(temp_name, dim)));

            ccode.open_for(null, cforcond, cforiter);

            if (dim < array_type.rank)
            {
                deserialize_array_dim(array_type, dim + 1, temp_name, new CCodeIdentifier(element_name), expr);
            }
            else
            {
                var size_check = new CCodeBinaryExpression(CCodeBinaryOperator.EQUALITY, new CCodeIdentifier(temp_name + "_size"), new CCodeIdentifier(temp_name + "_length"));

                ccode.open_if(size_check);

                // tmp_size = (2 * tmp_size);
                var new_size = new CCodeBinaryExpression(CCodeBinaryOperator.MUL, new CCodeConstant("2"), new CCodeIdentifier(temp_name + "_size"));
                ccode.add_assignment(new CCodeIdentifier(temp_name + "_size"), new_size);

                var renew_call = new CCodeFunctionCall(new CCodeIdentifier("g_renew"));
                renew_call.add_argument(new CCodeIdentifier(get_ccode_name(array_type.element_type)));
                renew_call.add_argument(new CCodeIdentifier(temp_name));
                // add one extra element for NULL-termination
                renew_call.add_argument(new CCodeBinaryExpression(CCodeBinaryOperator.PLUS, new CCodeIdentifier(temp_name + "_size"), new CCodeConstant("1")));
                ccode.add_assignment(new CCodeIdentifier(temp_name), renew_call);

                ccode.close();

                var  element_access = new CCodeElementAccess(new CCodeIdentifier(temp_name), new CCodeUnaryExpression(CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier(temp_name + "_length")));
                bool may_fail;
                var  element_expr = deserialize_expression(array_type.element_type, new CCodeIdentifier(element_name), null, out may_fail, null);
                ccode.add_assignment(element_access, element_expr);
            }

            var unref = new CCodeFunctionCall(new CCodeIdentifier("g_variant_unref"));

            unref.add_argument(new CCodeIdentifier(element_name));
            ccode.add_expression(unref);

            ccode.close();

            if (expr != null)
            {
                ccode.add_assignment(get_array_length(expr, dim), new CCodeIdentifier("%s_length%d".printf(temp_name, dim)));
            }
        }
예제 #5
0
        private void add_get_property_function(Class cl)
        {
            var get_prop = new CCodeFunction("_vala_%s_get_property".printf(get_ccode_lower_case_name(cl, null)), "void");

            get_prop.modifiers = CCodeModifiers.STATIC;
            get_prop.add_parameter(new CCodeParameter("object", "GObject *"));
            get_prop.add_parameter(new CCodeParameter("property_id", "guint"));
            get_prop.add_parameter(new CCodeParameter("value", "GValue *"));
            get_prop.add_parameter(new CCodeParameter("pspec", "GParamSpec *"));

            push_function(get_prop);

            CCodeFunctionCall ccall = generate_instance_cast(new CCodeIdentifier("object"), cl);

            ccode.add_declaration("%s *".printf(get_ccode_name(cl)), new CCodeVariableDeclarator("self", ccall));

            ccode.open_switch(new CCodeIdentifier("property_id"));
            var props = cl.get_properties();

            foreach (Property prop in props)
            {
                if (prop.get_accessor == null || prop.is_abstract)
                {
                    continue;
                }
                if (!is_gobject_property(prop))
                {
                    // don't register private properties
                    continue;
                }

                Property        base_prop = prop;
                CCodeExpression cself     = new CCodeIdentifier("self");
                if (prop.base_property != null)
                {
                    var base_type = (Class)prop.base_property.parent_symbol;
                    base_prop = prop.base_property;
                    cself     = get_cvalue_(transform_value(new GLibValue(new ObjectType(cl), cself, true), new ObjectType(base_type), prop));

                    generate_property_accessor_declaration(prop.base_property.get_accessor, cfile);
                }
                else if (prop.base_interface_property != null)
                {
                    var base_type = (Interface)prop.base_interface_property.parent_symbol;
                    base_prop = prop.base_interface_property;
                    cself     = get_cvalue_(transform_value(new GLibValue(new ObjectType(cl), cself, true), new ObjectType(base_type), prop));

                    generate_property_accessor_declaration(prop.base_interface_property.get_accessor, cfile);
                }

                CCodeExpression cfunc;
                if (!get_ccode_no_accessor_method(base_prop) && !get_ccode_concrete_accessor(base_prop))
                {
                    cfunc = new CCodeIdentifier(get_ccode_name(base_prop.get_accessor));
                }
                else
                {
                    // use the static real function as helper
                    cfunc = new CCodeIdentifier(get_ccode_real_name(prop.get_accessor));
                }

                ccode.add_case(new CCodeIdentifier(get_ccode_upper_case_name(prop)));
                if (prop.property_type.is_real_struct_type())
                {
                    var st = prop.property_type.data_type as Struct;

                    ccode.open_block();
                    ccode.add_declaration(get_ccode_name(st), new CCodeVariableDeclarator("boxed"));

                    ccall = new CCodeFunctionCall(cfunc);
                    ccall.add_argument(cself);
                    var boxed_addr = new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier("boxed"));
                    ccall.add_argument(boxed_addr);
                    ccode.add_expression(ccall);

                    var csetcall = new CCodeFunctionCall();
                    csetcall.call = get_value_setter_function(prop.property_type);
                    csetcall.add_argument(new CCodeIdentifier("value"));
                    csetcall.add_argument(boxed_addr);
                    add_guarded_expression(prop, csetcall);

                    if (requires_destroy(prop.get_accessor.value_type))
                    {
                        ccode.add_expression(destroy_value(new GLibValue(prop.get_accessor.value_type, new CCodeIdentifier("boxed"), true)));
                    }
                    ccode.close();
                }
                else
                {
                    ccall = new CCodeFunctionCall(cfunc);
                    ccall.add_argument(cself);
                    var array_type = prop.property_type as ArrayType;
                    if (array_type != null && array_type.element_type.data_type == string_type.data_type)
                    {
                        // G_TYPE_STRV
                        ccode.open_block();
                        ccode.add_declaration("int", new CCodeVariableDeclarator("length"));
                        ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier("length")));
                    }
                    var csetcall = new CCodeFunctionCall();
                    if (prop.get_accessor.value_type.value_owned)
                    {
                        csetcall.call = get_value_taker_function(prop.property_type);
                    }
                    else
                    {
                        csetcall.call = get_value_setter_function(prop.property_type);
                    }
                    csetcall.add_argument(new CCodeIdentifier("value"));
                    csetcall.add_argument(ccall);
                    add_guarded_expression(prop, csetcall);
                    if (array_type != null && array_type.element_type.data_type == string_type.data_type)
                    {
                        ccode.close();
                    }
                }
                ccode.add_break();
            }
            ccode.add_default();
            emit_invalid_property_id_warn();
            ccode.add_break();

            ccode.close();

            pop_function();

            cfile.add_function_declaration(get_prop);
            cfile.add_function(get_prop);
        }
예제 #6
0
        public override void visit_foreach_statement(ForeachStatement stmt)
        {
            ccode.open_block();

            var collection_backup = stmt.collection_variable;
            var collection_type   = collection_backup.variable_type;

            var array_type = collection_type as ArrayType;

            if (array_type != null)
            {
                // avoid assignment issues
                array_type.inline_allocated = false;
                array_type.fixed_length     = false;
            }

            visit_local_variable(collection_backup);
            ccode.add_assignment(get_variable_cexpression(get_local_cname(collection_backup)), get_cvalue(stmt.collection));

            if (stmt.tree_can_fail && stmt.collection.tree_can_fail)
            {
                // exception handling
                add_simple_check(stmt.collection);
            }

            if (stmt.collection.value_type is ArrayType)
            {
                array_type = (ArrayType)stmt.collection.value_type;

                var array_len = get_array_length_cexpression(stmt.collection);

                // store array length for use by _vala_array_free
                ccode.add_assignment(get_variable_cexpression(get_array_length_cname(get_local_cname(collection_backup), 1)), array_len);

                var iterator_variable = new LocalVariable(int_type.copy(), stmt.variable_name + "_it");
                visit_local_variable(iterator_variable);
                var it_name = get_local_cname(iterator_variable);

                var ccond = new CCodeBinaryExpression(CCodeBinaryOperator.LESS_THAN, get_variable_cexpression(it_name), array_len);

                ccode.open_for(new CCodeAssignment(get_variable_cexpression(it_name), new CCodeConstant("0")),
                               ccond,
                               new CCodeAssignment(get_variable_cexpression(it_name), new CCodeBinaryExpression(CCodeBinaryOperator.PLUS, get_variable_cexpression(it_name), new CCodeConstant("1"))));

                CCodeExpression element_expr = new CCodeElementAccess(get_variable_cexpression(get_local_cname(collection_backup)), get_variable_cexpression(it_name));

                var element_type = array_type.element_type.copy();
                element_type.value_owned = false;
                element_expr             = get_cvalue_(transform_value(new GLibValue(element_type, element_expr, true), stmt.type_reference, stmt));

                visit_local_variable(stmt.element_variable);
                ccode.add_assignment(get_variable_cexpression(get_local_cname(stmt.element_variable)), element_expr);

                // set array length for stacked arrays
                if (stmt.type_reference is ArrayType)
                {
                    var inner_array_type = (ArrayType)stmt.type_reference;
                    for (int dim = 1; dim <= inner_array_type.rank; dim++)
                    {
                        ccode.add_assignment(get_variable_cexpression(get_array_length_cname(get_local_cname(stmt.element_variable), dim)), new CCodeConstant("-1"));
                    }
                }

                stmt.body.emit(this);

                ccode.close();
            }
            else if (stmt.collection.value_type.compatible(new ObjectType(glist_type)) || stmt.collection.value_type.compatible(new ObjectType(gslist_type)))
            {
                // iterating over a GList or GSList

                var iterator_variable = new LocalVariable(collection_type.copy(), stmt.variable_name + "_it");
                visit_local_variable(iterator_variable);
                var it_name = get_local_cname(iterator_variable);

                var ccond = new CCodeBinaryExpression(CCodeBinaryOperator.INEQUALITY, get_variable_cexpression(it_name), new CCodeConstant("NULL"));

                ccode.open_for(new CCodeAssignment(get_variable_cexpression(it_name), get_variable_cexpression(get_local_cname(collection_backup))),
                               ccond,
                               new CCodeAssignment(get_variable_cexpression(it_name), CCodeMemberAccess.pointer(get_variable_cexpression(it_name), "next")));

                CCodeExpression element_expr = CCodeMemberAccess.pointer(get_variable_cexpression(it_name), "data");

                if (collection_type.get_type_arguments().Count != 1)
                {
                    Report.error(stmt.source_reference, "internal error: missing generic type argument");
                    stmt.error = true;
                    return;
                }

                var element_data_type = collection_type.get_type_arguments()[0].copy();
                element_data_type.value_owned = false;
                element_expr = convert_from_generic_pointer(element_expr, element_data_type);
                element_expr = get_cvalue_(transform_value(new GLibValue(element_data_type, element_expr), stmt.type_reference, stmt));

                visit_local_variable(stmt.element_variable);
                ccode.add_assignment(get_variable_cexpression(get_local_cname(stmt.element_variable)), element_expr);

                stmt.body.emit(this);

                ccode.close();
            }
            else if (stmt.collection.value_type.compatible(new ObjectType(gvaluearray_type)))
            {
                // iterating over a GValueArray

                var iterator_variable = new LocalVariable(uint_type.copy(), "%s_index".printf(stmt.variable_name));
                visit_local_variable(iterator_variable);
                var arr_index = get_variable_cname(get_local_cname(iterator_variable));

                var ccond = new CCodeBinaryExpression(CCodeBinaryOperator.LESS_THAN, get_variable_cexpression(arr_index), CCodeMemberAccess.pointer(get_variable_cexpression(get_local_cname(collection_backup)), "n_values"));

                ccode.open_for(new CCodeAssignment(get_variable_cexpression(arr_index), new CCodeConstant("0")),
                               ccond,
                               new CCodeAssignment(get_variable_cexpression(arr_index), new CCodeBinaryExpression(CCodeBinaryOperator.PLUS, get_variable_cexpression(arr_index), new CCodeConstant("1"))));

                var get_item = new CCodeFunctionCall(new CCodeIdentifier("g_value_array_get_nth"));
                get_item.add_argument(get_variable_cexpression(get_local_cname(collection_backup)));
                get_item.add_argument(get_variable_cexpression(arr_index));

                CCodeExpression element_expr = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, get_item);

                if (stmt.type_reference.value_owned)
                {
                    element_expr = get_cvalue_(copy_value(new GLibValue(stmt.type_reference, element_expr), new StructValueType(gvalue_type)));
                }

                visit_local_variable(stmt.element_variable);
                ccode.add_assignment(get_variable_cexpression(get_local_cname(stmt.element_variable)), element_expr);

                stmt.body.emit(this);

                ccode.close();
            }

            foreach (LocalVariable local in stmt.get_local_variables())
            {
                if (requires_destroy(local.variable_type))
                {
                    ccode.add_expression(destroy_local(local));
                }
            }

            ccode.close();
        }
예제 #7
0
        /* Returns access values to the given parameter */
        public override TargetValue get_parameter_cvalue(Parameter param)
        {
            var result = new GLibValue(param.variable_type.copy());

            result.lvalue = true;
            result.array_null_terminated = get_ccode_array_null_terminated(param);
            if (get_ccode_array_length_expr(param) != null)
            {
                result.array_length_cexpr = new CCodeConstant(get_ccode_array_length_expr(param));
            }
            result.ctype = get_ccode_type(param);

            var array_type    = result.value_type as ArrayType;
            var delegate_type = result.value_type as DelegateType;

            bool is_unowned_delegate = delegate_type != null && !param.variable_type.value_owned;

            if ((param.captured || is_in_coroutine()) && !is_unowned_delegate)
            {
                result.value_type.value_owned = true;
            }

            if (param.name == "this")
            {
                if (is_in_coroutine())
                {
                    // use closure
                    result.cvalue = CCodeMemberAccess.pointer(new CCodeIdentifier("_data_"), "self");
                }
                else
                {
                    var st = result.value_type.data_type as Struct;
                    if (st != null && !st.is_simple_type())
                    {
                        result.cvalue = new CCodeIdentifier("(*self)");
                    }
                    else
                    {
                        result.cvalue = new CCodeIdentifier("self");
                    }
                }
            }
            else
            {
                string name = param.name;

                if (param.captured)
                {
                    // captured variables are stored on the heap
                    var block = param.parent_symbol as Block;
                    if (block == null)
                    {
                        block = ((Method)param.parent_symbol).body;
                    }
                    result.cvalue = CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_variable_cname(param.name));
                    if (array_type != null && get_ccode_array_length(param))
                    {
                        for (int dim = 1; dim <= array_type.rank; dim++)
                        {
                            result.append_array_length_cvalue(CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_parameter_array_length_cname(param, dim)));
                        }
                    }
                    else if (delegate_type != null && delegate_type.delegate_symbol.has_target)
                    {
                        result.delegate_target_cvalue = CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_ccode_delegate_target_name(param));
                        if (result.value_type.is_disposable())
                        {
                            result.delegate_target_destroy_notify_cvalue = CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), get_delegate_target_destroy_notify_cname(get_variable_cname(param.name)));
                        }
                    }
                }
                else if (is_in_coroutine())
                {
                    // use closure
                    result.cvalue = get_variable_cexpression(param.name);
                    if (delegate_type != null && delegate_type.delegate_symbol.has_target)
                    {
                        result.delegate_target_cvalue = CCodeMemberAccess.pointer(new CCodeIdentifier("_data_"), get_ccode_delegate_target_name(param));
                        if (delegate_type.is_disposable())
                        {
                            result.delegate_target_destroy_notify_cvalue = CCodeMemberAccess.pointer(new CCodeIdentifier("_data_"), get_delegate_target_destroy_notify_cname(get_variable_cname(param.name)));
                        }
                    }
                }
                else
                {
                    var type_as_struct = result.value_type.data_type as Struct;

                    if (param.direction == ParameterDirection.OUT)
                    {
                        name = "_vala_%s".printf(name);
                    }

                    if (param.direction == ParameterDirection.REF ||
                        (param.direction == ParameterDirection.IN && type_as_struct != null && !type_as_struct.is_simple_type() && !result.value_type.nullable))
                    {
                        result.cvalue = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier(get_variable_cname(name)));
                    }
                    else
                    {
                        // Property setters of non simple structs shall replace all occurrences
                        // of the "value" formal parameter with a dereferencing version of that
                        // parameter.
                        if (current_property_accessor != null &&
                            current_property_accessor.writable &&
                            current_property_accessor.value_parameter == param &&
                            current_property_accessor.prop.property_type.is_real_struct_type() &&
                            !current_property_accessor.prop.property_type.nullable)
                        {
                            result.cvalue = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier("value"));
                        }
                        else
                        {
                            result.cvalue = get_variable_cexpression(name);
                        }
                    }
                    if (delegate_type != null && delegate_type.delegate_symbol.has_target)
                    {
                        var target_cname = get_ccode_delegate_target_name(param);
                        if (param.direction == ParameterDirection.OUT)
                        {
                            target_cname = "_vala_%s".printf(target_cname);
                        }
                        CCodeExpression target_expr = new CCodeIdentifier(target_cname);
                        CCodeExpression delegate_target_destroy_notify = new CCodeIdentifier(get_delegate_target_destroy_notify_cname(get_variable_cname(name)));
                        if (param.direction == ParameterDirection.REF)
                        {
                            // accessing argument of ref param
                            target_expr = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
                            delegate_target_destroy_notify = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, delegate_target_destroy_notify);
                        }
                        result.delegate_target_cvalue = target_expr;
                        if (result.value_type.is_disposable())
                        {
                            result.delegate_target_destroy_notify_cvalue = delegate_target_destroy_notify;
                        }
                    }
                }
                if (!param.captured && array_type != null)
                {
                    if (get_ccode_array_length(param) && !get_ccode_array_null_terminated(param))
                    {
                        for (int dim = 1; dim <= array_type.rank; dim++)
                        {
                            CCodeExpression length_expr = get_variable_cexpression(get_parameter_array_length_cname(param, dim));
                            if (param.direction == ParameterDirection.OUT)
                            {
                                length_expr = get_variable_cexpression(get_array_length_cname(get_variable_cname(name), dim));
                            }
                            else if (param.direction == ParameterDirection.REF)
                            {
                                // accessing argument of ref param
                                length_expr = new CCodeUnaryExpression(CCodeUnaryOperator.POINTER_INDIRECTION, length_expr);
                            }
                            result.append_array_length_cvalue(length_expr);
                        }
                    }
                }
            }

            return(result);
        }
예제 #8
0
        public override void visit_member_access(MemberAccess expr)
        {
            CCodeExpression pub_inst = null;

            if (expr.inner != null)
            {
                pub_inst = get_cvalue(expr.inner);
            }

            var array_type    = expr.value_type as ArrayType;
            var delegate_type = expr.value_type as DelegateType;

            if (expr.symbol_reference is Method)
            {
                var m = (Method)expr.symbol_reference;

                if (!(m is DynamicMethod || m is ArrayMoveMethod || m is ArrayResizeMethod || m is ArrayCopyMethod))
                {
                    generate_method_declaration(m, cfile);

                    if (!m.external && m.external_package)
                    {
                        // internal VAPI methods
                        // only add them once per source file
                        if (add_generated_external_symbol(m))
                        {
                            visit_method(m);
                        }
                    }
                }

                if (expr.inner is BaseAccess)
                {
                    if (m.base_method != null)
                    {
                        var base_class = (Class)m.base_method.parent_symbol;
                        var vcast      = new CCodeFunctionCall(new CCodeIdentifier("%s_CLASS".printf(get_ccode_upper_case_name(base_class, null))));
                        vcast.add_argument(new CCodeIdentifier("%s_parent_class".printf(get_ccode_lower_case_name(current_class, null))));

                        set_cvalue(expr, CCodeMemberAccess.pointer(vcast, get_ccode_vfunc_name(m)));
                        return;
                    }
                    else if (m.base_interface_method != null)
                    {
                        var    base_iface       = (Interface)m.base_interface_method.parent_symbol;
                        string parent_iface_var = "%s_%s_parent_iface".printf(get_ccode_lower_case_name(current_class), get_ccode_lower_case_name(base_iface));

                        set_cvalue(expr, CCodeMemberAccess.pointer(new CCodeIdentifier(parent_iface_var), get_ccode_vfunc_name(m)));
                        return;
                    }
                }

                if (m.base_method != null)
                {
                    if (!method_has_wrapper(m.base_method))
                    {
                        var base_class = (Class)m.base_method.parent_symbol;
                        var vclass     = new CCodeFunctionCall(new CCodeIdentifier("%s_GET_CLASS".printf(get_ccode_upper_case_name(base_class))));
                        vclass.add_argument(pub_inst);
                        set_cvalue(expr, CCodeMemberAccess.pointer(vclass, get_ccode_vfunc_name(m)));
                    }
                    else
                    {
                        set_cvalue(expr, new CCodeIdentifier(get_ccode_name(m.base_method)));
                    }
                }
                else if (m.base_interface_method != null)
                {
                    set_cvalue(expr, new CCodeIdentifier(get_ccode_name(m.base_interface_method)));
                }
                else if (m is CreationMethod)
                {
                    set_cvalue(expr, new CCodeIdentifier(get_ccode_real_name(m)));
                }
                else
                {
                    set_cvalue(expr, new CCodeIdentifier(get_ccode_name(m)));
                }

                set_delegate_target_destroy_notify(expr, new CCodeConstant("NULL"));
                if (m.binding == MemberBinding.STATIC)
                {
                    set_delegate_target(expr, new CCodeConstant("NULL"));
                }
                else if (m.is_async_callback)
                {
                    if (current_method.closure)
                    {
                        var block = ((Method)m.parent_symbol).body;
                        set_delegate_target(expr, CCodeMemberAccess.pointer(get_variable_cexpression("_data%d_".printf(get_block_id(block))), "_async_data_"));
                    }
                    else
                    {
                        set_delegate_target(expr, new CCodeIdentifier("_data_"));
                    }
                }
                else if (expr.inner != null && !expr.prototype_access)
                {
                    // expr.inner is null in the special case of referencing the method in a constant initializer
                    var delegate_target = (CCodeExpression)get_ccodenode(expr.inner);
                    delegate_type = expr.target_type as DelegateType;
                    if ((expr.value_type.value_owned || (delegate_type != null && delegate_type.is_called_once)) && expr.inner.value_type.data_type != null && is_reference_counting(expr.inner.value_type.data_type))
                    {
                        var ref_call = new CCodeFunctionCall(get_dup_func_expression(expr.inner.value_type, expr.source_reference));
                        ref_call.add_argument(delegate_target);
                        delegate_target = ref_call;
                        set_delegate_target_destroy_notify(expr, get_destroy_func_expression(expr.inner.value_type));
                    }
                    set_delegate_target(expr, delegate_target);
                }
            }
            else if (expr.symbol_reference is ArrayLengthField)
            {
                if (expr.value_type is ArrayType && !(expr.parent_node is ElementAccess))
                {
                    Report.error(expr.source_reference, "unsupported use of length field of multi-dimensional array");
                }
                set_cvalue(expr, get_array_length_cexpression(expr.inner, 1));
            }
            else if (expr.symbol_reference is Field)
            {
                var field = (Field)expr.symbol_reference;
                if (expr.lvalue)
                {
                    expr.target_value = get_field_cvalue(field, expr.inner != null ? expr.inner.target_value : null);
                }
                else
                {
                    expr.target_value = load_field(field, expr.inner != null ? expr.inner.target_value : null);
                }
            }
            else if (expr.symbol_reference is EnumValue)
            {
                var ev = (EnumValue)expr.symbol_reference;

                generate_enum_declaration((ValaEnum)ev.parent_symbol, cfile);

                set_cvalue(expr, new CCodeConstant(get_ccode_name(ev)));
            }
            else if (expr.symbol_reference is Constant)
            {
                var c = (Constant)expr.symbol_reference;

                generate_constant_declaration(c, cfile,
                                              c.source_reference != null && expr.source_reference != null &&
                                              c.source_reference.file == expr.source_reference.file);

                string fn = c.get_full_name();
                if (fn == "GLib.Log.FILE")
                {
                    string s = Path.GetFileName(expr.source_reference.file.filename);
                    set_cvalue(expr, new CCodeConstant("\"%s\"".printf(s)));
                }
                else if (fn == "GLib.Log.LINE")
                {
                    int i = expr.source_reference.begin.line;
                    set_cvalue(expr, new CCodeConstant("%d".printf(i)));
                }
                else if (fn == "GLib.Log.METHOD")
                {
                    string s = "";
                    if (current_method != null)
                    {
                        s = current_method.get_full_name();
                    }
                    set_cvalue(expr, new CCodeConstant("\"%s\"".printf(s)));
                }
                else
                {
                    set_cvalue(expr, new CCodeIdentifier(get_ccode_name(c)));
                }

                if (array_type != null)
                {
                    var ccall = new CCodeFunctionCall(new CCodeIdentifier("G_N_ELEMENTS"));
                    ccall.add_argument(new CCodeIdentifier(get_ccode_name(c)));
                    append_array_length(expr, ccall);
                }
            }
            else if (expr.symbol_reference is Property)
            {
                var prop = (Property)expr.symbol_reference;

                if (!(prop is DynamicProperty))
                {
                    generate_property_accessor_declaration(prop.get_accessor, cfile);

                    if (!prop.external && prop.external_package)
                    {
                        // internal VAPI properties
                        // only add them once per source file
                        if (add_generated_external_symbol(prop))
                        {
                            visit_property(prop);
                        }
                    }
                }

                if (expr.inner is BaseAccess)
                {
                    var base_prop = prop;
                    if (prop.base_property != null)
                    {
                        base_prop = prop.base_property;
                    }
                    else if (prop.base_interface_property != null)
                    {
                        base_prop = prop.base_interface_property;
                    }
                    if (base_prop.parent_symbol is Class)
                    {
                        var base_class = (Class)base_prop.parent_symbol;
                        var vcast      = new CCodeFunctionCall(new CCodeIdentifier("%s_CLASS".printf(get_ccode_upper_case_name(base_class, null))));
                        vcast.add_argument(new CCodeIdentifier("%s_parent_class".printf(get_ccode_lower_case_name(current_class, null))));

                        var ccall = new CCodeFunctionCall(CCodeMemberAccess.pointer(vcast, "get_%s".printf(prop.name)));
                        ccall.add_argument(get_cvalue(expr.inner));
                        if (prop.property_type.is_real_non_null_struct_type())
                        {
                            var temp_value = (GLibValue)create_temp_value(prop.get_accessor.value_type, false, expr);
                            expr.target_value = load_temp_value(temp_value);
                            var ctemp = get_cvalue_(temp_value);
                            ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, ctemp));
                            ccode.add_expression(ccall);
                        }
                        else
                        {
                            set_cvalue(expr, ccall);
                        }
                    }
                    else if (base_prop.parent_symbol is Interface)
                    {
                        var    base_iface       = (Interface)base_prop.parent_symbol;
                        string parent_iface_var = "%s_%s_parent_iface".printf(get_ccode_lower_case_name(current_class), get_ccode_lower_case_name(base_iface));

                        var ccall = new CCodeFunctionCall(CCodeMemberAccess.pointer(new CCodeIdentifier(parent_iface_var), "get_%s".printf(prop.name)));
                        ccall.add_argument(get_cvalue(expr.inner));
                        if (prop.property_type.is_real_non_null_struct_type())
                        {
                            var temp_value = (GLibValue)create_temp_value(prop.get_accessor.value_type, false, expr);
                            expr.target_value = load_temp_value(temp_value);
                            var ctemp = get_cvalue_(temp_value);
                            ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, ctemp));
                            ccode.add_expression(ccall);
                        }
                        else
                        {
                            set_cvalue(expr, ccall);
                        }
                    }
                }
                else if (prop.binding == MemberBinding.INSTANCE &&
                         prop.get_accessor.automatic_body &&
                         !prop.get_accessor.value_type.value_owned &&
                         current_type_symbol == prop.parent_symbol &&
                         current_type_symbol is Class &&
                         prop.base_property == null &&
                         prop.base_interface_property == null &&
                         !(prop.property_type is ArrayType || prop.property_type is DelegateType))
                {
                    CCodeExpression inst;
                    inst = CCodeMemberAccess.pointer(pub_inst, "priv");
                    set_cvalue(expr, CCodeMemberAccess.pointer(inst, get_ccode_name(prop.field)));
                }
                else if (!get_ccode_no_accessor_method(prop))
                {
                    string getter_cname;
                    if (prop is DynamicProperty)
                    {
                        getter_cname = get_dynamic_property_getter_cname((DynamicProperty)prop);
                    }
                    else
                    {
                        getter_cname = get_ccode_name(prop.get_accessor);
                    }
                    var ccall = new CCodeFunctionCall(new CCodeIdentifier(getter_cname));

                    if (prop.binding == MemberBinding.INSTANCE)
                    {
                        if (prop.parent_symbol is Struct && !((Struct)prop.parent_symbol).is_simple_type())
                        {
                            // we need to pass struct instance by reference
                            var instance = expr.inner.target_value;
                            if (!get_lvalue(instance))
                            {
                                instance = store_temp_value(instance, expr);
                            }
                            pub_inst = new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, get_cvalue_(instance));
                        }

                        ccall.add_argument(pub_inst);
                    }

                    bool prop_is_real_non_null_struct_type = prop.property_type.is_real_non_null_struct_type();
                    var  temp_value = (GLibValue)create_temp_value(prop.get_accessor.value_type, prop_is_real_non_null_struct_type, expr);
                    expr.target_value = load_temp_value(temp_value);
                    var ctemp = get_cvalue_(temp_value);

                    // Property access to real struct types is handled differently
                    // The value is returned by out parameter
                    if (prop_is_real_non_null_struct_type)
                    {
                        ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, ctemp));
                        ccode.add_expression(ccall);
                    }
                    else
                    {
                        ccode.add_assignment(ctemp, ccall);

                        array_type = prop.property_type as ArrayType;
                        if (array_type != null)
                        {
                            if (get_ccode_array_null_terminated(prop))
                            {
                                requires_array_length = true;
                                var len_call = new CCodeFunctionCall(new CCodeIdentifier("_vala_array_length"));
                                len_call.add_argument(ctemp);

                                ccode.add_assignment(temp_value.array_length_cvalues[0], len_call);
                            }
                            else if (get_ccode_array_length(prop))
                            {
                                for (int dim = 1; dim <= array_type.rank; dim++)
                                {
                                    ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, get_array_length_cvalue(temp_value, dim)));
                                }
                            }
                        }
                        else
                        {
                            delegate_type = prop.property_type as DelegateType;
                            if (delegate_type != null && delegate_type.delegate_symbol.has_target)
                            {
                                ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_cvalue(temp_value)));
                            }
                        }
                    }
                }
                else
                {
                    var ccall = new CCodeFunctionCall(new CCodeIdentifier("g_object_get"));
                    ccall.add_argument(pub_inst);

                    // property name is second argument of g_object_get
                    ccall.add_argument(get_property_canonical_cconstant(prop));

                    // g_object_get always returns owned values
                    // therefore, property getters of properties
                    // without accessor methods need to be marked as owned
                    if (!prop.get_accessor.value_type.value_owned)
                    {
                        // only report error for types where there actually
                        // is a difference between `owned' and `unowned'
                        var owned_value_type = prop.get_accessor.value_type.copy();
                        owned_value_type.value_owned = true;
                        if (requires_copy(owned_value_type))
                        {
                            Report.error(prop.get_accessor.source_reference, "unowned return value for getter of property `%s' not supported without accessor".printf(prop.get_full_name()));
                        }
                    }

                    if (expr.value_type.is_real_struct_type())
                    {
                        // gobject allocates structs on heap
                        expr.value_type.nullable = true;
                    }

                    var temp_var = get_temp_variable(expr.value_type);
                    var ctemp    = get_variable_cexpression(temp_var.name);
                    emit_temp_var(temp_var);
                    ccall.add_argument(new CCodeUnaryExpression(CCodeUnaryOperator.ADDRESS_OF, ctemp));
                    ccall.add_argument(new CCodeConstant("NULL"));
                    ccode.add_expression(ccall);
                    set_cvalue(expr, ctemp);
                }
                expr.target_value.value_type = expr.value_type;
                expr.target_value            = store_temp_value(expr.target_value, expr);
            }
            else if (expr.symbol_reference is LocalVariable)
            {
                var local = (LocalVariable)expr.symbol_reference;

                if (expr.parent_node is ReturnStatement &&
                    current_return_type.value_owned &&
                    local.variable_type.value_owned &&
                    !local.captured &&
                    !variable_accessible_in_finally(local) &&
                    !(local.variable_type is ArrayType && ((ArrayType)local.variable_type).inline_allocated))
                {
                    /* return expression is local variable taking ownership and
                     * current method is transferring ownership */

                    // don't ref expression
                    expr.value_type.value_owned = true;

                    // don't unref variable
                    local.active = false;

                    var glib_value = (GLibValue)get_local_cvalue(local);
                    expr.target_value = glib_value;
                    if (glib_value.delegate_target_cvalue == null)
                    {
                        glib_value.delegate_target_cvalue = new CCodeConstant("NULL");
                    }
                    if (glib_value.delegate_target_destroy_notify_cvalue == null)
                    {
                        glib_value.delegate_target_destroy_notify_cvalue = new CCodeConstant("NULL");
                    }
                }
                else
                {
                    if (expr.lvalue)
                    {
                        expr.target_value = get_local_cvalue(local);
                    }
                    else
                    {
                        expr.target_value = load_local(local);
                    }
                }
            }
            else if (expr.symbol_reference is Parameter)
            {
                var param = (Parameter)expr.symbol_reference;
                if (expr.lvalue)
                {
                    expr.target_value = get_parameter_cvalue(param);
                }
                else
                {
                    expr.target_value = load_parameter(param);
                }
            }
        }
예제 #9
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();
        }