Browse Source

Small optimizations in range checks

Checks of the form '1 <= x && x <= M' were rewritten in the form
'(unsigned)x - 1 < (unsigned)M', which is usually more efficient.
(Other similar checks have similar translations.) Although
some compilers do these optimizations, that does not happen
for all compilers or all cases.
pull/22/head
Roberto Ierusalimschy 6 years ago
parent
commit
d12262068d
  1. 10
      lapi.c
  2. 10
      ltable.c
  3. 8
      ltablib.c
  4. 3
      testes/utf8.lua

10
lapi.c

@ -936,8 +936,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
api_checknelems(L, 1); api_checknelems(L, 1);
o = index2value(L, idx); o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected"); api_check(L, ttisfulluserdata(o), "full userdata expected");
if (!(0 < n && n <= uvalue(o)->nuvalue)) if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
res = 0; res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
else { else {
setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1)); setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1));
luaC_barrierback(L, gcvalue(o), s2v(L->top - 1)); luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
@ -1313,7 +1313,8 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
switch (ttypetag(fi)) { switch (ttypetag(fi)) {
case LUA_TCCL: { /* C closure */ case LUA_TCCL: { /* C closure */
CClosure *f = clCvalue(fi); CClosure *f = clCvalue(fi);
if (!(1 <= n && n <= f->nupvalues)) return NULL; if (!(cast_uint(n) - 1u < cast_uint(f->nupvalues)))
return NULL; /* 'n' not in [1, f->nupvalues] */
*val = &f->upvalue[n-1]; *val = &f->upvalue[n-1];
if (owner) *owner = obj2gco(f); if (owner) *owner = obj2gco(f);
return ""; return "";
@ -1322,7 +1323,8 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
LClosure *f = clLvalue(fi); LClosure *f = clLvalue(fi);
TString *name; TString *name;
Proto *p = f->p; Proto *p = f->p;
if (!(1 <= n && n <= p->sizeupvalues)) return NULL; if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
return NULL; /* 'n' not in [1, p->sizeupvalues] */
*val = f->upvals[n-1]->v; *val = f->upvals[n-1]->v;
if (owner) *owner = obj2gco(f->upvals[n - 1]); if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name; name = p->upvalues[n-1].name;

10
ltable.c

@ -48,8 +48,8 @@
/* /*
** MAXASIZE is the maximum size of the array part. It is the minimum ** MAXASIZE is the maximum size of the array part. It is the minimum
** between 2^MAXABITS and the maximum size such that, measured in bytes, ** between 2^MAXABITS and the maximum size that, measured in bytes,
** it fits in a 'size_t'. ** fits in a 'size_t'.
*/ */
#define MAXASIZE luaM_limitN(1u << MAXABITS, TValue) #define MAXASIZE luaM_limitN(1u << MAXABITS, TValue)
@ -269,7 +269,7 @@ static const TValue *getgeneric (Table *t, const TValue *key) {
** the array part of a table, 0 otherwise. ** the array part of a table, 0 otherwise.
*/ */
static unsigned int arrayindex (lua_Integer k) { static unsigned int arrayindex (lua_Integer k) {
if (0 < k && l_castS2U(k) <= MAXASIZE) if (l_castS2U(k) - 1u < MAXASIZE) /* 'k' in [1, MAXASIZE]? */
return cast_uint(k); /* 'key' is an appropriate array index */ return cast_uint(k); /* 'key' is an appropriate array index */
else else
return 0; return 0;
@ -286,7 +286,7 @@ static unsigned int findindex (lua_State *L, Table *t, TValue *key,
unsigned int i; unsigned int i;
if (ttisnil(key)) return 0; /* first iteration */ if (ttisnil(key)) return 0; /* first iteration */
i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0; i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0;
if (i != 0 && i <= asize) /* is 'key' inside array part? */ if (i - 1u < asize) /* is 'key' inside array part? */
return i; /* yes; that's the index */ return i; /* yes; that's the index */
else { else {
const TValue *n = getgeneric(t, key); const TValue *n = getgeneric(t, key);
@ -678,7 +678,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
** changing the real size of the array). ** changing the real size of the array).
*/ */
const TValue *luaH_getint (Table *t, lua_Integer key) { const TValue *luaH_getint (Table *t, lua_Integer key) {
if (l_castS2U(key) - 1u < t->alimit) /* (1 <= key && key <= t->alimit)? */ if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */
return &t->array[key - 1]; return &t->array[key - 1];
else if (!limitequalsasize(t) && /* key still may be in the array part? */ else if (!limitequalsasize(t) && /* key still may be in the array part? */
(l_castS2U(key) == t->alimit + 1 || (l_castS2U(key) == t->alimit + 1 ||

8
ltablib.c

@ -69,7 +69,9 @@ static int tinsert (lua_State *L) {
case 3: { case 3: {
lua_Integer i; lua_Integer i;
pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */
luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); /* check whether 'pos' is in [1, e] */
luaL_argcheck(L, (lua_Unsigned)pos - 1u < (lua_Unsigned)e, 2,
"position out of bounds");
for (i = e; i > pos; i--) { /* move up elements */ for (i = e; i > pos; i--) { /* move up elements */
lua_geti(L, 1, i - 1); lua_geti(L, 1, i - 1);
lua_seti(L, 1, i); /* t[i] = t[i - 1] */ lua_seti(L, 1, i); /* t[i] = t[i - 1] */
@ -89,7 +91,9 @@ static int tremove (lua_State *L) {
lua_Integer size = aux_getn(L, 1, TAB_RW); lua_Integer size = aux_getn(L, 1, TAB_RW);
lua_Integer pos = luaL_optinteger(L, 2, size); lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */ if (pos != size) /* validate 'pos' if given */
luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); /* check whether 'pos' is in [1, size + 1] */
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1,
"position out of bounds");
lua_geti(L, 1, pos); /* result = t[pos] */ lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) { for ( ; pos < size; pos++) {
lua_geti(L, 1, pos + 1); lua_geti(L, 1, pos + 1);

3
testes/utf8.lua

@ -123,6 +123,9 @@ checkerror("continuation byte", utf8.offset, "𦧺", 1, 2)
checkerror("continuation byte", utf8.offset, "𦧺", 1, 2) checkerror("continuation byte", utf8.offset, "𦧺", 1, 2)
checkerror("continuation byte", utf8.offset, "\x80", 1) checkerror("continuation byte", utf8.offset, "\x80", 1)
-- error in indices for len
checkerror("out of string", utf8.len, "abc", 0, 2)
checkerror("out of string", utf8.len, "abc", 1, 4)
local s = "hello World" local s = "hello World"

Loading…
Cancel
Save