Patch 8.2.1023
Problem:    Vim9: redefining a function uses a new index every time.
Solution:   When redefining a function clear the contents and re-use the
            index.
Files:      src/vim9compile.c, src/proto/vim9compile.pro, src/userfunc.c,
            src/structs.h, src/eval.c, src/evalvars.c, src/vim9execute.c


*** ../vim-8.2.1022/src/vim9compile.c   2020-06-20 13:28:59.789336842 +0200
--- src/vim9compile.c   2020-06-20 18:08:25.626738128 +0200
***************
*** 1493,1499 ****
        return FAIL;
      }
  
!     if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED)
      {
        int             i;
  
--- 1493,1499 ----
        return FAIL;
      }
  
!     if (ufunc->uf_def_status != UF_NOT_COMPILED)
      {
        int             i;
  
***************
*** 1517,1532 ****
                return FAIL;
            }
        }
!       if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED)
            if (compile_def_function(ufunc, TRUE, NULL) == FAIL)
                return FAIL;
      }
  
      if ((isn = generate_instr(cctx,
!                   ufunc->uf_dfunc_idx != UF_NOT_COMPILED ? ISN_DCALL
                                                         : ISN_UCALL)) == NULL)
        return FAIL;
!     if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED)
      {
        isn->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
        isn->isn_arg.dfunc.cdf_argcount = argcount;
--- 1517,1532 ----
                return FAIL;
            }
        }
!       if (ufunc->uf_def_status == UF_TO_BE_COMPILED)
            if (compile_def_function(ufunc, TRUE, NULL) == FAIL)
                return FAIL;
      }
  
      if ((isn = generate_instr(cctx,
!                   ufunc->uf_def_status != UF_NOT_COMPILED ? ISN_DCALL
                                                         : ISN_UCALL)) == NULL)
        return FAIL;
!     if (ufunc->uf_def_status != UF_NOT_COMPILED)
      {
        isn->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
        isn->isn_arg.dfunc.cdf_argcount = argcount;
***************
*** 3042,3048 ****
      // Compile it into instructions.
      compile_def_function(ufunc, TRUE, cctx);
  
!     if (ufunc->uf_dfunc_idx >= 0)
        return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx);
      return FAIL;
  }
--- 3042,3048 ----
      // Compile it into instructions.
      compile_def_function(ufunc, TRUE, cctx);
  
!     if (ufunc->uf_def_status == UF_COMPILED)
        return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx);
      return FAIL;
  }
***************
*** 4539,4545 ****
  
      if (ufunc == NULL)
        return NULL;
!     if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
            && compile_def_function(ufunc, TRUE, cctx) == FAIL)
        return NULL;
  
--- 4539,4545 ----
  
      if (ufunc == NULL)
        return NULL;
!     if (ufunc->uf_def_status == UF_TO_BE_COMPILED
            && compile_def_function(ufunc, TRUE, cctx) == FAIL)
        return NULL;
  
