Skip to content

Commit 107e9ce

Browse files
committed
patch 8.2.2404: Vim9: profiling try/catch not correct
Problem: Vim9: profiling try/catch not correct. Solution: Add profile instructions. Fix that "entry" did not rethrow an excpetion.
1 parent ced68a0 commit 107e9ce

4 files changed

Lines changed: 131 additions & 56 deletions

File tree

src/testdir/test_profile.vim

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,11 @@ func RunProfileFunc(command, declare, assign)
100100
endfunc
101101

102102
func Test_profile_func_with_ifelse()
103-
call Run_profile_func_with_ifelse('func', 'let', 'let')
104-
call Run_profile_func_with_ifelse('def', 'var', '')
103+
call Run_profile_func_with_ifelse('func', 'let')
104+
call Run_profile_func_with_ifelse('def', 'var')
105105
endfunc
106106

107-
func Run_profile_func_with_ifelse(command, declare, assign)
107+
func Run_profile_func_with_ifelse(command, declare)
108108
let lines =<< trim [CODE]
109109
XXX Foo1()
110110
if 1
@@ -140,7 +140,6 @@ func Run_profile_func_with_ifelse(command, declare, assign)
140140

141141
call map(lines, {k, v -> substitute(v, 'XXX', a:command, '') })
142142
call map(lines, {k, v -> substitute(v, 'DDD', a:declare, '') })
143-
call map(lines, {k, v -> substitute(v, 'AAA', a:assign, '') })
144143

145144
call writefile(lines, 'Xprofile_func.vim')
146145
call system(GetVimCommand()
@@ -219,42 +218,56 @@ func Run_profile_func_with_ifelse(command, declare, assign)
219218
endfunc
220219

221220
func Test_profile_func_with_trycatch()
221+
call Run_profile_func_with_trycatch('func', 'let')
222+
call Run_profile_func_with_trycatch('def', 'var')
223+
endfunc
224+
225+
func Run_profile_func_with_trycatch(command, declare)
222226
let lines =<< trim [CODE]
223-
func! Foo1()
227+
XXX Foo1()
224228
try
225-
let x = 0
229+
DDD x = 0
226230
catch
227-
let x = 1
231+
DDD x = 1
228232
finally
229-
let x = 2
233+
DDD x = 2
230234
endtry
231-
endfunc
232-
func! Foo2()
235+
endXXX
236+
XXX Foo2()
233237
try
234238
throw 0
235239
catch
236-
let x = 1
240+
DDD x = 1
237241
finally
238-
let x = 2
242+
DDD x = 2
239243
endtry
240-
endfunc
241-
func! Foo3()
244+
endXXX
245+
XXX Foo3()
242246
try
243247
throw 0
244248
catch
245249
throw 1
246250
finally
247-
let x = 2
251+
DDD x = 2
248252
endtry
249-
endfunc
253+
endXXX
250254
call Foo1()
251255
call Foo2()
256+
let rethrown = 0
252257
try
253258
call Foo3()
254259
catch
260+
let rethrown = 1
255261
endtry
262+
if rethrown != 1
263+
" call Foo1 again so that the test fails
264+
call Foo1()
265+
endif
256266
[CODE]
257267

268+
call map(lines, {k, v -> substitute(v, 'XXX', a:command, '') })
269+
call map(lines, {k, v -> substitute(v, 'DDD', a:declare, '') })
270+
258271
call writefile(lines, 'Xprofile_func.vim')
259272
call system(GetVimCommand()
260273
\ . ' -es -i NONE --noplugin'
@@ -279,11 +292,11 @@ func Test_profile_func_with_trycatch()
279292
call assert_equal('', lines[5])
280293
call assert_equal('count total (s) self (s)', lines[6])
281294
call assert_match('^\s*1\s\+.*\stry$', lines[7])
282-
call assert_match('^\s*1\s\+.*\s let x = 0$', lines[8])
295+
call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 0$', lines[8])
283296
call assert_match( '^\s\+catch$', lines[9])
284-
call assert_match( '^\s\+let x = 1$', lines[10])
297+
call assert_match( '^\s\+\(let\|var\) x = 1$', lines[10])
285298
call assert_match('^\s*1\s\+.*\sfinally$', lines[11])
286-
call assert_match('^\s*1\s\+.*\s let x = 2$', lines[12])
299+
call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 2$', lines[12])
287300
call assert_match('^\s*1\s\+.*\sendtry$', lines[13])
288301
call assert_equal('', lines[14])
289302
call assert_equal('FUNCTION Foo2()', lines[15])
@@ -295,9 +308,9 @@ func Test_profile_func_with_trycatch()
295308
call assert_match('^\s*1\s\+.*\stry$', lines[22])
296309
call assert_match('^\s*1\s\+.*\s throw 0$', lines[23])
297310
call assert_match('^\s*1\s\+.*\scatch$', lines[24])
298-
call assert_match('^\s*1\s\+.*\s let x = 1$', lines[25])
311+
call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 1$', lines[25])
299312
call assert_match('^\s*1\s\+.*\sfinally$', lines[26])
300-
call assert_match('^\s*1\s\+.*\s let x = 2$', lines[27])
313+
call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 2$', lines[27])
301314
call assert_match('^\s*1\s\+.*\sendtry$', lines[28])
302315
call assert_equal('', lines[29])
303316
call assert_equal('FUNCTION Foo3()', lines[30])
@@ -311,7 +324,7 @@ func Test_profile_func_with_trycatch()
311324
call assert_match('^\s*1\s\+.*\scatch$', lines[39])
312325
call assert_match('^\s*1\s\+.*\s throw 1$', lines[40])
313326
call assert_match('^\s*1\s\+.*\sfinally$', lines[41])
314-
call assert_match('^\s*1\s\+.*\s let x = 2$', lines[42])
327+
call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 2$', lines[42])
315328
call assert_match( '^\s\+endtry$', lines[43])
316329
call assert_equal('', lines[44])
317330
call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[45])

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2404,
753755
/**/
754756
2403,
755757
/**/

src/vim9compile.c

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6566,7 +6566,7 @@ compile_jump_to_end(endlabel_T **el, jumpwhen_T when, cctx_T *cctx)
65666566
}
65676567

