comparison src/eval.c @ 30598:37aa9fd2ed72 v9.0.0634

patch 9.0.0634: evaluating "expr" options has more overhead than needed Commit: https://github.com/vim/vim/commit/a4e0b9785e409e9e660171cea76dfcc5fdafad9b Author: Bram Moolenaar <Bram@vim.org> Date: Sat Oct 1 19:43:52 2022 +0100 patch 9.0.0634: evaluating "expr" options has more overhead than needed Problem: Evaluating "expr" options has more overhead than needed. Solution: Use call_simple_func() for 'foldtext', 'includeexpr', 'printexpr', "expr" of 'spellsuggest', 'diffexpr', 'patchexpr', 'balloonexpr', 'formatexpr', 'indentexpr' and 'charconvert'.
author Bram Moolenaar <Bram@vim.org>
date Sat, 01 Oct 2022 20:45:04 +0200
parents 586b5b3aacf9
children d914a3812d5b
comparison
equal deleted inserted replaced
30597:1e1b0454599d 30598:37aa9fd2ed72
141 int 141 int
142 eval_to_bool( 142 eval_to_bool(
143 char_u *arg, 143 char_u *arg,
144 int *error, 144 int *error,
145 exarg_T *eap, 145 exarg_T *eap,
146 int skip) // only parse, don't execute 146 int skip, // only parse, don't execute
147 int use_simple_function)
147 { 148 {
148 typval_T tv; 149 typval_T tv;
149 varnumber_T retval = FALSE; 150 varnumber_T retval = FALSE;
150 evalarg_T evalarg; 151 evalarg_T evalarg;
152 int r;
151 153
152 fill_evalarg_from_eap(&evalarg, eap, skip); 154 fill_evalarg_from_eap(&evalarg, eap, skip);
153 155
154 if (skip) 156 if (skip)
155 ++emsg_skip; 157 ++emsg_skip;
156 if (eval0(arg, &tv, eap, &evalarg) == FAIL) 158 if (use_simple_function)
159 r = eval0_simple_funccal(arg, &tv, eap, &evalarg);
160 else
161 r = eval0(arg, &tv, eap, &evalarg);
162 if (r == FAIL)
157 *error = TRUE; 163 *error = TRUE;
158 else 164 else
159 { 165 {
160 *error = FALSE; 166 *error = FALSE;
161 if (!skip) 167 if (!skip)
599 */ 605 */
600 char_u * 606 char_u *
601 eval_to_string_eap( 607 eval_to_string_eap(
602 char_u *arg, 608 char_u *arg,
603 int convert, 609 int convert,
604 exarg_T *eap) 610 exarg_T *eap,
611 int use_simple_function)
605 { 612 {
606 typval_T tv; 613 typval_T tv;
607 char_u *retval; 614 char_u *retval;
608 evalarg_T evalarg; 615 evalarg_T evalarg;
616 int r;
609 617
610 fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); 618 fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip);
611 if (eval0(arg, &tv, NULL, &evalarg) == FAIL) 619 if (use_simple_function)
620 r = eval0_simple_funccal(arg, &tv, NULL, &evalarg);
621 else
622 r = eval0(arg, &tv, NULL, &evalarg);
623 if (r == FAIL)
612 retval = NULL; 624 retval = NULL;
613 else 625 else
614 { 626 {
615 retval = typval2string(&tv, convert); 627 retval = typval2string(&tv, convert);
616 clear_tv(&tv); 628 clear_tv(&tv);
621 } 633 }
622 634
623 char_u * 635 char_u *
624 eval_to_string( 636 eval_to_string(
625 char_u *arg, 637 char_u *arg,
626 int convert) 638 int convert,
627 { 639 int use_simple_function)
628 return eval_to_string_eap(arg, convert, NULL); 640 {
641 return eval_to_string_eap(arg, convert, NULL, use_simple_function);
629 } 642 }
630 643
631 /* 644 /*
632 * Call eval_to_string() without using current local variables and using 645 * Call eval_to_string() without using current local variables and using
633 * textlock. When "use_sandbox" is TRUE use the sandbox. 646 * textlock. When "use_sandbox" is TRUE use the sandbox.
635 */ 648 */
636 char_u * 649 char_u *
637 eval_to_string_safe( 650 eval_to_string_safe(
638 char_u *arg, 651 char_u *arg,
639 int use_sandbox, 652 int use_sandbox,
640 int keep_script_version) 653 int keep_script_version,
654 int use_simple_function)
641 { 655 {
642 char_u *retval; 656 char_u *retval;
643 funccal_entry_T funccal_entry; 657 funccal_entry_T funccal_entry;
644 int save_sc_version = current_sctx.sc_version; 658 int save_sc_version = current_sctx.sc_version;
645 int save_garbage = may_garbage_collect; 659 int save_garbage = may_garbage_collect;
649 save_funccal(&funccal_entry); 663 save_funccal(&funccal_entry);
650 if (use_sandbox) 664 if (use_sandbox)
651 ++sandbox; 665 ++sandbox;
652 ++textlock; 666 ++textlock;
653 may_garbage_collect = FALSE; 667 may_garbage_collect = FALSE;
654 retval = eval_to_string(arg, FALSE); 668 retval = eval_to_string(arg, FALSE, use_simple_function);
655 if (use_sandbox) 669 if (use_sandbox)
656 --sandbox; 670 --sandbox;
657 --textlock; 671 --textlock;
658 may_garbage_collect = save_garbage; 672 may_garbage_collect = save_garbage;
659 restore_funccal(); 673 restore_funccal();
665 * Top level evaluation function, returning a number. 679 * Top level evaluation function, returning a number.
666 * Evaluates "expr" silently. 680 * Evaluates "expr" silently.
667 * Returns -1 for an error. 681 * Returns -1 for an error.
668 */ 682 */
669 varnumber_T 683 varnumber_T
670 eval_to_number(char_u *expr) 684 eval_to_number(char_u *expr, int use_simple_function)
671 { 685 {
672 typval_T rettv; 686 typval_T rettv;
673 varnumber_T retval; 687 varnumber_T retval;
674 char_u *p = skipwhite(expr); 688 char_u *p = skipwhite(expr);
689 int r = NOTDONE;
675 690
676 ++emsg_off; 691 ++emsg_off;
677 692
678 if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL) 693 if (use_simple_function)
694 r = may_call_simple_func(expr, &rettv);
695 if (r == NOTDONE)
696 r = eval1(&p, &rettv, &EVALARG_EVALUATE);
697 if (r == FAIL)
679 retval = -1; 698 retval = -1;
680 else 699 else
681 { 700 {
682 retval = tv_get_number_chk(&rettv, NULL); 701 retval = tv_get_number_chk(&rettv, NULL);
683 clear_tv(&rettv); 702 clear_tv(&rettv);
693 * Returns NULL when there is an error. 712 * Returns NULL when there is an error.
694 */ 713 */
695 typval_T * 714 typval_T *
696 eval_expr(char_u *arg, exarg_T *eap) 715 eval_expr(char_u *arg, exarg_T *eap)
697 { 716 {
717 return eval_expr_ext(arg, eap, FALSE);
718 }
719
720 typval_T *
721 eval_expr_ext(char_u *arg, exarg_T *eap, int use_simple_function)
722 {
698 typval_T *tv; 723 typval_T *tv;
699 evalarg_T evalarg; 724 evalarg_T evalarg;
700 725
701 fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); 726 fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip);
702 727
703 tv = ALLOC_ONE(typval_T); 728 tv = ALLOC_ONE(typval_T);
704 if (tv != NULL && eval0(arg, tv, eap, &evalarg) == FAIL) 729 if (tv != NULL)
705 VIM_CLEAR(tv); 730 {
731 int r = NOTDONE;
732
733 if (use_simple_function)
734 r = eval0_simple_funccal(arg, tv, eap, &evalarg);
735 if (r == NOTDONE)
736 r = eval0(arg, tv, eap, &evalarg);
737
738 if (r == FAIL)
739 VIM_CLEAR(tv);
740 }
706 741
707 clear_evalarg(&evalarg, eap); 742 clear_evalarg(&evalarg, eap);
708 return tv; 743 return tv;
709 } 744 }
710 745
897 int 932 int
898 eval_foldexpr(win_T *wp, int *cp) 933 eval_foldexpr(win_T *wp, int *cp)
899 { 934 {
900 char_u *arg; 935 char_u *arg;
901 typval_T tv; 936 typval_T tv;
902 int r = NOTDONE;
903 varnumber_T retval; 937 varnumber_T retval;
904 char_u *s; 938 char_u *s;
905 sctx_T saved_sctx = current_sctx; 939 sctx_T saved_sctx = current_sctx;
906 int use_sandbox = was_set_insecurely((char_u *)"foldexpr", 940 int use_sandbox = was_set_insecurely((char_u *)"foldexpr",
907 OPT_LOCAL); 941 OPT_LOCAL);
908 942
909 arg = skipwhite(wp->w_p_fde); 943 arg = skipwhite(wp->w_p_fde);
910 current_sctx = wp->w_p_script_ctx[WV_FDE]; 944 current_sctx = wp->w_p_script_ctx[WV_FDE];
911 945
912 ++emsg_off; 946 ++emsg_off;
913 if (use_sandbox) 947 if (use_sandbox)
914 ++sandbox; 948 ++sandbox;
915 ++textlock; 949 ++textlock;
916 *cp = NUL; 950 *cp = NUL;
917 951
918 // If the expression is "FuncName()" then we can skip a lot of overhead. 952 // Evaluate the expression. If the expression is "FuncName()" call the
919 char_u *parens = (char_u *)strstr((char *)arg, "()"); 953 // function directly.
920 if (parens != NULL && *skipwhite(parens + 2) == NUL) 954 if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL)
921 {
922 char_u *p = STRNCMP(arg, "<SNR>", 5) == 0 ? skipdigits(arg + 5) : arg;
923
924 if (to_name_end(p, TRUE) == parens)
925 r = call_simple_func(arg, (int)(parens - arg), &tv);
926 }
927
928 if (r == NOTDONE)
929 r = eval0(arg, &tv, NULL, &EVALARG_EVALUATE);
930
931 if (r == FAIL)
932 retval = 0; 955 retval = 0;
933 else 956 else
934 { 957 {
935 // If the result is a number, just return the number. 958 // If the result is a number, just return the number.
936 if (tv.v_type == VAR_NUMBER) 959 if (tv.v_type == VAR_NUMBER)
2426 return eval_next_line(arg, evalarg); 2449 return eval_next_line(arg, evalarg);
2427 return p; 2450 return p;
2428 } 2451 }
2429 2452
2430 /* 2453 /*
2431 * The "evaluate" argument: When FALSE, the argument is only parsed but not 2454 * The "eval" functions have an "evalarg" argument: When NULL or
2432 * executed. The function may return OK, but the rettv will be of type 2455 * "evalarg->eval_flags" does not have EVAL_EVALUATE, then the argument is only
2433 * VAR_UNKNOWN. The function still returns FAIL for a syntax error. 2456 * parsed but not executed. The functions may return OK, but the rettv will be
2457 * of type VAR_UNKNOWN. The functions still returns FAIL for a syntax error.
2434 */ 2458 */
2435 2459
2436 /* 2460 /*
2437 * Handle zero level expression. 2461 * Handle zero level expression.
2438 * This calls eval1() and handles error message and nextcmd. 2462 * This calls eval1() and handles error message and nextcmd.
2447 typval_T *rettv, 2471 typval_T *rettv,
2448 exarg_T *eap, 2472 exarg_T *eap,
2449 evalarg_T *evalarg) 2473 evalarg_T *evalarg)
2450 { 2474 {
2451 return eval0_retarg(arg, rettv, eap, evalarg, NULL); 2475 return eval0_retarg(arg, rettv, eap, evalarg, NULL);
2476 }
2477
2478 /*
2479 * If "arg" is a simple function call without arguments then call it and return
2480 * the result. Otherwise return NOTDONE.
2481 */
2482 int
2483 may_call_simple_func(
2484 char_u *arg,
2485 typval_T *rettv)
2486 {
2487 char_u *parens = (char_u *)strstr((char *)arg, "()");
2488 int r = NOTDONE;
2489
2490 // If the expression is "FuncName()" then we can skip a lot of overhead.
2491 if (parens != NULL && *skipwhite(parens + 2) == NUL)
2492 {
2493 char_u *p = STRNCMP(arg, "<SNR>", 5) == 0 ? skipdigits(arg + 5) : arg;
2494
2495 if (to_name_end(p, TRUE) == parens)
2496 r = call_simple_func(arg, (int)(parens - arg), rettv);
2497 }
2498 return r;
2499 }
2500
2501 /*
2502 * Handle zero level expression with optimization for a simple function call.
2503 * Same arguments and return value as eval0().
2504 */
2505 int
2506 eval0_simple_funccal(
2507 char_u *arg,
2508 typval_T *rettv,
2509 exarg_T *eap,
2510 evalarg_T *evalarg)
2511 {
2512 int r = may_call_simple_func(arg, rettv);
2513
2514 if (r == NOTDONE)
2515 r = eval0_retarg(arg, rettv, eap, evalarg, NULL);
2516 return r;
2452 } 2517 }
2453 2518
2454 /* 2519 /*
2455 * Like eval0() but when "retarg" is not NULL store the pointer to after the 2520 * Like eval0() but when "retarg" is not NULL store the pointer to after the
2456 * expression and don't check what comes after the expression. 2521 * expression and don't check what comes after the expression.
6281 *expr_start = NUL; 6346 *expr_start = NUL;
6282 *expr_end = NUL; 6347 *expr_end = NUL;
6283 c1 = *in_end; 6348 c1 = *in_end;
6284 *in_end = NUL; 6349 *in_end = NUL;
6285 6350
6286 temp_result = eval_to_string(expr_start + 1, FALSE); 6351 temp_result = eval_to_string(expr_start + 1, FALSE, FALSE);
6287 if (temp_result != NULL) 6352 if (temp_result != NULL)
6288 { 6353 {
6289 retval = alloc(STRLEN(temp_result) + (expr_start - in_start) 6354 retval = alloc(STRLEN(temp_result) + (expr_start - in_start)
6290 + (in_end - expr_end) + 1); 6355 + (in_end - expr_end) + 1);
6291 if (retval != NULL) 6356 if (retval != NULL)