diff options
-rw-r--r-- | src/nvim/cmdexpand.c | 2 | ||||
-rw-r--r-- | src/nvim/eval.c | 73 | ||||
-rw-r--r-- | src/nvim/profile.c | 22 | ||||
-rw-r--r-- | src/nvim/runtime.c | 48 | ||||
-rw-r--r-- | src/nvim/runtime.h | 13 |
5 files changed, 75 insertions, 83 deletions
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 97feab2978..fcd6a73b2d 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -2524,7 +2524,7 @@ static char *get_scriptnames_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx) return NULL; } - scriptitem_T *si = &SCRIPT_ITEM(idx + 1); + scriptitem_T *si = SCRIPT_ITEM(idx + 1); home_replace(NULL, si->sn_name, NameBuff, MAXPATHL, true); return NameBuff; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3ab704e250..92a8ffd646 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -109,15 +109,7 @@ static hashtab_T compat_hashtab; /// Used for checking if local variables or arguments used in a lambda. bool *eval_lavars_used = NULL; -/// Array to hold the hashtab with variables local to each sourced script. -/// Each item holds a variable (nameless) that points to the dict_T. -typedef struct { - ScopeDictDictItem sv_var; - dict_T sv_dict; -} scriptvar_T; - -static garray_T ga_scripts = { 0, 0, sizeof(scriptvar_T *), 4, NULL }; -#define SCRIPT_SV(id) (((scriptvar_T **)ga_scripts.ga_data)[(id) - 1]) +#define SCRIPT_SV(id) (SCRIPT_ITEM(id)->sn_vars) #define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab) static int echo_attr = 0; // attributes used for ":echo" @@ -473,7 +465,7 @@ void eval_init(void) } #if defined(EXITFREE) -void eval_clear(void) +static void evalvars_clear(void) { for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) { struct vimvar *p = &vimvars[i]; @@ -488,28 +480,29 @@ void eval_clear(void) hash_init(&vimvarht); // garbage_collect() will access it hash_clear(&compat_hashtab); - free_scriptnames(); + // global variables + vars_clear(&globvarht); + + // Script-local variables. Clear all the variables here. + // The scriptvar_T is cleared later in free_scriptnames(), because a + // variable in one script might hold a reference to the whole scope of + // another script. + for (int i = 1; i <= script_items.ga_len; i++) { + vars_clear(&SCRIPT_VARS(i)); + } +} + +void eval_clear(void) +{ + evalvars_clear(); + free_scriptnames(); // must come after evalvars_clear(). # ifdef HAVE_WORKING_LIBINTL free_locales(); # endif - // global variables - vars_clear(&globvarht); - // autoloaded script names ga_clear_strings(&ga_loaded); - // Script-local variables. First clear all the variables and in a second - // loop free the scriptvar_T, because a variable in one script might hold - // a reference to the whole scope of another script. - for (int i = 1; i <= ga_scripts.ga_len; i++) { - vars_clear(&SCRIPT_VARS(i)); - } - for (int i = 1; i <= ga_scripts.ga_len; i++) { - xfree(SCRIPT_SV(i)); - } - ga_clear(&ga_scripts); - // unreferenced lists and dicts (void)garbage_collect(false); @@ -970,7 +963,7 @@ void list_vim_vars(int *first) /// List script-local variables, if there is a script. void list_script_vars(int *first) { - if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len) { + if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) { list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid), "s:", false, first); } } @@ -4116,7 +4109,7 @@ bool garbage_collect(bool testing) ABORTING(set_ref_in_previous_funccal)(copyID); // script-local variables - for (int i = 1; i <= ga_scripts.ga_len; i++) { + for (int i = 1; i <= script_items.ga_len; i++) { ABORTING(set_ref_in_ht)(&SCRIPT_VARS(i), copyID, NULL); } @@ -7131,7 +7124,7 @@ hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char } else if (*name == 's' // script variable && (current_sctx.sc_sid > 0 || current_sctx.sc_sid == SID_STR || current_sctx.sc_sid == SID_LUA) - && current_sctx.sc_sid <= ga_scripts.ga_len) { + && current_sctx.sc_sid <= script_items.ga_len) { // For anonymous scripts without a script item, create one now so script vars can be used if (current_sctx.sc_sid == SID_LUA) { // try to resolve lua filename & line no so it can be shown in lastset messages. @@ -7182,27 +7175,9 @@ hashtab_T *find_var_ht(const char *name, const size_t name_len, const char **var /// sourcing this script and when executing functions defined in the script. void new_script_vars(scid_T id) { - scriptvar_T *sv; - - ga_grow(&ga_scripts, id - ga_scripts.ga_len); - - // Re-allocating ga_data means that an ht_array pointing to - // ht_smallarray becomes invalid. We can recognize this: ht_mask is - // at its init value. Also reset "v_dict", it's always the same. - for (int i = 1; i <= ga_scripts.ga_len; i++) { - hashtab_T *ht = &SCRIPT_VARS(i); - if (ht->ht_mask == HT_INIT_SIZE - 1) { - ht->ht_array = ht->ht_smallarray; - } - sv = SCRIPT_SV(i); - sv->sv_var.di_tv.vval.v_dict = &sv->sv_dict; - } - - while (ga_scripts.ga_len < id) { - sv = SCRIPT_SV(ga_scripts.ga_len + 1) = xcalloc(1, sizeof(scriptvar_T)); - init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE); - ga_scripts.ga_len++; - } + scriptvar_T *sv = xcalloc(1, sizeof(scriptvar_T)); + init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE); + SCRIPT_ITEM(id)->sn_vars = sv; } /// Initialize dictionary "dict" as a scope and set variable "dict_var" to diff --git a/src/nvim/profile.c b/src/nvim/profile.c index 173332a428..6b841bd961 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -232,7 +232,7 @@ void profile_reset(void) { // Reset sourced files. for (int id = 1; id <= script_items.ga_len; id++) { - scriptitem_T *si = &SCRIPT_ITEM(id); + scriptitem_T *si = SCRIPT_ITEM(id); if (si->sn_prof_on) { si->sn_prof_on = false; si->sn_pr_force = false; @@ -407,7 +407,7 @@ bool prof_def_func(void) FUNC_ATTR_PURE { 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; } @@ -690,7 +690,7 @@ void profile_init(scriptitem_T *si) void script_prof_save(proftime_T *tm) { if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) { - scriptitem_T *si = &SCRIPT_ITEM(current_sctx.sc_sid); + scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); if (si->sn_prof_on && si->sn_pr_nest++ == 0) { si->sn_pr_child = profile_start(); } @@ -705,7 +705,7 @@ void script_prof_restore(const proftime_T *tm) return; } - scriptitem_T *si = &SCRIPT_ITEM(current_sctx.sc_sid); + scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); if (si->sn_prof_on && --si->sn_pr_nest == 0) { si->sn_pr_child = profile_end(si->sn_pr_child); // don't count wait time @@ -722,7 +722,7 @@ static void script_dump_profile(FILE *fd) sn_prl_T *pp; for (int id = 1; id <= script_items.ga_len; id++) { - scriptitem_T *si = &SCRIPT_ITEM(id); + scriptitem_T *si = SCRIPT_ITEM(id); if (si->sn_prof_on) { fprintf(fd, "SCRIPT %s\n", si->sn_name); if (si->sn_pr_count == 1) { @@ -804,12 +804,10 @@ void profile_dump(void) /// until later and we need to store the time now. void script_line_start(void) { - scriptitem_T *si; - if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len) { return; } - si = &SCRIPT_ITEM(current_sctx.sc_sid); + scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); if (si->sn_prof_on && SOURCING_LNUM >= 1) { // Grow the array before starting the timer, so that the time spent // here isn't counted. @@ -834,12 +832,10 @@ void script_line_start(void) /// Called when actually executing a function line. void script_line_exec(void) { - scriptitem_T *si; - if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len) { return; } - si = &SCRIPT_ITEM(current_sctx.sc_sid); + scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); if (si->sn_prof_on && si->sn_prl_idx >= 0) { si->sn_prl_execed = true; } @@ -848,12 +844,10 @@ void script_line_exec(void) /// Called when done with a function line. void script_line_end(void) { - scriptitem_T *si; - if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len) { return; } - si = &SCRIPT_ITEM(current_sctx.sc_sid); + scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); if (si->sn_prof_on && si->sn_prl_idx >= 0 && si->sn_prl_idx < si->sn_prl_ga.ga_len) { if (si->sn_prl_execed) { diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index cff0f886ce..9dc213d718 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -73,7 +73,7 @@ struct source_cookie { #endif garray_T exestack = { 0, 0, sizeof(estack_T), 50, NULL }; -garray_T script_items = { 0, 0, sizeof(scriptitem_T), 4, NULL }; +garray_T script_items = { 0, 0, sizeof(scriptitem_T *), 20, NULL }; /// Initialize the execution stack. void estack_init(void) @@ -144,7 +144,7 @@ char *estack_sfile(estack_arg_T which) ? &entry->es_info.ufunc->uf_script_ctx : &entry->es_info.aucmd->script_ctx); return def_ctx->sc_sid > 0 - ? xstrdup((SCRIPT_ITEM(def_ctx->sc_sid).sn_name)) + ? xstrdup((SCRIPT_ITEM(def_ctx->sc_sid)->sn_name)) : NULL; } else if (entry->es_type == ETYPE_SCRIPT) { return xstrdup(entry->es_name); @@ -1844,13 +1844,18 @@ scriptitem_T *new_script_item(char *const name, scid_T *const sid_out) } ga_grow(&script_items, sid - script_items.ga_len); while (script_items.ga_len < sid) { + scriptitem_T *si = xcalloc(1, sizeof(scriptitem_T)); script_items.ga_len++; - SCRIPT_ITEM(script_items.ga_len).sn_name = NULL; - SCRIPT_ITEM(script_items.ga_len).sn_prof_on = false; + SCRIPT_ITEM(script_items.ga_len) = si; + si->sn_name = NULL; + + // Allocate the local script variables to use for this script. + new_script_vars(script_items.ga_len); + + si->sn_prof_on = false; } - SCRIPT_ITEM(sid).sn_name = name; - new_script_vars(sid); // Allocate the local script variables to use for this script. - return &SCRIPT_ITEM(sid); + SCRIPT_ITEM(sid)->sn_name = name; + return SCRIPT_ITEM(sid); } static int source_using_linegetter(void *cookie, LineGetter fgetline, const char *traceback_name) @@ -2118,7 +2123,7 @@ int do_source(char *fname, int check_other, int is_vimrc) if (l_do_profiling == PROF_YES) { // 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) { si->sn_pr_start = profile_end(si->sn_pr_start); si->sn_pr_start = profile_sub_wait(wait_start, si->sn_pr_start); @@ -2198,7 +2203,7 @@ scriptitem_T *get_current_script_id(char **fnamep, sctx_T *ret_sctx) // inode number, even though to the user it is the same script. // - If a script is deleted and another script is written, with a // different name, the inode may be re-used. - si = &SCRIPT_ITEM(script_sctx.sc_sid); + si = SCRIPT_ITEM(script_sctx.sc_sid); if (si->sn_name != NULL && path_fnamecmp(si->sn_name, *fnamep) == 0) { // Found it! break; @@ -2224,7 +2229,7 @@ void ex_scriptnames(exarg_T *eap) emsg(_(e_invarg)); } else { if (eap->addr_count > 0) { - eap->arg = SCRIPT_ITEM(eap->line2).sn_name; + eap->arg = SCRIPT_ITEM(eap->line2)->sn_name; } else { expand_env(eap->arg, NameBuff, MAXPATHL); eap->arg = NameBuff; @@ -2235,8 +2240,8 @@ void ex_scriptnames(exarg_T *eap) } for (int i = 1; i <= script_items.ga_len && !got_int; i++) { - if (SCRIPT_ITEM(i).sn_name != NULL) { - home_replace(NULL, SCRIPT_ITEM(i).sn_name, NameBuff, MAXPATHL, true); + if (SCRIPT_ITEM(i)->sn_name != NULL) { + home_replace(NULL, SCRIPT_ITEM(i)->sn_name, NameBuff, MAXPATHL, true); vim_snprintf(IObuff, IOSIZE, "%3d: %s", i, NameBuff); if (!message_filtered(IObuff)) { msg_putchar('\n'); @@ -2252,8 +2257,8 @@ void ex_scriptnames(exarg_T *eap) void scriptnames_slash_adjust(void) { for (int i = 1; i <= script_items.ga_len; i++) { - if (SCRIPT_ITEM(i).sn_name != NULL) { - slash_adjust(SCRIPT_ITEM(i).sn_name); + if (SCRIPT_ITEM(i)->sn_name != NULL) { + slash_adjust(SCRIPT_ITEM(i)->sn_name); } } } @@ -2287,7 +2292,7 @@ char *get_scriptname(LastSet last_set, bool *should_free) case SID_STR: return _("anonymous :source"); default: { - char *const sname = SCRIPT_ITEM(last_set.script_ctx.sc_sid).sn_name; + char *const sname = SCRIPT_ITEM(last_set.script_ctx.sc_sid)->sn_name; if (sname == NULL) { snprintf(IObuff, IOSIZE, _("anonymous :source (script id %d)"), last_set.script_ctx.sc_sid); @@ -2305,8 +2310,17 @@ void free_scriptnames(void) { profile_reset(); -# define FREE_SCRIPTNAME(item) xfree((item)->sn_name) - GA_DEEP_CLEAR(&script_items, scriptitem_T, FREE_SCRIPTNAME); +# define FREE_SCRIPTNAME(item) \ + do { \ + scriptitem_T *_si = *(item); \ + /* the variables themselves are cleared in evalvars_clear() */ \ + xfree(_si->sn_vars); \ + xfree(_si->sn_name); \ + ga_clear(&_si->sn_prl_ga); \ + xfree(_si); \ + } while (0) \ + + GA_DEEP_CLEAR(&script_items, scriptitem_T *, FREE_SCRIPTNAME); } #endif diff --git a/src/nvim/runtime.h b/src/nvim/runtime.h index 97063b900c..9a810298f8 100644 --- a/src/nvim/runtime.h +++ b/src/nvim/runtime.h @@ -55,7 +55,16 @@ typedef enum { ESTACK_SCRIPT, } estack_arg_T; -typedef struct scriptitem_S { +/// Holds the hashtab with variables local to each sourced script. +/// Each item holds a variable (nameless) that points to the dict_T. +typedef struct { + ScopeDictDictItem sv_var; + dict_T sv_dict; +} scriptvar_T; + +typedef struct { + scriptvar_T *sn_vars; ///< stores s: variables for this script + char *sn_name; bool sn_prof_on; ///< true when script is/was profiled bool sn_pr_force; ///< forceit: profile functions in this script @@ -78,7 +87,7 @@ typedef struct scriptitem_S { /// Growarray to store info about already sourced scripts. extern garray_T script_items; -#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_ID_VALID(id) ((id) > 0 && (id) <= script_items.ga_len) typedef void (*DoInRuntimepathCB)(char *, void *); |