From 34aa0c5bd7493b6e01983df28f04af46a3d99967 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy <roberto@inf.puc-rio.br> Date: Wed, 30 May 2018 11:25:52 -0300 Subject: new macros 'likely'/'unlikely' with hints for jump predictions (used only in errors for now) --- ldo.c | 18 +++++++++--------- llimits.h | 21 ++++++++++++++++++++- lmem.c | 44 +++++++++++++++++++++++++++----------------- lstring.c | 10 +++++----- ltable.c | 11 ++++++----- lvm.c | 22 +++++++++++----------- 6 files changed, 78 insertions(+), 48 deletions(-) diff --git a/ldo.c b/ldo.c index 169eb714..fb077211 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.200 2018/03/16 15:33:34 roberto Exp roberto $ +** $Id: ldo.c,v 2.201 2018/05/22 12:02:36 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -182,7 +182,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { StkId newstack = luaM_reallocvector(L, L->stack, lim, newsize, StackValue); lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); - if (newstack == NULL) { /* reallocation failed? */ + if (unlikely(newstack == NULL)) { /* reallocation failed? */ if (raiseerror) luaM_error(L); else return 0; /* do not raise an error */ @@ -204,7 +204,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { int luaD_growstack (lua_State *L, int n, int raiseerror) { int size = L->stacksize; int newsize = 2 * size; /* tentative new size */ - if (size > LUAI_MAXSTACK) { /* need more space after extra size? */ + if (unlikely(size > LUAI_MAXSTACK)) { /* need more space after extra size? */ if (raiseerror) luaD_throw(L, LUA_ERRERR); /* error inside message handler */ else return 0; @@ -215,7 +215,7 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) { newsize = LUAI_MAXSTACK; if (newsize < needed) /* but must respect what was asked for */ newsize = needed; - if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ + if (unlikely(newsize > LUAI_MAXSTACK)) { /* stack overflow? */ /* add extra size to be able to handle the error message */ luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror); if (raiseerror) @@ -350,7 +350,7 @@ static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) { void luaD_tryfuncTM (lua_State *L, StkId func) { const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); StkId p; - if (!ttisfunction(tm)) + if (unlikely(!ttisfunction(tm))) luaG_typeerror(L, s2v(func), "call"); for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); @@ -660,14 +660,14 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, L->nny = 0; /* allow yields */ api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); status = luaD_rawrunprotected(L, resume, &nargs); - if (status == -1) /* error calling 'lua_resume'? */ + if (unlikely(status == -1)) /* error calling 'lua_resume'? */ status = LUA_ERRRUN; else { /* continue running after recoverable errors */ while (errorstatus(status) && recover(L, status)) { /* unroll continuation */ status = luaD_rawrunprotected(L, unroll, &status); } - if (errorstatus(status)) { /* unrecoverable error? */ + if (unlikely(errorstatus(status))) { /* unrecoverable error? */ L->status = cast_byte(status); /* mark thread as 'dead' */ seterrorobj(L, status, L->top); /* push error message */ L->ci->top = L->top; @@ -694,7 +694,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, luai_userstateyield(L, nresults); lua_lock(L); api_checknelems(L, nresults); - if (L->nny > 0) { + if (unlikely(L->nny > 0)) { if (L != G(L)->mainthread) luaG_runerror(L, "attempt to yield across a C-call boundary"); else @@ -727,7 +727,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_errfunc = L->errfunc; L->errfunc = ef; status = luaD_rawrunprotected(L, func, u); - if (status != LUA_OK) { /* an error occurred? */ + if (unlikely(status != LUA_OK)) { /* an error occurred? */ StkId oldtop = restorestack(L, old_top); luaF_close(L, oldtop); /* close possible pending closures */ seterrorobj(L, status, oldtop); diff --git a/llimits.h b/llimits.h index 9a3ae8d0..725d7c8b 100644 --- a/llimits.h +++ b/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.148 2017/12/28 11:51:00 roberto Exp roberto $ +** $Id: llimits.h,v 1.149 2018/01/28 15:13:26 roberto Exp roberto $ ** Limits, basic types, and some other 'installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -130,9 +130,27 @@ typedef LUAI_UACINT l_uacInt; #endif +/* +** macros to improve jump prediction (used mainly for error handling) +*/ +#if !defined(likely) + +#if defined(__GNUC__) +#define likely(x) (__builtin_expect(((x) != 0), 1)) +#define unlikely(x) (__builtin_expect(((x) != 0), 0)) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif + +#endif + + /* ** non-return type */ +#if !defined(l_noret) + #if defined(__GNUC__) #define l_noret void __attribute__((noreturn)) #elif defined(_MSC_VER) && _MSC_VER >= 1200 @@ -141,6 +159,7 @@ typedef LUAI_UACINT l_uacInt; #define l_noret void #endif +#endif /* diff --git a/lmem.c b/lmem.c index 2c1757f5..5c73acd5 100644 --- a/lmem.c +++ b/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.95 2017/12/11 12:27:48 roberto Exp roberto $ +** $Id: lmem.c,v 1.96 2018/01/28 15:13:26 roberto Exp roberto $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -60,7 +60,7 @@ void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize, if (nelems + 1 <= size) /* does one extra element still fit? */ return block; /* nothing to be done */ if (size >= limit / 2) { /* cannot double it? */ - if (size >= limit) /* cannot grow even a little? */ + if (unlikely(size >= limit)) /* cannot grow even a little? */ luaG_runerror(L, "too many %s (limit is %d)", what, limit); size = limit; /* still have at least one free place */ } @@ -73,7 +73,7 @@ void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize, /* 'limit' ensures that multiplication will not overflow */ newblock = luaM_realloc_(L, block, cast_sizet(*psize) * size_elems, cast_sizet(size) * size_elems); - if (newblock == NULL) + if (unlikely(newblock == NULL)) luaM_error(L); *psize = size; /* update only when everything else is OK */ return newblock; @@ -88,7 +88,7 @@ void *luaM_shrinkvector_ (lua_State *L, void *block, int *size, size_t newsize = cast_sizet(final_n * size_elem); lua_assert(newsize <= oldsize); newblock = (*g->frealloc)(g->ud, block, oldsize, newsize); - if (newblock == NULL && final_n > 0) /* allocation failed? */ + if (unlikely(newblock == NULL && final_n > 0)) /* allocation failed? */ luaM_error(L); else { g->GCdebt += newsize - oldsize; @@ -114,6 +114,22 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) { } +/* +** In case of allocation fail, this function will call the GC to try +** to free some memory and then try the allocation again. +** (It should not be called when shrinking a block, because then the +** interpreter may be in the middle of a collection step.) +*/ +static void *tryagain (lua_State *L, void *block, + size_t osize, size_t nsize) { + global_State *g = G(L); + if (g->version) { /* is state fully build? */ + luaC_fullgc(L, 1); /* try to free some memory... */ + return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ + } + else return NULL; /* cannot free any memory without a full state */ +} + /* ** generic allocation routine. @@ -124,13 +140,10 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { lua_assert((osize == 0) == (block == NULL)); hardtest(L, osize, nsize); newblock = (*g->frealloc)(g->ud, block, osize, nsize); - if (newblock == NULL && nsize > 0) { - /* Is state fully built? Not shrinking a block? */ - if (g->version && nsize > osize) { - luaC_fullgc(L, 1); /* try to free some memory... */ - newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ - } - if (newblock == NULL) + if (unlikely(newblock == NULL && nsize > 0)) { + if (nsize > osize) /* not shrinking a block? */ + newblock = tryagain(L, block, osize, nsize); + if (newblock == NULL) /* still no memory? */ return NULL; } lua_assert((nsize == 0) == (newblock == NULL)); @@ -142,7 +155,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { void *newblock = luaM_realloc_(L, block, osize, nsize); - if (newblock == NULL && nsize > 0) /* allocation failed? */ + if (unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */ luaM_error(L); return newblock; } @@ -155,11 +168,8 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) { else { global_State *g = G(L); void *newblock = (*g->frealloc)(g->ud, NULL, tag, size); - if (newblock == NULL) { - if (g->version) { /* is state fully built? */ - luaC_fullgc(L, 1); /* try to free some memory... */ - newblock = (*g->frealloc)(g->ud, NULL, tag, size); /* try again */ - } + if (unlikely(newblock == NULL)) { + newblock = tryagain(L, NULL, tag, size); if (newblock == NULL) luaM_error(L); } diff --git a/lstring.c b/lstring.c index 29a08212..f1e5d82b 100644 --- a/lstring.c +++ b/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.64 2018/02/15 18:06:24 roberto Exp roberto $ +** $Id: lstring.c,v 2.65 2018/02/20 16:52:50 roberto Exp roberto $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -99,7 +99,7 @@ void luaS_resize (lua_State *L, int nsize) { if (nsize < osize) /* shrinking table? */ tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */ newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*); - if (newvect == NULL) { /* reallocation failed? */ + if (unlikely(newvect == NULL)) { /* reallocation failed? */ if (nsize < osize) /* was it shrinking table? */ tablerehash(tb->hash, nsize, osize); /* restore to original size */ /* leave table as it was */ @@ -182,7 +182,7 @@ void luaS_remove (lua_State *L, TString *ts) { static void growstrtab (lua_State *L, stringtable *tb) { - if (tb->nuse == MAX_INT) { /* too many strings? */ + if (unlikely(tb->nuse == MAX_INT)) { /* too many strings? */ luaC_fullgc(L, 1); /* try to free some... */ if (tb->nuse == MAX_INT) /* still too many? */ luaM_error(L); /* cannot even create a message... */ @@ -233,7 +233,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { return internshrstr(L, str, l); else { TString *ts; - if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char)) + if (unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) luaM_toobig(L); ts = luaS_createlngstrobj(L, l); memcpy(getstr(ts), str, l * sizeof(char)); @@ -269,7 +269,7 @@ Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) { Udata *u; int i; GCObject *o; - if (s > MAX_SIZE - udatamemoffset(nuvalue)) + if (unlikely(s > MAX_SIZE - udatamemoffset(nuvalue))) luaM_toobig(L); o = luaC_newobj(L, LUA_TUSERDATA, sizeudata(nuvalue, s)); u = gco2u(o); diff --git a/ltable.c b/ltable.c index 7113f0ff..56fe64fd 100644 --- a/ltable.c +++ b/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.135 2018/02/26 14:16:05 roberto Exp roberto $ +** $Id: ltable.c,v 2.136 2018/05/29 18:01:50 roberto Exp roberto $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -235,7 +235,7 @@ static unsigned int findindex (lua_State *L, Table *t, TValue *key) { return i; /* yes; that's the index */ else { const TValue *n = getgeneric(t, key); - if (n == luaH_emptyobject) + if (unlikely(n == luaH_emptyobject)) luaG_runerror(L, "invalid key to 'next'"); /* key not found */ i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ @@ -467,7 +467,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, } /* allocate new array */ newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); - if (newarray == NULL && newasize > 0) { /* allocation failed? */ + if (unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ freehash(L, &newt); /* release new hash part */ luaM_error(L); /* raise error (with array unchanged) */ } @@ -560,7 +560,8 @@ static Node *getfreepos (Table *t) { TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { Node *mp; TValue aux; - if (ttisnil(key)) luaG_runerror(L, "table index is nil"); + if (unlikely(ttisnil(key))) + luaG_runerror(L, "table index is nil"); else if (ttisfloat(key)) { lua_Number f = fltvalue(key); lua_Integer k; @@ -568,7 +569,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { setivalue(&aux, k); key = &aux; /* insert it as an integer */ } - else if (luai_numisnan(f)) + else if (unlikely(luai_numisnan(f))) luaG_runerror(L, "table index is NaN"); } mp = mainpositionTV(t, key); diff --git a/lvm.c b/lvm.c index 4406afb6..36c7699f 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.354 2018/05/02 18:17:59 roberto Exp roberto $ +** $Id: lvm.c,v 2.355 2018/05/22 12:02:36 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -196,7 +196,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, if (slot == NULL) { /* 't' is not a table? */ lua_assert(!ttistable(t)); tm = luaT_gettmbyobj(L, t, TM_INDEX); - if (notm(tm)) + if (unlikely(notm(tm))) luaG_typeerror(L, t, "index"); /* no metamethod */ /* else will try the metamethod */ } @@ -253,7 +253,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, } else { /* not a table; check metamethod */ tm = luaT_gettmbyobj(L, t, TM_NEWINDEX); - if (notm(tm)) + if (unlikely(notm(tm))) luaG_typeerror(L, t, "index"); } /* try the metamethod */ @@ -561,7 +561,7 @@ void luaV_concat (lua_State *L, int total) { /* collect total length and number of strings */ for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { size_t l = vslen(s2v(top - n - 1)); - if (l >= (MAX_SIZE/sizeof(char)) - tl) + if (unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) luaG_runerror(L, "string length overflow"); tl += l; } @@ -605,7 +605,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { } default: { /* try metamethod */ tm = luaT_gettmbyobj(L, rb, TM_LEN); - if (notm(tm)) /* no metamethod? */ + if (unlikely(notm(tm))) /* no metamethod? */ luaG_typeerror(L, rb, "get length of"); break; } @@ -622,7 +622,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { */ lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ - if (n == 0) + if (unlikely(n == 0)) luaG_runerror(L, "attempt to divide by zero"); return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ } @@ -642,7 +642,7 @@ lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { */ lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ - if (n == 0) + if (unlikely(n == 0)) luaG_runerror(L, "attempt to perform 'n%%0'"); return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ } @@ -1665,7 +1665,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { TValue *plimit = s2v(ra + 1); lua_Integer ilimit, initv; int stopnow; - if (!forlimit(plimit, &ilimit, 1, &stopnow)) { + if (unlikely(!forlimit(plimit, &ilimit, 1, &stopnow))) { savestate(L, ci); /* for the error message */ luaG_runerror(L, "'for' limit must be a number"); } @@ -1717,13 +1717,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) { else { /* try making all values floats */ lua_Number ninit; lua_Number nlimit; lua_Number nstep; savestate(L, ci); /* in case of errors */ - if (!tonumber(plimit, &nlimit)) + if (unlikely(!tonumber(plimit, &nlimit))) luaG_runerror(L, "'for' limit must be a number"); setfltvalue(plimit, nlimit); - if (!tonumber(pstep, &nstep)) + if (unlikely(!tonumber(pstep, &nstep))) luaG_runerror(L, "'for' step must be a number"); setfltvalue(pstep, nstep); - if (!tonumber(init, &ninit)) + if (unlikely(!tonumber(init, &ninit))) luaG_runerror(L, "'for' initial value must be a number"); setfltvalue(init, luai_numsub(L, ninit, nstep)); } -- cgit v1.2.3-55-g6feb