patch 8.2.2400: Vim9: compiled functions are not profiled
Problem: Vim9: compiled functions are not profiled.
Solution: Add initial changes to profile compiled functions. Fix that a
script-local function was hard to debug.
diff --git a/src/vim9compile.c b/src/vim9compile.c
index ae5cb12..5a7da12 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -123,6 +123,8 @@
char_u *ctx_line_start; // start of current line or NULL
garray_T ctx_instr; // generated instructions
+ int ctx_profiling; // when TRUE generate ISN_PROF_START
+
garray_T ctx_locals; // currently visible local variables
int ctx_locals_count; // total number of local variables
@@ -1693,6 +1695,29 @@
}
/*
+ * Return TRUE if "ufunc" should be compiled, taking into account whether
+ * "profile" indicates profiling is to be done.
+ */
+ int
+func_needs_compiling(ufunc_T *ufunc, int profile)
+{
+ switch (ufunc->uf_def_status)
+ {
+ case UF_NOT_COMPILED: return FALSE;
+ case UF_TO_BE_COMPILED: return TRUE;
+ case UF_COMPILED:
+ {
+ dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ + ufunc->uf_dfunc_idx;
+
+ return profile ? dfunc->df_instr_prof == NULL
+ : dfunc->df_instr == NULL;
+ }
+ case UF_COMPILING: return FALSE;
+ }
+}
+
+/*
* Generate an ISN_DCALL or ISN_UCALL instruction.
* Return FAIL if the number of arguments is wrong.
*/
@@ -1744,10 +1769,10 @@
return FAIL;
}
}
- if (ufunc->uf_def_status == UF_TO_BE_COMPILED)
- if (compile_def_function(ufunc, ufunc->uf_ret_type == NULL, NULL)
- == FAIL)
- return FAIL;
+ if (func_needs_compiling(ufunc, cctx->ctx_profiling)
+ && compile_def_function(ufunc, ufunc->uf_ret_type == NULL,
+ cctx->ctx_profiling, NULL) == FAIL)
+ return FAIL;
}
if ((isn = generate_instr(cctx,
@@ -2063,6 +2088,19 @@
return OK;
}
+ static void
+may_generate_prof_end(cctx_T *cctx, int prof_lnum)
+{
+ if (cctx->ctx_profiling && prof_lnum >= 0)
+ {
+ int save_lnum = cctx->ctx_lnum;
+
+ cctx->ctx_lnum = prof_lnum;
+ generate_instr(cctx, ISN_PROF_END);
+ cctx->ctx_lnum = save_lnum;
+ }
+}
+
/*
* Reserve space for a local variable.
* Return the variable or NULL if it failed.
@@ -2575,9 +2613,10 @@
return FAIL;
// Need to compile any default values to get the argument types.
- if (ufunc->uf_def_status == UF_TO_BE_COMPILED)
- if (compile_def_function(ufunc, TRUE, NULL) == FAIL)
- return FAIL;
+ if (func_needs_compiling(ufunc, cctx->ctx_profiling)
+ && compile_def_function(ufunc, TRUE, cctx->ctx_profiling, NULL)
+ == FAIL)
+ return FAIL;
return generate_PUSHFUNC(cctx, ufunc->uf_name, ufunc->uf_func_type);
}
@@ -3070,7 +3109,7 @@
clear_tv(&rettv);
// Compile the function into instructions.
- compile_def_function(ufunc, TRUE, cctx);
+ compile_def_function(ufunc, TRUE, cctx->ctx_profiling, cctx);
clear_evalarg(&evalarg, NULL);
@@ -5047,8 +5086,9 @@
r = eap->skip ? OK : FAIL;
goto theend;
}
- if (ufunc->uf_def_status == UF_TO_BE_COMPILED
- && compile_def_function(ufunc, TRUE, cctx) == FAIL)
+ if (func_needs_compiling(ufunc, cctx->ctx_profiling)
+ && compile_def_function(ufunc, TRUE, cctx->ctx_profiling, cctx)
+ == FAIL)
{
func_ptr_unref(ufunc);
goto theend;
@@ -7101,7 +7141,11 @@
if (scope == NULL)
return NULL;
+ // "endwhile" jumps back here, one before when profiling
scope->se_u.se_while.ws_top_label = instr->ga_len;
+ if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1]
+ .isn_type == ISN_PROF_START)
+ --scope->se_u.se_while.ws_top_label;
// compile "expr"
if (compile_expr0(&p, cctx) == FAIL)
@@ -7134,6 +7178,9 @@
cctx->ctx_scope = scope->se_outer;
unwind_locals(cctx, scope->se_local_count);
+ // count the endwhile before jumping
+ may_generate_prof_end(cctx, cctx->ctx_lnum);
+
// At end of ":for" scope jump back to the FOR instruction.
generate_JUMP(cctx, JUMP_ALWAYS, scope->se_u.se_while.ws_top_label);
@@ -7794,13 +7841,18 @@
* When "check_return_type" is set then set ufunc->uf_ret_type to the type of
* the return statement (used for lambda). When uf_ret_type is already set
* then check that it matches.
+ * When "profiling" is true add ISN_PROF_START instructions.
* "outer_cctx" is set for a nested function.
* This can be used recursively through compile_lambda(), which may reallocate
* "def_functions".
* Returns OK or FAIL.
*/
int
-compile_def_function(ufunc_T *ufunc, int check_return_type, cctx_T *outer_cctx)
+compile_def_function(
+ ufunc_T *ufunc,
+ int check_return_type,
+ int profiling,
+ cctx_T *outer_cctx)
{
char_u *line = NULL;
char_u *p;
@@ -7813,6 +7865,7 @@
int save_estack_compiling = estack_compiling;
int do_estack_push;
int new_def_function = FALSE;
+ int prof_lnum = -1;
// When using a function that was compiled before: Free old instructions.
// The index is reused. Otherwise add a new entry in "def_functions".
@@ -7832,6 +7885,8 @@
ufunc->uf_def_status = UF_COMPILING;
CLEAR_FIELD(cctx);
+
+ cctx.ctx_profiling = profiling;
cctx.ctx_ufunc = ufunc;
cctx.ctx_lnum = -1;
cctx.ctx_outer = outer_cctx;
@@ -7932,22 +7987,35 @@
{
line = next_line_from_context(&cctx, FALSE);
if (cctx.ctx_lnum >= ufunc->uf_lines.ga_len)
+ {
// beyond the last line
+ may_generate_prof_end(&cctx, prof_lnum);
break;
+ }
}
CLEAR_FIELD(ea);
ea.cmdlinep = &line;
ea.cmd = skipwhite(line);
+ if (*ea.cmd == '#')
+ {
+ // "#" starts a comment
+ line = (char_u *)"";
+ continue;
+ }
+
+ if (cctx.ctx_profiling && cctx.ctx_lnum != prof_lnum)
+ {
+ may_generate_prof_end(&cctx, prof_lnum);
+
+ prof_lnum = cctx.ctx_lnum;
+ generate_instr(&cctx, ISN_PROF_START);
+ }
+
// Some things can be recognized by the first character.
switch (*ea.cmd)
{
- case '#':
- // "#" starts a comment
- line = (char_u *)"";
- continue;
-
case '}':
{
// "}" ends a block scope
@@ -8308,8 +8376,16 @@
+ ufunc->uf_dfunc_idx;
dfunc->df_deleted = FALSE;
dfunc->df_script_seq = current_sctx.sc_seq;
- dfunc->df_instr = instr->ga_data;
- dfunc->df_instr_count = instr->ga_len;
+ if (cctx.ctx_profiling)
+ {
+ dfunc->df_instr_prof = instr->ga_data;
+ dfunc->df_instr_prof_count = instr->ga_len;
+ }
+ else
+ {
+ dfunc->df_instr = instr->ga_data;
+ dfunc->df_instr_count = instr->ga_len;
+ }
dfunc->df_varcount = cctx.ctx_locals_count;
dfunc->df_has_closure = cctx.ctx_has_closure;
if (cctx.ctx_outer_used)
@@ -8586,6 +8662,8 @@
case ISN_OPNR:
case ISN_PCALL:
case ISN_PCALL_END:
+ case ISN_PROF_END:
+ case ISN_PROF_START:
case ISN_PUSHBOOL:
case ISN_PUSHF:
case ISN_PUSHNR: