1
0
forked from aniani/vim

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.
This commit is contained in:
Bram Moolenaar
2021-01-24 12:53:53 +01:00
parent 7cf0c114d6
commit b204990346
16 changed files with 311 additions and 109 deletions

View File

@@ -123,6 +123,8 @@ struct cctx_S {
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
@@ -1692,6 +1694,29 @@ generate_BLOBAPPEND(cctx_T *cctx)
return OK;
}
/*
* 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 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
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 @@ generate_undo_cmdmods(cctx_T *cctx)
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 @@ generate_funcref(cctx_T *cctx, char_u *name)
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 @@ compile_lambda(char_u **arg, cctx_T *cctx)
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 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
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 @@ compile_while(char_u *arg, cctx_T *cctx)
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 @@ compile_endwhile(char_u *arg, cctx_T *cctx)
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 @@ add_def_function(ufunc_T *ufunc)
* 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 @@ compile_def_function(ufunc_T *ufunc, int check_return_type, cctx_T *outer_cctx)
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 @@ compile_def_function(ufunc_T *ufunc, int check_return_type, cctx_T *outer_cctx)
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 @@ compile_def_function(ufunc_T *ufunc, int check_return_type, cctx_T *outer_cctx)
{
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 @@ nextline:
+ 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 @@ delete_instr(isn_T *isn)
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: