Mercurial > vim
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) |