Patch 9.0.0618
Problem:    Calling function for reduce() has too much overhead.
Solution:   Do not create a funccall_T every time.
Files:      src/eval.c, src/proto/eval.pro, src/list.c, src/proto/list.pro,
            src/blob.c, src/evalfunc.c, src/filepath.c, src/strings.c,
            src/dict.c


*** ../vim-9.0.0617/src/eval.c  2022-09-23 16:37:15.372190942 +0100
--- src/eval.c  2022-09-28 15:53:36.348502312 +0100
***************
*** 216,227 ****
  }
  
  /*
   * Evaluate an expression, which can be a function, partial or string.
   * Pass arguments "argv[argc]".
   * Return the result in "rettv" and OK or FAIL.
   */
      int
! eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
  {
      char_u    *s;
      char_u    buf[NUMBUFLEN];
--- 216,254 ----
  }
  
  /*
+  * When calling eval_expr_typval() many times we only need one funccall_T.
+  * Returns NULL when no funccall_T is to be used.
+  * When returning non-NULL remove_funccal() must be called later.
+  */
+     funccall_T *
+ eval_expr_get_funccal(typval_T *expr, typval_T *rettv)
+ {
+     if (expr->v_type != VAR_PARTIAL)
+       return NULL;
+ 
+     partial_T *partial = expr->vval.v_partial;
+     if (partial == NULL)
+       return NULL;
+     if (partial->pt_func == NULL
+           || partial->pt_func->uf_def_status == UF_NOT_COMPILED)
+       return NULL;
+ 
+     return create_funccal(partial->pt_func, rettv);
+ }
+ 
+ /*
   * Evaluate an expression, which can be a function, partial or string.
   * Pass arguments "argv[argc]".
+  * "fc_arg" is from eval_expr_get_funccal() or NULL;
   * Return the result in "rettv" and OK or FAIL.
   */
      int
! eval_expr_typval(
!       typval_T    *expr,
!       typval_T    *argv,
!       int         argc,
!       funccall_T  *fc_arg,
!       typval_T    *rettv)
  {
      char_u    *s;
      char_u    buf[NUMBUFLEN];
***************
*** 247,253 ****
        if (partial->pt_func != NULL
                          && partial->pt_func->uf_def_status != UF_NOT_COMPILED)
        {
!           funccall_T  *fc = create_funccal(partial->pt_func, rettv);
            int         r;
  
            if (fc == NULL)
--- 274,281 ----
        if (partial->pt_func != NULL
                          && partial->pt_func->uf_def_status != UF_NOT_COMPILED)
        {
!           funccall_T  *fc = fc_arg != NULL ? fc_arg
!                                    : create_funccal(partial->pt_func, rettv);
            int         r;
  
            if (fc == NULL)
***************
*** 256,262 ****
            // Shortcut to call a compiled function with minimal overhead.
            r = call_def_function(partial->pt_func, argc, argv,
                                          DEF_USE_PT_ARGV, partial, fc, rettv);
!           remove_funccal();
            if (r == FAIL)
                return FAIL;
        }
--- 284,291 ----
            // Shortcut to call a compiled function with minimal overhead.
            r = call_def_function(partial->pt_func, argc, argv,
                                          DEF_USE_PT_ARGV, partial, fc, rettv);
!           if (fc_arg == NULL)
!               remove_funccal();
            if (r == FAIL)
                return FAIL;
        }
***************
*** 304,310 ****
      typval_T  rettv;
      int               res;
  
!     if (eval_expr_typval(expr, NULL, 0, &rettv) == FAIL)
      {
        *error = TRUE;
        return FALSE;
--- 333,339 ----
      typval_T  rettv;
      int               res;
  
!     if (eval_expr_typval(expr, NULL, 0, NULL, &rettv) == FAIL)
      {
        *error = TRUE;
        return FALSE;
*** ../vim-9.0.0617/src/proto/eval.pro  2022-08-18 13:28:27.720128098 +0100
--- src/proto/eval.pro  2022-09-28 15:53:38.936499273 +0100
***************
*** 6,12 ****
  void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip);
  int eval_to_bool(char_u *arg, int *error, exarg_T *eap, int skip);
  int eval_expr_valid_arg(typval_T *tv);
! int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T 
*rettv);
  int eval_expr_to_bool(typval_T *expr, int *error);
  char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
  void init_evalarg(evalarg_T *evalarg);
--- 6,13 ----
  void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip);
  int eval_to_bool(char_u *arg, int *error, exarg_T *eap, int skip);
  int eval_expr_valid_arg(typval_T *tv);
