Patch 8.2.0499
Problem:    Calling a lambda is slower than evaluating a string.
Solution:   Make calling a lambda faster. (Ken Takata, closes #5727)
Files:      src/userfunc.c


*** ../vim-8.2.0498/src/userfunc.c      2020-03-28 21:38:02.128802283 +0100
--- src/userfunc.c      2020-04-02 18:32:54.399903028 +0200
***************
*** 24,29 ****
--- 24,30 ----
  #define FC_SANDBOX  0x40      // function defined in the sandbox
  #define FC_DEAD           0x80        // function kept only for reference to 
dfunc
  #define FC_EXPORT   0x100     // "export def Func()"
+ #define FC_NOARGS   0x200     // no a: variables in lambda
  
  /*
   * All user-defined functions are found in this hashtable.
***************
*** 384,389 ****
--- 385,393 ----
        ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
        STRCPY(p, "return ");
        vim_strncpy(p + 7, s, e - s);
+       if (strstr((char *)p + 7, "a:") == NULL)
+           // No a: variables are used for sure.
+           flags |= FC_NOARGS;
  
        fp->uf_refcount = 1;
        set_ufunc_name(fp, name);
***************
*** 1106,1130 ****
      }
  
      /*
!      * Init a: variables.
       * Set a:0 to "argcount" less number of named arguments, if >= 0.
       * Set a:000 to a list with room for the "..." arguments.
       */
      init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE);
!     add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "0",
                                (varnumber_T)(argcount >= fp->uf_args.ga_len
                                    ? argcount - fp->uf_args.ga_len : 0));
      fc->l_avars.dv_lock = VAR_FIXED;
!     // Use "name" to avoid a warning from some compiler that checks the
!     // destination size.
!     v = &fc->fixvar[fixvar_idx++].var;
!     name = v->di_key;
!     STRCPY(name, "000");
!     v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
!     hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v));
!     v->di_tv.v_type = VAR_LIST;
!     v->di_tv.v_lock = VAR_FIXED;
!     v->di_tv.vval.v_list = &fc->l_varlist;
      vim_memset(&fc->l_varlist, 0, sizeof(list_T));
      fc->l_varlist.lv_refcount = DO_NOT_FREE_CNT;
      fc->l_varlist.lv_lock = VAR_FIXED;
--- 1110,1138 ----
      }
  
      /*
!      * Init a: variables, unless none found (in lambda).
       * Set a:0 to "argcount" less number of named arguments, if >= 0.
       * Set a:000 to a list with room for the "..." arguments.
       */
      init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE);
!     if ((fp->uf_flags & FC_NOARGS) == 0)
!       add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "0",
                                (varnumber_T)(argcount >= fp->uf_args.ga_len
                                    ? argcount - fp->uf_args.ga_len : 0));
      fc->l_avars.dv_lock = VAR_FIXED;
!     if ((fp->uf_flags & FC_NOARGS) == 0)
!     {
!       // Use "name" to avoid a warning from some compiler that checks the
!       // destination size.
!       v = &fc->fixvar[fixvar_idx++].var;
!       name = v->di_key;
!       STRCPY(name, "000");
!       v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
!       hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v));
!       v->di_tv.v_type = VAR_LIST;
!       v->di_tv.v_lock = VAR_FIXED;
!       v->di_tv.vval.v_list = &fc->l_varlist;
!     }
      vim_memset(&fc->l_varlist, 0, sizeof(list_T));
      fc->l_varlist.lv_refcount = DO_NOT_FREE_CNT;
      fc->l_varlist.lv_lock = VAR_FIXED;
***************
*** 1133,1143 ****
       * Set a:firstline to "firstline" and a:lastline to "lastline".
       * Set a:name to named arguments.
       * Set a:N to the "..." arguments.
       */
!     add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "firstline",
                                                      (varnumber_T)firstline);
!     add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline",
                                                       (varnumber_T)lastline);
      for (i = 0; i < argcount || i < fp->uf_args.ga_len; ++i)
      {
        int         addlocal = FALSE;
--- 1141,1155 ----
       * Set a:firstline to "firstline" and a:lastline to "lastline".
       * Set a:name to named arguments.
       * Set a:N to the "..." arguments.
+      * Skipped when no a: variables used (in lambda).
       */
!     if ((fp->uf_flags & FC_NOARGS) == 0)
!     {
!       add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "firstline",
                                                      (varnumber_T)firstline);
!       add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline",
                                                       (varnumber_T)lastline);
