patch 8.2.0154: reallocating the list of scripts is inefficient

Problem:    Reallocating the list of scripts is inefficient.
Solution:   Instead of using a growarray of scriptitem_T, store pointers and
            allocate each scriptitem_T separately.  Also avoids that the
            growarray pointers change when sourcing a new script.
This commit is contained in:
Bram Moolenaar
2020-01-26 19:26:46 +01:00
parent b3de5114ac
commit 21b9e9773d
10 changed files with 54 additions and 46 deletions

View File

@ -692,7 +692,7 @@ get_lval(
if (current_sctx.sc_version == SCRIPT_VERSION_VIM9 && *p == ':') if (current_sctx.sc_version == SCRIPT_VERSION_VIM9 && *p == ':')
{ {
scriptitem_T *si = &SCRIPT_ITEM(current_sctx.sc_sid); scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
char_u *tp = skipwhite(p + 1); char_u *tp = skipwhite(p + 1);
// parse the type after the name // parse the type after the name

View File

@ -2289,7 +2289,7 @@ get_var_tv(
// imported variable from another script // imported variable from another script
if (import != NULL) if (import != NULL)
{ {
scriptitem_T *si = &SCRIPT_ITEM(import->imp_sid); scriptitem_T *si = SCRIPT_ITEM(import->imp_sid);
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
+ import->imp_var_vals_idx; + import->imp_var_vals_idx;
tv = sv->sv_tv; tv = sv->sv_tv;
@ -2571,7 +2571,7 @@ new_script_vars(scid_T id)
if (sv == NULL) if (sv == NULL)
return; return;
init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE); init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
SCRIPT_ITEM(id).sn_vars = sv; SCRIPT_ITEM(id)->sn_vars = sv;
} }
/* /*
@ -2876,7 +2876,7 @@ set_var_const(
if (is_script_local && current_sctx.sc_version == SCRIPT_VERSION_VIM9) if (is_script_local && current_sctx.sc_version == SCRIPT_VERSION_VIM9)
{ {
scriptitem_T *si = &SCRIPT_ITEM(current_sctx.sc_sid); scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
// Store a pointer to the typval_T, so that it can be found by // Store a pointer to the typval_T, so that it can be found by
// index instead of using a hastab lookup. // index instead of using a hastab lookup.

View File

@ -2496,7 +2496,7 @@ do_one_cmd(
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
// Set flag that any command was executed, used by ex_vim9script(). // Set flag that any command was executed, used by ex_vim9script().
if (getline_equal(ea.getline, ea.cookie, getsourceline)) if (getline_equal(ea.getline, ea.cookie, getsourceline))
SCRIPT_ITEM(current_sctx.sc_sid).sn_had_command = TRUE; SCRIPT_ITEM(current_sctx.sc_sid)->sn_had_command = TRUE;
/* /*
* If the command just executed called do_cmdline(), any throw or ":return" * If the command just executed called do_cmdline(), any throw or ":return"

View File

@ -285,9 +285,9 @@ EXTERN int debug_backtrace_level INIT(= 0); // breakpoint backtrace level
# ifdef FEAT_PROFILE # ifdef FEAT_PROFILE
EXTERN int do_profiling INIT(= PROF_NONE); // PROF_ values EXTERN int do_profiling INIT(= PROF_NONE); // PROF_ values
# endif # endif
EXTERN garray_T script_items INIT5(0, 0, sizeof(scriptitem_T), 4, NULL); EXTERN garray_T script_items INIT5(0, 0, sizeof(scriptitem_T *), 20, NULL);
# define SCRIPT_ITEM(id) (((scriptitem_T *)script_items.ga_data)[(id) - 1]) # define SCRIPT_ITEM(id) (((scriptitem_T **)script_items.ga_data)[(id) - 1])
# define SCRIPT_SV(id) (SCRIPT_ITEM(id).sn_vars) # define SCRIPT_SV(id) (SCRIPT_ITEM(id)->sn_vars)
# define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab) # define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab)
# define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j] # define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j]

View File

@ -440,7 +440,7 @@ prof_inchar_exit(void)
prof_def_func(void) prof_def_func(void)
{ {
if (current_sctx.sc_sid > 0) if (current_sctx.sc_sid > 0)
return SCRIPT_ITEM(current_sctx.sc_sid).sn_pr_force; return SCRIPT_ITEM(current_sctx.sc_sid)->sn_pr_force;
return FALSE; return FALSE;
} }
@ -763,7 +763,7 @@ script_prof_save(
if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
{ {
si = &SCRIPT_ITEM(current_sctx.sc_sid); si = SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on && si->sn_pr_nest++ == 0) if (si->sn_prof_on && si->sn_pr_nest++ == 0)
profile_start(&si->sn_pr_child); profile_start(&si->sn_pr_child);
} }
@ -780,7 +780,7 @@ script_prof_restore(proftime_T *tm)
if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
{ {
si = &SCRIPT_ITEM(current_sctx.sc_sid); si = SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on && --si->sn_pr_nest == 0) if (si->sn_prof_on && --si->sn_pr_nest == 0)
{ {
profile_end(&si->sn_pr_child); profile_end(&si->sn_pr_child);
@ -805,7 +805,7 @@ script_dump_profile(FILE *fd)
for (id = 1; id <= script_items.ga_len; ++id) for (id = 1; id <= script_items.ga_len; ++id)
{ {
si = &SCRIPT_ITEM(id); si = SCRIPT_ITEM(id);
if (si->sn_prof_on) if (si->sn_prof_on)
{ {
fprintf(fd, "SCRIPT %s\n", si->sn_name); fprintf(fd, "SCRIPT %s\n", si->sn_name);
@ -905,7 +905,7 @@ script_line_start(void)
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len) if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
return; return;
si = &SCRIPT_ITEM(current_sctx.sc_sid); si = SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on && SOURCING_LNUM >= 1) if (si->sn_prof_on && SOURCING_LNUM >= 1)
{ {
// Grow the array before starting the timer, so that the time spent // Grow the array before starting the timer, so that the time spent
@ -940,7 +940,7 @@ script_line_exec(void)
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len) if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
return; return;
si = &SCRIPT_ITEM(current_sctx.sc_sid); si = SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on && si->sn_prl_idx >= 0) if (si->sn_prof_on && si->sn_prl_idx >= 0)
si->sn_prl_execed = TRUE; si->sn_prl_execed = TRUE;
} }
@ -956,7 +956,7 @@ script_line_end(void)
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len) if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
return; return;
si = &SCRIPT_ITEM(current_sctx.sc_sid); si = SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on && si->sn_prl_idx >= 0 if (si->sn_prof_on && si->sn_prl_idx >= 0
&& si->sn_prl_idx < si->sn_prl_ga.ga_len) && si->sn_prl_idx < si->sn_prl_ga.ga_len)
{ {

View File

@ -1124,7 +1124,7 @@ do_source(
// inode number, even though to the user it is the same script. // inode number, even though to the user it is the same script.
// - If a script is deleted and another script is written, with a // - If a script is deleted and another script is written, with a
// different name, the inode may be re-used. // different name, the inode may be re-used.
si = &SCRIPT_ITEM(sid); si = SCRIPT_ITEM(sid);
if (si->sn_name != NULL && fnamecmp(si->sn_name, fname_exp) == 0) if (si->sn_name != NULL && fnamecmp(si->sn_name, fname_exp) == 0)
// Found it! // Found it!
break; break;
@ -1294,8 +1294,11 @@ do_source(
goto almosttheend; goto almosttheend;
while (script_items.ga_len < current_sctx.sc_sid) while (script_items.ga_len < current_sctx.sc_sid)
{ {
si = ALLOC_CLEAR_ONE(scriptitem_T);
if (si == NULL)
goto almosttheend;
++script_items.ga_len; ++script_items.ga_len;
si = &SCRIPT_ITEM(script_items.ga_len); SCRIPT_ITEM(script_items.ga_len) = si;
si->sn_name = NULL; si->sn_name = NULL;
si->sn_version = 1; si->sn_version = 1;
@ -1308,7 +1311,7 @@ do_source(
si->sn_prof_on = FALSE; si->sn_prof_on = FALSE;
# endif # endif
} }
si = &SCRIPT_ITEM(current_sctx.sc_sid); si = SCRIPT_ITEM(current_sctx.sc_sid);
si->sn_name = fname_exp; si->sn_name = fname_exp;
fname_exp = vim_strsave(si->sn_name); // used for autocmd fname_exp = vim_strsave(si->sn_name); // used for autocmd
if (ret_sid != NULL) if (ret_sid != NULL)
@ -1364,7 +1367,7 @@ do_source(
if (do_profiling == PROF_YES) if (do_profiling == PROF_YES)
{ {
// Get "si" again, "script_items" may have been reallocated. // Get "si" again, "script_items" may have been reallocated.
si = &SCRIPT_ITEM(current_sctx.sc_sid); si = SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on) if (si->sn_prof_on)
{ {
profile_end(&si->sn_pr_start); profile_end(&si->sn_pr_start);
@ -1411,7 +1414,7 @@ do_source(
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
almosttheend: almosttheend:
// Get "si" again, "script_items" may have been reallocated. // Get "si" again, "script_items" may have been reallocated.
si = &SCRIPT_ITEM(current_sctx.sc_sid); si = SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_save_cpo != NULL) if (si->sn_save_cpo != NULL)
{ {
free_string_option(p_cpo); free_string_option(p_cpo);
@ -1456,16 +1459,16 @@ ex_scriptnames(exarg_T *eap)
emsg(_(e_invarg)); emsg(_(e_invarg));
else else
{ {
eap->arg = SCRIPT_ITEM(eap->line2).sn_name; eap->arg = SCRIPT_ITEM(eap->line2)->sn_name;
do_exedit(eap, NULL); do_exedit(eap, NULL);
} }
return; return;
} }
for (i = 1; i <= script_items.ga_len && !got_int; ++i) for (i = 1; i <= script_items.ga_len && !got_int; ++i)
if (SCRIPT_ITEM(i).sn_name != NULL) if (SCRIPT_ITEM(i)->sn_name != NULL)
{ {
home_replace(NULL, SCRIPT_ITEM(i).sn_name, home_replace(NULL, SCRIPT_ITEM(i)->sn_name,
NameBuff, MAXPATHL, TRUE); NameBuff, MAXPATHL, TRUE);
smsg("%3d: %s", i, NameBuff); smsg("%3d: %s", i, NameBuff);
} }
@ -1481,8 +1484,8 @@ scriptnames_slash_adjust(void)
int i; int i;
for (i = 1; i <= script_items.ga_len; ++i) for (i = 1; i <= script_items.ga_len; ++i)
if (SCRIPT_ITEM(i).sn_name != NULL) if (SCRIPT_ITEM(i)->sn_name != NULL)
slash_adjust(SCRIPT_ITEM(i).sn_name); slash_adjust(SCRIPT_ITEM(i)->sn_name);
} }
# endif # endif
@ -1502,7 +1505,7 @@ get_scriptname(scid_T id)
return (char_u *)_("environment variable"); return (char_u *)_("environment variable");
if (id == SID_ERROR) if (id == SID_ERROR)
return (char_u *)_("error handler"); return (char_u *)_("error handler");
return SCRIPT_ITEM(id).sn_name; return SCRIPT_ITEM(id)->sn_name;
} }
# if defined(EXITFREE) || defined(PROTO) # if defined(EXITFREE) || defined(PROTO)
@ -1513,14 +1516,17 @@ free_scriptnames(void)
for (i = script_items.ga_len; i > 0; --i) for (i = script_items.ga_len; i > 0; --i)
{ {
// the variables themselves are cleared in evalvars_clear() scriptitem_T *si = SCRIPT_ITEM(i);
vim_free(SCRIPT_ITEM(i).sn_vars);
vim_free(SCRIPT_ITEM(i).sn_name); // the variables themselves are cleared in evalvars_clear()
free_string_option(SCRIPT_ITEM(i).sn_save_cpo); vim_free(si->sn_vars);
vim_free(si->sn_name);
free_string_option(si->sn_save_cpo);
# ifdef FEAT_PROFILE # ifdef FEAT_PROFILE
ga_clear(&SCRIPT_ITEM(i).sn_prl_ga); ga_clear(&si->sn_prl_ga);
# endif # endif
vim_free(si);
} }
ga_clear(&script_items); ga_clear(&script_items);
} }
@ -1832,7 +1838,7 @@ ex_scriptversion(exarg_T *eap UNUSED)
else else
{ {
current_sctx.sc_version = nr; current_sctx.sc_version = nr;
SCRIPT_ITEM(current_sctx.sc_sid).sn_version = nr; SCRIPT_ITEM(current_sctx.sc_sid)->sn_version = nr;
} }
#endif #endif
} }

View File

@ -742,6 +742,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
154,
/**/ /**/
153, 153,
/**/ /**/

View File

@ -1401,7 +1401,7 @@ get_script_item_idx(int sid, char_u *name, int check_writable)
{ {
hashtab_T *ht; hashtab_T *ht;
dictitem_T *di; dictitem_T *di;
scriptitem_T *si = &SCRIPT_ITEM(sid); scriptitem_T *si = SCRIPT_ITEM(sid);
int idx; int idx;
// First look the name up in the hashtable. // First look the name up in the hashtable.
@ -1433,7 +1433,7 @@ get_script_item_idx(int sid, char_u *name, int check_writable)
imported_T * imported_T *
find_imported(char_u *name, cctx_T *cctx) find_imported(char_u *name, cctx_T *cctx)
{ {
scriptitem_T *si = &SCRIPT_ITEM(current_sctx.sc_sid); scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
int idx; int idx;
if (cctx != NULL) if (cctx != NULL)
@ -1462,7 +1462,7 @@ find_imported(char_u *name, cctx_T *cctx)
static int static int
compile_load_scriptvar(cctx_T *cctx, char_u *name) compile_load_scriptvar(cctx_T *cctx, char_u *name)
{ {
scriptitem_T *si = &SCRIPT_ITEM(current_sctx.sc_sid); scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
int idx = get_script_item_idx(current_sctx.sc_sid, name, FALSE); int idx = get_script_item_idx(current_sctx.sc_sid, name, FALSE);
imported_T *import; imported_T *import;

View File

@ -492,7 +492,7 @@ call_def_function(
case ISN_LOADSCRIPT: case ISN_LOADSCRIPT:
{ {
scriptitem_T *si = scriptitem_T *si =
&SCRIPT_ITEM(iptr->isn_arg.script.script_sid); SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
svar_T *sv; svar_T *sv;
sv = ((svar_T *)si->sn_var_vals.ga_data) sv = ((svar_T *)si->sn_var_vals.ga_data)
@ -598,7 +598,7 @@ call_def_function(
// store script-local variable // store script-local variable
case ISN_STORESCRIPT: case ISN_STORESCRIPT:
{ {
scriptitem_T *si = &SCRIPT_ITEM( scriptitem_T *si = SCRIPT_ITEM(
iptr->isn_arg.script.script_sid); iptr->isn_arg.script.script_sid);
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
+ iptr->isn_arg.script.script_idx; + iptr->isn_arg.script.script_idx;
@ -1551,7 +1551,7 @@ ex_disassemble(exarg_T *eap)
case ISN_LOADSCRIPT: case ISN_LOADSCRIPT:
{ {
scriptitem_T *si = scriptitem_T *si =
&SCRIPT_ITEM(iptr->isn_arg.script.script_sid); SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
+ iptr->isn_arg.script.script_idx; + iptr->isn_arg.script.script_idx;
@ -1561,7 +1561,7 @@ ex_disassemble(exarg_T *eap)
break; break;
case ISN_LOADS: case ISN_LOADS:
{ {
scriptitem_T *si = &SCRIPT_ITEM(iptr->isn_arg.loads.ls_sid); scriptitem_T *si = SCRIPT_ITEM(iptr->isn_arg.loads.ls_sid);
smsg("%4d LOADS s:%s from %s", current, smsg("%4d LOADS s:%s from %s", current,
iptr->isn_arg.string, si->sn_name); iptr->isn_arg.string, si->sn_name);
@ -1589,7 +1589,7 @@ ex_disassemble(exarg_T *eap)
case ISN_STORESCRIPT: case ISN_STORESCRIPT:
{ {
scriptitem_T *si = scriptitem_T *si =
&SCRIPT_ITEM(iptr->isn_arg.script.script_sid); SCRIPT_ITEM(iptr->isn_arg.script.script_sid);
svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data)
+ iptr->isn_arg.script.script_idx; + iptr->isn_arg.script.script_idx;

View File

@ -32,7 +32,7 @@ in_vim9script(void)
void void
ex_vim9script(exarg_T *eap) ex_vim9script(exarg_T *eap)
{ {
scriptitem_T *si = &SCRIPT_ITEM(current_sctx.sc_sid); scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
if (!getline_equal(eap->getline, eap->cookie, getsourceline)) if (!getline_equal(eap->getline, eap->cookie, getsourceline))
{ {
@ -114,7 +114,7 @@ new_imported(garray_T *gap)
void void
free_imports(int sid) free_imports(int sid)
{ {
scriptitem_T *si = &SCRIPT_ITEM(sid); scriptitem_T *si = SCRIPT_ITEM(sid);
int idx; int idx;
for (idx = 0; idx < si->sn_imports.ga_len; ++idx) for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
@ -226,7 +226,7 @@ handle_import(char_u *arg_start, garray_T *gap, int import_sid)
if (*tv.vval.v_string == '.') if (*tv.vval.v_string == '.')
{ {
size_t len; size_t len;
scriptitem_T *si = &SCRIPT_ITEM(current_sctx.sc_sid); scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
char_u *tail = gettail(si->sn_name); char_u *tail = gettail(si->sn_name);
char_u *from_name; char_u *from_name;
@ -279,7 +279,7 @@ handle_import(char_u *arg_start, garray_T *gap, int import_sid)
if (*arg_start == '*') if (*arg_start == '*')
{ {
imported_T *imported = new_imported(gap != NULL ? gap imported_T *imported = new_imported(gap != NULL ? gap
: &SCRIPT_ITEM(import_sid).sn_imports); : &SCRIPT_ITEM(import_sid)->sn_imports);
if (imported == NULL) if (imported == NULL)
return NULL; return NULL;
@ -289,7 +289,7 @@ handle_import(char_u *arg_start, garray_T *gap, int import_sid)
} }
else else
{ {
scriptitem_T *script = &SCRIPT_ITEM(sid); scriptitem_T *script = SCRIPT_ITEM(sid);
arg = arg_start; arg = arg_start;
if (*arg == '{') if (*arg == '{')
@ -358,7 +358,7 @@ handle_import(char_u *arg_start, garray_T *gap, int import_sid)
} }
imported = new_imported(gap != NULL ? gap imported = new_imported(gap != NULL ? gap
: &SCRIPT_ITEM(import_sid).sn_imports); : &SCRIPT_ITEM(import_sid)->sn_imports);
if (imported == NULL) if (imported == NULL)
return NULL; return NULL;