new implementation for the Virtual Machine

This commit is contained in:
Roberto Ierusalimschy 2001-06-05 15:17:01 -03:00
parent 572a69b6af
commit 762d059a13
15 changed files with 1696 additions and 1538 deletions

18
lapi.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lapi.c,v 1.140 2001/04/17 17:35:54 roberto Exp roberto $ ** $Id: lapi.c,v 1.141 2001/04/23 16:35:45 roberto Exp roberto $
** Lua API ** Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -184,9 +184,10 @@ LUA_API int lua_iscfunction (lua_State *L, int index) {
LUA_API int lua_isnumber (lua_State *L, int index) { LUA_API int lua_isnumber (lua_State *L, int index) {
TObject *o; TObject *o;
int i; int i;
TObject n;
lua_lock(L); lua_lock(L);
o = luaA_indexAcceptable(L, index); o = luaA_indexAcceptable(L, index);
i = (o == NULL) ? 0 : (tonumber(o) == 0); i = (o != NULL && (ttype(o) == LUA_TNUMBER || luaV_tonumber(o, &n)));
lua_unlock(L); lua_unlock(L);
return i; return i;
} }
@ -234,13 +235,18 @@ LUA_API int lua_lessthan (lua_State *L, int index1, int index2) {
LUA_API lua_Number lua_tonumber (lua_State *L, int index) { LUA_API lua_Number lua_tonumber (lua_State *L, int index) {
StkId o; const TObject *o;
lua_Number n; TObject n;
lua_Number res;
lua_lock(L); lua_lock(L);
o = luaA_indexAcceptable(L, index); o = luaA_indexAcceptable(L, index);
n = (o == NULL || tonumber(o)) ? 0 : nvalue(o); if (o != NULL &&
(ttype(o) == LUA_TNUMBER || (o = luaV_tonumber(o, &n)) != NULL))
res = nvalue(o);
else
res = 0;
lua_unlock(L); lua_unlock(L);
return n; return res;
} }
LUA_API const l_char *lua_tostring (lua_State *L, int index) { LUA_API const l_char *lua_tostring (lua_State *L, int index) {

1141
lcode.c

File diff suppressed because it is too large Load Diff

49
lcode.h
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lcode.h,v 1.20 2001/02/20 18:15:33 roberto Exp roberto $ ** $Id: lcode.h,v 1.21 2001/02/23 17:17:25 roberto Exp roberto $
** Code generator for Lua ** Code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -31,43 +31,36 @@ typedef enum BinOpr {
OPR_NOBINOPR OPR_NOBINOPR
} BinOpr; } BinOpr;
#define binopistest(op) ((op) >= OPR_NE)
typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr; typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr;
enum Mode {iO, iU, iS, iAB}; /* instruction format */ #define luaK_codeAsBc(fs,o,A,sBc) luaK_codeABc(fs,o,A,(sBc)+MAXARG_sBc)
#define VD 100 /* flag for variable delta */
typedef struct OpProperties {
lu_byte mode;
lu_byte push;
lu_byte pop;
} OpProperties;
extern const OpProperties luaK_opproperties[];
void luaK_error (LexState *ls, const l_char *msg); void luaK_error (LexState *ls, const l_char *msg);
int luaK_code0 (FuncState *fs, OpCode o); int luaK_codeABc (FuncState *fs, OpCode o, int A, int Bc);
int luaK_code1 (FuncState *fs, OpCode o, int arg1); int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2); void luaK_nil (FuncState *fs, int from, int n);
void luaK_reserveregs (FuncState *fs, int n);
int luaK_stringk (FuncState *fs, TString *s);
int luaK_exp2anyreg (FuncState *fs, expdesc *e);
void luaK_exp2nextreg (FuncState *fs, expdesc *e);
void luaK_exp2val (FuncState *fs, expdesc *e);
int luaK_exp2RK (FuncState *fs, expdesc *e);
void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
void luaK_goiftrue (FuncState *fs, expdesc *e);
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults);
int luaK_jump (FuncState *fs); int luaK_jump (FuncState *fs);
void luaK_patchlist (FuncState *fs, int list, int target); void luaK_patchlist (FuncState *fs, int list, int target);
void luaK_fixfor (FuncState *fs, int pc, int dest); void luaK_fixfor (FuncState *fs, int pc, int dest);
void luaK_concat (FuncState *fs, int *l1, int l2); void luaK_concat (FuncState *fs, int *l1, int l2);
void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue);
int luaK_getlabel (FuncState *fs); int luaK_getlabel (FuncState *fs);
void luaK_deltastack (FuncState *fs, int delta); void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v);
void luaK_kstr (LexState *ls, int c); void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
void luaK_number (FuncState *fs, lua_Number f); void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2);
void luaK_adjuststack (FuncState *fs, int n);
int luaK_lastisopen (FuncState *fs);
void luaK_setcallreturns (FuncState *fs, int nresults);
void luaK_tostack (LexState *ls, expdesc *v, int onlyone);
void luaK_storevar (LexState *ls, const expdesc *var);
void luaK_prefix (LexState *ls, UnOpr op, expdesc *v);
void luaK_infix (LexState *ls, BinOpr op, expdesc *v);
void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2);
#endif #endif

