]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
codegen: Replace get_unref_expression_ with destroy_variable
authorLuca Bruno <lucabru@src.gnome.org>
Sat, 22 Jan 2011 11:26:03 +0000 (12:26 +0100)
committerJürg Billeter <j@bitron.ch>
Sun, 13 Feb 2011 14:47:10 +0000 (15:47 +0100)
codegen/valaccodearraymodule.vala
codegen/valaccodebasemodule.vala
codegen/valaccodecontrolflowmodule.vala
codegen/valaccodememberaccessmodule.vala
codegen/valadbusclientmodule.vala
codegen/valadbusservermodule.vala
codegen/valagasyncmodule.vala
codegen/valagdbusclientmodule.vala
codegen/valagdbusservermodule.vala

index 3bfb3b1fa0fbbf70d6d6f88896fb76183688035f..9a998d6c3a5f07ab660f31ddec1ad887e44c1a7a 100644 (file)
@@ -449,6 +449,25 @@ public class Vala.CCodeArrayModule : CCodeMethodCallModule {
                }
        }
 
+       public override CCodeExpression destroy_variable (Variable variable, CCodeExpression? inner = null) {
+               var array_type = variable.variable_type as ArrayType;
+               if (array_type != null && array_type.fixed_length) {
+                       requires_array_free = true;
+
+                       var ccall = new CCodeFunctionCall (get_destroy_func_expression (variable.variable_type));
+                       var value = get_variable_cvalue (variable);
+
+                       ccall = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_destroy"));
+                       ccall.add_argument (get_cvalue_ (value));
+                       ccall.add_argument (new CCodeConstant ("%d".printf (array_type.length)));
+                       ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
+
+                       return ccall;
+               }
+
+               return base.destroy_variable (variable, inner);
+       }
+
        public override CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
                var type = value.value_type;
 
index 328de67ef805a017cc6705a2a91709276620a4b1..53285c9e3340772f026f89e57efaf2a88a2e090b 100644 (file)
@@ -991,7 +991,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                }
 
                                foreach (LocalVariable local in temp_ref_vars) {
-                                       ccode.add_expression (get_unref_expression_ (local));
+                                       ccode.add_expression (destroy_variable (local));
                                }
 
                                temp_ref_vars.clear ();
@@ -1045,7 +1045,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                ccode.add_assignment (lhs, rhs);
 
                                foreach (LocalVariable local in temp_ref_vars) {
-                                       ccode.add_expression (get_unref_expression_ (local));
+                                       ccode.add_expression (destroy_variable (local));
                                }
 
                                temp_ref_vars.clear ();
@@ -1710,7 +1710,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                current_method.coroutine = false;
                        }
 
-                       free_block.add_statement (new CCodeExpressionStatement (get_unref_expression_ (param)));
+                       free_block.add_statement (new CCodeExpressionStatement (destroy_variable (param)));
 
                        if (old_coroutine) {
                                current_method.coroutine = true;
@@ -1803,7 +1803,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                                        current_method.coroutine = false;
                                                }
 
-                                               free_block.add_statement (new CCodeExpressionStatement (get_unref_expression_ (local)));
+                                               free_block.add_statement (new CCodeExpressionStatement (destroy_variable (local)));
 
                                                if (old_coroutine) {
                                                        current_method.coroutine = true;
@@ -1929,7 +1929,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        var local = local_vars[i];
                        local.active = false;
                        if (!local.unreachable && !local.floating && !local.captured && requires_destroy (local.variable_type)) {
-                               ccode.add_expression (get_unref_expression_ (local));
+                               ccode.add_expression (destroy_variable (local));
                        }
                }
 
@@ -1937,7 +1937,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        var m = (Method) b.parent_symbol;
                        foreach (Parameter param in m.get_parameters ()) {
                                if (!param.captured && !param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
-                                       ccode.add_expression (get_unref_expression_ (param));
+                                       ccode.add_expression (destroy_variable (param));
                                } else if (param.direction == ParameterDirection.OUT && !m.coroutine) {
                                        return_out_parameter (param);
                                }
@@ -2789,13 +2789,163 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                return null;
        }
 
