Patch 8.2.1023

5 views
Skip to first unread message

Bram Moolenaar

unread,
Jun 20, 2020, 12:20:03 PM6/20/20
to vim...@googlegroups.com

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 -- Br...@Moolenaar.net -- 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 ///
Reply all
Reply to author
Forward
0 new messages