416
ldebug.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: ldebug.c,v 1.75 2001/03/26 14:31:49 roberto Exp roberto $ ** $Id: ldebug.c,v 1.76 2001/04/06 18:25:00 roberto Exp roberto $
** Debug Interface ** Debug Interface
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -22,6 +22,7 @@
#include "ltable.h" #include "ltable.h"
#include "ltm.h" #include "ltm.h"
#include "luadebug.h" #include "luadebug.h"
#include "lvm.h"
@ -298,6 +299,10 @@ LUA_API int lua_getinfo (lua_State *L, const l_char *what, lua_Debug *ar) {
#define check(x) if (!(x)) return 0; #define check(x) if (!(x)) return 0;
#define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode)
#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize)
static int checklineinfo (const Proto *pt) { static int checklineinfo (const Proto *pt) {
int *lineinfo = pt->lineinfo; int *lineinfo = pt->lineinfo;
@ -318,231 +323,199 @@ static int precheck (const Proto *pt) {
} }
/* value for non-initialized entries in array stacklevel */ static int checkopenop (Instruction i) {
#define SL_EMPTY 255 OpCode op = GET_OPCODE(i);
switch (op) {
#define checkjump(pt,sl,top,pc) if (!checkjump_aux(pt,sl,top,pc)) return 0; case OP_CALL:
case OP_RETURN: {
static int checkjump_aux (const Proto *pt, lu_byte *sl, int top, int pc) { check(GETARG_B(i) == NO_REG);
check(0 <= pc && pc < pt->sizecode); return 1;
if (sl == NULL) return 1; /* not full checking */ }
if (sl[pc] == SL_EMPTY) case OP_SETLISTO: return 1;
sl[pc] = (lu_byte)top; default: return 0; /* invalid instruction after an open call */
else }
check(sl[pc] == top);
return 1;
} }
static Instruction luaG_symbexec (lua_State *L, const Proto *pt, static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
int lastpc, int stackpos) {
int stack[MAXSTACK]; /* stores last instruction that changed a stack entry */
lu_byte *sl = NULL;
int top;
int pc; int pc;
if (stackpos < 0) { /* full check? */ int last; /* stores position of last instruction that changed `reg' */
int i; last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */
sl = luaO_openspace(L, pt->sizecode, lu_byte); if (reg == NO_REG) /* full check? */
for (i=0; i<pt->sizecode; i++) /* initialize stack-level array */
sl[i] = SL_EMPTY;
check(precheck(pt)); check(precheck(pt));
} for (pc = 0; pc < lastpc; pc++) {
top = pt->numparams; const Instruction i = pt->code[pc];
pc = 0;
if (pt->is_vararg) /* varargs? */
top++; /* `arg' */
if (sl) sl[0] = (lu_byte)top;
while (pc < lastpc) {
const Instruction i = pt->code[pc++];
OpCode op = GET_OPCODE(i); OpCode op = GET_OPCODE(i);
int arg1 = 0; int a = GETARG_A(i);
int arg2 = 0; int b = 0;
int push, pop; int c = 0;
check(op < NUM_OPCODES); #undef check
push = (int)luaK_opproperties[op].push; #define check(x) if (!(x)) { \
pop = (int)luaK_opproperties[op].pop; printf(">>>%d %d %d %d %d %d\n", op, a, b, c, pt->maxstacksize, pt->sizek); \
switch ((enum Mode)luaK_opproperties[op].mode) { return 0; }
case iO: break; switch (getOpMode(op)) {
case iU: arg1 = GETARG_U(i); check(arg1 >= 0); break; case iABC: {
case iS: arg1 = GETARG_S(i); break; b = GETARG_B(i);
case iAB: c = GETARG_C(i);
arg1 = GETARG_A(i); arg2 = GETARG_B(i); check(arg1 >= 0); break; if (testOpMode(op, OpModeBreg)) {
} checkreg(pt, b);
switch (op) { check(c < pt->maxstacksize ||
case OP_RETURN: { (c >= MAXSTACK && c-MAXSTACK < pt->sizek));
check(arg1 <= top);
pop = top-arg1;
break;
}
case OP_CALL: {
if (arg2 == MULT_RET) arg2 = 1;
check(arg1 < top);
pop = top-arg1;
push = arg2;
break;
}
case OP_PUSHNIL: {
check(arg1 > 0);
push = arg1;
break;
}
case OP_POP: {
pop = arg1;
break;
}
case OP_PUSHSTRING:
case OP_GETGLOBAL:
case OP_GETDOTTED:
case OP_PUSHSELF:
case OP_SETGLOBAL: {
check(arg1 < pt->sizekstr);
break;
}
case OP_PUSHNUM:
case OP_PUSHNEGNUM: {
check(arg1 < pt->sizeknum);
break;
}
case OP_PUSHUPVALUE: {
check(arg1 < pt->nupvalues);
break;
}
case OP_GETLOCAL:
case OP_GETINDEXED:
case OP_SETLOCAL: {
check(arg1 < top);
break;
}
case OP_SETTABLE: {
check(3 <= arg1 && arg1 <= top);
pop = arg2;
break;
}
case OP_SETLIST: {
check(arg2 >= 0);
pop = top-arg2-1;
break;
}
case OP_SETMAP: {
check(arg1 >= 0);
pop = top-arg1-1;
break;
}
case OP_CONCAT: {
pop = arg1;
break;
}
case OP_CLOSURE: {
check(arg1 < pt->sizekproto);
check(arg2 == pt->kproto[arg1]->nupvalues);
pop = arg2;
break;
}
case OP_JMPNE:
case OP_JMPEQ:
case OP_JMPLT:
case OP_JMPLE:
case OP_JMPGT:
case OP_JMPGE:
case OP_JMPT:
case OP_JMPF:
case OP_JMP: {
checkjump(pt, sl, top-pop, pc+arg1);
break;
}
case OP_FORLOOP:
case OP_LFORLOOP:
case OP_JMPONT:
case OP_JMPONF: {
int newpc = pc+arg1;
checkjump(pt, sl, top, newpc);
/* jump is forward and do not skip `lastpc' and not full check? */
if (pc < newpc && newpc <= lastpc && stackpos >= 0) {
stack[top-1] = pc-1; /* value comes from `and'/`or' */
pc = newpc; /* do the jump */
pop = 0; /* do not pop */
} }
break; break;
} }
case OP_PUSHNILJMP: { case iABc: {
check(GET_OPCODE(pt->code[pc]) == OP_PUSHINT); /* only valid sequence */ b = GETARG_Bc(i);
if (testOpMode(op, OpModeK)) check(b < pt->sizek);
break; break;
} }
case OP_FORPREP: { case iAsBc: {
int endfor = pc-arg1-1; /* jump is `negative' here */ b = GETARG_sBc(i);
check(top >= 3);
checkjump(pt, sl, top+push, endfor);
check(GET_OPCODE(pt->code[endfor]) == OP_FORLOOP);
check(GETARG_S(pt->code[endfor]) == arg1);
break;
}
case OP_LFORPREP: {
int endfor = pc-arg1-1; /* jump is `negative' here */
check(top >= 1);
checkjump(pt, sl, top+push, endfor);
check(GET_OPCODE(pt->code[endfor]) == OP_LFORLOOP);
check(GETARG_S(pt->code[endfor]) == arg1);
break;
}
case OP_PUSHINT:
case OP_GETTABLE:
case OP_CREATETABLE:
case OP_ADD:
case OP_ADDI:
case OP_SUB:
case OP_MULT:
case OP_DIV:
case OP_POW:
case OP_MINUS:
case OP_NOT: {
break; break;
} }
} }
top -= pop; if (testOpMode(op, OpModeAreg)) checkreg(pt, a);
check(0 <= top && top+push <= pt->maxstacksize); if (testOpMode(op, OpModesetA)) {
while (push--) stack[top++] = pc-1; if (a == reg) last = pc; /* change register `a' */
checkjump(pt, sl, top, pc); }
if (testOpMode(op, OpModeT))
check(GET_OPCODE(pt->code[pc+1]) == OP_CJMP);
switch (op) {
case OP_LOADNIL: {
if (a <= reg && reg <= b)
last = pc; /* set registers from `a' to `b' */
break;
}
case OP_LOADUPVAL: {
check(b < pt->nupvalues);
break;
}
case OP_GETGLOBAL:
case OP_SETGLOBAL: {
check(ttype(&pt->k[b]) == LUA_TSTRING);
break;
}
case OP_SELF: {
checkreg(pt, a+1);
if (reg == a+1) last = pc;
break;
}
case OP_CONCAT: {
check(b < c); /* at least two operands */
break;
}
case OP_JMP:
case OP_CJMP: {
int dest = pc+1+b;
check(0 <= dest && dest < pt->sizecode);
/* not full check and jump is forward and do not skip `lastpc'? */
if (reg != NO_REG && pc < dest && dest <= lastpc)
pc += b; /* do the jump */
break;
}
case OP_TESTT:
case OP_TESTF: {
if (a != NO_REG)
checkreg(pt, a);
break;
}
case OP_NILJMP: {
check(pc+2 < pt->sizecode); /* check its jump */
break;
}
case OP_CALL: {
if (b == NO_REG) b = pt->maxstacksize;
if (c == NO_REG) {
check(checkopenop(pt->code[pc+1]));
c = 1;
}
check(b > a);
checkreg(pt, b-1);
checkreg(pt, a+c-1);
if (reg >= a) last = pc; /* affect all registers above base */
break;
}
case OP_RETURN: {
if (b == NO_REG) b = pt->maxstacksize;
checkreg(pt, b-1);
break;
}
case OP_FORPREP:
case OP_TFORPREP: {
int dest = pc-b; /* jump is negated here */
check(0 <= dest && dest < pt->sizecode &&
GET_OPCODE(pt->code[dest]) == op+1);
break;
}
case OP_FORLOOP:
case OP_TFORLOOP: {
int dest = pc+b;
check(0 <= dest && dest < pt->sizecode &&
pt->code[dest] == SET_OPCODE(i, op-1));
checkreg(pt, a + ((op == OP_FORLOOP) ? 2 : 3));
break;
}
case OP_SETLIST: {
checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1);
break;
}
case OP_CLOSURE: {
check(b < pt->sizekproto);
checkreg(pt, a + pt->kproto[b]->nupvalues - 1);
break;
}
default: break;
}
} }
return (stackpos >= 0) ? pt->code[stack[stackpos]] : 1; return pt->code[last];
} }
/* }====================================================== */ /* }====================================================== */
int luaG_checkcode (lua_State *L, const Proto *pt) { int luaG_checkcode (const Proto *pt) {
return luaG_symbexec(L, pt, pt->sizecode-1, -1); return luaG_symbexec(pt, pt->sizecode, NO_REG);
} }
static const l_char *getobjname (lua_State *L, StkId obj, const l_char **name) { static const l_char *getobjname (lua_State *L, StkId obj, const l_char **name) {
CallInfo *ci = ci_stack(L, obj); CallInfo *ci = ci_stack(L, obj);
if (!isLmark(ci)) if (isLmark(ci)) { /* an active Lua function? */
return NULL; /* not an active Lua function */
else {
Proto *p = ci_func(ci)->f.l; Proto *p = ci_func(ci)->f.l;
int pc = currentpc(ci); int pc = currentpc(ci);
int stackpos = obj - ci->base; int stackpos = obj - ci->base;
Instruction i = luaG_symbexec(L, p, pc, stackpos); Instruction i;
*name = luaF_getlocalname(p, stackpos+1, pc);
if (*name) /* is a local? */
return l_s("local");
i = luaG_symbexec(p, pc, stackpos); /* try symbolic execution */
lua_assert(pc != -1); lua_assert(pc != -1);
switch (GET_OPCODE(i)) { switch (GET_OPCODE(i)) {
case OP_GETGLOBAL: { case OP_GETGLOBAL: {
*name = getstr(p->kstr[GETARG_U(i)]); lua_assert(ttype(&p->k[GETARG_Bc(i)]) == LUA_TSTRING);
*name = getstr(tsvalue(&p->k[GETARG_Bc(i)]));
return l_s("global"); return l_s("global");
} }
case OP_GETLOCAL: { case OP_MOVE: {
*name = luaF_getlocalname(p, GETARG_U(i)+1, pc); int a = GETARG_A(i);
lua_assert(*name); int b = GETARG_B(i); /* move from `b' to `a' */
return l_s("local"); if (b < a)
return getobjname(L, ci->base+b, name); /* get name for `b' */
break;
} }
case OP_PUSHSELF: case OP_GETTABLE:
case OP_GETDOTTED: { case OP_SELF: {
*name = getstr(p->kstr[GETARG_U(i)]); int c = GETARG_C(i) - MAXSTACK;
return l_s("field"); if (c >= 0 && ttype(&p->k[c]) == LUA_TSTRING) {
*name = getstr(tsvalue(&p->k[c]));
return l_s("field");
}
break;
} }
default: default: break;
return NULL; /* no useful name found */
} }
} }
return NULL; /* no useful name found */
} }
@ -576,10 +549,18 @@ void luaG_typeerror (lua_State *L, StkId o, const l_char *op) {
} }
void luaG_binerror (lua_State *L, StkId p1, int t, const l_char *op) { void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
if (ttype(p1) == t) p1++; if (ttype(p1) == LUA_TSTRING) p1 = p2;
lua_assert(ttype(p1) != t); lua_assert(ttype(p1) != LUA_TSTRING);
luaG_typeerror(L, p1, op); luaG_typeerror(L, p1, l_s("concat"));
}
void luaG_aritherror (lua_State *L, StkId p1, TObject *p2) {
TObject temp;
if (luaV_tonumber(p1, &temp) != NULL)
p1 = p2; /* first operand is OK; error is in the second */
luaG_typeerror(L, p1, l_s("perform arithmetic on"));
} }
@ -592,3 +573,52 @@ void luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2) {
luaO_verror(L, l_s("attempt to compare %.10s with %.10s"), t1, t2); luaO_verror(L, l_s("attempt to compare %.10s with %.10s"), t1, t2);
} }
#define opmode(t,a,b,c,sa,k,m) (((t)<<OpModeT) | \
((a)<<OpModeAreg) | ((b)<<OpModeBreg) | ((c)<<OpModeCreg) | \
((sa)<<OpModesetA) | ((k)<<OpModeK) | (m))
const unsigned char luaG_opmodes[] = {
/* T A B C sA K mode opcode */
opmode(0,1,1,0, 1,0,iABC), /* OP_MOVE */
opmode(0,1,0,0, 1,1,iABc), /* OP_LOADK */
opmode(0,1,0,0, 1,0,iAsBc), /* OP_LOADINT */
opmode(0,1,1,0, 1,0,iABC), /* OP_LOADNIL */
opmode(0,1,0,0, 1,0,iABc), /* OP_LOADUPVAL */
opmode(0,1,0,0, 1,1,iABc), /* OP_GETGLOBAL */
opmode(0,1,1,1, 1,0,iABC), /* OP_GETTABLE */
opmode(0,1,0,0, 0,1,iABc), /* OP_SETGLOBAL */
opmode(0,1,1,1, 0,0,iABC), /* OP_SETTABLE */
opmode(0,1,0,0, 1,0,iABc), /* OP_NEWTABLE */
opmode(0,1,1,1, 1,0,iABC), /* OP_SELF */
opmode(0,1,1,1, 1,0,iABC), /* OP_ADD */
opmode(0,1,1,1, 1,0,iABC), /* OP_SUB */
opmode(0,1,1,1, 1,0,iABC), /* OP_MUL */
opmode(0,1,1,1, 1,0,iABC), /* OP_DIV */
opmode(0,1,1,1, 1,0,iABC), /* OP_POW */
opmode(0,1,1,0, 1,0,iABC), /* OP_UNM */
opmode(0,1,1,0, 1,0,iABC), /* OP_NOT */
opmode(0,1,1,1, 1,0,iABC), /* OP_CONCAT */
opmode(0,0,0,0, 0,0,iAsBc), /* OP_JMP */
opmode(0,0,0,0, 0,0,iAsBc), /* OP_CJMP */
opmode(1,0,1,1, 0,0,iABC), /* OP_TESTEQ */
opmode(1,0,1,1, 0,0,iABC), /* OP_TESTNE */
opmode(1,0,1,1, 0,0,iABC), /* OP_TESTLT */
opmode(1,0,1,1, 0,0,iABC), /* OP_TESTLE */
opmode(1,0,1,1, 0,0,iABC), /* OP_TESTGT */
opmode(1,0,1,1, 0,0,iABC), /* OP_TESTGE */
opmode(1,0,1,0, 1,0,iABC), /* OP_TESTT */
opmode(1,0,1,0, 1,0,iABC), /* OP_TESTF */
opmode(0,1,0,0, 1,0,iAsBc), /* OP_NILJMP */
opmode(0,1,0,0, 0,0,iABC), /* OP_CALL */
opmode(0,1,0,0, 0,0,iABC), /* OP_RETURN */
opmode(0,1,0,0, 0,0,iAsBc), /* OP_FORPREP */
opmode(0,1,0,0, 0,0,iAsBc), /* OP_FORLOOP */
opmode(0,1,0,0, 0,0,iAsBc), /* OP_TFORPREP */
opmode(0,1,0,0, 0,0,iAsBc), /* OP_TFORLOOP */
opmode(0,1,0,0, 0,0,iABc), /* OP_SETLIST */
opmode(0,1,0,0, 0,0,iABc), /* OP_SETLIST0 */
opmode(0,1,0,0, 0,0,iABc) /* OP_CLOSURE */
};

