Mercurial > vim
diff src/vim9execute.c @ 19532:b8f778dda1a1 v8.2.0323
patch 8.2.0323: Vim9: calling a function that is defined later is slow
Commit: https://github.com/vim/vim/commit/7eeefd4a395fe3d7c7a2a0879467cf7ed4c29fe6
Author: Bram Moolenaar <Bram@vim.org>
Date: Wed Feb 26 21:24:23 2020 +0100
patch 8.2.0323: Vim9: calling a function that is defined later is slow
Problem: Vim9: calling a function that is defined later is slow.
Solution: Once the function is found update the instruction so it can be
called directly.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Wed, 26 Feb 2020 21:30:04 +0100 |
parents | 3b026343f398 |
children | 7df9c8df26f1 |
line wrap: on
line diff
--- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -267,9 +267,10 @@ call_bfunc(int func_idx, int argcount, e /* * Execute a user defined function. + * "iptr" can be used to replace the instruction with a more efficient one. */ static int -call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx) +call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr) { typval_T argvars[MAX_FUNC_ARGS]; funcexe_T funcexe; @@ -277,8 +278,17 @@ call_ufunc(ufunc_T *ufunc, int argcount, int idx; if (ufunc->uf_dfunc_idx >= 0) - // The function has been compiled, can call it quickly. + { + // The function has been compiled, can call it quickly. For a function + // that was defined later: we can call it directly next time. + if (iptr != NULL) + { + iptr->isn_type = ISN_DCALL; + iptr->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx; + iptr->isn_arg.dfunc.cdf_argcount = argcount; + } return call_dfunc(ufunc->uf_dfunc_idx, argcount, ectx); + } if (call_prepare(argcount, argvars, ectx) == FAIL) return FAIL; @@ -305,10 +315,11 @@ call_ufunc(ufunc_T *ufunc, int argcount, /* * Execute a function by "name". * This can be a builtin function or a user function. + * "iptr" can be used to replace the instruction with a more efficient one. * Returns FAIL if not found without an error message. */ static int -call_by_name(char_u *name, int argcount, ectx_T *ectx) +call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr) { ufunc_T *ufunc; @@ -325,7 +336,7 @@ call_by_name(char_u *name, int argcount, ufunc = find_func(name, NULL); if (ufunc != NULL) - return call_ufunc(ufunc, argcount, ectx); + return call_ufunc(ufunc, argcount, ectx, iptr); return FAIL; } @@ -341,12 +352,12 @@ call_partial(typval_T *tv, int argcount, partial_T *pt = tv->vval.v_partial; if (pt->pt_func != NULL) - return call_ufunc(pt->pt_func, argcount, ectx); + return call_ufunc(pt->pt_func, argcount, ectx, NULL); name = pt->pt_name; } else name = tv->vval.v_string; - if (call_by_name(name, argcount, ectx) == FAIL) + if (call_by_name(name, argcount, ectx, NULL) == FAIL) { if (called_emsg == called_emsg_before) semsg(_(e_unknownfunc), name); @@ -372,13 +383,14 @@ store_var(char_u *name, typval_T *tv) /* * Execute a function by "name". * This can be a builtin function, user function or a funcref. + * "iptr" can be used to replace the instruction with a more efficient one. */ static int -call_eval_func(char_u *name, int argcount, ectx_T *ectx) +call_eval_func(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr) { int called_emsg_before = called_emsg; - if (call_by_name(name, argcount, ectx) == FAIL + if (call_by_name(name, argcount, ectx, iptr) == FAIL && called_emsg == called_emsg_before) { // "name" may be a variable that is a funcref or partial @@ -983,7 +995,7 @@ call_def_function( SOURCING_LNUM = iptr->isn_lnum; if (call_eval_func(cufunc->cuf_name, - cufunc->cuf_argcount, &ectx) == FAIL) + cufunc->cuf_argcount, &ectx, iptr) == FAIL) goto failed; } break; @@ -1558,10 +1570,7 @@ call_def_function( tv = STACK_TV_BOT(-1); if (check_not_string(tv) == FAIL) - { - --ectx.ec_stack.ga_len; goto failed; - } (void)tv_get_number_chk(tv, &error); if (error) goto failed; @@ -1627,6 +1636,10 @@ done: ret = OK; failed: + // When failed need to unwind the call stack. + while (ectx.ec_frame != initial_frame_ptr) + func_return(&ectx); + for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx) clear_tv(STACK_TV(idx)); vim_free(ectx.ec_stack.ga_data);