Mercurial > vim
diff src/userfunc.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 | af44ca0ddf49 |
children | dd9ab0674eec |
line wrap: on
line diff
--- a/src/userfunc.c +++ b/src/userfunc.c @@ -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 *re 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 *re 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); - - if (p_verbose >= 12) + ++no_wait_return; + verbose_enter_scroll(); + + smsg(_("calling %s"), SOURCING_NAME); + if (p_verbose >= 14) { - ++no_wait_return; - verbose_enter_scroll(); - - smsg(_("calling %s"), sourcing_name); - if (p_verbose >= 14) + char_u buf[MSG_BUF_LEN]; + char_u numbuf2[NUMBUFLEN]; + char_u *tofree; + char_u *s; + + 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; }