View File

@ -1,5 +1,5 @@
/* /*
** $Id: ldebug.h,v 1.10 2001/02/12 19:54:50 roberto Exp roberto $ ** $Id: ldebug.h,v 1.11 2001/02/23 17:17:25 roberto Exp roberto $
** Auxiliary functions from Debug Interface module ** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -12,11 +12,32 @@
#include "luadebug.h" #include "luadebug.h"
enum OpMode {iABC, iABc, iAsBc}; /* basic instruction format */
/*
** masks for instruction properties
*/
enum OpModeMask {
OpModeAreg = 2, /* A is a register */
OpModeBreg, /* B is a register */
OpModeCreg, /* C is a register/constant */
OpModesetA, /* instruction set register A */
OpModeK, /* Bc is a constant */
OpModeT /* operator is a test */
};
extern const unsigned char luaG_opmodes[];
#define getOpMode(m) ((enum OpMode)(luaG_opmodes[m] & 3))
#define testOpMode(m, b) (luaG_opmodes[m] & (1 << (b)))
void luaG_typeerror (lua_State *L, StkId o, const l_char *op); void luaG_typeerror (lua_State *L, StkId o, const l_char *op);
void luaG_binerror (lua_State *L, StkId p1, int t, const l_char *op); void luaG_concaterror (lua_State *L, StkId p1, StkId p2);
void luaG_aritherror (lua_State *L, StkId p1, TObject *p2);
int luaG_getline (int *lineinfo, int pc, int refline, int *refi); int luaG_getline (int *lineinfo, int pc, int refline, int *refi);
void luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2); void luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2);
int luaG_checkcode (lua_State *L, const Proto *pt); int luaG_checkcode (const Proto *pt);
#endif #endif