+     }
      for (i = 0; i < argcount || i < fp->uf_args.ga_len; ++i)
      {
        int         addlocal = FALSE;
***************
*** 1173,1178 ****
--- 1185,1194 ----
        }
        else
        {
+           if ((fp->uf_flags & FC_NOARGS) != 0)
+               // Bail out if no a: arguments used (in lambda).
+               break;
+ 
            // "..." argument a:1, a:2, etc.
            sprintf((char *)numbuf, "%d", ai + 1);
            name = numbuf;
***************
*** 1298,1303 ****
--- 1314,1329 ----
  
      if (default_arg_err && (fp->uf_flags & FC_ABORT))
        did_emsg = TRUE;
+     else if (islambda)
+     {
+       char_u *p = *(char_u **)fp->uf_lines.ga_data + 7;
+ 
+       // A Lambda always has the command "return {expr}".  It is much faster
+       // to evaluate {expr} directly.
+       ++ex_nesting_level;
+       eval1(&p, rettv, TRUE);
+       --ex_nesting_level;
+     }
      else
        // call do_cmdline() to execute the lines
        do_cmdline(NULL, get_func_line, (void *)fc,
***************
*** 1734,1744 ****
      int               ret = FAIL;
      int               error = FCERR_NONE;
      int               i;
!     ufunc_T   *fp;
      char_u    fname_buf[FLEN_FIXED + 1];
      char_u    *tofree = NULL;
!     char_u    *fname;
!     char_u    *name;
      int               argcount = argcount_in;
      typval_T  *argvars = argvars_in;
      dict_T    *selfdict = funcexe->selfdict;
--- 1760,1770 ----
      int               ret = FAIL;
      int               error = FCERR_NONE;
      int               i;
!     ufunc_T   *fp = NULL;
      char_u    fname_buf[FLEN_FIXED + 1];
      char_u    *tofree = NULL;
!     char_u    *fname = NULL;
!     char_u    *name = NULL;
      int               argcount = argcount_in;
      typval_T  *argvars = argvars_in;
      dict_T    *selfdict = funcexe->selfdict;
***************
*** 1752,1764 ****
      // even when call_func() returns FAIL.
      rettv->v_type = VAR_UNKNOWN;
  
!     // Make a copy of the name, if it comes from a funcref variable it could
!     // be changed or deleted in the called function.
!     name = len > 0 ? vim_strnsave(funcname, len) : vim_strsave(funcname);
!     if (name == NULL)
!       return ret;
  
!     fname = fname_trans_sid(name, fname_buf, &tofree, &error);
  
      if (funcexe->doesrange != NULL)
        *funcexe->doesrange = FALSE;
--- 1778,1795 ----
      // even when call_func() returns FAIL.
      rettv->v_type = VAR_UNKNOWN;
  
!     if (partial != NULL)
!       fp = partial->pt_func;
!     if (fp == NULL)
!     {
!       // Make a copy of the name, if it comes from a funcref variable it
!       // could be changed or deleted in the called function.
!       name = len > 0 ? vim_strnsave(funcname, len) : vim_strsave(funcname);
!       if (name == NULL)
!           return ret;
  
!       fname = fname_trans_sid(name, fname_buf, &tofree, &error);
!     }
  
      if (funcexe->doesrange != NULL)
        *funcexe->doesrange = FALSE;
***************
*** 1793,1813 ****
        char_u *rfname = fname;
  
        // Ignore "g:" before a function name.
!       if (fname[0] == 'g' && fname[1] == ':')
            rfname = fname + 2;
  
        rettv->v_type = VAR_NUMBER;     // default rettv is number zero
        rettv->vval.v_number = 0;
        error = FCERR_UNKNOWN;
  
!       if (!builtin_function(rfname, -1))
        {
            /*
             * User defined function.
             */
!           if (partial != NULL && partial->pt_func != NULL)
!               fp = partial->pt_func;
!           else
                fp = find_func(rfname, NULL);
  
            // Trigger FuncUndefined event, may load the function.
--- 1824,1842 ----
        char_u *rfname = fname;
  
        // Ignore "g:" before a function name.
!       if (fp == NULL && fname[0] == 'g' && fname[1] == ':')
            rfname = fname + 2;
  
        rettv->v_type = VAR_NUMBER;     // default rettv is number zero
        rettv->vval.v_number = 0;
        error = FCERR_UNKNOWN;
  
!       if (fp != NULL || !builtin_function(rfname, -1))
        {
            /*
             * User defined function.
             */
!           if (fp == NULL)
                fp = find_func(rfname, NULL);
  
            // Trigger FuncUndefined event, may load the function.
***************
*** 1887,1893 ****
       */
      if (!aborting())
      {
!       user_func_error(error, name);
      }
  
      // clear the copies made from the partial
--- 1916,1922 ----
       */
      if (!aborting())
      {
!       user_func_error(error, (name != NULL) ? name : funcname);
      }
  
      // clear the copies made from the partial
*** ../vim-8.2.0498/src/version.c       2020-04-02 16:00:01.120265119 +0200
--- src/version.c       2020-04-02 18:33:38.647723434 +0200
***************
*** 740,741 ****
--- 740,743 ----
  {   /* Add new patch number below this line */
+ /**/
+     499,
  /**/

-- 
Veni, Vidi, VW -- I came, I saw, I drove around in a little car.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            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/202004021635.032GZcDn026449%40masaka.moolenaar.net.

Raspunde prin e-mail lui