commit e381c582de1b80a5f3df2c0d36fc25b415b48de0
parent 9600c60df3e5a971ca642734470901775ef67ff9
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Thu, 25 Apr 2013 16:12:16 -0300
integer handling for order comparisons, power, and modulo operations
Diffstat:
M | lvm.c | | | 84 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- |
M | lvm.h | | | 5 | ++++- |
2 files changed, 83 insertions(+), 6 deletions(-)
diff --git a/lvm.c b/lvm.c
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 2.159 2013/04/25 15:59:42 roberto Exp roberto $
+** $Id: lvm.c,v 2.160 2013/04/25 16:07:52 roberto Exp roberto $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -150,7 +150,9 @@ static int l_strcmp (const TString *ls, const TString *rs) {
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
int res;
- if (ttisnumber(l) && ttisnumber(r))
+ if (ttisinteger(l) && ttisinteger(r))
+ return (ivalue(l) < ivalue(r));
+ else if (ttisnumber(l) && ttisnumber(r))
return luai_numlt(L, nvalue(l), nvalue(r));
else if (ttisstring(l) && ttisstring(r))
return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0;
@@ -162,7 +164,9 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
int res;
- if (ttisnumber(l) && ttisnumber(r))
+ if (ttisinteger(l) && ttisinteger(r))
+ return (ivalue(l) <= ivalue(r));
+ else if (ttisnumber(l) && ttisnumber(r))
return luai_numle(L, nvalue(l), nvalue(r));
else if (ttisstring(l) && ttisstring(r))
return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0;
@@ -283,6 +287,54 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
}
+lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y) {
+ if (cast_unsigned(y) + 1 <= 1U) { /* special cases: -1 or 0 */
+ if (y == 0)
+ luaG_runerror(L, "attempt to divide by zero");
+ else /* -1 */
+ return -x; /* avoid overflow with 0x80000... */
+ }
+ else {
+ lua_Integer d = x / y; /* perform division */
+ if ((x ^ y) >= 0 || x % y == 0) /* same signal or no rest? */
+ return d;
+ else
+ return d - 1; /* correct 'div' for negative case */
+ }
+}
+
+
+lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y) {
+ if (cast_unsigned(y) + 1 <= 1U) { /* special cases: -1 or 0 */
+ if (y == 0)
+ luaG_runerror(L, "attempt to divide by zero (in '%%')");
+ else /* -1 */
+ return 0; /* avoid overflow with 0x80000... */
+ }
+ else {
+ lua_Integer r = x % y;
+ if (r == 0 || (x ^ y) >= 0)
+ return r;
+ else
+ return r + y; /* correct 'mod' for negative case */
+ }
+}
+
+
+lua_Integer luaV_pow (lua_Integer x, lua_Integer y) {
+ lua_Integer r = 1;
+ lua_assert(y >= 0);
+ if (y == 0) return r;
+ for (; y > 1; y >>= 1) {
+ if (y & 1)
+ r = cast_integer(cast_unsigned(r) * cast_unsigned(x));
+ x = cast_integer(cast_unsigned(x) * cast_unsigned(x));
+ }
+ r = cast_integer(cast_unsigned(r) * cast_unsigned(x));
+ return r;
+}
+
+
void luaV_arith (lua_State *L, StkId ra, const TValue *rb,
const TValue *rc, TMS op) {
TValue tempb, tempc;
@@ -589,10 +641,32 @@ void luaV_execute (lua_State *L) {
else { Protect(luaV_arith(L, ra, rb, rc, TM_DIV)); }
)
vmcase(OP_MOD,
- arith_op(luai_nummod, TM_MOD);
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ if (ttisinteger(rb) && ttisinteger(rc)) {
+ lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
+ setivalue(ra, luaV_mod(L, ib, ic));
+ }
+ else if (ttisnumber(rb) && ttisnumber(rc)) {
+ lua_Number nb = nvalue(rb); lua_Number nc = nvalue(rc);
+ setnvalue(ra, luai_nummod(L, nb, nc));
+ }
+ else { Protect(luaV_arith(L, ra, rb, rc, TM_MOD)); }
)
vmcase(OP_POW,
- arith_op(luai_numpow, TM_POW);
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ lua_Integer ic;
+ if (ttisinteger(rb) && ttisinteger(rc) &&
+ (ic = ivalue(rc)) >= 0) {
+ lua_Integer ib = ivalue(rb);
+ setivalue(ra, luaV_pow(ib, ic));
+ }
+ else if (ttisnumber(rb) && ttisnumber(rc)) {
+ lua_Number nb = nvalue(rb); lua_Number nc = nvalue(rc);
+ setnvalue(ra, luai_numpow(L, nb, nc));
+ }
+ else { Protect(luaV_arith(L, ra, rb, rc, TM_POW)); }
)
vmcase(OP_UNM,
TValue *rb = RB(i);
diff --git a/lvm.h b/lvm.h
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.h,v 2.17 2011/05/31 18:27:56 roberto Exp $
+** $Id: lvm.h,v 2.19 2013/04/15 15:44:46 roberto Exp roberto $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -33,6 +33,9 @@ LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total);
+LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y);
+LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y);
+LUAI_FUNC lua_Integer luaV_pow (lua_Integer x, lua_Integer y);
LUAI_FUNC void luaV_arith (lua_State *L, StkId ra, const TValue *rb,
const TValue *rc, TMS op);
LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb);