diff options
author | Lua Team <team@lua.org> | 2013-07-06 12:00:00 +0000 |
---|---|---|
committer | repogen <> | 2013-07-06 12:00:00 +0000 |
commit | 87cc247b6b22184fba47184c218a642ea7a49e96 (patch) | |
tree | 299ba8b72b95aa32336b5c810b7133f8efc4fb29 /src/lcode.c | |
parent | dc27609467d2699ac9252e89d632432ac5f798f2 (diff) | |
download | lua-github-5.3.0-work1.tar.gz |
Lua 5.3.0-work15.3.0-work1
Diffstat (limited to 'src/lcode.c')
-rw-r--r-- | src/lcode.c | 126 |
1 files changed, 87 insertions, 39 deletions
diff --git a/src/lcode.c b/src/lcode.c index 56c26ac8..261090e0 100644 --- a/src/lcode.c +++ b/src/lcode.c @@ -1,10 +1,11 @@ /* -** $Id: lcode.c,v 2.62 2012/08/16 17:34:28 roberto Exp $ +** $Id: lcode.c,v 2.71 2013/06/25 18:57:18 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ +#include <math.h> #include <stdlib.h> #define lcode_c @@ -26,11 +27,29 @@ #include "lvm.h" +/* test for x == -0 */ +#if defined(signbit) +#define isminuszero(x) ((x) == 0.0 && signbit(x)) +#else +#define isminuszero(x) ((x) == 0.0 && 1.0/(x) < 0.0) +#endif + + #define hasjumps(e) ((e)->t != (e)->f) -static int isnumeral(expdesc *e) { - return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); +static int tonumeral(expdesc *e, TValue *v) { + if (e->t != NO_JUMP || e->f != NO_JUMP) + return 0; /* not a numeral */ + switch (e->k) { + case VKINT: + if (v) setivalue(v, e->u.ival); + return 1; + case VKFLT: + if (v) setnvalue(v, e->u.nval); + return 1; + default: return 0; + } } @@ -293,9 +312,8 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { TValue *idx = luaH_set(L, fs->h, key); Proto *f = fs->f; int k, oldsize; - if (ttisnumber(idx)) { - lua_Number n = nvalue(idx); - lua_number2int(k, n); + if (ttisinteger(idx)) { + k = ivalue(idx); if (luaV_rawequalobj(&f->k[k], v)) return k; /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0"); @@ -306,7 +324,7 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { k = fs->nk; /* numerical value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ - setnvalue(idx, cast_num(k)); + setivalue(idx, k); luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); setobj(L, &f->k[k], v); @@ -323,20 +341,28 @@ int luaK_stringK (FuncState *fs, TString *s) { } -int luaK_numberK (FuncState *fs, lua_Number r) { - int n; - lua_State *L = fs->ls->L; +/* +** use userdata as key to avoid collision with float with same value; +** conversion to 'void*' used only for hash, no "precision" problems +*/ +int luaK_intK (FuncState *fs, lua_Integer n) { + TValue k, o; + setpvalue(&k, cast(void*, cast(size_t, n))); + setivalue(&o, n); + return addk(fs, &k, &o); +} + + +/* +** Both NaN and -0.0 should not go to the constant table, as they have +** problems with the hashing. (NaN is not ** a valid key, +** -0.0 collides with +0.0.) +*/ +static int luaK_numberK (FuncState *fs, lua_Number r) { TValue o; + lua_assert(!luai_numisnan(NULL, r) && !isminuszero(r)); setnvalue(&o, r); - if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */ - /* use raw representation as key to avoid numeric problems */ - setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r))); - n = addk(fs, L->top - 1, &o); - L->top--; - } - else - n = addk(fs, &o, &o); /* regular case */ - return n; + return addk(fs, &o, &o); } @@ -433,10 +459,14 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_codek(fs, reg, e->u.info); break; } - case VKNUM: { + case VKFLT: { luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); break; } + case VKINT: { + luaK_codek(fs, reg, luaK_intK(fs, e->u.ival)); + break; + } case VRELOCABLE: { Instruction *pc = &getcode(fs, e); SETARG_A(*pc, reg); @@ -538,12 +568,18 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) { } else break; } - case VKNUM: { + case VKINT: { + e->u.info = luaK_intK(fs, e->u.ival); + e->k = VK; + goto vk; + } + case VKFLT: { e->u.info = luaK_numberK(fs, e->u.nval); e->k = VK; /* go through */ } case VK: { + vk: if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */ return RKASK(e->u.info); else break; @@ -627,7 +663,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) { pc = e->u.info; break; } - case VK: case VKNUM: case VTRUE: { + case VK: case VKFLT: case VKINT: case VTRUE: { pc = NO_JUMP; /* always true; do nothing */ break; } @@ -672,7 +708,7 @@ static void codenot (FuncState *fs, expdesc *e) { e->k = VTRUE; break; } - case VK: case VKNUM: case VTRUE: { + case VK: case VKFLT: case VKINT: case VTRUE: { e->k = VFALSE; break; } @@ -711,21 +747,34 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { - lua_Number r; - if (!isnumeral(e1) || !isnumeral(e2)) return 0; - if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0) - return 0; /* do not attempt to divide by 0 */ - r = luaO_arith(op - OP_ADD + LUA_OPADD, e1->u.nval, e2->u.nval); - e1->u.nval = r; + TValue v1, v2, res; + lua_Integer i; + if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2)) + return 0; + if (op == OP_IDIV && + (!tointeger(&v1, &i) || !tointeger(&v2, &i) || i == 0)) + return 0; /* avoid division by 0 and conversion errors */ + if (op == OP_MOD && ttisinteger(&v1) && ttisinteger(&v2) && ivalue(&v2) == 0) + return 0; /* avoid module by 0 at compile time */ + luaO_arith(NULL, op - OP_ADD + LUA_OPADD, &v1, &v2, &res); + if (ttisinteger(&res)) { + e1->k = VKINT; + e1->u.ival = ivalue(&res); + } + else { + lua_Number n = fltvalue(&res); + if (luai_numisnan(NULL, n) || isminuszero(n)) + return 0; /* folds neither NaN nor -0 */ + e1->k = VKFLT; + e1->u.nval = n; + } return 1; } static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2, int line) { - if (constfolding(op, e1, e2)) - return; - else { + if (!constfolding(op, e1, e2)) { /* could not fold operation? */ int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; int o1 = luaK_exp2RK(fs, e1); if (o1 > o2) { @@ -761,12 +810,10 @@ static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { expdesc e2; - e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; + e2.t = e2.f = NO_JUMP; e2.k = VKFLT; e2.u.nval = 0; switch (op) { case OPR_MINUS: { - if (isnumeral(e)) /* minus constant? */ - e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */ - else { + if (!constfolding(OP_UNM, e, e)) { /* cannot fold it? */ luaK_exp2anyreg(fs, e); codearith(fs, OP_UNM, e, &e2, line); } @@ -797,9 +844,10 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ break; } - case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_ADD: case OPR_SUB: + case OPR_MUL: case OPR_DIV: case OPR_IDIV: case OPR_MOD: case OPR_POW: { - if (!isnumeral(v)) luaK_exp2RK(fs, v); + if (!tonumeral(v, NULL)) luaK_exp2RK(fs, v); break; } default: { @@ -842,7 +890,7 @@ void luaK_posfix (FuncState *fs, BinOpr op, break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: - case OPR_MOD: case OPR_POW: { + case OPR_IDIV: case OPR_MOD: case OPR_POW: { codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line); break; } |