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 == '.' {
return true
}
/*
mut k := 0
defer {
k = 1
}
*/
apath := os.real_path(path)
/*
$if linux {

View File

@ -394,16 +394,11 @@ fn (g &Gen) cc_type(t table.Type) string {
if info.generic_types.len > 0 {
mut sgtyps := '_T'
for gt in info.generic_types {
gts := g.table.get_type_symbol(if gt.has_flag(.generic) {
g.unwrap_generic(gt)
} else {
gt
})
gts := g.table.get_type_symbol(if gt.has_flag(.generic) { g.unwrap_generic(gt) } else { gt })
sgtyps += '_$gts.name'
}
styp += sgtyps
}
else if styp.contains('<') {
} else if styp.contains('<') {
// TODO: yuck
styp = styp.replace('<', '_T_').replace('>', '').replace(',', '_')
}
@ -772,7 +767,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
}
ast.Return {
g.write_defer_stmts_when_needed()
if g.pref.autofree {
g.write_autofree_stmts_when_needed(node)
}
g.return_statement(node)
}
ast.SqlStmt {
@ -1095,18 +1092,18 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
info := sym.info as table.Array
styp := g.typ(info.elem_type)
g.write('$styp _var_$left.pos.pos = *($styp*)array_get(')
g.expr(it.left)
g.expr(left.left)
g.write(', ')
g.expr(it.index)
g.expr(left.index)
g.writeln(');')
} else if sym.kind == .map {
info := sym.info as table.Map
styp := g.typ(info.value_type)
zero := g.type_default(info.value_type)
g.write('$styp _var_$left.pos.pos = *($styp*)map_get(')
g.expr(it.left)
g.expr(left.left)
g.write(', ')
g.expr(it.index)
g.expr(left.index)
g.writeln(', &($styp[]){ $zero });')
}
}
@ -2486,7 +2483,21 @@ fn (mut g Gen) return_statement(node ast.Return) {
g.writeln('return $opt_tmp;')
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
if cast_interface {
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 {
g.write(')')
}
if free {
g.writeln(';')
g.write('return $tmp')
}
} else {
g.write('return')
}

View File

@ -74,7 +74,7 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl) {
}
mut impl_fn_name := name
if is_live_wrap {
impl_fn_name = 'impl_live_${name}'
impl_fn_name = 'impl_live_$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.
mut fn_args_list := []string{}
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_fnreturn := ''
if type_name != 'void' {
live_fncall = '${type_name} res = ${live_fncall}'
live_fncall = '$type_name res = $live_fncall'
live_fnreturn = 'return res;'
}
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(' $live_fncall')
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 {
// 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.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.
// It may require rewriting g.return_statement to assign the expressions
// to temporary variables, then protecting *them* from autofreeing ...
/*
g.writeln('/* autofreeings before return: -------')
//g.write( g.autofree_scope_vars(r.pos.pos) )
g.write( g.autofree_scope_vars(g.fn_decl.body_pos.pos) )
g.writeln('--------------------------------------------------- */')
*/
// g.writeln('// autofreeings before return: -------')
// g.writeln(g.autofree_scope_vars(g.fn_decl.body_pos.pos))
// g.writeln('//--------------------------------------------------- ') // //g.write( g.autofree_scope_vars(r.pos.pos) )
}
fn (mut g Gen) write_defer_stmts_when_needed() {
@ -248,7 +244,9 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
return
}
g.inside_call = true
defer {g.inside_call = false}
defer {
g.inside_call = false
}
gen_or := node.or_block.kind != .absent
cur_line := if gen_or && g.is_assign_rhs {
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)
}
// TODO performance, detect `array` method differently
if left_sym.kind == .array &&
node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last', 'clone', 'reverse', 'slice'] {
if left_sym.kind == .array && node.name in
['repeat', 'sort_with_compare', 'free', 'push_many', 'trim', 'first', 'last', 'clone', 'reverse', 'slice'] {
// && rec_sym.name == 'array' {
// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
// `array_byte_clone` => `array_clone`