! funccall_T *eval_expr_get_funccal(typval_T *expr, typval_T *rettv);
! int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, funccall_T 
*fc_arg, typval_T *rettv);
  int eval_expr_to_bool(typval_T *expr, int *error);
  char_u *eval_to_string_skip(char_u *arg, exarg_T *eap, int skip);
  void init_evalarg(evalarg_T *evalarg);
*** ../vim-9.0.0617/src/list.c  2022-09-28 15:19:06.462869991 +0100
--- src/list.c  2022-09-28 16:07:19.418424042 +0100
***************
*** 2320,2325 ****
--- 2320,2326 ----
        typval_T        *tv,        // original value
        typval_T        *expr,      // callback
        filtermap_T     filtermap,
+       funccall_T      *fc,        // from eval_expr_get_funccal()
        typval_T        *newtv,     // for map() and mapnew(): new value
        int             *remp)      // for filter(): remove flag
  {
***************
*** 2329,2335 ****
      copy_tv(tv, get_vim_var_tv(VV_VAL));
      argv[0] = *get_vim_var_tv(VV_KEY);
      argv[1] = *get_vim_var_tv(VV_VAL);
!     if (eval_expr_typval(expr, argv, 2, newtv) == FAIL)
        goto theend;
      if (filtermap == FILTERMAP_FILTER)
      {
--- 2330,2336 ----
      copy_tv(tv, get_vim_var_tv(VV_VAL));
      argv[0] = *get_vim_var_tv(VV_KEY);
      argv[1] = *get_vim_var_tv(VV_VAL);
!     if (eval_expr_typval(expr, argv, 2, fc, newtv) == FAIL)
        goto theend;
      if (filtermap == FILTERMAP_FILTER)
      {
***************
*** 2371,2376 ****
--- 2372,2379 ----
      int               idx = 0;
      int               rem;
      listitem_T        *li, *nli;
+     typval_T  newtv;
+     funccall_T        *fc;
  
      if (filtermap == FILTERMAP_MAPNEW)
      {
***************
*** 2395,2400 ****
--- 2398,2406 ----
      if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0)
        l->lv_lock = VAR_LOCKED;
  
+     // Create one funccal_T for all eval_expr_typval() calls.
+     fc = eval_expr_get_funccal(expr, &newtv);
+ 
      if (l->lv_first == &range_list_item)
      {
        varnumber_T     val = l->lv_u.nonmat.lv_start;
***************
*** 2413,2425 ****
        for (idx = 0; idx < len; ++idx)
        {
            typval_T tv;
-           typval_T newtv;
  
            tv.v_type = VAR_NUMBER;
            tv.v_lock = 0;
            tv.vval.v_number = val;
            set_vim_var_nr(VV_KEY, idx);
!           if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL)
                break;
            if (did_emsg)
            {
--- 2419,2430 ----
        for (idx = 0; idx < len; ++idx)
        {
            typval_T tv;
  
            tv.v_type = VAR_NUMBER;
            tv.v_lock = 0;
            tv.vval.v_number = val;
            set_vim_var_nr(VV_KEY, idx);
!           if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL)
                break;
            if (did_emsg)
            {
***************
*** 2457,2471 ****
        // Materialized list: loop over the items
        for (li = l->lv_first; li != NULL; li = nli)
        {
-           typval_T newtv;
- 
            if (filtermap == FILTERMAP_MAP && value_check_lock(
                        li->li_tv.v_lock, arg_errmsg, TRUE))
                break;
            nli = li->li_next;
            set_vim_var_nr(VV_KEY, idx);
!           if (filter_map_one(&li->li_tv, expr, filtermap,
!                       &newtv, &rem) == FAIL)
                break;
            if (did_emsg)
            {
--- 2462,2474 ----
        // Materialized list: loop over the items
        for (li = l->lv_first; li != NULL; li = nli)
        {
            if (filtermap == FILTERMAP_MAP && value_check_lock(
                        li->li_tv.v_lock, arg_errmsg, TRUE))
                break;
            nli = li->li_next;
            set_vim_var_nr(VV_KEY, idx);
!           if (filter_map_one(&li->li_tv, expr, filtermap, fc,
!                                                        &newtv, &rem) == FAIL)
                break;
            if (did_emsg)
            {
***************
*** 2498,2503 ****
--- 2501,2508 ----
      }
  
      l->lv_lock = prev_lock;
+     if (fc != NULL)
+       remove_funccal();
  }
  
  /*
***************
*** 3018,3023 ****
--- 3023,3029 ----
      int               r;
      int               called_emsg_start = called_emsg;
      int               prev_locked;
+     funccall_T        *fc;
  
      // Using reduce on a range() uses "range_idx" and "range_val".
      range_list = l != NULL && l->lv_first == &range_list_item;
***************
*** 3055,3060 ****
--- 3061,3069 ----
      if (l == NULL)
        return;
  
+     // Create one funccal_T for all eval_expr_typval() calls.
+     fc = eval_expr_get_funccal(expr, rettv);
+ 
      prev_locked = l->lv_lock;
      l->lv_lock = VAR_FIXED;  // disallow the list changing here
  
***************
*** 3071,3077 ****
        else
            argv[1] = li->li_tv;
  
!       r = eval_expr_typval(expr, argv, 2, rettv);
  
        if (argv[0].v_type != VAR_NUMBER && argv[0].v_type != VAR_UNKNOWN)
            clear_tv(&argv[0]);
--- 3080,3086 ----
        else
            argv[1] = li->li_tv;
  
!       r = eval_expr_typval(expr, argv, 2, fc, rettv);
  
        if (argv[0].v_type != VAR_NUMBER && argv[0].v_type != VAR_UNKNOWN)
            clear_tv(&argv[0]);
***************
*** 3088,3093 ****
--- 3097,3105 ----
            li = li->li_next;
      }
  
+     if (fc != NULL)
+       remove_funccal();
+ 
      l->lv_lock = prev_locked;
  }
  
*** ../vim-9.0.0617/src/proto/list.pro  2022-08-30 17:45:28.787606578 +0100
--- src/proto/list.pro  2022-09-28 16:05:50.542856457 +0100
***************
*** 52,58 ****
  void f_list2str(typval_T *argvars, typval_T *rettv);
  void f_sort(typval_T *argvars, typval_T *rettv);
  void f_uniq(typval_T *argvars, typval_T *rettv);
! int filter_map_one(typval_T *tv, typval_T *expr, filtermap_T filtermap, 
typval_T *newtv, int *remp);
  void f_filter(typval_T *argvars, typval_T *rettv);
  void f_map(typval_T *argvars, typval_T *rettv);
  void f_mapnew(typval_T *argvars, typval_T *rettv);
--- 52,58 ----
  void f_list2str(typval_T *argvars, typval_T *rettv);
  void f_sort(typval_T *argvars, typval_T *rettv);
  void f_uniq(typval_T *argvars, typval_T *rettv);
! int filter_map_one(typval_T *tv, typval_T *expr, filtermap_T filtermap, 
funccall_T *fc, typval_T *newtv, int *remp);
  void f_filter(typval_T *argvars, typval_T *rettv);
  void f_map(typval_T *argvars, typval_T *rettv);
  void f_mapnew(typval_T *argvars, typval_T *rettv);
*** ../vim-9.0.0617/src/blob.c  2022-09-27 11:46:35.151438619 +0100
--- src/blob.c  2022-09-28 16:06:20.502706906 +0100
***************
*** 559,564 ****
--- 559,566 ----
      blob_T    *b_ret;
      int               idx = 0;
      int               rem;
+     typval_T  newtv;
+     funccall_T        *fc;
  
      if (filtermap == FILTERMAP_MAPNEW)
      {
***************
*** 579,593 ****
      // set_vim_var_nr() doesn't set the type
      set_vim_var_type(VV_KEY, VAR_NUMBER);
  
      for (i = 0; i < b->bv_ga.ga_len; i++)
      {
-       typval_T newtv;
- 
        tv.v_type = VAR_NUMBER;
        val = blob_get(b, i);
        tv.vval.v_number = val;
        set_vim_var_nr(VV_KEY, idx);
!       if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL
                || did_emsg)
            break;
        if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL)
--- 581,596 ----
      // set_vim_var_nr() doesn't set the type
      set_vim_var_type(VV_KEY, VAR_NUMBER);
  
+     // Create one funccal_T for all eval_expr_typval() calls.
+     fc = eval_expr_get_funccal(expr, &newtv);
+ 
      for (i = 0; i < b->bv_ga.ga_len; i++)
      {
        tv.v_type = VAR_NUMBER;
        val = blob_get(b, i);
        tv.vval.v_number = val;
        set_vim_var_nr(VV_KEY, idx);
!       if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL
                || did_emsg)
            break;
        if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL)
***************
*** 612,617 ****
--- 615,623 ----
        }
        ++idx;
      }
+ 
+     if (fc != NULL)
+       remove_funccal();
  }
  
  /*
***************
*** 714,720 ****
        argv[1].v_type = VAR_NUMBER;
        argv[1].vval.v_number = blob_get(b, i);
  
!       r = eval_expr_typval(expr, argv, 2, rettv);
  
        clear_tv(&argv[0]);
        if (r == FAIL || called_emsg != called_emsg_start)
--- 720,726 ----
        argv[1].v_type = VAR_NUMBER;
        argv[1].vval.v_number = blob_get(b, i);
  
!       r = eval_expr_typval(expr, argv, 2, NULL, rettv);
  
        clear_tv(&argv[0]);
        if (r == FAIL || called_emsg != called_emsg_start)
*** ../vim-9.0.0617/src/evalfunc.c      2022-09-20 19:04:27.432762804 +0100
--- src/evalfunc.c      2022-09-28 15:49:08.272788713 +0100
***************
*** 6740,6746 ****
      argv[1] = *get_vim_var_tv(VV_VAL);
      newtv.v_type = VAR_UNKNOWN;
  
!     if (eval_expr_typval(expr, argv, 2, &newtv) == FAIL)
        return FALSE;
  
      found = tv_get_bool_chk(&newtv, &error);
--- 6740,6746 ----
      argv[1] = *get_vim_var_tv(VV_VAL);
      newtv.v_type = VAR_UNKNOWN;
  
!     if (eval_expr_typval(expr, argv, 2, NULL, &newtv) == FAIL)
        return FALSE;
  
      found = tv_get_bool_chk(&newtv, &error);
*** ../vim-9.0.0617/src/filepath.c      2022-09-07 21:30:40.139379052 +0100
--- src/filepath.c      2022-09-28 15:49:23.788773947 +0100
***************
*** 1609,1615 ****
        argv[0].vval.v_dict = dict;
      }
  
!     if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
        goto theend;
  
      // We want to use -1, but also true/false should be allowed.
--- 1609,1615 ----
        argv[0].vval.v_dict = dict;
      }
  
!     if (eval_expr_typval(expr, argv, 1, NULL, &rettv) == FAIL)
        goto theend;
  
      // We want to use -1, but also true/false should be allowed.
*** ../vim-9.0.0617/src/strings.c       2022-09-22 17:06:56.295037465 +0100
--- src/strings.c       2022-09-28 16:07:30.590371953 +0100
***************
*** 882,887 ****
--- 882,889 ----
      int               len = 0;
      int               idx = 0;
      int               rem;
+     typval_T  newtv;
+     funccall_T        *fc;
  
      rettv->v_type = VAR_STRING;
      rettv->vval.v_string = NULL;
***************
*** 889,906 ****
      // set_vim_var_nr() doesn't set the type
      set_vim_var_type(VV_KEY, VAR_NUMBER);
  
      ga_init2(&ga, sizeof(char), 80);
      for (p = str; *p != NUL; p += len)
      {
-       typval_T newtv;
- 
        if (copy_first_char_to_tv(p, &tv) == FAIL)
            break;
        len = (int)STRLEN(tv.vval.v_string);
  
        newtv.v_type = VAR_UNKNOWN;
        set_vim_var_nr(VV_KEY, idx);
!       if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL
                || did_emsg)
        {
            clear_tv(&newtv);
--- 891,909 ----
      // set_vim_var_nr() doesn't set the type
      set_vim_var_type(VV_KEY, VAR_NUMBER);
  
+     // Create one funccal_T for all eval_expr_typval() calls.
+     fc = eval_expr_get_funccal(expr, &newtv);
+ 
      ga_init2(&ga, sizeof(char), 80);
      for (p = str; *p != NUL; p += len)
      {
        if (copy_first_char_to_tv(p, &tv) == FAIL)
            break;
        len = (int)STRLEN(tv.vval.v_string);
  
        newtv.v_type = VAR_UNKNOWN;
        set_vim_var_nr(VV_KEY, idx);
!       if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL
                || did_emsg)
        {
            clear_tv(&newtv);
***************
*** 929,934 ****
--- 932,939 ----
      }
      ga_append(&ga, NUL);
      rettv->vval.v_string = ga.ga_data;
+     if (fc != NULL)
+       remove_funccal();
  }
  
  /*
***************
*** 947,952 ****
--- 952,958 ----
      typval_T  argv[3];
      int               r;
      int               called_emsg_start = called_emsg;
+     funccall_T        *fc;
  
      if (argvars[2].v_type == VAR_UNKNOWN)
      {
***************
*** 964,969 ****
--- 970,978 ----
      else
        copy_tv(&argvars[2], rettv);
  
+     // Create one funccal_T for all eval_expr_typval() calls.
+     fc = eval_expr_get_funccal(expr, rettv);
+ 
      for ( ; *p != NUL; p += len)
      {
        argv[0] = *rettv;
***************
*** 971,983 ****
            break;
        len = (int)STRLEN(argv[1].vval.v_string);
  
!       r = eval_expr_typval(expr, argv, 2, rettv);
  
        clear_tv(&argv[0]);
        clear_tv(&argv[1]);
        if (r == FAIL || called_emsg != called_emsg_start)
            return;
      }
  }
  
      static void
--- 980,995 ----
            break;
        len = (int)STRLEN(argv[1].vval.v_string);
  
!       r = eval_expr_typval(expr, argv, 2, fc, rettv);
  
        clear_tv(&argv[0]);
        clear_tv(&argv[1]);
        if (r == FAIL || called_emsg != called_emsg_start)
            return;
      }
+ 
+     if (fc != NULL)
+       remove_funccal();
  }
  
      static void
*** ../vim-9.0.0617/src/dict.c  2022-09-17 21:07:52.091993174 +0100
--- src/dict.c  2022-09-28 16:06:44.234591237 +0100
***************
*** 1315,1320 ****
--- 1315,1322 ----
      dictitem_T        *di;
      int               todo;
      int               rem;
+     typval_T  newtv;
+     funccall_T        *fc;
  
      if (filtermap == FILTERMAP_MAPNEW)
      {
***************
*** 1335,1340 ****
--- 1337,1345 ----
        d_ret = rettv->vval.v_dict;
      }
  
+     // Create one funccal_T for all eval_expr_typval() calls.
+     fc = eval_expr_get_funccal(expr, &newtv);
+ 
      if (filtermap != FILTERMAP_FILTER && d->dv_lock == 0)
        d->dv_lock = VAR_LOCKED;
      ht = &d->dv_hashtab;
***************
*** 1345,1351 ****
        if (!HASHITEM_EMPTY(hi))
        {
            int         r;
-           typval_T    newtv;
  
            --todo;
            di = HI2DI(hi);
--- 1350,1355 ----
***************
*** 1357,1364 ****
                break;
            set_vim_var_string(VV_KEY, di->di_key, -1);
            newtv.v_type = VAR_UNKNOWN;
!           r = filter_map_one(&di->di_tv, expr, filtermap,
!                   &newtv, &rem);
            clear_tv(get_vim_var_tv(VV_KEY));
            if (r == FAIL || did_emsg)
            {
--- 1361,1367 ----
                break;
            set_vim_var_string(VV_KEY, di->di_key, -1);
            newtv.v_type = VAR_UNKNOWN;
!           r = filter_map_one(&di->di_tv, expr, filtermap, fc, &newtv, &rem);
            clear_tv(get_vim_var_tv(VV_KEY));
            if (r == FAIL || did_emsg)
            {
***************
*** 1398,1403 ****
--- 1401,1408 ----
      }
      hash_unlock(ht);
      d->dv_lock = prev_lock;
+     if (fc != NULL)
+       remove_funccal();
  }
  
  /*
*** ../vim-9.0.0617/src/version.c       2022-09-28 15:19:06.466869975 +0100
--- src/version.c       2022-09-28 16:07:51.334276486 +0100
***************
*** 701,702 ****
--- 701,704 ----
  {   /* Add new patch number below this line */
+ /**/
+     618,
  /**/

-- 
Your mouse has moved.  Windows must be restarted for the change
to take effect.  Reboot now?

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220928151718.8E86C1C044A%40moolenaar.net.

Raspunde prin e-mail lui