11
lfunc.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lfunc.c,v 1.42 2001/02/23 17:17:25 roberto Exp roberto $ ** $Id: lfunc.c,v 1.43 2001/03/26 14:31:49 roberto Exp roberto $
** Auxiliary functions to manipulate prototypes and closures ** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -30,10 +30,8 @@ Closure *luaF_newclosure (lua_State *L, int nelems) {
Proto *luaF_newproto (lua_State *L) { Proto *luaF_newproto (lua_State *L) {
Proto *f = luaM_new(L, Proto); Proto *f = luaM_new(L, Proto);
f->knum = NULL; f->k = NULL;
f->sizeknum = 0; f->sizek = 0;
f->kstr = NULL;
f->sizekstr = 0;
f->kproto = NULL; f->kproto = NULL;
f->sizekproto = 0; f->sizekproto = 0;
f->code = NULL; f->code = NULL;
@ -58,8 +56,7 @@ Proto *luaF_newproto (lua_State *L) {
void luaF_freeproto (lua_State *L, Proto *f) { void luaF_freeproto (lua_State *L, Proto *f) {
luaM_freearray(L, f->code, f->sizecode, Instruction); luaM_freearray(L, f->code, f->sizecode, Instruction);
luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar); luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
luaM_freearray(L, f->kstr, f->sizekstr, TString *); luaM_freearray(L, f->k, f->sizek, TObject);
luaM_freearray(L, f->knum, f->sizeknum, lua_Number);
luaM_freearray(L, f->kproto, f->sizekproto, Proto *); luaM_freearray(L, f->kproto, f->sizekproto, Proto *);
luaM_freearray(L, f->lineinfo, f->sizelineinfo, int); luaM_freearray(L, f->lineinfo, f->sizelineinfo, int);
luaM_freelem(L, f, Proto); luaM_freelem(L, f, Proto);

8
lgc.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 1.96 2001/04/11 14:42:41 roberto Exp roberto $ ** $Id: lgc.c,v 1.97 2001/04/17 17:35:54 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -48,8 +48,10 @@ static void protomark (Proto *f) {
int i; int i;
f->marked = 1; f->marked = 1;
strmark(f->source); strmark(f->source);
for (i=0; i<f->sizekstr; i++) for (i=0; i<f->sizek; i++) {
strmark(f->kstr[i]); if (ttype(f->k+i) == LUA_TSTRING)
strmark(tsvalue(f->k+i));
}
for (i=0; i<f->sizekproto; i++) for (i=0; i<f->sizekproto; i++)
protomark(f->kproto[i]); protomark(f->kproto[i]);
for (i=0; i<f->sizelocvars; i++) /* mark local-variable names */ for (i=0; i<f->sizelocvars; i++) /* mark local-variable names */

View File

@ -1,5 +1,5 @@
/* /*
** $Id: llimits.h,v 1.27 2001/02/23 20:28:56 roberto Exp roberto $ ** $Id: llimits.h,v 1.28 2001/03/26 14:31:49 roberto Exp roberto $
** Limits, basic types, and some other `installation-dependent' definitions ** Limits, basic types, and some other `installation-dependent' definitions
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -89,92 +89,23 @@ union L_Umaxalign { double d; void *s; long l; };
/* /*
** type for virtual-machine instructions ** type for virtual-machine instructions
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
** For a very small machine, you may change that to 2 bytes (and adjust
** the following limits accordingly)
*/ */
typedef unsigned long Instruction; typedef unsigned long Instruction;
/* /* maximum stack for a Lua function */
** size and position of opcode arguments.
** For an instruction with 2 bytes, size is 16, and size_b can be 5
** (accordingly, size_u will be 10, and size_a will be 5)
*/
#define SIZE_INSTRUCTION 32
#define SIZE_B 8
#define SIZE_OP 6
#define SIZE_U (SIZE_INSTRUCTION-SIZE_OP)
#define POS_U SIZE_OP
#define POS_B SIZE_OP
#define SIZE_A (SIZE_INSTRUCTION-(SIZE_OP+SIZE_B))
#define POS_A (SIZE_OP+SIZE_B)
/*
** limits for opcode arguments.
** we use (signed) int to manipulate most arguments,
** so they must fit in BITS_INT-1 bits (-1 for sign)
*/
#if SIZE_U < BITS_INT-1
#define MAXARG_U ((1<<SIZE_U)-1)
#define MAXARG_S (MAXARG_U>>1) /* `S' is signed */
#else
#define MAXARG_U MAX_INT
#define MAXARG_S MAX_INT
#endif
#if SIZE_A < BITS_INT-1
#define MAXARG_A ((1<<SIZE_A)-1)
#else
#define MAXARG_A MAX_INT
#endif
#if SIZE_B < BITS_INT-1
#define MAXARG_B ((1<<SIZE_B)-1)
#else
#define MAXARG_B MAX_INT
#endif
/* maximum stack size in a function */
#ifndef MAXSTACK
#define MAXSTACK 250 #define MAXSTACK 250
#endif
#if MAXSTACK > MAXARG_B
#undef MAXSTACK
#define MAXSTACK MAXARG_B
#endif
/* maximum number of local variables */ /* maximum number of local variables */
#ifndef MAXLOCALS #ifndef MAXLOCALS
#define MAXLOCALS 200 /* arbitrary limit (<MAXSTACK) */ #define MAXLOCALS 200 /* arbitrary limit (<MAXSTACK) */
#endif #endif
#if MAXLOCALS>=MAXSTACK
#undef MAXLOCALS
#define MAXLOCALS (MAXSTACK-1)
#endif
/* maximum number of upvalues */ /* maximum number of upvalues */
#ifndef MAXUPVALUES #ifndef MAXUPVALUES
#define MAXUPVALUES 32 /* arbitrary limit (<=MAXARG_B) */ #define MAXUPVALUES 32 /* arbitrary limit (<MAXSTACK) */
#endif
#if MAXUPVALUES>MAXARG_B
#undef MAXUPVALUES
#define MAXUPVALUES MAXARG_B
#endif
/* maximum number of variables in the left side of an assignment */
#ifndef MAXVARSLH
#define MAXVARSLH 100 /* arbitrary limit (<MULT_RET) */
#endif
#if MAXVARSLH>=MULT_RET
#undef MAXVARSLH
#define MAXVARSLH (MULT_RET-1)
#endif #endif
@ -182,27 +113,17 @@ typedef unsigned long Instruction;
#ifndef MAXPARAMS #ifndef MAXPARAMS
#define MAXPARAMS 100 /* arbitrary limit (<MAXLOCALS) */ #define MAXPARAMS 100 /* arbitrary limit (<MAXLOCALS) */
#endif #endif
#if MAXPARAMS>=MAXLOCALS
#undef MAXPARAMS
#define MAXPARAMS (MAXLOCALS-1)
#endif
/* number of list items to accumulate before a SETLIST instruction */ /* number of list items to accumulate before a SETLIST instruction */
/* (must be a power of 2) */
#define LFIELDS_PER_FLUSH 64 #define LFIELDS_PER_FLUSH 64
#if LFIELDS_PER_FLUSH>(MAXSTACK/4)
#undef LFIELDS_PER_FLUSH
#define LFIELDS_PER_FLUSH (MAXSTACK/4)
#endif
/* number of record items to accumulate before a SETMAP instruction */
/* (each item counts 2 elements on the stack: an index and a value) */
#define RFIELDS_PER_FLUSH (LFIELDS_PER_FLUSH/2)
/* maximum lookback to find a real constant (for code generation) */ /* maximum lookback to find a real constant (for code generation) */
#ifndef LOOKBACKNUMS #ifndef LOOKBACKNUMS
#define LOOKBACKNUMS 20 /* arbitrary constant */ #define LOOKBACKNUMS 40 /* arbitrary constant */
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lobject.h,v 1.101 2001/03/07 18:09:25 roberto Exp roberto $ ** $Id: lobject.h,v 1.102 2001/04/11 14:42:41 roberto Exp roberto $
** Type definitions for Lua objects ** Type definitions for Lua objects
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -114,10 +114,8 @@ union L_UTString {
** Function Prototypes ** Function Prototypes
*/ */
typedef struct Proto { typedef struct Proto {
lua_Number *knum; /* numbers used by the function */ TObject *k; /* constants used by the function */
int sizeknum; /* size of `knum' */ int sizek; /* size of `k' */
struct TString **kstr; /* strings used by the function */
int sizekstr; /* size of `kstr' */
struct Proto **kproto; /* functions defined inside the function */ struct Proto **kproto; /* functions defined inside the function */
int sizekproto; /* size of `kproto' */ int sizekproto; /* size of `kproto' */
Instruction *code; Instruction *code;

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lopcodes.h,v 1.71 2001/03/07 13:22:55 roberto Exp roberto $ ** $Id: lopcodes.h,v 1.72 2001/04/06 18:25:00 roberto Exp roberto $
** Opcodes for Lua virtual machine ** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -12,29 +12,55 @@
/*=========================================================================== /*===========================================================================
We assume that instructions are unsigned numbers. We assume that instructions are unsigned numbers.
All instructions have an opcode in the first 6 bits. Moreover, All instructions have an opcode in the first 6 bits.
an instruction can have 0, 1, or 2 arguments. Instructions can Instructions can have the following fields:
have the following types: `A' : 8 bits (25-32)
type 0: no arguments `B' : 8 bits (17-24)
type 1: 1 unsigned argument in the higher bits (called `U') `C' : 10 bits (7-16)
type 2: 1 signed argument in the higher bits (`S') `Bc' : 18 bits (`B' and `C' together)
type 3: 1st unsigned argument in the higher bits (`A') `sBc' : signed Bc
2nd unsigned argument in the middle bits (`B')
A signed argument is represented in excess K; that is, the number A signed argument is represented in excess K; that is, the number
value is the unsigned value minus K. K is exactly the maximum value value is the unsigned value minus K. K is exactly the maximum value
for that argument (so that -max is represented by 0, and +max is for that argument (so that -max is represented by 0, and +max is
represented by 2*max), which is half the maximum for the corresponding represented by 2*max), which is half the maximum for the corresponding
unsigned argument. unsigned argument.
The size of each argument is defined in `llimits.h'. The usual is an
instruction with 32 bits, U arguments with 26 bits (32-6), B arguments
with 9 bits, and A arguments with 17 bits (32-6-9). For small
installations, the instruction size can be 16, so U has 10 bits,
and A and B have 5 bits each.
===========================================================================*/ ===========================================================================*/
/*
** size and position of opcode arguments.
*/
#define SIZE_C 10
#define SIZE_B 8
#define SIZE_Bc (SIZE_C + SIZE_B)
#define SIZE_A 8
#define SIZE_OP 6
#define POS_C SIZE_OP
#define POS_B (POS_C + SIZE_C)
#define POS_Bc POS_C
#define POS_A (POS_B + SIZE_B)
/*
** limits for opcode arguments.
** we use (signed) int to manipulate most arguments,
** so they must fit in BITS_INT-1 bits (-1 for sign)
*/
#if SIZE_Bc < BITS_INT-1
#define MAXARG_Bc ((1<<SIZE_Bc)-1)
#define MAXARG_sBc (MAXARG_Bc>>1) /* `sBc' is signed */
#else
#define MAXARG_Bc MAX_INT
#define MAXARG_sBc MAX_INT
#endif
#define MAXARG_A ((1<<SIZE_A)-1)
#define MAXARG_B ((1<<SIZE_B)-1)
#define MAXARG_C ((1<<SIZE_C)-1)
/* creates a mask with `n' 1 bits at position `p' */ /* creates a mask with `n' 1 bits at position `p' */
@ -47,120 +73,129 @@
** the following macros help to manipulate instructions ** the following macros help to manipulate instructions
*/ */
#define CREATE_0(o) ((Instruction)(o))
#define GET_OPCODE(i) ((OpCode)((i)&MASK1(SIZE_OP,0))) #define GET_OPCODE(i) ((OpCode)((i)&MASK1(SIZE_OP,0)))
#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,0)) | (Instruction)(o))) #define SET_OPCODE(i,o) (((i)&MASK0(SIZE_OP,0)) | (Instruction)(o))
#define CREATE_U(o,u) ((Instruction)(o) | ((Instruction)(u)<<POS_U))
#define GETARG_U(i) ((int)((i)>>POS_U))
#define SETARG_U(i,u) ((i) = (((i)&MASK0(SIZE_U,POS_U)) | \
((Instruction)(u)<<POS_U)))
#define CREATE_S(o,s) CREATE_U((o),(s)+MAXARG_S)
#define GETARG_S(i) (GETARG_U(i)-MAXARG_S)
#define SETARG_S(i,s) SETARG_U((i),(s)+MAXARG_S)
#define CREATE_AB(o,a,b) ((Instruction)(o) | ((Instruction)(a)<<POS_A) \
| ((Instruction)(b)<<POS_B))
#define GETARG_A(i) ((int)((i)>>POS_A)) #define GETARG_A(i) ((int)((i)>>POS_A))
#define SETARG_A(i,a) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ #define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
((Instruction)(a)<<POS_A))) ((Instruction)(u)<<POS_A)))
#define GETARG_B(i) ((int)(((i)>>POS_B) & MASK1(SIZE_B,0))) #define GETARG_B(i) ((int)(((i)>>POS_B) & MASK1(SIZE_B,0)))
#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ #define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \
((Instruction)(b)<<POS_B))) ((Instruction)(b)<<POS_B)))
#define GETARG_C(i) ((int)(((i)>>POS_C) & MASK1(SIZE_C,0)))
#define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \
((Instruction)(b)<<POS_C)))
#define GETARG_Bc(i) ((int)(((i)>>POS_Bc) & MASK1(SIZE_Bc,0)))
#define SETARG_Bc(i,b) ((i) = (((i)&MASK0(SIZE_Bc,POS_Bc)) | \
((Instruction)(b)<<POS_Bc)))
#define GETARG_sBc(i) (GETARG_Bc(i)-MAXARG_sBc)
#define SETARG_sBc(i,b) SETARG_Bc((i),(b)+MAXARG_sBc)
#define CREATE_ABC(o,a,b,c) ((Instruction)(o) \
| ((Instruction)(a)<<POS_A) \
| ((Instruction)(b)<<POS_B) \
| ((Instruction)(c)<<POS_C))
#define CREATE_ABc(o,a,bc) ((Instruction)(o) \
| ((Instruction)(a)<<POS_A) \
| ((Instruction)(bc)<<POS_Bc))
/* /*
** K = U argument used as index to `kstr' ** an invalid register that fits in 8 bits
** J = S argument used as jump offset (relative to pc of next instruction) */
** L = unsigned argument used as index of local variable #define NO_REG MAXARG_A
** N = U argument used as index to `knum'
/*
** R(x) - register
** Kst(x) - constant (in constant table)
** R/K(x) == if x < MAXSTACK then R(x) else Kst(x-MAXSTACK)
*/ */
typedef enum { typedef enum {
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
name args stack before stack after side effects name args description
------------------------------------------------------------------------*/ ------------------------------------------------------------------------*/
OP_RETURN,/* U v_n-v_x(at u) (return) returns v_x-v_n */ OP_MOVE,/* A B R(A) := R(B) */
OP_LOADK,/* A Bc R(A) := Kst(Bc) */
OP_LOADINT,/* A sBc R(A) := (Number)sBc */
OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */
OP_LOADUPVAL,/* A Bc R(A) := UpValue[Bc] */
OP_CALL,/* A B v_n-v_1 f(at a) r_b-r_1 f(v1,...,v_n) */ OP_GETGLOBAL,/* A Bc R(A) := Gbl[Kst(Bc)] */
OP_GETTABLE,/* A B C R(A) := R(B)[R/K(C)] */
OP_PUSHNIL,/* U - nil_1-nil_u */ OP_SETGLOBAL,/* A Bc Gbl[Kst(Bc)] := R(A) */
OP_POP,/* U a_u-a_1 - */ OP_SETTABLE,/* A B C R(B)[R/K(C)] := R(A) */
OP_PUSHINT,/* S - (lua_Number)s */ OP_NEWTABLE,/* A Bc R(A) := {} (size = Bc) */
OP_PUSHSTRING,/* K - KSTR[k] */
OP_PUSHNUM,/* N - KNUM[n] */
OP_PUSHNEGNUM,/* N - -KNUM[n] */
OP_PUSHUPVALUE,/* U - Closure[u] */ OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[R/K(C)] */
OP_GETLOCAL,/* L - LOC[l] */ OP_ADD,/* A B C R(A) := R(B) + R/K(C) */
OP_GETGLOBAL,/* K - VAR[KSTR[k]] */ OP_SUB,/* A B C R(A) := R(B) - R/K(C) */
OP_MUL,/* A B C R(A) := R(B) * R/K(C) */
OP_DIV,/* A B C R(A) := R(B) / R/K(C) */
OP_POW,/* A B C R(A) := R(B) ^ R/K(C) */
OP_UNM,/* A B R(A) := -R(B) */
OP_NOT,/* A B R(A) := not R(B) */
OP_GETTABLE,/* - i t t[i] */ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
OP_GETDOTTED,/* K t t[KSTR[k]] */
OP_GETINDEXED,/* L t t[LOC[l]] */
OP_PUSHSELF,/* K t t t[KSTR[k]] */
OP_CREATETABLE,/* U - newarray(size = u) */ OP_JMP,/* sBc PC += sBc */
OP_CJMP,/* sBc if test then PC += sBc (see (1)) */
OP_SETLOCAL,/* L x - LOC[l]=x */ OP_TESTEQ,/* B C test := (R(B) == R/K(C)) */
OP_SETGLOBAL,/* K x - VAR[KSTR[k]]=x */ OP_TESTNE,/* B C test := (R(B) ~= R/K(C)) */
OP_SETTABLE,/* A B v a_a-a_1 i t (pops b values) t[i]=v */ OP_TESTLT,/* B C test := (R(B) < R/K(C)) */
OP_TESTLE,/* B C test := (R(B) <= R/K(C)) */
OP_TESTGT,/* B C test := (R(B) > R/K(C)) */
OP_TESTGE,/* B C test := (R(B) >= R/K(C)) */
OP_SETLIST,/* A B v_n-v_1 v_b v_b v_b[i+a*FPF]=v_i */ OP_TESTT,/* A B test := R(B); if (test) R(A) := R(B) */
OP_SETMAP,/* U v_n k_n - v_1 k_1 v_u v_u v_u[k_i]=v_i */ OP_TESTF,/* A B test := not R(B); if (test) R(A) := nil */
OP_ADD,/* - y x x+y */ OP_NILJMP,/* A R(A) := nil; PC++; */
OP_ADDI,/* S x x+s */
OP_SUB,/* - y x x-y */
OP_MULT,/* - y x x*y */
OP_DIV,/* - y x x/y */
OP_POW,/* - y x x^y */
OP_CONCAT,/* U v_u-v_1 v1..-..v_u */
OP_MINUS,/* - x -x */
OP_NOT,/* - x (x==nil)? 1 : nil */
OP_JMPNE,/* J y x - (x~=y)? PC+=s */ OP_CALL,/* A B C R(A), ... ,R(A+C-1) := R(A)(R(A+1), ... ,R(B-1))*/
OP_JMPEQ,/* J y x - (x==y)? PC+=s */ OP_RETURN,/* A B return R(A), ... ,R(B-1) (see (3)) */
OP_JMPLT,/* J y x - (x<y)? PC+=s */
OP_JMPLE,/* J y x - (x<y)? PC+=s */
OP_JMPGT,/* J y x - (x>y)? PC+=s */
OP_JMPGE,/* J y x - (x>=y)? PC+=s */
OP_JMPT,/* J x - (x~=nil)? PC+=s */ OP_FORPREP,/* A sBc */
OP_JMPF,/* J x - (x==nil)? PC+=s */ OP_FORLOOP,/* A sBc */
OP_JMPONT,/* J x (x~=nil)? x : - (x~=nil)? PC+=s */
OP_JMPONF,/* J x (x==nil)? x : - (x==nil)? PC+=s */
OP_JMP,/* J - - PC+=s */
OP_PUSHNILJMP,/* - - nil PC++; */ OP_TFORPREP,/* A sBc */
OP_TFORLOOP,/* A sBc */
OP_FORPREP,/* J */ OP_SETLIST,/* A Bc R(A)[Bc-Bc%FPF+i] := R(A+i), 1 <= i <= Bc%FPF+1 */
OP_FORLOOP,/* J */ OP_SETLISTO,/* A Bc */
OP_LFORPREP,/* J */
OP_LFORLOOP,/* J */
OP_CLOSURE/* A B v_b-v_1 closure(KPROTO[a], v_1-v_b) */
OP_CLOSURE /* A Bc R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n)) */
} OpCode; } OpCode;
#define NUM_OPCODES ((int)OP_CLOSURE+1) #define NUM_OPCODES ((int)OP_CLOSURE+1)
#define ISJUMP(o) (OP_JMPNE <= (o) && (o) <= OP_JMP)
/*===========================================================================
Notes:
(1) In the current implementation there is no `test' variable;
instructions OP_TEST* and OP_CJMP must always occur together.
(2) In OP_CALL, if (B == NO_REG) then B = top. C is the number of returns,
and can be NO_REG. OP_CALL always set "top" to last_result+1, so
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use "top".
/* special code to fit a LUA_MULTRET inside an argB */ (3) In OP_RETURN, if (B == NO_REG) then B = top.
#define MULT_RET 255 /* (<=MAXARG_B) */ ===========================================================================*/
#if MULT_RET>MAXARG_B
#undef MULT_RET
#define MULT_RET MAXARG_B
#endif
#endif #endif

