mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
gen: implement a [manualfree]
tag, for functions, that want to do their own memory management
This commit is contained in:
parent
06bcd404b0
commit
083dc23db8
@ -7,6 +7,7 @@
|
||||
- `byte.str()` has been fixed and works like with all other numbers. `byte.ascii_str()` has been added.
|
||||
- Smart cast in for loops: `for mut x is string {}`.
|
||||
- `[noinit]` struct attribute to disallow direct struct initialization with `Foo{}`.
|
||||
- `[manualfree]` attribute for functions, that want to do their own memory management.
|
||||
|
||||
## V 0.2.1
|
||||
*30 Dec 2020*
|
||||
|
@ -67,3 +67,10 @@ These build flags are enabled on `build` and `run` as long as the backend is set
|
||||
|
||||
-keepc
|
||||
Do not remove the temporary .tmp.c and .tmp.c.rsp files. Also do not use a random prefix for them, so they would be fixed and predictable.
|
||||
|
||||
-autofree
|
||||
Free memory used in functions automatically.
|
||||
|
||||
-manualfree
|
||||
Do not free memory used in functions (the developer has to put x.free() and unsafe{free(x)} calls manually in this mode).
|
||||
Some short lived applications, like compilers and other CLI tools are more performant without autofree.
|
||||
|
@ -2517,7 +2517,8 @@ Python, Go, or Java, except there's no heavy GC tracing everything or expensive
|
||||
each object.
|
||||
|
||||
For developers willing to have more low level control, autofree can be disabled with
|
||||
`-noautofree`.
|
||||
`-manualfree`, or by adding a `[manualfree]` on each function that wants manage its
|
||||
memory manually.
|
||||
|
||||
Note: right now autofree is hidden behind the -autofree flag. It will be enabled by
|
||||
default in V 0.3.
|
||||
|
@ -296,6 +296,7 @@ pub:
|
||||
is_pub bool
|
||||
is_variadic bool
|
||||
is_anon bool
|
||||
is_manualfree bool // true, when [manualfree] is used on a fn
|
||||
receiver Field
|
||||
receiver_pos token.Position // `(u User)` in `fn (u User) name()` position
|
||||
is_method bool
|
||||
|
@ -3,7 +3,6 @@
|
||||
module gen
|
||||
|
||||
import v.table
|
||||
import v.pref
|
||||
import v.util
|
||||
|
||||
fn (mut g Gen) gen_str_default(sym table.TypeSymbol, styp string, str_fn_name string) {
|
||||
@ -230,7 +229,7 @@ fn (mut g Gen) gen_str_for_array(info table.Array, styp string, str_fn_name stri
|
||||
}
|
||||
}
|
||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write(&sb, x);')
|
||||
if g.pref.autofree && typ != table.bool_type {
|
||||
if g.is_autofree && typ != table.bool_type {
|
||||
// no need to free "true"/"false" literals
|
||||
g.auto_str_funcs.writeln('\t\tstring_free(&x);')
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ mut:
|
||||
stmt_path_pos []int // positions of each statement start, for inserting C statements before the current statement
|
||||
skip_stmt_pos bool // for handling if expressions + autofree (since both prepend C statements)
|
||||
right_is_opt bool
|
||||
autofree bool
|
||||
is_autofree bool // false, inside the bodies of fns marked with [manualfree], otherwise === g.pref.autofree
|
||||
indent int
|
||||
empty_line bool
|
||||
is_test bool
|
||||
@ -186,7 +186,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||
table: table
|
||||
pref: pref
|
||||
fn_decl: 0
|
||||
autofree: true
|
||||
is_autofree: true
|
||||
indent: -1
|
||||
module_built: module_built
|
||||
timers: util.new_timers(timers_should_print)
|
||||
@ -216,9 +216,9 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||
if g.file.path == '' || !g.pref.autofree {
|
||||
// cgen test or building V
|
||||
// println('autofree=false')
|
||||
g.autofree = false
|
||||
g.is_autofree = false
|
||||
} else {
|
||||
g.autofree = true
|
||||
g.is_autofree = true
|
||||
autofree_used = true
|
||||
}
|
||||
// anon fn may include assert and thus this needs
|
||||
@ -232,7 +232,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
|
||||
}
|
||||
g.timers.start('cgen common')
|
||||
if autofree_used {
|
||||
g.autofree = true // so that void _vcleanup is generated
|
||||
g.is_autofree = true // so that void _vcleanup is generated
|
||||
}
|
||||
// to make sure type idx's are the same in cached mods
|
||||
if g.pref.build_mode == .build_module {
|
||||
@ -799,7 +799,7 @@ fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) {
|
||||
g.write('')
|
||||
g.write(')')
|
||||
}
|
||||
if g.pref.autofree && !g.inside_vweb_tmpl && stmts.len > 0 {
|
||||
if g.is_autofree && !g.inside_vweb_tmpl && stmts.len > 0 {
|
||||
// use the first stmt to get the scope
|
||||
stmt := stmts[0]
|
||||
// stmt := stmts[stmts.len-1]
|
||||
@ -878,7 +878,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
}
|
||||
} else {
|
||||
// continue or break
|
||||
if g.pref.autofree && !g.is_builtin_mod {
|
||||
if g.is_autofree && !g.is_builtin_mod {
|
||||
g.writeln('// free before continue/break')
|
||||
g.autofree_scope_vars_stop(node.pos.pos - 1, node.pos.line_nr, true,
|
||||
g.branch_parent_pos)
|
||||
@ -935,7 +935,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
}
|
||||
ast.ExprStmt {
|
||||
g.write_v_source_line_info(node.pos)
|
||||
// af := g.pref.autofree && node.expr is ast.CallExpr && !g.is_builtin_mod
|
||||
// af := g.autofree && node.expr is ast.CallExpr && !g.is_builtin_mod
|
||||
// if af {
|
||||
// g.autofree_call_pregen(node.expr as ast.CallExpr)
|
||||
// }
|
||||
@ -1129,9 +1129,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
}
|
||||
ast.Return {
|
||||
g.write_defer_stmts_when_needed()
|
||||
// af := g.pref.autofree && node.exprs.len > 0 && node.exprs[0] is ast.CallExpr && !g.is_builtin_mod
|
||||
// af := g.autofree && node.exprs.len > 0 && node.exprs[0] is ast.CallExpr && !g.is_builtin_mod
|
||||
/*
|
||||
af := g.pref.autofree && !g.is_builtin_mod
|
||||
af := g.autofree && !g.is_builtin_mod
|
||||
if false && af {
|
||||
g.writeln('// ast.Return free')
|
||||
g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
|
||||
@ -1172,7 +1172,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
}
|
||||
// If we have temporary string exprs to free after this statement, do it. e.g.:
|
||||
// `foo('a' + 'b')` => `tmp := 'a' + 'b'; foo(tmp); string_free(&tmp);`
|
||||
if g.pref.autofree {
|
||||
if g.is_autofree {
|
||||
// if node is ast.ExprStmt {&& node.expr is ast.CallExpr {
|
||||
if node !is ast.FnDecl {
|
||||
// p := node.position()
|
||||
@ -1584,7 +1584,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||
}
|
||||
// Free the old value assigned to this string var (only if it's `str = [new value]`
|
||||
// or `x.str = [new value]` )
|
||||
mut af := g.pref.autofree && !g.is_builtin_mod && assign_stmt.op == .assign && assign_stmt.left_types.len ==
|
||||
mut af := g.is_autofree && !g.is_builtin_mod && assign_stmt.op == .assign && assign_stmt.left_types.len ==
|
||||
1 &&
|
||||
(assign_stmt.left[0] is ast.Ident || assign_stmt.left[0] is ast.SelectorExpr)
|
||||
// assign_stmt.left_types[0] in [table.string_type, table.array_type] &&
|
||||
@ -1623,7 +1623,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||
}
|
||||
// Autofree tmp arg vars
|
||||
// first_right := assign_stmt.right[0]
|
||||
// af := g.pref.autofree && first_right is ast.CallExpr && !g.is_builtin_mod
|
||||
// af := g.autofree && first_right is ast.CallExpr && !g.is_builtin_mod
|
||||
// if af {
|
||||
// g.autofree_call_pregen(first_right as ast.CallExpr)
|
||||
// }
|
||||
@ -1641,7 +1641,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||
// }
|
||||
// int pos = *(int*)_t190.data;
|
||||
mut tmp_opt := ''
|
||||
is_optional := g.pref.autofree &&
|
||||
is_optional := g.is_autofree &&
|
||||
(assign_stmt.op in [.decl_assign, .assign]) && assign_stmt.left_types.len == 1 && assign_stmt.right[0] is
|
||||
ast.CallExpr
|
||||
if is_optional {
|
||||
@ -1727,7 +1727,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||
if left.left_type.is_ptr() {
|
||||
g.write('*')
|
||||
}
|
||||
needs_clone := info.elem_type == table.string_type && g.pref.autofree
|
||||
needs_clone := info.elem_type == table.string_type && g.is_autofree
|
||||
if needs_clone {
|
||||
g.write('/*1*/string_clone(')
|
||||
}
|
||||
@ -1969,7 +1969,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||
g.write(', ')
|
||||
}
|
||||
mut cloned := false
|
||||
if g.autofree && right_sym.kind in [.array, .string] {
|
||||
if g.is_autofree && right_sym.kind in [.array, .string] {
|
||||
if g.gen_clone_assignment(val, right_sym, false) {
|
||||
cloned = true
|
||||
}
|
||||
@ -1980,7 +1980,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||
// `pos := s.index(...
|
||||
// `int pos = *(int)_t10.data;`
|
||||
g.write('*($styp*)')
|
||||
if g.pref.autofree {
|
||||
if g.is_autofree {
|
||||
g.write(tmp_opt + '.data/*FFz*/')
|
||||
g.right_is_opt = false
|
||||
g.is_assign_rhs = false
|
||||
@ -2037,7 +2037,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||
}
|
||||
}
|
||||
if unwrap_optional {
|
||||
if g.pref.autofree {
|
||||
if g.is_autofree {
|
||||
// g.write(tmp_opt + '/*FF*/')
|
||||
} else {
|
||||
g.write('.data')
|
||||
@ -2150,7 +2150,7 @@ fn (mut g Gen) gen_clone_assignment(val ast.Expr, right_sym table.TypeSymbol, ad
|
||||
if val !is ast.Ident && val !is ast.SelectorExpr {
|
||||
return false
|
||||
}
|
||||
if g.autofree && right_sym.kind == .array {
|
||||
if g.is_autofree && right_sym.kind == .array {
|
||||
// `arr1 = arr2` => `arr1 = arr2.clone()`
|
||||
if add_eq {
|
||||
g.write('=')
|
||||
@ -2158,7 +2158,7 @@ fn (mut g Gen) gen_clone_assignment(val ast.Expr, right_sym table.TypeSymbol, ad
|
||||
g.write(' array_clone_static(')
|
||||
g.expr(val)
|
||||
g.write(')')
|
||||
} else if g.autofree && right_sym.kind == .string {
|
||||
} else if g.is_autofree && right_sym.kind == .string {
|
||||
if add_eq {
|
||||
g.write('=')
|
||||
}
|
||||
@ -2407,8 +2407,8 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||
// if g.fileis('1.strings') {
|
||||
// println('before:' + node.autofree_pregen)
|
||||
// }
|
||||
if g.pref.autofree && !g.is_builtin_mod && !g.is_js_call && g.strs_to_free0.len ==
|
||||
0 && !g.inside_lambda { // && g.inside_ternary ==
|
||||
if g.is_autofree && !g.is_builtin_mod && !g.is_js_call && g.strs_to_free0.len == 0 &&
|
||||
!g.inside_lambda { // && g.inside_ternary ==
|
||||
// if len != 0, that means we are handling call expr inside call expr (arg)
|
||||
// and it'll get messed up here, since it's handled recursively in autofree_call_pregen()
|
||||
// so just skip it
|
||||
@ -2419,9 +2419,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||
g.strs_to_free0 = []
|
||||
// println('pos=$node.pos.pos')
|
||||
}
|
||||
// if g.pref.autofree && node.autofree_pregen != '' { // g.strs_to_free0.len != 0 {
|
||||
// if g.autofree && node.autofree_pregen != '' { // g.strs_to_free0.len != 0 {
|
||||
/*
|
||||
if g.pref.autofree {
|
||||
if g.autofree {
|
||||
s := g.autofree_pregen[node.pos.pos.str()]
|
||||
if s != '' {
|
||||
// g.insert_before_stmt('/*START2*/' + g.strs_to_free0.join('\n') + '/*END*/')
|
||||
@ -3167,7 +3167,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||
if elem_sym.kind == .interface_ && node.right_type != info.elem_type {
|
||||
g.interface_call(node.right_type, info.elem_type)
|
||||
}
|
||||
// if g.pref.autofree
|
||||
// if g.autofree
|
||||
needs_clone := info.elem_type == table.string_type && !g.is_builtin_mod
|
||||
if needs_clone {
|
||||
g.write('string_clone(')
|
||||
@ -3713,12 +3713,12 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||
// Always use this in -autofree, since ?: can have tmp expressions that have to be freed.
|
||||
first_branch := node.branches[0]
|
||||
needs_tmp_var := node.is_expr &&
|
||||
(g.pref.autofree || (g.pref.experimental &&
|
||||
(g.is_autofree || (g.pref.experimental &&
|
||||
(first_branch.stmts.len > 1 || (first_branch.stmts[0] is ast.ExprStmt &&
|
||||
(first_branch.stmts[0] as ast.ExprStmt).expr is ast.IfExpr))))
|
||||
/*
|
||||
needs_tmp_var := node.is_expr &&
|
||||
(g.pref.autofree || g.pref.experimental) &&
|
||||
(g.autofree || g.pref.experimental) &&
|
||||
(node.branches[0].stmts.len > 1 || node.branches[0].stmts[0] is ast.IfExpr)
|
||||
*/
|
||||
tmp := if needs_tmp_var { g.new_tmp_var() } else { '' }
|
||||
@ -3957,7 +3957,7 @@ fn (mut g Gen) index_expr(node ast.IndexExpr) {
|
||||
.function { 'voidptr*' }
|
||||
else { '$elem_type_str*' }
|
||||
}
|
||||
needs_clone := info.elem_type == table.string_type_idx && g.pref.autofree &&
|
||||
needs_clone := info.elem_type == table.string_type_idx && g.is_autofree &&
|
||||
!g.is_assign_lhs
|
||||
if needs_clone {
|
||||
g.write('/*2*/string_clone(')
|
||||
@ -4141,7 +4141,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||
g.writeln('$styp $tmp = {.ok = true};')
|
||||
g.writeln('return $tmp;')
|
||||
} else {
|
||||
if g.pref.autofree && !g.is_builtin_mod {
|
||||
if g.is_autofree && !g.is_builtin_mod {
|
||||
g.writeln('// free before return (no values returned)')
|
||||
g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
|
||||
}
|
||||
@ -4275,7 +4275,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
|
||||
g.writeln('return $opt_tmp;')
|
||||
return
|
||||
}
|
||||
free := g.pref.autofree && !g.is_builtin_mod // node.exprs[0] is ast.CallExpr
|
||||
free := g.is_autofree && !g.is_builtin_mod // node.exprs[0] is ast.CallExpr
|
||||
mut tmp := ''
|
||||
if free {
|
||||
// `return foo(a, b, c)`
|
||||
@ -4404,7 +4404,7 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, val string, typ ta
|
||||
cname := '_const_$name'
|
||||
g.definitions.writeln('$styp $cname; // inited later')
|
||||
g.inits[mod].writeln('\t$cname = $val;')
|
||||
if g.pref.autofree {
|
||||
if g.is_autofree {
|
||||
if styp.starts_with('array_') {
|
||||
g.cleanups[mod].writeln('\tarray_free(&$cname);')
|
||||
}
|
||||
@ -4491,7 +4491,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
||||
}
|
||||
field_type_sym := g.table.get_type_symbol(field.typ)
|
||||
mut cloned := false
|
||||
if g.autofree && !field.typ.is_ptr() && field_type_sym.kind in [.array, .string] {
|
||||
if g.is_autofree && !field.typ.is_ptr() && field_type_sym.kind in [.array, .string] {
|
||||
g.write('/*clone1*/')
|
||||
if g.gen_clone_assignment(field.expr, field_type_sym, false) {
|
||||
cloned = true
|
||||
@ -4560,7 +4560,7 @@ fn (mut g Gen) struct_init(struct_init ast.StructInit) {
|
||||
mut cloned := false
|
||||
is_interface := expected_field_type_sym.kind == .interface_ &&
|
||||
field_type_sym.kind != .interface_
|
||||
if g.autofree && !sfield.typ.is_ptr() && field_type_sym.kind in [.array, .string] {
|
||||
if g.is_autofree && !sfield.typ.is_ptr() && field_type_sym.kind in [.array, .string] {
|
||||
g.write('/*clone1*/')
|
||||
if g.gen_clone_assignment(sfield.expr, field_type_sym, false) {
|
||||
cloned = true
|
||||
@ -4705,7 +4705,7 @@ fn (mut g Gen) write_init_function() {
|
||||
} else {
|
||||
g.writeln('void _vinit() {')
|
||||
}
|
||||
if g.pref.autofree {
|
||||
if g.is_autofree {
|
||||
// Pre-allocate the string buffer
|
||||
// s_str_buf_size := os.getenv('V_STRBUF_MB')
|
||||
// mb_size := if s_str_buf_size == '' { 1 } else { s_str_buf_size.int() }
|
||||
@ -4735,7 +4735,7 @@ fn (mut g Gen) write_init_function() {
|
||||
if g.pref.printfn_list.len > 0 && '_vinit' in g.pref.printfn_list {
|
||||
println(g.out.after(fn_vinit_start_pos))
|
||||
}
|
||||
if g.autofree {
|
||||
if g.is_autofree {
|
||||
fn_vcleanup_start_pos := g.out.len
|
||||
g.writeln('void _vcleanup() {')
|
||||
// g.writeln('puts("cleaning up...");')
|
||||
|
@ -75,7 +75,7 @@ fn (mut g Gen) gen_c_main_header() {
|
||||
g.writeln('')
|
||||
}
|
||||
if g.is_importing_os() {
|
||||
if g.autofree {
|
||||
if g.is_autofree {
|
||||
g.writeln('free(_const_os__args.data); // empty, inited in _vinit()')
|
||||
}
|
||||
if g.pref.os == .windows {
|
||||
@ -90,7 +90,7 @@ fn (mut g Gen) gen_c_main_header() {
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) gen_c_main_footer() {
|
||||
if g.autofree {
|
||||
if g.is_autofree {
|
||||
g.writeln('\t_vcleanup();')
|
||||
}
|
||||
g.writeln('\treturn 0;')
|
||||
@ -99,7 +99,7 @@ pub fn (mut g Gen) gen_c_main_footer() {
|
||||
|
||||
pub fn (mut g Gen) gen_c_android_sokol_main() {
|
||||
// Weave autofree into sokol lifecycle callback(s)
|
||||
if g.autofree {
|
||||
if g.is_autofree {
|
||||
g.writeln('// Wrapping cleanup/free callbacks for sokol to include _vcleanup()
|
||||
void (*_vsokol_user_cleanup_ptr)(void);
|
||||
void (*_vsokol_user_cleanup_cb_ptr)(void *);
|
||||
@ -126,7 +126,7 @@ sapp_desc sokol_main(int argc, char* argv[]) {
|
||||
_vinit();
|
||||
main__main();
|
||||
')
|
||||
if g.autofree {
|
||||
if g.is_autofree {
|
||||
g.writeln(' // Wrap user provided cleanup/free functions for sokol to be able to call _vcleanup()
|
||||
if (g_desc.cleanup_cb) {
|
||||
_vsokol_user_cleanup_ptr = g_desc.cleanup_cb;
|
||||
@ -170,7 +170,7 @@ pub fn (mut g Gen) write_tests_main() {
|
||||
g.writeln('\tmain__BenchedTests_end_testing(&bt);')
|
||||
}
|
||||
g.writeln('')
|
||||
if g.autofree {
|
||||
if g.is_autofree {
|
||||
g.writeln('\t_vcleanup();')
|
||||
}
|
||||
g.writeln('\treturn g_test_fails > 0;')
|
||||
|
@ -16,6 +16,15 @@ fn (mut g Gen) gen_fn_decl(it ast.FnDecl, skip bool) {
|
||||
return
|
||||
}
|
||||
g.returned_var_name = ''
|
||||
//
|
||||
old_g_autofree := g.is_autofree
|
||||
if it.is_manualfree {
|
||||
g.is_autofree = false
|
||||
}
|
||||
defer {
|
||||
g.is_autofree = old_g_autofree
|
||||
}
|
||||
//
|
||||
// if g.fileis('vweb.v') {
|
||||
// println('\ngen_fn_decl() $it.name $it.is_generic $g.cur_generic_type')
|
||||
// }
|
||||
@ -263,12 +272,12 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||
defer {
|
||||
g.inside_call = false
|
||||
}
|
||||
gen_or := node.or_block.kind != .absent && !g.pref.autofree
|
||||
gen_or := node.or_block.kind != .absent && !g.is_autofree
|
||||
// if gen_or {
|
||||
// g.writeln('/*start*/')
|
||||
// }
|
||||
is_gen_or_and_assign_rhs := gen_or && g.is_assign_rhs
|
||||
cur_line := if is_gen_or_and_assign_rhs && !g.pref.autofree {
|
||||
cur_line := if is_gen_or_and_assign_rhs && !g.is_autofree {
|
||||
line := g.go_before_stmt(0)
|
||||
g.out.write(tabs[g.indent])
|
||||
line
|
||||
@ -290,8 +299,8 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||
} else {
|
||||
g.fn_call(node)
|
||||
}
|
||||
if gen_or { // && !g.pref.autofree {
|
||||
if !g.pref.autofree {
|
||||
if gen_or { // && !g.autofree {
|
||||
if !g.is_autofree {
|
||||
g.or_block(tmp_opt, node.or_block, node.return_type)
|
||||
}
|
||||
if is_gen_or_and_assign_rhs {
|
||||
@ -557,7 +566,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||
tmp2 = g.new_tmp_var()
|
||||
g.writeln('Option_$typ $tmp2 = $fn_name ($json_obj);')
|
||||
}
|
||||
if !g.pref.autofree {
|
||||
if !g.is_autofree {
|
||||
g.write('cJSON_Delete($json_obj); //del')
|
||||
}
|
||||
g.write('\n$cur_line')
|
||||
@ -594,7 +603,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||
// check if alias parent also not a string
|
||||
if typ != table.string_type {
|
||||
expr := node.args[0].expr
|
||||
if g.autofree && !typ.has_flag(.optional) {
|
||||
if g.is_autofree && !typ.has_flag(.optional) {
|
||||
// Create a temporary variable so that the value can be freed
|
||||
tmp := g.new_tmp_var()
|
||||
// tmps << tmp
|
||||
@ -640,7 +649,7 @@ fn (mut g Gen) autofree_call_pregen(node ast.CallExpr) {
|
||||
// g.writeln('// autofree_call_pregen()')
|
||||
// Create a temporary var before fn call for each argument in order to free it (only if it's a complex expression,
|
||||
// like `foo(get_string())` or `foo(a + b)`
|
||||
mut free_tmp_arg_vars := g.autofree && !g.is_builtin_mod && node.args.len > 0 && !node.args[0].typ.has_flag(.optional) // TODO copy pasta checker.v
|
||||
mut free_tmp_arg_vars := g.is_autofree && !g.is_builtin_mod && node.args.len > 0 && !node.args[0].typ.has_flag(.optional) // TODO copy pasta checker.v
|
||||
if !free_tmp_arg_vars {
|
||||
return
|
||||
}
|
||||
@ -775,7 +784,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
||||
if is_variadic && i == expected_types.len - 1 {
|
||||
break
|
||||
}
|
||||
use_tmp_var_autofree := g.autofree && arg.typ == table.string_type && arg.is_tmp_autofree &&
|
||||
use_tmp_var_autofree := g.is_autofree && arg.typ == table.string_type && arg.is_tmp_autofree &&
|
||||
!g.inside_const && !g.is_builtin_mod
|
||||
// g.write('/* af=$arg.is_tmp_autofree */')
|
||||
mut is_interface := false
|
||||
|
@ -156,6 +156,7 @@ pub fn (mut p Parser) call_args() []ast.CallArg {
|
||||
fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
p.top_level_statement_start()
|
||||
start_pos := p.tok.position()
|
||||
is_manualfree := p.attrs.contains('manualfree')
|
||||
is_deprecated := p.attrs.contains('deprecated')
|
||||
is_direct_arr := p.attrs.contains('direct_array_access')
|
||||
mut is_unsafe := p.attrs.contains('unsafe')
|
||||
@ -395,6 +396,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
stmts: stmts
|
||||
return_type: return_type
|
||||
params: params
|
||||
is_manualfree: is_manualfree
|
||||
is_deprecated: is_deprecated
|
||||
is_direct_arr: is_direct_arr
|
||||
is_pub: is_pub
|
||||
|
@ -81,7 +81,6 @@ pub mut:
|
||||
use_cache bool // = true
|
||||
retry_compilation bool = true
|
||||
is_stats bool // `v -stats file_test.v` will produce more detailed statistics for the tests that were run
|
||||
no_auto_free bool // `v -nofree` disable automatic `free()` insertion for better performance in some applications (e.g. compilers)
|
||||
// TODO Convert this into a []string
|
||||
cflags string // Additional options which will be passed to the C compiler.
|
||||
// For example, passing -cflags -Os will cause the C compiler to optimize the generated binaries for size.
|
||||
@ -92,7 +91,8 @@ pub mut:
|
||||
ccompiler_type CompilerType // the type of the C compiler used
|
||||
third_party_option string
|
||||
building_v bool
|
||||
autofree bool
|
||||
autofree bool // `v -manualfree` => false, `v -autofree` => true; false by default for now.
|
||||
// Disabling `free()` insertion results in better performance in some applications (e.g. compilers)
|
||||
compress bool
|
||||
// skip_builtin bool // Skips re-compilation of the builtin module
|
||||
// to increase compilation time.
|
||||
@ -213,6 +213,10 @@ pub fn parse_args(args []string) (&Preferences, string) {
|
||||
res.autofree = true
|
||||
res.build_options << arg
|
||||
}
|
||||
'-manualfree' {
|
||||
res.autofree = false
|
||||
res.build_options << arg
|
||||
}
|
||||
'-compress' {
|
||||
res.compress = true
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user