diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-12-28 13:42:57 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-12-28 13:42:57 -0200 |
commit | cf7eff45f3abf2386d5392c0b431498bbb274ac7 (patch) | |
tree | 0eaafe3456bd03b241e447f1375296341fb648e8 | |
parent | 8691612f01ae4b32d861464032521d969766c1c5 (diff) | |
download | lua-cf7eff45f3abf2386d5392c0b431498bbb274ac7.tar.gz lua-cf7eff45f3abf2386d5392c0b431498bbb274ac7.tar.bz2 lua-cf7eff45f3abf2386d5392c0b431498bbb274ac7.zip |
keep control of stack top in Lua functions concentrated in 'luaV_execute'
-rw-r--r-- | ldebug.c | 9 | ||||
-rw-r--r-- | lgc.c | 11 | ||||
-rw-r--r-- | ltm.c | 22 | ||||
-rw-r--r-- | lvm.c | 46 |
4 files changed, 40 insertions, 48 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldebug.c,v 2.149 2017/12/15 13:07:10 roberto Exp roberto $ | 2 | ** $Id: ldebug.c,v 2.150 2017/12/20 14:58:05 roberto Exp roberto $ |
3 | ** Debug Interface | 3 | ** Debug Interface |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -737,8 +737,6 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { | |||
737 | const char *msg; | 737 | const char *msg; |
738 | va_list argp; | 738 | va_list argp; |
739 | luaC_checkGC(L); /* error message uses memory */ | 739 | luaC_checkGC(L); /* error message uses memory */ |
740 | if (isLuacode(ci)) | ||
741 | L->top = ci->top; /* prepare top */ | ||
742 | va_start(argp, fmt); | 740 | va_start(argp, fmt); |
743 | msg = luaO_pushvfstring(L, fmt, argp); /* format message */ | 741 | msg = luaO_pushvfstring(L, fmt, argp); /* format message */ |
744 | va_end(argp); | 742 | va_end(argp); |
@@ -762,7 +760,6 @@ static int changedline (Proto *p, int oldpc, int newpc) { | |||
762 | 760 | ||
763 | 761 | ||
764 | void luaG_traceexec (lua_State *L) { | 762 | void luaG_traceexec (lua_State *L) { |
765 | ptrdiff_t oldtop = savestack(L, L->top); | ||
766 | CallInfo *ci = L->ci; | 763 | CallInfo *ci = L->ci; |
767 | lu_byte mask = L->hookmask; | 764 | lu_byte mask = L->hookmask; |
768 | int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); | 765 | int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); |
@@ -774,7 +771,8 @@ void luaG_traceexec (lua_State *L) { | |||
774 | ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ | 771 | ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ |
775 | return; /* do not call hook again (VM yielded, so it did not move) */ | 772 | return; /* do not call hook again (VM yielded, so it did not move) */ |
776 | } | 773 | } |
777 | L->top = ci->top; /* prepare top */ | 774 | if (!isIT(*(ci->u.l.savedpc - 1))) |
775 | L->top = ci->top; /* prepare top */ | ||
778 | if (counthook) | 776 | if (counthook) |
779 | luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ | 777 | luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ |
780 | if (mask & LUA_MASKLINE) { | 778 | if (mask & LUA_MASKLINE) { |
@@ -789,7 +787,6 @@ void luaG_traceexec (lua_State *L) { | |||
789 | } | 787 | } |
790 | L->oldpc = npc; | 788 | L->oldpc = npc; |
791 | } | 789 | } |
792 | L->top = restorestack(L, oldtop); | ||
793 | if (L->status == LUA_YIELD) { /* did hook yield? */ | 790 | if (L->status == LUA_YIELD) { /* did hook yield? */ |
794 | if (counthook) | 791 | if (counthook) |
795 | L->hookcount = 1; /* undo decrement to zero */ | 792 | L->hookcount = 1; /* undo decrement to zero */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.242 2017/12/08 17:28:25 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.243 2017/12/20 14:58:05 roberto Exp roberto $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -571,21 +571,16 @@ static int traverseLclosure (global_State *g, LClosure *cl) { | |||
571 | 571 | ||
572 | /* | 572 | /* |
573 | ** Traverse a thread, marking the elements in the stack up to its top | 573 | ** Traverse a thread, marking the elements in the stack up to its top |
574 | ** and cleaning the rest of the stack in the last traversal. | 574 | ** and cleaning the rest of the stack in the final traversal. |
575 | ** That ensures that the entire stack have valid (non-dead) objects. | 575 | ** That ensures that the entire stack have valid (non-dead) objects. |
576 | ** In an emergency collection running Lua code, 'L->top' may not be | ||
577 | ** update. In that case, traverse at least up to 'ci->top'. | ||
578 | */ | 576 | */ |
579 | static int traversethread (global_State *g, lua_State *th) { | 577 | static int traversethread (global_State *g, lua_State *th) { |
580 | StkId o = th->stack; | 578 | StkId o = th->stack; |
581 | StkId top = th->top; | ||
582 | if (o == NULL) | 579 | if (o == NULL) |
583 | return 1; /* stack not completely built yet */ | 580 | return 1; /* stack not completely built yet */ |
584 | lua_assert(g->gcstate == GCSatomic || | 581 | lua_assert(g->gcstate == GCSatomic || |
585 | th->openupval == NULL || isintwups(th)); | 582 | th->openupval == NULL || isintwups(th)); |
586 | if (g->gcemergency && isLuacode(th->ci) && top < th->ci->top) | 583 | for (; o < th->top; o++) /* mark live elements in the stack */ |
587 | top = th->ci->top; | ||
588 | for (; o < top; o++) /* mark live elements in the stack */ | ||
589 | markvalue(g, s2v(o)); | 584 | markvalue(g, s2v(o)); |
590 | if (g->gcstate == GCSatomic) { /* final traversal? */ | 585 | if (g->gcstate == GCSatomic) { /* final traversal? */ |
591 | StkId lim = th->stack + th->stacksize; /* real end of stack */ | 586 | StkId lim = th->stack + th->stacksize; /* real end of stack */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltm.c,v 2.54 2017/12/19 16:40:17 roberto Exp roberto $ | 2 | ** $Id: ltm.c,v 2.55 2017/12/20 14:58:05 roberto Exp roberto $ |
3 | ** Tag methods | 3 | ** Tag methods |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -101,7 +101,7 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) { | |||
101 | 101 | ||
102 | void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, | 102 | void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, |
103 | const TValue *p2, const TValue *p3) { | 103 | const TValue *p2, const TValue *p3) { |
104 | StkId func = (isLuacode(L->ci)) ? L->ci->top : L->top; | 104 | StkId func = L->top; |
105 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ | 105 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ |
106 | setobj2s(L, func + 1, p1); /* 1st argument */ | 106 | setobj2s(L, func + 1, p1); /* 1st argument */ |
107 | setobj2s(L, func + 2, p2); /* 2nd argument */ | 107 | setobj2s(L, func + 2, p2); /* 2nd argument */ |
@@ -115,8 +115,8 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, | |||
115 | } | 115 | } |
116 | 116 | ||
117 | 117 | ||
118 | static void reallycallTMres (lua_State *L, const TValue *f, const TValue *p1, | 118 | void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, |
119 | const TValue *p2, StkId res) { | 119 | const TValue *p2, StkId res) { |
120 | ptrdiff_t result = savestack(L, res); | 120 | ptrdiff_t result = savestack(L, res); |
121 | StkId func = L->top; | 121 | StkId func = L->top; |
122 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ | 122 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ |
@@ -133,29 +133,19 @@ static void reallycallTMres (lua_State *L, const TValue *f, const TValue *p1, | |||
133 | } | 133 | } |
134 | 134 | ||
135 | 135 | ||
136 | void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, | ||
137 | const TValue *p2, StkId res) { | ||
138 | if (isLuacode(L->ci)) | ||
139 | L->top = L->ci->top; /* prepare top */ | ||
140 | reallycallTMres(L, f, p1, p2, res); | ||
141 | } | ||
142 | |||
143 | |||
144 | static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2, | 136 | static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2, |
145 | StkId res, TMS event) { | 137 | StkId res, TMS event) { |
146 | const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ | 138 | const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ |
147 | if (ttisnil(tm)) | 139 | if (ttisnil(tm)) |
148 | tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ | 140 | tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ |
149 | if (ttisnil(tm)) return 0; | 141 | if (ttisnil(tm)) return 0; |
150 | reallycallTMres(L, tm, p1, p2, res); | 142 | luaT_callTMres(L, tm, p1, p2, res); |
151 | return 1; | 143 | return 1; |
152 | } | 144 | } |
153 | 145 | ||
154 | 146 | ||
155 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, | 147 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, |
156 | StkId res, TMS event) { | 148 | StkId res, TMS event) { |
157 | if (event != TM_CONCAT && isLuacode(L->ci)) | ||
158 | L->top = L->ci->top; /* prepare top */ | ||
159 | if (!callbinTM(L, p1, p2, res, event)) { | 149 | if (!callbinTM(L, p1, p2, res, event)) { |
160 | switch (event) { | 150 | switch (event) { |
161 | case TM_CONCAT: | 151 | case TM_CONCAT: |
@@ -195,8 +185,6 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, int i2, | |||
195 | 185 | ||
196 | int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, | 186 | int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, |
197 | TMS event) { | 187 | TMS event) { |
198 | if (isLuacode(L->ci)) | ||
199 | L->top = L->ci->top; /* prepare top */ | ||
200 | if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ | 188 | if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ |
201 | return !l_isfalse(s2v(L->top)); | 189 | return !l_isfalse(s2v(L->top)); |
202 | else if (event == TM_LE) { | 190 | else if (event == TM_LE) { |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 2.328 2017/12/20 14:58:05 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.329 2017/12/22 14:16:46 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -464,8 +464,6 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { | |||
464 | } | 464 | } |
465 | if (tm == NULL) /* no TM? */ | 465 | if (tm == NULL) /* no TM? */ |
466 | return 0; /* objects are different */ | 466 | return 0; /* objects are different */ |
467 | if (isLuacode(L->ci)) | ||
468 | L->top = L->ci->top; /* prepare top */ | ||
469 | luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */ | 467 | luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */ |
470 | return !l_isfalse(s2v(L->top)); | 468 | return !l_isfalse(s2v(L->top)); |
471 | } | 469 | } |
@@ -780,20 +778,29 @@ void luaV_finishOp (lua_State *L) { | |||
780 | #define donextjump(ci) { i = *pc; dojump(ci, i, 1); } | 778 | #define donextjump(ci) { i = *pc; dojump(ci, i, 1); } |
781 | 779 | ||
782 | /* | 780 | /* |
783 | ** Whenever code can raise errors (including memory errors), the global | 781 | ** Correct global 'pc'. |
784 | ** 'pc' must be correct to report occasional errors. | ||
785 | */ | 782 | */ |
786 | #define savepc(L) (ci->u.l.savedpc = pc) | 783 | #define savepc(L) (ci->u.l.savedpc = pc) |
787 | 784 | ||
788 | 785 | ||
789 | /* | 786 | /* |
787 | ** Whenever code can raise errors, the global 'pc' and the global | ||
788 | ** 'top' must be correct to report occasional errors. | ||
789 | */ | ||
790 | #define savestate(L,ci) (savepc(L), L->top = ci->top) | ||
791 | |||
792 | |||
793 | /* | ||
790 | ** Protect code that, in general, can raise errors, reallocate the | 794 | ** Protect code that, in general, can raise errors, reallocate the |
791 | ** stack, and change the hooks. | 795 | ** stack, and change the hooks. |
792 | */ | 796 | */ |
793 | #define Protect(exp) (savepc(L), (exp), updatetrap(ci)) | 797 | #define Protect(exp) (savestate(L,ci), (exp), updatetrap(ci)) |
798 | |||
799 | /* special version that does not change the top */ | ||
800 | #define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) | ||
794 | 801 | ||
795 | /* | 802 | /* |
796 | ** Protect code that will return. | 803 | ** Protect code that will finish the loop (returns). |
797 | */ | 804 | */ |
798 | #define halfProtect(exp) (savepc(L), (exp)) | 805 | #define halfProtect(exp) (savepc(L), (exp)) |
799 | 806 | ||
@@ -842,6 +849,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
842 | vmfetch(); | 849 | vmfetch(); |
843 | lua_assert(base == ci->func + 1); | 850 | lua_assert(base == ci->func + 1); |
844 | lua_assert(base <= L->top && L->top < L->stack + L->stacksize); | 851 | lua_assert(base <= L->top && L->top < L->stack + L->stacksize); |
852 | lua_assert(ci->top < L->stack + L->stacksize); | ||
845 | vmdispatch (GET_OPCODE(i)) { | 853 | vmdispatch (GET_OPCODE(i)) { |
846 | vmcase(OP_MOVE) { | 854 | vmcase(OP_MOVE) { |
847 | setobjs2s(L, ra, RB(i)); | 855 | setobjs2s(L, ra, RB(i)); |
@@ -1000,10 +1008,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1000 | int b = GETARG_B(i); | 1008 | int b = GETARG_B(i); |
1001 | int c = GETARG_C(i); | 1009 | int c = GETARG_C(i); |
1002 | Table *t; | 1010 | Table *t; |
1003 | t = luaH_new(L); | 1011 | L->top = ci->top; /* correct top in case of GC */ |
1012 | t = luaH_new(L); /* memory allocation */ | ||
1004 | sethvalue2s(L, ra, t); | 1013 | sethvalue2s(L, ra, t); |
1005 | if (b != 0 || c != 0) | 1014 | if (b != 0 || c != 0) |
1006 | luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); | 1015 | luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); /* idem */ |
1007 | checkGC(L, ra + 1); | 1016 | checkGC(L, ra + 1); |
1008 | vmbreak; | 1017 | vmbreak; |
1009 | } | 1018 | } |
@@ -1371,7 +1380,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1371 | int c = GETARG_C(i); | 1380 | int c = GETARG_C(i); |
1372 | StkId rb; | 1381 | StkId rb; |
1373 | L->top = base + c + 1; /* mark the end of concat operands */ | 1382 | L->top = base + c + 1; /* mark the end of concat operands */ |
1374 | Protect(luaV_concat(L, c - b + 1)); | 1383 | ProtectNT(luaV_concat(L, c - b + 1)); |
1375 | if (trap) { /* 'luaV_concat' may move the stack */ | 1384 | if (trap) { /* 'luaV_concat' may move the stack */ |
1376 | updatebase(ci); | 1385 | updatebase(ci); |
1377 | ra = RA(i); | 1386 | ra = RA(i); |
@@ -1481,7 +1490,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1481 | if (b != 0) /* fixed number of arguments? */ | 1490 | if (b != 0) /* fixed number of arguments? */ |
1482 | L->top = ra + b; /* top signals number of arguments */ | 1491 | L->top = ra + b; /* top signals number of arguments */ |
1483 | /* else previous instruction set top */ | 1492 | /* else previous instruction set top */ |
1484 | Protect(luaD_call(L, ra, nresults)); | 1493 | ProtectNT(luaD_call(L, ra, nresults)); |
1485 | vmbreak; | 1494 | vmbreak; |
1486 | } | 1495 | } |
1487 | vmcase(OP_TAILCALL) { | 1496 | vmcase(OP_TAILCALL) { |
@@ -1493,12 +1502,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1493 | lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); | 1502 | lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); |
1494 | if (!ttisfunction(vra)) { /* not a function? */ | 1503 | if (!ttisfunction(vra)) { /* not a function? */ |
1495 | /* try to get '__call' metamethod */ | 1504 | /* try to get '__call' metamethod */ |
1496 | Protect(ra = luaD_tryfuncTM(L, ra)); | 1505 | ProtectNT(ra = luaD_tryfuncTM(L, ra)); |
1497 | vra = s2v(ra); | 1506 | vra = s2v(ra); |
1498 | b++; /* there is now one extra argument */ | 1507 | b++; /* there is now one extra argument */ |
1499 | } | 1508 | } |
1500 | if (!ttisLclosure(vra)) { /* C function? */ | 1509 | if (!ttisLclosure(vra)) { /* C function? */ |
1501 | Protect(luaD_call(L, ra, LUA_MULTRET)); /* call it */ | 1510 | ProtectNT(luaD_call(L, ra, LUA_MULTRET)); /* call it */ |
1502 | /* next instruction will do the return */ | 1511 | /* next instruction will do the return */ |
1503 | } | 1512 | } |
1504 | else { /* tail call */ | 1513 | else { /* tail call */ |
@@ -1568,7 +1577,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1568 | lua_Integer ilimit, initv; | 1577 | lua_Integer ilimit, initv; |
1569 | int stopnow; | 1578 | int stopnow; |
1570 | if (!forlimit(plimit, &ilimit, 1, &stopnow)) { | 1579 | if (!forlimit(plimit, &ilimit, 1, &stopnow)) { |
1571 | savepc(L); /* for the error message */ | 1580 | savestate(L, ci); /* for the error message */ |
1572 | luaG_runerror(L, "'for' limit must be a number"); | 1581 | luaG_runerror(L, "'for' limit must be a number"); |
1573 | } | 1582 | } |
1574 | initv = (stopnow ? 0 : ivalue(init)); | 1583 | initv = (stopnow ? 0 : ivalue(init)); |
@@ -1618,7 +1627,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1618 | } | 1627 | } |
1619 | else { /* try making all values floats */ | 1628 | else { /* try making all values floats */ |
1620 | lua_Number ninit; lua_Number nlimit; lua_Number nstep; | 1629 | lua_Number ninit; lua_Number nlimit; lua_Number nstep; |
1621 | savepc(L); /* in case of errors */ | 1630 | savestate(L, ci); /* in case of errors */ |
1622 | if (!tonumber(plimit, &nlimit)) | 1631 | if (!tonumber(plimit, &nlimit)) |
1623 | luaG_runerror(L, "'for' limit must be a number"); | 1632 | luaG_runerror(L, "'for' limit must be a number"); |
1624 | setfltvalue(plimit, nlimit); | 1633 | setfltvalue(plimit, nlimit); |
@@ -1659,7 +1668,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1659 | int c = GETARG_C(i); | 1668 | int c = GETARG_C(i); |
1660 | unsigned int last; | 1669 | unsigned int last; |
1661 | Table *h; | 1670 | Table *h; |
1662 | if (n == 0) n = cast_int(L->top - ra) - 1; | 1671 | if (n == 0) |
1672 | n = cast_int(L->top - ra) - 1; | ||
1673 | else | ||
1674 | L->top = ci->top; /* correct top in case of GC */ | ||
1663 | if (c == 0) { | 1675 | if (c == 0) { |
1664 | c = GETARG_Ax(*pc); pc++; | 1676 | c = GETARG_Ax(*pc); pc++; |
1665 | } | 1677 | } |
@@ -1679,7 +1691,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1679 | Proto *p = cl->p->p[GETARG_Bx(i)]; | 1691 | Proto *p = cl->p->p[GETARG_Bx(i)]; |
1680 | LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ | 1692 | LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ |
1681 | if (ncl == NULL) { /* no match? */ | 1693 | if (ncl == NULL) { /* no match? */ |
1682 | savepc(L); /* in case of allocation errors */ | 1694 | savestate(L, ci); /* in case of allocation errors */ |
1683 | pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ | 1695 | pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ |
1684 | } | 1696 | } |
1685 | else | 1697 | else |