560
lparser.c

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lparser.h,v 1.29 2000/12/28 12:55:41 roberto Exp roberto $ ** $Id: lparser.h,v 1.30 2001/02/20 18:28:11 roberto Exp roberto $
** LL(1) Parser and code generator for Lua ** LL(1) Parser and code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -16,25 +16,32 @@
*/ */
typedef enum { typedef enum {
VGLOBAL, VVOID, /* no value */
VLOCAL, VNIL,
VINDEXED, VNUMBER, /* n = value */
VEXP VK, /* info = index of constant in `k' */
VGLOBAL, /* info = index of global name in `k' */
VLOCAL, /* info = local register */
VINDEXED, /* info = table register; aux = index register (or `k') */
VRELOCABLE, /* info = instruction pc */
VNONRELOC, /* info = result register */
VJMP, /* info = result register */
VCALL /* info = result register */
} expkind; } expkind;
typedef struct expdesc { typedef struct expdesc {
expkind k; expkind k;
union { union {
int index; /* VGLOBAL: `kstr' index of global name; VLOCAL: stack index */
struct { struct {
int t; /* patch list of `exit when true' */ int info, aux;
int f; /* patch list of `exit when false' */ } i;
} l; lua_Number n;
} u; } u;
int t; /* patch list of `exit when true' */
int f; /* patch list of `exit when false' */
} expdesc; } expdesc;
/* state needed to generate code for a given function */ /* state needed to generate code for a given function */
typedef struct FuncState { typedef struct FuncState {
Proto *f; /* current function header */ Proto *f; /* current function header */
@ -44,10 +51,9 @@ typedef struct FuncState {
int pc; /* next position to code (equivalent to `ncode') */ int pc; /* next position to code (equivalent to `ncode') */
int lasttarget; /* `pc' of last `jump target' */ int lasttarget; /* `pc' of last `jump target' */
int jlt; /* list of jumps to `lasttarget' */ int jlt; /* list of jumps to `lasttarget' */
int stacklevel; /* number of values on activation register */ int freereg; /* first free register */
int nkstr; /* number of elements in `kstr' */ int nk; /* number of elements in `k' */
int nkproto; /* number of elements in `kproto' */ int nkproto; /* number of elements in `kproto' */
int nknum; /* number of elements in `knum' */
int nlineinfo; /* number of elements in `lineinfo' */ int nlineinfo; /* number of elements in `lineinfo' */
int nlocvars; /* number of elements in `locvars' */ int nlocvars; /* number of elements in `locvars' */
int nactloc; /* number of active local variables */ int nactloc; /* number of active local variables */

133
ltests.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: ltests.c,v 1.79 2001/04/17 17:35:54 roberto Exp roberto $ ** $Id: ltests.c,v 1.80 2001/04/23 16:35:45 roberto Exp roberto $
** Internal Module for Debugging of the Lua Implementation ** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -140,77 +140,65 @@ void *debug_realloc (void *block, size_t oldsize, size_t size) {
static const l_char *const instrname[NUM_OPCODES] = { static const l_char *const instrname[NUM_OPCODES] = {
l_s("RETURN"), l_s("OP_MOVE"),
l_s("CALL"), l_s("OP_LOADK"),
l_s("PUSHNIL"), l_s("OP_LOADINT"),
l_s("POP"), l_s("OP_LOADNIL"),
l_s("PUSHINT"), l_s("OP_LOADUPVAL"),
l_s("PUSHSTRING"), l_s("OP_GETGLOBAL"),
l_s("PUSHNUM"), l_s("OP_GETTABLE"),
l_s("PUSHNEGNUM"), l_s("OP_SETGLOBAL"),
l_s("PUSHUPVALUE"), l_s("OP_SETTABLE"),
l_s("GETLOCAL"), l_s("OP_NEWTABLE"),
l_s("GETGLOBAL"), l_s("OP_SELF"),
l_s("GETTABLE"), l_s("OP_ADD"),
l_s("GETDOTTED"), l_s("OP_SUB"),
l_s("GETINDEXED"), l_s("OP_MUL"),
l_s("PUSHSELF"), l_s("OP_DIV"),
l_s("CREATETABLE"), l_s("OP_POW"),
l_s("SETLOCAL"), l_s("OP_UNM"),
l_s("SETGLOBAL"), l_s("OP_NOT"),
l_s("SETTABLE"), l_s("OP_CONCAT"),
l_s("SETLIST"), l_s("OP_JMP"),
l_s("SETMAP"), l_s("OP_CJMP"),
l_s("ADD"), l_s("OP_TESTEQ"),
l_s("ADDI"), l_s("OP_TESTNE"),
l_s("SUB"), l_s("OP_TESTLT"),
l_s("MULT"), l_s("OP_TESTLE"),
l_s("DIV"), l_s("OP_TESTGT"),
l_s("POW"), l_s("OP_TESTGE"),
l_s("CONCAT"), l_s("OP_TESTT"),
l_s("MINUS"), l_s("OP_TESTF"),
l_s("NOT"), l_s("OP_NILJMP"),
l_s("JMPNE"), l_s("OP_CALL"),
l_s("JMPEQ"), l_s("OP_RETURN"),
l_s("JMPLT"), l_s("OP_FORPREP"),
l_s("JMPLE"), l_s("OP_FORLOOP"),
l_s("JMPGT"), l_s("OP_LFORPREP"),
l_s("JMPGE"), l_s("OP_LFORLOOP"),
l_s("JMPT"), l_s("OP_SETLIST"),
l_s("JMPF"), l_s("OP_CLOSURE")
l_s("JMPONT"),
l_s("JMPONF"),
l_s("JMP"),
l_s("PUSHNILJMP"),
l_s("FORPREP"),
l_s("FORLOOP"),
l_s("LFORPREP"),
l_s("LFORLOOP"),
l_s("CLOSURE")
}; };
static void pushop (lua_State *L, Proto *p, int pc) { static l_char *buildop (Proto *p, int pc, l_char *buff) {
l_char buff[100];
Instruction i = p->code[pc]; Instruction i = p->code[pc];
OpCode o = GET_OPCODE(i); OpCode o = GET_OPCODE(i);
const l_char *name = instrname[o]; const l_char *name = instrname[o];
sprintf(buff, l_s("%5d - "), luaG_getline(p->lineinfo, pc, 1, NULL)); sprintf(buff, l_s("%4d - "), pc);
switch ((enum Mode)luaK_opproperties[o].mode) { switch (getOpMode(o)) {
case iO: case iABC:
sprintf(buff+8, l_s("%-12s"), name); sprintf(buff+strlen(buff), l_s("%-12s%4d %4d %4d"), name,
GETARG_A(i), GETARG_B(i), GETARG_C(i));
break; break;
case iU: case iABc:
sprintf(buff+8, l_s("%-12s%4u"), name, GETARG_U(i)); sprintf(buff+strlen(buff), l_s("%-12s%4d %4d"), name, GETARG_A(i), GETARG_Bc(i));
break; break;
case iS: case iAsBc:
sprintf(buff+8, l_s("%-12s%4d"), name, GETARG_S(i)); sprintf(buff+strlen(buff), l_s("%-12s%4d %4d"), name, GETARG_A(i), GETARG_sBc(i));
break;
case iAB:
sprintf(buff+8, l_s("%-12s%4d %4d"), name, GETARG_A(i), GETARG_B(i));
break; break;
} }
lua_pushstring(L, buff); return buff;
} }
@ -224,24 +212,25 @@ static int listcode (lua_State *L) {
setnameval(L, l_s("maxstack"), p->maxstacksize); setnameval(L, l_s("maxstack"), p->maxstacksize);
setnameval(L, l_s("numparams"), p->numparams); setnameval(L, l_s("numparams"), p->numparams);
for (pc=0; pc<p->sizecode; pc++) { for (pc=0; pc<p->sizecode; pc++) {
l_char buff[100];
lua_pushnumber(L, pc+1); lua_pushnumber(L, pc+1);
pushop(L, p, pc); lua_pushstring(L, buildop(p, pc, buff));
lua_settable(L, -3); lua_settable(L, -3);
} }
return 1; return 1;
} }
static int liststrings (lua_State *L) { static int listk (lua_State *L) {
Proto *p; Proto *p;
int i; int i;
luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
1, l_s("Lua function expected")); 1, l_s("Lua function expected"));
p = clvalue(luaA_index(L, 1))->f.l; p = clvalue(luaA_index(L, 1))->f.l;
lua_newtable(L); lua_newtable(L);
for (i=0; i<p->sizekstr; i++) { for (i=0; i<p->sizek; i++) {
lua_pushnumber(L, i+1); lua_pushnumber(L, i+1);
lua_pushstring(L, getstr(p->kstr[i])); luaA_pushobject(L, p->k+i);
lua_settable(L, -3); lua_settable(L, -3);
} }
return 1; return 1;
@ -276,20 +265,10 @@ static int get_limits (lua_State *L) {
lua_newtable(L); lua_newtable(L);
setnameval(L, l_s("BITS_INT"), BITS_INT); setnameval(L, l_s("BITS_INT"), BITS_INT);
setnameval(L, l_s("LFPF"), LFIELDS_PER_FLUSH); setnameval(L, l_s("LFPF"), LFIELDS_PER_FLUSH);
setnameval(L, l_s("MAXARG_A"), MAXARG_A);
setnameval(L, l_s("MAXARG_B"), MAXARG_B);
setnameval(L, l_s("MAXARG_S"), MAXARG_S);
setnameval(L, l_s("MAXARG_U"), MAXARG_U);
setnameval(L, l_s("MAXLOCALS"), MAXLOCALS); setnameval(L, l_s("MAXLOCALS"), MAXLOCALS);
setnameval(L, l_s("MAXPARAMS"), MAXPARAMS); setnameval(L, l_s("MAXPARAMS"), MAXPARAMS);
setnameval(L, l_s("MAXSTACK"), MAXSTACK); setnameval(L, l_s("MAXSTACK"), MAXSTACK);
setnameval(L, l_s("MAXUPVALUES"), MAXUPVALUES); setnameval(L, l_s("MAXUPVALUES"), MAXUPVALUES);
setnameval(L, l_s("MAXVARSLH"), MAXVARSLH);
setnameval(L, l_s("RFPF"), RFIELDS_PER_FLUSH);
setnameval(L, l_s("SIZE_A"), SIZE_A);
setnameval(L, l_s("SIZE_B"), SIZE_B);
setnameval(L, l_s("SIZE_OP"), SIZE_OP);
setnameval(L, l_s("SIZE_U"), SIZE_U);
return 1; return 1;
} }
@ -700,7 +679,7 @@ static const struct luaL_reg tests_funcs[] = {
{l_s("hash"), hash_query}, {l_s("hash"), hash_query},
{l_s("limits"), get_limits}, {l_s("limits"), get_limits},
{l_s("listcode"), listcode}, {l_s("listcode"), listcode},
{l_s("liststrings"), liststrings}, {l_s("listk"), listk},
{l_s("listlocals"), listlocals}, {l_s("listlocals"), listlocals},
{l_s("loadlib"), loadlib}, {l_s("loadlib"), loadlib},
{l_s("querystr"), string_query}, {l_s("querystr"), string_query},

516
lvm.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lvm.c,v 1.177 2001/03/26 14:31:49 roberto Exp roberto $ ** $Id: lvm.c,v 1.178 2001/04/06 18:25:00 roberto Exp roberto $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -28,15 +28,14 @@
int luaV_tonumber (TObject *obj) { const TObject *luaV_tonumber (const TObject *obj, TObject *n) {
if (ttype(obj) != LUA_TSTRING) if (ttype(obj) == LUA_TNUMBER) return obj;
return 1; if (ttype(obj) == LUA_TSTRING && luaO_str2d(svalue(obj), &nvalue(n))) {
else { ttype(n) = LUA_TNUMBER;
if (!luaO_str2d(svalue(obj), &nvalue(obj))) return n;
return 2;
ttype(obj) = LUA_TNUMBER;
return 0;
} }
else
return NULL;
} }
@ -148,8 +147,7 @@ void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) {
} }
} }
/* else will call the tag method */ /* else will call the tag method */
} } else { /* not a table; try a `gettable' tag method */
else { /* not a table; try a `gettable' tag method */
tm = luaT_gettmbyObj(G(L), t, TM_GETTABLE); tm = luaT_gettmbyObj(G(L), t, TM_GETTABLE);
if (tm == NULL) /* no tag method? */ if (tm == NULL) /* no tag method? */
luaG_typeerror(L, t, l_s("index")); luaG_typeerror(L, t, l_s("index"));
@ -162,7 +160,7 @@ void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) {
/* /*
** Receives table at `t', key at `key' and value at `val'. ** Receives table at `t', key at `key' and value at `val'.
*/ */
void luaV_settable (lua_State *L, StkId t, StkId key, StkId val) { void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val) {
Closure *tm; Closure *tm;
if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */ if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */
int tg = hvalue(t)->htag; int tg = hvalue(t)->htag;
@ -172,8 +170,7 @@ void luaV_settable (lua_State *L, StkId t, StkId key, StkId val) {
return; return;
} }
/* else will call the tag method */ /* else will call the tag method */
} } else { /* not a table; try a `settable' tag method */
else { /* not a table; try a `settable' tag method */
tm = luaT_gettmbyObj(G(L), t, TM_SETTABLE); tm = luaT_gettmbyObj(G(L), t, TM_SETTABLE);
if (tm == NULL) /* no tag method? */ if (tm == NULL) /* no tag method? */
luaG_typeerror(L, t, l_s("index")); luaG_typeerror(L, t, l_s("index"));
@ -188,8 +185,7 @@ void luaV_getglobal (lua_State *L, TString *name, StkId res) {
if (!HAS_TM_GETGLOBAL(L, ttype(value)) || /* is there a tag method? */ if (!HAS_TM_GETGLOBAL(L, ttype(value)) || /* is there a tag method? */
(tm = luaT_gettmbyObj(G(L), value, TM_GETGLOBAL)) == NULL) { (tm = luaT_gettmbyObj(G(L), value, TM_GETGLOBAL)) == NULL) {
setobj(res, value); /* default behavior */ setobj(res, value); /* default behavior */
} } else
else
callTM(L, l_s("csor"), tm, name, value, res); callTM(L, l_s("csor"), tm, name, value, res);
} }
@ -200,8 +196,7 @@ void luaV_setglobal (lua_State *L, TString *name, StkId val) {
if (!HAS_TM_SETGLOBAL(L, ttype(oldvalue)) || /* no tag methods? */ if (!HAS_TM_SETGLOBAL(L, ttype(oldvalue)) || /* no tag methods? */
(tm = luaT_gettmbyObj(G(L), oldvalue, TM_SETGLOBAL)) == NULL) { (tm = luaT_gettmbyObj(G(L), oldvalue, TM_SETGLOBAL)) == NULL) {
setobj(oldvalue, val); /* raw set */ setobj(oldvalue, val); /* raw set */
} } else
else
callTM(L, l_s("csoo"), tm, name, oldvalue, val); callTM(L, l_s("csoo"), tm, name, oldvalue, val);
} }
@ -224,9 +219,10 @@ static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2,
} }
static void call_arith (lua_State *L, StkId p1, TMS event) { static void call_arith (lua_State *L, StkId p1, TObject *p2,
if (!call_binTM(L, p1, p1+1, p1, event)) StkId res, TMS event) {
luaG_binerror(L, p1, LUA_TNUMBER, l_s("perform arithmetic on")); if (!call_binTM(L, p1, p2, res, event))
luaG_aritherror(L, p1, p2);
} }
@ -270,9 +266,8 @@ void luaV_strconc (lua_State *L, int total, StkId top) {
int n = 2; /* number of elements handled in this pass (at least 2) */ int n = 2; /* number of elements handled in this pass (at least 2) */
if (tostring(L, top-2) || tostring(L, top-1)) { if (tostring(L, top-2) || tostring(L, top-1)) {
if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
luaG_binerror(L, top-2, LUA_TSTRING, l_s("concat")); luaG_concaterror(L, top-2, top-1);
} } else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */
else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */
/* at least two string values; get as many as possible */ /* at least two string values; get as many as possible */
lu_mem tl = (lu_mem)tsvalue(top-1)->len + (lu_mem)tsvalue(top-2)->len; lu_mem tl = (lu_mem)tsvalue(top-1)->len + (lu_mem)tsvalue(top-2)->len;
l_char *buffer; l_char *buffer;
@ -321,7 +316,32 @@ static void adjust_varargs (lua_State *L, StkId base, int nfixargs) {
#define dojump(pc, i) ((pc) += GETARG_S(i)) /*
** some macros for common tasks in `luaV_execute'
*/
#define runtime_check(L, c) { if (!(c)) return L->top; }
#define RA(i) (base+GETARG_A(i))
#define RB(i) (base+GETARG_B(i))
#define RC(i) (base+GETARG_C(i))
#define RKC(i) ((GETARG_C(i) < MAXSTACK) ? \
base+GETARG_C(i) : \
tf->k+GETARG_C(i)-MAXSTACK)
#define KBc(i) (tf->k+GETARG_Bc(i))
#define Arith(op, optm) { \
const TObject *b = RB(i); const TObject *c = RKC(i); \
TObject tempb, tempc; \
if ((ttype(b) == LUA_TNUMBER || (b = luaV_tonumber(b, &tempb)) != NULL) && \
(ttype(c) == LUA_TNUMBER || (c = luaV_tonumber(c, &tempc)) != NULL)) { \
setnvalue(RA(i), nvalue(b) op nvalue(c)); \
} else \
call_arith(L, RB(i), RKC(i), RA(i), optm); \
}
#define dojump(pc, i) ((pc) += GETARG_sBc(i))
/* /*
** Executes the given Lua function. Parameters are between [base,top). ** Executes the given Lua function. Parameters are between [base,top).
@ -329,328 +349,294 @@ static void adjust_varargs (lua_State *L, StkId base, int nfixargs) {
*/ */
StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) { StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) {
const Proto *const tf = cl->f.l; const Proto *const tf = cl->f.l;
StkId top; /* keep top local, for performance */ const Instruction *pc;
const Instruction *pc = tf->code; lua_Hook linehook;
const lua_Hook linehook = L->linehook;
L->ci->pc = &pc;
if (tf->is_vararg) /* varargs? */ if (tf->is_vararg) /* varargs? */
adjust_varargs(L, base, tf->numparams); adjust_varargs(L, base, tf->numparams);
luaD_adjusttop(L, base, tf->maxstacksize); luaD_adjusttop(L, base, tf->maxstacksize);
top = base+tf->numparams+tf->is_vararg; pc = tf->code;
L->ci->pc = &pc;
linehook = L->linehook;
/* main loop of interpreter */ /* main loop of interpreter */
for (;;) { for (;;) {
const Instruction i = *pc++; const Instruction i = *pc++;
lua_assert(L->top == base+tf->maxstacksize);
if (linehook) if (linehook)
traceexec(L, linehook); traceexec(L, linehook);
switch (GET_OPCODE(i)) { switch (GET_OPCODE(i)) {
case OP_RETURN: { case OP_MOVE: {
L->top = top; setobj(RA(i), RB(i));
return base+GETARG_U(i);
}
case OP_CALL: {
int nres = GETARG_B(i);
if (nres == MULT_RET) nres = LUA_MULTRET;
L->top = top;
luaD_call(L, base+GETARG_A(i), nres);
top = L->top;
L->top = base+tf->maxstacksize;
break; break;
} }
case OP_PUSHNIL: { case OP_LOADK: {
int n = GETARG_U(i); setobj(RA(i), KBc(i));
lua_assert(n>0); break;
}
case OP_LOADINT: {
setnvalue(RA(i), (lua_Number)GETARG_sBc(i));
break;
}
case OP_LOADUPVAL: {
setobj(RA(i), cl->upvalue+GETARG_Bc(i));
break;
}
case OP_LOADNIL: {
TObject *ra = RA(i);
TObject *rb = RB(i);
do { do {
setnilvalue(top++); setnilvalue(ra++);
} while (--n > 0); } while (ra <= rb);
break;
}
case OP_POP: {
top -= GETARG_U(i);
break;
}
case OP_PUSHINT: {
setnvalue(top, (lua_Number)GETARG_S(i));
top++;
break;
}
case OP_PUSHSTRING: {
setsvalue(top, tf->kstr[GETARG_U(i)]);
top++;
break;
}
case OP_PUSHNUM: {
setnvalue(top, tf->knum[GETARG_U(i)]);
top++;
break;
}
case OP_PUSHNEGNUM: {
setnvalue(top, -tf->knum[GETARG_U(i)]);
top++;
break;
}
case OP_PUSHUPVALUE: {
setobj(top++, &cl->upvalue[GETARG_U(i)]);
break;
}
case OP_GETLOCAL: {
setobj(top++, base+GETARG_U(i));
break; break;
} }
case OP_GETGLOBAL: { case OP_GETGLOBAL: {
luaV_getglobal(L, tf->kstr[GETARG_U(i)], top); lua_assert(ttype(KBc(i)) == LUA_TSTRING);
top++; luaV_getglobal(L, tsvalue(KBc(i)), RA(i));
break; break;
} }
case OP_GETTABLE: { case OP_GETTABLE: {
top--; luaV_gettable(L, RB(i), RKC(i), RA(i));
luaV_gettable(L, top-1, top, top-1);
break;
}
case OP_GETDOTTED: {
setsvalue(top, tf->kstr[GETARG_U(i)]);
luaV_gettable(L, top-1, top, top-1);
break;
}
case OP_GETINDEXED: {
luaV_gettable(L, top-1, base+GETARG_U(i), top-1);
break;
}
case OP_PUSHSELF: {
setobj(top, top-1);
setsvalue(top+1, tf->kstr[GETARG_U(i)]);
luaV_gettable(L, top-1, top+1, top-1);
top++;
break;
}
case OP_CREATETABLE: {
luaC_checkGC(L);
sethvalue(top, luaH_new(L, GETARG_U(i)));
top++;
break;
}
case OP_SETLOCAL: {
setobj(base+GETARG_U(i), --top);
break; break;
} }
case OP_SETGLOBAL: { case OP_SETGLOBAL: {
top--; lua_assert(ttype(KBc(i)) == LUA_TSTRING);
luaV_setglobal(L, tf->kstr[GETARG_U(i)], top); luaV_setglobal(L, tsvalue(KBc(i)), RA(i));
break; break;
} }
case OP_SETTABLE: { case OP_SETTABLE: {
StkId t = top-GETARG_A(i); luaV_settable(L, RB(i), RKC(i), RA(i));
luaV_settable(L, t, t+1, top-1);
top -= GETARG_B(i); /* pop values */
break; break;
} }
case OP_SETLIST: { case OP_NEWTABLE: {
int aux = GETARG_A(i) * LFIELDS_PER_FLUSH; luaC_checkGC(L);
TObject *t = base+GETARG_B(i); sethvalue(RA(i), luaH_new(L, GETARG_Bc(i)));
Hash *h = hvalue(t);
int n;
for (n = top-t-1; n; n--)
setobj(luaH_setnum(L, h, n+aux), --top);
break; break;
} }
case OP_SETMAP: { case OP_SELF: {
TObject *t = base+GETARG_U(i); StkId ra = RA(i);
Hash *h = hvalue(t); StkId rb = RB(i);
while (top-1 > t) { setobj(ra+1, rb);
top-=2; luaV_gettable(L, rb, RKC(i), ra);
setobj(luaH_set(L, h, top), top+1);
}
break; break;
} }
case OP_ADD: { case OP_ADD: {
if (tonumber(top-2) || tonumber(top-1)) Arith( + , TM_ADD);
call_arith(L, top-2, TM_ADD);
else
nvalue(top-2) += nvalue(top-1);
top--;
break;
}
case OP_ADDI: {
if (tonumber(top-1)) {
setnvalue(top, (lua_Number)GETARG_S(i));
call_arith(L, top-1, TM_ADD);
}
else
nvalue(top-1) += (lua_Number)GETARG_S(i);
break; break;
} }
case OP_SUB: { case OP_SUB: {
if (tonumber(top-2) || tonumber(top-1)) Arith( - , TM_SUB);
call_arith(L, top-2, TM_SUB);
else
nvalue(top-2) -= nvalue(top-1);
top--;
break; break;
} }
case OP_MULT: { case OP_MUL: {
if (tonumber(top-2) || tonumber(top-1)) Arith( * , TM_MUL);
call_arith(L, top-2, TM_MUL);
else
nvalue(top-2) *= nvalue(top-1);
top--;
break; break;
} }
case OP_DIV: { case OP_DIV: {
if (tonumber(top-2) || tonumber(top-1)) Arith( / , TM_DIV);
call_arith(L, top-2, TM_DIV);
else
nvalue(top-2) /= nvalue(top-1);
top--;
break; break;
} }
case OP_POW: { case OP_POW: {
if (!call_binTM(L, top-2, top-1, top-2, TM_POW)) call_arith(L, RB(i), RKC(i), RA(i), TM_POW);
luaD_error(L, l_s("undefined operation"));
top--;
break; break;
} }
case OP_CONCAT: { case OP_UNM: {
int n = GETARG_U(i); const TObject *rb = RB(i);
luaV_strconc(L, n, top); StkId ra = RA(i);
top -= n-1; if (ttype(rb) == LUA_TNUMBER || (rb=luaV_tonumber(rb, ra)) != NULL) {
luaC_checkGC(L); setnvalue(ra, -nvalue(rb));
break; }
} else {
case OP_MINUS: { TObject temp;
if (tonumber(top-1)) { setnilvalue(&temp);
setnilvalue(top); call_arith(L, RB(i), &temp, ra, TM_UNM);
call_arith(L, top-1, TM_UNM);
} }
else
nvalue(top-1) = -nvalue(top-1);
break; break;
} }
case OP_NOT: { case OP_NOT: {
ttype(top-1) = if (ttype(RB(i)) == LUA_TNIL) {
(ttype(top-1) == LUA_TNIL) ? LUA_TNUMBER : LUA_TNIL; setnvalue(RA(i), 1);
nvalue(top-1) = 1; } else {
setnilvalue(RA(i));
}
break; break;
} }
case OP_JMPNE: { case OP_CONCAT: {
top -= 2; StkId top = RC(i)+1;
if (!luaO_equalObj(top, top+1)) dojump(pc, i); StkId rb = RB(i);
break; luaV_strconc(L, top-rb, top);
} setobj(RA(i), rb);
case OP_JMPEQ: { luaC_checkGC(L);
top -= 2;
if (luaO_equalObj(top, top+1)) dojump(pc, i);
break;
}
case OP_JMPLT: {
top -= 2;
if (luaV_lessthan(L, top, top+1)) dojump(pc, i);
break;
}
case OP_JMPLE: { /* a <= b === !(b<a) */
top -= 2;
if (!luaV_lessthan(L, top+1, top)) dojump(pc, i);
break;
}
case OP_JMPGT: { /* a > b === (b<a) */
top -= 2;
if (luaV_lessthan(L, top+1, top)) dojump(pc, i);
break;
}
case OP_JMPGE: { /* a >= b === !(a<b) */
top -= 2;
if (!luaV_lessthan(L, top, top+1)) dojump(pc, i);
break;
}
case OP_JMPT: {
if (ttype(--top) != LUA_TNIL) dojump(pc, i);
break;
}
case OP_JMPF: {
if (ttype(--top) == LUA_TNIL) dojump(pc, i);
break;
}
case OP_JMPONT: {
if (ttype(top-1) == LUA_TNIL) top--;
else dojump(pc, i);
break;
}
case OP_JMPONF: {
if (ttype(top-1) != LUA_TNIL) top--;
else dojump(pc, i);
break; break;
} }
case OP_CJMP:
case OP_JMP: { case OP_JMP: {
dojump(pc, i); dojump(pc, i);
break; break;
} }
case OP_PUSHNILJMP: { case OP_TESTEQ: {
setnilvalue(top++); lua_assert(GET_OPCODE(*pc) == OP_CJMP);
if (luaO_equalObj(RB(i), RKC(i))) dojump(pc, *pc);
pc++; pc++;
break; break;
} }
case OP_TESTNE: {
lua_assert(GET_OPCODE(*pc) == OP_CJMP);
if (!luaO_equalObj(RB(i), RKC(i))) dojump(pc, *pc);
pc++;
break;
}
case OP_TESTLT: {
lua_assert(GET_OPCODE(*pc) == OP_CJMP);
if (luaV_lessthan(L, RB(i), RKC(i))) dojump(pc, *pc);
pc++;
break;
}
case OP_TESTLE: { /* b <= c === !(c<b) */
lua_assert(GET_OPCODE(*pc) == OP_CJMP);
if (!luaV_lessthan(L, RKC(i), RB(i))) dojump(pc, *pc);
pc++;
break;
}
case OP_TESTGT: { /* b > c === (c<b) */
lua_assert(GET_OPCODE(*pc) == OP_CJMP);
if (luaV_lessthan(L, RKC(i), RB(i))) dojump(pc, *pc);
pc++;
break;
}
case OP_TESTGE: { /* b >= c === !(b<c) */
lua_assert(GET_OPCODE(*pc) == OP_CJMP);
if (!luaV_lessthan(L, RB(i), RKC(i))) dojump(pc, *pc);
pc++;
break;
}
case OP_TESTT: {
StkId rb = RB(i);
lua_assert(GET_OPCODE(*pc) == OP_CJMP);
if (ttype(rb) != LUA_TNIL) {
int a = GETARG_A(i);
if (a != NO_REG) setobj(base+a, rb);
dojump(pc, *pc);
}
pc++;
break;
}
case OP_TESTF: {
lua_assert(GET_OPCODE(*pc) == OP_CJMP);
if (ttype(RB(i)) == LUA_TNIL) {
int a = GETARG_A(i);
if (a != NO_REG) setnilvalue(base+a);
dojump(pc, *pc);
}
pc++;
break;
}
case OP_NILJMP: {
setnilvalue(RA(i));
pc++;
break;
}
case OP_CALL: {
int nres;
int b = GETARG_B(i);
if (b != NO_REG)
L->top = base+b;
nres = GETARG_C(i);
if (nres == NO_REG) nres = LUA_MULTRET;
luaD_call(L, RA(i), nres);
if (nres != LUA_MULTRET) {
lua_assert(L->top == RA(i)+nres);
L->top = base+tf->maxstacksize;
}
break;
}
case OP_RETURN: {
int b = GETARG_B(i);
if (b != NO_REG)
L->top = base+b;
return RA(i);
}
case OP_FORPREP: { case OP_FORPREP: {
int jmp = GETARG_S(i); int jmp = GETARG_sBc(i);
if (tonumber(top-1)) StkId breg = RA(i);
luaD_error(L, l_s("`for' step must be a number")); if (luaV_tonumber(breg, breg) == NULL)
if (tonumber(top-2))
luaD_error(L, l_s("`for' limit must be a number"));
if (tonumber(top-3))
luaD_error(L, l_s("`for' initial value must be a number")); luaD_error(L, l_s("`for' initial value must be a number"));
if (luaV_tonumber(breg+1, breg+1) == NULL)
luaD_error(L, l_s("`for' limit must be a number"));
if (luaV_tonumber(breg+2, breg+2) == NULL)
luaD_error(L, l_s("`for' step must be a number"));
pc += -jmp; /* `jump' to loop end (delta is negated here) */ pc += -jmp; /* `jump' to loop end (delta is negated here) */
goto forloop; /* do not increment index */ nvalue(breg) -= nvalue(breg+2);/* decrement index (to be incremented) */
/* go through */
} }
case OP_FORLOOP: { case OP_FORLOOP: {
lua_assert(ttype(top-1) == LUA_TNUMBER); StkId breg = RA(i);
lua_assert(ttype(top-2) == LUA_TNUMBER); if (ttype(breg) != LUA_TNUMBER)
if (ttype(top-3) != LUA_TNUMBER)
luaD_error(L, l_s("`for' index must be a number")); luaD_error(L, l_s("`for' index must be a number"));
nvalue(top-3) += nvalue(top-1); /* increment index */ runtime_check(L, ttype(breg+1) == LUA_TNUMBER &&
forloop: ttype(breg+2) == LUA_TNUMBER);
if (nvalue(top-1) > 0 ? nvalue(breg) += nvalue(breg+2); /* increment index */
nvalue(top-3) > nvalue(top-2) : if (nvalue(breg+2) > 0 ?
nvalue(top-3) < nvalue(top-2)) nvalue(breg) <= nvalue(breg+1) :
top -= 3; /* end loop: remove control variables */ nvalue(breg) >= nvalue(breg+1))
else
dojump(pc, i); /* repeat loop */ dojump(pc, i); /* repeat loop */
break; break;
} }
case OP_LFORPREP: { case OP_TFORPREP: {
int jmp = GETARG_S(i); int jmp = GETARG_sBc(i);
if (ttype(top-1) != LUA_TTABLE) StkId breg = RA(i);
if (ttype(breg) != LUA_TTABLE)
luaD_error(L, l_s("`for' table must be a table")); luaD_error(L, l_s("`for' table must be a table"));
top += 3; /* index,key,value */ setnvalue(breg+1, -1); /* initial index */
setnvalue(top-3, -1); /* initial index */ setnilvalue(breg+2);
setnilvalue(top-2); setnilvalue(breg+3);
setnilvalue(top-1);
pc += -jmp; /* `jump' to loop end (delta is negated here) */ pc += -jmp; /* `jump' to loop end (delta is negated here) */
/* go through */ /* go through */
} }
case OP_LFORLOOP: { case OP_TFORLOOP: {
Hash *t = hvalue(top-4); StkId breg = RA(i);
int n = (int)nvalue(top-3); Hash *t;
lua_assert(ttype(top-3) == LUA_TNUMBER); int n;
lua_assert(ttype(top-4) == LUA_TTABLE); runtime_check(L, ttype(breg) == LUA_TTABLE);
runtime_check(L, ttype(breg+1) == LUA_TNUMBER);
t = hvalue(breg);
n = (int)nvalue(breg+1);
n = luaH_nexti(t, n); n = luaH_nexti(t, n);
if (n == -1) /* end loop? */ if (n != -1) { /* repeat loop? */
top -= 4; /* remove table, index, key, and value */
else {
Node *node = node(t, n); Node *node = node(t, n);
setnvalue(top-3, n); /* index */ setnvalue(breg+1, n); /* index */
setkey2obj(top-2, node); setkey2obj(breg+2, node);
setobj(top-1, val(node)); setobj(breg+3, val(node));
dojump(pc, i); /* repeat loop */ dojump(pc, i); /* repeat loop */
} }
break; break;
} }
case OP_SETLIST:
case OP_SETLISTO: {
int bc;
int n;
Hash *h;
StkId ra = RA(i);
runtime_check(L, ttype(ra) == LUA_TTABLE);
h = hvalue(ra);
bc = GETARG_Bc(i);
if (GET_OPCODE(i) == OP_SETLIST)
n = (bc&(LFIELDS_PER_FLUSH-1)) + 1;
else
n = L->top - ra - 1;
bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */
for (; n > 0; n--)
setobj(luaH_setnum(L, h, bc+n), ra+n);
break;
}
case OP_CLOSURE: { case OP_CLOSURE: {
int nup = GETARG_B(i); Proto *p = tf->kproto[GETARG_Bc(i)];
luaC_checkGC(L); int nup = p->nupvalues;
L->top = top; StkId ra = RA(i);
luaV_Lclosure(L, tf->kproto[GETARG_A(i)], nup); L->top = ra+nup;
top -= (nup-1); luaV_Lclosure(L, p, nup);
L->top = base+tf->maxstacksize; L->top = base+tf->maxstacksize;
luaC_checkGC(L);
break; break;
} }
} }
} }
} }

