v.pref: support `v -skip-unused run examples/hello_world.v`
parent
80697ec7f3
commit
40fff7b56a
|
@ -12,8 +12,6 @@ import v.pref
|
||||||
import v.util
|
import v.util
|
||||||
import v.errors
|
import v.errors
|
||||||
import v.pkgconfig
|
import v.pkgconfig
|
||||||
import v.walker
|
|
||||||
import time
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
max_nr_errors = 300
|
max_nr_errors = 300
|
||||||
|
@ -229,26 +227,8 @@ pub fn (mut c Checker) check_files(ast_files []ast.File) {
|
||||||
} else if !has_main_fn {
|
} else if !has_main_fn {
|
||||||
c.error('function `main` must be declared in the main module', token.Position{})
|
c.error('function `main` must be declared in the main module', token.Position{})
|
||||||
}
|
}
|
||||||
// Walk the tree starting at main() and mark all used fns.
|
if c.pref.skip_unused {
|
||||||
if c.pref.experimental {
|
c.mark_used(ast_files)
|
||||||
println('walking the ast')
|
|
||||||
// c.is_recursive = true
|
|
||||||
// c.fn_decl(mut c.table2.main_fn_decl_node)
|
|
||||||
t := time.ticks()
|
|
||||||
mut walker := walker.Walker{
|
|
||||||
files: ast_files
|
|
||||||
}
|
|
||||||
for stmt in c.main_fn_decl_node.stmts {
|
|
||||||
walker.stmt(stmt)
|
|
||||||
}
|
|
||||||
// walker.fn_decl(mut c.table2.main_fn_decl_node)
|
|
||||||
println('time = ${time.ticks() - t}ms, nr used fns=$walker.used_fns.len')
|
|
||||||
|
|
||||||
for key, _ in walker.used_fns {
|
|
||||||
println(key)
|
|
||||||
}
|
|
||||||
// println(walker.used_fns)
|
|
||||||
// c.walk(ast_files)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
module checker
|
||||||
|
|
||||||
|
import v.ast
|
||||||
|
import v.table
|
||||||
|
import v.checker.mark_used_walker
|
||||||
|
|
||||||
|
// mark_used walks the AST, starting at main() and marks all used fns transitively
|
||||||
|
fn (mut c Checker) mark_used(ast_files []ast.File) {
|
||||||
|
// println('walking the ast')
|
||||||
|
// c.is_recursive = true
|
||||||
|
// c.fn_decl(mut c.table2.main_fn_decl_node)
|
||||||
|
|
||||||
|
// c.timing_measure(@FN)
|
||||||
|
mut walker := mark_used_walker.Walker{
|
||||||
|
files: ast_files
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: walking over the AST using roots != main.main, like `panic`
|
||||||
|
// for example, will potentially eliminate many cases where manual
|
||||||
|
// whitelisting is needed.
|
||||||
|
// TODO: use the full name of the functions in the map. For now the
|
||||||
|
// receiver type is skipped, so we can not distinguish between
|
||||||
|
// array.trim and string.trim etc.
|
||||||
|
for stmt in c.main_fn_decl_node.stmts {
|
||||||
|
walker.stmt(stmt)
|
||||||
|
}
|
||||||
|
// walker.fn_decl(mut c.table2.main_fn_decl_node)
|
||||||
|
// println('time = ${time.ticks() - t}ms, nr used fns=$walker.used_fns.len')
|
||||||
|
|
||||||
|
/*
|
||||||
|
for key, _ in walker.used_fns {
|
||||||
|
println(key)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
c.table.used_fns = walker.used_fns
|
||||||
|
|
||||||
|
// Whitelist some functions that are used by cgen directly:
|
||||||
|
c.table.used_fns['tos'] = true
|
||||||
|
c.table.used_fns['tos2'] = true
|
||||||
|
c.table.used_fns['v_panic'] = true
|
||||||
|
c.table.used_fns['panic'] = true
|
||||||
|
c.table.used_fns['eprintln'] = true
|
||||||
|
c.table.used_fns['print_backtrace_skipping_top_frames'] = true
|
||||||
|
c.table.used_fns['print_backtrace_skipping_top_frames_linux'] = true
|
||||||
|
c.table.used_fns['new_array_from_c_array'] = true
|
||||||
|
c.table.used_fns['__new_array_with_default'] = true
|
||||||
|
c.table.used_fns['__new_array'] = true
|
||||||
|
c.table.used_fns['vcalloc'] = true
|
||||||
|
c.table.used_fns['set_unsafe'] = true
|
||||||
|
c.table.used_fns['get_unsafe'] = true
|
||||||
|
c.table.used_fns['push'] = true
|
||||||
|
c.table.used_fns['ensure_cap'] = true
|
||||||
|
c.table.used_fns['v_realloc'] = true
|
||||||
|
c.table.used_fns['all_before'] = true
|
||||||
|
c.table.used_fns['all_after'] = true
|
||||||
|
c.table.used_fns['add'] = true
|
||||||
|
c.table.used_fns['isnil'] = true
|
||||||
|
c.table.used_fns['vstrlen'] = true
|
||||||
|
c.table.used_fns['trim_space'] = true
|
||||||
|
c.table.used_fns['malloc'] = true
|
||||||
|
c.table.used_fns['trim'] = true
|
||||||
|
c.table.used_fns['at'] = true
|
||||||
|
c.table.used_fns['replace'] = true
|
||||||
|
c.table.used_fns['index_'] = true
|
||||||
|
c.table.used_fns['index_after'] = true
|
||||||
|
c.table.used_fns['index_kmp'] = true
|
||||||
|
c.table.used_fns['substr'] = true
|
||||||
|
c.table.used_fns['clone'] = true
|
||||||
|
c.table.used_fns['free'] = true
|
||||||
|
c.table.used_fns['has_index'] = true
|
||||||
|
c.table.used_fns['key'] = true
|
||||||
|
c.table.used_fns['set'] = true
|
||||||
|
c.table.used_fns['get'] = true
|
||||||
|
c.table.used_fns['new_node'] = true
|
||||||
|
c.table.used_fns['eq'] = true
|
||||||
|
c.table.used_fns['ne'] = true
|
||||||
|
c.table.used_fns['lt'] = true
|
||||||
|
c.table.used_fns['gt'] = true
|
||||||
|
c.table.used_fns['le'] = true
|
||||||
|
c.table.used_fns['ge'] = true
|
||||||
|
c.table.used_fns['split_child'] = true
|
||||||
|
c.table.used_fns['bytes'] = true
|
||||||
|
c.table.used_fns['utf8_char_len'] = true
|
||||||
|
c.table.used_fns['utf8_str_visible_length'] = true
|
||||||
|
c.table.used_fns['main.main'] = true
|
||||||
|
c.table.used_fns['builtin_init'] = true
|
||||||
|
c.table.used_fns['memdup'] = true
|
||||||
|
// c.timing_measure(@FN)
|
||||||
|
|
||||||
|
// println(walker.used_fns)
|
||||||
|
// c.walk(ast_files)
|
||||||
|
}
|
|
@ -1,9 +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 walker
|
module mark_used_walker
|
||||||
|
|
||||||
// This module walks the entire program starting at fn main and marks used (called)
|
// This module walks the entire program starting at fn main and marks used (called) functions.
|
||||||
// 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
|
||||||
|
|
||||||
|
@ -91,7 +90,7 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
|
||||||
if node.language == .c {
|
if node.language == .c {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
println('fn decl $fn_name')
|
// println('fn decl $fn_name')
|
||||||
w.used_fns[fn_name] = true
|
w.used_fns[fn_name] = true
|
||||||
for stmt in node.stmts {
|
for stmt in node.stmts {
|
||||||
w.stmt(stmt)
|
w.stmt(stmt)
|
||||||
|
@ -102,7 +101,7 @@ pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
|
||||||
pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
|
pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
|
||||||
fn_name := if node.is_method { node.receiver_type.str() + '.' + node.name } else { node.name }
|
fn_name := if node.is_method { node.receiver_type.str() + '.' + node.name } else { node.name }
|
||||||
// fn_name := node.name
|
// fn_name := node.name
|
||||||
println('call_expr $fn_name')
|
// println('call_expr $fn_name')
|
||||||
// if node.is_method {
|
// if node.is_method {
|
||||||
// println('M $node.name $node.receiver_type')
|
// println('M $node.name $node.receiver_type')
|
||||||
//}
|
//}
|
|
@ -27,13 +27,12 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if g.pref.experimental {
|
if g.pref.skip_unused {
|
||||||
if f := g.table.find_fn(node.name) {
|
is_used_by_main := g.table.used_fns[ node.name ]
|
||||||
println('> usages: ${f.usages:-10} | node.name: $node.name')
|
// println('> is_used_by_main: $is_used_by_main | node.name: $node.name')
|
||||||
if f.usages == 0 {
|
if !is_used_by_main {
|
||||||
g.writeln('// fn $node.name UNUSED')
|
g.writeln('// fn $node.name UNUSED')
|
||||||
return
|
return
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,7 @@ pub mut:
|
||||||
is_vweb bool // skip _ var warning in templates
|
is_vweb bool // skip _ var warning in templates
|
||||||
only_check_syntax bool // when true, just parse the files, then stop, before running checker
|
only_check_syntax bool // when true, just parse the files, then stop, before running checker
|
||||||
experimental bool // enable experimental features
|
experimental bool // enable experimental features
|
||||||
|
skip_unused bool // skip generating C code for functions, that are not used
|
||||||
show_timings bool // show how much time each compiler stage took
|
show_timings bool // show how much time each compiler stage took
|
||||||
is_ios_simulator bool
|
is_ios_simulator bool
|
||||||
is_apk bool // build as Android .apk format
|
is_apk bool // build as Android .apk format
|
||||||
|
@ -221,6 +222,9 @@ pub fn parse_args(args []string) (&Preferences, string) {
|
||||||
res.autofree = false
|
res.autofree = false
|
||||||
res.build_options << arg
|
res.build_options << arg
|
||||||
}
|
}
|
||||||
|
'-skip-unused' {
|
||||||
|
res.skip_unused = true
|
||||||
|
}
|
||||||
'-compress' {
|
'-compress' {
|
||||||
res.compress = true
|
res.compress = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub mut:
|
||||||
fn_gen_types map[string][][]Type // for generic functions
|
fn_gen_types map[string][][]Type // for generic functions
|
||||||
cmod_prefix string // needed for table.type_to_str(Type) while vfmt; contains `os.`
|
cmod_prefix string // needed for table.type_to_str(Type) while vfmt; contains `os.`
|
||||||
is_fmt bool
|
is_fmt bool
|
||||||
|
used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Fn {
|
pub struct Fn {
|
||||||
|
|
Loading…
Reference in New Issue