diff --git a/lapi.c b/lapi.c index 45139f6c..36e0aef7 100644 --- 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 index 783158d9..2658e602 100644 --- 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,148 +115,55 @@ 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; - } -} - - -void luaK_kstr (LexState *ls, int c) { - luaK_code1(ls->fs, OP_PUSHSTRING, c); -} - - -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; -} - - -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 */ +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 - luaK_code1(fs, OP_PUSHNUM, number_constant(fs, f)); + return (pc+1)+offset; /* turn offset into absolute position */ } -void luaK_adjuststack (FuncState *fs, int n) { - if (n > 0) - luaK_code1(fs, OP_POP, n); - else - luaK_code1(fs, OP_PUSHNIL, -n); -} - - -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_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 */ +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 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 */ - } - var->k = VEXP; - var->u.l.t = var->u.l.f = NO_JUMP; - return 1; +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 */ } -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 */ -} - - -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 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 void luaK_patchlistaux (FuncState *fs, int list, int target, - OpCode special, int special_target) { - Instruction *code = fs->f->code; +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 = &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); + 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; } @@ -248,15 +174,7 @@ 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 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 */ + luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target); } @@ -273,155 +191,558 @@ void luaK_concat (FuncState *fs, int *l1, int l2) { } -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 */ +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; } - else { - golist = &v->u.l.t; /* go if true */ - exitlist = &v->u.l.f; /* exit if false */ - } - 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))); - } - 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 freereg (FuncState *fs, int reg) { + if (reg >= fs->nactloc && reg < MAXSTACK) { + fs->freereg--; + lua_assert(reg == fs->freereg); + } } -static void luaK_goiffalse (FuncState *fs, expdesc *v) { - luaK_testgo(fs, v, 0, OP_JMPONT); +static void freeexp (FuncState *fs, expdesc *e) { + if (e->k == VNONRELOC) + freereg(fs, e->u.i.info); } -static int code_label (FuncState *fs, OpCode op, int arg) { +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 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); +} + + +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)); + } + } +} + + +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 code_label (FuncState *fs, OpCode op, int A, int sBc) { luaK_getlabel(fs); /* those instructions may be jump targets */ - return luaK_code1(fs, op, arg); + return luaK_codeAsBc(fs, op, A, sBc); } -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; +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; } -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_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 */ - } -} - - - -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); +static void discharge2reg (FuncState *fs, expdesc *e, int reg) { + dischargevars(fs, e); + switch (e->k) { + case VNIL: { + luaK_nil(fs, reg, 1); 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 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; + } + 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); + } +} + + +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: { - luaK_tostack(ls, v2, 1); /* `v2' must be a value */ - luaK_code1(fs, codes[op].opcode, codes[op].arg); + lua_assert(0); /* cannot happen */ + break; + } + } + dischargejumps(fs, e, reg); + e->u.i.info = reg; + e->k = VNONRELOC; +} + + +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); +} + + +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_exp2val (FuncState *fs, expdesc *e) { + if (hasjumps(e)) + luaK_exp2anyreg(fs, e); + else + dischargevars(fs, e); +} + + +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; +} + + +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 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: { + lua_assert(0); /* invalid var kind to store */ + break; + } + } +} + + +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 */ + } +} + + +static void invertjump (FuncState *fs, expdesc *e) { + Instruction *pc = getjumpcontrol(fs, e->u.i.info); + *pc = SET_OPCODE(*pc, invertoperator(GET_OPCODE(*pc))); +} + + +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); +} + + +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 VNIL: { + pc = luaK_codeAsBc(fs, OP_JMP, 0, NO_JUMP); /* always jump */ + break; + } + case VJMP: { + invertjump(fs, e); + pc = e->u.i.info; + break; + } + case VRELOCABLE: + case VNONRELOC: { + pc = jumponcond(fs, e, OP_TESTF); + break; + } + default: { + pc = 0; /* to avoid warnings */ + lua_assert(0); /* cannot happen */ + 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 VJMP: { + pc = e->u.i.info; + break; + } + case VK: case VNUMBER: /* cannot optimize it (`or' must keep value) */ + case VRELOCABLE: + case VNONRELOC: { + pc = jumponcond(fs, e, OP_TESTT); + break; + } + default: { + pc = 0; /* to avoid warnings */ + lua_assert(0); /* cannot happen */ + 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 VK: case VNUMBER: { + e->k = VNIL; + break; + } + case VJMP: { + invertjump(fs, e); + break; + } + 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; + } + default: { + lua_assert(0); /* cannot happen */ + 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 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; + } + } +} + + + +/* 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; + } } } } @@ -444,261 +765,27 @@ static void codelineinfo (FuncState *fs) { } -int luaK_code0 (FuncState *fs, OpCode o) { - return luaK_code2(fs, o, 0, 0); -} - - -int luaK_code1 (FuncState *fs, OpCode o, int arg1) { - return luaK_code2(fs, o, arg1, 0); -} - - -int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { +static int luaK_code (FuncState *fs, Instruction i) { 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; - break; - } - case OP_SETTABLE: { - pop = arg2; - break; - } - case OP_SETLIST: { - pop = fs->stacklevel - 1 - arg2; - break; - } - case OP_SETMAP: { - pop = fs->stacklevel - 1 - arg1; - 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; - } - 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; - } - 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; - } - break; - } - case OP_ADD: { - switch(GET_OPCODE(i)) { - case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); optm = 1; break; /* `a+k' */ - default: break; - } - 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; - } - 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; - } - 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; - } - break; - } - case OP_JMPNE: { - if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a~=nil' */ - i = CREATE_S(OP_JMPT, NO_JUMP); - optm = 1; - } - 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; - } - 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; - } - 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; - } - break; - } - case OP_GETDOTTED: - case OP_GETINDEXED: - case OP_ADDI: { - lua_assert(0); /* instruction used only for optimizations */ - break; - } - default: { - 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 */ - } - /* 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; - } 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 index b73e9947..e82d1b17 100644 --- 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; +#define binopistest(op) ((op) >= OPR_NE) + typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr; -enum Mode {iO, iU, iS, iAB}; /* instruction format */ - -#define VD 100 /* flag for variable delta */ - -typedef struct OpProperties { - lu_byte mode; - lu_byte push; - lu_byte pop; -} OpProperties; - -extern const OpProperties luaK_opproperties[]; - +#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 index f8369d2d..9cb65a1f 100644 --- 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; isizecode; 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; - break; - } - case OP_CALL: { - if (arg2 == MULT_RET) arg2 = 1; - check(arg1 < top); - pop = top-arg1; - push = arg2; - break; - } - case OP_PUSHNIL: { - check(arg1 > 0); - push = arg1; - break; - } - case OP_POP: { - pop = arg1; - break; - } - case OP_PUSHSTRING: - case OP_GETGLOBAL: - case OP_GETDOTTED: - case OP_PUSHSELF: - case OP_SETGLOBAL: { - check(arg1 < pt->sizekstr); - break; - } - case OP_PUSHNUM: - case OP_PUSHNEGNUM: { - check(arg1 < pt->sizeknum); - break; - } - case OP_PUSHUPVALUE: { - check(arg1 < pt->nupvalues); - break; - } - case OP_GETLOCAL: - case OP_GETINDEXED: - case OP_SETLOCAL: { - check(arg1 < top); - break; - } - case OP_SETTABLE: { - check(3 <= arg1 && arg1 <= top); - pop = arg2; - break; - } - case OP_SETLIST: { - check(arg2 >= 0); - pop = top-arg2-1; - break; - } - case OP_SETMAP: { - check(arg1 >= 0); - pop = top-arg1-1; - break; - } - case OP_CONCAT: { - pop = arg1; - break; - } - case OP_CLOSURE: { - check(arg1 < pt->sizekproto); - check(arg2 == pt->kproto[arg1]->nupvalues); - pop = arg2; - break; - } - case OP_JMPNE: - case OP_JMPEQ: - case OP_JMPLT: - case OP_JMPLE: - case OP_JMPGT: - case OP_JMPGE: - case OP_JMPT: - case OP_JMPF: - case OP_JMP: { - checkjump(pt, sl, top-pop, pc+arg1); - break; - } - case OP_FORLOOP: - case OP_LFORLOOP: - case OP_JMPONT: - case OP_JMPONF: { - int newpc = pc+arg1; - checkjump(pt, sl, top, newpc); - /* jump is forward and do not skip `lastpc' and not full check? */ - if (pc < newpc && newpc <= lastpc && stackpos >= 0) { - stack[top-1] = pc-1; /* value comes from `and'/`or' */ - pc = newpc; /* do the jump */ - pop = 0; /* do not pop */ + 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_PUSHNILJMP: { - check(GET_OPCODE(pt->code[pc]) == OP_PUSHINT); /* only valid sequence */ + case iABc: { + b = GETARG_Bc(i); + if (testOpMode(op, OpModeK)) check(b < pt->sizek); 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); - 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 iAsBc: { + b = GETARG_sBc(i); break; } } - top -= pop; - check(0 <= top && top+push <= pt->maxstacksize); - while (push--) stack[top++] = pc-1; - checkjump(pt, sl, top, pc); + 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_LOADUPVAL: { + check(b < pt->nupvalues); + break; + } + case OP_GETGLOBAL: + case OP_SETGLOBAL: { + check(ttype(&pt->k[b]) == LUA_TSTRING); + break; + } + case OP_SELF: { + checkreg(pt, a+1); + if (reg == a+1) last = pc; + break; + } + case OP_CONCAT: { + check(b < c); /* at least two operands */ + break; + } + case OP_JMP: + case OP_CJMP: { + int dest = pc+1+b; + check(0 <= dest && dest < pt->sizecode); + /* not full check and jump is forward and do not skip `lastpc'? */ + if (reg != NO_REG && pc < dest && dest <= lastpc) + pc += b; /* do the jump */ + break; + } + case OP_TESTT: + case OP_TESTF: { + if (a != NO_REG) + checkreg(pt, a); + break; + } + case OP_NILJMP: { + check(pc+2 < pt->sizecode); /* check its jump */ + break; + } + case OP_CALL: { + if (b == NO_REG) b = pt->maxstacksize; + if (c == NO_REG) { + check(checkopenop(pt->code[pc+1])); + c = 1; + } + check(b > a); + checkreg(pt, b-1); + checkreg(pt, a+c-1); + if (reg >= a) last = pc; /* affect all registers above base */ + break; + } + case OP_RETURN: { + if (b == NO_REG) b = pt->maxstacksize; + checkreg(pt, b-1); + break; + } + case OP_FORPREP: + case OP_TFORPREP: { + int dest = pc-b; /* jump is negated here */ + check(0 <= dest && dest < pt->sizecode && + GET_OPCODE(pt->code[dest]) == op+1); + break; + } + case OP_FORLOOP: + case OP_TFORLOOP: { + int dest = pc+b; + check(0 <= dest && dest < pt->sizecode && + pt->code[dest] == SET_OPCODE(i, op-1)); + checkreg(pt, a + ((op == OP_FORLOOP) ? 2 : 3)); + break; + } + case OP_SETLIST: { + checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1); + break; + } + case OP_CLOSURE: { + check(b < pt->sizekproto); + checkreg(pt, a + pt->kproto[b]->nupvalues - 1); + break; + } + default: break; + } } - return (stackpos >= 0) ? pt->code[stack[stackpos]] : 1; + return pt->code[last]; } /* }====================================================== */ -int luaG_checkcode (lua_State *L, const Proto *pt) { - 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)<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 index 0237b88c..6eba56d9 100644 --- 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; isizekstr; i++) - strmark(f->kstr[i]); + for (i=0; isizek; i++) { + if (ttype(f->k+i) == LUA_TSTRING) + strmark(tsvalue(f->k+i)); + } for (i=0; isizekproto; i++) protomark(f->kproto[i]); for (i=0; isizelocvars; i++) /* mark local-variable names */ diff --git a/llimits.h b/llimits.h index 51dbe7af..2b288981 100644 --- 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<>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< MAXARG_B -#undef MAXSTACK -#define MAXSTACK MAXARG_B -#endif /* maximum number of local variables */ #ifndef MAXLOCALS #define MAXLOCALS 200 /* arbitrary limit (=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 -#undef MAXVARSLH -#define MAXVARSLH (MULT_RET-1) +#define MAXUPVALUES 32 /* arbitrary limit (=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 index b6f7afac..97f77a97 100644 --- 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 index 3b743880..5819c407 100644 --- 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<>1) /* `sBc' is signed */ +#else +#define MAXARG_Bc MAX_INT +#define MAXARG_sBc MAX_INT +#endif + + +#define MAXARG_A ((1<>POS_U)) -#define SETARG_U(i,u) ((i) = (((i)&MASK0(SIZE_U,POS_U)) | \ - ((Instruction)(u)<>POS_A)) -#define SETARG_A(i,a) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \ - ((Instruction)(a)<>POS_B) & MASK1(SIZE_B,0))) #define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \ ((Instruction)(b)<>POS_C) & MASK1(SIZE_C,0))) +#define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \ + ((Instruction)(b)<>POS_Bc) & MASK1(SIZE_Bc,0))) +#define SETARG_Bc(i,b) ((i) = (((i)&MASK0(SIZE_Bc,POS_Bc)) | \ + ((Instruction)(b)< R/K(C)) */ +OP_TESTGE,/* B C test := (R(B) >= R/K(C)) */ -OP_SETLIST,/* A B v_n-v_1 v_b v_b v_b[i+a*FPF]=v_i */ -OP_SETMAP,/* U v_n k_n - v_1 k_1 v_u v_u v_u[k_i]=v_i */ +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_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_NILJMP,/* A R(A) := nil; PC++; */ -OP_JMPNE,/* J y x - (x~=y)? PC+=s */ -OP_JMPEQ,/* J y x - (x==y)? PC+=s */ -OP_JMPLT,/* J y x - (xy)? PC+=s */ -OP_JMPGE,/* J y x - (x>=y)? PC+=s */ +OP_CALL,/* A B C R(A), ... ,R(A+C-1) := R(A)(R(A+1), ... ,R(B-1))*/ +OP_RETURN,/* A B return R(A), ... ,R(B-1) (see (3)) */ -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_FORPREP,/* A sBc */ +OP_FORLOOP,/* A sBc */ -OP_PUSHNILJMP,/* - - nil PC++; */ +OP_TFORPREP,/* A sBc */ +OP_TFORLOOP,/* A sBc */ -OP_FORPREP,/* J */ -OP_FORLOOP,/* J */ - -OP_LFORPREP,/* J */ -OP_LFORLOOP,/* J */ - -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 index a5a56829..2236d79d 100644 --- 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(" 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; if->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 */ - } - else /* more values than variables */ - luaK_setcallreturns(fs, 0); /* call should provide no value */ + 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); + } } - /* 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; if->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(" expected")); + check_condition(&lexstate, (lexstate.t.token == TK_EOS), + l_s(" 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(" 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); + 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 */ + } } - 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; - } - 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 index a754b3be..b55270c1 100644 --- 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 index 77fc6048..95d7813d 100644 --- 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; pcsizecode; 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; isizekstr; i++) { + for (i=0; isizek; 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 index 9c1b13d0..4cead1d9 100644 --- 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; + case OP_MOVE: { + setobj(RA(i), RB(i)); break; } - case OP_PUSHNIL: { - int n = GETARG_U(i); - lua_assert(n>0); + case OP_LOADK: { + setobj(RA(i), KBc(i)); + break; + } + case OP_LOADINT: { + setnvalue(RA(i), (lua_Number)GETARG_sBc(i)); + break; + } + case OP_LOADUPVAL: { + setobj(RA(i), cl->upvalue+GETARG_Bc(i)); + break; + } + case OP_LOADNIL: { + TObject *ra = RA(i); + TObject *rb = RB(i); do { - setnilvalue(top++); - } while (--n > 0); - break; - } - case OP_POP: { - top -= GETARG_U(i); - break; - } - case OP_PUSHINT: { - setnvalue(top, (lua_Number)GETARG_S(i)); - top++; - break; - } - case OP_PUSHSTRING: { - setsvalue(top, tf->kstr[GETARG_U(i)]); - top++; - break; - } - case OP_PUSHNUM: { - setnvalue(top, tf->knum[GETARG_U(i)]); - top++; - break; - } - case OP_PUSHNEGNUM: { - setnvalue(top, -tf->knum[GETARG_U(i)]); - top++; - break; - } - case OP_PUSHUPVALUE: { - setobj(top++, &cl->upvalue[GETARG_U(i)]); - break; - } - case OP_GETLOCAL: { - setobj(top++, base+GETARG_U(i)); + setnilvalue(ra++); + } while (ra <= rb); break; } case OP_GETGLOBAL: { - luaV_getglobal(L, tf->kstr[GETARG_U(i)], top); - top++; + lua_assert(ttype(KBc(i)) == LUA_TSTRING); + luaV_getglobal(L, tsvalue(KBc(i)), RA(i)); break; } case OP_GETTABLE: { - top--; - luaV_gettable(L, top-1, top, top-1); - break; - } - case OP_GETDOTTED: { - setsvalue(top, tf->kstr[GETARG_U(i)]); - luaV_gettable(L, top-1, top, top-1); - break; - } - case OP_GETINDEXED: { - luaV_gettable(L, top-1, base+GETARG_U(i), top-1); - break; - } - case OP_PUSHSELF: { - setobj(top, top-1); - setsvalue(top+1, tf->kstr[GETARG_U(i)]); - luaV_gettable(L, top-1, top+1, top-1); - top++; - break; - } - case OP_CREATETABLE: { - luaC_checkGC(L); - sethvalue(top, luaH_new(L, GETARG_U(i))); - top++; - break; - } - case OP_SETLOCAL: { - setobj(base+GETARG_U(i), --top); + luaV_gettable(L, RB(i), RKC(i), RA(i)); break; } case OP_SETGLOBAL: { - top--; - luaV_setglobal(L, tf->kstr[GETARG_U(i)], top); + lua_assert(ttype(KBc(i)) == LUA_TSTRING); + luaV_setglobal(L, tsvalue(KBc(i)), RA(i)); break; } case OP_SETTABLE: { - StkId t = top-GETARG_A(i); - luaV_settable(L, t, t+1, top-1); - top -= GETARG_B(i); /* pop values */ + luaV_settable(L, RB(i), RKC(i), RA(i)); break; } - case OP_SETLIST: { - int aux = GETARG_A(i) * LFIELDS_PER_FLUSH; - TObject *t = base+GETARG_B(i); - Hash *h = hvalue(t); - int n; - for (n = top-t-1; n; n--) - setobj(luaH_setnum(L, h, n+aux), --top); + case OP_NEWTABLE: { + luaC_checkGC(L); + sethvalue(RA(i), luaH_new(L, GETARG_Bc(i))); break; } - case OP_SETMAP: { - TObject *t = base+GETARG_U(i); - Hash *h = hvalue(t); - while (top-1 > t) { - top-=2; - setobj(luaH_set(L, h, top), top+1); - } + case OP_SELF: { + StkId ra = RA(i); + StkId rb = RB(i); + setobj(ra+1, rb); + luaV_gettable(L, rb, RKC(i), ra); break; } case OP_ADD: { - if (tonumber(top-2) || tonumber(top-1)) - call_arith(L, top-2, TM_ADD); - else - nvalue(top-2) += nvalue(top-1); - top--; - break; - } - case OP_ADDI: { - if (tonumber(top-1)) { - setnvalue(top, (lua_Number)GETARG_S(i)); - call_arith(L, top-1, TM_ADD); - } - else - nvalue(top-1) += (lua_Number)GETARG_S(i); + Arith( + , TM_ADD); break; } case OP_SUB: { - if (tonumber(top-2) || tonumber(top-1)) - call_arith(L, top-2, TM_SUB); - else - nvalue(top-2) -= nvalue(top-1); - top--; + Arith( - , TM_SUB); break; } - case OP_MULT: { - if (tonumber(top-2) || tonumber(top-1)) - call_arith(L, top-2, TM_MUL); - else - nvalue(top-2) *= nvalue(top-1); - top--; + case OP_MUL: { + Arith( * , TM_MUL); break; } case OP_DIV: { - if (tonumber(top-2) || tonumber(top-1)) - call_arith(L, top-2, TM_DIV); - else - nvalue(top-2) /= nvalue(top-1); - top--; + Arith( / , TM_DIV); break; } case OP_POW: { - if (!call_binTM(L, top-2, top-1, top-2, TM_POW)) - luaD_error(L, l_s("undefined operation")); - top--; + call_arith(L, RB(i), RKC(i), RA(i), TM_POW); break; } - case OP_CONCAT: { - int n = GETARG_U(i); - luaV_strconc(L, n, top); - top -= n-1; - luaC_checkGC(L); - break; - } - case OP_MINUS: { - if (tonumber(top-1)) { - setnilvalue(top); - call_arith(L, top-1, TM_UNM); + case OP_UNM: { + const TObject *rb = RB(i); + StkId ra = RA(i); + if (ttype(rb) == LUA_TNUMBER || (rb=luaV_tonumber(rb, ra)) != NULL) { + setnvalue(ra, -nvalue(rb)); + } + else { + TObject temp; + setnilvalue(&temp); + call_arith(L, RB(i), &temp, ra, TM_UNM); } - else - nvalue(top-1) = -nvalue(top-1); break; } case OP_NOT: { - ttype(top-1) = - (ttype(top-1) == LUA_TNIL) ? LUA_TNUMBER : LUA_TNIL; - nvalue(top-1) = 1; + if (ttype(RB(i)) == LUA_TNIL) { + setnvalue(RA(i), 1); + } else { + setnilvalue(RA(i)); + } break; } - case OP_JMPNE: { - top -= 2; - if (!luaO_equalObj(top, top+1)) dojump(pc, i); - break; - } - case OP_JMPEQ: { - top -= 2; - if (luaO_equalObj(top, top+1)) dojump(pc, i); - break; - } - case OP_JMPLT: { - top -= 2; - if (luaV_lessthan(L, top, top+1)) dojump(pc, i); - break; - } - case OP_JMPLE: { /* a <= b === !(b b === (b= b === !(a c === (c= c === !(btop = 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 index a8513c8a..cbd47be4 100644 --- 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);