0
0
mirror of https://github.com/vim/vim.git synced 2025-09-26 04:04:07 -04:00

patch 8.2.0056: execution stack is incomplete and inefficient

Problem:    Execution stack is incomplete and inefficient.
Solution:   Introduce a proper execution stack and use it instead of
            sourcing_name/sourcing_lnum.  Create a string only when used.
This commit is contained in:
Bram Moolenaar
2019-12-29 23:04:25 +01:00
parent 257a396879
commit 1a47ae32cd
23 changed files with 385 additions and 240 deletions

View File

@@ -226,6 +226,22 @@ register_closure(ufunc_T *fp)
return OK;
}
static void
set_ufunc_name(ufunc_T *fp, char_u *name)
{
STRCPY(fp->uf_name, name);
if (name[0] == K_SPECIAL)
{
fp->uf_name_exp = alloc(STRLEN(name) + 3);
if (fp->uf_name_exp != NULL)
{
STRCPY(fp->uf_name_exp, "<SNR>");
STRCAT(fp->uf_name_exp, fp->uf_name + 3);
}
}
}
/*
* Parse a lambda expression and get a Funcref from "*arg".
* Return OK or FAIL. Returns NOTDONE for dict or {expr}.
@@ -309,7 +325,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
vim_strncpy(p + 7, s, e - s);
fp->uf_refcount = 1;
STRCPY(fp->uf_name, name);
set_ufunc_name(fp, name);
hash_add(&func_hashtab, UF2HIKEY(fp));
fp->uf_args = newargs;
ga_init(&fp->uf_def_args);
@@ -333,7 +349,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
fp->uf_flags = flags;
fp->uf_calls = 0;
fp->uf_script_ctx = current_sctx;
fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len;
fp->uf_script_ctx.sc_lnum += SOURCING_LNUM - newlines.ga_len;
pt->pt_func = fp;
pt->pt_refcount = 1;
@@ -759,8 +775,6 @@ call_user_func(
linenr_T lastline, // last line of range
dict_T *selfdict) // Dictionary for "self"
{
char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
sctx_T save_current_sctx;
int using_sandbox = FALSE;
funccall_T *fc;
@@ -774,7 +788,6 @@ call_user_func(
int islambda = FALSE;
char_u numbuf[NUMBUFLEN];
char_u *name;
size_t len;
#ifdef FEAT_PROFILE
proftime_T wait_start;
proftime_T call_start;
@@ -948,9 +961,6 @@ call_user_func(
// Don't redraw while executing the function.
++RedrawingDisabled;
save_sourcing_name = sourcing_name;
save_sourcing_lnum = sourcing_lnum;
sourcing_lnum = 1;
if (fp->uf_flags & FC_SANDBOX)
{
@@ -958,65 +968,51 @@ call_user_func(
++sandbox;
}
// need space for function name + ("function " + 3) or "[number]"
len = (save_sourcing_name == NULL ? 0 : STRLEN(save_sourcing_name))
+ STRLEN(fp->uf_name) + 20;
sourcing_name = alloc(len);
if (sourcing_name != NULL)
estack_push_ufunc(ETYPE_UFUNC, fp, 1);
if (p_verbose >= 12)
{
if (save_sourcing_name != NULL
&& STRNCMP(save_sourcing_name, "function ", 9) == 0)
sprintf((char *)sourcing_name, "%s[%d]..",
save_sourcing_name, (int)save_sourcing_lnum);
else
STRCPY(sourcing_name, "function ");
cat_func_name(sourcing_name + STRLEN(sourcing_name), fp);
++no_wait_return;
verbose_enter_scroll();
if (p_verbose >= 12)
smsg(_("calling %s"), SOURCING_NAME);
if (p_verbose >= 14)
{
++no_wait_return;
verbose_enter_scroll();
char_u buf[MSG_BUF_LEN];
char_u numbuf2[NUMBUFLEN];
char_u *tofree;
char_u *s;
smsg(_("calling %s"), sourcing_name);
if (p_verbose >= 14)
msg_puts("(");
for (i = 0; i < argcount; ++i)
{
char_u buf[MSG_BUF_LEN];
char_u numbuf2[NUMBUFLEN];
char_u *tofree;
char_u *s;
msg_puts("(");
for (i = 0; i < argcount; ++i)
if (i > 0)
msg_puts(", ");
if (argvars[i].v_type == VAR_NUMBER)
msg_outnum((long)argvars[i].vval.v_number);
else
{
if (i > 0)
msg_puts(", ");
if (argvars[i].v_type == VAR_NUMBER)
msg_outnum((long)argvars[i].vval.v_number);
else
// Do not want errors such as E724 here.
++emsg_off;
s = tv2string(&argvars[i], &tofree, numbuf2, 0);
--emsg_off;
if (s != NULL)
{
// Do not want errors such as E724 here.
++emsg_off;
s = tv2string(&argvars[i], &tofree, numbuf2, 0);
--emsg_off;
if (s != NULL)
if (vim_strsize(s) > MSG_BUF_CLEN)
{
if (vim_strsize(s) > MSG_BUF_CLEN)
{
trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
s = buf;
}
msg_puts((char *)s);
vim_free(tofree);
trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
s = buf;
}
msg_puts((char *)s);
vim_free(tofree);
}
}
msg_puts(")");
}
msg_puts("\n"); // don't overwrite this either
verbose_leave_scroll();
--no_wait_return;
msg_puts(")");
}
msg_puts("\n"); // don't overwrite this either
verbose_leave_scroll();
--no_wait_return;
}
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
@@ -1085,9 +1081,9 @@ call_user_func(
verbose_enter_scroll();
if (aborting())
smsg(_("%s aborted"), sourcing_name);
smsg(_("%s aborted"), SOURCING_NAME);
else if (fc->rettv->v_type == VAR_NUMBER)
smsg(_("%s returning #%ld"), sourcing_name,
smsg(_("%s returning #%ld"), SOURCING_NAME,
(long)fc->rettv->vval.v_number);
else
{
@@ -1109,7 +1105,7 @@ call_user_func(
trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
s = buf;
}
smsg(_("%s returning %s"), sourcing_name, s);
smsg(_("%s returning %s"), SOURCING_NAME, s);
vim_free(tofree);
}
}
@@ -1119,9 +1115,7 @@ call_user_func(
--no_wait_return;
}
vim_free(sourcing_name);
sourcing_name = save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
estack_pop();
current_sctx = save_current_sctx;
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
@@ -1130,12 +1124,12 @@ call_user_func(
if (using_sandbox)
--sandbox;
if (p_verbose >= 12 && sourcing_name != NULL)
if (p_verbose >= 12 && SOURCING_NAME != NULL)
{
++no_wait_return;
verbose_enter_scroll();
smsg(_("continuing in %s"), sourcing_name);
smsg(_("continuing in %s"), SOURCING_NAME);
msg_puts("\n"); // don't overwrite this either
verbose_leave_scroll();
@@ -1204,13 +1198,11 @@ func_clear_items(ufunc_T *fp)
ga_clear_strings(&(fp->uf_args));
ga_clear_strings(&(fp->uf_def_args));
ga_clear_strings(&(fp->uf_lines));
VIM_CLEAR(fp->uf_name_exp);
#ifdef FEAT_PROFILE
vim_free(fp->uf_tml_count);
fp->uf_tml_count = NULL;
vim_free(fp->uf_tml_total);
fp->uf_tml_total = NULL;
vim_free(fp->uf_tml_self);
fp->uf_tml_self = NULL;
VIM_CLEAR(fp->uf_tml_count);
VIM_CLEAR(fp->uf_tml_total);
VIM_CLEAR(fp->uf_tml_self);
#endif
}
@@ -1736,11 +1728,8 @@ list_func_head(ufunc_T *fp, int indent)
if (indent)
msg_puts(" ");
msg_puts("function ");
if (fp->uf_name[0] == K_SPECIAL)
{
msg_puts_attr("<SNR>", HL_ATTR(HLF_8));
msg_puts((char *)fp->uf_name + 3);
}
if (fp->uf_name_exp != NULL)
msg_puts((char *)fp->uf_name_exp);
else
msg_puts((char *)fp->uf_name);
msg_putchar('(');
@@ -2308,7 +2297,7 @@ ex_function(exarg_T *eap)
}
// Save the starting line number.
sourcing_lnum_top = sourcing_lnum;
sourcing_lnum_top = SOURCING_LNUM;
indent = 2;
nesting = 0;
@@ -2351,10 +2340,10 @@ ex_function(exarg_T *eap)
goto erret;
}
// Detect line continuation: sourcing_lnum increased more than one.
// Detect line continuation: SOURCING_LNUM increased more than one.
sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie);
if (sourcing_lnum < sourcing_lnum_off)
sourcing_lnum_off -= sourcing_lnum;
if (SOURCING_LNUM < sourcing_lnum_off)
sourcing_lnum_off -= SOURCING_LNUM;
else
sourcing_lnum_off = 0;
@@ -2631,16 +2620,16 @@ ex_function(exarg_T *eap)
// Check that the autoload name matches the script name.
j = FAIL;
if (sourcing_name != NULL)
if (SOURCING_NAME != NULL)
{
scriptname = autoload_name(name);
if (scriptname != NULL)
{
p = vim_strchr(scriptname, '/');
plen = (int)STRLEN(p);
slen = (int)STRLEN(sourcing_name);
slen = (int)STRLEN(SOURCING_NAME);
if (slen > plen && fnamecmp(p,
sourcing_name + slen - plen) == 0)
SOURCING_NAME + slen - plen) == 0)
j = OK;
vim_free(scriptname);
}
@@ -2685,7 +2674,7 @@ ex_function(exarg_T *eap)
}
// insert the new function in the function list
STRCPY(fp->uf_name, name);
set_ufunc_name(fp, name);
if (overwrite)
{
hi = hash_find(&func_hashtab, name);
@@ -3353,7 +3342,7 @@ get_func_line(
if (fcp->dbg_tick != debug_tick)
{
fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
sourcing_lnum);
SOURCING_LNUM);
fcp->dbg_tick = debug_tick;
}
#ifdef FEAT_PROFILE
@@ -3376,7 +3365,7 @@ get_func_line(
else
{
retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]);
sourcing_lnum = fcp->linenr;
SOURCING_LNUM = fcp->linenr;
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
func_line_start(cookie);
@@ -3385,12 +3374,12 @@ get_func_line(
}
// Did we encounter a breakpoint?
if (fcp->breakpoint != 0 && fcp->breakpoint <= sourcing_lnum)
if (fcp->breakpoint != 0 && fcp->breakpoint <= SOURCING_LNUM)
{
dbg_breakpoint(fp->uf_name, sourcing_lnum);
dbg_breakpoint(fp->uf_name, SOURCING_LNUM);
// Find next breakpoint.
fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
sourcing_lnum);
SOURCING_LNUM);
fcp->dbg_tick = debug_tick;
}