forked from aniani/vim
patch 8.2.2403: Vim9: profiling if/elseif/endif not correct
Problem: Vim9: profiling if/elseif/endif not correct. Solution: Add profile instructions. Fix that "elseif" was wrong.
This commit is contained in:
parent
8323cab31c
commit
ced68a0070
@ -100,39 +100,48 @@ func RunProfileFunc(command, declare, assign)
|
|||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_profile_func_with_ifelse()
|
func Test_profile_func_with_ifelse()
|
||||||
|
call Run_profile_func_with_ifelse('func', 'let', 'let')
|
||||||
|
call Run_profile_func_with_ifelse('def', 'var', '')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Run_profile_func_with_ifelse(command, declare, assign)
|
||||||
let lines =<< trim [CODE]
|
let lines =<< trim [CODE]
|
||||||
func! Foo1()
|
XXX Foo1()
|
||||||
if 1
|
if 1
|
||||||
let x = 0
|
DDD x = 0
|
||||||
elseif 1
|
elseif 1
|
||||||
let x = 1
|
DDD x = 1
|
||||||
else
|
else
|
||||||
let x = 2
|
DDD x = 2
|
||||||
endif
|
endif
|
||||||
endfunc
|
endXXX
|
||||||
func! Foo2()
|
XXX Foo2()
|
||||||
if 0
|
if 0
|
||||||
let x = 0
|
DDD x = 0
|
||||||
elseif 1
|
elseif 1
|
||||||
let x = 1
|
DDD x = 1
|
||||||
else
|
else
|
||||||
let x = 2
|
DDD x = 2
|
||||||
endif
|
endif
|
||||||
endfunc
|
endXXX
|
||||||
func! Foo3()
|
XXX Foo3()
|
||||||
if 0
|
if 0
|
||||||
let x = 0
|
DDD x = 0
|
||||||
elseif 0
|
elseif 0
|
||||||
let x = 1
|
DDD x = 1
|
||||||
else
|
else
|
||||||
let x = 2
|
DDD x = 2
|
||||||
endif
|
endif
|
||||||
endfunc
|
endXXX
|
||||||
call Foo1()
|
call Foo1()
|
||||||
call Foo2()
|
call Foo2()
|
||||||
call Foo3()
|
call Foo3()
|
||||||
[CODE]
|
[CODE]
|
||||||
|
|
||||||
|
call map(lines, {k, v -> substitute(v, 'XXX', a:command, '') })
|
||||||
|
call map(lines, {k, v -> substitute(v, 'DDD', a:declare, '') })
|
||||||
|
call map(lines, {k, v -> substitute(v, 'AAA', a:assign, '') })
|
||||||
|
|
||||||
call writefile(lines, 'Xprofile_func.vim')
|
call writefile(lines, 'Xprofile_func.vim')
|
||||||
call system(GetVimCommand()
|
call system(GetVimCommand()
|
||||||
\ . ' -es -i NONE --noplugin'
|
\ . ' -es -i NONE --noplugin'
|
||||||
@ -157,11 +166,11 @@ func Test_profile_func_with_ifelse()
|
|||||||
call assert_equal('', lines[5])
|
call assert_equal('', lines[5])
|
||||||
call assert_equal('count total (s) self (s)', lines[6])
|
call assert_equal('count total (s) self (s)', lines[6])
|
||||||
call assert_match('^\s*1\s\+.*\sif 1$', lines[7])
|
call assert_match('^\s*1\s\+.*\sif 1$', lines[7])
|
||||||
call assert_match('^\s*1\s\+.*\s let x = 0$', lines[8])
|
call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 0$', lines[8])
|
||||||
call assert_match( '^\s\+elseif 1$', lines[9])
|
call assert_match( '^\s\+elseif 1$', lines[9])
|
||||||
call assert_match( '^\s\+let x = 1$', lines[10])
|
call assert_match( '^\s\+\(let\|var\) x = 1$', lines[10])
|
||||||
call assert_match( '^\s\+else$', lines[11])
|
call assert_match( '^\s\+else$', lines[11])
|
||||||
call assert_match( '^\s\+let x = 2$', lines[12])
|
call assert_match( '^\s\+\(let\|var\) x = 2$', lines[12])
|
||||||
call assert_match('^\s*1\s\+.*\sendif$', lines[13])
|
call assert_match('^\s*1\s\+.*\sendif$', lines[13])
|
||||||
call assert_equal('', lines[14])
|
call assert_equal('', lines[14])
|
||||||
call assert_equal('FUNCTION Foo2()', lines[15])
|
call assert_equal('FUNCTION Foo2()', lines[15])
|
||||||
@ -171,11 +180,11 @@ func Test_profile_func_with_ifelse()
|
|||||||
call assert_equal('', lines[20])
|
call assert_equal('', lines[20])
|
||||||
call assert_equal('count total (s) self (s)', lines[21])
|
call assert_equal('count total (s) self (s)', lines[21])
|
||||||
call assert_match('^\s*1\s\+.*\sif 0$', lines[22])
|
call assert_match('^\s*1\s\+.*\sif 0$', lines[22])
|
||||||
call assert_match( '^\s\+let x = 0$', lines[23])
|
call assert_match( '^\s\+\(let\|var\) x = 0$', lines[23])
|
||||||
call assert_match('^\s*1\s\+.*\selseif 1$', lines[24])
|
call assert_match('^\s*1\s\+.*\selseif 1$', lines[24])
|
||||||
call assert_match('^\s*1\s\+.*\s let x = 1$', lines[25])
|
call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 1$', lines[25])
|
||||||
call assert_match( '^\s\+else$', lines[26])
|
call assert_match( '^\s\+else$', lines[26])
|
||||||
call assert_match( '^\s\+let x = 2$', lines[27])
|
call assert_match( '^\s\+\(let\|var\) x = 2$', lines[27])
|
||||||
call assert_match('^\s*1\s\+.*\sendif$', lines[28])
|
call assert_match('^\s*1\s\+.*\sendif$', lines[28])
|
||||||
call assert_equal('', lines[29])
|
call assert_equal('', lines[29])
|
||||||
call assert_equal('FUNCTION Foo3()', lines[30])
|
call assert_equal('FUNCTION Foo3()', lines[30])
|
||||||
@ -185,11 +194,11 @@ func Test_profile_func_with_ifelse()
|
|||||||
call assert_equal('', lines[35])
|
call assert_equal('', lines[35])
|
||||||
call assert_equal('count total (s) self (s)', lines[36])
|
call assert_equal('count total (s) self (s)', lines[36])
|
||||||
call assert_match('^\s*1\s\+.*\sif 0$', lines[37])
|
call assert_match('^\s*1\s\+.*\sif 0$', lines[37])
|
||||||
call assert_match( '^\s\+let x = 0$', lines[38])
|
call assert_match( '^\s\+\(let\|var\) x = 0$', lines[38])
|
||||||
call assert_match('^\s*1\s\+.*\selseif 0$', lines[39])
|
call assert_match('^\s*1\s\+.*\selseif 0$', lines[39])
|
||||||
call assert_match( '^\s\+let x = 1$', lines[40])
|
call assert_match( '^\s\+\(let\|var\) x = 1$', lines[40])
|
||||||
call assert_match('^\s*1\s\+.*\selse$', lines[41])
|
call assert_match('^\s*1\s\+.*\selse$', lines[41])
|
||||||
call assert_match('^\s*1\s\+.*\s let x = 2$', lines[42])
|
call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 2$', lines[42])
|
||||||
call assert_match('^\s*1\s\+.*\sendif$', lines[43])
|
call assert_match('^\s*1\s\+.*\sendif$', lines[43])
|
||||||
call assert_equal('', lines[44])
|
call assert_equal('', lines[44])
|
||||||
call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[45])
|
call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[45])
|
||||||
|
@ -1857,8 +1857,8 @@ def Test_profiled()
|
|||||||
'\d PROFILE START line 1\_s*' ..
|
'\d PROFILE START line 1\_s*' ..
|
||||||
'\d PUSHS "profiled"\_s*' ..
|
'\d PUSHS "profiled"\_s*' ..
|
||||||
'\d ECHO 1\_s*' ..
|
'\d ECHO 1\_s*' ..
|
||||||
'\d PROFILE END\_s*' ..
|
|
||||||
'return "done"\_s*' ..
|
'return "done"\_s*' ..
|
||||||
|
'\d PROFILE END\_s*' ..
|
||||||
'\d PROFILE START line 2\_s*' ..
|
'\d PROFILE START line 2\_s*' ..
|
||||||
'\d PUSHS "done"\_s*' ..
|
'\d PUSHS "done"\_s*' ..
|
||||||
'\d RETURN\_s*' ..
|
'\d RETURN\_s*' ..
|
||||||
|
@ -1741,7 +1741,7 @@ def Test_if_elseif_else_fails()
|
|||||||
CheckDefFailure(['elseif true'], 'E582:')
|
CheckDefFailure(['elseif true'], 'E582:')
|
||||||
CheckDefFailure(['else'], 'E581:')
|
CheckDefFailure(['else'], 'E581:')
|
||||||
CheckDefFailure(['endif'], 'E580:')
|
CheckDefFailure(['endif'], 'E580:')
|
||||||
CheckDefFailure(['if true', 'elseif xxx'], 'E1001:')
|
CheckDefFailure(['if g:abool', 'elseif xxx'], 'E1001:')
|
||||||
CheckDefFailure(['if true', 'echo 1'], 'E171:')
|
CheckDefFailure(['if true', 'echo 1'], 'E171:')
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2403,
|
||||||
/**/
|
/**/
|
||||||
2402,
|
2402,
|
||||||
/**/
|
/**/
|
||||||
|
@ -44,6 +44,7 @@ struct endlabel_S {
|
|||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int is_seen_else;
|
int is_seen_else;
|
||||||
|
int is_seen_skip_not; // a block was unconditionally executed
|
||||||
int is_had_return; // every block ends in :return
|
int is_had_return; // every block ends in :return
|
||||||
int is_if_label; // instruction idx at IF or ELSEIF
|
int is_if_label; // instruction idx at IF or ELSEIF
|
||||||
endlabel_T *is_end_label; // instructions to set end label
|
endlabel_T *is_end_label; // instructions to set end label
|
||||||
@ -2098,13 +2099,7 @@ generate_undo_cmdmods(cctx_T *cctx)
|
|||||||
may_generate_prof_end(cctx_T *cctx, int prof_lnum)
|
may_generate_prof_end(cctx_T *cctx, int prof_lnum)
|
||||||
{
|
{
|
||||||
if (cctx->ctx_profiling && prof_lnum >= 0)
|
if (cctx->ctx_profiling && prof_lnum >= 0)
|
||||||
{
|
|
||||||
int save_lnum = cctx->ctx_lnum;
|
|
||||||
|
|
||||||
cctx->ctx_lnum = prof_lnum;
|
|
||||||
generate_instr(cctx, ISN_PROF_END);
|
generate_instr(cctx, ISN_PROF_END);
|
||||||
cctx->ctx_lnum = save_lnum;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -6735,6 +6730,18 @@ compile_if(char_u *arg, cctx_T *cctx)
|
|||||||
else
|
else
|
||||||
scope->se_u.se_if.is_if_label = -1;
|
scope->se_u.se_if.is_if_label = -1;
|
||||||
|
|
||||||
|
#ifdef FEAT_PROFILE
|
||||||
|
if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES
|
||||||
|
&& skip_save != SKIP_YES)
|
||||||
|
{
|
||||||
|
// generated a profile start, need to generate a profile end, since it
|
||||||
|
// won't be done after returning
|
||||||
|
cctx->ctx_skip = SKIP_NOT;
|
||||||
|
generate_instr(cctx, ISN_PROF_END);
|
||||||
|
cctx->ctx_skip = SKIP_YES;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6758,6 +6765,25 @@ compile_elseif(char_u *arg, cctx_T *cctx)
|
|||||||
if (!cctx->ctx_had_return)
|
if (!cctx->ctx_had_return)
|
||||||
scope->se_u.se_if.is_had_return = FALSE;
|
scope->se_u.se_if.is_had_return = FALSE;
|
||||||
|
|
||||||
|
if (cctx->ctx_skip == SKIP_NOT)
|
||||||
|
{
|
||||||
|
// previous block was executed, this one and following will not
|
||||||
|
cctx->ctx_skip = SKIP_YES;
|
||||||
|
scope->se_u.se_if.is_seen_skip_not = TRUE;
|
||||||
|
}
|
||||||
|
if (scope->se_u.se_if.is_seen_skip_not)
|
||||||
|
{
|
||||||
|
// A previous block was executed, skip over expression and bail out.
|
||||||
|
// Do not count the "elseif" for profiling.
|
||||||
|
#ifdef FEAT_PROFILE
|
||||||
|
if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
|
||||||
|
.isn_type == ISN_PROF_START)
|
||||||
|
--instr->ga_len;
|
||||||
|
#endif
|
||||||
|
skip_expr_cctx(&p, cctx);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
if (cctx->ctx_skip == SKIP_UNKNOWN)
|
if (cctx->ctx_skip == SKIP_UNKNOWN)
|
||||||
{
|
{
|
||||||
if (compile_jump_to_end(&scope->se_u.se_if.is_end_label,
|
if (compile_jump_to_end(&scope->se_u.se_if.is_end_label,
|
||||||
@ -6771,7 +6797,17 @@ compile_elseif(char_u *arg, cctx_T *cctx)
|
|||||||
// compile "expr"; if we know it evaluates to FALSE skip the block
|
// compile "expr"; if we know it evaluates to FALSE skip the block
|
||||||
CLEAR_FIELD(ppconst);
|
CLEAR_FIELD(ppconst);
|
||||||
if (cctx->ctx_skip == SKIP_YES)
|
if (cctx->ctx_skip == SKIP_YES)
|
||||||
|
{
|
||||||
cctx->ctx_skip = SKIP_UNKNOWN;
|
cctx->ctx_skip = SKIP_UNKNOWN;
|
||||||
|
#ifdef FEAT_PROFILE
|
||||||
|
if (cctx->ctx_profiling)
|
||||||
|
{
|
||||||
|
// the previous block was skipped, need to profile this line
|
||||||
|
generate_instr(cctx, ISN_PROF_START);
|
||||||
|
instr_count = instr->ga_len;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
if (compile_expr1(&p, cctx, &ppconst) == FAIL)
|
if (compile_expr1(&p, cctx, &ppconst) == FAIL)
|
||||||
{
|
{
|
||||||
clear_ppconst(&ppconst);
|
clear_ppconst(&ppconst);
|
||||||
@ -6829,7 +6865,27 @@ compile_else(char_u *arg, cctx_T *cctx)
|
|||||||
scope->se_u.se_if.is_had_return = FALSE;
|
scope->se_u.se_if.is_had_return = FALSE;
|
||||||
scope->se_u.se_if.is_seen_else = TRUE;
|
scope->se_u.se_if.is_seen_else = TRUE;
|
||||||
|
|
||||||
if (scope->se_skip_save != SKIP_YES)
|
#ifdef FEAT_PROFILE
|
||||||
|
if (cctx->ctx_profiling)
|
||||||
|
{
|
||||||
|
if (cctx->ctx_skip == SKIP_NOT
|
||||||
|
&& ((isn_T *)instr->ga_data)[instr->ga_len - 1]
|
||||||
|
.isn_type == ISN_PROF_START)
|
||||||
|
// the previous block was executed, do not count "else" for profiling
|
||||||
|
--instr->ga_len;
|
||||||
|
if (cctx->ctx_skip == SKIP_YES && !scope->se_u.se_if.is_seen_skip_not)
|
||||||
|
{
|
||||||
|
// the previous block was not executed, this one will, do count the
|
||||||
|
// "else" for profiling
|
||||||
|
cctx->ctx_skip = SKIP_NOT;
|
||||||
|
generate_instr(cctx, ISN_PROF_END);
|
||||||
|
generate_instr(cctx, ISN_PROF_START);
|
||||||
|
cctx->ctx_skip = SKIP_YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!scope->se_u.se_if.is_seen_skip_not && scope->se_skip_save != SKIP_YES)
|
||||||
{
|
{
|
||||||
// jump from previous block to the end, unless the else block is empty
|
// jump from previous block to the end, unless the else block is empty
|
||||||
if (cctx->ctx_skip == SKIP_UNKNOWN)
|
if (cctx->ctx_skip == SKIP_UNKNOWN)
|
||||||
@ -6884,6 +6940,17 @@ compile_endif(char_u *arg, cctx_T *cctx)
|
|||||||
}
|
}
|
||||||
// Fill in the "end" label in jumps at the end of the blocks.
|
// Fill in the "end" label in jumps at the end of the blocks.
|
||||||
compile_fill_jump_to_end(&ifscope->is_end_label, cctx);
|
compile_fill_jump_to_end(&ifscope->is_end_label, cctx);
|
||||||
|
|
||||||
|
#ifdef FEAT_PROFILE
|
||||||
|
// even when skipping we count the endif as executed, unless the block it's
|
||||||
|
// in is skipped
|
||||||
|
if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES
|
||||||
|
&& scope->se_skip_save != SKIP_YES)
|
||||||
|
{
|
||||||
|
cctx->ctx_skip = SKIP_NOT;
|
||||||
|
generate_instr(cctx, ISN_PROF_START);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
cctx->ctx_skip = scope->se_skip_save;
|
cctx->ctx_skip = scope->se_skip_save;
|
||||||
|
|
||||||
// If all the blocks end in :return and there is an :else then the
|
// If all the blocks end in :return and there is an :else then the
|
||||||
@ -8005,7 +8072,8 @@ compile_def_function(
|
|||||||
{
|
{
|
||||||
// beyond the last line
|
// beyond the last line
|
||||||
#ifdef FEAT_PROFILE
|
#ifdef FEAT_PROFILE
|
||||||
may_generate_prof_end(&cctx, prof_lnum);
|
if (cctx.ctx_skip != SKIP_YES)
|
||||||
|
may_generate_prof_end(&cctx, prof_lnum);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -8023,7 +8091,8 @@ compile_def_function(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FEAT_PROFILE
|
#ifdef FEAT_PROFILE
|
||||||
if (cctx.ctx_profiling && cctx.ctx_lnum != prof_lnum)
|
if (cctx.ctx_profiling && cctx.ctx_lnum != prof_lnum &&
|
||||||
|
cctx.ctx_skip != SKIP_YES)
|
||||||
{
|
{
|
||||||
may_generate_prof_end(&cctx, prof_lnum);
|
may_generate_prof_end(&cctx, prof_lnum);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user