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

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
** See Copyright Notice in lua.h
*/
@@ -28,15 +28,14 @@
int luaV_tonumber (TObject *obj) {
if (ttype(obj) != LUA_TSTRING)
return 1;
else {
if (!luaO_str2d(svalue(obj), &nvalue(obj)))
return 2;
ttype(obj) = LUA_TNUMBER;
return 0;
const TObject *luaV_tonumber (const TObject *obj, TObject *n) {
if (ttype(obj) == LUA_TNUMBER) return obj;
if (ttype(obj) == LUA_TSTRING && luaO_str2d(svalue(obj), &nvalue(n))) {
ttype(n) = LUA_TNUMBER;
return n;
}
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 { /* 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);
if (tm == NULL) /* no tag method? */
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'.
*/
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;
if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */
int tg = hvalue(t)->htag;
@@ -172,8 +170,7 @@ void luaV_settable (lua_State *L, StkId t, StkId key, StkId val) {
return;
}
/* 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);
if (tm == NULL) /* no tag method? */
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? */
(tm = luaT_gettmbyObj(G(L), value, TM_GETGLOBAL)) == NULL) {
setobj(res, value); /* default behavior */
}
else
} else
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? */
(tm = luaT_gettmbyObj(G(L), oldvalue, TM_SETGLOBAL)) == NULL) {
setobj(oldvalue, val); /* raw set */
}
else
} else
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) {
if (!call_binTM(L, p1, p1+1, p1, event))
luaG_binerror(L, p1, LUA_TNUMBER, l_s("perform arithmetic on"));
static void call_arith (lua_State *L, StkId p1, TObject *p2,
StkId res, TMS event) {
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) */
if (tostring(L, top-2) || tostring(L, top-1)) {
if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
luaG_binerror(L, top-2, LUA_TSTRING, l_s("concat"));
}
else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */
luaG_concaterror(L, top-2, top-1);
} else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */
/* 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;
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).
@@ -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) {
const Proto *const tf = cl->f.l;
StkId top; /* keep top local, for performance */
const Instruction *pc = tf->code;
const lua_Hook linehook = L->linehook;
L->ci->pc = &pc;
const Instruction *pc;
lua_Hook linehook;
if (tf->is_vararg) /* varargs? */
adjust_varargs(L, base, tf->numparams);
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 */
for (;;) {
const Instruction i = *pc++;
lua_assert(L->top == base+tf->maxstacksize);
if (linehook)
traceexec(L, linehook);
switch (GET_OPCODE(i)) {
case OP_RETURN: {
L->top = top;
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;
case OP_MOVE: {
setobj(RA(i), RB(i));
break;
}
case OP_PUSHNIL: {
int n = GETARG_U(i);
lua_assert(n>0);
case OP_LOADK: {
setobj(RA(i), KBc(i));
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 {
setnilvalue(top++);
} while (--n > 0);
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));
setnilvalue(ra++);
} while (ra <= rb);
break;
}
case OP_GETGLOBAL: {
luaV_getglobal(L, tf->kstr[GETARG_U(i)], top);
top++;
lua_assert(ttype(KBc(i)) == LUA_TSTRING);
luaV_getglobal(L, tsvalue(KBc(i)), RA(i));
break;
}
case OP_GETTABLE: {
top--;
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);
luaV_gettable(L, RB(i), RKC(i), RA(i));
break;
}
case OP_SETGLOBAL: {
top--;
luaV_setglobal(L, tf->kstr[GETARG_U(i)], top);
lua_assert(ttype(KBc(i)) == LUA_TSTRING);
luaV_setglobal(L, tsvalue(KBc(i)), RA(i));
break;
}
case OP_SETTABLE: {
StkId t = top-GETARG_A(i);
luaV_settable(L, t, t+1, top-1);
top -= GETARG_B(i); /* pop values */
luaV_settable(L, RB(i), RKC(i), RA(i));
break;
}
case OP_SETLIST: {
int aux = GETARG_A(i) * LFIELDS_PER_FLUSH;
TObject *t = base+GETARG_B(i);
Hash *h = hvalue(t);
int n;
for (n = top-t-1; n; n--)
setobj(luaH_setnum(L, h, n+aux), --top);
case OP_NEWTABLE: {
luaC_checkGC(L);
sethvalue(RA(i), luaH_new(L, GETARG_Bc(i)));
break;
}
case OP_SETMAP: {
TObject *t = base+GETARG_U(i);
Hash *h = hvalue(t);
while (top-1 > t) {
top-=2;
setobj(luaH_set(L, h, top), top+1);
}
case OP_SELF: {
StkId ra = RA(i);
StkId rb = RB(i);
setobj(ra+1, rb);
luaV_gettable(L, rb, RKC(i), ra);
break;
}
case OP_ADD: {
if (tonumber(top-2) || tonumber(top-1))
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);
Arith( + , TM_ADD);
break;
}
case OP_SUB: {
if (tonumber(top-2) || tonumber(top-1))
call_arith(L, top-2, TM_SUB);
else
nvalue(top-2) -= nvalue(top-1);
top--;
Arith( - , TM_SUB);
break;
}
case OP_MULT: {
if (tonumber(top-2) || tonumber(top-1))
call_arith(L, top-2, TM_MUL);
else
nvalue(top-2) *= nvalue(top-1);
top--;
case OP_MUL: {
Arith( * , TM_MUL);
break;
}
case OP_DIV: {
if (tonumber(top-2) || tonumber(top-1))
call_arith(L, top-2, TM_DIV);
else
nvalue(top-2) /= nvalue(top-1);
top--;
Arith( / , TM_DIV);
break;
}
case OP_POW: {
if (!call_binTM(L, top-2, top-1, top-2, TM_POW))
luaD_error(L, l_s("undefined operation"));
top--;
call_arith(L, RB(i), RKC(i), RA(i), TM_POW);
break;
}
case OP_CONCAT: {
int n = GETARG_U(i);
luaV_strconc(L, n, top);
top -= n-1;
luaC_checkGC(L);
break;
}
case OP_MINUS: {
if (tonumber(top-1)) {
setnilvalue(top);
call_arith(L, top-1, TM_UNM);
case OP_UNM: {
const TObject *rb = RB(i);
StkId ra = RA(i);
if (ttype(rb) == LUA_TNUMBER || (rb=luaV_tonumber(rb, ra)) != NULL) {
setnvalue(ra, -nvalue(rb));
}
else {
TObject temp;
setnilvalue(&temp);
call_arith(L, RB(i), &temp, ra, TM_UNM);
}
else
nvalue(top-1) = -nvalue(top-1);
break;
}
case OP_NOT: {
ttype(top-1) =
(ttype(top-1) == LUA_TNIL) ? LUA_TNUMBER : LUA_TNIL;
nvalue(top-1) = 1;
if (ttype(RB(i)) == LUA_TNIL) {
setnvalue(RA(i), 1);
} else {
setnilvalue(RA(i));
}
break;
}
case OP_JMPNE: {
top -= 2;
if (!luaO_equalObj(top, top+1)) dojump(pc, i);
break;
}
case OP_JMPEQ: {
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);
case OP_CONCAT: {
StkId top = RC(i)+1;
StkId rb = RB(i);
luaV_strconc(L, top-rb, top);
setobj(RA(i), rb);
luaC_checkGC(L);
break;
}
case OP_CJMP:
case OP_JMP: {
dojump(pc, i);
break;
}
case OP_PUSHNILJMP: {
setnilvalue(top++);
case OP_TESTEQ: {
lua_assert(GET_OPCODE(*pc) == OP_CJMP);
if (luaO_equalObj(RB(i), RKC(i))) dojump(pc, *pc);
pc++;
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: {
int jmp = GETARG_S(i);
if (tonumber(top-1))
luaD_error(L, l_s("`for' step must be a number"));
if (tonumber(top-2))
luaD_error(L, l_s("`for' limit must be a number"));
if (tonumber(top-3))
int jmp = GETARG_sBc(i);
StkId breg = RA(i);
if (luaV_tonumber(breg, breg) == NULL)
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) */
goto forloop; /* do not increment index */
nvalue(breg) -= nvalue(breg+2);/* decrement index (to be incremented) */
/* go through */
}
case OP_FORLOOP: {
lua_assert(ttype(top-1) == LUA_TNUMBER);
lua_assert(ttype(top-2) == LUA_TNUMBER);
if (ttype(top-3) != LUA_TNUMBER)
StkId breg = RA(i);
if (ttype(breg) != LUA_TNUMBER)
luaD_error(L, l_s("`for' index must be a number"));
nvalue(top-3) += nvalue(top-1); /* increment index */
forloop:
if (nvalue(top-1) > 0 ?
nvalue(top-3) > nvalue(top-2) :
nvalue(top-3) < nvalue(top-2))
top -= 3; /* end loop: remove control variables */
else
runtime_check(L, ttype(breg+1) == LUA_TNUMBER &&
ttype(breg+2) == LUA_TNUMBER);
nvalue(breg) += nvalue(breg+2); /* increment index */
if (nvalue(breg+2) > 0 ?
nvalue(breg) <= nvalue(breg+1) :
nvalue(breg) >= nvalue(breg+1))
dojump(pc, i); /* repeat loop */
break;
}
case OP_LFORPREP: {
int jmp = GETARG_S(i);
if (ttype(top-1) != LUA_TTABLE)
case OP_TFORPREP: {
int jmp = GETARG_sBc(i);
StkId breg = RA(i);
if (ttype(breg) != LUA_TTABLE)
luaD_error(L, l_s("`for' table must be a table"));
top += 3; /* index,key,value */
setnvalue(top-3, -1); /* initial index */
setnilvalue(top-2);
setnilvalue(top-1);
setnvalue(breg+1, -1); /* initial index */
setnilvalue(breg+2);
setnilvalue(breg+3);
pc += -jmp; /* `jump' to loop end (delta is negated here) */
/* go through */
}
case OP_LFORLOOP: {
Hash *t = hvalue(top-4);
int n = (int)nvalue(top-3);
lua_assert(ttype(top-3) == LUA_TNUMBER);
lua_assert(ttype(top-4) == LUA_TTABLE);
case OP_TFORLOOP: {
StkId breg = RA(i);
Hash *t;
int n;
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);
if (n == -1) /* end loop? */
top -= 4; /* remove table, index, key, and value */
else {
if (n != -1) { /* repeat loop? */
Node *node = node(t, n);
setnvalue(top-3, n); /* index */
setkey2obj(top-2, node);
setobj(top-1, val(node));
setnvalue(breg+1, n); /* index */
setkey2obj(breg+2, node);
setobj(breg+3, val(node));
dojump(pc, i); /* repeat loop */
}
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: {
int nup = GETARG_B(i);
luaC_checkGC(L);
L->top = top;
luaV_Lclosure(L, tf->kproto[GETARG_A(i)], nup);
top -= (nup-1);
Proto *p = tf->kproto[GETARG_Bc(i)];
int nup = p->nupvalues;
StkId ra = RA(i);
L->top = ra+nup;
luaV_Lclosure(L, p, nup);
L->top = base+tf->maxstacksize;
luaC_checkGC(L);
break;
}
}
}
}