diff --git a/lcode.c b/lcode.c index 3f0418b9..76702869 100644 --- a/lcode.c +++ b/lcode.c @@ -5,6 +5,8 @@ */ +#define LUA_REENTRANT + #include "lcode.h" #include "ldo.h" #include "llex.h" @@ -47,9 +49,9 @@ int luaK_primitivecode (LexState *ls, Instruction i) { static void luaK_minus (LexState *ls) { Instruction *previous = previous_instruction(ls); switch(GET_OPCODE(*previous)) { - case PUSHINT: *previous = SETARG_S(*previous, -GETARG_S(*previous)); return; - case PUSHNUM: *previous = SET_OPCODE(*previous, PUSHNEGNUM); return; - case PUSHNEGNUM: *previous = SET_OPCODE(*previous, PUSHNUM); return; + case PUSHINT: SETARG_S(*previous, -GETARG_S(*previous)); return; + case PUSHNUM: SET_OPCODE(*previous, PUSHNEGNUM); return; + case PUSHNEGNUM: SET_OPCODE(*previous, PUSHNUM); return; default: luaK_primitivecode(ls, CREATE_0(MINUSOP)); } } @@ -59,7 +61,7 @@ static void luaK_gettable (LexState *ls) { Instruction *previous = previous_instruction(ls); luaK_deltastack(ls, -1); switch(GET_OPCODE(*previous)) { - case PUSHSTRING: *previous = SET_OPCODE(*previous, GETDOTTED); break; + case PUSHSTRING: SET_OPCODE(*previous, GETDOTTED); break; default: luaK_primitivecode(ls, CREATE_0(GETTABLE)); } } @@ -69,7 +71,7 @@ static void luaK_add (LexState *ls) { Instruction *previous = previous_instruction(ls); luaK_deltastack(ls, -1); switch(GET_OPCODE(*previous)) { - case PUSHINT: *previous = SET_OPCODE(*previous, ADDI); break; + case PUSHINT: SET_OPCODE(*previous, ADDI); break; default: luaK_primitivecode(ls, CREATE_0(ADDOP)); } } @@ -80,8 +82,8 @@ static void luaK_sub (LexState *ls) { luaK_deltastack(ls, -1); switch(GET_OPCODE(*previous)) { case PUSHINT: - *previous = SET_OPCODE(*previous, ADDI); - *previous = SETARG_S(*previous, -GETARG_S(*previous)); + SET_OPCODE(*previous, ADDI); + SETARG_S(*previous, -GETARG_S(*previous)); break; default: luaK_primitivecode(ls, CREATE_0(SUBOP)); } @@ -92,7 +94,7 @@ static void luaK_conc (LexState *ls) { Instruction *previous = previous_instruction(ls); luaK_deltastack(ls, -1); switch(GET_OPCODE(*previous)) { - case CONCOP: *previous = SETARG_U(*previous, GETARG_U(*previous)+1); break; + case CONCOP: SETARG_U(*previous, GETARG_U(*previous)+1); break; default: luaK_primitivecode(ls, CREATE_U(CONCOP, 2)); } } @@ -102,8 +104,8 @@ void luaK_retcode (LexState *ls, int nlocals, int nexps) { Instruction *previous = previous_instruction(ls); if (nexps > 0 && GET_OPCODE(*previous) == CALL) { LUA_ASSERT(ls->L, GETARG_B(*previous) == MULT_RET, "call should be open"); - *previous = SET_OPCODE(*previous, TAILCALL); - *previous = SETARG_B(*previous, nlocals); + SET_OPCODE(*previous, TAILCALL); + SETARG_B(*previous, nlocals); } else luaK_primitivecode(ls, CREATE_U(RETCODE, nlocals)); @@ -115,7 +117,7 @@ static void luaK_pushnil (LexState *ls, int n) { luaK_deltastack(ls, n); switch(GET_OPCODE(*previous)) { case PUSHNIL: - *previous = SETARG_U(*previous, GETARG_U(*previous)+n); + SETARG_U(*previous, GETARG_U(*previous)+n); break; default: luaK_primitivecode(ls, CREATE_U(PUSHNIL, n)); } @@ -132,7 +134,7 @@ void luaK_fixjump (LexState *ls, int pc, int dest) { FuncState *fs = ls->fs; Instruction *jmp = &fs->f->code[pc]; /* jump is relative to position following jump instruction */ - *jmp = SETARG_S(*jmp, dest-(pc+1)); + SETARG_S(*jmp, dest-(pc+1)); } @@ -213,7 +215,7 @@ void luaK_setcallreturns (LexState *ls, int nresults) { Instruction *i = previous_instruction(ls); if (GET_OPCODE(*i) == CALL) { /* expression is a function call? */ LUA_ASSERT(ls->L, GETARG_B(*i) == MULT_RET, "call should be open"); - *i = SETARG_B(*i, nresults); /* set nresults */ + SETARG_B(*i, nresults); /* set nresults */ luaK_deltastack(ls, nresults); /* push results */ } } @@ -224,41 +226,43 @@ static void assertglobal (LexState *ls, int index) { } -void luaK_tostack (LexState *ls, expdesc *var) { +static int discharge (LexState *ls, expdesc *var) { switch (var->k) { case VLOCAL: - luaK_U(ls, PUSHLOCAL, var->info, 1); + luaK_U(ls, PUSHLOCAL, var->u.index, 1); break; case VGLOBAL: - luaK_U(ls, GETGLOBAL, var->info, 1); - assertglobal(ls, var->info); /* make sure that there is a global */ + luaK_U(ls, GETGLOBAL, var->u.index, 1); + assertglobal(ls, var->u.index); /* make sure that there is a global */ break; case VINDEXED: luaK_gettable(ls); break; case VEXP: - return; /* exp result is already on stack */ + return 0; /* nothing to do */ } var->k = VEXP; + var->u.l.t = var->u.l.f = 0; + return 1; } -void luaK_1tostack (LexState *ls, expdesc *var) { - if (var->k == VEXP) +static void discharge1 (LexState *ls, expdesc *var) { + discharge(ls, var); + /* if it has jumps it is already discharged */ + if (var->u.l.t == 0 && var->u.l.f == 0) luaK_setcallreturns(ls, 1); /* call must return 1 value */ - else - luaK_tostack(ls, var); } - + void luaK_storevar (LexState *ls, const expdesc *var) { switch (var->k) { case VLOCAL: - luaK_U(ls, SETLOCAL, var->info, -1); + luaK_U(ls, SETLOCAL, var->u.index, -1); break; case VGLOBAL: - luaK_U(ls, SETGLOBAL, var->info, -1); - assertglobal(ls, var->info); /* make sure that there is a global */ + luaK_U(ls, SETGLOBAL, var->u.index, -1); + assertglobal(ls, var->u.index); /* make sure that there is a global */ break; case VINDEXED: luaK_0(ls, SETTABLEPOP, -3); @@ -269,40 +273,228 @@ void luaK_storevar (LexState *ls, const expdesc *var) { } +static OpCode invertjump (OpCode op) { + switch (op) { + case IFNEQJMP: return IFEQJMP; + case IFEQJMP: return IFNEQJMP; + case IFLTJMP: return IFGEJMP; + case IFLEJMP: return IFGTJMP; + case IFGTJMP: return IFLEJMP; + case IFGEJMP: return IFLTJMP; + default: + LUA_INTERNALERROR(NULL, "invalid jump instruction"); + return ENDCODE; /* to avoid warnings */ + } +} + + +static void insert_last (FuncState *fs, int *list) { + int temp = *list; + *list = fs->pc-1; + if (temp == 0) /* chain list */ + SETARG_S(fs->f->code[*list], 0); + else + SETARG_S(fs->f->code[*list], temp-fs->pc); +} + + +static void luaK_patchlistaux (LexState *ls, int list, int target, + OpCode special, int special_target) { + if (list != 0) { + Instruction *code = ls->fs->f->code; + for (;;) { + Instruction *i = &code[list]; + OpCode op = GET_OPCODE(*i); + int temp = GETARG_S(*i); + if (op == special) + SETARG_S(*i, special_target-(list+1)); + else { + SETARG_S(*i, target-(list+1)); + if (op == ONTJMP) + SET_OPCODE(*i, IFTJMP); + else if (op == ONFJMP) + SET_OPCODE(*i, IFFJMP); + } + if (temp == 0) return; + list += temp+1; + } + } +} + + +void luaK_patchlist (LexState *ls, int list, int target) { + luaK_patchlistaux(ls, list, target, ENDCODE, 0); +} + + +static int has_jumps (FuncState *fs, int list, OpCode ignore) { + if (list == 0) return 0; + else { + Instruction *code = fs->f->code; + for (;;) { + int temp = GETARG_S(code[list]); + if (GET_OPCODE(code[list]) != ignore) return 1; + else if (temp == 0) return 0; + list += temp+1; + } + } +} + + +static void concatlists (LexState *ls, int *l1, int l2) { + if (*l1 == 0) + *l1 = l2; + else if (l2 != 0) { + FuncState *fs = ls->fs; + int list = *l1; + for (;;) { /* traverse `l1' */ + int temp = GETARG_S(fs->f->code[list]); + if (temp == 0) { /* end of list? */ + SETARG_S(fs->f->code[list], l2-(list+1)); /* end points to `l2' */ + return; + } + list += temp+1; + } + } +} + + +void luaK_goiftrue (LexState *ls, expdesc *v, int keepvalue) { + FuncState *fs = ls->fs; + Instruction *previous; + discharge1(ls, v); + previous = &fs->f->code[fs->pc-1]; + if (ISJUMP(GET_OPCODE(*previous))) + SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous))); + else { + OpCode jump = keepvalue ? ONFJMP : IFFJMP; + luaK_S(ls, jump, 0, -1); + } + insert_last(fs, &v->u.l.f); + luaK_patchlist(ls, v->u.l.t, luaK_getlabel(ls)); + v->u.l.t = 0; +} + + +void luaK_goiffalse (LexState *ls, expdesc *v, int keepvalue) { + FuncState *fs = ls->fs; + Instruction *previous; + discharge1(ls, v); + previous = &fs->f->code[fs->pc-1]; + if (!ISJUMP(GET_OPCODE(*previous))) { + OpCode jump = keepvalue ? ONTJMP : IFTJMP; + luaK_S(ls, jump, 0, -1); + } + insert_last(fs, &v->u.l.t); + luaK_patchlist(ls, v->u.l.f, luaK_getlabel(ls)); + v->u.l.f = 0; +} + + +void luaK_tostack (LexState *ls, expdesc *v, int onlyone) { + if (discharge(ls, v)) return; + else { /* is an expression */ + FuncState *fs = ls->fs; + Instruction *previous = &fs->f->code[fs->pc-1]; + if (!ISJUMP(GET_OPCODE(*previous)) && v->u.l.f == 0 && v->u.l.t == 0) { + /* it is an expression without jumps */ + if (onlyone && v->k == VEXP) + luaK_setcallreturns(ls, 1); /* call must return 1 value */ + return; + } + else { /* expression has jumps... */ + int p_nil = 0; /* position of an eventual PUSHNIL */ + int p_1 = 0; /* position of an eventual PUSHINT */ + int final; /* position after whole expression */ + if (ISJUMP(GET_OPCODE(*previous))) { + insert_last(fs, &v->u.l.t); + p_nil = luaK_0(ls, PUSHNILJMP, 0); + p_1 = luaK_S(ls, PUSHINT, 1, 1); + } + else { /* still may need a PUSHNIL or a PUSHINT */ + int need_nil = has_jumps(fs, v->u.l.f, ONFJMP); /* needs a PUSHNIL? */ + int need_1 = has_jumps(fs, v->u.l.t, ONTJMP); /* needs a PUSHINT? */ + if (need_nil && need_1) { + luaK_S(ls, JMP, 2, 0); + p_nil = luaK_0(ls, PUSHNILJMP, 0); + p_1 = luaK_S(ls, PUSHINT, 1, 1); + } + else if (need_nil || need_1) { + luaK_S(ls, JMP, 1, 0); + if (need_nil) + p_nil = luaK_0(ls, PUSHNIL, 1); + else /* need_1 */ + p_1 = luaK_S(ls, PUSHINT, 1, 1); + } + } + final = luaK_getlabel(ls); + luaK_patchlistaux(ls, v->u.l.f, p_nil, ONFJMP, final); + luaK_patchlistaux(ls, v->u.l.t, p_1, ONTJMP, final); + v->u.l.f = v->u.l.t = 0; + } + } +} + + void luaK_prefix (LexState *ls, int op, expdesc *v) { - luaK_1tostack(ls, v); - if (op == '-') luaK_minus(ls); - else luaK_0(ls, NOTOP, 0); + if (op == '-') { + luaK_tostack(ls, v, 1); + luaK_minus(ls); + } + else { /* op == NOT */ + FuncState *fs = ls->fs; + Instruction *previous; + discharge1(ls, v); + previous = &fs->f->code[fs->pc-1]; + if (ISJUMP(GET_OPCODE(*previous))) + SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous))); + else + luaK_0(ls, NOTOP, 0); + /* 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, int op, expdesc *v) { - luaK_1tostack(ls, v); if (op == AND) - v->info = luaK_0(ls, ONFJMP, -1); + luaK_goiftrue(ls, v, 1); else if (op == OR) - v->info = luaK_0(ls, ONTJMP, -1); + luaK_goiffalse(ls, v, 1); + else + luaK_tostack(ls, v, 1); } void luaK_posfix (LexState *ls, int op, expdesc *v1, expdesc *v2) { - luaK_1tostack(ls, v2); - switch (op) { - case AND: case OR: - luaK_fixjump(ls, v1->info, luaK_getlabel(ls)); - break; - case '+': luaK_add(ls); break; - case '-': luaK_sub(ls); break; - case '*': luaK_0(ls, MULTOP, -1); break; - case '/': luaK_0(ls, DIVOP, -1); break; - case '^': luaK_0(ls, POWOP, -1); break; - case CONC: luaK_conc(ls); break; - case EQ: luaK_0(ls, EQOP, -1); break; - case NE: luaK_0(ls, NEQOP, -1); break; - case '>': luaK_0(ls, GTOP, -1); break; - case '<': luaK_0(ls, LTOP, -1); break; - case GE: luaK_0(ls, GEOP, -1); break; - case LE: luaK_0(ls, LEOP, -1); break; + if (op == AND) { + LUA_ASSERT(ls->L, v1->u.l.t == 0, "list must be closed"); + discharge1(ls, v2); + v1->u.l.t = v2->u.l.t; + concatlists(ls, &v1->u.l.f, v2->u.l.f); + } + else if (op == OR) { + LUA_ASSERT(ls->L, v1->u.l.f == 0, "list must be closed"); + discharge1(ls, v2); + v1->u.l.f = v2->u.l.f; + concatlists(ls, &v1->u.l.t, v2->u.l.t); + } + else { + luaK_tostack(ls, v2, 1); /* `v2' must have a value */ + switch (op) { + case '+': luaK_add(ls); break; + case '-': luaK_sub(ls); break; + case '*': luaK_0(ls, MULTOP, -1); break; + case '/': luaK_0(ls, DIVOP, -1); break; + case '^': luaK_0(ls, POWOP, -1); break; + case CONC: luaK_conc(ls); break; + case EQ: luaK_S(ls, IFEQJMP, 0, -2); break; + case NE: luaK_S(ls, IFNEQJMP, 0, -2); break; + case '>': luaK_S(ls, IFGTJMP, 0, -2); break; + case '<': luaK_S(ls, IFLTJMP, 0, -2); break; + case GE: luaK_S(ls, IFGEJMP, 0, -2); break; + case LE: luaK_S(ls, IFLEJMP, 0, -2); break; + } } } diff --git a/lcode.h b/lcode.h index 0f8eadc1..91674ad3 100644 --- a/lcode.h +++ b/lcode.h @@ -24,6 +24,9 @@ int luaK_primitivecode (LexState *ls, Instruction i); int luaK_code (LexState *ls, Instruction i, int delta); void luaK_retcode (LexState *ls, int nlocals, int nexps); void luaK_fixjump (LexState *ls, int pc, int dest); +void luaK_patchlist (LexState *ls, int list, int target); +void luaK_goiftrue (LexState *ls, expdesc *v, int keepvalue); +void luaK_goiffalse (LexState *ls, expdesc *v, int keepvalue); int luaK_getlabel (LexState *ls); void luaK_deltastack (LexState *ls, int delta); void luaK_kstr (LexState *ls, int c); @@ -31,8 +34,7 @@ void luaK_number (LexState *ls, real f); void luaK_adjuststack (LexState *ls, int n); int luaK_lastisopen (LexState *ls); void luaK_setcallreturns (LexState *ls, int nresults); -void luaK_tostack (LexState *ls, expdesc *var); -void luaK_1tostack (LexState *ls, expdesc *var); +void luaK_tostack (LexState *ls, expdesc *v, int onlyone); void luaK_storevar (LexState *ls, const expdesc *var); void luaK_prefix (LexState *ls, int op, expdesc *v); void luaK_infix (LexState *ls, int op, expdesc *v); diff --git a/lopcodes.h b/lopcodes.h index 1e3b9ee9..cd19ff3d 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -11,7 +11,7 @@ /*=========================================================================== We assume that instructions are unsigned numbers with 4 bytes. - All instructions have an opcode in the lower byte. Moreover, + All instructions have an opcode in the 8 bits. Moreover, an instruction can have 0, 1, or 2 arguments. There are 4 types of Instructions: type 0: no arguments @@ -24,21 +24,23 @@ is the usigned value minus 2^23. ===========================================================================*/ +#define SIZE_INSTRUCTION 32 + #define SIZE_OP 8 -#define SIZE_U 24 -#define POS_U 8 -#define SIZE_S 24 -#define POS_S 8 -#define SIZE_A 16 -#define POS_A 16 +#define SIZE_U (SIZE_INSTRUCTION-SIZE_OP) +#define POS_U SIZE_OP +#define SIZE_S (SIZE_INSTRUCTION-SIZE_OP) +#define POS_S SIZE_OP #define SIZE_B 8 -#define POS_B 8 +#define POS_B SIZE_OP +#define SIZE_A (SIZE_INSTRUCTION-(SIZE_OP+SIZE_B)) +#define POS_A (SIZE_OP+SIZE_B) #define EXCESS_S (1<<(SIZE_S-1)) /* == 2^23 */ /* creates a mask with `n' 1 bits at position `p' */ -#define MASK1(n,p) ((~((~0ul)<>POS_A)) #define GETARG_B(i) ((int)(((i)>>POS_B) & MASK1(SIZE_B,0))) -#define SET_OPCODE(i,o) (((i)&MASK0(SIZE_OP,0)) | (Instruction)(o)) -#define SETARG_U(i,u) (((i)&MASK0(SIZE_U,POS_U)) | ((Instruction)(u)<y)? 1 : nil */ -GEOP,/* - y x (x>=y)? 1 : nil */ - ADDOP,/* - y x x+y */ ADDI,/* S x x+s */ SUBOP,/* - y x x-y */ @@ -132,19 +131,32 @@ CONCOP,/* U v_u-v_1 v1..-..v_u */ MINUSOP,/* - x -x */ NOTOP,/* - x (x==nil)? 1 : nil */ +IFNEQJMP,/* J y x - (x~=y)? PC+=s */ +IFEQJMP,/* J y x - (x==y)? PC+=s */ +IFLTJMP,/* J y x - (xy)? PC+=s */ +IFGEJMP,/* J y x - (x>=y)? PC+=s */ + +IFTJMP,/* J x - (x!=nil)? PC+=s */ +IFFJMP,/* J x - (x==nil)? PC+=s */ ONTJMP,/* J x (x!=nil)? x : - (x!=nil)? PC+=s */ ONFJMP,/* J x (x==nil)? x : - (x==nil)? PC+=s */ JMP,/* J - - PC+=s */ -IFTJMP,/* J x - (x!=nil)? PC+=s */ -IFFJMP,/* J x - (x==nil)? PC+=s */ -CLOSURE,/* A B v_b-v_1 closure(CNST[a], v_b-v_1) */ +PUSHNILJMP,/* - - nil PC++; */ + +CLOSURE,/* A B v_b-v_1 closure(CNST[a], v_1-v_b) */ SETLINE/* U - - LINE=u */ } OpCode; + +#define ISJUMP(o) (IFNEQJMP <= (o) && (o) <= JMP) + + #define RFIELDS_PER_FLUSH 32 /* records (SETMAP) */ #define LFIELDS_PER_FLUSH 64 /* FPF - lists (SETLIST) (<=MAXARG_B) */ diff --git a/lparser.c b/lparser.c index 7fb5a0d7..a8198190 100644 --- a/lparser.c +++ b/lparser.c @@ -218,7 +218,7 @@ static void singlevar (LexState *ls, TaggedString *n, expdesc *var, int prev) { int i = aux_localname(fs, n); if (i >= 0) { /* local value? */ var->k = VLOCAL; - var->info = i; + var->u.index = i; } else { FuncState *level = fs; @@ -226,7 +226,7 @@ static void singlevar (LexState *ls, TaggedString *n, expdesc *var, int prev) { if (aux_localname(level, n) >= 0) luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str); var->k = VGLOBAL; - var->info = string_constant(ls, fs, n); + var->u.index = string_constant(ls, fs, n); } } @@ -237,7 +237,7 @@ static int indexupvalue (LexState *ls, TaggedString *n) { int i; singlevar(ls, n, &v, 1); for (i=0; inupvalues; i++) { - if (fs->upvalues[i].k == v.k && fs->upvalues[i].info == v.info) + if (fs->upvalues[i].k == v.k && fs->upvalues[i].u.index == v.u.index) return i; } /* new one */ @@ -296,9 +296,9 @@ static void code_args (LexState *ls, int nparams, int dots) { static int getvarname (LexState *ls, expdesc *var) { switch (var->k) { case VGLOBAL: - return var->info; + return var->u.index; case VLOCAL: - return string_constant(ls, ls->fs, ls->fs->localvar[var->info]); + return string_constant(ls, ls->fs, ls->fs->localvar[var->u.index]); break; default: error_unexpected(ls); /* there is no `var name' */ @@ -311,7 +311,7 @@ static void func_onstack (LexState *ls, FuncState *func) { TProtoFunc *f = ls->fs->f; int i; for (i=0; inupvalues; i++) - luaK_1tostack(ls, &func->upvalues[i]); + luaK_tostack(ls, &func->upvalues[i], 1); luaM_growvector(ls->L, f->kproto, f->nkproto, 1, TProtoFunc *, constantEM, MAXARG_A); f->kproto[f->nkproto++] = func->f; @@ -388,12 +388,12 @@ static int explist1 (LexState *ls) { expdesc v; expr(ls, &v); while (ls->token == ',') { - luaK_1tostack(ls, &v); /* gets only 1 value from previous expression */ + luaK_tostack(ls, &v, 1); /* gets only 1 value from previous expression */ next(ls); /* skip comma */ expr(ls, &v); n++; } - luaK_tostack(ls, &v); + luaK_tostack(ls, &v, 0); return n; } @@ -451,14 +451,14 @@ static void var_or_func_tail (LexState *ls, expdesc *v) { switch (ls->token) { case '.': /* var_or_func_tail -> '.' NAME */ next(ls); - luaK_1tostack(ls, v); /* `v' must be on stack */ + luaK_tostack(ls, v, 1); /* `v' must be on stack */ luaK_kstr(ls, checkname(ls)); v->k = VINDEXED; break; case '[': /* var_or_func_tail -> '[' exp1 ']' */ next(ls); - luaK_1tostack(ls, v); /* `v' must be on stack */ + luaK_tostack(ls, v, 1); /* `v' must be on stack */ v->k = VINDEXED; exp1(ls); check(ls, ']'); @@ -468,17 +468,19 @@ static void var_or_func_tail (LexState *ls, expdesc *v) { int name; next(ls); name = checkname(ls); - luaK_1tostack(ls, v); /* `v' must be on stack */ + luaK_tostack(ls, v, 1); /* `v' must be on stack */ luaK_U(ls, PUSHSELF, name, 1); funcargs(ls, 1); v->k = VEXP; + v->u.l.t = v->u.l.f = 0; break; } case '(': case STRING: case '{': /* var_or_func_tail -> funcargs */ - luaK_1tostack(ls, v); /* `v' must be on stack */ + luaK_tostack(ls, v, 1); /* `v' must be on stack */ funcargs(ls, 0); v->k = VEXP; + v->u.l.t = v->u.l.f = 0; break; default: return; /* should be follow... */ @@ -492,6 +494,7 @@ static void var_or_func (LexState *ls, expdesc *v) { if (optional(ls, '%')) { /* upvalue? */ pushupvalue(ls, str_checkname(ls)); v->k = VEXP; + v->u.l.t = v->u.l.f = 0; } else /* variable name */ singlevar(ls, str_checkname(ls), v, 0); @@ -591,7 +594,7 @@ static void constructor_part (LexState *ls, constdesc *cd) { cd->k = 1; /* record */ } else { - luaK_tostack(ls, &v); + luaK_tostack(ls, &v, 0); cd->n = listfields(ls); cd->k = 0; /* list */ } @@ -632,7 +635,7 @@ static void constructor (LexState *ls) { } check_match(ls, '}', '{', line); /* set initial table size */ - ls->fs->f->code[pc] = SETARG_U(ls->fs->f->code[pc], nelems); + SETARG_U(ls->fs->f->code[pc], nelems); } /* }====================================================================== */ @@ -691,13 +694,14 @@ static void simpleexp (LexState *ls, expdesc *v) { return; } v->k = VEXP; + v->u.l.t = v->u.l.f = 0; } static void exp1 (LexState *ls) { expdesc v; expr(ls, &v); - luaK_1tostack(ls, &v); + luaK_tostack(ls, &v, 1); } @@ -820,10 +824,13 @@ static void whilestat (LexState *ls, int line) { FuncState *fs = ls->fs; int while_init = luaK_getlabel(ls); int loopentry; /* point to jump to repeat the loop */ + int cond_init; /* init of condition, after the move */ int cond_size; + expdesc v; int i; next(ls); /* skip WHILE */ - exp1(ls); /* read condition */ + expr(ls, &v); /* read condition */ + luaK_goiffalse(ls, &v, 0); cond_size = fs->pc - while_init; /* save condition (to move it to after body) */ if (cond_size > MAX_WHILE_EXP) @@ -831,28 +838,31 @@ static void whilestat (LexState *ls, int line) { for (i=0; if->code[while_init+i]; /* go back to state prior condition */ fs->pc = while_init; - luaK_deltastack(ls, -1); luaK_S(ls, JMP, 0, 0); /* initial jump to condition */ check(ls, DO); loopentry = luaK_getlabel(ls); block(ls); check_match(ls, END, WHILE, line); - luaK_fixjump(ls, while_init, luaK_getlabel(ls)); - /* copy condition to new position, and correct stack */ + cond_init = luaK_getlabel(ls); + luaK_fixjump(ls, while_init, cond_init); + /* correct `v' and copy condition to new position */ + if (v.u.l.t != 0) v.u.l.t += cond_init-while_init; for (i=0; i REPEAT block UNTIL exp1 */ int repeat_init = luaK_getlabel(ls); + expdesc v; next(ls); block(ls); check_match(ls, UNTIL, REPEAT, line); - exp1(ls); - luaK_fixjump(ls, luaK_S(ls, IFFJMP, 0, -1), repeat_init); + expr(ls, &v); + luaK_goiftrue(ls, &v, 0); + luaK_patchlist(ls, v.u.l.f, repeat_init); } @@ -900,7 +910,7 @@ static int funcname (LexState *ls, expdesc *v) { if (ls->token == ':' || ls->token == '.') { needself = (ls->token == ':'); next(ls); - luaK_1tostack(ls, v); + luaK_tostack(ls, v, 1); luaK_kstr(ls, checkname(ls)); v->k = VINDEXED; } @@ -943,11 +953,11 @@ static void namestat (LexState *ls) { static void ifpart (LexState *ls, int line) { /* ifpart -> cond THEN block (ELSEIF ifpart | [ELSE block] END) */ FuncState *fs = ls->fs; - int c; /* address of the conditional jump */ + expdesc v; int elseinit; next(ls); /* skip IF or ELSEIF */ - exp1(ls); /* cond */ - c = luaK_S(ls, IFFJMP, 0, -1); /* 1st jump: over `then' part */ + expr(ls, &v); /* cond */ + luaK_goiftrue(ls, &v, 0); check(ls, THEN); block(ls); /* `then' part */ luaK_S(ls, JMP, 0, 0); /* 2nd jump: over `else' part */ @@ -960,13 +970,13 @@ static void ifpart (LexState *ls, int line) { check_match(ls, END, IF, line); } if (fs->pc > elseinit) { /* is there an `else' part? */ - luaK_fixjump(ls, c, elseinit); /* fix 1st jump to `else' part */ luaK_fixjump(ls, elseinit-1, luaK_getlabel(ls)); /* fix 2nd jump */ } else { /* no else part */ fs->pc--; /* remove 2nd jump */ - luaK_fixjump(ls, c, luaK_getlabel(ls)); /* fix 1st jump to `if' end */ + elseinit = luaK_getlabel(ls); /* `elseinit' points to end */ } + luaK_patchlist(ls, v.u.l.f, elseinit); /* fix 1st jump to `else' part */ } diff --git a/lparser.h b/lparser.h index adc7f012..01332478 100644 --- a/lparser.h +++ b/lparser.h @@ -47,15 +47,21 @@ */ typedef enum { - VGLOBAL, /* info is constant index of global name */ - VLOCAL, /* info is stack index */ + VGLOBAL, + VLOCAL, VINDEXED, - VEXP /* info is jump target if exp has internal jumps */ + VEXP } expkind; typedef struct expdesc { expkind k; - int info; + 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; + } u; } expdesc; diff --git a/lvm.c b/lvm.c index 4a24c43a..5fa8e1c6 100644 --- a/lvm.c +++ b/lvm.c @@ -478,36 +478,6 @@ StkId luaV_execute (lua_State *L, const Closure *cl, const TProtoFunc *tf, break; } - case NEQOP: - top--; - setbool(top-1, !luaO_equalObj(top-1, top)); - break; - - case EQOP: - top--; - setbool(top-1, luaO_equalObj(top-1, top)); - break; - - case LTOP: - top--; - setbool(top-1, luaV_lessthan(L, top-1, top, top+1)); - break; - - case LEOP: /* a <= b === !(b b === (b= b === !(a b === (b= b === !(a