memory fixes: 21% of V compiler leaks fixed

pull/4166/head
Alexander Medvednikov 2020-03-31 14:33:16 +02:00
parent 9b9c1cc834
commit 956bf23390
4 changed files with 181 additions and 122 deletions

View File

@ -73,7 +73,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
for file in files { for file in files {
g.file = file g.file = file
// println('\ncgen "$g.file.path" nr_stmts=$file.stmts.len') // println('\ncgen "$g.file.path" nr_stmts=$file.stmts.len')
building_v := g.file.path.contains('/vlib/') || g.file.path.contains('cmd/v') building_v := true && (g.file.path.contains('/vlib/') || g.file.path.contains('cmd/v'))
is_test := g.file.path.ends_with('.vv') || g.file.path.ends_with('_test.v') is_test := g.file.path.ends_with('.vv') || g.file.path.ends_with('_test.v')
if g.file.path.ends_with('_test.v') { if g.file.path.ends_with('_test.v') {
g.is_test = is_test g.is_test = is_test
@ -454,7 +454,7 @@ fn (g mut Gen) for_in(it ast.ForInStmt) {
g.write('; $i < ') g.write('; $i < ')
g.expr(it.high) g.expr(it.high)
g.writeln('; $i++) { ') g.writeln('; $i++) { ')
g.writeln('int $it.val_var = $i;') g.writeln('\tint $it.val_var = $i;')
g.stmts(it.stmts) g.stmts(it.stmts)
g.writeln('}') g.writeln('}')
} }
@ -467,7 +467,7 @@ fn (g mut Gen) for_in(it ast.ForInStmt) {
g.write('for (int $i = 0; $i < ') g.write('for (int $i = 0; $i < ')
g.expr(it.cond) g.expr(it.cond)
g.writeln('.len; $i++) {') g.writeln('.len; $i++) {')
g.write('$styp $it.val_var = (($styp*)') g.write('\t$styp $it.val_var = (($styp*)')
g.expr(it.cond) g.expr(it.cond)
g.writeln('.data)[$i];') g.writeln('.data)[$i];')
g.stmts(it.stmts) g.stmts(it.stmts)
@ -486,8 +486,8 @@ fn (g mut Gen) for_in(it ast.ForInStmt) {
g.expr(it.cond) g.expr(it.cond)
g.writeln(');') g.writeln(');')
g.writeln('for (int $idx = 0; $idx < ${keys_tmp}.len; $idx++) {') g.writeln('for (int $idx = 0; $idx < ${keys_tmp}.len; $idx++) {')
g.writeln('$key_styp $key = (($key_styp*)${keys_tmp}.data)[$idx];') g.writeln('\t$key_styp $key = (($key_styp*)${keys_tmp}.data)[$idx];')
g.write('$val_styp $it.val_var = (*($val_styp*)map_get3(') g.write('\t$val_styp $it.val_var = (*($val_styp*)map_get3(')
g.expr(it.cond) g.expr(it.cond)
g.writeln(', $key, &($val_styp[]){ $zero }));') g.writeln(', $key, &($val_styp[]){ $zero }));')
g.stmts(it.stmts) g.stmts(it.stmts)
@ -641,36 +641,28 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
} }
} }
else { else {
mut is_fixed_array_init := false
mut is_ident := false
right_sym := g.table.get_type_symbol(assign_stmt.right_types[i]) right_sym := g.table.get_type_symbol(assign_stmt.right_types[i])
mut is_fixed_array_init := false
match val { match val {
ast.ArrayInit { ast.ArrayInit {
is_fixed_array_init = right_sym.kind == .array_fixed is_fixed_array_init = right_sym.kind == .array_fixed
} }
ast.Ident {
is_ident = true
}
else {} else {}
} }
is_decl := assign_stmt.op == .decl_assign is_decl := assign_stmt.op == .decl_assign
g.write('/*assign_stmt*/')
if is_decl { if is_decl {
g.write('$styp ') g.write('$styp ')
} }
g.expr(ident) g.expr(ident)
if g.autofree && right_sym.kind == .array && is_ident { if g.autofree && right_sym.kind in [.array, .string] {
// `arr1 = arr2` => `arr1 = arr2.clone()` if g.gen_clone_assignment(val, right_sym, true) {
g.write(' = array_clone(&') g.writeln(';')
g.expr(val) // g.expr_var_name = ''
g.write(')') return
} }
else if g.autofree && right_sym.kind == .string && is_ident {
// `str1 = str2` => `str1 = str2.clone()`
g.write(' = string_clone(')
g.expr(val)
g.write(')')
} }
else if !is_fixed_array_init { if !is_fixed_array_init {
g.write(' = ') g.write(' = ')
if !is_decl { if !is_decl {
g.expr_with_cast(val, assign_stmt.left_types[i], ident_var_info.typ) g.expr_with_cast(val, assign_stmt.left_types[i], ident_var_info.typ)
@ -692,6 +684,40 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
} }
} }
fn (g mut Gen) gen_clone_assignment(val ast.Expr, right_sym table.TypeSymbol, add_eq bool) bool {
mut is_ident := false
match val {
ast.Ident {
is_ident = true
}
ast.SelectorExpr {
is_ident = true
}
else {
return false
}
}
if g.autofree && right_sym.kind == .array && is_ident {
// `arr1 = arr2` => `arr1 = arr2.clone()`
if add_eq {
g.write('=')
}
g.write(' array_clone(&')
g.expr(val)
g.write(')')
}
else if g.autofree && right_sym.kind == .string && is_ident {
if add_eq {
g.write('=')
}
// `str1 = str2` => `str1 = str2.clone()`
g.write(' string_clone(')
g.expr(val)
g.write(')')
}
return true
}
fn (g mut Gen) gen_fn_decl(it ast.FnDecl) { fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
if it.is_c { if it.is_c {
// || it.no_body { // || it.no_body {
@ -1173,7 +1199,18 @@ fn (g mut Gen) assign_expr(node ast.AssignExpr) {
g.write(', ') g.write(', ')
} }
g.is_assign_lhs = false g.is_assign_lhs = false
right_sym := g.table.get_type_symbol(node.right_type)
// left_sym := g.table.get_type_symbol(node.left_type)
mut cloned := false
// !g.is_array_set
if g.autofree && right_sym.kind in [.array, .string] {
if g.gen_clone_assignment(node.val, right_sym, false) {
cloned = true
}
}
if !cloned {
g.expr_with_cast(node.val, node.right_type, node.left_type) g.expr_with_cast(node.val, node.right_type, node.left_type)
}
if g.is_array_set { if g.is_array_set {
g.write(' })') g.write(' })')
g.is_array_set = false g.is_array_set = false
@ -1397,7 +1434,7 @@ fn (g mut Gen) match_expr(node ast.MatchExpr) {
ast.Type { ast.Type {
it_type := g.typ(it.typ) it_type := g.typ(it.typ)
// g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it') // g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it')
g.write('$it_type* it = ($it_type*)') g.write('\t$it_type* it = ($it_type*)')
g.expr(node.cond) g.expr(node.cond)
g.writeln('.obj; // ST it') g.writeln('.obj; // ST it')
} }
@ -2194,6 +2231,17 @@ fn (g mut Gen) call_expr(node ast.CallExpr) {
g.write('$styp $tmp_opt = ') g.write('$styp $tmp_opt = ')
} }
if node.is_method { if node.is_method {
g.method_call(node)
}
else {
g.fn_call(node)
}
if gen_or {
g.or_block(tmp_opt, node.or_block.stmts, node.return_type)
}
}
fn (g mut Gen) method_call(node ast.CallExpr) {
// TODO: there are still due to unchecked exprs (opt/some fn arg) // TODO: there are still due to unchecked exprs (opt/some fn arg)
if node.left_type == 0 { if node.left_type == 0 {
verror('method receiver type is 0, this means there are some uchecked exprs') verror('method receiver type is 0, this means there are some uchecked exprs')
@ -2253,8 +2301,12 @@ fn (g mut Gen) call_expr(node ast.CallExpr) {
// /////// // ///////
g.call_args(node.args, node.exp_arg_types) g.call_args(node.args, node.exp_arg_types)
g.write(')') g.write(')')
// if node.or_block.stmts.len > 0 {
// g.or_block(node.or_block.stmts, node.return_type)
// }
} }
else {
fn (g mut Gen) fn_call(node ast.CallExpr) {
mut name := node.name mut name := node.name
is_print := name == 'println' is_print := name == 'println'
if node.is_c { if node.is_c {
@ -2311,12 +2363,11 @@ fn (g mut Gen) call_expr(node ast.CallExpr) {
g.call_args(node.args, node.exp_arg_types) g.call_args(node.args, node.exp_arg_types)
g.write(')') g.write(')')
} }
// if node.or_block.stmts.len > 0 {
// g.or_block(node.or_block.stmts, node.return_type)
// }
g.is_c_call = false g.is_c_call = false
} }
if gen_or {
g.or_block(tmp_opt, node.or_block.stmts, node.return_type)
}
}
// If user is accessing the return value eg. in assigment, pass the variable name. // If user is accessing the return value eg. in assigment, pass the variable name.
// If the user is not using the optional return value. We need to pass a temp var // If the user is not using the optional return value. We need to pass a temp var

View File

@ -26,7 +26,7 @@ fn (p mut Parser) comp_if() ast.CompIf {
// `$if os {` for a different target, skip everything inside // `$if os {` for a different target, skip everything inside
// to avoid compilation errors (like including <windows.h> or calling WinAPI fns // to avoid compilation errors (like including <windows.h> or calling WinAPI fns
// on non-Windows systems) // on non-Windows systems)
if ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) && !p.pref.output_cross_c { if false && ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) && !p.pref.output_cross_c {
skip_os = true skip_os = true
p.check(.lcbr) p.check(.lcbr)
// p.warn('skipping $if $val os=$os p.pref.os=$p.pref.os') // p.warn('skipping $if $val os=$os p.pref.os=$p.pref.os')

View File

@ -70,9 +70,10 @@ pub fn (p mut Parser) parse_multi_return_type() table.Type {
pub fn (p mut Parser) parse_fn_type(name string) table.Type { pub fn (p mut Parser) parse_fn_type(name string) table.Type {
// p.warn('parse fn') // p.warn('parse fn')
p.check(.key_fn) p.check(.key_fn)
line_nr := p.tok.line_nr
args,is_variadic := p.fn_args() args,is_variadic := p.fn_args()
mut return_type := table.void_type mut return_type := table.void_type
if p.tok.kind.is_start_of_type() { if p.tok.line_nr == line_nr && p.tok.kind.is_start_of_type() {
return_type = p.parse_type() return_type = p.parse_type()
} }
func := table.Fn{ func := table.Fn{

View File

@ -1520,6 +1520,13 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
field_name := p.check_name() field_name := p.check_name()
// p.warn('field $field_name') // p.warn('field $field_name')
typ := p.parse_type() typ := p.parse_type()
/*
if name == '_net_module_s' {
s := p.table.get_type_symbol(typ)
println('XXXX' + s.str())
}
*/
// Default value // Default value
if p.tok.kind == .assign { if p.tok.kind == .assign {
p.next() p.next()