***************
*** 6517,6529 ****
  
  /*
   * Add a function to the list of :def functions.
!  * This "sets ufunc->uf_dfunc_idx" but the function isn't compiled yet.
   */
      static int
  add_def_function(ufunc_T *ufunc)
  {
      dfunc_T *dfunc;
  
      // Add the function to "def_functions".
      if (ga_grow(&def_functions, 1) == FAIL)
        return FAIL;
--- 6517,6538 ----
  
  /*
   * Add a function to the list of :def functions.
!  * This sets "ufunc->uf_dfunc_idx" but the function isn't compiled yet.
   */
      static int
  add_def_function(ufunc_T *ufunc)
  {
      dfunc_T *dfunc;
  
+     if (def_functions.ga_len == 0)
+     {
+       // The first position is not used, so that a zero uf_dfunc_idx means it
+       // wasn't set.
+       if (ga_grow(&def_functions, 1) == FAIL)
+           return FAIL;
+       ++def_functions.ga_len;
+     }
+ 
      // Add the function to "def_functions".
      if (ga_grow(&def_functions, 1) == FAIL)
        return FAIL;
***************
*** 6563,6569 ****
  
      // When using a function that was compiled before: Free old instructions.
      // Otherwise add a new entry in "def_functions".
!     if (ufunc->uf_dfunc_idx >= 0)
      {
        dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
--- 6572,6578 ----
  
      // When using a function that was compiled before: Free old instructions.
      // Otherwise add a new entry in "def_functions".
!     if (ufunc->uf_dfunc_idx > 0)
      {
        dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
***************
*** 7014,7019 ****
--- 7023,7029 ----
        dfunc->df_closure_count = cctx.ctx_closure_count;
        if (cctx.ctx_outer_used)
            ufunc->uf_flags |= FC_CLOSURE;
+       ufunc->uf_def_status = UF_COMPILED;
      }
  
      ret = OK;
***************
*** 7033,7039 ****
        if (!dfunc->df_deleted
                            && ufunc->uf_dfunc_idx == def_functions.ga_len - 1)
            --def_functions.ga_len;
!       ufunc->uf_dfunc_idx = UF_NOT_COMPILED;
  
        while (cctx.ctx_scope != NULL)
            drop_scope(&cctx);
--- 7043,7049 ----
        if (!dfunc->df_deleted
                            && ufunc->uf_dfunc_idx == def_functions.ga_len - 1)
            --def_functions.ga_len;
!       ufunc->uf_def_status = UF_NOT_COMPILED;
  
        while (cctx.ctx_scope != NULL)
            drop_scope(&cctx);
***************
*** 7261,7277 ****
  }
  
  /*
!  * When a user function is deleted, delete any associated def function.
   */
      void
! delete_def_function(ufunc_T *ufunc)
  {
!     if (ufunc->uf_dfunc_idx >= 0)
      {
        dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
  
        delete_def_function_contents(dfunc);
      }
  }
  
--- 7271,7289 ----
  }
  
  /*
!  * When a user function is deleted, clear the contents of any associated def
!  * function.  The position in def_functions can be re-used.
   */
      void
! clear_def_function(ufunc_T *ufunc)
  {
!     if (ufunc->uf_dfunc_idx > 0)
      {
        dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
                                                         + ufunc->uf_dfunc_idx;
  
        delete_def_function_contents(dfunc);
+       ufunc->uf_def_status = UF_NOT_COMPILED;
      }
  }
  
*** ../vim-8.2.1022/src/proto/vim9compile.pro   2020-06-13 19:00:06.887160162 
+0200
--- src/proto/vim9compile.pro   2020-06-20 17:09:03.149877236 +0200
***************
*** 14,19 ****
  int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T 
*outer_cctx);
  void set_function_type(ufunc_T *ufunc);
  void delete_instr(isn_T *isn);
! void delete_def_function(ufunc_T *ufunc);
  void free_def_functions(void);
  /* vim: set ft=c : */
--- 14,19 ----
  int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T 
*outer_cctx);
  void set_function_type(ufunc_T *ufunc);
  void delete_instr(isn_T *isn);
! void clear_def_function(ufunc_T *ufunc);
  void free_def_functions(void);
  /* vim: set ft=c : */
*** ../vim-8.2.1022/src/userfunc.c      2020-06-12 22:59:07.274097177 +0200
--- src/userfunc.c      2020-06-20 18:03:30.735597023 +0200
***************
*** 409,415 ****
        fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
        if (fp == NULL)
            goto errret;
!       fp->uf_dfunc_idx = UF_NOT_COMPILED;
        pt = ALLOC_CLEAR_ONE(partial_T);
        if (pt == NULL)
            goto errret;
--- 409,415 ----
        fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
        if (fp == NULL)
            goto errret;
!       fp->uf_def_status = UF_NOT_COMPILED;
        pt = ALLOC_CLEAR_ONE(partial_T);
        if (pt == NULL)
            goto errret;
