cgen: store return vals in tmp vars with -autofree

pull/5604/head
Alexander Medvednikov 2020-07-01 14:34:14 +02:00
parent 92eea7f95a
commit 5eb76606ae
3 changed files with 48 additions and 29 deletions

View File

@ -103,6 +103,12 @@ pub fn mkdir(path string) ?bool {
if path == '.' { if path == '.' {
return true return true
} }
/*
mut k := 0
defer {
k = 1
}
*/
apath := os.real_path(path) apath := os.real_path(path)
/* /*
$if linux { $if linux {

View File

@ -394,16 +394,11 @@ fn (g &Gen) cc_type(t table.Type) string {
if info.generic_types.len > 0 { if info.generic_types.len > 0 {
mut sgtyps := '_T' mut sgtyps := '_T'
for gt in info.generic_types { for gt in info.generic_types {
gts := g.table.get_type_symbol(if gt.has_flag(.generic) { gts := g.table.get_type_symbol(if gt.has_flag(.generic) { g.unwrap_generic(gt) } else { gt })
g.unwrap_generic(gt)
} else {
gt
})
sgtyps += '_$gts.name' sgtyps += '_$gts.name'
} }
styp += sgtyps styp += sgtyps
} } else if styp.contains('<') {
else if styp.contains('<') {
// TODO: yuck // TODO: yuck
styp = styp.replace('<', '_T_').replace('>', '').replace(',', '_') styp = styp.replace('<', '_T_').replace('>', '').replace(',', '_')
} }
@ -772,7 +767,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
} }
ast.Return { ast.Return {
g.write_defer_stmts_when_needed() g.write_defer_stmts_when_needed()
g.write_autofree_stmts_when_needed(node) if g.pref.autofree {
g.write_autofree_stmts_when_needed(node)
}
g.return_statement(node) g.return_statement(node)
} }
ast.SqlStmt { ast.SqlStmt {
@ -1095,18 +1092,18 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
info := sym.info as table.Array info := sym.info as table.Array
styp := g.typ(info.elem_type) styp := g.typ(info.elem_type)
g.write('$styp _var_$left.pos.pos = *($styp*)array_get(') g.write('$styp _var_$left.pos.pos = *($styp*)array_get(')
g.expr(it.left) g.expr(left.left)
g.write(', ') g.write(', ')
g.expr(it.index) g.expr(left.index)
g.writeln(');') g.writeln(');')
} else if sym.kind == .map { } else if sym.kind == .map {
info := sym.info as table.Map info := sym.info as table.Map
styp := g.typ(info.value_type) styp := g.typ(info.value_type)
zero := g.type_default(info.value_type) zero := g.type_default(info.value_type)
g.write('$styp _var_$left.pos.pos = *($styp*)map_get(') g.write('$styp _var_$left.pos.pos = *($styp*)map_get(')
g.expr(it.left) g.expr(left.left)
g.write(', ') g.write(', ')
g.expr(it.index) g.expr(left.index)
g.writeln(', &($styp[]){ $zero });') g.writeln(', &($styp[]){ $zero });')
} }
} }
@ -2486,7 +2483,21 @@ fn (mut g Gen) return_statement(node ast.Return) {
g.writeln('return $opt_tmp;') g.writeln('return $opt_tmp;')
return return
} }
g.write('return ') free := g.pref.autofree && node.exprs[0] is ast.CallExpr
mut tmp := ''
if free {
// `return foo(a, b, c)`
// `tmp := foo(a, b, c); free(a); free(b); free(c); return tmp;`
// Save return value in a temp var so that it all args (a,b,c) can be freed
tmp = g.new_tmp_var()
g.write(g.typ(g.fn_decl.return_type))
g.write(' ')
g.write(tmp)
g.write(' = ')
// g.write('return $tmp;')
} else {
g.write('return ')
}
cast_interface := sym.kind == .interface_ && node.types[0] != g.fn_decl.return_type cast_interface := sym.kind == .interface_ && node.types[0] != g.fn_decl.return_type
if cast_interface { if cast_interface {
g.interface_call(node.types[0], g.fn_decl.return_type) g.interface_call(node.types[0], g.fn_decl.return_type)
@ -2495,6 +2506,10 @@ fn (mut g Gen) return_statement(node ast.Return) {
if cast_interface { if cast_interface {
g.write(')') g.write(')')
} }
if free {
g.writeln(';')
g.write('return $tmp')
}
} else { } else {
g.write('return') g.write('return')
} }
@ -2824,7 +2839,7 @@ fn (mut g Gen) write_init_function() {
g.writeln('void _vcleanup() {') g.writeln('void _vcleanup() {')
// g.writeln('puts("cleaning up...");') // g.writeln('puts("cleaning up...");')
g.writeln(g.cleanups.str()) g.writeln(g.cleanups.str())
//g.writeln('\tfree(g_str_buf);') // g.writeln('\tfree(g_str_buf);')
g.writeln('}') g.writeln('}')
if g.pref.printfn_list.len > 0 && '_vcleanup' in g.pref.printfn_list { if g.pref.printfn_list.len > 0 && '_vcleanup' in g.pref.printfn_list {
println(g.out.after(fn_vcleanup_start_pos)) println(g.out.after(fn_vcleanup_start_pos))

View File

@ -74,7 +74,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
} }
mut impl_fn_name := name mut impl_fn_name := name
if is_live_wrap { if is_live_wrap {
impl_fn_name = 'impl_live_${name}' impl_fn_name = 'impl_live_$name'
} }
g.last_fn_c_name = impl_fn_name g.last_fn_c_name = impl_fn_name
// //
@ -113,17 +113,16 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
// an early exit, which will leave the mutex locked. // an early exit, which will leave the mutex locked.
mut fn_args_list := []string{} mut fn_args_list := []string{}
for ia, fa in fargs { for ia, fa in fargs {
fn_args_list << '${fargtypes[ia]} ${fa}' fn_args_list << '${fargtypes[ia]} $fa'
} }
mut live_fncall := '${impl_fn_name}(' + fargs.join(', ') + ');' mut live_fncall := '${impl_fn_name}(' + fargs.join(', ') + ');'
mut live_fnreturn := '' mut live_fnreturn := ''
if type_name != 'void' { if type_name != 'void' {
live_fncall = '${type_name} res = ${live_fncall}' live_fncall = '$type_name res = $live_fncall'
live_fnreturn = 'return res;' live_fnreturn = 'return res;'
} }
g.definitions.writeln('$type_name ${name}(' + fn_args_list.join(', ') + ');') g.definitions.writeln('$type_name ${name}(' + fn_args_list.join(', ') + ');')
g.hotcode_definitions.writeln('$type_name ${name}(' + fn_args_list.join(', ') + g.hotcode_definitions.writeln('$type_name ${name}(' + fn_args_list.join(', ') + '){')
'){')
g.hotcode_definitions.writeln(' pthread_mutex_lock(&live_fn_mutex);') g.hotcode_definitions.writeln(' pthread_mutex_lock(&live_fn_mutex);')
g.hotcode_definitions.writeln(' $live_fncall') g.hotcode_definitions.writeln(' $live_fncall')
g.hotcode_definitions.writeln(' pthread_mutex_unlock(&live_fn_mutex);') g.hotcode_definitions.writeln(' pthread_mutex_unlock(&live_fn_mutex);')
@ -140,7 +139,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
// ///////// // /////////
if g.autofree { if g.autofree {
// TODO: remove this, when g.write_autofree_stmts_when_needed works properly // TODO: remove this, when g.write_autofree_stmts_when_needed works properly
g.writeln(g.autofree_scope_vars(it.body_pos.pos)) // g.writeln(g.autofree_scope_vars(it.body_pos.pos))
} }
g.writeln('}') g.writeln('}')
g.defer_stmts = [] g.defer_stmts = []
@ -154,12 +153,9 @@ fn (mut g Gen) write_autofree_stmts_when_needed(r ast.Return) {
// TODO: write_autofree_stmts_when_needed should not free the returned variables. // TODO: write_autofree_stmts_when_needed should not free the returned variables.
// It may require rewriting g.return_statement to assign the expressions // It may require rewriting g.return_statement to assign the expressions
// to temporary variables, then protecting *them* from autofreeing ... // to temporary variables, then protecting *them* from autofreeing ...
/* // g.writeln('// autofreeings before return: -------')
g.writeln('/* autofreeings before return: -------') // g.writeln(g.autofree_scope_vars(g.fn_decl.body_pos.pos))
//g.write( g.autofree_scope_vars(r.pos.pos) ) // g.writeln('//--------------------------------------------------- ') // //g.write( g.autofree_scope_vars(r.pos.pos) )
g.write( g.autofree_scope_vars(g.fn_decl.body_pos.pos) )
g.writeln('--------------------------------------------------- */')
*/
} }
fn (mut g Gen) write_defer_stmts_when_needed() { fn (mut g Gen) write_defer_stmts_when_needed() {
@ -248,7 +244,9 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
return return
} }
g.inside_call = true g.inside_call = true
defer {g.inside_call = false} defer {
g.inside_call = false
}
gen_or := node.or_block.kind != .absent gen_or := node.or_block.kind != .absent
cur_line := if gen_or && g.is_assign_rhs { cur_line := if gen_or && g.is_assign_rhs {
line := g.go_before_stmt(0) line := g.go_before_stmt(0)
@ -336,8 +334,8 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
g.gen_str_for_type_with_styp(node.receiver_type, styp) g.gen_str_for_type_with_styp(node.receiver_type, styp)
} }
// TODO performance, detect `array` method differently // TODO performance, detect `array` method differently
if left_sym.kind == .array && if left_sym.kind == .array && node.name in
node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last', 'clone', 'reverse', 'slice'] { ['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last', 'clone', 'reverse', 'slice'] {
// && rec_sym.name == 'array' { // && rec_sym.name == 'array' {
// && rec_sym.name == 'array' && receiver_name.starts_with('array') { // && rec_sym.name == 'array' && receiver_name.starts_with('array') {
// `array_byte_clone` => `array_clone` // `array_byte_clone` => `array_clone`