builder,checker: split the unused marking into a new `v.markused` module

pull/8727/head
Delyan Angelov 2021-02-13 17:36:14 +02:00
parent 4ef3a21c8a
commit e809264f12
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
4 changed files with 59 additions and 45 deletions

View File

@ -5,6 +5,7 @@ import v.parser
import v.pref
import v.util
import v.gen.c
import v.markused
pub fn (mut b Builder) gen_c(v_files []string) string {
util.timing_start('PARSE')
@ -20,6 +21,10 @@ pub fn (mut b Builder) gen_c(v_files []string) string {
b.checker.check_files(b.parsed_files)
util.timing_measure('CHECK')
//
if b.pref.skip_unused {
markused.mark_used(mut b.table, b.pref, b.parsed_files)
}
b.print_warnings_and_errors()
// TODO: move gen.cgen() to c.gen()
util.timing_start('C GEN')

View File

@ -212,9 +212,6 @@ pub fn (mut c Checker) check_files(ast_files []ast.File) {
c.error('a _test.v file should have *at least* one `test_` function', token.Position{})
}
}
if c.pref.skip_unused {
c.mark_used(ast_files)
}
// Make sure fn main is defined in non lib builds
if c.pref.build_mode == .build_module || c.pref.is_test {
return

View File

@ -1,39 +1,20 @@
module checker
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
module markused
import v.ast
import v.table
import v.util
import v.checker.mark_used_walker
import v.pref
// mark_used walks the AST, starting at main() and marks all used fns transitively
fn (mut c Checker) mark_used(ast_files []ast.File) {
pub fn mark_used(mut the_table table.Table, pref &pref.Preferences, ast_files []ast.File) {
mut all_fns, all_consts := all_fn_and_const(ast_files)
util.timing_start(@METHOD)
util.timing_start('all_fn_and_const')
mut all_fns := map[string]ast.FnDecl{}
mut all_consts := map[string]ast.ConstField{}
for i in 0 .. ast_files.len {
file := unsafe { &ast_files[i] }
for node in file.stmts {
match node {
ast.FnDecl {
fkey := if node.is_method {
'${int(node.receiver.typ)}.$node.name'
} else {
node.name
}
all_fns[fkey] = node
}
ast.ConstDecl {
for cfield in node.fields {
ckey := cfield.name
all_consts[ckey] = cfield
}
}
else {}
}
}
defer {
util.timing_measure(@METHOD)
}
util.timing_measure('all_fn_and_const')
mut all_fn_root_names := [
'main.main',
@ -120,7 +101,7 @@ fn (mut c Checker) mark_used(ast_files []ast.File) {
// implicit string builders are generated in auto_eq_methods.v
mut sb_mut_type := ''
if sbfn := c.table.find_fn('strings.new_builder') {
if sbfn := the_table.find_fn('strings.new_builder') {
sb_mut_type = sbfn.return_type.set_nr_muls(1).str() + '.'
}
@ -138,7 +119,7 @@ fn (mut c Checker) mark_used(ast_files []ast.File) {
|| k.ends_with('.runlock') {
all_fn_root_names << k
}
if c.pref.is_test {
if pref.is_test {
if k.starts_with('test_') || k.contains('.test_') {
all_fn_root_names << k
}
@ -151,13 +132,13 @@ fn (mut c Checker) mark_used(ast_files []ast.File) {
all_fn_root_names << k
}
}
if c.pref.is_debug {
if pref.is_debug {
all_fn_root_names << 'panic_debug'
}
if c.pref.is_test {
if pref.is_test {
all_fn_root_names << 'main.cb_assertion_ok'
all_fn_root_names << 'main.cb_assertion_failed'
if benched_tests_sym := c.table.find_type('main.BenchedTests') {
if benched_tests_sym := the_table.find_type('main.BenchedTests') {
bts_type := benched_tests_sym.methods[0].params[0].typ
all_fn_root_names << '${bts_type}.testing_step_start'
all_fn_root_names << '${bts_type}.testing_step_end'
@ -166,8 +147,8 @@ fn (mut c Checker) mark_used(ast_files []ast.File) {
}
}
mut walker := mark_used_walker.Walker{
table: c.table
mut walker := Walker{
table: the_table
files: ast_files
all_fns: all_fns
all_consts: all_consts
@ -197,13 +178,44 @@ fn (mut c Checker) mark_used(ast_files []ast.File) {
}
}
c.table.used_fns = walker.used_fns
c.table.used_consts = walker.used_consts
the_table.used_fns = walker.used_fns
the_table.used_consts = walker.used_consts
$if trace_skip_unused ? {
eprintln('>> c.table.used_fns: $c.table.used_fns.keys()')
eprintln('>> c.table.used_consts: $c.table.used_consts.keys()')
eprintln('>> the_table.used_fns: $the_table.used_fns.keys()')
eprintln('>> the_table.used_consts: $the_table.used_consts.keys()')
eprintln('>> walker.n_maps: $walker.n_maps')
}
util.timing_measure(@METHOD)
}
fn all_fn_and_const(ast_files []ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField) {
util.timing_start(@METHOD)
defer {
util.timing_measure(@METHOD)
}
mut all_fns := map[string]ast.FnDecl{}
mut all_consts := map[string]ast.ConstField{}
for i in 0 .. ast_files.len {
file := unsafe { &ast_files[i] }
for node in file.stmts {
match node {
ast.FnDecl {
fkey := if node.is_method {
'${int(node.receiver.typ)}.$node.name'
} else {
node.name
}
all_fns[fkey] = node
}
ast.ConstDecl {
for cfield in node.fields {
ckey := cfield.name
all_consts[ckey] = cfield
}
}
else {}
}
}
}
return all_fns, all_consts
}

View File

@ -1,8 +1,8 @@
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
module mark_used_walker
module markused
// This module walks the entire program starting at fn main and marks used (called) functions.
// Walk the entire program starting at fn main and marks used (called) functions.
// Unused functions can be safely skipped by the backends to save CPU time and space.
import v.ast
import v.table