-       public CCodeExpression get_unref_expression_ (Variable variable, CCodeExpression? inner = null) {
-               return destroy_value (get_variable_cvalue (variable, inner));
+       // logic in this method is temporarily duplicated in destroy_value
+       // apply changes to both methods
+       public virtual CCodeExpression destroy_variable (Variable variable, CCodeExpression? inner = null) {
+               var type = variable.variable_type;
+               var target_lvalue = get_variable_cvalue (variable, inner);
+               var cvar = get_cvalue_ (target_lvalue);
+
+               if (type is DelegateType) {
+                       var delegate_target = get_delegate_target_cvalue (target_lvalue);
+                       var delegate_target_destroy_notify = get_delegate_target_destroy_notify_cvalue (target_lvalue);
+
+                       var ccall = new CCodeFunctionCall (delegate_target_destroy_notify);
+                       ccall.add_argument (delegate_target);
+
+                       var destroy_call = new CCodeCommaExpression ();
+                       destroy_call.append_expression (ccall);
+                       destroy_call.append_expression (new CCodeConstant ("NULL"));
+
+                       var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, delegate_target_destroy_notify, new CCodeConstant ("NULL"));
+
+                       var ccomma = new CCodeCommaExpression ();
+                       ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), destroy_call));
+                       ccomma.append_expression (new CCodeAssignment (cvar, new CCodeConstant ("NULL")));
+                       ccomma.append_expression (new CCodeAssignment (delegate_target, new CCodeConstant ("NULL")));
+                       ccomma.append_expression (new CCodeAssignment (delegate_target_destroy_notify, new CCodeConstant ("NULL")));
+
+                       return ccomma;
+               }
+
+               var ccall = new CCodeFunctionCall (get_destroy_func_expression (type));
+
+               if (type is ValueType && !type.nullable) {
+                       // normal value type, no null check
+                       var st = type.data_type as Struct;
+                       if (st != null && st.is_simple_type ()) {
+                               // used for va_list
+                               ccall.add_argument (cvar);
+                       } else {
+                               ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
+                       }
+
+                       if (gvalue_type != null && type.data_type == gvalue_type) {
+                               // g_value_unset must not be called for already unset values
+                               var cisvalid = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_VALUE"));
+                               cisvalid.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cvar));
+
+                               var ccomma = new CCodeCommaExpression ();
+                               ccomma.append_expression (ccall);
+                               ccomma.append_expression (new CCodeConstant ("NULL"));
+
+                               return new CCodeConditionalExpression (cisvalid, ccomma, new CCodeConstant ("NULL"));
+                       } else {
+                               return ccall;
+                       }
+               }
+
+               if (ccall.call is CCodeIdentifier && !(type is ArrayType)) {
+                       // generate and use NULL-aware free macro to simplify code
+
+                       var freeid = (CCodeIdentifier) ccall.call;
+                       string free0_func = "_%s0".printf (freeid.name);
+
+                       if (add_wrapper (free0_func)) {
+                               var macro = destroy_value (new GLibValue (type, new CCodeIdentifier ("var")), true);
+                               cfile.add_type_declaration (new CCodeMacroReplacement.with_expression ("%s(var)".printf (free0_func), macro));
+                       }
+
+                       ccall = new CCodeFunctionCall (new CCodeIdentifier (free0_func));
+                       ccall.add_argument (cvar);
+                       return ccall;
+               }
+
+               /* (foo == NULL ? NULL : foo = (unref (foo), NULL)) */
+
+               /* can be simplified to
+                * foo = (unref (foo), NULL)
+                * if foo is of static type non-null
+                */
+
+               var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cvar, new CCodeConstant ("NULL"));
+               if (type.type_parameter != null) {
+                       if (!(current_type_symbol is Class) || current_class.is_compact) {
+                               return new CCodeConstant ("NULL");
+                       }
+
+                       // unref functions are optional for type parameters
+                       var cunrefisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_destroy_func_expression (type), new CCodeConstant ("NULL"));
+                       cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cunrefisnull);
+               }
+
+               ccall.add_argument (cvar);
+
+               /* set freed references to NULL to prevent further use */
+               var ccomma = new CCodeCommaExpression ();
+
+               if (context.profile == Profile.GOBJECT) {
+                       if (type.data_type != null && !type.data_type.is_reference_counting () &&
+                           (type.data_type == gstringbuilder_type
+                            || type.data_type == garray_type
+                            || type.data_type == gbytearray_type
+                            || type.data_type == gptrarray_type)) {
+                               ccall.add_argument (new CCodeConstant ("TRUE"));
+                       } else if (type.data_type == gthreadpool_type) {
+                               ccall.add_argument (new CCodeConstant ("FALSE"));
+                               ccall.add_argument (new CCodeConstant ("TRUE"));
+                       } else if (type is ArrayType) {
+                               var array_type = (ArrayType) type;
+                               if (requires_destroy (array_type.element_type) && !variable.no_array_length) {
+                                       CCodeExpression csizeexpr = null;
+                                       TargetValue access_value = null;
+                                       if (variable is LocalVariable) {
+                                               access_value = load_local ((LocalVariable) variable);
+                                       } else if (variable is Parameter) {
+                                               access_value = load_parameter ((Parameter) variable);
+                                       }
+                                       bool first = true;
+                                       for (int dim = 1; dim <= array_type.rank; dim++) {
+                                               if (first) {
+                                                       csizeexpr = get_array_length_cvalue (access_value, dim);
+                                                       first = false;
+                                               } else {
+                                                       csizeexpr = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeexpr, get_array_length_cvalue (access_value, dim));
+                                               }
+                                       }
+
+                                       var st = array_type.element_type.data_type as Struct;
+                                       if (st != null && !array_type.element_type.nullable) {
+                                               ccall.call = new CCodeIdentifier (append_struct_array_free (st));
+                                               ccall.add_argument (csizeexpr);
+                                       } else {
+                                               requires_array_free = true;
+                                               ccall.call = new CCodeIdentifier ("_vala_array_free");
+                                               ccall.add_argument (csizeexpr);
+                                               ccall.add_argument (new CCodeCastExpression (get_destroy_func_expression (array_type.element_type), "GDestroyNotify"));
+                                       }
+                               }
+                       }
+               }
+
+               ccomma.append_expression (ccall);
+               ccomma.append_expression (new CCodeConstant ("NULL"));
+
+               var cassign = new CCodeAssignment (cvar, ccomma);
+
+               // g_free (NULL) is allowed
+               bool uses_gfree = (type.data_type != null && !type.data_type.is_reference_counting () && type.data_type.get_free_function () == "g_free");
+               uses_gfree = uses_gfree || type is ArrayType;
+               if (uses_gfree) {
+                       return cassign;
+               }
+
+               return new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), cassign);
        }
 
        public CCodeExpression get_unref_expression (CCodeExpression cvar, DataType type, Expression? expr, bool is_macro_definition = false) {
                if (expr != null && (expr.symbol_reference is LocalVariable || expr.symbol_reference is Parameter)) {
-                       return get_unref_expression_ ((Variable) expr.symbol_reference);
+                       return destroy_variable ((Variable) expr.symbol_reference);
                }
                var value = new GLibValue (type, cvar);
                if (expr != null && expr.target_value != null) {
@@ -2806,6 +2956,8 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                return destroy_value (value, is_macro_definition);
        }
 
+       // logic in this method is temporarily duplicated in destroy_variable
+       // apply changes to both methods
        public virtual CCodeExpression destroy_value (TargetValue value, bool is_macro_definition = false) {
                var type = value.value_type;
                var cvar = get_cvalue_ (value);
@@ -2984,7 +3136,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                }
                
                foreach (LocalVariable local in temp_ref_vars) {
-                       expr_list.append_expression (get_unref_expression_ (local));
+                       expr_list.append_expression (destroy_variable (local));
                }
 
                if (full_expr_var != null) {
@@ -3060,7 +3212,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                /* free temporary objects and handle errors */
 
                foreach (LocalVariable local in temp_ref_vars) {
-                       ccode.add_expression (get_unref_expression_ (local));
+                       ccode.add_expression (destroy_variable (local));
                }
 
                if (stmt.tree_can_fail && stmt.expression.tree_can_fail) {
@@ -3079,7 +3231,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                for (int i = local_vars.size - 1; i >= 0; i--) {
                        var local = local_vars[i];
                        if (!local.unreachable && local.active && !local.floating && !local.captured && requires_destroy (local.variable_type)) {
-                               ccode.add_expression (get_unref_expression_ (local));
+                               ccode.add_expression (destroy_variable (local));
                        }
                }
 
@@ -3114,7 +3266,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
        private void append_param_free (Method m) {
                foreach (Parameter param in m.get_parameters ()) {
                        if (!param.ellipsis && requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
-                               ccode.add_expression (get_unref_expression_ (param));
+                               ccode.add_expression (destroy_variable (param));
                        }
                }
        }
@@ -3154,7 +3306,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 
                if (param.variable_type.is_disposable ()){
                        ccode.add_else ();
-                       ccode.add_expression (get_unref_expression_ (param));
+                       ccode.add_expression (destroy_variable (param));
                }
                ccode.close ();
 
@@ -3527,6 +3679,10 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                assert_not_reached ();
        }
 
+       public virtual TargetValue load_parameter (Parameter param) {
+               assert_not_reached ();
+       }
+
        public virtual string get_delegate_target_cname (string delegate_cname) {
                assert_not_reached ();
        }
index 6ad5f014d116fa9d6e61e2dc1dcbed7761c9fad2..86023721d640e22f9bc11ce0db01fa31e8a2c4cc 100644 (file)
@@ -380,7 +380,7 @@ public abstract class Vala.CCodeControlFlowModule : CCodeMethodModule {
 
                foreach (LocalVariable local in stmt.get_local_variables ()) {
                        if (requires_destroy (local.variable_type)) {
-                               ccode.add_expression (get_unref_expression_ (local));
+                               ccode.add_expression (destroy_variable (local));
                        }
                }
 
index 882109dce2c9ca54a33321f6e734045e8aa3d07c..f1937c206fb6600b5c5e935898a0693c481af17f 100644 (file)
@@ -704,7 +704,8 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
                return load_variable (local, result);
        }
 
-       public TargetValue load_parameter (Parameter param) {
+       /* Returns unowned access to the given parameter */
+       public override TargetValue load_parameter (Parameter param) {
                var result = (GLibValue) get_parameter_cvalue (param);
                if (result.value_type is DelegateType) {
                        result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
index 7428ac2bdf8390b3f1ba11094e9af09a15622c4c..074415289a74937d8b7dc127702a2b7e313ec8b1 100644 (file)
@@ -1577,7 +1577,7 @@ public class Vala.DBusClientModule : DBusModule {
                        if (requires_destroy (owned_type)) {
                                // keep local alive (symbol_reference is weak)
                                var local = new LocalVariable (owned_type, param.name);
-                               var stmt = new CCodeExpressionStatement (get_unref_expression_ (local));
+                               var stmt = new CCodeExpressionStatement (destroy_variable (local));
                                postfragment.append (stmt);
                        }
                }
index 3cc1c89fe5731194594fde5294147870b4e17fb9..cbae8cf749e0aeba9bac77838801f7f1db492063 100644 (file)
@@ -252,7 +252,7 @@ public class Vala.DBusServerModule : DBusClientModule {
                        if (requires_destroy (owned_type)) {
                                // keep local alive (symbol_reference is weak)
                                var local = new LocalVariable (owned_type, param.name);
-                               var stmt = new CCodeExpressionStatement (get_unref_expression_ (local));
+                               var stmt = new CCodeExpressionStatement (destroy_variable (local));
                                if (param.direction == ParameterDirection.IN) {
                                        in_postfragment.append (stmt);
                                } else {
index 997181793e3cf55fb4f114bd7e3398934925cee4..5aafe8dbf109a835fa3ea4d1b47794e47a77bb6d 100644 (file)
@@ -111,7 +111,7 @@ public class Vala.GAsyncModule : GSignalModule {
                                        bool old_captured = param.captured;
                                        param.captured = false;
 
-                                       freeblock.add_statement (new CCodeExpressionStatement (get_unref_expression_ (param)));
+                                       freeblock.add_statement (new CCodeExpressionStatement (destroy_variable (param)));
 
                                        param.captured = old_captured;
                                }
@@ -593,7 +593,7 @@ public class Vala.GAsyncModule : GSignalModule {
                /* free temporary objects */
 
                foreach (LocalVariable local in temp_ref_vars) {
-                       ccode.add_expression (get_unref_expression_ (local));
+                       ccode.add_expression (destroy_variable (local));
                }
 
                temp_ref_vars.clear ();
index 666ac198880612c045b11b719f4941893fe2ef67..054047ae20e7ee4310a930a7a905e614809c7be2 100644 (file)
@@ -395,7 +395,7 @@ public class Vala.GDBusClientModule : GDBusModule {
                        if (requires_destroy (owned_type)) {
                                // keep local alive (symbol_reference is weak)
                                var local = new LocalVariable (owned_type, param.name);
-                               ccode.add_expression (get_unref_expression_ (local));
+                               ccode.add_expression (destroy_variable (local));
                        }
                }
 
index 7514c1d9ae3a2a160370333d8617f02871b640e6..2f718573d3093ac9477d29793185b00a39860833 100644 (file)
@@ -389,7 +389,7 @@ public class Vala.GDBusServerModule : GDBusClientModule {
                                if (requires_destroy (owned_type)) {
                                        // keep local alive (symbol_reference is weak)
                                        var local = new LocalVariable (owned_type, param.name);
-                                       ccode.add_expression (get_unref_expression_ (local));
+                                       ccode.add_expression (destroy_variable (local));
                                }
                        }
                }