Mercurial > vim
diff src/scriptfile.c @ 18991:847cc7932c42 v8.2.0056
patch 8.2.0056: execution stack is incomplete and inefficient
Commit: https://github.com/vim/vim/commit/1a47ae32cdc19b0fd5a82e19fe5fddf45db1a506
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Dec 29 23:04:25 2019 +0100
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.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 29 Dec 2019 23:15:04 +0100 |
parents | b5b2e3b824c2 |
children | dcbc559510f6 |
line wrap: on
line diff
--- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -19,6 +19,122 @@ static garray_T ga_loaded = {0, 0, size #endif /* + * Initialize the execution stack. + */ + void +estack_init(void) +{ + estack_T *entry; + + if (ga_grow(&exestack, 10) == FAIL) + mch_exit(0); + entry = ((estack_T *)exestack.ga_data) + exestack.ga_len; + entry->es_type = ETYPE_TOP; + entry->es_name = NULL; + entry->es_lnum = 0; + entry->es_info.ufunc = NULL; + ++exestack.ga_len; +} + +/* + * Add an item to the execution stack. + * Returns the new entry or NULL when out of memory. + */ + estack_T * +estack_push(etype_T type, char_u *name, long lnum) +{ + estack_T *entry; + + // If memory allocation fails then we'll pop more than we push, eventually + // at the top level it will be OK again. + if (ga_grow(&exestack, 1) == OK) + { + entry = ((estack_T *)exestack.ga_data) + exestack.ga_len; + entry->es_type = type; + entry->es_name = name; + entry->es_lnum = lnum; + entry->es_info.ufunc = NULL; + ++exestack.ga_len; + return entry; + } + return NULL; +} + +/* + * Add a user function to the execution stack. + */ + void +estack_push_ufunc(etype_T type, ufunc_T *ufunc, long lnum) +{ + estack_T *entry = estack_push(type, + ufunc->uf_name_exp != NULL + ? ufunc->uf_name_exp : ufunc->uf_name, lnum); + if (entry != NULL) + entry->es_info.ufunc = ufunc; +} + +/* + * Take an item off of the execution stack. + */ + void +estack_pop(void) +{ + if (exestack.ga_len > 1) + --exestack.ga_len; +} + +/* + * Get the current value for <sfile> in allocated memory. + */ + char_u * +estack_sfile(void) +{ + int len; + int idx; + estack_T *entry; + char *res; + int done; + + entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; + if (entry->es_name == NULL) + return NULL; + if (entry->es_info.ufunc == NULL) + return vim_strsave(entry->es_name); + + // For a function we compose the call stack, as it was done in the past: + // "function One[123]..Two[456]..Three" + len = STRLEN(entry->es_name) + 10; + for (idx = exestack.ga_len - 2; idx >= 0; --idx) + { + entry = ((estack_T *)exestack.ga_data) + idx; + if (entry->es_name == NULL || entry->es_info.ufunc == NULL) + { + ++idx; + break; + } + len += STRLEN(entry->es_name) + 15; + } + + res = (char *)alloc(len); + if (res != NULL) + { + STRCPY(res, "function "); + while (idx < exestack.ga_len - 1) + { + done = STRLEN(res); + entry = ((estack_T *)exestack.ga_data) + idx; + vim_snprintf(res + done, len - done, "%s[%ld]..", + entry->es_name, entry->es_lnum); + ++idx; + } + done = STRLEN(res); + entry = ((estack_T *)exestack.ga_data) + idx; + vim_snprintf(res + done, len - done, "%s", entry->es_name); + } + return (char_u *)res; +} + +/* * ":runtime [what] {name}" */ void @@ -947,8 +1063,6 @@ do_source( int is_vimrc) // DOSO_ value { struct source_cookie cookie; - char_u *save_sourcing_name; - linenr_T save_sourcing_lnum; char_u *p; char_u *fname_exp; char_u *firstline = NULL; @@ -1039,11 +1153,11 @@ do_source( if (p_verbose > 0) { verbose_enter(); - if (sourcing_name == NULL) + if (SOURCING_NAME == NULL) smsg(_("could not source \"%s\""), fname); else smsg(_("line %ld: could not source \"%s\""), - sourcing_lnum, fname); + SOURCING_LNUM, fname); verbose_leave(); } goto theend; @@ -1055,11 +1169,10 @@ do_source( if (p_verbose > 1) { verbose_enter(); - if (sourcing_name == NULL) + if (SOURCING_NAME == NULL) smsg(_("sourcing \"%s\""), fname); else - smsg(_("line %ld: sourcing \"%s\""), - sourcing_lnum, fname); + smsg(_("line %ld: sourcing \"%s\""), SOURCING_LNUM, fname); verbose_leave(); } if (is_vimrc == DOSO_VIMRC) @@ -1090,10 +1203,7 @@ do_source( #endif // Keep the sourcing name/lnum, for recursive calls. - save_sourcing_name = sourcing_name; - sourcing_name = fname_exp; - save_sourcing_lnum = sourcing_lnum; - sourcing_lnum = 0; + estack_push(ETYPE_SCRIPT, fname_exp, 0); #ifdef STARTUPTIME if (time_fd != NULL) @@ -1233,14 +1343,13 @@ do_source( if (got_int) emsg(_(e_interr)); - sourcing_name = save_sourcing_name; - sourcing_lnum = save_sourcing_lnum; + estack_pop(); if (p_verbose > 1) { verbose_enter(); smsg(_("finished sourcing %s"), fname); - if (sourcing_name != NULL) - smsg(_("continuing in %s"), sourcing_name); + if (SOURCING_NAME != NULL) + smsg(_("continuing in %s"), SOURCING_NAME); verbose_leave(); } #ifdef STARTUPTIME @@ -1381,7 +1490,7 @@ get_sourced_lnum(char_u *(*fgetline)(int { return fgetline == getsourceline ? ((struct source_cookie *)cookie)->sourcing_lnum - : sourcing_lnum; + : SOURCING_LNUM; } static char_u * @@ -1507,7 +1616,7 @@ getsourceline(int c UNUSED, void *cookie // If breakpoints have been added/deleted need to check for it. if (sp->dbg_tick < debug_tick) { - sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum); + sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, SOURCING_LNUM); sp->dbg_tick = debug_tick; } # ifdef FEAT_PROFILE @@ -1517,7 +1626,7 @@ getsourceline(int c UNUSED, void *cookie #endif // Set the current sourcing line number. - sourcing_lnum = sp->sourcing_lnum + 1; + SOURCING_LNUM = sp->sourcing_lnum + 1; // Get current line. If there is a read-ahead line, use it, otherwise get // one now. @@ -1602,11 +1711,11 @@ getsourceline(int c UNUSED, void *cookie #ifdef FEAT_EVAL // Did we encounter a breakpoint? - if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum) + if (sp->breakpoint != 0 && sp->breakpoint <= SOURCING_LNUM) { - dbg_breakpoint(sp->fname, sourcing_lnum); + dbg_breakpoint(sp->fname, SOURCING_LNUM); // Find next breakpoint. - sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum); + sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, SOURCING_LNUM); sp->dbg_tick = debug_tick; } #endif