diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index eea4f99582722a..2257890bfdfd27 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -10,22 +10,39 @@ import v.util @[heap; minify] pub struct UsedFeatures { pub mut: - interfaces bool // interface - dump bool // dump() - builtin_types bool // uses any builtin type - index bool // string[0] - range_index bool // string[0..1] - cast_ptr bool // &u8(...) - as_cast bool // expr as Type - anon_fn bool // fn () { } - auto_str bool // auto str fns - auto_str_ptr bool // auto str fns for ptr type - arr_prepend bool // arr.prepend() - arr_first bool // arr.first() - arr_last bool // arr.last() - arr_pop bool // arr.pop() - option_or_result bool // has panic call - print_types map[int]bool // print() idx types + interfaces bool // interface + dump bool // dump() + builtin_types bool // uses any builtin type + index bool // string[0] + range_index bool // string[0..1] + cast_ptr bool // &u8(...) + as_cast bool // expr as Type + anon_fn bool // fn () { } + auto_str bool // auto str fns + auto_str_ptr bool // auto str fns for ptr type + arr_prepend bool // arr.prepend() + arr_first bool // arr.first() + arr_last bool // arr.last() + arr_pop bool // arr.pop() + option_or_result bool // has panic call + print_types map[int]bool // print() idx types + used_fns map[string]bool // filled in by markused + used_consts map[string]bool // filled in by markused + used_globals map[string]bool // filled in by markused + used_veb_types []Type // veb context types, filled in by checker + used_maps int // how many times maps were used, filled in by markused + used_arrays int // how many times arrays were used, filled in by markused +} + +@[unsafe] +pub fn (mut uf UsedFeatures) free() { + unsafe { + uf.print_types.free() + uf.used_fns.free() + uf.used_consts.free() + uf.used_globals.free() + uf.used_veb_types.free() + } } @[heap; minify] @@ -48,14 +65,9 @@ pub mut: sumtypes map[int]SumTypeDecl cmod_prefix string // needed for ast.type_to_str(Type) while vfmt; contains `os.` is_fmt bool - used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true; - used_consts map[string]bool // filled in by the checker, when pref.skip_unused = true; - used_globals map[string]bool // filled in by the checker, when pref.skip_unused = true; - used_features UsedFeatures // filled in by the checker, when pref.skip_unused = true; - used_veb_types []Type // veb context types, filled in by checker, when pref.skip_unused = true; - veb_res_idx_cache int // Cache of `veb.Result` type - veb_ctx_idx_cache int // Cache of `veb.Context` type - used_maps int // how many times maps were used, filled in by checker, when pref.skip_unused = true; + used_features &UsedFeatures = &UsedFeatures{} // filled in by the checker/markused, when pref.skip_unused = true; + veb_res_idx_cache int // Cache of `veb.Result` type + veb_ctx_idx_cache int // Cache of `veb.Context` type panic_handler FnPanicHandler = default_table_panic_handler panic_userdata voidptr = unsafe { nil } // can be used to pass arbitrary data to panic_handler; panic_npanics int @@ -94,10 +106,7 @@ pub fn (mut t Table) free() { t.redefined_fns.free() t.fn_generic_types.free() t.cmod_prefix.free() - t.used_fns.free() - t.used_consts.free() - t.used_globals.free() - t.used_veb_types.free() + t.used_features.free() } } diff --git a/vlib/v/callgraph/callgraph.v b/vlib/v/callgraph/callgraph.v index 50c3f2e0d3dc99..d0bbfb98c3b782 100644 --- a/vlib/v/callgraph/callgraph.v +++ b/vlib/v/callgraph/callgraph.v @@ -94,7 +94,7 @@ fn (mut m Mapper) visit(node &ast.Node) ! { ast.FnDecl { m.is_caller_used = true if m.pref.skip_unused { - m.is_caller_used = m.table.used_fns[node.fkey()] + m.is_caller_used = m.table.used_features.used_fns[node.fkey()] } m.fn_decl = unsafe { &node } m.caller_name = m.fn_name(node.name, node.receiver.typ, node.is_method) diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index b8e21ec4886287..7a94a83397aab9 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -624,7 +624,7 @@ fn (mut c Checker) verify_all_vweb_routes() { if c.vweb_gen_types.len == 0 { return } - c.table.used_veb_types = c.vweb_gen_types + c.table.used_features.used_veb_types = c.vweb_gen_types typ_vweb_result := c.table.find_type('vweb.Result') old_file := c.file for vgt in c.vweb_gen_types { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 52980eabc57639..a09801e4bc6b12 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -849,7 +849,7 @@ pub fn (mut g Gen) init() { } else { g.cheaders.writeln(c_headers) } - if !g.pref.skip_unused || g.table.used_maps > 0 { + if !g.pref.skip_unused || g.table.used_features.used_maps > 0 { g.cheaders.writeln(c_wyhash_headers) } } @@ -936,11 +936,11 @@ pub fn (mut g Gen) init() { // and this is being called in the main thread, so we can mutate the table mut muttable := unsafe { &ast.Table(g.table) } if g.use_segfault_handler { - muttable.used_fns['v_segmentation_fault_handler'] = true + muttable.used_features.used_fns['v_segmentation_fault_handler'] = true } - muttable.used_fns['eprintln'] = true - muttable.used_fns['print_backtrace'] = true - muttable.used_fns['exit'] = true + muttable.used_features.used_fns['eprintln'] = true + muttable.used_features.used_fns['print_backtrace'] = true + muttable.used_features.used_fns['exit'] = true } pub fn (mut g Gen) finish() { @@ -6009,7 +6009,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) { } for field in node.fields { if g.pref.skip_unused { - if field.name !in g.table.used_consts { + if field.name !in g.table.used_features.used_consts { $if trace_skip_unused_consts ? { eprintln('>> skipping unused const name: ${field.name}') } @@ -6413,7 +6413,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) { } for field in node.fields { if g.pref.skip_unused { - if field.name !in g.table.used_globals { + if field.name !in g.table.used_features.used_globals { $if trace_skip_unused_globals ? { eprintln('>> skipping unused global name: ${field.name}') } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 7a405f10827b42..5e31dfead6d19b 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -16,7 +16,7 @@ fn (mut g Gen) is_used_by_main(node ast.FnDecl) bool { mut is_used_by_main := true if g.pref.skip_unused { fkey := node.fkey() - is_used_by_main = g.table.used_fns[fkey] + is_used_by_main = g.table.used_features.used_fns[fkey] $if trace_skip_unused_fns ? { println('> is_used_by_main: ${is_used_by_main} | node.name: ${node.name} | fkey: ${fkey} | node.is_method: ${node.is_method}') } diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index 423173df772a12..a8d0caa12c18f9 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -339,14 +339,14 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a if 'C.cJSON_Parse' in all_fns { all_fn_root_names << 'tos5' } - mut walker := Walker{ + mut walker := Walker.new( table: table files: ast_files all_fns: all_fns all_consts: all_consts all_globals: all_globals pref: pref_ - } + ) // println( all_fns.keys() ) walker.mark_markused_fns() // tagged with `@[markused]` walker.mark_markused_consts() // tagged with `@[markused]` @@ -357,7 +357,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a if walker.n_asserts > 0 { unsafe { walker.fn_decl(mut all_fns['__print_assert_failure']) } } - if table.used_maps > 0 { + if table.used_features.used_maps > 0 { for k, mut mfn in all_fns { mut method_receiver_typename := '' if mfn.is_method { @@ -405,15 +405,15 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a walker.mark_const_as_used(kcon) } } - table.used_fns = walker.used_fns.move() - table.used_consts = walker.used_consts.move() - table.used_globals = walker.used_globals.move() + table.used_features.used_fns = walker.used_fns.move() + table.used_features.used_consts = walker.used_consts.move() + table.used_features.used_globals = walker.used_globals.move() $if trace_skip_unused ? { - eprintln('>> t.used_fns: ${table.used_fns.keys()}') - eprintln('>> t.used_consts: ${table.used_consts.keys()}') - eprintln('>> t.used_globals: ${table.used_globals.keys()}') - eprintln('>> walker.table.used_maps: ${walker.table.used_maps}') + eprintln('>> t.used_fns: ${table.used_features.used_fns.keys()}') + eprintln('>> t.used_consts: ${table.used_features.used_consts.keys()}') + eprintln('>> t.used_globals: ${table.used_features.used_globals.keys()}') + eprintln('>> walker.table.used_features.used_maps: ${walker.table.used_features.used_maps}') } } @@ -460,7 +460,7 @@ fn handle_vweb(mut table ast.Table, mut all_fn_root_names []string, result_name all_fn_root_names << filter_name typ_vweb_context := table.find_type(context_name).set_nr_muls(1) all_fn_root_names << '${int(typ_vweb_context)}.html' - for vgt in table.used_veb_types { + for vgt in table.used_features.used_veb_types { sym_app := table.sym(vgt) for m in sym_app.methods { mut skip := true diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index de28a219e1faeb..5bf5f65d1a1a41 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -9,7 +9,8 @@ import v.pref pub struct Walker { pub mut: - table &ast.Table = unsafe { nil } + table &ast.Table = unsafe { nil } + features &ast.UsedFeatures = unsafe { nil } used_fns map[string]bool // used_fns['println'] == true used_consts map[string]bool // used_consts['os.args'] == true used_globals map[string]bool @@ -23,6 +24,14 @@ mut: all_globals map[string]ast.GlobalField } +pub fn Walker.new(params Walker) &Walker { + mut new_walker := &Walker{ + ...params + } + new_walker.features = params.table.used_features + return new_walker +} + pub fn (mut w Walker) mark_fn_as_used(fkey string) { $if trace_skip_unused_marked ? { eprintln(' fn > |${fkey}|') @@ -77,7 +86,7 @@ pub fn (mut w Walker) mark_root_fns(all_fn_root_names []string) { for fn_name in all_fn_root_names { if fn_name !in w.used_fns { $if trace_skip_unused_roots ? { - println('>>>> ${fn_name} uses: ') + println('>>>> walking root func: ${fn_name} ...') } unsafe { w.fn_decl(mut w.all_fns[fn_name]) } } @@ -87,6 +96,9 @@ pub fn (mut w Walker) mark_root_fns(all_fn_root_names []string) { pub fn (mut w Walker) mark_exported_fns() { for _, mut func in w.all_fns { if func.is_exported { + $if trace_skip_unused_exported_fns ? { + println('>>>> walking exported func: ${func.name} ...') + } w.fn_decl(mut func) } } @@ -95,6 +107,9 @@ pub fn (mut w Walker) mark_exported_fns() { pub fn (mut w Walker) mark_markused_fns() { for _, mut func in w.all_fns { if func.is_markused { + $if trace_skip_unused_markused_fns ? { + println('>>>> walking markused func: ${func.name} ...') + } w.fn_decl(mut func) } } @@ -103,6 +118,9 @@ pub fn (mut w Walker) mark_markused_fns() { pub fn (mut w Walker) mark_markused_consts() { for ckey, mut constfield in w.all_consts { if constfield.is_markused { + $if trace_skip_unused_markused_consts ? { + println('>>>> walking markused const: ${ckey}') + } w.mark_const_as_used(ckey) } } @@ -111,6 +129,9 @@ pub fn (mut w Walker) mark_markused_consts() { pub fn (mut w Walker) mark_markused_globals() { for gkey, mut globalfield in w.all_globals { if globalfield.is_markused || globalfield.is_exported { + $if trace_skip_unused_markused_globals ? { + println('>>>> walking markused global: ${gkey}') + } w.mark_global_as_used(gkey) } } @@ -170,9 +191,10 @@ pub fn (mut w Walker) stmt(node_ ast.Stmt) { w.expr(node.high) w.stmts(node.stmts) if node.kind == .map { - w.table.used_maps++ - } - if node.kind == .struct { + w.features.used_maps++ + } else if node.kind == .array { + w.features.used_arrays++ + } else if node.kind == .struct { if node.cond_type == 0 { return } @@ -268,6 +290,7 @@ fn (mut w Walker) expr(node_ ast.Expr) { w.expr(node.cap_expr) w.expr(node.init_expr) w.exprs(node.exprs) + w.features.used_arrays++ } ast.Assoc { w.exprs(node.exprs) @@ -325,7 +348,9 @@ fn (mut w Walker) expr(node_ ast.Expr) { } sym := w.table.final_sym(node.left_type) if sym.kind == .map { - w.table.used_maps++ + w.features.used_maps++ + } else if sym.kind == .array { + w.features.used_arrays++ } } ast.InfixExpr { @@ -347,8 +372,12 @@ fn (mut w Walker) expr(node_ ast.Expr) { return } right_sym := w.table.sym(node.right_type) - if node.op in [.not_in, .key_in] && right_sym.kind == .map { - w.table.used_maps++ + if node.op in [.not_in, .key_in] { + if right_sym.kind == .map { + w.features.used_maps++ + } else if right_sym.kind == .array { + w.features.used_arrays++ + } } } ast.IfGuardExpr { @@ -387,7 +416,7 @@ fn (mut w Walker) expr(node_ ast.Expr) { ast.MapInit { w.exprs(node.keys) w.exprs(node.vals) - w.table.used_maps++ + w.features.used_maps++ } ast.MatchExpr { w.expr(node.cond) @@ -503,9 +532,10 @@ pub fn (mut w Walker) a_struct_info(sname string, info ast.Struct) { if ifield.typ != 0 { fsym := w.table.sym(ifield.typ) if fsym.kind == .map { - w.table.used_maps++ - } - if fsym.kind == .struct { + w.features.used_maps++ + } else if fsym.kind == .array { + w.features.used_arrays++ + } else if fsym.kind == .struct { w.a_struct_info(fsym.name, fsym.struct_info()) } } @@ -518,8 +548,6 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) { } fkey := node.fkey() if w.used_fns[fkey] { - // This function is already known to be called, meaning it has been processed already. - // Save CPU time and do nothing. return } w.mark_fn_as_used(fkey) @@ -533,7 +561,7 @@ pub fn (mut w Walker) call_expr(mut node ast.CallExpr) { } if node.language == .c { if node.name in ['C.wyhash', 'C.wyhash64'] { - w.table.used_maps++ + w.features.used_maps++ } return }