To: vim_dev@googlegroups.com Subject: Patch 9.0.0618 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@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 ///