65686568
static void
6569-
compile_fill_jump_to_end(endlabel_T **el, cctx_T *cctx)
6569+
compile_fill_jump_to_end(endlabel_T **el, int jump_where, cctx_T *cctx)
65706570
{
65716571
garray_T *instr = &cctx->ctx_instr;
65726572

@@ -6576,7 +6576,7 @@ compile_fill_jump_to_end(endlabel_T **el, cctx_T *cctx)
65766576
isn_T *isn;
65776577

65786578
isn = ((isn_T *)instr->ga_data) + cur->el_end_label;
6579-
isn->isn_arg.jump.jump_where = instr->ga_len;
6579+
isn->isn_arg.jump.jump_where = jump_where;
65806580
*el = cur->el_next;
65816581
vim_free(cur);
65826582
}
@@ -6939,7 +6939,7 @@ compile_endif(char_u *arg, cctx_T *cctx)
69396939
isn->isn_arg.jump.jump_where = instr->ga_len;
69406940
}
69416941
// Fill in the "end" label in jumps at the end of the blocks.
6942-
compile_fill_jump_to_end(&ifscope->is_end_label, cctx);
6942+
compile_fill_jump_to_end(&ifscope->is_end_label, instr->ga_len, cctx);
69436943

69446944
#ifdef FEAT_PROFILE
69456945
// even when skipping we count the endif as executed, unless the block it's
@@ -7182,7 +7182,7 @@ compile_endfor(char_u *arg, cctx_T *cctx)
71827182
isn->isn_arg.forloop.for_end = instr->ga_len;
71837183

71847184
// Fill in the "end" label any BREAK statements
7185-
compile_fill_jump_to_end(&forscope->fs_end_label, cctx);
7185+
compile_fill_jump_to_end(&forscope->fs_end_label, instr->ga_len, cctx);
71867186

