1
0
forked from aniani/vim

patch 8.2.3212: Vim9: execution speed can be improved

Problem:    Vim9: execution speed can be improved.
Solution:   Use __builtin_expect() to have the compiler produce better code.
            (Dominique Pellé, closes #8613)
This commit is contained in:
Dominique Pelle
2021-07-24 19:32:12 +02:00
committed by Bram Moolenaar
parent 7973de35ba
commit 5a9e5845e1
2 changed files with 54 additions and 44 deletions

View File

@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
3212,
/**/ /**/
3211, 3211,
/**/ /**/

View File

@@ -22,6 +22,14 @@
#include "vim9.h" #include "vim9.h"
#if defined(__GNUC__) || defined(__clang__)
# define likely(x) __builtin_expect((x), 1)
# define unlikely(x) __builtin_expect((x), 0)
#else
# define unlikely(x) (x)
# define likely(x) (x)
#endif
// Structure put on ec_trystack when ISN_TRY is encountered. // Structure put on ec_trystack when ISN_TRY is encountered.
typedef struct { typedef struct {
int tcd_frame_idx; // ec_frame_idx at ISN_TRY int tcd_frame_idx; // ec_frame_idx at ISN_TRY
@@ -137,7 +145,7 @@ exe_newlist(int count, ectx_T *ectx)
if (count > 0) if (count > 0)
ectx->ec_stack.ga_len -= count - 1; ectx->ec_stack.ga_len -= count - 1;
else if (GA_GROW(&ectx->ec_stack, 1) == FAIL) else if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
return FAIL; return FAIL;
else else
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
@@ -210,7 +218,7 @@ call_dfunc(
#ifdef FEAT_PROFILE #ifdef FEAT_PROFILE
if (do_profiling == PROF_YES) if (do_profiling == PROF_YES)
{ {
if (ga_grow(&profile_info_ga, 1) == OK) if (likely(ga_grow(&profile_info_ga, 1) == OK))
{ {
profinfo_T *info = ((profinfo_T *)profile_info_ga.ga_data) profinfo_T *info = ((profinfo_T *)profile_info_ga.ga_data)
+ profile_info_ga.ga_len; + profile_info_ga.ga_len;
@@ -289,8 +297,8 @@ call_dfunc(
// - if needed: a counter for number of closures created in // - if needed: a counter for number of closures created in
// ectx->ec_funcrefs. // ectx->ec_funcrefs.
varcount = dfunc->df_varcount + dfunc->df_has_closure; varcount = dfunc->df_varcount + dfunc->df_has_closure;
if (ga_grow(&ectx->ec_stack, arg_to_add + STACK_FRAME_SIZE + varcount) if (unlikely(ga_grow(&ectx->ec_stack, arg_to_add + STACK_FRAME_SIZE
== FAIL) + varcount) == FAIL))
return FAIL; return FAIL;
// If depth of calling is getting too high, don't execute the function. // If depth of calling is getting too high, don't execute the function.
@@ -361,7 +369,7 @@ call_dfunc(
else else
{ {
ref->or_outer = ALLOC_CLEAR_ONE(outer_T); ref->or_outer = ALLOC_CLEAR_ONE(outer_T);
if (ref->or_outer == NULL) if (unlikely(ref->or_outer == NULL))
{ {
vim_free(ref); vim_free(ref);
return FAIL; return FAIL;
@@ -703,7 +711,7 @@ call_prepare(int argcount, typval_T *argvars, ectx_T *ectx)
// Result replaces the arguments on the stack. // Result replaces the arguments on the stack.
if (argcount > 0) if (argcount > 0)
ectx->ec_stack.ga_len -= argcount - 1; ectx->ec_stack.ga_len -= argcount - 1;
else if (GA_GROW(&ectx->ec_stack, 1) == FAIL) else if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
return FAIL; return FAIL;
else else
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
@@ -941,7 +949,7 @@ call_partial(
{ {
// Make space for arguments from the partial, shift the "argcount" // Make space for arguments from the partial, shift the "argcount"
// arguments up. // arguments up.
if (ga_grow(&ectx->ec_stack, pt->pt_argc) == FAIL) if (unlikely(ga_grow(&ectx->ec_stack, pt->pt_argc) == FAIL))
return FAIL; return FAIL;
for (i = 1; i <= argcount; ++i) for (i = 1; i <= argcount; ++i)
*STACK_TV_BOT(-i + pt->pt_argc) = *STACK_TV_BOT(-i); *STACK_TV_BOT(-i + pt->pt_argc) = *STACK_TV_BOT(-i);
@@ -1371,7 +1379,7 @@ fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx)
// If this function returns and the closure is still being used, we // If this function returns and the closure is still being used, we
// need to make a copy of the context (arguments and local variables). // need to make a copy of the context (arguments and local variables).
// Store a reference to the partial so we can handle that. // Store a reference to the partial so we can handle that.
if (ga_grow(&ectx->ec_funcrefs, 1) == FAIL) if (unlikely(ga_grow(&ectx->ec_funcrefs, 1) == FAIL))
{ {
vim_free(pt); vim_free(pt);
return FAIL; return FAIL;
@@ -1504,7 +1512,7 @@ handle_debug(isn_T *iptr, ectx_T *ectx)
p = skipwhite(p); p = skipwhite(p);
if (*p == '#') if (*p == '#')
break; break;
if (ga_grow(&ga, 1) == OK) if (likely(ga_grow(&ga, 1) == OK))
((char_u **)(ga.ga_data))[ga.ga_len++] = p; ((char_u **)(ga.ga_data))[ga.ga_len++] = p;
if (STRNCMP(p, "def ", 4) == 0) if (STRNCMP(p, "def ", 4) == 0)
break; break;
@@ -1544,12 +1552,12 @@ exec_instructions(ectx_T *ectx)
isn_T *iptr; isn_T *iptr;
typval_T *tv; typval_T *tv;
if (++breakcheck_count >= 100) if (unlikely(++breakcheck_count >= 100))
{ {
line_breakcheck(); line_breakcheck();
breakcheck_count = 0; breakcheck_count = 0;
} }
if (got_int) if (unlikely(got_int))
{ {
// Turn CTRL-C into an exception. // Turn CTRL-C into an exception.
got_int = FALSE; got_int = FALSE;
@@ -1558,7 +1566,7 @@ exec_instructions(ectx_T *ectx)
did_throw = TRUE; did_throw = TRUE;
} }
if (did_emsg && msg_list != NULL && *msg_list != NULL) if (unlikely(did_emsg && msg_list != NULL && *msg_list != NULL))
{ {
// Turn an error message into an exception. // Turn an error message into an exception.
did_emsg = FALSE; did_emsg = FALSE;
@@ -1568,7 +1576,7 @@ exec_instructions(ectx_T *ectx)
*msg_list = NULL; *msg_list = NULL;
} }
if (did_throw) if (unlikely(did_throw))
{ {
garray_T *trystack = &ectx->ec_trystack; garray_T *trystack = &ectx->ec_trystack;
trycmd_T *trycmd = NULL; trycmd_T *trycmd = NULL;
@@ -1605,7 +1613,7 @@ exec_instructions(ectx_T *ectx)
{ {
// Not inside try or need to return from current functions. // Not inside try or need to return from current functions.
// Push a dummy return value. // Push a dummy return value.
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
tv = STACK_TV_BOT(0); tv = STACK_TV_BOT(0);
tv->v_type = VAR_NUMBER; tv->v_type = VAR_NUMBER;
@@ -1680,7 +1688,7 @@ exec_instructions(ectx_T *ectx)
int res; int res;
int save_flags = cmdmod.cmod_flags; int save_flags = cmdmod.cmod_flags;
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
tv = STACK_TV_BOT(0); tv = STACK_TV_BOT(0);
init_tv(tv); init_tv(tv);
@@ -1696,7 +1704,7 @@ exec_instructions(ectx_T *ectx)
// push typeval VAR_INSTR with instructions to be executed // push typeval VAR_INSTR with instructions to be executed
case ISN_INSTR: case ISN_INSTR:
{ {
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
tv = STACK_TV_BOT(0); tv = STACK_TV_BOT(0);
tv->vval.v_instr = ALLOC_ONE(instr_T); tv->vval.v_instr = ALLOC_ONE(instr_T);
@@ -1761,7 +1769,7 @@ exec_instructions(ectx_T *ectx)
clear_redir_lval(); clear_redir_lval();
redir_vname = 0; redir_vname = 0;
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
{ {
vim_free(res); vim_free(res);
goto theend; goto theend;
@@ -1828,7 +1836,7 @@ exec_instructions(ectx_T *ectx)
if (pass == 1) if (pass == 1)
{ {
cmd = alloc(len + 1); cmd = alloc(len + 1);
if (cmd == NULL) if (unlikely(cmd == NULL))
goto theend; goto theend;
len = 0; len = 0;
} }
@@ -1897,7 +1905,7 @@ exec_instructions(ectx_T *ectx)
p = tv_stringify(tv, buf); p = tv_stringify(tv, buf);
len = (int)STRLEN(p); len = (int)STRLEN(p);
if (ga_grow(&ga, len + 2) == FAIL) if (unlikely(ga_grow(&ga, len + 2) == FAIL))
failed = TRUE; failed = TRUE;
else else
{ {
@@ -1948,7 +1956,7 @@ exec_instructions(ectx_T *ectx)
// load local variable or argument // load local variable or argument
case ISN_LOAD: case ISN_LOAD:
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0)); copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0));
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
@@ -1956,7 +1964,7 @@ exec_instructions(ectx_T *ectx)
// load v: variable // load v: variable
case ISN_LOADV: case ISN_LOADV:
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0)); copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0));
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
@@ -1972,7 +1980,7 @@ exec_instructions(ectx_T *ectx)
if (sv == NULL) if (sv == NULL)
goto theend; goto theend;
allocate_if_null(sv->sv_tv); allocate_if_null(sv->sv_tv);
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
copy_tv(sv->sv_tv, STACK_TV_BOT(0)); copy_tv(sv->sv_tv, STACK_TV_BOT(0));
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
@@ -1995,7 +2003,7 @@ exec_instructions(ectx_T *ectx)
} }
else else
{ {
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
copy_tv(&di->di_tv, STACK_TV_BOT(0)); copy_tv(&di->di_tv, STACK_TV_BOT(0));
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
@@ -2045,7 +2053,7 @@ exec_instructions(ectx_T *ectx)
} }
else else
{ {
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
copy_tv(&di->di_tv, STACK_TV_BOT(0)); copy_tv(&di->di_tv, STACK_TV_BOT(0));
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
@@ -2058,7 +2066,7 @@ exec_instructions(ectx_T *ectx)
{ {
char_u *name = iptr->isn_arg.string; char_u *name = iptr->isn_arg.string;
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
SOURCING_LNUM = iptr->isn_lnum; SOURCING_LNUM = iptr->isn_lnum;
if (eval_variable(name, (int)STRLEN(name), if (eval_variable(name, (int)STRLEN(name),
@@ -2085,7 +2093,7 @@ exec_instructions(ectx_T *ectx)
default: // Cannot reach here default: // Cannot reach here
goto theend; goto theend;
} }
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
tv = STACK_TV_BOT(0); tv = STACK_TV_BOT(0);
tv->v_type = VAR_DICT; tv->v_type = VAR_DICT;
@@ -2104,7 +2112,7 @@ exec_instructions(ectx_T *ectx)
// This is not expected to fail, name is checked during // This is not expected to fail, name is checked during
// compilation: don't set SOURCING_LNUM. // compilation: don't set SOURCING_LNUM.
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
if (eval_option(&name, &optval, TRUE) == FAIL) if (eval_option(&name, &optval, TRUE) == FAIL)
goto theend; goto theend;
@@ -2119,7 +2127,7 @@ exec_instructions(ectx_T *ectx)
typval_T optval; typval_T optval;
char_u *name = iptr->isn_arg.string; char_u *name = iptr->isn_arg.string;
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
// name is always valid, checked when compiling // name is always valid, checked when compiling
(void)eval_env_var(&name, &optval, TRUE); (void)eval_env_var(&name, &optval, TRUE);
@@ -2130,7 +2138,7 @@ exec_instructions(ectx_T *ectx)
// load @register // load @register
case ISN_LOADREG: case ISN_LOADREG:
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
tv = STACK_TV_BOT(0); tv = STACK_TV_BOT(0);
tv->v_type = VAR_STRING; tv->v_type = VAR_STRING;
@@ -2565,7 +2573,7 @@ exec_instructions(ectx_T *ectx)
+ iptr->isn_arg.outer.outer_idx; + iptr->isn_arg.outer.outer_idx;
if (iptr->isn_type == ISN_LOADOUTER) if (iptr->isn_type == ISN_LOADOUTER)
{ {
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
copy_tv(tv, STACK_TV_BOT(0)); copy_tv(tv, STACK_TV_BOT(0));
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
@@ -2753,7 +2761,7 @@ exec_instructions(ectx_T *ectx)
case ISN_PUSHFUNC: case ISN_PUSHFUNC:
case ISN_PUSHCHANNEL: case ISN_PUSHCHANNEL:
case ISN_PUSHJOB: case ISN_PUSHJOB:
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
tv = STACK_TV_BOT(0); tv = STACK_TV_BOT(0);
tv->v_lock = 0; tv->v_lock = 0;
@@ -2842,7 +2850,7 @@ exec_instructions(ectx_T *ectx)
char_u *key; char_u *key;
int idx; int idx;
if (dict == NULL) if (unlikely(dict == NULL))
goto theend; goto theend;
for (idx = 0; idx < count; ++idx) for (idx = 0; idx < count; ++idx)
{ {
@@ -2861,7 +2869,7 @@ exec_instructions(ectx_T *ectx)
} }
item = dictitem_alloc(key); item = dictitem_alloc(key);
clear_tv(tv); clear_tv(tv);
if (item == NULL) if (unlikely(item == NULL))
{ {
dict_unref(dict); dict_unref(dict);
goto theend; goto theend;
@@ -2878,7 +2886,7 @@ exec_instructions(ectx_T *ectx)
if (count > 0) if (count > 0)
ectx->ec_stack.ga_len -= 2 * count - 1; ectx->ec_stack.ga_len -= 2 * count - 1;
else if (GA_GROW(&ectx->ec_stack, 1) == FAIL) else if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
else else
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
@@ -2960,7 +2968,7 @@ exec_instructions(ectx_T *ectx)
// return from a :def function call without a value // return from a :def function call without a value
case ISN_RETURN_VOID: case ISN_RETURN_VOID:
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
tv = STACK_TV_BOT(0); tv = STACK_TV_BOT(0);
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
@@ -3002,7 +3010,7 @@ exec_instructions(ectx_T *ectx)
if (pt == NULL) if (pt == NULL)
goto theend; goto theend;
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
{ {
vim_free(pt); vim_free(pt);
goto theend; goto theend;
@@ -3097,7 +3105,7 @@ exec_instructions(ectx_T *ectx)
typval_T *idxtv = typval_T *idxtv =
STACK_TV_VAR(iptr->isn_arg.forloop.for_idx); STACK_TV_VAR(iptr->isn_arg.forloop.for_idx);
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
if (ltv->v_type == VAR_LIST) if (ltv->v_type == VAR_LIST)
{ {
@@ -3204,7 +3212,7 @@ exec_instructions(ectx_T *ectx)
{ {
trycmd_T *trycmd = NULL; trycmd_T *trycmd = NULL;
if (GA_GROW(&ectx->ec_trystack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_trystack, 1) == FAIL))
goto theend; goto theend;
trycmd = ((trycmd_T *)ectx->ec_trystack.ga_data) trycmd = ((trycmd_T *)ectx->ec_trystack.ga_data)
+ ectx->ec_trystack.ga_len; + ectx->ec_trystack.ga_len;
@@ -3229,7 +3237,7 @@ exec_instructions(ectx_T *ectx)
iemsg("Evaluating catch while current_exception is NULL"); iemsg("Evaluating catch while current_exception is NULL");
goto theend; goto theend;
} }
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
tv = STACK_TV_BOT(0); tv = STACK_TV_BOT(0);
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
@@ -3888,7 +3896,7 @@ exec_instructions(ectx_T *ectx)
tv = STACK_TV_BOT(-1 - gi->gi_with_op); tv = STACK_TV_BOT(-1 - gi->gi_with_op);
li = list_find(tv->vval.v_list, gi->gi_index); li = list_find(tv->vval.v_list, gi->gi_index);
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
copy_tv(&li->li_tv, STACK_TV_BOT(-1)); copy_tv(&li->li_tv, STACK_TV_BOT(-1));
@@ -4123,7 +4131,7 @@ exec_instructions(ectx_T *ectx)
if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL) if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL)
goto on_error; goto on_error;
if (GA_GROW(&ectx->ec_stack, 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL))
goto theend; goto theend;
++ectx->ec_stack.ga_len; ++ectx->ec_stack.ga_len;
tv = STACK_TV_BOT(-1); tv = STACK_TV_BOT(-1);
@@ -4225,7 +4233,7 @@ exec_instructions(ectx_T *ectx)
} }
CHECK_LIST_MATERIALIZE(l); CHECK_LIST_MATERIALIZE(l);
if (GA_GROW(&ectx->ec_stack, count - 1) == FAIL) if (unlikely(GA_GROW(&ectx->ec_stack, count - 1) == FAIL))
goto theend; goto theend;
ectx->ec_stack.ga_len += count - 1; ectx->ec_stack.ga_len += count - 1;
@@ -4499,7 +4507,7 @@ call_def_function(
CLEAR_FIELD(ectx); CLEAR_FIELD(ectx);
ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx; ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
if (ga_grow(&ectx.ec_stack, 20) == FAIL) if (unlikely(ga_grow(&ectx.ec_stack, 20) == FAIL))
{ {
funcdepth_decrement(); funcdepth_decrement();
return FAIL; return FAIL;
@@ -5506,7 +5514,7 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
NULL, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE); NULL, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE);
buf = alloc(len + 1); buf = alloc(len + 1);
if (buf != NULL) if (likely(buf != NULL))
{ {
(void)produce_cmdmods( (void)produce_cmdmods(
buf, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE); buf, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE);