To: vim_dev@googlegroups.com Subject: Patch 8.2.3212 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3212 Problem: Vim9: execution speed can be improved. Solution: Use __builtin_expect() to have the compiler produce better code. (Dominique Pellé, closes #8613) Files: src/vim9execute.c *** ../vim-8.2.3211/src/vim9execute.c 2021-07-22 18:48:45.456351455 +0200 --- src/vim9execute.c 2021-07-24 19:30:12.080997318 +0200 *************** *** 22,27 **** --- 22,35 ---- #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. typedef struct { int tcd_frame_idx; // ec_frame_idx at ISN_TRY *************** *** 137,143 **** if (count > 0) ectx->ec_stack.ga_len -= count - 1; ! else if (GA_GROW(&ectx->ec_stack, 1) == FAIL) return FAIL; else ++ectx->ec_stack.ga_len; --- 145,151 ---- if (count > 0) ectx->ec_stack.ga_len -= count - 1; ! else if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) return FAIL; else ++ectx->ec_stack.ga_len; *************** *** 210,216 **** #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) { ! if (ga_grow(&profile_info_ga, 1) == OK) { profinfo_T *info = ((profinfo_T *)profile_info_ga.ga_data) + profile_info_ga.ga_len; --- 218,224 ---- #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) { ! if (likely(ga_grow(&profile_info_ga, 1) == OK)) { profinfo_T *info = ((profinfo_T *)profile_info_ga.ga_data) + profile_info_ga.ga_len; *************** *** 289,296 **** // - if needed: a counter for number of closures created in // ectx->ec_funcrefs. varcount = dfunc->df_varcount + dfunc->df_has_closure; ! if (ga_grow(&ectx->ec_stack, arg_to_add + STACK_FRAME_SIZE + varcount) ! == FAIL) return FAIL; // If depth of calling is getting too high, don't execute the function. --- 297,304 ---- // - if needed: a counter for number of closures created in // ectx->ec_funcrefs. varcount = dfunc->df_varcount + dfunc->df_has_closure; ! if (unlikely(ga_grow(&ectx->ec_stack, arg_to_add + STACK_FRAME_SIZE ! + varcount) == FAIL)) return FAIL; // If depth of calling is getting too high, don't execute the function. *************** *** 361,367 **** else { ref->or_outer = ALLOC_CLEAR_ONE(outer_T); ! if (ref->or_outer == NULL) { vim_free(ref); return FAIL; --- 369,375 ---- else { ref->or_outer = ALLOC_CLEAR_ONE(outer_T); ! if (unlikely(ref->or_outer == NULL)) { vim_free(ref); return FAIL; *************** *** 703,709 **** // Result replaces the arguments on the stack. if (argcount > 0) ectx->ec_stack.ga_len -= argcount - 1; ! else if (GA_GROW(&ectx->ec_stack, 1) == FAIL) return FAIL; else ++ectx->ec_stack.ga_len; --- 711,717 ---- // Result replaces the arguments on the stack. if (argcount > 0) ectx->ec_stack.ga_len -= argcount - 1; ! else if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) return FAIL; else ++ectx->ec_stack.ga_len; *************** *** 941,947 **** { // Make space for arguments from the partial, shift the "argcount" // arguments up. ! if (ga_grow(&ectx->ec_stack, pt->pt_argc) == FAIL) return FAIL; for (i = 1; i <= argcount; ++i) *STACK_TV_BOT(-i + pt->pt_argc) = *STACK_TV_BOT(-i); --- 949,955 ---- { // Make space for arguments from the partial, shift the "argcount" // arguments up. ! if (unlikely(ga_grow(&ectx->ec_stack, pt->pt_argc) == FAIL)) return FAIL; for (i = 1; i <= argcount; ++i) *STACK_TV_BOT(-i + pt->pt_argc) = *STACK_TV_BOT(-i); *************** *** 1371,1377 **** // If this function returns and the closure is still being used, we // need to make a copy of the context (arguments and local variables). // Store a reference to the partial so we can handle that. ! if (ga_grow(&ectx->ec_funcrefs, 1) == FAIL) { vim_free(pt); return FAIL; --- 1379,1385 ---- // If this function returns and the closure is still being used, we // need to make a copy of the context (arguments and local variables). // Store a reference to the partial so we can handle that. ! if (unlikely(ga_grow(&ectx->ec_funcrefs, 1) == FAIL)) { vim_free(pt); return FAIL; *************** *** 1504,1510 **** p = skipwhite(p); if (*p == '#') break; ! if (ga_grow(&ga, 1) == OK) ((char_u **)(ga.ga_data))[ga.ga_len++] = p; if (STRNCMP(p, "def ", 4) == 0) break; --- 1512,1518 ---- p = skipwhite(p); if (*p == '#') break; ! if (likely(ga_grow(&ga, 1) == OK)) ((char_u **)(ga.ga_data))[ga.ga_len++] = p; if (STRNCMP(p, "def ", 4) == 0) break; *************** *** 1544,1555 **** isn_T *iptr; typval_T *tv; ! if (++breakcheck_count >= 100) { line_breakcheck(); breakcheck_count = 0; } ! if (got_int) { // Turn CTRL-C into an exception. got_int = FALSE; --- 1552,1563 ---- isn_T *iptr; typval_T *tv; ! if (unlikely(++breakcheck_count >= 100)) { line_breakcheck(); breakcheck_count = 0; } ! if (unlikely(got_int)) { // Turn CTRL-C into an exception. got_int = FALSE; *************** *** 1558,1564 **** did_throw = TRUE; } ! if (did_emsg && msg_list != NULL && *msg_list != NULL) { // Turn an error message into an exception. did_emsg = FALSE; --- 1566,1572 ---- did_throw = TRUE; } ! if (unlikely(did_emsg && msg_list != NULL && *msg_list != NULL)) { // Turn an error message into an exception. did_emsg = FALSE; *************** *** 1568,1574 **** *msg_list = NULL; } ! if (did_throw) { garray_T *trystack = &ectx->ec_trystack; trycmd_T *trycmd = NULL; --- 1576,1582 ---- *msg_list = NULL; } ! if (unlikely(did_throw)) { garray_T *trystack = &ectx->ec_trystack; trycmd_T *trycmd = NULL; *************** *** 1605,1611 **** { // Not inside try or need to return from current functions. // Push a dummy return value. ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_NUMBER; --- 1613,1619 ---- { // Not inside try or need to return from current functions. // Push a dummy return value. ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_NUMBER; *************** *** 1680,1686 **** int res; int save_flags = cmdmod.cmod_flags; ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; tv = STACK_TV_BOT(0); init_tv(tv); --- 1688,1694 ---- int res; int save_flags = cmdmod.cmod_flags; ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; tv = STACK_TV_BOT(0); init_tv(tv); *************** *** 1696,1702 **** // push typeval VAR_INSTR with instructions to be executed case ISN_INSTR: { ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; tv = STACK_TV_BOT(0); tv->vval.v_instr = ALLOC_ONE(instr_T); --- 1704,1710 ---- // push typeval VAR_INSTR with instructions to be executed case ISN_INSTR: { ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; tv = STACK_TV_BOT(0); tv->vval.v_instr = ALLOC_ONE(instr_T); *************** *** 1761,1767 **** clear_redir_lval(); redir_vname = 0; ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) { vim_free(res); goto theend; --- 1769,1775 ---- clear_redir_lval(); redir_vname = 0; ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) { vim_free(res); goto theend; *************** *** 1828,1834 **** if (pass == 1) { cmd = alloc(len + 1); ! if (cmd == NULL) goto theend; len = 0; } --- 1836,1842 ---- if (pass == 1) { cmd = alloc(len + 1); ! if (unlikely(cmd == NULL)) goto theend; len = 0; } *************** *** 1897,1903 **** p = tv_stringify(tv, buf); len = (int)STRLEN(p); ! if (ga_grow(&ga, len + 2) == FAIL) failed = TRUE; else { --- 1905,1911 ---- p = tv_stringify(tv, buf); len = (int)STRLEN(p); ! if (unlikely(ga_grow(&ga, len + 2) == FAIL)) failed = TRUE; else { *************** *** 1948,1954 **** // load local variable or argument case ISN_LOAD: ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; --- 1956,1962 ---- // load local variable or argument case ISN_LOAD: ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; *************** *** 1956,1962 **** // load v: variable case ISN_LOADV: ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; --- 1964,1970 ---- // load v: variable case ISN_LOADV: ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; *************** *** 1972,1978 **** if (sv == NULL) goto theend; allocate_if_null(sv->sv_tv); ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; copy_tv(sv->sv_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; --- 1980,1986 ---- if (sv == NULL) goto theend; allocate_if_null(sv->sv_tv); ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; copy_tv(sv->sv_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; *************** *** 1995,2001 **** } else { ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; copy_tv(&di->di_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; --- 2003,2009 ---- } else { ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; copy_tv(&di->di_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; *************** *** 2045,2051 **** } else { ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; copy_tv(&di->di_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; --- 2053,2059 ---- } else { ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; copy_tv(&di->di_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; *************** *** 2058,2064 **** { char_u *name = iptr->isn_arg.string; ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; SOURCING_LNUM = iptr->isn_lnum; if (eval_variable(name, (int)STRLEN(name), --- 2066,2072 ---- { char_u *name = iptr->isn_arg.string; ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; SOURCING_LNUM = iptr->isn_lnum; if (eval_variable(name, (int)STRLEN(name), *************** *** 2085,2091 **** default: // Cannot reach here goto theend; } ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_DICT; --- 2093,2099 ---- default: // Cannot reach here goto theend; } ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_DICT; *************** *** 2104,2110 **** // This is not expected to fail, name is checked during // compilation: don't set SOURCING_LNUM. ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; if (eval_option(&name, &optval, TRUE) == FAIL) goto theend; --- 2112,2118 ---- // This is not expected to fail, name is checked during // compilation: don't set SOURCING_LNUM. ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; if (eval_option(&name, &optval, TRUE) == FAIL) goto theend; *************** *** 2119,2125 **** typval_T optval; char_u *name = iptr->isn_arg.string; ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; // name is always valid, checked when compiling (void)eval_env_var(&name, &optval, TRUE); --- 2127,2133 ---- typval_T optval; char_u *name = iptr->isn_arg.string; ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; // name is always valid, checked when compiling (void)eval_env_var(&name, &optval, TRUE); *************** *** 2130,2136 **** // load @register case ISN_LOADREG: ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_STRING; --- 2138,2144 ---- // load @register case ISN_LOADREG: ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_STRING; *************** *** 2565,2571 **** + iptr->isn_arg.outer.outer_idx; if (iptr->isn_type == ISN_LOADOUTER) { ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; copy_tv(tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; --- 2573,2579 ---- + iptr->isn_arg.outer.outer_idx; if (iptr->isn_type == ISN_LOADOUTER) { ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; copy_tv(tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; *************** *** 2753,2759 **** case ISN_PUSHFUNC: case ISN_PUSHCHANNEL: case ISN_PUSHJOB: ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; tv = STACK_TV_BOT(0); tv->v_lock = 0; --- 2761,2767 ---- case ISN_PUSHFUNC: case ISN_PUSHCHANNEL: case ISN_PUSHJOB: ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; tv = STACK_TV_BOT(0); tv->v_lock = 0; *************** *** 2842,2848 **** char_u *key; int idx; ! if (dict == NULL) goto theend; for (idx = 0; idx < count; ++idx) { --- 2850,2856 ---- char_u *key; int idx; ! if (unlikely(dict == NULL)) goto theend; for (idx = 0; idx < count; ++idx) { *************** *** 2861,2867 **** } item = dictitem_alloc(key); clear_tv(tv); ! if (item == NULL) { dict_unref(dict); goto theend; --- 2869,2875 ---- } item = dictitem_alloc(key); clear_tv(tv); ! if (unlikely(item == NULL)) { dict_unref(dict); goto theend; *************** *** 2878,2884 **** if (count > 0) ectx->ec_stack.ga_len -= 2 * count - 1; ! else if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; else ++ectx->ec_stack.ga_len; --- 2886,2892 ---- if (count > 0) ectx->ec_stack.ga_len -= 2 * count - 1; ! else if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; else ++ectx->ec_stack.ga_len; *************** *** 2960,2966 **** // return from a :def function call without a value case ISN_RETURN_VOID: ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; --- 2968,2974 ---- // return from a :def function call without a value case ISN_RETURN_VOID: ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; *************** *** 3002,3008 **** if (pt == NULL) goto theend; ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) { vim_free(pt); goto theend; --- 3010,3016 ---- if (pt == NULL) goto theend; ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) { vim_free(pt); goto theend; *************** *** 3097,3103 **** typval_T *idxtv = STACK_TV_VAR(iptr->isn_arg.forloop.for_idx); ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; if (ltv->v_type == VAR_LIST) { --- 3105,3111 ---- typval_T *idxtv = STACK_TV_VAR(iptr->isn_arg.forloop.for_idx); ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; if (ltv->v_type == VAR_LIST) { *************** *** 3204,3210 **** { trycmd_T *trycmd = NULL; ! if (GA_GROW(&ectx->ec_trystack, 1) == FAIL) goto theend; trycmd = ((trycmd_T *)ectx->ec_trystack.ga_data) + ectx->ec_trystack.ga_len; --- 3212,3218 ---- { trycmd_T *trycmd = NULL; ! if (unlikely(GA_GROW(&ectx->ec_trystack, 1) == FAIL)) goto theend; trycmd = ((trycmd_T *)ectx->ec_trystack.ga_data) + ectx->ec_trystack.ga_len; *************** *** 3229,3235 **** iemsg("Evaluating catch while current_exception is NULL"); goto theend; } ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; --- 3237,3243 ---- iemsg("Evaluating catch while current_exception is NULL"); goto theend; } ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; *************** *** 3888,3894 **** tv = STACK_TV_BOT(-1 - gi->gi_with_op); li = list_find(tv->vval.v_list, gi->gi_index); ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; ++ectx->ec_stack.ga_len; copy_tv(&li->li_tv, STACK_TV_BOT(-1)); --- 3896,3902 ---- tv = STACK_TV_BOT(-1 - gi->gi_with_op); li = list_find(tv->vval.v_list, gi->gi_index); ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; ++ectx->ec_stack.ga_len; copy_tv(&li->li_tv, STACK_TV_BOT(-1)); *************** *** 4123,4129 **** if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL) goto on_error; ! if (GA_GROW(&ectx->ec_stack, 1) == FAIL) goto theend; ++ectx->ec_stack.ga_len; tv = STACK_TV_BOT(-1); --- 4131,4137 ---- if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL) goto on_error; ! if (unlikely(GA_GROW(&ectx->ec_stack, 1) == FAIL)) goto theend; ++ectx->ec_stack.ga_len; tv = STACK_TV_BOT(-1); *************** *** 4225,4231 **** } CHECK_LIST_MATERIALIZE(l); ! if (GA_GROW(&ectx->ec_stack, count - 1) == FAIL) goto theend; ectx->ec_stack.ga_len += count - 1; --- 4233,4239 ---- } CHECK_LIST_MATERIALIZE(l); ! if (unlikely(GA_GROW(&ectx->ec_stack, count - 1) == FAIL)) goto theend; ectx->ec_stack.ga_len += count - 1; *************** *** 4499,4505 **** CLEAR_FIELD(ectx); ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx; ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); ! if (ga_grow(&ectx.ec_stack, 20) == FAIL) { funcdepth_decrement(); return FAIL; --- 4507,4513 ---- CLEAR_FIELD(ectx); ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx; ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); ! if (unlikely(ga_grow(&ectx.ec_stack, 20) == FAIL)) { funcdepth_decrement(); return FAIL; *************** *** 5506,5512 **** NULL, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE); buf = alloc(len + 1); ! if (buf != NULL) { (void)produce_cmdmods( buf, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE); --- 5514,5520 ---- NULL, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE); buf = alloc(len + 1); ! if (likely(buf != NULL)) { (void)produce_cmdmods( buf, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE); *** ../vim-8.2.3211/src/version.c 2021-07-24 16:16:11.542239515 +0200 --- src/version.c 2021-07-24 19:30:35.532944023 +0200 *************** *** 757,758 **** --- 757,760 ---- { /* Add new patch number below this line */ + /**/ + 3212, /**/ -- hundred-and-one symptoms of being an internet addict: 204. You have learned not to fall asleep on your keyboard the hard way /// 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 ///