From ddc2c493651bb4a7609de2589cf9766eea19e0ec Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Fri, 25 Mar 2022 08:42:54 +0200 Subject: [PATCH] cgen: autofree out of scope variables in reverse order of their creation --- vlib/v/gen/c/cgen.v | 29 +++++++----- ...e_variables_in_reverse_order_of_creation.v | 46 +++++++++++++++++++ 2 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 vlib/v/tests/valgrind/free_variables_in_reverse_order_of_creation.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index c0c321ff35..c689aa0cd0 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -203,6 +203,7 @@ mut: cur_lock ast.LockExpr autofree_methods map[int]bool generated_free_methods map[int]bool + autofree_scope_stmts []string } pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { @@ -716,7 +717,8 @@ pub fn (mut g Gen) init() { } if g.pref.autofree { g.comptime_definitions.writeln('#define _VAUTOFREE (1)') - // g.comptime_definitions.writeln('unsigned char* g_cur_str;') + } else { + g.comptime_definitions.writeln('#define _VAUTOFREE (0)') } if g.pref.prealloc { g.comptime_definitions.writeln('#define _VPREALLOC (1)') @@ -2577,6 +2579,9 @@ fn (mut g Gen) autofree_scope_vars2(scope &ast.Scope, start_pos int, end_pos int else {} } } + for g.autofree_scope_stmts.len > 0 { + g.write(g.autofree_scope_stmts.pop()) + } // Free all vars in parent scopes as well: // ``` // s := ... @@ -2663,30 +2668,32 @@ fn (mut g Gen) autofree_var_call(free_fn_name string, v ast.Var) { // TODO remove this temporary hack return } + mut af := strings.new_builder(128) if v.typ.is_ptr() { - g.write('\t') + af.write_string('\t') if v.typ.share() == .shared_t { - g.write(free_fn_name.replace_each(['__shared__', ''])) + af.write_string(free_fn_name.replace_each(['__shared__', ''])) } else { - g.write(free_fn_name) + af.write_string(free_fn_name) } - g.write('(') + af.write_string('(') if v.typ.share() == .shared_t { - g.write('&') + af.write_string('&') } - g.write(strings.repeat(`*`, v.typ.nr_muls() - 1)) // dereference if it is a pointer to a pointer - g.write(c_name(v.name)) + af.write_string(strings.repeat(`*`, v.typ.nr_muls() - 1)) // dereference if it is a pointer to a pointer + af.write_string(c_name(v.name)) if v.typ.share() == .shared_t { - g.write('->val') + af.write_string('->val') } - g.writeln('); // autofreed ptr var') + af.writeln('); // autofreed ptr var') } else { if v.typ == ast.error_type && !v.is_autofree_tmp { return } - g.writeln('\t${free_fn_name}(&${c_name(v.name)}); // autofreed var $g.cur_mod.name $g.is_builtin_mod') + af.writeln('\t${free_fn_name}(&${c_name(v.name)}); // autofreed var $g.cur_mod.name $g.is_builtin_mod') } + g.autofree_scope_stmts << af.str() } fn (mut g Gen) map_fn_ptrs(key_typ ast.TypeSymbol) (string, string, string, string) { diff --git a/vlib/v/tests/valgrind/free_variables_in_reverse_order_of_creation.v b/vlib/v/tests/valgrind/free_variables_in_reverse_order_of_creation.v new file mode 100644 index 0000000000..ff7afe48a0 --- /dev/null +++ b/vlib/v/tests/valgrind/free_variables_in_reverse_order_of_creation.v @@ -0,0 +1,46 @@ +[has_globals] +module main + +__global frees = []int{cap: 100} + +struct Test { + a int +} + +fn (t &Test) free() { + frees << t.a +} + +fn test(a int) Test { + return Test{a} +} + +fn use_some_returned_variables() { + a := test(1) + println(a) + { + cc := test(333) + dd := test(444) + println(cc) + println(dd) + } + b := test(2) + if C._VAUTOFREE == 1 { + assert frees.len == 2 + assert frees[0] == 444 + assert frees[1] == 333 + } + println(b) +} + +fn main() { + use_some_returned_variables() + if C._VAUTOFREE == 1 { + assert frees.len == 4 + assert frees[0] == 444 + assert frees[1] == 333 + assert frees[2] == 2 + assert frees[3] == 1 + } + unsafe { frees.free() } +}