diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-02-05 20:39:12 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-02-05 20:39:12 -0200 |
| commit | 38b0e6128da7796300e2e8621e87835e16539f5b (patch) | |
| tree | 5b0a7ad2b0fb850d47f0566fd06b8cda013bbc8b | |
| parent | addbe8c8b0587fd316f33fb013034e035f9217ed (diff) | |
| download | lua-38b0e6128da7796300e2e8621e87835e16539f5b.tar.gz lua-38b0e6128da7796300e2e8621e87835e16539f5b.tar.bz2 lua-38b0e6128da7796300e2e8621e87835e16539f5b.zip | |
simpler implementation for `for' loops
| -rw-r--r-- | lcode.c | 11 | ||||
| -rw-r--r-- | lcode.h | 1 | ||||
| -rw-r--r-- | ldebug.c | 40 | ||||
| -rw-r--r-- | lopcodes.c | 12 | ||||
| -rw-r--r-- | lopcodes.h | 6 | ||||
| -rw-r--r-- | lparser.c | 15 | ||||
| -rw-r--r-- | lvm.c | 67 |
7 files changed, 57 insertions, 95 deletions
| @@ -77,17 +77,6 @@ static void luaK_fixjump (FuncState *fs, int pc, int dest) { | |||
| 77 | 77 | ||
| 78 | 78 | ||
| 79 | /* | 79 | /* |
| 80 | ** prep-for instructions (OP_FORPREP & OP_TFORPREP) have a negated jump, | ||
| 81 | ** as they simulate the real jump... | ||
| 82 | */ | ||
| 83 | void luaK_fixfor (FuncState *fs, int pc, int dest) { | ||
| 84 | Instruction *jmp = &fs->f->code[pc]; | ||
| 85 | int offset = dest-(pc+1); | ||
| 86 | SETARG_sBc(*jmp, -offset); | ||
| 87 | } | ||
| 88 | |||
| 89 | |||
| 90 | /* | ||
| 91 | ** returns current `pc' and marks it as a jump target (to avoid wrong | 80 | ** returns current `pc' and marks it as a jump target (to avoid wrong |
| 92 | ** optimizations with consecutive instructions not in the same basic block). | 81 | ** optimizations with consecutive instructions not in the same basic block). |
| 93 | ** discharge list of jumps to last target. | 82 | ** discharge list of jumps to last target. |
| @@ -57,7 +57,6 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); | |||
| 57 | void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults); | 57 | void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults); |
| 58 | int luaK_jump (FuncState *fs); | 58 | int luaK_jump (FuncState *fs); |
| 59 | void luaK_patchlist (FuncState *fs, int list, int target); | 59 | void luaK_patchlist (FuncState *fs, int list, int target); |
| 60 | void luaK_fixfor (FuncState *fs, int pc, int dest); | ||
| 61 | void luaK_concat (FuncState *fs, int *l1, int l2); | 60 | void luaK_concat (FuncState *fs, int *l1, int l2); |
| 62 | int luaK_getlabel (FuncState *fs); | 61 | int luaK_getlabel (FuncState *fs); |
| 63 | void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); | 62 | void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v); |
| @@ -54,13 +54,6 @@ LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func) { | |||
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | 56 | ||
| 57 | static CallInfo *ci_stack (lua_State *L, StkId obj) { | ||
| 58 | CallInfo *ci = L->ci; | ||
| 59 | while (ci->base > obj && ci > L->base_ci) ci--; | ||
| 60 | return ci; | ||
| 61 | } | ||
| 62 | |||
| 63 | |||
| 64 | LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { | 57 | LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { |
| 65 | int status; | 58 | int status; |
| 66 | lua_lock(L); | 59 | lua_lock(L); |
| @@ -283,6 +276,7 @@ static int checklineinfo (const Proto *pt) { | |||
| 283 | int *lineinfo = pt->lineinfo; | 276 | int *lineinfo = pt->lineinfo; |
| 284 | if (lineinfo == NULL) return 1; | 277 | if (lineinfo == NULL) return 1; |
| 285 | check(pt->sizelineinfo >= 2 && lineinfo[pt->sizelineinfo-1] == MAX_INT); | 278 | check(pt->sizelineinfo >= 2 && lineinfo[pt->sizelineinfo-1] == MAX_INT); |
| 279 | lua_assert(luaG_getline(lineinfo, pt->sizecode-1, 1, NULL) < MAX_INT); | ||
| 286 | if (*lineinfo < 0) lineinfo++; | 280 | if (*lineinfo < 0) lineinfo++; |
| 287 | check(*lineinfo == 0); | 281 | check(*lineinfo == 0); |
| 288 | return 1; | 282 | return 1; |
| @@ -292,7 +286,7 @@ static int checklineinfo (const Proto *pt) { | |||
| 292 | static int precheck (const Proto *pt) { | 286 | static int precheck (const Proto *pt) { |
| 293 | check(checklineinfo(pt)); | 287 | check(checklineinfo(pt)); |
| 294 | check(pt->maxstacksize <= MAXSTACK); | 288 | check(pt->maxstacksize <= MAXSTACK); |
| 295 | check(pt->numparams+pt->is_vararg <= pt->maxstacksize); | 289 | lua_assert(pt->numparams+pt->is_vararg <= pt->maxstacksize); |
| 296 | check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); | 290 | check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); |
| 297 | return 1; | 291 | return 1; |
| 298 | } | 292 | } |
| @@ -381,7 +375,9 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { | |||
| 381 | check(c < MAXSTACK && b < c); | 375 | check(c < MAXSTACK && b < c); |
| 382 | break; | 376 | break; |
| 383 | } | 377 | } |
| 384 | case OP_JMP: { | 378 | case OP_JMP: |
| 379 | case OP_FORLOOP: | ||
| 380 | case OP_TFORLOOP: { | ||
| 385 | int dest = pc+1+b; | 381 | int dest = pc+1+b; |
| 386 | check(0 <= dest && dest < pt->sizecode); | 382 | check(0 <= dest && dest < pt->sizecode); |
| 387 | /* not full check and jump is forward and do not skip `lastpc'? */ | 383 | /* not full check and jump is forward and do not skip `lastpc'? */ |
| @@ -407,21 +403,6 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { | |||
| 407 | if (b > 0) checkreg(pt, a+b-1); | 403 | if (b > 0) checkreg(pt, a+b-1); |
| 408 | break; | 404 | break; |
| 409 | } | 405 | } |
| 410 | case OP_FORPREP: | ||
| 411 | case OP_TFORPREP: { | ||
| 412 | int dest = pc-b; /* jump is negated here */ | ||
| 413 | check(0 <= dest && dest < pt->sizecode && | ||
| 414 | GET_OPCODE(pt->code[dest]) == op+1); | ||
| 415 | break; | ||
| 416 | } | ||
| 417 | case OP_FORLOOP: | ||
| 418 | case OP_TFORLOOP: { | ||
| 419 | int dest = pc+b; | ||
| 420 | check(0 <= dest && dest < pt->sizecode && | ||
| 421 | pt->code[dest] == SET_OPCODE(i, op-1)); | ||
| 422 | checkreg(pt, a + ((op == OP_FORLOOP) ? 2 : 3)); | ||
| 423 | break; | ||
| 424 | } | ||
| 425 | case OP_SETLIST: { | 406 | case OP_SETLIST: { |
| 426 | checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1); | 407 | checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1); |
| 427 | break; | 408 | break; |
| @@ -445,12 +426,11 @@ int luaG_checkcode (const Proto *pt) { | |||
| 445 | } | 426 | } |
| 446 | 427 | ||
| 447 | 428 | ||
| 448 | static const char *getobjname (lua_State *L, StkId obj, const char **name) { | 429 | static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, |
| 449 | CallInfo *ci = ci_stack(L, obj); | 430 | const char **name) { |
| 450 | if (isLmark(ci)) { /* an active Lua function? */ | 431 | if (isLmark(ci)) { /* an active Lua function? */ |
| 451 | Proto *p = ci_func(ci)->l.p; | 432 | Proto *p = ci_func(ci)->l.p; |
| 452 | int pc = currentpc(L, ci); | 433 | int pc = currentpc(L, ci); |
| 453 | int stackpos = obj - ci->base; | ||
| 454 | Instruction i; | 434 | Instruction i; |
| 455 | *name = luaF_getlocalname(p, stackpos+1, pc); | 435 | *name = luaF_getlocalname(p, stackpos+1, pc); |
| 456 | if (*name) /* is a local? */ | 436 | if (*name) /* is a local? */ |
| @@ -467,7 +447,7 @@ static const char *getobjname (lua_State *L, StkId obj, const char **name) { | |||
| 467 | int a = GETARG_A(i); | 447 | int a = GETARG_A(i); |
| 468 | int b = GETARG_B(i); /* move from `b' to `a' */ | 448 | int b = GETARG_B(i); /* move from `b' to `a' */ |
| 469 | if (b < a) | 449 | if (b < a) |
| 470 | return getobjname(L, ci->base+b, name); /* get name for `b' */ | 450 | return getobjname(L, ci, b, name); /* get name for `b' */ |
| 471 | break; | 451 | break; |
| 472 | } | 452 | } |
| 473 | case OP_GETTABLE: | 453 | case OP_GETTABLE: |
| @@ -496,7 +476,7 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { | |||
| 496 | Instruction i; | 476 | Instruction i; |
| 497 | i = p->code[pc]; | 477 | i = p->code[pc]; |
| 498 | return (GET_OPCODE(i) == OP_CALL | 478 | return (GET_OPCODE(i) == OP_CALL |
| 499 | ? getobjname(L, ci->base+GETARG_A(i), name) | 479 | ? getobjname(L, ci, GETARG_A(i), name) |
| 500 | : NULL); /* no useful name found */ | 480 | : NULL); /* no useful name found */ |
| 501 | } | 481 | } |
| 502 | } | 482 | } |
| @@ -504,7 +484,7 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { | |||
| 504 | 484 | ||
| 505 | void luaG_typeerror (lua_State *L, StkId o, const char *op) { | 485 | void luaG_typeerror (lua_State *L, StkId o, const char *op) { |
| 506 | const char *name; | 486 | const char *name; |
| 507 | const char *kind = getobjname(L, o, &name); | 487 | const char *kind = getobjname(L, L->ci, o - L->ci->base, &name); /* ?? */ |
| 508 | const char *t = luaT_typenames[ttype(o)]; | 488 | const char *t = luaT_typenames[ttype(o)]; |
| 509 | if (kind) | 489 | if (kind) |
| 510 | luaO_verror(L, "attempt to %.30s %.20s `%.40s' (a %.10s value)", | 490 | luaO_verror(L, "attempt to %.30s %.20s `%.40s' (a %.10s value)", |
| @@ -46,9 +46,7 @@ const char *const luaP_opnames[] = { | |||
| 46 | "TESTF", | 46 | "TESTF", |
| 47 | "CALL", | 47 | "CALL", |
| 48 | "RETURN", | 48 | "RETURN", |
| 49 | "FORPREP", | ||
| 50 | "FORLOOP", | 49 | "FORLOOP", |
| 51 | "TFORPREP", | ||
| 52 | "TFORLOOP", | 50 | "TFORLOOP", |
| 53 | "SETLIST", | 51 | "SETLIST", |
| 54 | "SETLISTO", | 52 | "SETLISTO", |
| @@ -60,10 +58,10 @@ const char *const luaP_opnames[] = { | |||
| 60 | 58 | ||
| 61 | #define opmode(t,x,b,c,sa,k,m) (((t)<<OpModeT) | \ | 59 | #define opmode(t,x,b,c,sa,k,m) (((t)<<OpModeT) | \ |
| 62 | ((b)<<OpModeBreg) | ((c)<<OpModeCreg) | \ | 60 | ((b)<<OpModeBreg) | ((c)<<OpModeCreg) | \ |
| 63 | ((sa)<<OpModesetA) | ((k)<<OpModeK) | (m)) | 61 | ((sa)<<OpModesetA) | ((k)<<OpModeK) | (x)<<OpModeNoTrace | (m)) |
| 64 | 62 | ||
| 65 | const lu_byte luaP_opmodes[NUM_OPCODES] = { | 63 | const lu_byte luaP_opmodes[NUM_OPCODES] = { |
| 66 | /* T _ B C sA K mode opcode */ | 64 | /* T n B C sA K mode opcode */ |
| 67 | opmode(0,0,1,0, 1,0,iABC) /* OP_MOVE */ | 65 | opmode(0,0,1,0, 1,0,iABC) /* OP_MOVE */ |
| 68 | ,opmode(0,0,0,0, 1,1,iABc) /* OP_LOADK */ | 66 | ,opmode(0,0,0,0, 1,1,iABc) /* OP_LOADK */ |
| 69 | ,opmode(0,0,0,0, 1,0,iABC) /* OP_LOADBOOL */ | 67 | ,opmode(0,0,0,0, 1,0,iABC) /* OP_LOADBOOL */ |
| @@ -95,10 +93,8 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = { | |||
| 95 | ,opmode(1,0,1,0, 1,0,iABC) /* OP_TESTF */ | 93 | ,opmode(1,0,1,0, 1,0,iABC) /* OP_TESTF */ |
| 96 | ,opmode(0,0,0,0, 0,0,iABC) /* OP_CALL */ | 94 | ,opmode(0,0,0,0, 0,0,iABC) /* OP_CALL */ |
| 97 | ,opmode(0,0,0,0, 0,0,iABC) /* OP_RETURN */ | 95 | ,opmode(0,0,0,0, 0,0,iABC) /* OP_RETURN */ |
| 98 | ,opmode(0,0,0,0, 0,0,iAsBc) /* OP_FORPREP */ | 96 | ,opmode(0,1,0,0, 0,0,iAsBc) /* OP_FORLOOP */ |
| 99 | ,opmode(0,0,0,0, 0,0,iAsBc) /* OP_FORLOOP */ | 97 | ,opmode(0,1,0,0, 0,0,iAsBc) /* OP_TFORLOOP */ |
| 100 | ,opmode(0,0,0,0, 0,0,iAsBc) /* OP_TFORPREP */ | ||
| 101 | ,opmode(0,0,0,0, 0,0,iAsBc) /* OP_TFORLOOP */ | ||
| 102 | ,opmode(0,0,0,0, 0,0,iABc) /* OP_SETLIST */ | 98 | ,opmode(0,0,0,0, 0,0,iABc) /* OP_SETLIST */ |
| 103 | ,opmode(0,0,0,0, 0,0,iABc) /* OP_SETLISTO */ | 99 | ,opmode(0,0,0,0, 0,0,iABc) /* OP_SETLISTO */ |
| 104 | ,opmode(0,0,0,0, 0,0,iABC) /* OP_CLOSE */ | 100 | ,opmode(0,0,0,0, 0,0,iABC) /* OP_CLOSE */ |
| @@ -169,10 +169,7 @@ OP_TESTF,/* A B if not (R(B)) then R(A) := R(B) else pc++ */ | |||
| 169 | OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))*/ | 169 | OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))*/ |
| 170 | OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see (3)) */ | 170 | OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see (3)) */ |
| 171 | 171 | ||
| 172 | OP_FORPREP,/* A sBc */ | ||
| 173 | OP_FORLOOP,/* A sBc */ | 172 | OP_FORLOOP,/* A sBc */ |
| 174 | |||
| 175 | OP_TFORPREP,/* A sBc */ | ||
| 176 | OP_TFORLOOP,/* A sBc */ | 173 | OP_TFORLOOP,/* A sBc */ |
| 177 | 174 | ||
| 178 | OP_SETLIST,/* A Bc R(A)[Bc-Bc%FPF+i] := R(A+i), 1 <= i <= Bc%FPF+1 */ | 175 | OP_SETLIST,/* A Bc R(A)[Bc-Bc%FPF+i] := R(A+i), 1 <= i <= Bc%FPF+1 */ |
| @@ -206,7 +203,8 @@ enum OpModeMask { | |||
| 206 | OpModeCreg, /* C is a register/constant */ | 203 | OpModeCreg, /* C is a register/constant */ |
| 207 | OpModesetA, /* instruction set register A */ | 204 | OpModesetA, /* instruction set register A */ |
| 208 | OpModeK, /* Bc is a constant */ | 205 | OpModeK, /* Bc is a constant */ |
| 209 | OpModeT /* operator is a test */ | 206 | OpModeT, /* operator is a test */ |
| 207 | OpModeNoTrace /* operator should not be traced */ | ||
| 210 | }; | 208 | }; |
| 211 | 209 | ||
| 212 | extern const lu_byte luaP_opmodes[NUM_OPCODES]; | 210 | extern const lu_byte luaP_opmodes[NUM_OPCODES]; |
| @@ -955,17 +955,17 @@ static void exp1 (LexState *ls) { | |||
| 955 | } | 955 | } |
| 956 | 956 | ||
| 957 | 957 | ||
| 958 | static void forbody (LexState *ls, int nvar, OpCode prepfor, OpCode loopfor) { | 958 | static void forbody (LexState *ls, int nvar, OpCode loopfor) { |
| 959 | /* forbody -> DO block END */ | 959 | /* forbody -> DO block END */ |
| 960 | FuncState *fs = ls->fs; | 960 | FuncState *fs = ls->fs; |
| 961 | int basereg = fs->freereg - nvar; | 961 | int basereg = fs->freereg - nvar; |
| 962 | int prep = luaK_codeAsBc(fs, prepfor, basereg, NO_JUMP); | 962 | int prep = luaK_jump(fs); |
| 963 | int blockinit = luaK_getlabel(fs); | 963 | int blockinit = luaK_getlabel(fs); |
| 964 | check(ls, TK_DO); | 964 | check(ls, TK_DO); |
| 965 | adjustlocalvars(ls, nvar); /* scope for control variables */ | 965 | adjustlocalvars(ls, nvar); /* scope for control variables */ |
| 966 | block(ls); | 966 | block(ls); |
| 967 | luaK_patchlist(fs, prep, luaK_getlabel(fs)); | ||
| 967 | luaK_patchlist(fs, luaK_codeAsBc(fs, loopfor, basereg, NO_JUMP), blockinit); | 968 | luaK_patchlist(fs, luaK_codeAsBc(fs, loopfor, basereg, NO_JUMP), blockinit); |
| 968 | luaK_fixfor(fs, prep, luaK_getlabel(fs)); | ||
| 969 | removelocalvars(ls, nvar, 1); | 969 | removelocalvars(ls, nvar, 1); |
| 970 | } | 970 | } |
| 971 | 971 | ||
| @@ -986,13 +986,15 @@ static void fornum (LexState *ls, TString *varname) { | |||
| 986 | new_localvar(ls, varname, 0); | 986 | new_localvar(ls, varname, 0); |
| 987 | new_localvarstr(ls, "(limit)", 1); | 987 | new_localvarstr(ls, "(limit)", 1); |
| 988 | new_localvarstr(ls, "(step)", 2); | 988 | new_localvarstr(ls, "(step)", 2); |
| 989 | forbody(ls, 3, OP_FORPREP, OP_FORLOOP); | 989 | luaK_codeABC(fs, OP_SUB, fs->freereg - 3, fs->freereg - 3, fs->freereg - 1); |
| 990 | forbody(ls, 3, OP_FORLOOP); | ||
| 990 | } | 991 | } |
| 991 | 992 | ||
| 992 | 993 | ||
| 993 | static void forlist (LexState *ls, TString *indexname) { | 994 | static void forlist (LexState *ls, TString *indexname) { |
| 994 | /* forlist -> NAME,NAME IN exp1 forbody */ | 995 | /* forlist -> NAME,NAME IN exp1 forbody */ |
| 995 | TString *valname; | 996 | TString *valname; |
| 997 | FuncState *fs = ls->fs; | ||
| 996 | check(ls, ','); | 998 | check(ls, ','); |
| 997 | valname = str_checkname(ls); | 999 | valname = str_checkname(ls); |
| 998 | next(ls); /* skip var name */ | 1000 | next(ls); /* skip var name */ |
| @@ -1002,8 +1004,9 @@ static void forlist (LexState *ls, TString *indexname) { | |||
| 1002 | new_localvarstr(ls, "(index)", 1); | 1004 | new_localvarstr(ls, "(index)", 1); |
| 1003 | new_localvar(ls, indexname, 2); | 1005 | new_localvar(ls, indexname, 2); |
| 1004 | new_localvar(ls, valname, 3); | 1006 | new_localvar(ls, valname, 3); |
| 1005 | luaK_reserveregs(ls->fs, 3); /* registers for control, index and val */ | 1007 | luaK_reserveregs(fs, 3); /* registers for control, index and val */ |
| 1006 | forbody(ls, 4, OP_TFORPREP, OP_TFORLOOP); | 1008 | luaK_codeABc(fs, OP_LOADK, fs->freereg - 3, luaK_numberK(fs, -1)); |
| 1009 | forbody(ls, 4, OP_TFORLOOP); | ||
| 1007 | } | 1010 | } |
| 1008 | 1011 | ||
| 1009 | 1012 | ||
| @@ -26,6 +26,9 @@ | |||
| 26 | #include "lvm.h" | 26 | #include "lvm.h" |
| 27 | 27 | ||
| 28 | 28 | ||
| 29 | /* limit for table tag-method chains (to avoid loops) */ | ||
| 30 | #define MAXTAGLOOP 10000 | ||
| 31 | |||
| 29 | 32 | ||
| 30 | static void luaV_checkGC (lua_State *L, StkId top) { | 33 | static void luaV_checkGC (lua_State *L, StkId top) { |
| 31 | if (G(L)->nblocks >= G(L)->GCthreshold) { | 34 | if (G(L)->nblocks >= G(L)->GCthreshold) { |
| @@ -65,6 +68,8 @@ static void traceexec (lua_State *L, lua_Hook linehook) { | |||
| 65 | int *lineinfo = ci_func(ci)->l.p->lineinfo; | 68 | int *lineinfo = ci_func(ci)->l.p->lineinfo; |
| 66 | int pc = cast(int, *ci->pc - ci_func(ci)->l.p->code) - 1; | 69 | int pc = cast(int, *ci->pc - ci_func(ci)->l.p->code) - 1; |
| 67 | int newline; | 70 | int newline; |
| 71 | if (testOpMode(GET_OPCODE(*(*ci->pc - 1)), OpModeNoTrace)) | ||
| 72 | return; | ||
| 68 | if (ci->line == -1) return; /* no linehooks for this function */ | 73 | if (ci->line == -1) return; /* no linehooks for this function */ |
| 69 | else if (ci->line == 0) { /* first linehook? */ | 74 | else if (ci->line == 0) { /* first linehook? */ |
| 70 | if (pc == 0) { /* function is starting now? */ | 75 | if (pc == 0) { /* function is starting now? */ |
| @@ -123,6 +128,7 @@ static void callTM (lua_State *L, const TObject *f, | |||
| 123 | */ | 128 | */ |
| 124 | void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) { | 129 | void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) { |
| 125 | const TObject *tm; | 130 | const TObject *tm; |
| 131 | int loop = 0; | ||
| 126 | init: | 132 | init: |
| 127 | if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */ | 133 | if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */ |
| 128 | Table *et = hvalue(t)->metatable; | 134 | Table *et = hvalue(t)->metatable; |
| @@ -145,6 +151,7 @@ void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) { | |||
| 145 | if (ttype(tm) == LUA_TFUNCTION) | 151 | if (ttype(tm) == LUA_TFUNCTION) |
| 146 | callTMres(L, tm, t, key, res); | 152 | callTMres(L, tm, t, key, res); |
| 147 | else { | 153 | else { |
| 154 | if (++loop == MAXTAGLOOP) luaD_error(L, "loop in gettable"); | ||
| 148 | t = (StkId)tm; /* ?? */ | 155 | t = (StkId)tm; /* ?? */ |
| 149 | goto init; /* return luaV_gettable(L, tm, key, res); */ | 156 | goto init; /* return luaV_gettable(L, tm, key, res); */ |
| 150 | } | 157 | } |
| @@ -156,6 +163,7 @@ void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) { | |||
| 156 | */ | 163 | */ |
| 157 | void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val) { | 164 | void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val) { |
| 158 | const TObject *tm; | 165 | const TObject *tm; |
| 166 | int loop = 0; | ||
| 159 | init: | 167 | init: |
| 160 | if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */ | 168 | if (ttype(t) == LUA_TTABLE) { /* `t' is a table? */ |
| 161 | Table *et = hvalue(t)->metatable; | 169 | Table *et = hvalue(t)->metatable; |
| @@ -173,6 +181,7 @@ void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val) { | |||
| 173 | if (ttype(tm) == LUA_TFUNCTION) | 181 | if (ttype(tm) == LUA_TFUNCTION) |
| 174 | callTM(L, tm, t, key, val); | 182 | callTM(L, tm, t, key, val); |
| 175 | else { | 183 | else { |
| 184 | if (++loop == MAXTAGLOOP) luaD_error(L, "loop in settable"); | ||
| 176 | t = (StkId)tm; /* ?? */ | 185 | t = (StkId)tm; /* ?? */ |
| 177 | goto init; /* luaV_settable(L, tm, key, val); */ | 186 | goto init; /* luaV_settable(L, tm, key, val); */ |
| 178 | } | 187 | } |
| @@ -301,8 +310,8 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { | |||
| 301 | #define Arith(op, optm) { \ | 310 | #define Arith(op, optm) { \ |
| 302 | const TObject *b = RB(i); const TObject *c = RKC(i); \ | 311 | const TObject *b = RB(i); const TObject *c = RKC(i); \ |
| 303 | TObject tempb, tempc; \ | 312 | TObject tempb, tempc; \ |
| 304 | if ((ttype(b) == LUA_TNUMBER || (b = luaV_tonumber(b, &tempb)) != NULL) && \ | 313 | if ((b = luaV_tonumber(b, &tempb)) != NULL && \ |
| 305 | (ttype(c) == LUA_TNUMBER || (c = luaV_tonumber(c, &tempc)) != NULL)) { \ | 314 | (c = luaV_tonumber(c, &tempc)) != NULL) { \ |
| 306 | setnvalue(ra, nvalue(b) op nvalue(c)); \ | 315 | setnvalue(ra, nvalue(b) op nvalue(c)); \ |
| 307 | } else \ | 316 | } else \ |
| 308 | call_arith(L, RB(i), RKC(i), ra, optm); \ | 317 | call_arith(L, RB(i), RKC(i), ra, optm); \ |
| @@ -423,7 +432,7 @@ StkId luaV_execute (lua_State *L) { | |||
| 423 | } | 432 | } |
| 424 | case OP_UNM: { | 433 | case OP_UNM: { |
| 425 | const TObject *rb = RB(i); | 434 | const TObject *rb = RB(i); |
| 426 | if (ttype(rb) == LUA_TNUMBER || (rb=luaV_tonumber(rb, ra)) != NULL) { | 435 | if ((rb=luaV_tonumber(rb, ra)) != NULL) { |
| 427 | setnvalue(ra, -nvalue(rb)); | 436 | setnvalue(ra, -nvalue(rb)); |
| 428 | } | 437 | } |
| 429 | else { | 438 | else { |
| @@ -441,7 +450,7 @@ StkId luaV_execute (lua_State *L) { | |||
| 441 | case OP_CONCAT: { | 450 | case OP_CONCAT: { |
| 442 | int b = GETARG_B(i); | 451 | int b = GETARG_B(i); |
| 443 | int c = GETARG_C(i); | 452 | int c = GETARG_C(i); |
| 444 | luaV_strconc(L, c-b+1, c); /* this call may change `base' (and `ra') */ | 453 | luaV_strconc(L, c-b+1, c); /* may change `base' (and `ra') */ |
| 445 | setobj(base+GETARG_A(i), base+b); | 454 | setobj(base+GETARG_A(i), base+b); |
| 446 | luaV_checkGC(L, base+c+1); | 455 | luaV_checkGC(L, base+c+1); |
| 447 | break; | 456 | break; |
| @@ -532,53 +541,41 @@ StkId luaV_execute (lua_State *L) { | |||
| 532 | } | 541 | } |
| 533 | break; | 542 | break; |
| 534 | } | 543 | } |
| 535 | case OP_FORPREP: { | 544 | case OP_FORLOOP: { |
| 536 | if (luaV_tonumber(ra, ra) == NULL) | 545 | lua_Number step, index, limit; |
| 546 | int j = GETARG_sBc(i); | ||
| 547 | pc += j; /* jump back before tests (for error messages) */ | ||
| 548 | if (ttype(ra) != LUA_TNUMBER) | ||
| 537 | luaD_error(L, "`for' initial value must be a number"); | 549 | luaD_error(L, "`for' initial value must be a number"); |
| 538 | if (luaV_tonumber(ra+1, ra+1) == NULL) | 550 | if (luaV_tonumber(ra+1, ra+1) == NULL) |
| 539 | luaD_error(L, "`for' limit must be a number"); | 551 | luaD_error(L, "`for' limit must be a number"); |
| 540 | if (luaV_tonumber(ra+2, ra+2) == NULL) | 552 | if (luaV_tonumber(ra+2, ra+2) == NULL) |
| 541 | luaD_error(L, "`for' step must be a number"); | 553 | luaD_error(L, "`for' step must be a number"); |
| 542 | /* decrement index (to be incremented) */ | 554 | step = nvalue(ra+2); |
| 543 | chgnvalue(ra, nvalue(ra) - nvalue(ra+2)); | 555 | index = nvalue(ra) + step; /* increment index */ |
| 544 | pc += -GETARG_sBc(i); /* `jump' to loop end (delta is negated here) */ | 556 | limit = nvalue(ra+1); |
| 545 | /* store in `ra+1' total number of repetitions */ | 557 | if (step > 0 ? index <= limit : index >= limit) |
| 546 | chgnvalue(ra+1, (nvalue(ra+1)-nvalue(ra))/nvalue(ra+2)); | 558 | chgnvalue(ra, index); /* update index */ |
| 547 | /* go through */ | 559 | else |
| 548 | } | 560 | pc -= j; /* undo jump */ |
| 549 | case OP_FORLOOP: { | ||
| 550 | runtime_check(L, ttype(ra+1) == LUA_TNUMBER && | ||
| 551 | ttype(ra+2) == LUA_TNUMBER); | ||
| 552 | if (ttype(ra) != LUA_TNUMBER) | ||
| 553 | luaD_error(L, "`for' index must be a number"); | ||
| 554 | chgnvalue(ra+1, nvalue(ra+1) - 1); /* decrement counter */ | ||
| 555 | if (nvalue(ra+1) >= 0) { | ||
| 556 | chgnvalue(ra, nvalue(ra) + nvalue(ra+2)); /* increment index */ | ||
| 557 | dojump(pc, i); /* repeat loop */ | ||
| 558 | } | ||
| 559 | break; | 561 | break; |
| 560 | } | 562 | } |
| 561 | case OP_TFORPREP: { | ||
| 562 | if (ttype(ra) != LUA_TTABLE) | ||
| 563 | luaD_error(L, "`for' table must be a table"); | ||
| 564 | setnvalue(ra+1, -1); /* initial index */ | ||
| 565 | setnilvalue(ra+2); | ||
| 566 | setnilvalue(ra+3); | ||
| 567 | pc += -GETARG_sBc(i); /* `jump' to loop end (delta is negated here) */ | ||
| 568 | /* go through */ | ||
| 569 | } | ||
| 570 | case OP_TFORLOOP: { | 563 | case OP_TFORLOOP: { |
| 571 | Table *t; | 564 | Table *t; |
| 572 | int n; | 565 | int n; |
| 573 | runtime_check(L, ttype(ra) == LUA_TTABLE && | 566 | int j = GETARG_sBc(i); |
| 574 | ttype(ra+1) == LUA_TNUMBER); | 567 | pc += j; /* jump back before tests (for error messages) */ |
| 568 | if (ttype(ra) != LUA_TTABLE) | ||
| 569 | luaD_error(L, "`for' table must be a table"); | ||
| 570 | runtime_check(L, ttype(ra+1) == LUA_TNUMBER); | ||
| 575 | t = hvalue(ra); | 571 | t = hvalue(ra); |
| 576 | n = cast(int, nvalue(ra+1)); | 572 | n = cast(int, nvalue(ra+1)); |
| 577 | n = luaH_nexti(t, n, ra+2); | 573 | n = luaH_nexti(t, n, ra+2); |
| 578 | if (n != -1) { /* repeat loop? */ | 574 | if (n != -1) { /* repeat loop? */ |
| 579 | setnvalue(ra+1, n); /* index */ | 575 | setnvalue(ra+1, n); /* index */ |
| 580 | dojump(pc, i); /* repeat loop */ | ||
| 581 | } | 576 | } |
| 577 | else | ||
| 578 | pc -= j; /* undo jump */ | ||
| 582 | break; | 579 | break; |
| 583 | } | 580 | } |
| 584 | case OP_SETLIST: | 581 | case OP_SETLIST: |
