]> granicus.if.org Git - vim/commitdiff
patch 9.0.0618: calling function for reduce() has too much overhead v9.0.0618
authorBram Moolenaar <Bram@vim.org>
Wed, 28 Sep 2022 15:16:15 +0000 (16:16 +0100)
committerBram Moolenaar <Bram@vim.org>
Wed, 28 Sep 2022 15:16:15 +0000 (16:16 +0100)
Problem:    Calling function for reduce() has too much overhead.
Solution:   Do not create a funccall_T every time.

src/blob.c
src/dict.c
src/eval.c
src/evalfunc.c
src/filepath.c
src/list.c
src/proto/eval.pro
src/proto/list.pro
src/strings.c
src/version.c

index e4d23d260bfed175175c1b2b27daf9828b370a1c..a4e99818c396299664e1997516cfe192340412dd 100644 (file)
@@ -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)
index 1cb3e89a8dceb77f1bbde715b1fa0a0aba5c95b7..63b30e06bed98e2a399a752aca0fdf781285237d 100644 (file)
@@ -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();
 }
 
 /*
index 0102bd70b5cb8ef729007424d02718c28c1b7421..2330bd6a10682d618b08f0863a641b3f92b8d917 100644 (file)
@@ -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,7 +284,8 @@ 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);
-           remove_funccal();
+           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;
index 3223a02933cba5d79dfec3cf4179c9ce90aa3953..857f211a21dba63d236377e131e1bc166519393f 100644 (file)
@@ -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);
index 373a784f648789045cdc3bd4192e459aed0a8a3b..673cdb5accbe82cad586c783c4c20e457e753b2e 100644 (file)
@@ -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.
index a39c9f974b34f237b5fa716e67b655461850d374..c67b7fe9db25631b97946a5508b256fa4e7aa47c 100644 (file)
@@ -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,15 +2462,13 @@ 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,
-                       &newtv, &rem) == FAIL)
+           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;
 }
 
index 27a13c9498bae5181c3d7aed254f20a58e55247c..1ac579c54abc952626838b21750aebe14706f6f8 100644 (file)
@@ -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);
index 6c3523a0abccbbb59a2d8cce72d62bba38d3d891..5abe03c096092dfc5a1ec3c54bbbb4e1155f48e9 100644 (file)
@@ -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);
index 15ead2bfb9f43377284ae5e5fb5bf4359b4b9e47..edcae6f8a49e7f47f5231faeecf7a880b7132527 100644 (file)
@@ -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
index 43569d01c4d9af1a2e9959cd3f1396385073b911..11cf724338c158d4bab48e7bcee14317cefdd9f0 100644 (file)
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    618,
 /**/
     617,
 /**/