***************
*** 1001,1007 ****
      {
        // When there is a def-function index do not actually remove the
        // function, so we can find the index when defining the function again.
!       if (fp->uf_dfunc_idx >= 0)
            fp->uf_flags |= FC_DEAD;
        else
            hash_remove(&func_hashtab, hi);
--- 1001,1007 ----
      {
        // When there is a def-function index do not actually remove the
        // function, so we can find the index when defining the function again.
!       if (fp->uf_def_status == UF_COMPILED)
            fp->uf_flags |= FC_DEAD;
        else
            hash_remove(&func_hashtab, hi);
***************
*** 1046,1052 ****
      // clear this function
      func_clear_items(fp);
      funccal_unref(fp->uf_scoped, fp, force);
!     delete_def_function(fp);
  }
  
  /*
--- 1046,1052 ----
      // clear this function
      func_clear_items(fp);
      funccal_unref(fp->uf_scoped, fp, force);
!     clear_def_function(fp);
  }
  
  /*
***************
*** 1074,1080 ****
  func_clear_free(ufunc_T *fp, int force)
  {
      func_clear(fp, force);
!     func_free(fp, force);
  }
  
  
--- 1074,1081 ----
  func_clear_free(ufunc_T *fp, int force)
  {
      func_clear(fp, force);
!     if (force || fp->uf_dfunc_idx == 0)
!       func_free(fp, force);
  }
  
  
***************
*** 1137,1143 ****
      ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
      func_ptr_ref(fp);
  
!     if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
      {
        estack_push_ufunc(fp, 1);
        save_current_sctx = current_sctx;
--- 1138,1144 ----
      ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
      func_ptr_ref(fp);
  
!     if (fp->uf_def_status != UF_NOT_COMPILED)
      {
        estack_push_ufunc(fp, 1);
        save_current_sctx = current_sctx;
***************
*** 1662,1668 ****
                // clear the def function index now
                fp = HI2UF(hi);
                fp->uf_flags &= ~FC_DEAD;
!               fp->uf_dfunc_idx = UF_NOT_COMPILED;
  
                // Only free functions that are not refcounted, those are
                // supposed to be freed when no longer referenced.
--- 1663,1669 ----
                // clear the def function index now
                fp = HI2UF(hi);
                fp->uf_flags &= ~FC_DEAD;
!               fp->uf_def_status = UF_NOT_COMPILED;
  
                // Only free functions that are not refcounted, those are
                // supposed to be freed when no longer referenced.
***************
*** 2058,2064 ****
      msg_start();
      if (indent)
        msg_puts("   ");
!     if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
        msg_puts("def ");
      else
        msg_puts("function ");
--- 2059,2065 ----
      msg_start();
      if (indent)
        msg_puts("   ");
!     if (fp->uf_def_status != UF_NOT_COMPILED)
        msg_puts("def ");
      else
        msg_puts("function ");
***************
*** 2107,2113 ****
      }
      msg_putchar(')');
  
!     if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
      {
        if (fp->uf_ret_type != &t_void)
        {
--- 2108,2114 ----
      }
      msg_putchar(')');
  
!     if (fp->uf_def_status != UF_NOT_COMPILED)
      {
        if (fp->uf_ret_type != &t_void)
        {
***************
*** 2624,2630 ****
                if (!got_int)
                {
                    msg_putchar('\n');
!                   if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
                        msg_puts("   enddef");
                    else
                        msg_puts("   endfunction");
--- 2625,2631 ----
                if (!got_int)
                {
                    msg_putchar('\n');
!                   if (fp->uf_def_status != UF_NOT_COMPILED)
                        msg_puts("   enddef");
                    else
                        msg_puts("   endfunction");
***************
*** 3097,3102 ****
--- 3098,3104 ----
                fp->uf_profiling = FALSE;
                fp->uf_prof_initialized = FALSE;
  #endif
+               clear_def_function(fp);
            }
        }
      }
***************
*** 3162,3168 ****
        fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
        if (fp == NULL)
            goto erret;
!       fp->uf_dfunc_idx = eap->cmdidx == CMD_def ? UF_TO_BE_COMPILED
                                                             : UF_NOT_COMPILED;
  
        if (fudi.fd_dict != NULL)
--- 3164,3170 ----
        fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
        if (fp == NULL)
            goto erret;
!       fp->uf_def_status = eap->cmdidx == CMD_def ? UF_TO_BE_COMPILED
                                                             : UF_NOT_COMPILED;
  
        if (fudi.fd_dict != NULL)
***************
*** 3219,3225 ****
      {
        int     lnum_save = SOURCING_LNUM;
  
!       fp->uf_dfunc_idx = UF_TO_BE_COMPILED;
  
        // error messages are for the first function line
        SOURCING_LNUM = sourcing_lnum_top;
--- 3221,3227 ----
      {
        int     lnum_save = SOURCING_LNUM;
  
!       fp->uf_def_status = UF_TO_BE_COMPILED;
  
        // error messages are for the first function line
        SOURCING_LNUM = sourcing_lnum_top;
***************
*** 3289,3295 ****
        SOURCING_LNUM = lnum_save;
      }
      else
!       fp->uf_dfunc_idx = UF_NOT_COMPILED;
  
      fp->uf_lines = newlines;
      if ((flags & FC_CLOSURE) != 0)
--- 3291,3297 ----
        SOURCING_LNUM = lnum_save;
      }
      else
!       fp->uf_def_status = UF_NOT_COMPILED;
  
      fp->uf_lines = newlines;
      if ((flags & FC_CLOSURE) != 0)
***************
*** 3372,3378 ****
            --todo;
            ufunc = HI2UF(hi);
            if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
!                   && ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED)
            {
                compile_def_function(ufunc, FALSE, NULL);
  
--- 3374,3380 ----
            --todo;
            ufunc = HI2UF(hi);
            if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
!                   && ufunc->uf_def_status == UF_TO_BE_COMPILED)
            {
                compile_def_function(ufunc, FALSE, NULL);
  
*** ../vim-8.2.1022/src/structs.h       2020-06-10 22:11:59.922786692 +0200
--- src/structs.h       2020-06-20 17:23:33.607530399 +0200
***************
*** 1531,1538 ****
  typedef struct funccall_S funccall_T;
  
  // values used for "uf_dfunc_idx"
! # define UF_NOT_COMPILED -2
! # define UF_TO_BE_COMPILED -1
  
  /*
   * Structure to hold info for a user function.
--- 1531,1541 ----
  typedef struct funccall_S funccall_T;
  
  // values used for "uf_dfunc_idx"
! typedef enum {
!     UF_NOT_COMPILED,
!     UF_TO_BE_COMPILED,
!     UF_COMPILED
! } def_status_T;
  
  /*
   * Structure to hold info for a user function.
***************
*** 1543,1549 ****
      int               uf_flags;       // FC_ flags
      int               uf_calls;       // nr of active calls
      int               uf_cleared;     // func_clear() was already called
!     int               uf_dfunc_idx;   // UF_NOT_COMPILED, UF_TO_BE_COMPILED 
or >= 0
      garray_T  uf_args;        // arguments, including optional arguments
      garray_T  uf_def_args;    // default argument expressions
  
--- 1546,1553 ----
      int               uf_flags;       // FC_ flags
      int               uf_calls;       // nr of active calls
      int               uf_cleared;     // func_clear() was already called
!     def_status_T uf_def_status; // UF_NOT_COMPILED, UF_TO_BE_COMPILED, etc.
!     int               uf_dfunc_idx;   // only valid if uf_def_status is 
UF_COMPILED
      garray_T  uf_args;        // arguments, including optional arguments
      garray_T  uf_def_args;    // default argument expressions
  
*** ../vim-8.2.1022/src/eval.c  2020-06-16 11:34:38.314223444 +0200
--- src/eval.c  2020-06-20 17:18:11.624401510 +0200
***************
*** 253,259 ****
            return FAIL;
  
        if (partial->pt_func != NULL
!                         && partial->pt_func->uf_dfunc_idx != UF_NOT_COMPILED)
        {
            if (call_def_function(partial->pt_func, argc, argv,
                                                       partial, rettv) == FAIL)
--- 253,259 ----
            return FAIL;
  
        if (partial->pt_func != NULL
!                         && partial->pt_func->uf_def_status != UF_NOT_COMPILED)
        {
            if (call_def_function(partial->pt_func, argc, argv,
                                                       partial, rettv) == FAIL)
*** ../vim-8.2.1022/src/evalvars.c      2020-06-19 18:34:10.989945091 +0200
--- src/evalvars.c      2020-06-20 17:18:20.972376257 +0200
***************
*** 2628,2634 ****
      if (*name == 'v')                         // v: variable
        return &vimvarht;
      if (get_current_funccal() != NULL
!              && get_current_funccal()->func->uf_dfunc_idx == UF_NOT_COMPILED)
      {
        // a: and l: are only used in functions defined with ":function"
        if (*name == 'a')                       // a: function argument
--- 2628,2634 ----
      if (*name == 'v')                         // v: variable
        return &vimvarht;
      if (get_current_funccal() != NULL
!              && get_current_funccal()->func->uf_def_status == UF_NOT_COMPILED)
      {
        // a: and l: are only used in functions defined with ":function"
        if (*name == 'a')                       // a: function argument
*** ../vim-8.2.1022/src/vim9execute.c   2020-06-19 18:34:10.989945091 +0200
--- src/vim9execute.c   2020-06-20 17:23:06.527603748 +0200
***************
*** 487,496 ****
      int               error;
      int               idx;
  
!     if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
            && compile_def_function(ufunc, FALSE, NULL) == FAIL)
        return FAIL;
!     if (ufunc->uf_dfunc_idx >= 0)
      {
        // The function has been compiled, can call it quickly.  For a function
        // that was defined later: we can call it directly next time.
--- 487,496 ----
      int               error;
      int               idx;
  
!     if (ufunc->uf_def_status == UF_TO_BE_COMPILED
            && compile_def_function(ufunc, FALSE, NULL) == FAIL)
        return FAIL;
!     if (ufunc->uf_def_status == UF_COMPILED)
      {
        // The function has been compiled, can call it quickly.  For a function
        // that was defined later: we can call it directly next time.
***************
*** 671,678 ****
  // Like STACK_TV_VAR but use the outer scope
  #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + 
ectx.ec_outer_frame + STACK_FRAME_SIZE + idx)
  
!     if (ufunc->uf_dfunc_idx == UF_NOT_COMPILED
!           || (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
                          && compile_def_function(ufunc, FALSE, NULL) == FAIL))
      {
        if (called_emsg == called_emsg_before)
--- 671,678 ----
  // Like STACK_TV_VAR but use the outer scope
  #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + 
ectx.ec_outer_frame + STACK_FRAME_SIZE + idx)
  
!     if (ufunc->uf_def_status == UF_NOT_COMPILED
!           || (ufunc->uf_def_status == UF_TO_BE_COMPILED
                          && compile_def_function(ufunc, FALSE, NULL) == FAIL))
      {
        if (called_emsg == called_emsg_before)
***************
*** 2379,2388 ****
        semsg(_("E1061: Cannot find function %s"), eap->arg);
        return;
      }
!     if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
            && compile_def_function(ufunc, FALSE, NULL) == FAIL)
        return;
!     if (ufunc->uf_dfunc_idx < 0)
      {
        semsg(_("E1062: Function %s is not compiled"), eap->arg);
        return;
--- 2379,2388 ----
        semsg(_("E1061: Cannot find function %s"), eap->arg);
        return;
      }
!     if (ufunc->uf_def_status == UF_TO_BE_COMPILED
            && compile_def_function(ufunc, FALSE, NULL) == FAIL)
        return;
!     if (ufunc->uf_def_status != UF_COMPILED)
      {
        semsg(_("E1062: Function %s is not compiled"), eap->arg);
        return;
*** ../vim-8.2.1022/src/version.c       2020-06-20 16:05:29.016185239 +0200
--- src/version.c       2020-06-20 18:17:42.265122310 +0200
***************
*** 756,757 ****
--- 756,759 ----
  {   /* Add new patch number below this line */
+ /**/
+     1023,
  /**/

-- 
ROBIN:  The what?
ARTHUR: The Holy Hand Grenade of Antioch.  'Tis one of the sacred relics
        Brother Maynard always carries with him.
ALL:    Yes. Of course.
ARTHUR: (shouting) Bring up the Holy Hand Grenade!
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// 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/202006201619.05KGJrmp947082%40masaka.moolenaar.net.

Raspunde prin e-mail lui