mirror of
https://github.com/lua/lua
synced 2024-11-26 06:39:41 +03:00
Changed internal representation of booleans
Instead of an explicit value (field 'b'), true and false use different tag variants. This avoids reading an extra field and results in more direct code. (Most code that uses booleans needs to distinguish between true and false anyway.)
This commit is contained in:
parent
e3c83835e7
commit
5ff408d218
5
lapi.c
5
lapi.c
@ -574,7 +574,10 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
|
||||
|
||||
LUA_API void lua_pushboolean (lua_State *L, int b) {
|
||||
lua_lock(L);
|
||||
setbvalue(s2v(L->top), (b != 0)); /* ensure that true is 1 */
|
||||
if (b)
|
||||
setbtvalue(s2v(L->top));
|
||||
else
|
||||
setbfvalue(s2v(L->top));
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
50
lcode.c
50
lcode.c
@ -84,8 +84,11 @@ int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v) {
|
||||
if (hasjumps(e))
|
||||
return 0; /* not a constant */
|
||||
switch (e->k) {
|
||||
case VFALSE: case VTRUE:
|
||||
setbvalue(v, e->k == VTRUE);
|
||||
case VFALSE:
|
||||
setbfvalue(v);
|
||||
return 1;
|
||||
case VTRUE:
|
||||
setbtvalue(v);
|
||||
return 1;
|
||||
case VNIL:
|
||||
setnilvalue(v);
|
||||
@ -604,11 +607,21 @@ static int luaK_numberK (FuncState *fs, lua_Number r) {
|
||||
|
||||
|
||||
/*
|
||||
** Add a boolean to list of constants and return its index.
|
||||
** Add a false to list of constants and return its index.
|
||||
*/
|
||||
static int boolK (FuncState *fs, int b) {
|
||||
static int boolF (FuncState *fs) {
|
||||
TValue o;
|
||||
setbvalue(&o, b);
|
||||
setbfvalue(&o);
|
||||
return addk(fs, &o, &o); /* use boolean itself as key */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Add a true to list of constants and return its index.
|
||||
*/
|
||||
static int boolT (FuncState *fs) {
|
||||
TValue o;
|
||||
setbtvalue(&o);
|
||||
return addk(fs, &o, &o); /* use boolean itself as key */
|
||||
}
|
||||
|
||||
@ -671,8 +684,11 @@ static void const2exp (TValue *v, expdesc *e) {
|
||||
case LUA_TNUMFLT:
|
||||
e->k = VKFLT; e->u.nval = fltvalue(v);
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
e->k = bvalue(v) ? VTRUE : VFALSE;
|
||||
case LUA_TFALSE:
|
||||
e->k = VFALSE;
|
||||
break;
|
||||
case LUA_TTRUE:
|
||||
e->k = VTRUE;
|
||||
break;
|
||||
case LUA_TNIL:
|
||||
e->k = VNIL;
|
||||
@ -801,8 +817,12 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
luaK_nil(fs, reg, 1);
|
||||
break;
|
||||
}
|
||||
case VFALSE: case VTRUE: {
|
||||
luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
|
||||
case VFALSE: {
|
||||
luaK_codeABC(fs, OP_LOADFALSE, reg, 0, 0);
|
||||
break;
|
||||
}
|
||||
case VTRUE: {
|
||||
luaK_codeABC(fs, OP_LOADTRUE, reg, 0, 0);
|
||||
break;
|
||||
}
|
||||
case VKSTR: {
|
||||
@ -852,9 +872,9 @@ static void discharge2anyreg (FuncState *fs, expdesc *e) {
|
||||
}
|
||||
|
||||
|
||||
static int code_loadbool (FuncState *fs, int A, int b, int jump) {
|
||||
static int code_loadbool (FuncState *fs, int A, OpCode op, int jump) {
|
||||
luaK_getlabel(fs); /* those instructions may be jump targets */
|
||||
return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
|
||||
return luaK_codeABC(fs, op, A, jump, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -888,8 +908,8 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) {
|
||||
int p_t = NO_JUMP; /* position of an eventual LOAD true */
|
||||
if (need_value(fs, e->t) || need_value(fs, e->f)) {
|
||||
int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
|
||||
p_f = code_loadbool(fs, reg, 0, 1); /* load false and skip next i. */
|
||||
p_t = code_loadbool(fs, reg, 1, 0); /* load true */
|
||||
p_f = code_loadbool(fs, reg, OP_LOADFALSE, 1); /* skip next inst. */
|
||||
p_t = code_loadbool(fs, reg, OP_LOADTRUE, 0);
|
||||
/* jump around these booleans if 'e' is not a test */
|
||||
luaK_patchtohere(fs, fj);
|
||||
}
|
||||
@ -963,8 +983,8 @@ static int luaK_exp2K (FuncState *fs, expdesc *e) {
|
||||
if (!hasjumps(e)) {
|
||||
int info;
|
||||
switch (e->k) { /* move constants to 'k' */
|
||||
case VTRUE: info = boolK(fs, 1); break;
|
||||
case VFALSE: info = boolK(fs, 0); break;
|
||||
case VTRUE: info = boolT(fs); break;
|
||||
case VFALSE: info = boolF(fs); break;
|
||||
case VNIL: info = nilK(fs); break;
|
||||
case VKINT: info = luaK_intK(fs, e->u.ival); break;
|
||||
case VKFLT: info = luaK_numberK(fs, e->u.nval); break;
|
||||
|
2
ldebug.c
2
ldebug.c
@ -306,7 +306,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
Table *t = luaH_new(L); /* new table to store active lines */
|
||||
sethvalue2s(L, L->top, t); /* push it on stack */
|
||||
api_incr_top(L);
|
||||
setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */
|
||||
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
||||
for (i = 0; i < p->sizelineinfo; i++) { /* for all lines with code */
|
||||
currentline = nextline(p, currentline, i);
|
||||
luaH_setint(L, t, currentline, &v); /* table[line] = true */
|
||||
|
5
ldump.c
5
ldump.c
@ -113,10 +113,7 @@ static void DumpConstants (const Proto *f, DumpState *D) {
|
||||
const TValue *o = &f->k[i];
|
||||
DumpByte(ttypetag(o), D);
|
||||
switch (ttypetag(o)) {
|
||||
case LUA_TNIL:
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
DumpByte(bvalue(o), D);
|
||||
case LUA_TNIL: case LUA_TFALSE: case LUA_TTRUE:
|
||||
break;
|
||||
case LUA_TNUMFLT:
|
||||
DumpNumber(fltvalue(o), D);
|
||||
|
@ -30,7 +30,8 @@ static void *disptab[NUM_OPCODES] = {
|
||||
&&L_OP_LOADF,
|
||||
&&L_OP_LOADK,
|
||||
&&L_OP_LOADKX,
|
||||
&&L_OP_LOADBOOL,
|
||||
&&L_OP_LOADFALSE,
|
||||
&&L_OP_LOADTRUE,
|
||||
&&L_OP_LOADNIL,
|
||||
&&L_OP_GETUPVAL,
|
||||
&&L_OP_SETUPVAL,
|
||||
|
2
llex.c
2
llex.c
@ -136,7 +136,7 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
|
||||
if (isempty(o)) { /* not in use yet? */
|
||||
/* boolean value does not need GC barrier;
|
||||
table is not a metatable, so it does not need to invalidate cache */
|
||||
setbvalue(o, 1); /* t[string] = true */
|
||||
setbtvalue(o); /* t[string] = true */
|
||||
luaC_checkGC(L);
|
||||
}
|
||||
else { /* string already present */
|
||||
|
17
lobject.h
17
lobject.h
@ -44,7 +44,6 @@
|
||||
typedef union Value {
|
||||
struct GCObject *gc; /* collectable objects */
|
||||
void *p; /* light userdata */
|
||||
int b; /* booleans */
|
||||
lua_CFunction f; /* light C functions */
|
||||
lua_Integer i; /* integer numbers */
|
||||
lua_Number n; /* float numbers */
|
||||
@ -210,16 +209,20 @@ typedef StackValue *StkId;
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
#define ttisboolean(o) checktag((o), LUA_TBOOLEAN)
|
||||
|
||||
#define bvalue(o) check_exp(ttisboolean(o), val_(o).b)
|
||||
#define LUA_TFALSE (LUA_TBOOLEAN | (1 << 4))
|
||||
#define LUA_TTRUE (LUA_TBOOLEAN | (2 << 4))
|
||||
|
||||
#define bvalueraw(v) ((v).b)
|
||||
#define ttisboolean(o) checktype((o), LUA_TBOOLEAN)
|
||||
#define ttisfalse(o) checktag((o), LUA_TFALSE)
|
||||
#define ttistrue(o) checktag((o), LUA_TTRUE)
|
||||
|
||||
#define l_isfalse(o) (ttisboolean(o) ? bvalue(o) == 0 : ttisnil(o))
|
||||
|
||||
#define setbvalue(obj,x) \
|
||||
{ TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); }
|
||||
#define l_isfalse(o) (ttisfalse(o) || ttisnil(o))
|
||||
|
||||
|
||||
#define setbfvalue(obj) settt_(obj, LUA_TFALSE)
|
||||
#define setbtvalue(obj) settt_(obj, LUA_TTRUE)
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
@ -24,7 +24,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
||||
,opmode(0, 0, 0, 0, 1, iAsBx) /* OP_LOADF */
|
||||
,opmode(0, 0, 0, 0, 1, iABx) /* OP_LOADK */
|
||||
,opmode(0, 0, 0, 0, 1, iABx) /* OP_LOADKX */
|
||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADBOOL */
|
||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADFALSE */
|
||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADTRUE */
|
||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_LOADNIL */
|
||||
,opmode(0, 0, 0, 0, 1, iABC) /* OP_GETUPVAL */
|
||||
,opmode(0, 0, 0, 0, 0, iABC) /* OP_SETUPVAL */
|
||||
|
@ -202,7 +202,8 @@ OP_LOADI,/* A sBx R[A] := sBx */
|
||||
OP_LOADF,/* A sBx R[A] := (lua_Number)sBx */
|
||||
OP_LOADK,/* A Bx R[A] := K[Bx] */
|
||||
OP_LOADKX,/* A R[A] := K[extra arg] */
|
||||
OP_LOADBOOL,/* A B C R[A] := (Bool)B; if (C) pc++ */
|
||||
OP_LOADFALSE,/* A B R[A] := false; if (B) pc++ */
|
||||
OP_LOADTRUE,/* A R[A] := true */
|
||||
OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
|
||||
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
|
||||
OP_SETUPVAL,/* A B UpValue[B] := R[A] */
|
||||
|
@ -15,7 +15,8 @@ static const char *const opnames[] = {
|
||||
"LOADF",
|
||||
"LOADK",
|
||||
"LOADKX",
|
||||
"LOADBOOL",
|
||||
"LOADFALSE",
|
||||
"LOADTRUE",
|
||||
"LOADNIL",
|
||||
"GETUPVAL",
|
||||
"SETUPVAL",
|
||||
|
10
ltable.c
10
ltable.c
@ -143,8 +143,10 @@ static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
|
||||
return hashstr(t, tsvalueraw(*kvl));
|
||||
case LUA_TLNGSTR:
|
||||
return hashpow2(t, luaS_hashlongstr(tsvalueraw(*kvl)));
|
||||
case LUA_TBOOLEAN:
|
||||
return hashboolean(t, bvalueraw(*kvl));
|
||||
case LUA_TFALSE:
|
||||
return hashboolean(t, 0);
|
||||
case LUA_TTRUE:
|
||||
return hashboolean(t, 1);
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
return hashpointer(t, pvalueraw(*kvl));
|
||||
case LUA_TLCF:
|
||||
@ -175,14 +177,12 @@ static int equalkey (const TValue *k1, const Node *n2) {
|
||||
if (rawtt(k1) != keytt(n2)) /* not the same variants? */
|
||||
return 0; /* cannot be same key */
|
||||
switch (ttypetag(k1)) {
|
||||
case LUA_TNIL:
|
||||
case LUA_TNIL: case LUA_TFALSE: case LUA_TTRUE:
|
||||
return 1;
|
||||
case LUA_TNUMINT:
|
||||
return (ivalue(k1) == keyival(n2));
|
||||
case LUA_TNUMFLT:
|
||||
return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2)));
|
||||
case LUA_TBOOLEAN:
|
||||
return bvalue(k1) == bvalueraw(keyval(n2));
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
return pvalue(k1) == pvalueraw(keyval(n2));
|
||||
case LUA_TLCF:
|
||||
|
@ -160,8 +160,11 @@ static void LoadConstants (LoadState *S, Proto *f) {
|
||||
case LUA_TNIL:
|
||||
setnilvalue(o);
|
||||
break;
|
||||
case LUA_TBOOLEAN:
|
||||
setbvalue(o, LoadByte(S));
|
||||
case LUA_TFALSE:
|
||||
setbfvalue(o);
|
||||
break;
|
||||
case LUA_TTRUE:
|
||||
setbtvalue(o);
|
||||
break;
|
||||
case LUA_TNUMFLT:
|
||||
setfltvalue(o, LoadNumber(S));
|
||||
|
19
lvm.c
19
lvm.c
@ -577,10 +577,9 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
|
||||
}
|
||||
/* values have same type and same variant */
|
||||
switch (ttypetag(t1)) {
|
||||
case LUA_TNIL: return 1;
|
||||
case LUA_TNIL: case LUA_TFALSE: case LUA_TTRUE: return 1;
|
||||
case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2));
|
||||
case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2));
|
||||
case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1! */
|
||||
case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
|
||||
case LUA_TLCF: return fvalue(t1) == fvalue(t2);
|
||||
case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2));
|
||||
@ -1182,9 +1181,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
setobj2s(L, ra, rb);
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LOADBOOL) {
|
||||
setbvalue(s2v(ra), GETARG_B(i));
|
||||
if (GETARG_C(i)) pc++; /* skip next instruction (if C) */
|
||||
vmcase(OP_LOADFALSE) {
|
||||
setbfvalue(s2v(ra));
|
||||
if (GETARG_B(i)) pc++; /* if B, skip next instruction */
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LOADTRUE) {
|
||||
setbtvalue(s2v(ra));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LOADNIL) {
|
||||
@ -1503,8 +1506,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
}
|
||||
vmcase(OP_NOT) {
|
||||
TValue *rb = vRB(i);
|
||||
int nrb = l_isfalse(rb); /* next assignment may change this value */
|
||||
setbvalue(s2v(ra), nrb);
|
||||
if (l_isfalse(rb))
|
||||
setbtvalue(s2v(ra));
|
||||
else
|
||||
setbfvalue(s2v(ra));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LEN) {
|
||||
|
@ -144,10 +144,10 @@ check(function (a,b,c,d) return a..b..c..d end,
|
||||
'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN1')
|
||||
|
||||
-- not
|
||||
check(function () return not not nil end, 'LOADBOOL', 'RETURN1')
|
||||
check(function () return not not kFalse end, 'LOADBOOL', 'RETURN1')
|
||||
check(function () return not not true end, 'LOADBOOL', 'RETURN1')
|
||||
check(function () return not not k3 end, 'LOADBOOL', 'RETURN1')
|
||||
check(function () return not not nil end, 'LOADFALSE', 'RETURN1')
|
||||
check(function () return not not kFalse end, 'LOADFALSE', 'RETURN1')
|
||||
check(function () return not not true end, 'LOADTRUE', 'RETURN1')
|
||||
check(function () return not not k3 end, 'LOADTRUE', 'RETURN1')
|
||||
|
||||
-- direct access to locals
|
||||
check(function ()
|
||||
@ -194,7 +194,7 @@ check(function ()
|
||||
local a,b
|
||||
a[kTrue] = false
|
||||
end,
|
||||
'LOADNIL', 'LOADBOOL', 'SETTABLE', 'RETURN0')
|
||||
'LOADNIL', 'LOADTRUE', 'SETTABLE', 'RETURN0')
|
||||
|
||||
|
||||
-- equalities
|
||||
|
Loading…
Reference in New Issue
Block a user