[vala/staging] codegen: Use memset to initialize inline-allocated array with non-constant size



commit b95a766454eb914f4eb5a68e9040e03faffabf52
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Wed Mar 18 14:05:13 2020 +0100

    codegen: Use memset to initialize inline-allocated array with non-constant size
    
    In addition to a0bb129e5a2e8580eb272d9a68ba054e7b170dba
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/910

 codegen/valaccodebasemodule.vala                 | 50 +++++++++++++++++-----
 tests/arrays/fixed-length-init0-not-allowed.vala | 54 ++++++++++++++++++++----
 2 files changed, 85 insertions(+), 19 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 27b0ba101..a21b8f315 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -1453,6 +1453,19 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                return (null != cparenthesized && is_constant_ccode_expression (cparenthesized.inner));
        }
 
+       public static bool is_constant_ccode (CodeNode expr) {
+               if (expr is Constant) {
+                       // Local constants are not considered constant in C
+                       return !(((Constant) expr).parent_symbol is Block);
+               } else if (expr is MemberAccess) {
+                       return is_constant_ccode (((MemberAccess) expr).symbol_reference);
+               } else if (expr is CastExpression) {
+                       return is_constant_ccode (((CastExpression) expr).inner);
+               }
+
+               return false;
+       }
+
        /**
         * Returns whether the passed cexpr is a pure expression, i.e. an
         * expression without side-effects.
@@ -2523,9 +2536,17 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 
                                // try to initialize uninitialized variables
                                // initialization not necessary for variables stored in closure
-                               if (is_init_allowed (local.variable_type)) {
+                               CCodeExpression? size = null;
+                               if (!requires_memset_init (local, out size)) {
                                        cvar.initializer = default_value_for_type (local.variable_type, true);
                                        cvar.init0 = true;
+                               } else if (size != null && local.initializer == null) {
+                                       cfile.add_include ("string.h");
+                                       var memset_call = new CCodeFunctionCall (new CCodeIdentifier 
("memset"));
+                                       memset_call.add_argument (get_variable_cexpression (local.name));
+                                       memset_call.add_argument (new CCodeConstant ("0"));
+                                       memset_call.add_argument (size);
+                                       ccode.add_expression (memset_call);
                                }
 
                                ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
@@ -3786,9 +3807,17 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        }
                } else {
                        var cvar = new CCodeVariableDeclarator (local.name, null, get_ccode_declarator_suffix 
(local.variable_type));
-                       if (init && is_init_allowed (local.variable_type)) {
+                       CCodeExpression? size = null;
+                       if (init && !requires_memset_init (local, out size)) {
                                cvar.initializer = default_value_for_type (local.variable_type, true, 
on_error);
                                cvar.init0 = true;
+                       } else if (init && size != null && local.initializer == null) {
+                               cfile.add_include ("string.h");
+                               var memset_call = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
+                               memset_call.add_argument (get_variable_cexpression (local.name));
+                               memset_call.add_argument (new CCodeConstant ("0"));
+                               memset_call.add_argument (size);
+                               ccode.add_expression (memset_call);
                        }
                        ccode.add_declaration (get_ccode_name (local.variable_type), cvar);
                }
@@ -6249,15 +6278,16 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                return true;
        }
 
-       public bool is_init_allowed (DataType type) {
-               unowned ArrayType? array_type = type as ArrayType;
-               if (array_type != null && array_type.inline_allocated
-                  && array_type.fixed_length) {
-                  unowned Constant? c = array_type.length.symbol_reference as Constant;
-                  // our local constants are not actual constants in C
-                  return (c == null || !(c.parent_symbol is Block));
+       public bool requires_memset_init (Variable variable, out CCodeExpression? size) {
+               unowned ArrayType? array_type = variable.variable_type as ArrayType;
+               if (array_type != null && array_type.fixed_length && !is_constant_ccode (array_type.length)) {
+                       var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+                       sizeof_call.add_argument (new CCodeIdentifier (get_ccode_name 
(array_type.element_type)));
+                       size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, get_ccodenode 
(array_type.length), sizeof_call);
+                       return true;
                }
-               return true;
+               size = null;
+               return false;
        }
 
        public CCodeDeclaratorSuffix? get_ccode_declarator_suffix (DataType type) {
diff --git a/tests/arrays/fixed-length-init0-not-allowed.vala 
b/tests/arrays/fixed-length-init0-not-allowed.vala
index 932f011b3..9cb8a43a7 100644
--- a/tests/arrays/fixed-length-init0-not-allowed.vala
+++ b/tests/arrays/fixed-length-init0-not-allowed.vala
@@ -1,13 +1,49 @@
+const int BAR = 1024;
+
 void main () {
-       const int FOO = 4;
+       {
+               const int FOO = 4;
+
+               char bar[FOO] = { 'f', 'o', 'o', '\0' };
+               assert ((string) bar == "foo");
+
+               char baz[FOO];
+               baz[0] = 'f';
+               baz[1] = 'o';
+               baz[2] = 'o';
+               baz[3] = '\0';
+               assert ((string) baz == "foo");
+       }
+       {
+               const int FOO = 1024;
+
+               string foo[FOO];
+
+               assert (foo[0] == null);
+               assert (foo[FOO / 2] == null);
+               assert (foo[FOO - 1] == null);
+       }
+       {
+               const int FOO = 1024;
+
+               string array[16 * FOO];
+
+               assert (array[0] == null);
+               assert (array[16 * FOO / 2] == null);
+               assert (array[16 * FOO - 1] == null);
+       }
+       {
+               string array[BAR];
 
-       char bar[FOO] = { 'f', 'o', 'o', '\0' };
-       assert ((string) bar == "foo");
+               assert (array[0] == null);
+               assert (array[BAR / 2] == null);
+               assert (array[BAR - 1] == null);
+       }
+       {
+               string array[16 * BAR];
 
-       char baz[FOO];
-       baz[0] = 'f';
-       baz[1] = 'o';
-       baz[2] = 'o';
-       baz[3] = '\0';
-       assert ((string) baz == "foo");
+               assert (array[0] == null);
+               assert (array[16 * BAR / 2] == null);
+               assert (array[16 * BAR - 1] == null);
+       }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]