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: |