71877187
// Below the ":for" scope drop the "expr" list from the stack.
71887188
if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL)
@@ -7245,6 +7245,7 @@ compile_while(char_u *arg, cctx_T *cctx)
72457245
compile_endwhile(char_u *arg, cctx_T *cctx)
72467246
{
72477247
scope_T *scope = cctx->ctx_scope;
7248+
garray_T *instr = &cctx->ctx_instr;
72487249

72497250
if (scope == NULL || scope->se_type != WHILE_SCOPE)
72507251
{
@@ -7264,7 +7265,8 @@ compile_endwhile(char_u *arg, cctx_T *cctx)
72647265

72657266
// Fill in the "end" label in the WHILE statement so it can jump here.
72667267
// And in any jumps for ":break"
7267-
compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label, cctx);
7268+
compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label,
7269+
instr->ga_len, cctx);
72687270

72697271
vim_free(scope);
72707272

@@ -7446,6 +7448,12 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED)
74467448

74477449
if (cctx->ctx_skip != SKIP_YES)
74487450
{
7451+
#ifdef FEAT_PROFILE
7452+
// the profile-start should be after the jump
7453+
if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
7454+
.isn_type == ISN_PROF_START)
7455+
--instr->ga_len;
7456+
#endif
74497457
// Jump from end of previous block to :finally or :endtry
74507458
if (compile_jump_to_end(&scope->se_u.se_try.ts_end_label,
74517459
JUMP_ALWAYS, cctx) == FAIL)
@@ -7461,6 +7469,15 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED)
74617469
isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label;
74627470
isn->isn_arg.jump.jump_where = instr->ga_len;
74637471
}
7472+
#ifdef FEAT_PROFILE
7473+
if (cctx->ctx_profiling)
7474+
{
7475+
// a "throw" that jumps here needs to be counted
7476+
generate_instr(cctx, ISN_PROF_END);
7477+
// the "catch" is also counted
7478+
generate_instr(cctx, ISN_PROF_START);
7479+
}
7480+
#endif
74647481
}
74657482

74667483
p = skipwhite(arg);
@@ -7521,6 +7538,7 @@ compile_finally(char_u *arg, cctx_T *cctx)
75217538
scope_T *scope = cctx->ctx_scope;
75227539
garray_T *instr = &cctx->ctx_instr;
75237540
isn_T *isn;
7541+
int this_instr;
75247542

75257543
// end block scope from :try or :catch
75267544
if (scope != NULL && scope->se_type == BLOCK_SCOPE)
@@ -7542,15 +7560,24 @@ compile_finally(char_u *arg, cctx_T *cctx)
75427560
return NULL;
75437561
}
75447562

7563+
this_instr = instr->ga_len;
7564+
#ifdef FEAT_PROFILE
7565+
if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
7566+
.isn_type == ISN_PROF_START)
7567+
// jump to the profile start of the "finally"
7568+
--this_instr;
7569+
#endif
7570+
75457571
// Fill in the "end" label in jumps at the end of the blocks.
7546-
compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, cctx);
7572+
compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label,
7573+
this_instr, cctx);
75477574

7548-
isn->isn_arg.try.try_finally = instr->ga_len;
7575+
isn->isn_arg.try.try_finally = this_instr;
75497576
if (scope->se_u.se_try.ts_catch_label != 0)
75507577
{
75517578
// Previous catch without match jumps here
75527579
isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label;
7553-
isn->isn_arg.jump.jump_where = instr->ga_len;
7580+
isn->isn_arg.jump.jump_where = this_instr;
75547581
scope->se_u.se_try.ts_catch_label = 0;
75557582
}
75567583

@@ -7595,9 +7622,18 @@ compile_endtry(char_u *arg, cctx_T *cctx)
75957622
return NULL;
75967623
}
75977624

7625+
#ifdef FEAT_PROFILE
7626+
if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
7627+
.isn_type == ISN_PROF_START)
7628+
// move the profile start after "endtry" so that it's not counted when
7629+
// the exception is rethrown.
7630+
--instr->ga_len;
7631+
#endif
7632+
75987633
// Fill in the "end" label in jumps at the end of the blocks, if not
75997634
// done by ":finally".
7600-
compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, cctx);
7635+
compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label,
7636+
instr->ga_len, cctx);
76017637

