commit 762d059a13d83eb367238a6115bbb4f5f13fcb49
parent 572a69b6afbd368beab8844bc876b0f9690b5253
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Tue, 5 Jun 2001 15:16:39 -0300
new implementation for the Virtual Machine
Diffstat:
M | lapi.c | | | 18 | ++++++++++++------ |
M | lcode.c | | | 1045 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
M | lcode.h | | | 49 | +++++++++++++++++++++---------------------------- |
M | ldebug.c | | | 360 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
M | ldebug.h | | | 27 | ++++++++++++++++++++++++--- |
M | lfunc.c | | | 11 | ++++------- |
M | lgc.c | | | 8 | +++++--- |
M | llimits.h | | | 89 | +++++-------------------------------------------------------------------------- |
M | lobject.h | | | 8 | +++----- |
M | lopcodes.h | | | 219 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
M | lparser.c | | | 558 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
M | lparser.h | | | 32 | +++++++++++++++++++------------- |
M | ltests.c | | | 133 | +++++++++++++++++++++++++++++++++---------------------------------------------- |
M | lvm.c | | | 476 | ++++++++++++++++++++++++++++++++++++++----------------------------------------- |
M | lvm.h | | | 7 | +++---- |
15 files changed, 1599 insertions(+), 1441 deletions(-)
diff --git a/lapi.c b/lapi.c
@@ -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
** 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) {
TObject *o;
int i;
+ TObject n;
lua_lock(L);
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);
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) {
- StkId o;
- lua_Number n;
+ const TObject *o;
+ TObject n;
+ lua_Number res;
lua_lock(L);
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);
- return n;
+ return res;
}
LUA_API const l_char *lua_tostring (lua_State *L, int index) {
diff --git a/lcode.c b/lcode.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.c,v 1.67 2001/04/06 18:25:00 roberto Exp roberto $
+** $Id: lcode.c,v 1.68 2001/04/23 16:35:45 roberto Exp roberto $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -11,6 +11,7 @@
#include "lua.h"
#include "lcode.h"
+#include "ldebug.h"
#include "ldo.h"
#include "llex.h"
#include "lmem.h"
@@ -19,6 +20,12 @@
#include "lparser.h"
+#define hasjumps(e) ((e)->t != (e)->f)
+
+#define getcode(fs,e) ((fs)->f->code[(e)->u.i.info])
+
+
+
void luaK_error (LexState *ls, const l_char *msg) {
luaX_error(ls, msg, ls->t.token);
}
@@ -33,12 +40,27 @@ static Instruction previous_instruction (FuncState *fs) {
if (fs->pc > fs->lasttarget) /* no jumps to current position? */
return fs->f->code[fs->pc-1]; /* returns previous instruction */
else
- return CREATE_0(-1); /* no optimizations after an invalid instruction */
+ return (Instruction)(-1);/* no optimizations after an invalid instruction */
+}
+
+
+void luaK_nil (FuncState *fs, int from, int n) {
+ Instruction previous = previous_instruction(fs);
+ if (GET_OPCODE(previous) == OP_LOADNIL) {
+ int pfrom = GETARG_A(previous);
+ int pto = GETARG_B(previous);
+ if (pfrom <= from && from <= pto+1) { /* can connect both? */
+ if (from+n-1 > pto)
+ SETARG_B(fs->f->code[fs->pc-1], from+n-1);
+ return;
+ }
+ }
+ luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */
}
int luaK_jump (FuncState *fs) {
- int j = luaK_code1(fs, OP_JMP, NO_JUMP);
+ int j = luaK_codeAsBc(fs, OP_JMP, 0, NO_JUMP);
if (j == fs->lasttarget) { /* possible jumps to this jump? */
luaK_concat(fs, &j, fs->jlt); /* keep them on hold */
fs->jlt = NO_JUMP;
@@ -47,36 +69,33 @@ int luaK_jump (FuncState *fs) {
}
+static int luaK_condjump (FuncState *fs, OpCode op, int B, int C) {
+ luaK_codeABC(fs, op, NO_REG, B, C);
+ return luaK_codeAsBc(fs, OP_CJMP, 0, NO_JUMP);
+}
+
+
static void luaK_fixjump (FuncState *fs, int pc, int dest) {
Instruction *jmp = &fs->f->code[pc];
if (dest == NO_JUMP)
- SETARG_S(*jmp, NO_JUMP); /* point to itself to represent end of list */
+ SETARG_sBc(*jmp, NO_JUMP); /* point to itself to represent end of list */
else { /* jump is relative to position following jump instruction */
int offset = dest-(pc+1);
- if (abs(offset) > MAXARG_S)
+ if (abs(offset) > MAXARG_sBc)
luaK_error(fs->ls, l_s("control structure too long"));
- SETARG_S(*jmp, offset);
+ SETARG_sBc(*jmp, offset);
}
}
/*
-** prep-for instructions (OP_FORPREP & OP_LFORPREP) have a negated jump,
+** prep-for instructions (OP_FORPREP & OP_TFORPREP) have a negated jump,
** as they simulate the real jump...
*/
void luaK_fixfor (FuncState *fs, int pc, int dest) {
Instruction *jmp = &fs->f->code[pc];
int offset = dest-(pc+1);
- SETARG_S(*jmp, -offset);
-}
-
-
-static int luaK_getjump (FuncState *fs, int pc) {
- int offset = GETARG_S(fs->f->code[pc]);
- if (offset == NO_JUMP) /* point to itself represents end of list */
- return NO_JUMP; /* end of list */
- else
- return (pc+1)+offset; /* turn offset into absolute position */
+ SETARG_sBc(*jmp, -offset);
}
@@ -96,609 +115,677 @@ int luaK_getlabel (FuncState *fs) {
}
-void luaK_deltastack (FuncState *fs, int delta) {
- fs->stacklevel += delta;
- if (fs->stacklevel > fs->f->maxstacksize) {
- if (fs->stacklevel > MAXSTACK)
- luaK_error(fs->ls, l_s("function or expression too complex"));
- fs->f->maxstacksize = (short)fs->stacklevel;
- }
+static int luaK_getjump (FuncState *fs, int pc) {
+ int offset = GETARG_sBc(fs->f->code[pc]);
+ if (offset == NO_JUMP) /* point to itself represents end of list */
+ return NO_JUMP; /* end of list */
+ else
+ return (pc+1)+offset; /* turn offset into absolute position */
}
-void luaK_kstr (LexState *ls, int c) {
- luaK_code1(ls->fs, OP_PUSHSTRING, c);
+static Instruction *getjumpcontrol (FuncState *fs, int pc) {
+ Instruction *pi = &fs->f->code[pc];
+ OpCode op = GET_OPCODE(*pi);
+ if (op == OP_CJMP)
+ return pi-1;
+ else {
+ lua_assert(op == OP_JMP || op == OP_FORLOOP || op == OP_TFORLOOP);
+ return pi;
+ }
}
-static int number_constant (FuncState *fs, lua_Number r) {
- /* check whether `r' has appeared within the last LOOKBACKNUMS entries */
- Proto *f = fs->f;
- int c = fs->nknum;
- int lim = c < LOOKBACKNUMS ? 0 : c-LOOKBACKNUMS;
- while (--c >= lim)
- if (f->knum[c] == r) return c;
- /* not found; create a new entry */
- luaM_growvector(fs->L, f->knum, fs->nknum, f->sizeknum, lua_Number,
- MAXARG_U, l_s("constant table overflow"));
- c = fs->nknum++;
- f->knum[c] = r;
- return c;
+static int need_value (FuncState *fs, int list, OpCode op) {
+ /* check whether list has any jump different from `op' */
+ for (; list != NO_JUMP; list = luaK_getjump(fs, list))
+ if (GET_OPCODE(*getjumpcontrol(fs, list)) != op) return 1;
+ return 0; /* not found */
}
-void luaK_number (FuncState *fs, lua_Number f) {
- if (f <= (lua_Number)MAXARG_S && (lua_Number)(int)f == f)
- luaK_code1(fs, OP_PUSHINT, (int)f); /* f has a short integer value */
- else
- luaK_code1(fs, OP_PUSHNUM, number_constant(fs, f));
+static void luaK_patchlistaux (FuncState *fs, int list,
+ int ttarget, int treg, int ftarget, int freg, int dtarget) {
+ while (list != NO_JUMP) {
+ int next = luaK_getjump(fs, list);
+ Instruction *i = getjumpcontrol(fs, list);
+ switch (GET_OPCODE(*i)) {
+ case OP_TESTT: {
+ SETARG_A(*i, treg);
+ luaK_fixjump(fs, list, ttarget);
+ break;
+ }
+ case OP_TESTF: {
+ SETARG_A(*i, freg);
+ luaK_fixjump(fs, list, ftarget);
+ break;
+ }
+ default: {
+ luaK_fixjump(fs, list, dtarget); /* jump to default target */
+ break;
+ }
+ }
+ list = next;
+ }
}
-void luaK_adjuststack (FuncState *fs, int n) {
- if (n > 0)
- luaK_code1(fs, OP_POP, n);
+void luaK_patchlist (FuncState *fs, int list, int target) {
+ if (target == fs->lasttarget) /* same target that list `jlt'? */
+ luaK_concat(fs, &fs->jlt, list); /* delay fixing */
else
- luaK_code1(fs, OP_PUSHNIL, -n);
+ luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target);
}
-int luaK_lastisopen (FuncState *fs) {
- /* check whether last instruction is an open function call */
- Instruction i = previous_instruction(fs);
- if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET)
- return 1;
- else return 0;
+void luaK_concat (FuncState *fs, int *l1, int l2) {
+ if (*l1 == NO_JUMP)
+ *l1 = l2;
+ else {
+ int list = *l1;
+ int next;
+ while ((next = luaK_getjump(fs, list)) != NO_JUMP) /* find last element */
+ list = next;
+ luaK_fixjump(fs, list, l2);
+ }
}
-void luaK_setcallreturns (FuncState *fs, int nresults) {
- if (luaK_lastisopen(fs)) { /* expression is an open function call? */
- SETARG_B(fs->f->code[fs->pc-1], nresults); /* set number of results */
- luaK_deltastack(fs, nresults); /* push results */
+void luaK_reserveregs (FuncState *fs, int n) {
+ fs->freereg += n;
+ if (fs->freereg > fs->f->maxstacksize) {
+ if (fs->freereg >= MAXSTACK)
+ luaK_error(fs->ls, l_s("function or expression too complex"));
+ fs->f->maxstacksize = (short)fs->freereg;
}
}
-static int discharge (FuncState *fs, expdesc *var) {
- switch (var->k) {
- case VLOCAL:
- luaK_code1(fs, OP_GETLOCAL, var->u.index);
- break;
- case VGLOBAL:
- luaK_code1(fs, OP_GETGLOBAL, var->u.index);
- break;
- case VINDEXED:
- luaK_code0(fs, OP_GETTABLE);
- break;
- case VEXP:
- return 0; /* nothing to do */
+static void freereg (FuncState *fs, int reg) {
+ if (reg >= fs->nactloc && reg < MAXSTACK) {
+ fs->freereg--;
+ lua_assert(reg == fs->freereg);
}
- var->k = VEXP;
- var->u.l.t = var->u.l.f = NO_JUMP;
- return 1;
}
-static void discharge1 (FuncState *fs, expdesc *var) {
- discharge(fs, var);
- /* if it has jumps then it is already discharged */
- if (var->u.l.t == NO_JUMP && var->u.l.f == NO_JUMP)
- luaK_setcallreturns(fs, 1); /* call must return 1 value */
+static void freeexp (FuncState *fs, expdesc *e) {
+ if (e->k == VNONRELOC)
+ freereg(fs, e->u.i.info);
}
-void luaK_storevar (LexState *ls, const expdesc *var) {
- FuncState *fs = ls->fs;
- switch (var->k) {
- case VLOCAL:
- luaK_code1(fs, OP_SETLOCAL, var->u.index);
- break;
- case VGLOBAL:
- luaK_code1(fs, OP_SETGLOBAL, var->u.index);
- break;
- case VINDEXED: /* table is at top-3; pop 3 elements after operation */
- luaK_code2(fs, OP_SETTABLE, 3, 3);
- break;
- default:
- lua_assert(0); /* invalid var kind to store */
+static int addk (FuncState *fs, TObject *k) {
+ Proto *f = fs->f;
+ luaM_growvector(fs->L, f->k, fs->nk, f->sizek, TObject,
+ MAXARG_Bc, l_s("constant table overflow"));
+ setobj(&f->k[fs->nk], k);
+ return fs->nk++;
+}
+
+
+int luaK_stringk (FuncState *fs, TString *s) {
+ Proto *f = fs->f;
+ int c = s->u.s.constindex;
+ if (c >= fs->nk || ttype(&f->k[c]) != LUA_TSTRING || tsvalue(&f->k[c]) != s) {
+ TObject o;
+ setsvalue(&o, s);
+ c = addk(fs, &o);
+ s->u.s.constindex = c; /* hint for next time */
}
+ return c;
}
-static OpCode invertjump (OpCode op) {
- switch (op) {
- case OP_JMPNE: return OP_JMPEQ;
- case OP_JMPEQ: return OP_JMPNE;
- case OP_JMPLT: return OP_JMPGE;
- case OP_JMPLE: return OP_JMPGT;
- case OP_JMPGT: return OP_JMPLE;
- case OP_JMPGE: return OP_JMPLT;
- case OP_JMPT: case OP_JMPONT: return OP_JMPF;
- case OP_JMPF: case OP_JMPONF: return OP_JMPT;
- default:
- lua_assert(0); /* invalid jump instruction */
- return OP_JMP; /* to avoid warnings */
+static int number_constant (FuncState *fs, lua_Number r) {
+ /* check whether `r' has appeared within the last LOOKBACKNUMS entries */
+ TObject o;
+ Proto *f = fs->f;
+ int c = fs->nk;
+ int lim = c < LOOKBACKNUMS ? 0 : c-LOOKBACKNUMS;
+ while (--c >= lim) {
+ if (ttype(&f->k[c]) == LUA_TNUMBER && nvalue(&f->k[c]) == r)
+ return c;
}
+ /* not found; create a new entry */
+ setnvalue(&o, r);
+ return addk(fs, &o);
}
-static void luaK_patchlistaux (FuncState *fs, int list, int target,
- OpCode special, int special_target) {
- Instruction *code = fs->f->code;
- while (list != NO_JUMP) {
- int next = luaK_getjump(fs, list);
- Instruction *i = &code[list];
- OpCode op = GET_OPCODE(*i);
- if (op == special) /* this `op' already has a value */
- luaK_fixjump(fs, list, special_target);
- else {
- luaK_fixjump(fs, list, target); /* do the patch */
- if (op == OP_JMPONT) /* remove eventual values */
- SET_OPCODE(*i, OP_JMPT);
- else if (op == OP_JMPONF)
- SET_OPCODE(*i, OP_JMPF);
+void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) {
+ if (e->k == VCALL) { /* expression is an open function call? */
+ SETARG_C(getcode(fs, e), nresults); /* set number of results */
+ if (nresults == 1) { /* `regular' expression? */
+ e->k = VNONRELOC;
+ e->u.i.info = GETARG_A(getcode(fs, e));
}
- list = next;
}
}
-void luaK_patchlist (FuncState *fs, int list, int target) {
- if (target == fs->lasttarget) /* same target that list `jlt'? */
- luaK_concat(fs, &fs->jlt, list); /* delay fixing */
- else
- luaK_patchlistaux(fs, list, target, OP_ADD, 0);
+static void dischargevars (FuncState *fs, expdesc *e) {
+ switch (e->k) {
+ case VLOCAL: {
+ e->k = VNONRELOC;
+ break;
+ }
+ case VGLOBAL: {
+ e->u.i.info = luaK_codeABc(fs, OP_GETGLOBAL, 0, e->u.i.info);
+ e->k = VRELOCABLE;
+ break;
+ }
+ case VINDEXED: {
+ freereg(fs, e->u.i.aux);
+ freereg(fs, e->u.i.info);
+ e->u.i.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.i.info, e->u.i.aux);
+ e->k = VRELOCABLE;
+ break;
+ }
+ case VCALL: {
+ luaK_setcallreturns(fs, e, 1);
+ break;
+ }
+ default: break; /* there is one value available (somewhere) */
+ }
}
-static int need_value (FuncState *fs, int list, OpCode hasvalue) {
- /* check whether list has a jump without a value */
- for (; list != NO_JUMP; list = luaK_getjump(fs, list))
- if (GET_OPCODE(fs->f->code[list]) != hasvalue) return 1;
- return 0; /* not found */
+static int code_label (FuncState *fs, OpCode op, int A, int sBc) {
+ luaK_getlabel(fs); /* those instructions may be jump targets */
+ return luaK_codeAsBc(fs, op, A, sBc);
}
-void luaK_concat (FuncState *fs, int *l1, int l2) {
- if (*l1 == NO_JUMP)
- *l1 = l2;
- else {
- int list = *l1;
- int next;
- while ((next = luaK_getjump(fs, list)) != NO_JUMP) /* find last element */
- list = next;
- luaK_fixjump(fs, list, l2);
+static void dischargejumps (FuncState *fs, expdesc *e, int reg) {
+ if (hasjumps(e)) {
+ int final; /* position after whole expression */
+ int p_nil = NO_JUMP; /* position of an eventual PUSHNIL */
+ int p_1 = NO_JUMP; /* position of an eventual PUSHINT */
+ if (need_value(fs, e->f, OP_TESTF) || need_value(fs, e->t, OP_TESTT)) {
+ /* expression needs values */
+ if (e->k != VJMP)
+ code_label(fs, OP_JMP, 0, 2); /* to jump over both pushes */
+ p_nil = code_label(fs, OP_NILJMP, reg, 0);
+ p_1 = code_label(fs, OP_LOADINT, reg, 1);
+ }
+ final = luaK_getlabel(fs);
+ luaK_patchlistaux(fs, e->f, p_nil, NO_REG, final, reg, p_nil);
+ luaK_patchlistaux(fs, e->t, final, reg, p_1, NO_REG, p_1);
}
+ e->f = e->t = NO_JUMP;
}
-static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) {
- int prevpos; /* position of last instruction */
- Instruction *previous;
- int *golist, *exitlist;
- if (!invert) {
- golist = &v->u.l.f; /* go if false */
- exitlist = &v->u.l.t; /* exit if true */
- }
- else {
- golist = &v->u.l.t; /* go if true */
- exitlist = &v->u.l.f; /* exit if false */
+static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
+ dischargevars(fs, e);
+ switch (e->k) {
+ case VNIL: {
+ luaK_nil(fs, reg, 1);
+ break;
+ }
+ case VNUMBER: {
+ lua_Number f = e->u.n;
+ int i = (int)f;
+ if ((lua_Number)i == f && -MAXARG_sBc <= i && i <= MAXARG_sBc)
+ luaK_codeAsBc(fs, OP_LOADINT, reg, i); /* f has a small int value */
+ else
+ luaK_codeABc(fs, OP_LOADK, reg, number_constant(fs, f));
+ break;
+ }
+ case VK: {
+ luaK_codeABc(fs, OP_LOADK, reg, e->u.i.info);
+ break;
+ }
+ case VRELOCABLE: {
+ Instruction *pc = &getcode(fs, e);
+ SETARG_A(*pc, reg);
+ break;
+ }
+ default: return;
}
- discharge1(fs, v);
- prevpos = fs->pc-1;
- previous = &fs->f->code[prevpos];
- lua_assert(*previous==previous_instruction(fs)); /* no jump allowed here */
- if (!ISJUMP(GET_OPCODE(*previous)))
- prevpos = luaK_code1(fs, jump, NO_JUMP);
- else { /* last instruction is already a jump */
- if (invert)
- SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
+ e->u.i.info = reg;
+ e->k = VNONRELOC;
+}
+
+
+static void discharge2anyreg (FuncState *fs, expdesc *e) {
+ if (e->k != VNONRELOC) {
+ luaK_reserveregs(fs, 1);
+ discharge2reg(fs, e, fs->freereg-1);
}
- luaK_concat(fs, exitlist, prevpos); /* insert last jump in `exitlist' */
- luaK_patchlist(fs, *golist, luaK_getlabel(fs));
- *golist = NO_JUMP;
}
-void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue) {
- luaK_testgo(fs, v, 1, keepvalue ? OP_JMPONF : OP_JMPF);
+static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) {
+ discharge2reg(fs, e, reg);
+ switch (e->k) {
+ case VVOID: {
+ return; /* nothing to do... */
+ }
+ case VNONRELOC: {
+ if (reg != e->u.i.info)
+ luaK_codeABC(fs, OP_MOVE, reg, e->u.i.info, 0);
+ break;
+ }
+ case VJMP: {
+ luaK_concat(fs, &e->t, e->u.i.info); /* put this jump in `t' list */
+ break;
+ }
+ default: {
+ lua_assert(0); /* cannot happen */
+ break;
+ }
+ }
+ dischargejumps(fs, e, reg);
+ e->u.i.info = reg;
+ e->k = VNONRELOC;
}
-static void luaK_goiffalse (FuncState *fs, expdesc *v) {
- luaK_testgo(fs, v, 0, OP_JMPONT);
+void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
+ int reg;
+ dischargevars(fs, e);
+ freeexp(fs, e);
+ reg = fs->freereg;
+ luaK_reserveregs(fs, 1);
+ luaK_exp2reg(fs, e, reg);
}
-static int code_label (FuncState *fs, OpCode op, int arg) {
- luaK_getlabel(fs); /* those instructions may be jump targets */
- return luaK_code1(fs, op, arg);
-}
-
-
-void luaK_tostack (LexState *ls, expdesc *v, int onlyone) {
- FuncState *fs = ls->fs;
- if (!discharge(fs, v)) { /* `v' is an expression? */
- OpCode previous = GET_OPCODE(fs->f->code[fs->pc-1]);
- if (!ISJUMP(previous) && v->u.l.f == NO_JUMP && v->u.l.t == NO_JUMP) {
- /* expression has no jumps */
- if (onlyone)
- luaK_setcallreturns(fs, 1); /* call must return 1 value */
- }
- else { /* expression has jumps */
- int final; /* position after whole expression */
- int j = NO_JUMP; /* eventual jump over values */
- int p_nil = NO_JUMP; /* position of an eventual PUSHNIL */
- int p_1 = NO_JUMP; /* position of an eventual PUSHINT */
- if (ISJUMP(previous) || need_value(fs, v->u.l.f, OP_JMPONF)
- || need_value(fs, v->u.l.t, OP_JMPONT)) {
- /* expression needs values */
- if (ISJUMP(previous))
- luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in t. list */
- else {
- j = code_label(fs, OP_JMP, NO_JUMP); /* to jump over both pushes */
- /* correct stack for compiler and symbolic execution */
- luaK_adjuststack(fs, 1);
- }
- p_nil = code_label(fs, OP_PUSHNILJMP, 0);
- p_1 = code_label(fs, OP_PUSHINT, 1);
- luaK_patchlist(fs, j, luaK_getlabel(fs));
- }
- final = luaK_getlabel(fs);
- luaK_patchlistaux(fs, v->u.l.f, p_nil, OP_JMPONF, final);
- luaK_patchlistaux(fs, v->u.l.t, p_1, OP_JMPONT, final);
- v->u.l.f = v->u.l.t = NO_JUMP;
+int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
+ dischargevars(fs, e);
+ if (e->k == VNONRELOC) {
+ if (!hasjumps(e)) return e->u.i.info; /* exp is already in a register */
+ if (e->u.i.info >= fs->nactloc) { /* reg. is not a local? */
+ dischargejumps(fs, e, e->u.i.info); /* put value on it */
+ return e->u.i.info;
}
}
+ luaK_exp2nextreg(fs, e); /* default */
+ return e->u.i.info;
}
-void luaK_prefix (LexState *ls, UnOpr op, expdesc *v) {
- FuncState *fs = ls->fs;
- if (op == OPR_MINUS) {
- luaK_tostack(ls, v, 1);
- luaK_code0(fs, OP_MINUS);
- }
- else { /* op == NOT */
- Instruction *previous;
- discharge1(fs, v);
- previous = &fs->f->code[fs->pc-1];
- if (ISJUMP(GET_OPCODE(*previous)))
- SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
- else
- luaK_code0(fs, OP_NOT);
- /* interchange true and false lists */
- { int temp = v->u.l.f; v->u.l.f = v->u.l.t; v->u.l.t = temp; }
- }
+void luaK_exp2val (FuncState *fs, expdesc *e) {
+ if (hasjumps(e))
+ luaK_exp2anyreg(fs, e);
+ else
+ dischargevars(fs, e);
}
-void luaK_infix (LexState *ls, BinOpr op, expdesc *v) {
- FuncState *fs = ls->fs;
- switch (op) {
- case OPR_AND:
- luaK_goiftrue(fs, v, 1);
- break;
- case OPR_OR:
- luaK_goiffalse(fs, v);
- break;
- default:
- luaK_tostack(ls, v, 1); /* all other binary operators need a value */
+int luaK_exp2RK (FuncState *fs, expdesc *e) {
+ luaK_exp2val(fs, e);
+ if (e->k == VNUMBER && fs->nk + MAXSTACK <= MAXARG_C) {
+ e->u.i.info = number_constant(fs, e->u.n);
+ e->k = VK;
}
+ else if (!(e->k == VK && e->u.i.info + MAXSTACK <= MAXARG_C))
+ luaK_exp2anyreg(fs, e); /* not a constant in the right range */
+ return (e->k == VK) ? e->u.i.info+MAXSTACK : e->u.i.info;
}
-
-static const struct {
- OpCode opcode; /* opcode for each binary operator */
- int arg; /* default argument for the opcode */
-} codes[] = { /* ORDER OPR */
- {OP_ADD, 0}, {OP_SUB, 0}, {OP_MULT, 0}, {OP_DIV, 0},
- {OP_POW, 0}, {OP_CONCAT, 2},
- {OP_JMPNE, NO_JUMP}, {OP_JMPEQ, NO_JUMP},
- {OP_JMPLT, NO_JUMP}, {OP_JMPLE, NO_JUMP},
- {OP_JMPGT, NO_JUMP}, {OP_JMPGE, NO_JUMP}
-};
-
-
-void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2) {
- FuncState *fs = ls->fs;
- switch (op) {
- case OPR_AND: {
- lua_assert(v1->u.l.t == NO_JUMP); /* list must be closed */
- discharge1(fs, v2);
- v1->u.l.t = v2->u.l.t;
- luaK_concat(fs, &v1->u.l.f, v2->u.l.f);
+void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) {
+ switch (var->k) {
+ case VLOCAL: {
+ freeexp(fs, exp);
+ luaK_exp2reg(fs, exp, var->u.i.info);
break;
}
- case OPR_OR: {
- lua_assert(v1->u.l.f == NO_JUMP); /* list must be closed */
- discharge1(fs, v2);
- v1->u.l.f = v2->u.l.f;
- luaK_concat(fs, &v1->u.l.t, v2->u.l.t);
+ case VGLOBAL: {
+ int e = luaK_exp2anyreg(fs, exp);
+ freereg(fs, e);
+ luaK_codeABc(fs, OP_SETGLOBAL, e, var->u.i.info);
+ break;
+ }
+ case VINDEXED: {
+ int e = luaK_exp2anyreg(fs, exp);
+ freereg(fs, e);
+ luaK_codeABC(fs, OP_SETTABLE, e, var->u.i.info, var->u.i.aux);
break;
}
default: {
- luaK_tostack(ls, v2, 1); /* `v2' must be a value */
- luaK_code1(fs, codes[op].opcode, codes[op].arg);
+ lua_assert(0); /* invalid var kind to store */
+ break;
}
}
}
-static void codelineinfo (FuncState *fs) {
- Proto *f = fs->f;
- LexState *ls = fs->ls;
- if (ls->lastline > fs->lastline) {
- if (ls->lastline > fs->lastline+1) {
- luaM_growvector(fs->L, f->lineinfo, fs->nlineinfo, f->sizelineinfo, int,
- MAX_INT, l_s("line info overflow"));
- f->lineinfo[fs->nlineinfo++] = -(ls->lastline - (fs->lastline+1));
- }
- luaM_growvector(fs->L, f->lineinfo, fs->nlineinfo, f->sizelineinfo, int,
- MAX_INT, l_s("line info overflow"));
- f->lineinfo[fs->nlineinfo++] = fs->pc;
- fs->lastline = ls->lastline;
+void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
+ luaK_exp2anyreg(fs, e);
+ freeexp(fs, e);
+ luaK_reserveregs(fs, 2);
+ luaK_codeABC(fs, OP_SELF, fs->freereg-2, e->u.i.info, luaK_exp2RK(fs, key));
+ e->u.i.info = fs->freereg-2;
+ e->k = VNONRELOC;
+}
+
+
+static OpCode invertoperator (OpCode op) {
+ switch (op) {
+ case OP_TESTNE: return OP_TESTEQ;
+ case OP_TESTEQ: return OP_TESTNE;
+ case OP_TESTLT: return OP_TESTGE;
+ case OP_TESTLE: return OP_TESTGT;
+ case OP_TESTGT: return OP_TESTLE;
+ case OP_TESTGE: return OP_TESTLT;
+ case OP_TESTT: return OP_TESTF;
+ case OP_TESTF: return OP_TESTT;
+ default: lua_assert(0); return op; /* invalid jump instruction */
}
}
-int luaK_code0 (FuncState *fs, OpCode o) {
- return luaK_code2(fs, o, 0, 0);
+static void invertjump (FuncState *fs, expdesc *e) {
+ Instruction *pc = getjumpcontrol(fs, e->u.i.info);
+ *pc = SET_OPCODE(*pc, invertoperator(GET_OPCODE(*pc)));
}
-int luaK_code1 (FuncState *fs, OpCode o, int arg1) {
- return luaK_code2(fs, o, arg1, 0);
+static int jumponcond (FuncState *fs, expdesc *e, OpCode op) {
+ if (e->k == VRELOCABLE) {
+ Instruction ie = getcode(fs, e);
+ if (GET_OPCODE(ie) == OP_NOT) {
+ op = invertoperator(op);
+ fs->pc--; /* remove previous OP_NOT */
+ return luaK_condjump(fs, op, GETARG_B(ie), 0);
+ }
+ /* else go through */
+ }
+ discharge2anyreg(fs, e);
+ freeexp(fs, e);
+ return luaK_condjump(fs, op, e->u.i.info, 0);
}
-int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
- Proto *f;
- Instruction i = previous_instruction(fs);
- int push = (int)luaK_opproperties[o].push;
- int pop = (int)luaK_opproperties[o].pop;
- int optm = 0; /* 1 when there is an optimization */
- switch (o) {
- case OP_CLOSURE: {
- pop = arg2;
+void luaK_goiftrue (FuncState *fs, expdesc *e) {
+ int pc; /* pc of last jump */
+ dischargevars(fs, e);
+ switch (e->k) {
+ case VK: case VNUMBER: {
+ pc = NO_JUMP; /* always true; do nothing */
break;
}
- case OP_SETTABLE: {
- pop = arg2;
+ case VNIL: {
+ pc = luaK_codeAsBc(fs, OP_JMP, 0, NO_JUMP); /* always jump */
break;
}
- case OP_SETLIST: {
- pop = fs->stacklevel - 1 - arg2;
+ case VJMP: {
+ invertjump(fs, e);
+ pc = e->u.i.info;
break;
}
- case OP_SETMAP: {
- pop = fs->stacklevel - 1 - arg1;
+ case VRELOCABLE:
+ case VNONRELOC: {
+ pc = jumponcond(fs, e, OP_TESTF);
break;
}
- case OP_PUSHNIL: {
- if (arg1 == 0) return NO_JUMP; /* nothing to do */
- push = arg1;
- switch(GET_OPCODE(i)) {
- case OP_PUSHNIL: SETARG_U(i, GETARG_U(i)+arg1); optm = 1; break;
- default: break;
- }
+ default: {
+ pc = 0; /* to avoid warnings */
+ lua_assert(0); /* cannot happen */
break;
}
- case OP_POP: {
- if (arg1 == 0) return NO_JUMP; /* nothing to do */
- pop = arg1;
- switch(GET_OPCODE(i)) {
- case OP_SETTABLE: SETARG_B(i, GETARG_B(i)+arg1); optm = 1; break;
- default: break;
- }
+ }
+ luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
+ luaK_patchlist(fs, e->t, luaK_getlabel(fs));
+ e->t = NO_JUMP;
+}
+
+
+static void luaK_goiffalse (FuncState *fs, expdesc *e) {
+ int pc; /* pc of last jump */
+ dischargevars(fs, e);
+ switch (e->k) {
+ case VNIL: {
+ pc = NO_JUMP; /* always false; do nothing */
break;
}
- case OP_GETTABLE: {
- switch(GET_OPCODE(i)) {
- case OP_PUSHSTRING: /* `t.x' */
- SET_OPCODE(i, OP_GETDOTTED);
- optm = 1;
- break;
- case OP_GETLOCAL: /* `t[i]' */
- SET_OPCODE(i, OP_GETINDEXED);
- optm = 1;
- break;
- default: break;
- }
+ case VJMP: {
+ pc = e->u.i.info;
break;
}
- case OP_ADD: {
- switch(GET_OPCODE(i)) {
- case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); optm = 1; break; /* `a+k' */
- default: break;
- }
+ case VK: case VNUMBER: /* cannot optimize it (`or' must keep value) */
+ case VRELOCABLE:
+ case VNONRELOC: {
+ pc = jumponcond(fs, e, OP_TESTT);
break;
}
- case OP_SUB: {
- switch(GET_OPCODE(i)) {
- case OP_PUSHINT: /* `a-k' */
- i = CREATE_S(OP_ADDI, -GETARG_S(i));
- optm = 1;
- break;
- default: break;
- }
+ default: {
+ pc = 0; /* to avoid warnings */
+ lua_assert(0); /* cannot happen */
break;
}
- case OP_CONCAT: {
- pop = arg1;
- switch(GET_OPCODE(i)) {
- case OP_CONCAT: /* `a..b..c' */
- SETARG_U(i, GETARG_U(i)+1);
- optm = 1;
- break;
- default: break;
- }
+ }
+ luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */
+ luaK_patchlist(fs, e->f, luaK_getlabel(fs));
+ e->f = NO_JUMP;
+}
+
+
+static void codenot (FuncState *fs, expdesc *e) {
+ dischargevars(fs, e);
+ switch (e->k) {
+ case VNIL: {
+ e->u.n = 1;
+ e->k = VNUMBER;
break;
}
- case OP_MINUS: {
- switch(GET_OPCODE(i)) {
- case OP_PUSHINT: /* `-k' */
- SETARG_S(i, -GETARG_S(i));
- optm = 1;
- break;
- case OP_PUSHNUM: /* `-k' */
- SET_OPCODE(i, OP_PUSHNEGNUM);
- optm = 1;
- break;
- default: break;
- }
+ case VK: case VNUMBER: {
+ e->k = VNIL;
break;
}
- case OP_JMPNE: {
- if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a~=nil' */
- i = CREATE_S(OP_JMPT, NO_JUMP);
- optm = 1;
- }
+ case VJMP: {
+ invertjump(fs, e);
break;
}
- case OP_JMPEQ: {
- if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a==nil' */
- i = CREATE_0(OP_NOT);
- pop = 1; /* just undo effect of previous PUSHNIL */
- optm = 1;
- }
+ case VRELOCABLE:
+ case VNONRELOC: {
+ discharge2anyreg(fs, e);
+ freeexp(fs, e);
+ e->u.i.info = luaK_codeABC(fs, OP_NOT, 0, e->u.i.info, 0);
+ e->k = VRELOCABLE;
break;
}
- case OP_JMPT:
- case OP_JMPONT: {
- switch (GET_OPCODE(i)) {
- case OP_NOT: {
- i = CREATE_S(OP_JMPF, NO_JUMP);
- optm = 1;
- break;
- }
- case OP_PUSHINT: {
- if (o == OP_JMPT) { /* JMPONT must keep original integer value */
- i = CREATE_S(OP_JMP, NO_JUMP);
- optm = 1;
- }
- break;
- }
- case OP_PUSHNIL: {
- if (GETARG_U(i) == 1) {
- fs->pc--; /* erase previous instruction */
- luaK_deltastack(fs, -1); /* correct stack */
- return NO_JUMP;
- }
- break;
- }
- default: break;
- }
+ default: {
+ lua_assert(0); /* cannot happen */
break;
}
- case OP_JMPF:
- case OP_JMPONF: {
- switch (GET_OPCODE(i)) {
- case OP_NOT: {
- i = CREATE_S(OP_JMPT, NO_JUMP);
- optm = 1;
- break;
- }
- case OP_PUSHINT: { /* `while 1 do ...' */
- fs->pc--; /* erase previous instruction */
- luaK_deltastack(fs, -1); /* correct stack */
- return NO_JUMP;
- }
- case OP_PUSHNIL: { /* `repeat ... until nil' */
- if (GETARG_U(i) == 1) {
- i = CREATE_S(OP_JMP, NO_JUMP);
- optm = 1;
- }
- break;
- }
- default: break;
- }
+ }
+ /* interchange true and false lists */
+ { int temp = e->f; e->f = e->t; e->t = temp; }
+}
+
+
+void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
+ t->u.i.aux = luaK_exp2RK(fs, k);
+ t->k = VINDEXED;
+}
+
+
+void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
+ if (op == OPR_MINUS) {
+ luaK_exp2val(fs, e);
+ if (e->k == VNUMBER)
+ e->u.n = -e->u.n;
+ else {
+ luaK_exp2anyreg(fs, e);
+ freeexp(fs, e);
+ e->u.i.info = luaK_codeABC(fs, OP_UNM, 0, e->u.i.info, 0);
+ e->k = VRELOCABLE;
+ }
+ }
+ else /* op == NOT */
+ codenot(fs, e);
+}
+
+
+void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
+ switch (op) {
+ case OPR_AND: {
+ luaK_goiftrue(fs, v);
+ break;
+ }
+ case OPR_OR: {
+ luaK_goiffalse(fs, v);
+ break;
+ }
+ case OPR_CONCAT: {
+ luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */
break;
}
- case OP_GETDOTTED:
- case OP_GETINDEXED:
- case OP_ADDI: {
- lua_assert(0); /* instruction used only for optimizations */
+ case OPR_SUB: case OPR_DIV: case OPR_POW: {
+ /* non-comutative operators */
+ luaK_exp2anyreg(fs, v); /* first operand must be a register */
break;
}
default: {
+ luaK_exp2RK(fs, v);
break;
}
}
- f = fs->f;
- lua_assert(push != VD);
- lua_assert(pop != VD);
- luaK_deltastack(fs, push);
- luaK_deltastack(fs, -pop);
- if (optm) { /* optimize: put instruction in place of last one */
- f->code[fs->pc-1] = i; /* change previous instruction */
- return fs->pc-1; /* do not generate new instruction */
+}
+
+
+
+/* opcode for each binary operator */
+static const OpCode codes[] = { /* ORDER OPR */
+ OP_ADD, OP_SUB, OP_MUL, OP_DIV,
+ OP_POW, OP_CONCAT,
+ OP_TESTNE, OP_TESTEQ,
+ OP_TESTLT, OP_TESTLE, OP_TESTGT, OP_TESTGE
+};
+
+
+/* `inverted' opcode for each binary operator */
+/* ( -1 means operator has no inverse) */
+static const OpCode invcodes[] = { /* ORDER OPR */
+ OP_ADD, (OpCode)-1, OP_MUL, (OpCode)-1,
+ (OpCode)-1, (OpCode)-1,
+ OP_TESTNE, OP_TESTEQ,
+ OP_TESTGT, OP_TESTGE, OP_TESTLT, OP_TESTLE
+};
+
+
+void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
+ switch (op) {
+ case OPR_AND: {
+ lua_assert(e1->t == NO_JUMP); /* list must be closed */
+ dischargevars(fs, e2);
+ luaK_concat(fs, &e1->f, e2->f);
+ e1->k = e2->k; e1->u = e2->u; e1->t = e2->t;
+ break;
+ }
+ case OPR_OR: {
+ lua_assert(e1->f == NO_JUMP); /* list must be closed */
+ dischargevars(fs, e2);
+ luaK_concat(fs, &e1->t, e2->t);
+ e1->k = e2->k; e1->u = e2->u; e1->f = e2->f;
+ break;
+ }
+ case OPR_CONCAT: {
+ luaK_exp2val(fs, e2);
+ if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
+ lua_assert(e1->u.i.info == GETARG_B(getcode(fs, e2))-1);
+ freeexp(fs, e1);
+ SETARG_B(getcode(fs, e2), e1->u.i.info);
+ e1->k = e2->k; e1->u.i.info = e2->u.i.info;
+ }
+ else {
+ luaK_exp2nextreg(fs, e2);
+ freeexp(fs, e2);
+ freeexp(fs, e1);
+ e1->u.i.info = luaK_codeABC(fs, codes[op], 0, e1->u.i.info,
+ e2->u.i.info);
+ e1->k = VRELOCABLE;
+ }
+ break;
+ }
+ case OPR_EQ: case OPR_NE: {
+ luaK_exp2val(fs, e2);
+ if (e2->k == VNIL) { /* exp x= nil ? */
+ if (e1->k == VK) { /* constant x= nil ? */
+ if (op == OPR_EQ) /* constant == nil ? */
+ e1->k = VNIL; /* always false */
+ /* else always true (leave the constant itself) */
+ }
+ else {
+ OpCode opc = (op == OPR_EQ) ? OP_TESTF : OP_TESTT;
+ e1->u.i.info = jumponcond(fs, e1, opc);
+ e1->k = VJMP;
+ }
+ break;
+ }
+ /* else go through */
+ }
+ default: {
+ int o1, o2;
+ OpCode opc;
+ if (e1->k != VK) { /* not a constant operator? */
+ o1 = e1->u.i.info;
+ o2 = luaK_exp2RK(fs, e2); /* maybe other operator is constant... */
+ opc = codes[op];
+ }
+ else { /* invert operands */
+ o2 = luaK_exp2RK(fs, e1); /* constant must be 2nd operand */
+ o1 = luaK_exp2anyreg(fs, e2); /* other operator must be in register */
+ opc = invcodes[op]; /* use inverted operator */
+ }
+ freeexp(fs, e2);
+ freeexp(fs, e1);
+ if (op < OPR_NE) { /* ORDER OPR */
+ e1->u.i.info = luaK_codeABC(fs, opc, 0, o1, o2);
+ e1->k = VRELOCABLE;
+ }
+ else { /* jump */
+ e1->u.i.info = luaK_condjump(fs, opc, o1, o2);
+ e1->k = VJMP;
+ }
+ }
}
- /* else build new instruction */
- switch ((enum Mode)luaK_opproperties[o].mode) {
- case iO: i = CREATE_0(o); break;
- case iU: i = CREATE_U(o, arg1); break;
- case iS: i = CREATE_S(o, arg1); break;
- case iAB: i = CREATE_AB(o, arg1, arg2); break;
+}
+
+
+static void codelineinfo (FuncState *fs) {
+ Proto *f = fs->f;
+ LexState *ls = fs->ls;
+ if (ls->lastline > fs->lastline) {
+ if (ls->lastline > fs->lastline+1) {
+ luaM_growvector(fs->L, f->lineinfo, fs->nlineinfo, f->sizelineinfo, int,
+ MAX_INT, l_s("line info overflow"));
+ f->lineinfo[fs->nlineinfo++] = -(ls->lastline - (fs->lastline+1));
+ }
+ luaM_growvector(fs->L, f->lineinfo, fs->nlineinfo, f->sizelineinfo, int,
+ MAX_INT, l_s("line info overflow"));
+ f->lineinfo[fs->nlineinfo++] = fs->pc;
+ fs->lastline = ls->lastline;
}
+}
+
+
+static int luaK_code (FuncState *fs, Instruction i) {
+ Proto *f;
codelineinfo(fs);
+ f = fs->f;
/* put new instruction in code array */
luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
MAX_INT, l_s("code size overflow"));
f->code[fs->pc] = i;
+/*printf("free: %d ", fs->freereg); printopcode(f, fs->pc);*/
return fs->pc++;
}
-const OpProperties luaK_opproperties[] = {
- {iU, 0, 0}, /* OP_RETURN */
- {iAB, 0, 0}, /* OP_CALL */
- {iU, VD, 0}, /* OP_PUSHNIL */
- {iU, 0, VD}, /* OP_POP */
- {iS, 1, 0}, /* OP_PUSHINT */
- {iU, 1, 0}, /* OP_PUSHSTRING */
- {iU, 1, 0}, /* OP_PUSHNUM */
- {iU, 1, 0}, /* OP_PUSHNEGNUM */
- {iU, 1, 0}, /* OP_PUSHUPVALUE */
- {iU, 1, 0}, /* OP_GETLOCAL */
- {iU, 1, 0}, /* OP_GETGLOBAL */
- {iO, 1, 2}, /* OP_GETTABLE */
- {iU, 1, 1}, /* OP_GETDOTTED */
- {iU, 1, 1}, /* OP_GETINDEXED */
- {iU, 2, 1}, /* OP_PUSHSELF */
- {iU, 1, 0}, /* OP_CREATETABLE */
- {iU, 0, 1}, /* OP_SETLOCAL */
- {iU, 0, 1}, /* OP_SETGLOBAL */
- {iAB, 0, VD}, /* OP_SETTABLE */
- {iAB, 0, VD}, /* OP_SETLIST */
- {iU, 0, VD}, /* OP_SETMAP */
- {iO, 1, 2}, /* OP_ADD */
- {iS, 1, 1}, /* OP_ADDI */
- {iO, 1, 2}, /* OP_SUB */
- {iO, 1, 2}, /* OP_MULT */
- {iO, 1, 2}, /* OP_DIV */
- {iO, 1, 2}, /* OP_POW */
- {iU, 1, VD}, /* OP_CONCAT */
- {iO, 1, 1}, /* OP_MINUS */
- {iO, 1, 1}, /* OP_NOT */
- {iS, 0, 2}, /* OP_JMPNE */
- {iS, 0, 2}, /* OP_JMPEQ */
- {iS, 0, 2}, /* OP_JMPLT */
- {iS, 0, 2}, /* OP_JMPLE */
- {iS, 0, 2}, /* OP_JMPGT */
- {iS, 0, 2}, /* OP_JMPGE */
- {iS, 0, 1}, /* OP_JMPT */
- {iS, 0, 1}, /* OP_JMPF */
- {iS, 0, 1}, /* OP_JMPONT */
- {iS, 0, 1}, /* OP_JMPONF */
- {iS, 0, 0}, /* OP_JMP */
- {iO, 0, 0}, /* OP_PUSHNILJMP */
- {iS, 0, 0}, /* OP_FORPREP */
- {iS, 0, 3}, /* OP_FORLOOP */
- {iS, 3, 0}, /* OP_LFORPREP */
- {iS, 0, 4}, /* OP_LFORLOOP */
- {iAB, 1, VD} /* OP_CLOSURE */
-};
+int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
+ lua_assert(getOpMode(o) == iABC);
+ return luaK_code(fs, CREATE_ABC(o, a, b, c));
+}
+
+
+int luaK_codeABc (FuncState *fs, OpCode o, int a, int bc) {
+ lua_assert(getOpMode(o) == iABc || getOpMode(o) == iAsBc);
+ return luaK_code(fs, CREATE_ABc(o, a, bc));
+}
diff --git a/lcode.h b/lcode.h
@@ -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
** See Copyright Notice in lua.h
*/
@@ -31,43 +31,36 @@ typedef enum BinOpr {
OPR_NOBINOPR
} BinOpr;
-typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr;
-
-
-enum Mode {iO, iU, iS, iAB}; /* instruction format */
+#define binopistest(op) ((op) >= OPR_NE)
-#define VD 100 /* flag for variable delta */
-
-typedef struct OpProperties {
- lu_byte mode;
- lu_byte push;
- lu_byte pop;
-} OpProperties;
+typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr;
-extern const OpProperties luaK_opproperties[];
+#define luaK_codeAsBc(fs,o,A,sBc) luaK_codeABc(fs,o,A,(sBc)+MAXARG_sBc)
void luaK_error (LexState *ls, const l_char *msg);
-int luaK_code0 (FuncState *fs, OpCode o);
-int luaK_code1 (FuncState *fs, OpCode o, int arg1);
-int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2);
+int luaK_codeABc (FuncState *fs, OpCode o, int A, int Bc);
+int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
+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);
void luaK_patchlist (FuncState *fs, int list, int target);
void luaK_fixfor (FuncState *fs, int pc, int dest);
void luaK_concat (FuncState *fs, int *l1, int l2);
-void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue);
int luaK_getlabel (FuncState *fs);
-void luaK_deltastack (FuncState *fs, int delta);
-void luaK_kstr (LexState *ls, int c);
-void luaK_number (FuncState *fs, lua_Number f);
-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);
+void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v);
+void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
+void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2);
#endif
diff --git a/ldebug.c b/ldebug.c
@@ -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
** See Copyright Notice in lua.h
*/
@@ -22,6 +22,7 @@
#include "ltable.h"
#include "ltm.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 checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode)
+
+#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize)
+
static int checklineinfo (const Proto *pt) {
int *lineinfo = pt->lineinfo;
@@ -318,231 +323,199 @@ static int precheck (const Proto *pt) {
}
-/* value for non-initialized entries in array stacklevel */
-#define SL_EMPTY 255
-
-#define checkjump(pt,sl,top,pc) if (!checkjump_aux(pt,sl,top,pc)) return 0;
-
-static int checkjump_aux (const Proto *pt, lu_byte *sl, int top, int pc) {
- check(0 <= pc && pc < pt->sizecode);
- if (sl == NULL) return 1; /* not full checking */
- if (sl[pc] == SL_EMPTY)
- sl[pc] = (lu_byte)top;
- else
- check(sl[pc] == top);
- return 1;
+static int checkopenop (Instruction i) {
+ OpCode op = GET_OPCODE(i);
+ switch (op) {
+ case OP_CALL:
+ case OP_RETURN: {
+ check(GETARG_B(i) == NO_REG);
+ return 1;
+ }
+ case OP_SETLISTO: return 1;
+ default: return 0; /* invalid instruction after an open call */
+ }
}
-static Instruction luaG_symbexec (lua_State *L, const Proto *pt,
- int lastpc, int stackpos) {
- int stack[MAXSTACK]; /* stores last instruction that changed a stack entry */
- lu_byte *sl = NULL;
- int top;
+static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
int pc;
- if (stackpos < 0) { /* full check? */
- int i;
- sl = luaO_openspace(L, pt->sizecode, lu_byte);
- for (i=0; i<pt->sizecode; i++) /* initialize stack-level array */
- sl[i] = SL_EMPTY;
+ int last; /* stores position of last instruction that changed `reg' */
+ last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */
+ if (reg == NO_REG) /* full check? */
check(precheck(pt));
- }
- top = pt->numparams;
- 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++];
+ for (pc = 0; pc < lastpc; pc++) {
+ const Instruction i = pt->code[pc];
OpCode op = GET_OPCODE(i);
- int arg1 = 0;
- int arg2 = 0;
- int push, pop;
- check(op < NUM_OPCODES);
- push = (int)luaK_opproperties[op].push;
- pop = (int)luaK_opproperties[op].pop;
- switch ((enum Mode)luaK_opproperties[op].mode) {
- case iO: break;
- case iU: arg1 = GETARG_U(i); check(arg1 >= 0); break;
- case iS: arg1 = GETARG_S(i); break;
- case iAB:
- arg1 = GETARG_A(i); arg2 = GETARG_B(i); check(arg1 >= 0); break;
- }
- switch (op) {
- case OP_RETURN: {
- check(arg1 <= top);
- pop = top-arg1;
+ int a = GETARG_A(i);
+ int b = 0;
+ int c = 0;
+#undef check
+#define check(x) if (!(x)) { \
+printf(">>>%d %d %d %d %d %d\n", op, a, b, c, pt->maxstacksize, pt->sizek); \
+return 0; }
+ switch (getOpMode(op)) {
+ case iABC: {
+ b = GETARG_B(i);
+ c = GETARG_C(i);
+ if (testOpMode(op, OpModeBreg)) {
+ checkreg(pt, b);
+ check(c < pt->maxstacksize ||
+ (c >= MAXSTACK && c-MAXSTACK < pt->sizek));
+ }
break;
}
- case OP_CALL: {
- if (arg2 == MULT_RET) arg2 = 1;
- check(arg1 < top);
- pop = top-arg1;
- push = arg2;
+ case iABc: {
+ b = GETARG_Bc(i);
+ if (testOpMode(op, OpModeK)) check(b < pt->sizek);
break;
}
- case OP_PUSHNIL: {
- check(arg1 > 0);
- push = arg1;
+ case iAsBc: {
+ b = GETARG_sBc(i);
break;
}
- case OP_POP: {
- pop = arg1;
+ }
+ if (testOpMode(op, OpModeAreg)) checkreg(pt, a);
+ if (testOpMode(op, OpModesetA)) {
+ if (a == reg) last = pc; /* change register `a' */
+ }
+ 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_PUSHSTRING:
- case OP_GETGLOBAL:
- case OP_GETDOTTED:
- case OP_PUSHSELF:
- case OP_SETGLOBAL: {
- check(arg1 < pt->sizekstr);
+ case OP_LOADUPVAL: {
+ check(b < pt->nupvalues);
break;
}
- case OP_PUSHNUM:
- case OP_PUSHNEGNUM: {
- check(arg1 < pt->sizeknum);
+ case OP_GETGLOBAL:
+ case OP_SETGLOBAL: {
+ check(ttype(&pt->k[b]) == LUA_TSTRING);
break;
}
- case OP_PUSHUPVALUE: {
- check(arg1 < pt->nupvalues);
+ case OP_SELF: {
+ checkreg(pt, a+1);
+ if (reg == a+1) last = pc;
break;
}
- case OP_GETLOCAL:
- case OP_GETINDEXED:
- case OP_SETLOCAL: {
- check(arg1 < top);
+ case OP_CONCAT: {
+ check(b < c); /* at least two operands */
break;
}
- case OP_SETTABLE: {
- check(3 <= arg1 && arg1 <= top);
- pop = arg2;
+ 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_SETLIST: {
- check(arg2 >= 0);
- pop = top-arg2-1;
+ case OP_TESTT:
+ case OP_TESTF: {
+ if (a != NO_REG)
+ checkreg(pt, a);
break;
}
- case OP_SETMAP: {
- check(arg1 >= 0);
- pop = top-arg1-1;
+ case OP_NILJMP: {
+ check(pc+2 < pt->sizecode); /* check its jump */
break;
}
- case OP_CONCAT: {
- pop = arg1;
+ 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_CLOSURE: {
- check(arg1 < pt->sizekproto);
- check(arg2 == pt->kproto[arg1]->nupvalues);
- pop = arg2;
+ case OP_RETURN: {
+ if (b == NO_REG) b = pt->maxstacksize;
+ checkreg(pt, b-1);
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);
+ 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_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;
- }
- case OP_PUSHNILJMP: {
- check(GET_OPCODE(pt->code[pc]) == OP_PUSHINT); /* only valid sequence */
+ 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_FORPREP: {
- int endfor = pc-arg1-1; /* jump is `negative' here */
- 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);
+ case OP_SETLIST: {
+ checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1);
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: {
+ case OP_CLOSURE: {
+ check(b < pt->sizekproto);
+ checkreg(pt, a + pt->kproto[b]->nupvalues - 1);
break;
}
+ default: break;
}
- top -= pop;
- check(0 <= top && top+push <= pt->maxstacksize);
- while (push--) stack[top++] = pc-1;
- checkjump(pt, sl, top, pc);
}
- return (stackpos >= 0) ? pt->code[stack[stackpos]] : 1;
+ return pt->code[last];
}
/* }====================================================== */
-int luaG_checkcode (lua_State *L, const Proto *pt) {
- return luaG_symbexec(L, pt, pt->sizecode-1, -1);
+int luaG_checkcode (const Proto *pt) {
+ return luaG_symbexec(pt, pt->sizecode, NO_REG);
}
static const l_char *getobjname (lua_State *L, StkId obj, const l_char **name) {
CallInfo *ci = ci_stack(L, obj);
- if (!isLmark(ci))
- return NULL; /* not an active Lua function */
- else {
+ if (isLmark(ci)) { /* an active Lua function? */
Proto *p = ci_func(ci)->f.l;
int pc = currentpc(ci);
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);
switch (GET_OPCODE(i)) {
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");
}
- case OP_GETLOCAL: {
- *name = luaF_getlocalname(p, GETARG_U(i)+1, pc);
- lua_assert(*name);
- return l_s("local");
+ case OP_MOVE: {
+ int a = GETARG_A(i);
+ int b = GETARG_B(i); /* move from `b' to `a' */
+ if (b < a)
+ return getobjname(L, ci->base+b, name); /* get name for `b' */
+ break;
}
- case OP_PUSHSELF:
- case OP_GETDOTTED: {
- *name = getstr(p->kstr[GETARG_U(i)]);
- return l_s("field");
+ case OP_GETTABLE:
+ case OP_SELF: {
+ int c = GETARG_C(i) - MAXSTACK;
+ if (c >= 0 && ttype(&p->k[c]) == LUA_TSTRING) {
+ *name = getstr(tsvalue(&p->k[c]));
+ return l_s("field");
+ }
+ break;
}
- default:
- return NULL; /* no useful name found */
+ default: break;
}
}
+ 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) {
- if (ttype(p1) == t) p1++;
- lua_assert(ttype(p1) != t);
- luaG_typeerror(L, p1, op);
+void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
+ if (ttype(p1) == LUA_TSTRING) p1 = p2;
+ lua_assert(ttype(p1) != LUA_TSTRING);
+ 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);
}
+
+
+#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 */
+};
diff --git a/ldebug.h b/ldebug.h
@@ -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
** See Copyright Notice in lua.h
*/
@@ -12,11 +12,32 @@
#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_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);
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
diff --git a/lfunc.c b/lfunc.c
@@ -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
** 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 *f = luaM_new(L, Proto);
- f->knum = NULL;
- f->sizeknum = 0;
- f->kstr = NULL;
- f->sizekstr = 0;
+ f->k = NULL;
+ f->sizek = 0;
f->kproto = NULL;
f->sizekproto = 0;
f->code = NULL;
@@ -58,8 +56,7 @@ Proto *luaF_newproto (lua_State *L) {
void luaF_freeproto (lua_State *L, Proto *f) {
luaM_freearray(L, f->code, f->sizecode, Instruction);
luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
- luaM_freearray(L, f->kstr, f->sizekstr, TString *);
- luaM_freearray(L, f->knum, f->sizeknum, lua_Number);
+ luaM_freearray(L, f->k, f->sizek, TObject);
luaM_freearray(L, f->kproto, f->sizekproto, Proto *);
luaM_freearray(L, f->lineinfo, f->sizelineinfo, int);
luaM_freelem(L, f, Proto);
diff --git a/lgc.c b/lgc.c
@@ -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
** See Copyright Notice in lua.h
*/
@@ -48,8 +48,10 @@ static void protomark (Proto *f) {
int i;
f->marked = 1;
strmark(f->source);
- for (i=0; i<f->sizekstr; i++)
- strmark(f->kstr[i]);
+ for (i=0; i<f->sizek; i++) {
+ if (ttype(f->k+i) == LUA_TSTRING)
+ strmark(tsvalue(f->k+i));
+ }
for (i=0; i<f->sizekproto; i++)
protomark(f->kproto[i]);
for (i=0; i<f->sizelocvars; i++) /* mark local-variable names */
diff --git a/llimits.h b/llimits.h
@@ -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
** See Copyright Notice in lua.h
*/
@@ -89,92 +89,23 @@ union L_Umaxalign { double d; void *s; long l; };
/*
** type for virtual-machine instructions
** 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;
-/*
-** 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
+/* maximum stack for a Lua function */
#define MAXSTACK 250
-#endif
-
-#if MAXSTACK > MAXARG_B
-#undef MAXSTACK
-#define MAXSTACK MAXARG_B
-#endif
/* maximum number of local variables */
#ifndef MAXLOCALS
#define MAXLOCALS 200 /* arbitrary limit (<MAXSTACK) */
#endif
-#if MAXLOCALS>=MAXSTACK
-#undef MAXLOCALS
-#define MAXLOCALS (MAXSTACK-1)
-#endif
/* maximum number of upvalues */
#ifndef MAXUPVALUES
-#define MAXUPVALUES 32 /* arbitrary limit (<=MAXARG_B) */
-#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)
+#define MAXUPVALUES 32 /* arbitrary limit (<MAXSTACK) */
#endif
@@ -182,27 +113,17 @@ typedef unsigned long Instruction;
#ifndef MAXPARAMS
#define MAXPARAMS 100 /* arbitrary limit (<MAXLOCALS) */
#endif
-#if MAXPARAMS>=MAXLOCALS
-#undef MAXPARAMS
-#define MAXPARAMS (MAXLOCALS-1)
-#endif
/* number of list items to accumulate before a SETLIST instruction */
+/* (must be a power of 2) */
#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) */
#ifndef LOOKBACKNUMS
-#define LOOKBACKNUMS 20 /* arbitrary constant */
+#define LOOKBACKNUMS 40 /* arbitrary constant */
#endif
diff --git a/lobject.h b/lobject.h
@@ -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
** See Copyright Notice in lua.h
*/
@@ -114,10 +114,8 @@ union L_UTString {
** Function Prototypes
*/
typedef struct Proto {
- lua_Number *knum; /* numbers used by the function */
- int sizeknum; /* size of `knum' */
- struct TString **kstr; /* strings used by the function */
- int sizekstr; /* size of `kstr' */
+ TObject *k; /* constants used by the function */
+ int sizek; /* size of `k' */
struct Proto **kproto; /* functions defined inside the function */
int sizekproto; /* size of `kproto' */
Instruction *code;
diff --git a/lopcodes.h b/lopcodes.h
@@ -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
** See Copyright Notice in lua.h
*/
@@ -12,29 +12,55 @@
/*===========================================================================
We assume that instructions are unsigned numbers.
- All instructions have an opcode in the first 6 bits. Moreover,
- an instruction can have 0, 1, or 2 arguments. Instructions can
- have the following types:
- type 0: no arguments
- type 1: 1 unsigned argument in the higher bits (called `U')
- type 2: 1 signed argument in the higher bits (`S')
- type 3: 1st unsigned argument in the higher bits (`A')
- 2nd unsigned argument in the middle bits (`B')
+ All instructions have an opcode in the first 6 bits.
+ Instructions can have the following fields:
+ `A' : 8 bits (25-32)
+ `B' : 8 bits (17-24)
+ `C' : 10 bits (7-16)
+ `Bc' : 18 bits (`B' and `C' together)
+ `sBc' : signed Bc
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
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
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' */
@@ -47,120 +73,129 @@
** the following macros help to manipulate instructions
*/
-#define CREATE_0(o) ((Instruction)(o))
#define GET_OPCODE(i) ((OpCode)((i)&MASK1(SIZE_OP,0)))
-#define SET_OPCODE(i,o) ((i) = (((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 SET_OPCODE(i,o) (((i)&MASK0(SIZE_OP,0)) | (Instruction)(o))
-#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 SETARG_A(i,a) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
- ((Instruction)(a)<<POS_A)))
+#define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
+ ((Instruction)(u)<<POS_A)))
+
#define GETARG_B(i) ((int)(((i)>>POS_B) & MASK1(SIZE_B,0)))
#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_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'
-** J = S argument used as jump offset (relative to pc of next instruction)
-** L = unsigned argument used as index of local variable
-** N = U argument used as index to `knum'
+** an invalid register that fits in 8 bits
+*/
+#define NO_REG MAXARG_A
+
+
+/*
+** R(x) - register
+** Kst(x) - constant (in constant table)
+** R/K(x) == if x < MAXSTACK then R(x) else Kst(x-MAXSTACK)
*/
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_CALL,/* A B v_n-v_1 f(at a) r_b-r_1 f(v1,...,v_n) */
-
-OP_PUSHNIL,/* U - nil_1-nil_u */
-OP_POP,/* U a_u-a_1 - */
+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_PUSHINT,/* S - (lua_Number)s */
-OP_PUSHSTRING,/* K - KSTR[k] */
-OP_PUSHNUM,/* N - KNUM[n] */
-OP_PUSHNEGNUM,/* N - -KNUM[n] */
+OP_GETGLOBAL,/* A Bc R(A) := Gbl[Kst(Bc)] */
+OP_GETTABLE,/* A B C R(A) := R(B)[R/K(C)] */
-OP_PUSHUPVALUE,/* U - Closure[u] */
+OP_SETGLOBAL,/* A Bc Gbl[Kst(Bc)] := R(A) */
+OP_SETTABLE,/* A B C R(B)[R/K(C)] := R(A) */
-OP_GETLOCAL,/* L - LOC[l] */
-OP_GETGLOBAL,/* K - VAR[KSTR[k]] */
+OP_NEWTABLE,/* A Bc R(A) := {} (size = Bc) */
-OP_GETTABLE,/* - i t t[i] */
-OP_GETDOTTED,/* K t t[KSTR[k]] */
-OP_GETINDEXED,/* L t t[LOC[l]] */
-OP_PUSHSELF,/* K t t t[KSTR[k]] */
+OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[R/K(C)] */
-OP_CREATETABLE,/* U - newarray(size = u) */
+OP_ADD,/* A B C R(A) := R(B) + R/K(C) */
+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_SETLOCAL,/* L x - LOC[l]=x */
-OP_SETGLOBAL,/* K x - VAR[KSTR[k]]=x */
-OP_SETTABLE,/* A B v a_a-a_1 i t (pops b values) t[i]=v */
+OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
-OP_SETLIST,/* A B v_n-v_1 v_b v_b v_b[i+a*FPF]=v_i */
-OP_SETMAP,/* U v_n k_n - v_1 k_1 v_u v_u v_u[k_i]=v_i */
+OP_JMP,/* sBc PC += sBc */
+OP_CJMP,/* sBc if test then PC += sBc (see (1)) */
-OP_ADD,/* - y x x+y */
-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_TESTEQ,/* B C test := (R(B) == R/K(C)) */
+OP_TESTNE,/* B C test := (R(B) ~= R/K(C)) */
+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_JMPNE,/* J y x - (x~=y)? PC+=s */
-OP_JMPEQ,/* J y x - (x==y)? PC+=s */
-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_TESTT,/* A B test := R(B); if (test) R(A) := R(B) */
+OP_TESTF,/* A B test := not R(B); if (test) R(A) := nil */
-OP_JMPT,/* J x - (x~=nil)? PC+=s */
-OP_JMPF,/* J x - (x==nil)? PC+=s */
-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_NILJMP,/* A R(A) := nil; PC++; */
-OP_PUSHNILJMP,/* - - nil PC++; */
+OP_CALL,/* A B C R(A), ... ,R(A+C-1) := R(A)(R(A+1), ... ,R(B-1))*/
+OP_RETURN,/* A B return R(A), ... ,R(B-1) (see (3)) */
-OP_FORPREP,/* J */
-OP_FORLOOP,/* J */
+OP_FORPREP,/* A sBc */
+OP_FORLOOP,/* A sBc */
-OP_LFORPREP,/* J */
-OP_LFORLOOP,/* J */
+OP_TFORPREP,/* A sBc */
+OP_TFORLOOP,/* A sBc */
-OP_CLOSURE/* A B v_b-v_1 closure(KPROTO[a], v_1-v_b) */
+OP_SETLIST,/* A Bc R(A)[Bc-Bc%FPF+i] := R(A+i), 1 <= i <= Bc%FPF+1 */
+OP_SETLISTO,/* A Bc */
+OP_CLOSURE /* A Bc R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n)) */
} OpCode;
+
#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 */
-#define MULT_RET 255 /* (<=MAXARG_B) */
-#if MULT_RET>MAXARG_B
-#undef MULT_RET
-#define MULT_RET MAXARG_B
-#endif
+ (3) In OP_RETURN, if (B == NO_REG) then B = top.
+===========================================================================*/
#endif
diff --git a/lparser.c b/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 1.141 2001/04/05 16:49:14 roberto Exp roberto $
+** $Id: lparser.c,v 1.142 2001/04/06 18:25:00 roberto Exp roberto $
** LL(1) Parser and code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -35,10 +35,12 @@ typedef struct Constdesc {
} Constdesc;
+/*
+** nodes for break list (list of active breakable loops)
+*/
typedef struct Breaklabel {
struct Breaklabel *previous; /* chain */
- int breaklist;
- int stacklevel;
+ int breaklist; /* list of jumps out of this loop */
} Breaklabel;
@@ -47,11 +49,10 @@ typedef struct Breaklabel {
/*
** prototypes for recursive non-terminal functions
*/
-static void body (LexState *ls, int needself, int line);
+static void body (LexState *ls, expdesc *v, int needself, int line);
static void chunk (LexState *ls);
-static void constructor (LexState *ls);
+static void constructor (LexState *ls, expdesc *v);
static void expr (LexState *ls, expdesc *v);
-static void exp1 (LexState *ls);
@@ -119,25 +120,6 @@ static void check_match (LexState *ls, int what, int who, int where) {
}
-static int string_constant (FuncState *fs, TString *s) {
- Proto *f = fs->f;
- int c = s->u.s.constindex;
- if (c >= fs->nkstr || f->kstr[c] != s) {
- luaM_growvector(fs->L, f->kstr, fs->nkstr, f->sizekstr, TString *,
- MAXARG_U, l_s("constant table overflow"));
- c = fs->nkstr++;
- f->kstr[c] = s;
- s->u.s.constindex = c; /* hint for next time */
- }
- return c;
-}
-
-
-static void code_string (LexState *ls, TString *s) {
- luaK_kstr(ls, string_constant(ls->fs, s));
-}
-
-
static TString *str_checkname (LexState *ls) {
TString *ts;
check_condition(ls, (ls->t.token == TK_NAME), l_s("<name> expected"));
@@ -147,11 +129,21 @@ static TString *str_checkname (LexState *ls) {
}
-static int checkname (LexState *ls) {
- return string_constant(ls->fs, str_checkname(ls));
+static void init_exp (expdesc *e, expkind k, int i) {
+ e->f = e->t = NO_JUMP;
+ e->k = k;
+ e->u.i.info = i;
+}
+
+
+static void codestring (LexState *ls, expdesc *e, TString *s) {
+ init_exp(e, VK, luaK_stringk(ls->fs, s));
}
+#define checkname(ls,e) codestring(ls,e,str_checkname(ls))
+
+
static int luaI_registerlocalvar (LexState *ls, TString *varname) {
FuncState *fs = ls->fs;
Proto *f = fs->f;
@@ -195,14 +187,13 @@ static int search_local (LexState *ls, TString *n, expdesc *var) {
int i;
for (i=fs->nactloc-1; i >= 0; i--) {
if (n == fs->f->locvars[fs->actloc[i]].varname) {
- var->k = VLOCAL;
- var->u.index = i;
+ init_exp(var, VLOCAL, i);
return level;
}
}
level++; /* `var' not found; check outer level */
}
- var->k = VGLOBAL; /* not found in any level; must be global */
+ init_exp(var, VGLOBAL, 0); /* not found in any level; must be global */
return -1;
}
@@ -213,7 +204,7 @@ static void singlevar (LexState *ls, TString *n, expdesc *var) {
luaX_syntaxerror(ls, l_s("cannot access a variable in outer function"),
getstr(n));
else if (level == -1) /* global? */
- var->u.index = string_constant(ls->fs, n);
+ var->u.i.info = luaK_stringk(ls->fs, n);
}
@@ -221,7 +212,7 @@ static int indexupvalue (LexState *ls, expdesc *v) {
FuncState *fs = ls->fs;
int i;
for (i=0; i<fs->f->nupvalues; i++) {
- if (fs->upvalues[i].k == v->k && fs->upvalues[i].u.index == v->u.index)
+ if (fs->upvalues[i].k == v->k && fs->upvalues[i].u.i.info == v->u.i.info)
return i;
}
/* new one */
@@ -231,37 +222,43 @@ static int indexupvalue (LexState *ls, expdesc *v) {
}
-static void pushupvalue (LexState *ls, TString *n) {
+static void codeupvalue (LexState *ls, expdesc *v, TString *n) {
FuncState *fs = ls->fs;
- expdesc v;
- int level = search_local(ls, n, &v);
+ int level;
+ level = search_local(ls, n, v);
if (level == -1) { /* global? */
if (fs->prev == NULL)
- luaX_syntaxerror(ls, l_s("cannot access an upvalue at top level"), getstr(n));
- v.u.index = string_constant(fs->prev, n);
+ luaX_syntaxerror(ls, l_s("cannot access an upvalue at top level"),
+ getstr(n));
+ v->u.i.info = luaK_stringk(fs->prev, n);
}
else if (level != 1) {
luaX_syntaxerror(ls,
- l_s("upvalue must be global or local to immediately outer function"), getstr(n));
+ l_s("upvalue must be global or local to immediately outer function"),
+ getstr(n));
}
- luaK_code1(fs, OP_PUSHUPVALUE, indexupvalue(ls, &v));
+ init_exp(v, VRELOCABLE,
+ luaK_codeABc(fs, OP_LOADUPVAL, 0, indexupvalue(ls, v)));
}
-static void adjust_mult_assign (LexState *ls, int nvars, int nexps) {
+static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
FuncState *fs = ls->fs;
- int diff = nexps - nvars;
- if (nexps > 0 && luaK_lastisopen(fs)) { /* list ends in a function call */
- diff--; /* do not count function call itself */
- if (diff <= 0) { /* more variables than values? */
- luaK_setcallreturns(fs, -diff); /* function call provide extra values */
- diff = 0; /* no more difference */
+ int extra = nvars - nexps;
+ if (e->k == VCALL) {
+ extra++; /* includes call itself */
+ if (extra <= 0) extra = 0;
+ else luaK_reserveregs(fs, extra-1);
+ luaK_setcallreturns(fs, e, extra); /* call provides the difference */
+ }
+ else {
+ if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */
+ if (extra > 0) {
+ int reg = fs->freereg;
+ luaK_reserveregs(fs, extra);
+ luaK_nil(fs, reg, extra);
}
- else /* more values than variables */
- luaK_setcallreturns(fs, 0); /* call should provide no value */
}
- /* push or pop eventual difference between list lengths */
- luaK_adjuststack(fs, diff);
}
@@ -275,12 +272,11 @@ static void code_params (LexState *ls, int nparams, short dots) {
new_localvarstr(ls, l_s("arg"), 0);
adjustlocalvars(ls, 1);
}
- luaK_deltastack(fs, fs->nactloc); /* count parameters in the stack */
+ luaK_reserveregs(fs, fs->nactloc); /* reserve register for parameters */
}
static void enterbreak (FuncState *fs, Breaklabel *bl) {
- bl->stacklevel = fs->stacklevel;
bl->breaklist = NO_JUMP;
bl->previous = fs->bl;
fs->bl = bl;
@@ -289,21 +285,24 @@ static void enterbreak (FuncState *fs, Breaklabel *bl) {
static void leavebreak (FuncState *fs, Breaklabel *bl) {
fs->bl = bl->previous;
- lua_assert(bl->stacklevel == fs->stacklevel);
luaK_patchlist(fs, bl->breaklist, luaK_getlabel(fs));
}
-static void pushclosure (LexState *ls, FuncState *func) {
+static void pushclosure (LexState *ls, FuncState *func, expdesc *v) {
FuncState *fs = ls->fs;
Proto *f = fs->f;
int i;
+ int reg = fs->freereg;
for (i=0; i<func->f->nupvalues; i++)
- luaK_tostack(ls, &func->upvalues[i], 1);
+ luaK_exp2nextreg(fs, &func->upvalues[i]);
luaM_growvector(ls->L, f->kproto, fs->nkproto, f->sizekproto, Proto *,
- MAXARG_A, l_s("constant table overflow"));
+ MAXARG_Bc, l_s("constant table overflow"));
f->kproto[fs->nkproto++] = func->f;
- luaK_code2(fs, OP_CLOSURE, fs->nkproto-1, func->f->nupvalues);
+ fs->freereg = reg; /* CLOSURE will consume those values */
+ init_exp(v, VNONRELOC, reg);
+ luaK_reserveregs(fs, 1);
+ luaK_codeABc(fs, OP_CLOSURE, v->u.i.info, fs->nkproto-1);
}
@@ -317,10 +316,9 @@ static void open_func (LexState *ls, FuncState *fs) {
fs->pc = 0;
fs->lasttarget = 0;
fs->jlt = NO_JUMP;
- fs->stacklevel = 0;
- fs->nkstr = 0;
+ fs->freereg = 0;
+ fs->nk = 0;
fs->nkproto = 0;
- fs->nknum = 0;
fs->nlineinfo = 0;
fs->nlocvars = 0;
fs->nactloc = 0;
@@ -328,7 +326,7 @@ static void open_func (LexState *ls, FuncState *fs) {
fs->bl = NULL;
f->code = NULL;
f->source = ls->source;
- f->maxstacksize = 0;
+ f->maxstacksize = 1; /* register 0 is always valid */
f->numparams = 0; /* default for main chunk */
f->is_vararg = 0; /* default for main chunk */
}
@@ -338,15 +336,13 @@ static void close_func (LexState *ls) {
lua_State *L = ls->L;
FuncState *fs = ls->fs;
Proto *f = fs->f;
- luaK_code1(fs, OP_RETURN, ls->fs->nactloc); /* final return */
+ luaK_codeABC(fs, OP_RETURN, 0, 0, 0); /* final return */
luaK_getlabel(fs); /* close eventual list of pending jumps */
removelocalvars(ls, fs->nactloc);
luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
f->sizecode = fs->pc;
- luaM_reallocvector(L, f->kstr, f->sizekstr, fs->nkstr, TString *);
- f->sizekstr = fs->nkstr;
- luaM_reallocvector(L, f->knum, f->sizeknum, fs->nknum, lua_Number);
- f->sizeknum = fs->nknum;
+ luaM_reallocvector(L, f->k, f->sizek, fs->nk, TObject);
+ f->sizek = fs->nk;
luaM_reallocvector(L, f->kproto, f->sizekproto, fs->nkproto, Proto *);
f->sizekproto = fs->nkproto;
luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
@@ -354,9 +350,9 @@ static void close_func (LexState *ls) {
luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->nlineinfo+1, int);
f->lineinfo[fs->nlineinfo++] = MAX_INT; /* end flag */
f->sizelineinfo = fs->nlineinfo;
- lua_assert(luaG_checkcode(L, f));
- ls->fs = fs->prev;
+ lua_assert(luaG_checkcode(f));
lua_assert(fs->bl == NULL);
+ ls->fs = fs->prev;
}
@@ -367,7 +363,8 @@ Proto *luaY_parser (lua_State *L, ZIO *z) {
open_func(&lexstate, &funcstate);
next(&lexstate); /* read first token */
chunk(&lexstate);
- check_condition(&lexstate, (lexstate.t.token == TK_EOS), l_s("<eof> expected"));
+ check_condition(&lexstate, (lexstate.t.token == TK_EOS),
+ l_s("<eof> expected"));
close_func(&lexstate);
lua_assert(funcstate.prev == NULL);
lua_assert(funcstate.f->nupvalues == 0);
@@ -381,48 +378,64 @@ Proto *luaY_parser (lua_State *L, ZIO *z) {
/*============================================================*/
-static int explist1 (LexState *ls) {
+static void luaY_field (LexState *ls, expdesc *v) {
+ /* field -> ['.' | ':'] NAME */
+ FuncState *fs = ls->fs;
+ expdesc key;
+ luaK_exp2anyreg(fs, v);
+ next(ls); /* skip the dot or colon */
+ checkname(ls, &key);
+ luaK_indexed(fs, v, &key);
+}
+
+
+static void luaY_index (LexState *ls, expdesc *v) {
+ /* index -> '[' expr ']' */
+ next(ls); /* skip the '[' */
+ expr(ls, v);
+ luaK_exp2val(ls->fs, v);
+ check(ls, l_c(']'));
+}
+
+
+static int explist1 (LexState *ls, expdesc *v) {
/* explist1 -> expr { `,' expr } */
int n = 1; /* at least one expression */
- expdesc v;
- expr(ls, &v);
+ expr(ls, v);
while (ls->t.token == l_c(',')) {
next(ls); /* skip comma */
- luaK_tostack(ls, &v, 1); /* gets only 1 value from previous expression */
- expr(ls, &v);
+ luaK_exp2nextreg(ls->fs, v);
+ expr(ls, v);
n++;
}
- luaK_tostack(ls, &v, 0); /* keep open number of values of last expression */
return n;
}
-static void funcargs (LexState *ls, int slf) {
+static void funcargs (LexState *ls, expdesc *f) {
FuncState *fs = ls->fs;
- int slevel = fs->stacklevel - slf - 1; /* where is func in the stack */
+ expdesc args;
+ int base, top;
switch (ls->t.token) {
case l_c('('): { /* funcargs -> `(' [ explist1 ] `)' */
int line = ls->linenumber;
- int nargs = 0;
next(ls);
- if (ls->t.token != l_c(')')) /* arg list not empty? */
- nargs = explist1(ls);
+ if (ls->t.token == l_c(')')) /* arg list is empty? */
+ args.k = VVOID;
+ else {
+ explist1(ls, &args);
+ luaK_setcallreturns(fs, &args, NO_REG);
+ }
check_match(ls, l_c(')'), l_c('('), line);
-#ifdef LUA_COMPAT_ARGRET
- if (nargs > 0) /* arg list is not empty? */
- luaK_setcallreturns(fs, 1); /* last call returns only 1 value */
-#else
- UNUSED(nargs); /* to avoid warnings */
-#endif
break;
}
case l_c('{'): { /* funcargs -> constructor */
- constructor(ls);
+ constructor(ls, &args);
break;
}
case TK_STRING: { /* funcargs -> STRING */
- code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */
- next(ls);
+ codestring(ls, &args, ls->t.seminfo.ts);
+ next(ls); /* must use `seminfo' before `next' */
break;
}
default: {
@@ -430,11 +443,22 @@ static void funcargs (LexState *ls, int slf) {
break;
}
}
- fs->stacklevel = slevel; /* call will remove function and arguments */
- luaK_code2(fs, OP_CALL, slevel, MULT_RET);
+ lua_assert(f->k == VNONRELOC);
+ base = f->u.i.info; /* base register for call */
+ if (args.k == VCALL)
+ top = NO_REG; /* open call */
+ else {
+ if (args.k != VVOID)
+ luaK_exp2nextreg(fs, &args); /* close last argument */
+ top = fs->freereg;
+ }
+ init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, top, 1));
+ fs->freereg = base+1; /* call remove function and arguments and leaves
+ (unless changed) one result */
}
+
/*
** {======================================================================
** Rules for Constructors
@@ -442,69 +466,82 @@ static void funcargs (LexState *ls, int slf) {
*/
-static void recfield (LexState *ls) {
+static void recfield (LexState *ls, expdesc *t) {
/* recfield -> (NAME | `['exp1`]') = exp1 */
+ FuncState *fs = ls->fs;
+ int reg = ls->fs->freereg;
+ expdesc key, val;
switch (ls->t.token) {
case TK_NAME: {
- luaK_kstr(ls, checkname(ls));
+ checkname(ls, &key);
break;
}
case l_c('['): {
- next(ls);
- exp1(ls);
- check(ls, l_c(']'));
+ luaY_index(ls, &key);
break;
}
default: luaK_error(ls, l_s("<name> or `[' expected"));
}
check(ls, l_c('='));
- exp1(ls);
+ luaK_exp2RK(fs, &key);
+ expr(ls, &val);
+ luaK_exp2anyreg(fs, &val);
+ luaK_codeABC(fs, OP_SETTABLE, val.u.i.info, t->u.i.info,
+ luaK_exp2RK(fs, &key));
+ fs->freereg = reg; /* free registers */
}
-static int recfields (LexState *ls) {
+static int recfields (LexState *ls, expdesc *t) {
/* recfields -> recfield { `,' recfield } [`,'] */
- FuncState *fs = ls->fs;
- int t = fs->stacklevel-1; /* level of table on the stack */
int n = 1; /* at least one element */
- recfield(ls);
- while (ls->t.token == l_c(',') &&
- (next(ls), (ls->t.token != l_c(';') && ls->t.token != l_c('}')))) {
- if (n%RFIELDS_PER_FLUSH == 0)
- luaK_code1(fs, OP_SETMAP, t);
- recfield(ls);
+ luaK_exp2nextreg(ls->fs, t);
+ recfield(ls, t);
+ while (ls->t.token == l_c(',')) {
+ next(ls);
+ if (ls->t.token == l_c(';') || ls->t.token == l_c('}')) break;
+ recfield(ls, t);
n++;
}
- luaK_code1(fs, OP_SETMAP, t);
return n;
}
-static int listfields (LexState *ls) {
+static int listfields (LexState *ls, expdesc *t) {
/* listfields -> exp1 { `,' exp1 } [`,'] */
expdesc v;
FuncState *fs = ls->fs;
- int t = fs->stacklevel-1; /* level of table on the stack */
int n = 1; /* at least one element */
+ int reg;
+ luaK_exp2nextreg(ls->fs, t);
+ reg = fs->freereg;
expr(ls, &v);
while (ls->t.token == l_c(',') &&
(next(ls), (ls->t.token != l_c(';') && ls->t.token != l_c('}')))) {
- luaK_tostack(ls, &v, 1); /* only one value from intermediate expressions */
- luaX_checklimit(ls, n/LFIELDS_PER_FLUSH, MAXARG_A,
- l_s("`item groups' in a list initializer"));
- if (n%LFIELDS_PER_FLUSH == 0)
- luaK_code2(fs, OP_SETLIST, (n-1)/LFIELDS_PER_FLUSH, t);
+ luaK_exp2nextreg(fs, &v);
+ luaX_checklimit(ls, n, MAXARG_Bc,
+ l_s("`item groups' in a list initializer"));
+ if (n%LFIELDS_PER_FLUSH == 0) {
+ luaK_codeABc(fs, OP_SETLIST, t->u.i.info, n-1);
+ fs->freereg = reg; /* free registers */
+ }
expr(ls, &v);
n++;
}
- luaK_tostack(ls, &v, 0); /* allow multiple values for last expression */
- luaK_code2(fs, OP_SETLIST, (n-1)/LFIELDS_PER_FLUSH, t);
+ if (v.k == VCALL) {
+ luaK_setcallreturns(fs, &v, NO_REG);
+ luaK_codeABc(fs, OP_SETLISTO, t->u.i.info, n-1);
+ }
+ else {
+ luaK_exp2nextreg(fs, &v);
+ luaK_codeABc(fs, OP_SETLIST, t->u.i.info, n-1);
+ }
+ fs->freereg = reg; /* free registers */
return n;
}
-
-static void constructor_part (LexState *ls, Constdesc *cd) {
+static void constructor_part (LexState *ls, expdesc *t, Constdesc *cd) {
switch (ls->t.token) {
case l_c(';'): case l_c('}'): { /* constructor_part -> empty */
cd->n = 0;
@@ -518,13 +555,13 @@ static void constructor_part (LexState *ls, Constdesc *cd) {
/* else go through to recfields */
}
case l_c('['): { /* constructor_part -> recfields */
- cd->n = recfields(ls);
+ cd->n = recfields(ls, t);
cd->k = 1; /* record */
break;
}
default: { /* constructor_part -> listfields */
case_default:
- cd->n = listfields(ls);
+ cd->n = listfields(ls, t);
cd->k = 0; /* list */
break;
}
@@ -532,25 +569,27 @@ static void constructor_part (LexState *ls, Constdesc *cd) {
}
-static void constructor (LexState *ls) {
+static void constructor (LexState *ls, expdesc *t) {
/* constructor -> `{' constructor_part [`;' constructor_part] `}' */
FuncState *fs = ls->fs;
int line = ls->linenumber;
- int pc = luaK_code1(fs, OP_CREATETABLE, 0);
- int nelems;
+ int n;
+ int pc;
Constdesc cd;
+ pc = luaK_codeABc(fs, OP_NEWTABLE, 0, 0);
+ init_exp(t, VRELOCABLE, pc);
check(ls, l_c('{'));
- constructor_part(ls, &cd);
- nelems = cd.n;
+ constructor_part(ls, t, &cd);
+ n = cd.n;
if (optional(ls, l_c(';'))) {
Constdesc other_cd;
- constructor_part(ls, &other_cd);
+ constructor_part(ls, t, &other_cd);
check_condition(ls, (cd.k != other_cd.k), l_s("invalid constructor syntax"));
- nelems += other_cd.n;
+ n += other_cd.n;
}
check_match(ls, l_c('}'), l_c('{'), line);
- luaX_checklimit(ls, nelems, MAXARG_U, l_s("elements in a table constructor"));
- SETARG_U(fs->f->code[pc], nelems); /* set initial table size */
+ luaX_checklimit(ls, n, MAXARG_Bc, l_s("elements in a table constructor"));
+ SETARG_Bc(fs->f->code[pc], n); /* set initial table size */
}
/* }====================================================================== */
@@ -565,31 +604,30 @@ static void constructor (LexState *ls) {
*/
static void primaryexp (LexState *ls, expdesc *v) {
- FuncState *fs = ls->fs;
switch (ls->t.token) {
case TK_NUMBER: {
- lua_Number r = ls->t.seminfo.r;
- next(ls);
- luaK_number(fs, r);
+ init_exp(v, VNUMBER, 0);
+ v->u.n = ls->t.seminfo.r;
+ next(ls); /* must use `seminfo' before `next' */
break;
}
case TK_STRING: {
- code_string(ls, ls->t.seminfo.ts); /* must use `seminfo' before `next' */
- next(ls);
+ codestring(ls, v, ls->t.seminfo.ts);
+ next(ls); /* must use `seminfo' before `next' */
break;
}
case TK_NIL: {
- luaK_adjuststack(fs, -1);
+ init_exp(v, VNIL, 0);
next(ls);
break;
}
case l_c('{'): { /* constructor */
- constructor(ls);
+ constructor(ls, v);
break;
}
case TK_FUNCTION: {
next(ls);
- body(ls, 0, ls->linenumber);
+ body(ls, v, 0, ls->linenumber);
break;
}
case l_c('('): {
@@ -604,7 +642,7 @@ static void primaryexp (LexState *ls, expdesc *v) {
}
case l_c('%'): {
next(ls); /* skip `%' */
- pushupvalue(ls, str_checkname(ls));
+ codeupvalue(ls, v, str_checkname(ls));
break;
}
default: {
@@ -612,46 +650,38 @@ static void primaryexp (LexState *ls, expdesc *v) {
return;
}
}
- v->k = VEXP;
- v->u.l.t = v->u.l.f = NO_JUMP;
}
static void simpleexp (LexState *ls, expdesc *v) {
/* simpleexp ->
primaryexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
+ FuncState *fs = ls->fs;
primaryexp(ls, v);
for (;;) {
switch (ls->t.token) {
- case l_c('.'): { /* `.' NAME */
- next(ls);
- luaK_tostack(ls, v, 1); /* `v' must be on stack */
- luaK_kstr(ls, checkname(ls));
- v->k = VINDEXED;
+ case l_c('.'): { /* field */
+ luaY_field(ls, v);
break;
}
case l_c('['): { /* `[' exp1 `]' */
- next(ls);
- luaK_tostack(ls, v, 1); /* `v' must be on stack */
- v->k = VINDEXED;
- exp1(ls);
- check(ls, l_c(']'));
+ expdesc key;
+ luaK_exp2anyreg(fs, v);
+ luaY_index(ls, &key);
+ luaK_indexed(fs, v, &key);
break;
}
case l_c(':'): { /* `:' NAME funcargs */
+ expdesc key;
next(ls);
- luaK_tostack(ls, v, 1); /* `v' must be on stack */
- luaK_code1(ls->fs, OP_PUSHSELF, checkname(ls));
- funcargs(ls, 1);
- v->k = VEXP;
- v->u.l.t = v->u.l.f = NO_JUMP;
+ checkname(ls, &key);
+ luaK_self(fs, v, &key);
+ funcargs(ls, v);
break;
}
case l_c('('): case TK_STRING: case l_c('{'): { /* funcargs */
- luaK_tostack(ls, v, 1); /* `v' must be on stack */
- funcargs(ls, 0);
- v->k = VEXP;
- v->u.l.t = v->u.l.f = NO_JUMP;
+ luaK_exp2nextreg(fs, v);
+ funcargs(ls, v);
break;
}
default: return; /* should be follow... */
@@ -714,7 +744,7 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
if (uop != OPR_NOUNOPR) {
next(ls);
subexpr(ls, v, UNARY_PRIORITY);
- luaK_prefix(ls, uop, v);
+ luaK_prefix(ls->fs, uop, v);
}
else simpleexp(ls, v);
/* expand while operators have priorities higher than `limit' */
@@ -723,10 +753,10 @@ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
expdesc v2;
BinOpr nextop;
next(ls);
- luaK_infix(ls, op, v);
+ luaK_infix(ls->fs, op, v);
/* read sub-expression with higher priority */
nextop = subexpr(ls, &v2, (int)priority[op].right);
- luaK_posfix(ls, op, v, &v2);
+ luaK_posfix(ls->fs, op, v, &v2);
op = nextop;
}
return op; /* return first untreated operator */
@@ -737,13 +767,6 @@ static void expr (LexState *ls, expdesc *v) {
subexpr(ls, v, -1);
}
-
-static void exp1 (LexState *ls) {
- expdesc v;
- expr(ls, &v);
- luaK_tostack(ls, &v, 1);
-}
-
/* }==================================================================== */
@@ -769,41 +792,87 @@ static void block (LexState *ls) {
FuncState *fs = ls->fs;
int nactloc = fs->nactloc;
chunk(ls);
- luaK_adjuststack(fs, fs->nactloc - nactloc); /* remove local variables */
removelocalvars(ls, fs->nactloc - nactloc);
+ fs->freereg = nactloc; /* free registers used by locals */
}
-static int assignment (LexState *ls, expdesc *v, int nvars) {
- int left = 0; /* number of values left in the stack after assignment */
- luaX_checklimit(ls, nvars, MAXVARSLH, l_s("variables in a multiple assignment"));
+/*
+** structure to chain all variables in the left-hand side of an
+** assignment
+*/
+struct LHS_assign {
+ struct LHS_assign *prev;
+ expdesc v; /* variable (global, local, or indexed) */
+};
+
+
+/*
+** check whether, in an assignment to a local variable, the local variable
+** is needed in a previous assignment (to a table). If so, save original
+** local value in a safe place and use this safe copy in the previous
+** assignment.
+*/
+static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
+ FuncState *fs = ls->fs;
+ int extra = fs->freereg; /* eventual position to save local variable */
+ int conflict = 0;
+ for (; lh; lh = lh->prev) {
+ if (lh->v.k == VINDEXED) {
+ if (lh->v.u.i.info == v->u.i.info) { /* conflict? */
+ conflict = 1;
+ lh->v.u.i.info = extra; /* previous assignment will use safe copy */
+ }
+ if (lh->v.u.i.aux == v->u.i.info) { /* conflict? */
+ conflict = 1;
+ lh->v.u.i.aux = extra; /* previous assignment will use safe copy */
+ }
+ }
+ }
+ if (conflict) {
+ luaK_codeABC(fs, OP_MOVE, fs->freereg, v->u.i.info, 0); /* make copy */
+ luaK_reserveregs(fs, 1);
+ }
+}
+
+
+static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
+ expdesc e;
+ check_condition(ls, lh->v.k == VLOCAL || lh->v.k == VGLOBAL ||
+ lh->v.k == VINDEXED,
+ l_s("syntax error"));
if (ls->t.token == l_c(',')) { /* assignment -> `,' simpleexp assignment */
- expdesc nv;
+ struct LHS_assign nv;
+ nv.prev = lh;
next(ls);
- simpleexp(ls, &nv);
- check_condition(ls, (nv.k != VEXP), l_s("syntax error"));
- left = assignment(ls, &nv, nvars+1);
+ simpleexp(ls, &nv.v);
+ if (nv.v.k == VLOCAL)
+ check_conflict(ls, lh, &nv.v);
+ assignment(ls, &nv, nvars+1);
}
else { /* assignment -> `=' explist1 */
int nexps;
check(ls, l_c('='));
- nexps = explist1(ls);
- adjust_mult_assign(ls, nvars, nexps);
- }
- if (v->k != VINDEXED)
- luaK_storevar(ls, v);
- else { /* there may be garbage between table-index and value */
- luaK_code2(ls->fs, OP_SETTABLE, left+nvars+2, 1);
- left += 2;
+ nexps = explist1(ls, &e);
+ if (nexps != nvars) {
+ adjust_assign(ls, nvars, nexps, &e);
+ if (nexps > nvars)
+ ls->fs->freereg -= nexps - nvars; /* remove extra values */
+ }
+ else {
+ luaK_storevar(ls->fs, &lh->v, &e);
+ return; /* avoid default */
+ }
}
- return left;
+ init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */
+ luaK_storevar(ls->fs, &lh->v, &e);
}
static void cond (LexState *ls, expdesc *v) {
/* cond -> exp */
expr(ls, v); /* read condition */
- luaK_goiftrue(ls->fs, v, 0);
+ luaK_goiftrue(ls->fs, v);
}
@@ -819,7 +888,7 @@ static void whilestat (LexState *ls, int line) {
check(ls, TK_DO);
block(ls);
luaK_patchlist(fs, luaK_jump(fs), while_init);
- luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs));
+ luaK_patchlist(fs, v.f, luaK_getlabel(fs));
check_match(ls, TK_END, TK_WHILE, line);
leavebreak(fs, &bl);
}
@@ -836,20 +905,28 @@ static void repeatstat (LexState *ls, int line) {
block(ls);
check_match(ls, TK_UNTIL, TK_REPEAT, line);
cond(ls, &v);
- luaK_patchlist(fs, v.u.l.f, repeat_init);
+ luaK_patchlist(fs, v.f, repeat_init);
leavebreak(fs, &bl);
}
+static void exp1 (LexState *ls) {
+ expdesc e;
+ expr(ls, &e);
+ luaK_exp2nextreg(ls->fs, &e);
+}
+
+
static void forbody (LexState *ls, int nvar, OpCode prepfor, OpCode loopfor) {
/* forbody -> DO block END */
FuncState *fs = ls->fs;
- int prep = luaK_code1(fs, prepfor, NO_JUMP);
+ int basereg = fs->freereg - nvar;
+ int prep = luaK_codeAsBc(fs, prepfor, basereg, NO_JUMP);
int blockinit = luaK_getlabel(fs);
check(ls, TK_DO);
adjustlocalvars(ls, nvar); /* scope for control variables */
block(ls);
- luaK_patchlist(fs, luaK_code1(fs, loopfor, NO_JUMP), blockinit);
+ luaK_patchlist(fs, luaK_codeAsBc(fs, loopfor, basereg, NO_JUMP), blockinit);
luaK_fixfor(fs, prep, luaK_getlabel(fs));
removelocalvars(ls, nvar);
}
@@ -864,8 +941,10 @@ static void fornum (LexState *ls, TString *varname) {
exp1(ls); /* limit */
if (optional(ls, l_c(',')))
exp1(ls); /* optional step */
- else
- luaK_code1(fs, OP_PUSHINT, 1); /* default step */
+ else {
+ luaK_codeAsBc(fs, OP_LOADINT, fs->freereg, 1); /* default step */
+ luaK_reserveregs(fs, 1);
+ }
new_localvar(ls, varname, 0);
new_localvarstr(ls, l_s("(limit)"), 1);
new_localvarstr(ls, l_s("(step)"), 2);
@@ -889,7 +968,8 @@ static void forlist (LexState *ls, TString *indexname) {
new_localvarstr(ls, l_s("(index)"), 1);
new_localvar(ls, indexname, 2);
new_localvar(ls, valname, 3);
- forbody(ls, 4, OP_LFORPREP, OP_LFORLOOP);
+ luaK_reserveregs(ls->fs, 3); /* registers for control, index and val */
+ forbody(ls, 4, OP_TFORPREP, OP_TFORLOOP);
}
@@ -928,17 +1008,17 @@ static void ifstat (LexState *ls, int line) {
test_then_block(ls, &v); /* IF cond THEN block */
while (ls->t.token == TK_ELSEIF) {
luaK_concat(fs, &escapelist, luaK_jump(fs));
- luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs));
+ luaK_patchlist(fs, v.f, luaK_getlabel(fs));
test_then_block(ls, &v); /* ELSEIF cond THEN block */
}
if (ls->t.token == TK_ELSE) {
luaK_concat(fs, &escapelist, luaK_jump(fs));
- luaK_patchlist(fs, v.u.l.f, luaK_getlabel(fs));
+ luaK_patchlist(fs, v.f, luaK_getlabel(fs));
next(ls); /* skip ELSE */
block(ls); /* `else' part */
}
else
- luaK_concat(fs, &escapelist, v.u.l.f);
+ luaK_concat(fs, &escapelist, v.f);
luaK_patchlist(fs, escapelist, luaK_getlabel(fs));
check_match(ls, TK_END, TK_IF, line);
}
@@ -948,35 +1028,32 @@ static void localstat (LexState *ls) {
/* stat -> LOCAL NAME {`,' NAME} [`=' explist1] */
int nvars = 0;
int nexps;
+ expdesc e;
do {
next(ls); /* skip LOCAL or `,' */
new_localvar(ls, str_checkname(ls), nvars++);
} while (ls->t.token == l_c(','));
if (optional(ls, l_c('=')))
- nexps = explist1(ls);
- else
+ nexps = explist1(ls, &e);
+ else {
+ e.k = VVOID;
nexps = 0;
- adjust_mult_assign(ls, nvars, nexps);
+ }
+ adjust_assign(ls, nvars, nexps, &e);
adjustlocalvars(ls, nvars);
}
static int funcname (LexState *ls, expdesc *v) {
- /* funcname -> NAME {`.' NAME} [`:' NAME] */
+ /* funcname -> NAME {field} [`:' NAME] */
int needself = 0;
singlevar(ls, str_checkname(ls), v);
while (ls->t.token == l_c('.')) {
- next(ls);
- luaK_tostack(ls, v, 1);
- luaK_kstr(ls, checkname(ls));
- v->k = VINDEXED;
+ luaY_field(ls, v);
}
if (ls->t.token == l_c(':')) {
needself = 1;
- next(ls);
- luaK_tostack(ls, v, 1);
- luaK_kstr(ls, checkname(ls));
- v->k = VINDEXED;
+ luaY_field(ls, v);
}
return needself;
}
@@ -985,26 +1062,25 @@ static int funcname (LexState *ls, expdesc *v) {
static void funcstat (LexState *ls, int line) {
/* funcstat -> FUNCTION funcname body */
int needself;
- expdesc v;
+ expdesc v, b;
next(ls); /* skip FUNCTION */
needself = funcname(ls, &v);
- body(ls, needself, line);
- luaK_storevar(ls, &v);
+ body(ls, &b, needself, line);
+ luaK_storevar(ls->fs, &v, &b);
}
static void exprstat (LexState *ls) {
/* stat -> func | assignment */
FuncState *fs = ls->fs;
- expdesc v;
- simpleexp(ls, &v);
- if (v.k == VEXP) { /* stat -> func */
- check_condition(ls, luaK_lastisopen(fs), l_s("syntax error")); /* an upvalue? */
- luaK_setcallreturns(fs, 0); /* call statement uses no results */
+ struct LHS_assign v;
+ simpleexp(ls, &v.v);
+ if (v.v.k == VCALL) { /* stat -> func */
+ luaK_setcallreturns(fs, &v.v, 0); /* call statement uses no results */
}
else { /* stat -> assignment */
- int left = assignment(ls, &v, 1);
- luaK_adjuststack(fs, left); /* remove eventual garbage left on stack */
+ v.prev = NULL;
+ assignment(ls, &v, 1);
}
}
@@ -1012,26 +1088,45 @@ static void exprstat (LexState *ls) {
static void retstat (LexState *ls) {
/* stat -> RETURN explist */
FuncState *fs = ls->fs;
+ expdesc e;
+ int first, last1; /* registers with returned values */
next(ls); /* skip RETURN */
- if (!block_follow(ls->t.token) && ls->t.token != l_c(';'))
- explist1(ls); /* optional return values */
- luaK_code1(fs, OP_RETURN, ls->fs->nactloc);
- fs->stacklevel = fs->nactloc; /* removes all temp values */
+ if (block_follow(ls->t.token) || ls->t.token == l_c(';'))
+ first = last1 = 0; /* return no values */
+ else {
+ int n = explist1(ls, &e); /* optional return values */
+ if (e.k == VCALL) {
+ luaK_setcallreturns(fs, &e, NO_REG);
+ first = fs->nactloc;
+ last1 = NO_REG; /* return all values */
+ }
+ else {
+ if (n == 1) { /* only one value? */
+ luaK_exp2anyreg(fs, &e);
+ first = e.u.i.info;
+ last1 = first+1; /* return only this value */
+ }
+ else {
+ luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */
+ first = fs->nactloc;
+ last1 = fs->freereg; /* return all `active' values */
+ }
+ }
+ }
+ luaK_codeABC(fs, OP_RETURN, first, last1, 0);
+ fs->freereg = fs->nactloc; /* removes all temp values */
}
static void breakstat (LexState *ls) {
/* stat -> BREAK [NAME] */
FuncState *fs = ls->fs;
- int currentlevel = fs->stacklevel;
Breaklabel *bl = fs->bl;
if (!bl)
luaK_error(ls, l_s("no loop to break"));
next(ls); /* skip BREAK */
- luaK_adjuststack(fs, currentlevel - bl->stacklevel);
luaK_concat(fs, &bl->breaklist, luaK_jump(fs));
/* correct stack for compiler and symbolic execution */
- luaK_adjuststack(fs, bl->stacklevel - currentlevel);
}
@@ -1105,7 +1200,7 @@ static void parlist (LexState *ls) {
}
-static void body (LexState *ls, int needself, int line) {
+static void body (LexState *ls, expdesc *e, int needself, int line) {
/* body -> `(' parlist `)' chunk END */
FuncState new_fs;
open_func(ls, &new_fs);
@@ -1120,7 +1215,7 @@ static void body (LexState *ls, int needself, int line) {
chunk(ls);
check_match(ls, TK_END, TK_FUNCTION, line);
close_func(ls);
- pushclosure(ls, &new_fs);
+ pushclosure(ls, &new_fs, e);
}
@@ -1133,7 +1228,10 @@ static void chunk (LexState *ls) {
while (!islast && !block_follow(ls->t.token)) {
islast = statement(ls);
optional(ls, l_c(';'));
- lua_assert(ls->fs->stacklevel == ls->fs->nactloc);
+if (ls->fs->freereg < ls->fs->nactloc)
+printf(">>>>>>> %d %d\n", ls->fs->freereg, ls->fs->nactloc);
+ lua_assert(ls->fs->freereg >= ls->fs->nactloc);
+ ls->fs->freereg = ls->fs->nactloc; /* free registers */
}
}
diff --git a/lparser.h b/lparser.h
@@ -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
** See Copyright Notice in lua.h
*/
@@ -16,25 +16,32 @@
*/
typedef enum {
- VGLOBAL,
- VLOCAL,
- VINDEXED,
- VEXP
+ VVOID, /* no value */
+ VNIL,
+ VNUMBER, /* n = value */
+ 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;
typedef struct expdesc {
expkind k;
union {
- int index; /* VGLOBAL: `kstr' index of global name; VLOCAL: stack index */
struct {
- int t; /* patch list of `exit when true' */
- int f; /* patch list of `exit when false' */
- } l;
+ int info, aux;
+ } i;
+ lua_Number n;
} u;
+ int t; /* patch list of `exit when true' */
+ int f; /* patch list of `exit when false' */
} expdesc;
-
/* state needed to generate code for a given function */
typedef struct FuncState {
Proto *f; /* current function header */
@@ -44,10 +51,9 @@ typedef struct FuncState {
int pc; /* next position to code (equivalent to `ncode') */
int lasttarget; /* `pc' of last `jump target' */
int jlt; /* list of jumps to `lasttarget' */
- int stacklevel; /* number of values on activation register */
- int nkstr; /* number of elements in `kstr' */
+ int freereg; /* first free register */
+ int nk; /* number of elements in `k' */
int nkproto; /* number of elements in `kproto' */
- int nknum; /* number of elements in `knum' */
int nlineinfo; /* number of elements in `lineinfo' */
int nlocvars; /* number of elements in `locvars' */
int nactloc; /* number of active local variables */
diff --git a/ltests.c b/ltests.c
@@ -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
** 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] = {
- l_s("RETURN"),
- l_s("CALL"),
- l_s("PUSHNIL"),
- l_s("POP"),
- l_s("PUSHINT"),
- l_s("PUSHSTRING"),
- l_s("PUSHNUM"),
- l_s("PUSHNEGNUM"),
- l_s("PUSHUPVALUE"),
- l_s("GETLOCAL"),
- l_s("GETGLOBAL"),
- l_s("GETTABLE"),
- l_s("GETDOTTED"),
- l_s("GETINDEXED"),
- l_s("PUSHSELF"),
- l_s("CREATETABLE"),
- l_s("SETLOCAL"),
- l_s("SETGLOBAL"),
- l_s("SETTABLE"),
- l_s("SETLIST"),
- l_s("SETMAP"),
- l_s("ADD"),
- l_s("ADDI"),
- l_s("SUB"),
- l_s("MULT"),
- l_s("DIV"),
- l_s("POW"),
- l_s("CONCAT"),
- l_s("MINUS"),
- l_s("NOT"),
- l_s("JMPNE"),
- l_s("JMPEQ"),
- l_s("JMPLT"),
- l_s("JMPLE"),
- l_s("JMPGT"),
- l_s("JMPGE"),
- l_s("JMPT"),
- l_s("JMPF"),
- 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")
+ l_s("OP_MOVE"),
+ l_s("OP_LOADK"),
+ l_s("OP_LOADINT"),
+ l_s("OP_LOADNIL"),
+ l_s("OP_LOADUPVAL"),
+ l_s("OP_GETGLOBAL"),
+ l_s("OP_GETTABLE"),
+ l_s("OP_SETGLOBAL"),
+ l_s("OP_SETTABLE"),
+ l_s("OP_NEWTABLE"),
+ l_s("OP_SELF"),
+ l_s("OP_ADD"),
+ l_s("OP_SUB"),
+ l_s("OP_MUL"),
+ l_s("OP_DIV"),
+ l_s("OP_POW"),
+ l_s("OP_UNM"),
+ l_s("OP_NOT"),
+ l_s("OP_CONCAT"),
+ l_s("OP_JMP"),
+ l_s("OP_CJMP"),
+ l_s("OP_TESTEQ"),
+ l_s("OP_TESTNE"),
+ l_s("OP_TESTLT"),
+ l_s("OP_TESTLE"),
+ l_s("OP_TESTGT"),
+ l_s("OP_TESTGE"),
+ l_s("OP_TESTT"),
+ l_s("OP_TESTF"),
+ l_s("OP_NILJMP"),
+ l_s("OP_CALL"),
+ l_s("OP_RETURN"),
+ l_s("OP_FORPREP"),
+ l_s("OP_FORLOOP"),
+ l_s("OP_LFORPREP"),
+ l_s("OP_LFORLOOP"),
+ l_s("OP_SETLIST"),
+ l_s("OP_CLOSURE")
};
-static void pushop (lua_State *L, Proto *p, int pc) {
- l_char buff[100];
+static l_char *buildop (Proto *p, int pc, l_char *buff) {
Instruction i = p->code[pc];
OpCode o = GET_OPCODE(i);
const l_char *name = instrname[o];
- sprintf(buff, l_s("%5d - "), luaG_getline(p->lineinfo, pc, 1, NULL));
- switch ((enum Mode)luaK_opproperties[o].mode) {
- case iO:
- sprintf(buff+8, l_s("%-12s"), name);
+ sprintf(buff, l_s("%4d - "), pc);
+ switch (getOpMode(o)) {
+ case iABC:
+ sprintf(buff+strlen(buff), l_s("%-12s%4d %4d %4d"), name,
+ GETARG_A(i), GETARG_B(i), GETARG_C(i));
break;
- case iU:
- sprintf(buff+8, l_s("%-12s%4u"), name, GETARG_U(i));
+ case iABc:
+ sprintf(buff+strlen(buff), l_s("%-12s%4d %4d"), name, GETARG_A(i), GETARG_Bc(i));
break;
- case iS:
- sprintf(buff+8, l_s("%-12s%4d"), name, GETARG_S(i));
- break;
- case iAB:
- sprintf(buff+8, l_s("%-12s%4d %4d"), name, GETARG_A(i), GETARG_B(i));
+ case iAsBc:
+ sprintf(buff+strlen(buff), l_s("%-12s%4d %4d"), name, GETARG_A(i), GETARG_sBc(i));
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("numparams"), p->numparams);
for (pc=0; pc<p->sizecode; pc++) {
+ l_char buff[100];
lua_pushnumber(L, pc+1);
- pushop(L, p, pc);
+ lua_pushstring(L, buildop(p, pc, buff));
lua_settable(L, -3);
}
return 1;
}
-static int liststrings (lua_State *L) {
+static int listk (lua_State *L) {
Proto *p;
int i;
luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
1, l_s("Lua function expected"));
p = clvalue(luaA_index(L, 1))->f.l;
lua_newtable(L);
- for (i=0; i<p->sizekstr; i++) {
+ for (i=0; i<p->sizek; i++) {
lua_pushnumber(L, i+1);
- lua_pushstring(L, getstr(p->kstr[i]));
+ luaA_pushobject(L, p->k+i);
lua_settable(L, -3);
}
return 1;
@@ -276,20 +265,10 @@ static int get_limits (lua_State *L) {
lua_newtable(L);
setnameval(L, l_s("BITS_INT"), BITS_INT);
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("MAXPARAMS"), MAXPARAMS);
setnameval(L, l_s("MAXSTACK"), MAXSTACK);
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;
}
@@ -700,7 +679,7 @@ static const struct luaL_reg tests_funcs[] = {
{l_s("hash"), hash_query},
{l_s("limits"), get_limits},
{l_s("listcode"), listcode},
- {l_s("liststrings"), liststrings},
+ {l_s("listk"), listk},
{l_s("listlocals"), listlocals},
{l_s("loadlib"), loadlib},
{l_s("querystr"), string_query},
diff --git a/lvm.c b/lvm.c
@@ -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;
- break;
- }
- case OP_PUSHNIL: {
- int n = GETARG_U(i);
- lua_assert(n>0);
- 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++;
+ case OP_MOVE: {
+ setobj(RA(i), RB(i));
break;
}
- case OP_PUSHNUM: {
- setnvalue(top, tf->knum[GETARG_U(i)]);
- top++;
+ case OP_LOADK: {
+ setobj(RA(i), KBc(i));
break;
}
- case OP_PUSHNEGNUM: {
- setnvalue(top, -tf->knum[GETARG_U(i)]);
- top++;
+ case OP_LOADINT: {
+ setnvalue(RA(i), (lua_Number)GETARG_sBc(i));
break;
}
- case OP_PUSHUPVALUE: {
- setobj(top++, &cl->upvalue[GETARG_U(i)]);
+ case OP_LOADUPVAL: {
+ setobj(RA(i), cl->upvalue+GETARG_Bc(i));
break;
}
- case OP_GETLOCAL: {
- setobj(top++, base+GETARG_U(i));
+ case OP_LOADNIL: {
+ TObject *ra = RA(i);
+ TObject *rb = RB(i);
+ do {
+ 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);
+ 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_JMPEQ: {
- top -= 2;
- if (luaO_equalObj(top, top+1)) dojump(pc, i);
+ case OP_CJMP:
+ case OP_JMP: {
+ dojump(pc, i);
break;
}
- case OP_JMPLT: {
- top -= 2;
- if (luaV_lessthan(L, top, top+1)) dojump(pc, i);
+ case OP_TESTEQ: {
+ lua_assert(GET_OPCODE(*pc) == OP_CJMP);
+ if (luaO_equalObj(RB(i), RKC(i))) dojump(pc, *pc);
+ pc++;
break;
}
- case OP_JMPLE: { /* a <= b === !(b<a) */
- top -= 2;
- if (!luaV_lessthan(L, top+1, top)) dojump(pc, i);
+ case OP_TESTNE: {
+ lua_assert(GET_OPCODE(*pc) == OP_CJMP);
+ if (!luaO_equalObj(RB(i), RKC(i))) dojump(pc, *pc);
+ pc++;
break;
}
- case OP_JMPGT: { /* a > b === (b<a) */
- top -= 2;
- if (luaV_lessthan(L, top+1, top)) dojump(pc, i);
+ 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_JMPGE: { /* a >= b === !(a<b) */
- top -= 2;
- if (!luaV_lessthan(L, top, top+1)) dojump(pc, i);
+ 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_JMPT: {
- if (ttype(--top) != LUA_TNIL) dojump(pc, i);
+ 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_JMPF: {
- if (ttype(--top) == LUA_TNIL) dojump(pc, i);
+ 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_JMPONT: {
- if (ttype(top-1) == LUA_TNIL) top--;
- else dojump(pc, i);
+ 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_JMPONF: {
- if (ttype(top-1) != LUA_TNIL) top--;
- else dojump(pc, i);
+ 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_JMP: {
- dojump(pc, i);
+ case OP_NILJMP: {
+ setnilvalue(RA(i));
+ pc++;
break;
}
- case OP_PUSHNILJMP: {
- setnilvalue(top++);
- pc++;
+ 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;
}
}
}
}
+
diff --git a/lvm.h b/lvm.h
@@ -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
** See Copyright Notice in lua.h
*/
@@ -13,14 +13,13 @@
#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))
-int luaV_tonumber (TObject *obj);
+const TObject *luaV_tonumber (const TObject *obj, TObject *n);
int luaV_tostring (lua_State *L, TObject *obj);
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_setglobal (lua_State *L, TString *s, StkId val);
StkId luaV_execute (lua_State *L, const Closure *cl, StkId base);