# HG changeset patch # User Bram Moolenaar # Date 1611605706 -3600 # Node ID 7caffd835aa1ac5e550995263c0b5217f369ca2d # Parent f4946b73ba39340e9cee183a06d20fda165b6950 patch 8.2.2409: Vim9: profiling only works for one function Commit: https://github.com/vim/vim/commit/e5ea346a07a7750c02a89996b67716b43c767d06 Author: Bram Moolenaar Date: Mon Jan 25 21:01:48 2021 +0100 patch 8.2.2409: Vim9: profiling only works for one function Problem: Vim9: profiling only works for one function. Solution: Select the right instructions when calling and returning. (closes #7743) diff --git a/src/testdir/test_profile.vim b/src/testdir/test_profile.vim --- a/src/testdir/test_profile.vim +++ b/src/testdir/test_profile.vim @@ -5,6 +5,7 @@ CheckFeature profile source shared.vim source screendump.vim +source vim9.vim func Test_profile_func() call RunProfileFunc('func', 'let', 'let') @@ -583,4 +584,21 @@ func Test_profile_typed_func() call delete('XtestProfile') endfunc +func Test_vim9_profiling() + " only tests that compiling and calling functions doesn't crash + let lines =<< trim END + vim9script + def Func() + Crash() + enddef + def Crash() + enddef + prof start /tmp/profile.log + prof func Func + Func() + END + call CheckScriptSuccess(lines) +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2409, +/**/ 2408, /**/ 2407, diff --git a/src/vim9.h b/src/vim9.h --- a/src/vim9.h +++ b/src/vim9.h @@ -408,3 +408,13 @@ extern garray_T def_functions; // Used for "lnum" when a range is to be taken from the stack and "!" is used. #define LNUM_VARIABLE_RANGE_ABOVE -888 + +#ifdef FEAT_PROFILE +# define PROFILING(ufunc) (do_profiling == PROF_YES && (ufunc)->uf_profiling) +# define INSTRUCTIONS(dfunc) \ + ((do_profiling == PROF_YES && (dfunc->df_ufunc)->uf_profiling) \ + ? (dfunc)->df_instr_prof : (dfunc)->df_instr) +#else +# define PROFILING FALSE +# define INSTRUCTIONS(dfunc) ((dfunc)->df_instr) +#endif diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1775,9 +1775,9 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufu return FAIL; } } - if (func_needs_compiling(ufunc, cctx->ctx_profiling) + if (func_needs_compiling(ufunc, PROFILING(ufunc)) && compile_def_function(ufunc, ufunc->uf_ret_type == NULL, - cctx->ctx_profiling, NULL) == FAIL) + PROFILING(ufunc), NULL) == FAIL) return FAIL; } @@ -2615,8 +2615,8 @@ generate_funcref(cctx_T *cctx, char_u *n return FAIL; // Need to compile any default values to get the argument types. - if (func_needs_compiling(ufunc, cctx->ctx_profiling) - && compile_def_function(ufunc, TRUE, cctx->ctx_profiling, NULL) + if (func_needs_compiling(ufunc, PROFILING(ufunc)) + && compile_def_function(ufunc, TRUE, PROFILING(ufunc), NULL) == FAIL) return FAIL; return generate_PUSHFUNC(cctx, ufunc->uf_name, ufunc->uf_func_type); @@ -3111,7 +3111,7 @@ compile_lambda(char_u **arg, cctx_T *cct clear_tv(&rettv); // Compile the function into instructions. - compile_def_function(ufunc, TRUE, cctx->ctx_profiling, cctx); + compile_def_function(ufunc, TRUE, PROFILING(ufunc), cctx); clear_evalarg(&evalarg, NULL); @@ -5088,8 +5088,8 @@ compile_nested_function(exarg_T *eap, cc r = eap->skip ? OK : FAIL; goto theend; } - if (func_needs_compiling(ufunc, cctx->ctx_profiling) - && compile_def_function(ufunc, TRUE, cctx->ctx_profiling, cctx) + if (func_needs_compiling(ufunc, PROFILING(ufunc)) + && compile_def_function(ufunc, TRUE, PROFILING(ufunc), cctx) == FAIL) { func_ptr_unref(ufunc); diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -181,6 +181,16 @@ call_dfunc(int cdf_idx, partial_T *pt, i return FAIL; } +#ifdef FEAT_PROFILE + // Profiling might be enabled/disabled along the way. This should not + // fail, since the function was compiled before and toggling profiling + // doesn't change any errors. + if (func_needs_compiling(ufunc, PROFILING(ufunc)) + && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL) + == FAIL) + return FAIL; +#endif + if (ufunc->uf_va_name != NULL) { // Need to make a list out of the vararg arguments. @@ -293,7 +303,7 @@ call_dfunc(int cdf_idx, partial_T *pt, i // Set execution state to the start of the called function. ectx->ec_dfunc_idx = cdf_idx; - ectx->ec_instr = dfunc->df_instr; + ectx->ec_instr = INSTRUCTIONS(dfunc); entry = estack_push_ufunc(ufunc, 1); if (entry != NULL) { @@ -542,7 +552,7 @@ func_return(ectx_T *ectx) ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_IDX_OFF)->vval.v_number; dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; - ectx->ec_instr = dfunc->df_instr; + ectx->ec_instr = INSTRUCTIONS(dfunc); if (ret_idx > 0) { @@ -1103,6 +1113,7 @@ fill_partial_and_closure(partial_T *pt, return OK; } + /* * Call a "def" function from old Vim script. * Return OK or FAIL. @@ -1135,11 +1146,6 @@ call_def_function( int save_did_emsg_def = did_emsg_def; int trylevel_at_start = trylevel; int orig_funcdepth; -#ifdef FEAT_PROFILE - int profiling = do_profiling == PROF_YES && ufunc->uf_profiling; -#else -# define profiling FALSE -#endif // Get pointer to item in the stack. #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx) @@ -1152,8 +1158,8 @@ call_def_function( #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx) if (ufunc->uf_def_status == UF_NOT_COMPILED - || (func_needs_compiling(ufunc, profiling) - && compile_def_function(ufunc, FALSE, profiling, NULL) + || (func_needs_compiling(ufunc, PROFILING(ufunc)) + && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL) == FAIL)) { if (did_emsg_cumul + did_emsg == did_emsg_before) @@ -1166,11 +1172,7 @@ call_def_function( // Check the function was really compiled. dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; - if (( -#ifdef FEAT_PROFILE - profiling ? dfunc->df_instr_prof : -#endif - dfunc->df_instr) == NULL) + if (INSTRUCTIONS(dfunc) == NULL) { iemsg("using call_def_function() on not compiled function"); return FAIL; @@ -1309,11 +1311,7 @@ call_def_function( ++ectx.ec_stack.ga_len; } -#ifdef FEAT_PROFILE - ectx.ec_instr = profiling ? dfunc->df_instr_prof : dfunc->df_instr; -#else - ectx.ec_instr = dfunc->df_instr; -#endif + ectx.ec_instr = INSTRUCTIONS(dfunc); } // Following errors are in the function, not the caller.