mirror of
https://github.com/vim/vim.git
synced 2025-09-23 03:43:49 -04:00
patch 9.0.0618: calling function for reduce() has too much overhead
Problem: Calling function for reduce() has too much overhead. Solution: Do not create a funccall_T every time.
This commit is contained in:
14
src/blob.c
14
src/blob.c
@@ -559,6 +559,8 @@ blob_filter_map(
|
||||
blob_T *b_ret;
|
||||
int idx = 0;
|
||||
int rem;
|
||||
typval_T newtv;
|
||||
funccall_T *fc;
|
||||
|
||||
if (filtermap == FILTERMAP_MAPNEW)
|
||||
{
|
||||
@@ -579,15 +581,16 @@ blob_filter_map(
|
||||
// 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++)
|
||||
{
|
||||
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
|
||||
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,6 +615,9 @@ blob_filter_map(
|
||||
}
|
||||
++idx;
|
||||
}
|
||||
|
||||
if (fc != NULL)
|
||||
remove_funccal();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -714,7 +720,7 @@ blob_reduce(
|
||||
argv[1].v_type = VAR_NUMBER;
|
||||
argv[1].vval.v_number = blob_get(b, i);
|
||||
|
||||
r = eval_expr_typval(expr, argv, 2, rettv);
|
||||
r = eval_expr_typval(expr, argv, 2, NULL, rettv);
|
||||
|
||||
clear_tv(&argv[0]);
|
||||
if (r == FAIL || called_emsg != called_emsg_start)
|
||||
|
11
src/dict.c
11
src/dict.c
@@ -1315,6 +1315,8 @@ dict_filter_map(
|
||||
dictitem_T *di;
|
||||
int todo;
|
||||
int rem;
|
||||
typval_T newtv;
|
||||
funccall_T *fc;
|
||||
|
||||
if (filtermap == FILTERMAP_MAPNEW)
|
||||
{
|
||||
@@ -1335,6 +1337,9 @@ dict_filter_map(
|
||||
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,7 +1350,6 @@ dict_filter_map(
|
||||
if (!HASHITEM_EMPTY(hi))
|
||||
{
|
||||
int r;
|
||||
typval_T newtv;
|
||||
|
||||
--todo;
|
||||
di = HI2DI(hi);
|
||||
@@ -1357,8 +1361,7 @@ dict_filter_map(
|
||||
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);
|
||||
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,6 +1401,8 @@ dict_filter_map(
|
||||
}
|
||||
hash_unlock(ht);
|
||||
d->dv_lock = prev_lock;
|
||||
if (fc != NULL)
|
||||
remove_funccal();
|
||||
}
|
||||
|
||||
/*
|
||||
|
35
src/eval.c
35
src/eval.c
@@ -215,13 +215,40 @@ eval_expr_valid_arg(typval_T *tv)
|
||||
|| (tv->vval.v_string != NULL && *tv->vval.v_string != NUL));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, typval_T *rettv)
|
||||
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,7 +274,8 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
|
||||
if (partial->pt_func != NULL
|
||||
&& partial->pt_func->uf_def_status != UF_NOT_COMPILED)
|
||||
{
|
||||
funccall_T *fc = create_funccal(partial->pt_func, rettv);
|
||||
funccall_T *fc = fc_arg != NULL ? fc_arg
|
||||
: create_funccal(partial->pt_func, rettv);
|
||||
int r;
|
||||
|
||||
if (fc == NULL)
|
||||
@@ -256,6 +284,7 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
|
||||
// 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,7 +333,7 @@ eval_expr_to_bool(typval_T *expr, int *error)
|
||||
typval_T rettv;
|
||||
int res;
|
||||
|
||||
if (eval_expr_typval(expr, NULL, 0, &rettv) == FAIL)
|
||||
if (eval_expr_typval(expr, NULL, 0, NULL, &rettv) == FAIL)
|
||||
{
|
||||
*error = TRUE;
|
||||
return FALSE;
|
||||
|
@@ -6740,7 +6740,7 @@ indexof_eval_expr(typval_T *expr)
|
||||
argv[1] = *get_vim_var_tv(VV_VAL);
|
||||
newtv.v_type = VAR_UNKNOWN;
|
||||
|
||||
if (eval_expr_typval(expr, argv, 2, &newtv) == FAIL)
|
||||
if (eval_expr_typval(expr, argv, 2, NULL, &newtv) == FAIL)
|
||||
return FALSE;
|
||||
|
||||
found = tv_get_bool_chk(&newtv, &error);
|
||||
|
@@ -1609,7 +1609,7 @@ checkitem_common(void *context, char_u *name, dict_T *dict)
|
||||
argv[0].vval.v_dict = dict;
|
||||
}
|
||||
|
||||
if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
|
||||
if (eval_expr_typval(expr, argv, 1, NULL, &rettv) == FAIL)
|
||||
goto theend;
|
||||
|
||||
// We want to use -1, but also true/false should be allowed.
|
||||
|
26
src/list.c
26
src/list.c
@@ -2320,6 +2320,7 @@ filter_map_one(
|
||||
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,7 +2330,7 @@ filter_map_one(
|
||||
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)
|
||||
if (eval_expr_typval(expr, argv, 2, fc, newtv) == FAIL)
|
||||
goto theend;
|
||||
if (filtermap == FILTERMAP_FILTER)
|
||||
{
|
||||
@@ -2371,6 +2372,8 @@ list_filter_map(
|
||||
int idx = 0;
|
||||
int rem;
|
||||
listitem_T *li, *nli;
|
||||
typval_T newtv;
|
||||
funccall_T *fc;
|
||||
|
||||
if (filtermap == FILTERMAP_MAPNEW)
|
||||
{
|
||||
@@ -2395,6 +2398,9 @@ list_filter_map(
|
||||
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,13 +2419,12 @@ list_filter_map(
|
||||
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)
|
||||
if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL)
|
||||
break;
|
||||
if (did_emsg)
|
||||
{
|
||||
@@ -2457,14 +2462,12 @@ list_filter_map(
|
||||
// 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,
|
||||
if (filter_map_one(&li->li_tv, expr, filtermap, fc,
|
||||
&newtv, &rem) == FAIL)
|
||||
break;
|
||||
if (did_emsg)
|
||||
@@ -2498,6 +2501,8 @@ list_filter_map(
|
||||
}
|
||||
|
||||
l->lv_lock = prev_lock;
|
||||
if (fc != NULL)
|
||||
remove_funccal();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3018,6 +3023,7 @@ list_reduce(
|
||||
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,6 +3061,9 @@ list_reduce(
|
||||
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,7 +3080,7 @@ list_reduce(
|
||||
else
|
||||
argv[1] = li->li_tv;
|
||||
|
||||
r = eval_expr_typval(expr, argv, 2, rettv);
|
||||
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,6 +3097,9 @@ list_reduce(
|
||||
li = li->li_next;
|
||||
}
|
||||
|
||||
if (fc != NULL)
|
||||
remove_funccal();
|
||||
|
||||
l->lv_lock = prev_locked;
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,8 @@ void eval_clear(void);
|
||||
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);
|
||||
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);
|
||||
|
@@ -52,7 +52,7 @@ void init_static_list(staticList10_T *sl);
|
||||
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);
|
||||
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);
|
||||
|
@@ -882,6 +882,8 @@ string_filter_map(
|
||||
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,18 +891,19 @@ string_filter_map(
|
||||
// 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)
|
||||
{
|
||||
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
|
||||
if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL
|
||||
|| did_emsg)
|
||||
{
|
||||
clear_tv(&newtv);
|
||||
@@ -929,6 +932,8 @@ string_filter_map(
|
||||
}
|
||||
ga_append(&ga, NUL);
|
||||
rettv->vval.v_string = ga.ga_data;
|
||||
if (fc != NULL)
|
||||
remove_funccal();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -947,6 +952,7 @@ string_reduce(
|
||||
typval_T argv[3];
|
||||
int r;
|
||||
int called_emsg_start = called_emsg;
|
||||
funccall_T *fc;
|
||||
|
||||
if (argvars[2].v_type == VAR_UNKNOWN)
|
||||
{
|
||||
@@ -964,6 +970,9 @@ string_reduce(
|
||||
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,13 +980,16 @@ string_reduce(
|
||||
break;
|
||||
len = (int)STRLEN(argv[1].vval.v_string);
|
||||
|
||||
r = eval_expr_typval(expr, argv, 2, rettv);
|
||||
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
|
||||
|
@@ -699,6 +699,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
618,
|
||||
/**/
|
||||
617,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user