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.pref
import v.util import v.util
import v.gen.c import v.gen.c
import v.markused
pub fn (mut b Builder) gen_c(v_files []string) string { pub fn (mut b Builder) gen_c(v_files []string) string {
util.timing_start('PARSE') 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) b.checker.check_files(b.parsed_files)
util.timing_measure('CHECK') 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() b.print_warnings_and_errors()
// TODO: move gen.cgen() to c.gen() // TODO: move gen.cgen() to c.gen()
util.timing_start('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{}) 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 // Make sure fn main is defined in non lib builds
if c.pref.build_mode == .build_module || c.pref.is_test { if c.pref.build_mode == .build_module || c.pref.is_test {
return 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.ast
import v.table import v.table
import v.util 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 // 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(@METHOD)
util.timing_start('all_fn_and_const') defer {
mut all_fns := map[string]ast.FnDecl{} util.timing_measure(@METHOD)
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 {}
}
}
} }
util.timing_measure('all_fn_and_const')
mut all_fn_root_names := [ mut all_fn_root_names := [
'main.main', '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 // implicit string builders are generated in auto_eq_methods.v
mut sb_mut_type := '' 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() + '.' 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') { || k.ends_with('.runlock') {
all_fn_root_names << k all_fn_root_names << k
} }
if c.pref.is_test { if pref.is_test {
if k.starts_with('test_') || k.contains('.test_') { if k.starts_with('test_') || k.contains('.test_') {
all_fn_root_names << k all_fn_root_names << k
} }
@ -151,13 +132,13 @@ fn (mut c Checker) mark_used(ast_files []ast.File) {
all_fn_root_names << k all_fn_root_names << k
} }
} }
if c.pref.is_debug { if pref.is_debug {
all_fn_root_names << 'panic_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_ok'
all_fn_root_names << 'main.cb_assertion_failed' 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 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_start'
all_fn_root_names << '${bts_type}.testing_step_end' 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{ mut walker := Walker{
table: c.table table: the_table
files: ast_files files: ast_files
all_fns: all_fns all_fns: all_fns
all_consts: all_consts 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 the_table.used_fns = walker.used_fns
c.table.used_consts = walker.used_consts the_table.used_consts = walker.used_consts
$if trace_skip_unused ? { $if trace_skip_unused ? {
eprintln('>> c.table.used_fns: $c.table.used_fns.keys()') eprintln('>> the_table.used_fns: $the_table.used_fns.keys()')
eprintln('>> c.table.used_consts: $c.table.used_consts.keys()') eprintln('>> the_table.used_consts: $the_table.used_consts.keys()')
eprintln('>> walker.n_maps: $walker.n_maps') 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. // 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. // 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. // Unused functions can be safely skipped by the backends to save CPU time and space.
import v.ast import v.ast
import v.table import v.table