mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
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'.
This commit is contained in:
129
src/eval.c
129
src/eval.c
@@ -143,17 +143,23 @@ eval_to_bool(
|
||||
char_u *arg,
|
||||
int *error,
|
||||
exarg_T *eap,
|
||||
int skip) // only parse, don't execute
|
||||
int skip, // only parse, don't execute
|
||||
int use_simple_function)
|
||||
{
|
||||
typval_T tv;
|
||||
varnumber_T retval = FALSE;
|
||||
evalarg_T evalarg;
|
||||
int r;
|
||||
|
||||
fill_evalarg_from_eap(&evalarg, eap, skip);
|
||||
|
||||
if (skip)
|
||||
++emsg_skip;
|
||||
if (eval0(arg, &tv, eap, &evalarg) == FAIL)
|
||||
if (use_simple_function)
|
||||
r = eval0_simple_funccal(arg, &tv, eap, &evalarg);
|
||||
else
|
||||
r = eval0(arg, &tv, eap, &evalarg);
|
||||
if (r == FAIL)
|
||||
*error = TRUE;
|
||||
else
|
||||
{
|
||||
@@ -601,14 +607,20 @@ typval2string(typval_T *tv, int convert)
|
||||
eval_to_string_eap(
|
||||
char_u *arg,
|
||||
int convert,
|
||||
exarg_T *eap)
|
||||
exarg_T *eap,
|
||||
int use_simple_function)
|
||||
{
|
||||
typval_T tv;
|
||||
char_u *retval;
|
||||
evalarg_T evalarg;
|
||||
int r;
|
||||
|
||||
fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip);
|
||||
if (eval0(arg, &tv, NULL, &evalarg) == FAIL)
|
||||
if (use_simple_function)
|
||||
r = eval0_simple_funccal(arg, &tv, NULL, &evalarg);
|
||||
else
|
||||
r = eval0(arg, &tv, NULL, &evalarg);
|
||||
if (r == FAIL)
|
||||
retval = NULL;
|
||||
else
|
||||
{
|
||||
@@ -623,9 +635,10 @@ eval_to_string_eap(
|
||||
char_u *
|
||||
eval_to_string(
|
||||
char_u *arg,
|
||||
int convert)
|
||||
int convert,
|
||||
int use_simple_function)
|
||||
{
|
||||
return eval_to_string_eap(arg, convert, NULL);
|
||||
return eval_to_string_eap(arg, convert, NULL, use_simple_function);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -637,7 +650,8 @@ eval_to_string(
|
||||
eval_to_string_safe(
|
||||
char_u *arg,
|
||||
int use_sandbox,
|
||||
int keep_script_version)
|
||||
int keep_script_version,
|
||||
int use_simple_function)
|
||||
{
|
||||
char_u *retval;
|
||||
funccal_entry_T funccal_entry;
|
||||
@@ -651,7 +665,7 @@ eval_to_string_safe(
|
||||
++sandbox;
|
||||
++textlock;
|
||||
may_garbage_collect = FALSE;
|
||||
retval = eval_to_string(arg, FALSE);
|
||||
retval = eval_to_string(arg, FALSE, use_simple_function);
|
||||
if (use_sandbox)
|
||||
--sandbox;
|
||||
--textlock;
|
||||
@@ -667,15 +681,20 @@ eval_to_string_safe(
|
||||
* Returns -1 for an error.
|
||||
*/
|
||||
varnumber_T
|
||||
eval_to_number(char_u *expr)
|
||||
eval_to_number(char_u *expr, int use_simple_function)
|
||||
{
|
||||
typval_T rettv;
|
||||
varnumber_T retval;
|
||||
char_u *p = skipwhite(expr);
|
||||
int r = NOTDONE;
|
||||
|
||||
++emsg_off;
|
||||
|
||||
if (eval1(&p, &rettv, &EVALARG_EVALUATE) == FAIL)
|
||||
if (use_simple_function)
|
||||
r = may_call_simple_func(expr, &rettv);
|
||||
if (r == NOTDONE)
|
||||
r = eval1(&p, &rettv, &EVALARG_EVALUATE);
|
||||
if (r == FAIL)
|
||||
retval = -1;
|
||||
else
|
||||
{
|
||||
@@ -694,6 +713,12 @@ eval_to_number(char_u *expr)
|
||||
*/
|
||||
typval_T *
|
||||
eval_expr(char_u *arg, exarg_T *eap)
|
||||
{
|
||||
return eval_expr_ext(arg, eap, FALSE);
|
||||
}
|
||||
|
||||
typval_T *
|
||||
eval_expr_ext(char_u *arg, exarg_T *eap, int use_simple_function)
|
||||
{
|
||||
typval_T *tv;
|
||||
evalarg_T evalarg;
|
||||
@@ -701,8 +726,18 @@ eval_expr(char_u *arg, exarg_T *eap)
|
||||
fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip);
|
||||
|
||||
tv = ALLOC_ONE(typval_T);
|
||||
if (tv != NULL && eval0(arg, tv, eap, &evalarg) == FAIL)
|
||||
VIM_CLEAR(tv);
|
||||
if (tv != NULL)
|
||||
{
|
||||
int r = NOTDONE;
|
||||
|
||||
if (use_simple_function)
|
||||
r = eval0_simple_funccal(arg, tv, eap, &evalarg);
|
||||
if (r == NOTDONE)
|
||||
r = eval0(arg, tv, eap, &evalarg);
|
||||
|
||||
if (r == FAIL)
|
||||
VIM_CLEAR(tv);
|
||||
}
|
||||
|
||||
clear_evalarg(&evalarg, eap);
|
||||
return tv;
|
||||
@@ -899,12 +934,11 @@ eval_foldexpr(win_T *wp, int *cp)
|
||||
{
|
||||
char_u *arg;
|
||||
typval_T tv;
|
||||
int r = NOTDONE;
|
||||
varnumber_T retval;
|
||||
char_u *s;
|
||||
sctx_T saved_sctx = current_sctx;
|
||||
int use_sandbox = was_set_insecurely((char_u *)"foldexpr",
|
||||
OPT_LOCAL);
|
||||
OPT_LOCAL);
|
||||
|
||||
arg = skipwhite(wp->w_p_fde);
|
||||
current_sctx = wp->w_p_script_ctx[WV_FDE];
|
||||
@@ -915,20 +949,9 @@ eval_foldexpr(win_T *wp, int *cp)
|
||||
++textlock;
|
||||
*cp = NUL;
|
||||
|
||||
// If the expression is "FuncName()" then we can skip a lot of overhead.
|
||||
char_u *parens = (char_u *)strstr((char *)arg, "()");
|
||||
if (parens != NULL && *skipwhite(parens + 2) == NUL)
|
||||
{
|
||||
char_u *p = STRNCMP(arg, "<SNR>", 5) == 0 ? skipdigits(arg + 5) : arg;
|
||||
|
||||
if (to_name_end(p, TRUE) == parens)
|
||||
r = call_simple_func(arg, (int)(parens - arg), &tv);
|
||||
}
|
||||
|
||||
if (r == NOTDONE)
|
||||
r = eval0(arg, &tv, NULL, &EVALARG_EVALUATE);
|
||||
|
||||
if (r == FAIL)
|
||||
// Evaluate the expression. If the expression is "FuncName()" call the
|
||||
// function directly.
|
||||
if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL)
|
||||
retval = 0;
|
||||
else
|
||||
{
|
||||
@@ -2428,9 +2451,10 @@ skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg)
|
||||
}
|
||||
|
||||
/*
|
||||
* The "evaluate" argument: When FALSE, the argument is only parsed but not
|
||||
* executed. The function may return OK, but the rettv will be of type
|
||||
* VAR_UNKNOWN. The function still returns FAIL for a syntax error.
|
||||
* The "eval" functions have an "evalarg" argument: When NULL or
|
||||
* "evalarg->eval_flags" does not have EVAL_EVALUATE, then the argument is only
|
||||
* parsed but not executed. The functions may return OK, but the rettv will be
|
||||
* of type VAR_UNKNOWN. The functions still returns FAIL for a syntax error.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -2451,6 +2475,47 @@ eval0(
|
||||
return eval0_retarg(arg, rettv, eap, evalarg, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If "arg" is a simple function call without arguments then call it and return
|
||||
* the result. Otherwise return NOTDONE.
|
||||
*/
|
||||
int
|
||||
may_call_simple_func(
|
||||
char_u *arg,
|
||||
typval_T *rettv)
|
||||
{
|
||||
char_u *parens = (char_u *)strstr((char *)arg, "()");
|
||||
int r = NOTDONE;
|
||||
|
||||
// If the expression is "FuncName()" then we can skip a lot of overhead.
|
||||
if (parens != NULL && *skipwhite(parens + 2) == NUL)
|
||||
{
|
||||
char_u *p = STRNCMP(arg, "<SNR>", 5) == 0 ? skipdigits(arg + 5) : arg;
|
||||
|
||||
if (to_name_end(p, TRUE) == parens)
|
||||
r = call_simple_func(arg, (int)(parens - arg), rettv);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle zero level expression with optimization for a simple function call.
|
||||
* Same arguments and return value as eval0().
|
||||
*/
|
||||
int
|
||||
eval0_simple_funccal(
|
||||
char_u *arg,
|
||||
typval_T *rettv,
|
||||
exarg_T *eap,
|
||||
evalarg_T *evalarg)
|
||||
{
|
||||
int r = may_call_simple_func(arg, rettv);
|
||||
|
||||
if (r == NOTDONE)
|
||||
r = eval0_retarg(arg, rettv, eap, evalarg, NULL);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like eval0() but when "retarg" is not NULL store the pointer to after the
|
||||
* expression and don't check what comes after the expression.
|
||||
@@ -6283,7 +6348,7 @@ make_expanded_name(
|
||||
c1 = *in_end;
|
||||
*in_end = NUL;
|
||||
|
||||
temp_result = eval_to_string(expr_start + 1, FALSE);
|
||||
temp_result = eval_to_string(expr_start + 1, FALSE, FALSE);
|
||||
if (temp_result != NULL)
|
||||
{
|
||||
retval = alloc(STRLEN(temp_result) + (expr_start - in_start)
|
||||
|
Reference in New Issue
Block a user