1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

v.pref: support v -trace-calls run file.v (#15450)

This commit is contained in:
Larpon 2022-08-18 10:45:37 +02:00 committed by GitHub
parent d3307fd2e3
commit af8bd10761
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 124 additions and 1 deletions

View File

@ -77,6 +77,7 @@ fn test_all() {
global_run_dir := '$checker_dir/globals_run'
run_dir := '$checker_dir/run'
skip_unused_dir := 'vlib/v/tests/skip_unused'
trace_calls_dir := 'vlib/v/tests/trace_calls'
//
checker_tests := get_tests_in_dir(checker_dir, false)
parser_tests := get_tests_in_dir(parser_dir, false)
@ -86,6 +87,7 @@ fn test_all() {
module_tests := get_tests_in_dir(module_dir, true)
run_tests := get_tests_in_dir(run_dir, false)
skip_unused_dir_tests := get_tests_in_dir(skip_unused_dir, false)
trace_calls_dir_tests := get_tests_in_dir(trace_calls_dir, false)
mut tasks := Tasks{
vexe: vexe
label: 'all tests'
@ -113,6 +115,15 @@ fn test_all() {
skip_unused_tasks.add('', skip_unused_dir, '-d no_backtrace -skip-unused run',
'.skip_unused.run.out', skip_unused_dir_tests, false)
skip_unused_tasks.run()
//
mut trace_calls_tasks := Tasks{
vexe: vexe
parallel_jobs: 1
label: '-trace-calls tests'
}
trace_calls_tasks.add('', trace_calls_dir, '-trace-calls run', '.run.out', trace_calls_dir_tests,
false)
trace_calls_tasks.run()
}
//
if github_job == 'ubuntu-tcc' {

View File

@ -158,7 +158,8 @@ pub mut:
building_v 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 // when set, use `upx` to compress the generated executable
trace_calls bool // -trace-calls true = the transformer stage will generate and inject print calls for tracing function calls
compress bool // when set, use `upx` to compress the generated executable
// generating_vh bool
no_builtin bool // Skip adding the `builtin` module implicitly. The generated C code may not compile.
enable_globals bool // allow __global for low level code
@ -429,6 +430,9 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
res.autofree = true
res.build_options << arg
}
'-trace-calls' {
res.trace_calls = true
}
'-manualfree' {
res.autofree = false
res.build_options << arg

View File

@ -0,0 +1,6 @@
> trace fn main()
> trace fn foo()
> trace fn bar()
> trace fn baz()
> trace fn (b Boo) call_1()
end

View File

@ -0,0 +1,25 @@
module main
fn C.test()
struct Boo {}
fn (b Boo) call_1() {}
fn foo() {
bar()
}
fn bar() {
baz()
}
fn baz() {
boo := Boo{}
boo.call_1()
}
fn main() {
foo()
eprintln('end')
}

View File

@ -0,0 +1,8 @@
> trace fn init_os_args(argc int, argv &&u8) []string
> trace pub fn getwd() string
> trace fn main()
> trace fn f1()
> trace fn f2()
> trace fn f3()
> trace pub fn join_path(base string, dirs ...string) string
end

View File

@ -0,0 +1,20 @@
module main
import os
fn f1() {
f2()
}
fn f2() {
f3()
}
fn f3() {
_ := os.join_path('1', '2', '3')
}
fn main() {
f1()
eprintln('end')
}

View File

@ -226,6 +226,7 @@ pub fn (mut t Transformer) stmt(mut node ast.Stmt) ast.Stmt {
}
}
ast.FnDecl {
t.fn_decl(mut node)
t.index.indent(true)
for mut stmt in node.stmts {
stmt = t.stmt(mut stmt)
@ -1034,3 +1035,51 @@ pub fn (mut t Transformer) sql_expr(mut node ast.SqlExpr) ast.Expr {
}
return node
}
// fn_decl mutates `node`.
// if `pref.trace_calls` is true ast Nodes for `eprintln(...)` is prepended to the `FnDecl`'s
// stmts list to let the gen backend generate the target specific code for the print.
pub fn (mut t Transformer) fn_decl(mut node ast.FnDecl) {
if t.pref.trace_calls {
// Skip `C.fn()` and all of builtin
// builtin could probably be traced also but would need
// special cases for, at least, println/eprintln
if node.no_body || node.is_builtin {
return
}
call_expr := t.gen_trace_print_call_expr(node)
expr_stmt := ast.ExprStmt{
expr: call_expr
}
node.stmts.prepend(expr_stmt)
}
}
// gen_trace_print_expr_stmt generates an ast.CallExpr representation of a
// `eprint(...)` V code statement.
fn (t Transformer) gen_trace_print_call_expr(node ast.FnDecl) ast.CallExpr {
print_str := '> trace ' + node.stringify(t.table, node.mod, map[string]string{})
call_arg := ast.CallArg{
expr: ast.StringLiteral{
val: print_str
}
typ: ast.string_type_idx
}
args := [call_arg]
fn_name := 'eprintln'
call_expr := ast.CallExpr{
name: fn_name
args: args
mod: node.mod
pos: node.pos
language: node.language
scope: node.scope
comments: [ast.Comment{
text: 'fn $node.short_name trace call'
}]
}
return call_expr
}