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 -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///