76027638
// End :catch or :finally scope: set value in ISN_TRY instruction
76037639
if (isn->isn_arg.try.try_catch == 0)
@@ -7617,6 +7653,10 @@ compile_endtry(char_u *arg, cctx_T *cctx)
76177653

76187654
if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_ENDTRY) == NULL)
76197655
return NULL;
7656+
#ifdef FEAT_PROFILE
7657+
if (cctx->ctx_profiling)
7658+
generate_instr(cctx, ISN_PROF_START);
7659+
#endif
76207660
return arg;
76217661
}
76227662

src/vim9execute.c

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2613,7 +2613,7 @@ call_def_function(
26132613

26142614
if (trystack->ga_len > 0)
26152615
{
2616-
trycmd_T *trycmd = NULL;
2616+
trycmd_T *trycmd;
26172617

26182618
--trystack->ga_len;
26192619
--trylevel;
@@ -2635,34 +2635,54 @@ call_def_function(
26352635
break;
26362636

26372637
case ISN_THROW:
2638-
if (ectx.ec_trystack.ga_len == 0 && trylevel == 0
2639-
&& emsg_silent)
26402638
{
2641-
// throwing an exception while using "silent!" causes the
2642-
// function to abort but not display an error.
2643-
tv = STACK_TV_BOT(-1);
2644-
clear_tv(tv);
2645-
tv->v_type = VAR_NUMBER;
2646-
tv->vval.v_number = 0;
2647-
goto done;
2648-
}
2649-
--ectx.ec_stack.ga_len;
2650-
tv = STACK_TV_BOT(0);
2651-
if (tv->vval.v_string == NULL
2639+
garray_T *trystack = &ectx.ec_trystack;
2640+
2641+
if (trystack->ga_len == 0 && trylevel == 0 && emsg_silent)
2642+
{
2643+
// throwing an exception while using "silent!" causes
2644+
// the function to abort but not display an error.
2645+
tv = STACK_TV_BOT(-1);
2646+
clear_tv(tv);
2647+
tv->v_type = VAR_NUMBER;
2648+
tv->vval.v_number = 0;
2649+
goto done;
2650+
}
2651+
--ectx.ec_stack.ga_len;
2652+
tv = STACK_TV_BOT(0);
2653+
if (tv->vval.v_string == NULL
26522654
|| *skipwhite(tv->vval.v_string) == NUL)
2653-
{
2654-
vim_free(tv->vval.v_string);
2655-
SOURCING_LNUM = iptr->isn_lnum;
2656-
emsg(_(e_throw_with_empty_string));
2657-
goto failed;
2658-
}
2655+
{
2656+
vim_free(tv->vval.v_string);
2657+
SOURCING_LNUM = iptr->isn_lnum;
2658+
emsg(_(e_throw_with_empty_string));
2659+
goto failed;
2660+
}
26592661

2660-
if (throw_exception(tv->vval.v_string, ET_USER, NULL) == FAIL)
2661-
{
2662-
vim_free(tv->vval.v_string);
2663-
goto failed;
2662+
// Inside a "catch" we need to first discard the caught
2663+
// exception.
2664+
if (trystack->ga_len > 0)
2665+
{
2666+
trycmd_T *trycmd = ((trycmd_T *)trystack->ga_data)
2667+
+ trystack->ga_len - 1;
2668+
if (trycmd->tcd_caught && current_exception != NULL)
2669+
{
2670+
// discard the exception
2671+
if (caught_stack == current_exception)
2672+
caught_stack = caught_stack->caught;
2673+
discard_current_exception();
2674+
trycmd->tcd_caught = FALSE;
2675+
}
2676+
}
2677+
2678+
if (throw_exception(tv->vval.v_string, ET_USER, NULL)
2679+
== FAIL)
2680+
{
2681+
vim_free(tv->vval.v_string);
2682+
goto failed;
2683+
}
2684+
did_throw = TRUE;
26642685
}
2665-
did_throw = TRUE;
26662686
break;
26672687

26682688
// compare with special values

0 commit comments

Comments
 (0)