7
lvm.h
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lvm.h,v 1.28 2001/02/01 16:03:38 roberto Exp roberto $ ** $Id: lvm.h,v 1.29 2001/02/07 18:13:49 roberto Exp roberto $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -13,14 +13,13 @@
#include "ltm.h" #include "ltm.h"
#define tonumber(o) ((ttype(o) != LUA_TNUMBER) && (luaV_tonumber(o) != 0))
#define tostring(L,o) ((ttype(o) != LUA_TSTRING) && (luaV_tostring(L, o) != 0)) #define tostring(L,o) ((ttype(o) != LUA_TSTRING) && (luaV_tostring(L, o) != 0))
int luaV_tonumber (TObject *obj); const TObject *luaV_tonumber (const TObject *obj, TObject *n);
int luaV_tostring (lua_State *L, TObject *obj); int luaV_tostring (lua_State *L, TObject *obj);
void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res); void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res);
void luaV_settable (lua_State *L, StkId t, StkId key, StkId val); void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val);
void luaV_getglobal (lua_State *L, TString *s, StkId res); void luaV_getglobal (lua_State *L, TString *s, StkId res);
void luaV_setglobal (lua_State *L, TString *s, StkId val); void luaV_setglobal (lua_State *L, TString *s, StkId val);
StkId luaV_execute (lua_State *L, const Closure *cl, StkId base); StkId luaV_execute (lua_State *L, const Closure *cl, StkId base);