From ad0704e40cc7b3135fedc6d40a522addb039e090 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Tue, 7 Nov 2017 11:25:26 -0200 Subject: [PATCH] back to 'CallInfo' (no gains with its removal) --- lapi.c | 81 +++++++++++------------ lapi.h | 9 ++- ldebug.c | 161 ++++++++++++++++++++------------------------- ldo.c | 190 +++++++++++++++++++++++++++--------------------------- ldo.h | 5 +- lgc.c | 6 +- lobject.h | 32 +-------- lstate.c | 63 +++++++++++++++--- lstate.h | 50 +++++++++++--- ltests.c | 23 +++---- ltm.c | 6 +- lua.h | 5 +- lvm.c | 133 +++++++++++++++++++------------------- 13 files changed, 394 insertions(+), 370 deletions(-) diff --git a/lapi.c b/lapi.c index 8750cefa..1c1e8f9e 100644 --- a/lapi.c +++ b/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.274 2017/11/03 12:12:30 roberto Exp roberto $ +** $Id: lapi.c,v 2.273 2017/11/02 11:28:56 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ @@ -10,7 +10,6 @@ #include "lprefix.h" -#include #include #include @@ -59,14 +58,15 @@ const char lua_ident[] = static TValue *index2value (lua_State *L, int idx) { + CallInfo *ci = L->ci; if (idx > 0) { - StkId o = L->func + idx; - api_check(L, idx < L->func->stkci.framesize, "unacceptable index"); + StkId o = ci->func + idx; + api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index"); if (o >= L->top) return NONVALIDVALUE; else return s2v(o); } else if (!ispseudo(idx)) { /* negative index */ - api_check(L, idx != 0 && -idx < L->func->stkci.framesize, "invalid index"); + api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); return s2v(L->top + idx); } else if (idx == LUA_REGISTRYINDEX) @@ -74,10 +74,10 @@ static TValue *index2value (lua_State *L, int idx) { else { /* upvalues */ idx = LUA_REGISTRYINDEX - idx; api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); - if (ttislcf(s2v(L->func))) /* light C function? */ + if (ttislcf(s2v(ci->func))) /* light C function? */ return NONVALIDVALUE; /* it has no upvalues */ else { - CClosure *func = clCvalue(s2v(L->func)); + CClosure *func = clCvalue(s2v(ci->func)); return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; } } @@ -85,13 +85,14 @@ static TValue *index2value (lua_State *L, int idx) { static StkId index2stack (lua_State *L, int idx) { + CallInfo *ci = L->ci; if (idx > 0) { - StkId o = L->func + idx; + StkId o = ci->func + idx; api_check(L, o < L->top, "unacceptable index"); return o; } else { /* non-positive index */ - api_check(L, idx != 0 && -idx <= L->top - (L->func + 1), "invalid index"); + api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); api_check(L, !ispseudo(idx), "invalid index"); return L->top + idx; } @@ -110,12 +111,10 @@ static void growstack (lua_State *L, void *ud) { LUA_API int lua_checkstack (lua_State *L, int n) { int res; - int frameuse = L->top - L->func; + CallInfo *ci = L->ci; lua_lock(L); api_check(L, n >= 0, "negative 'n'"); - if (n >= USHRT_MAX - frameuse) - res = 0; /* frame size overflow */ - else if (L->stack_last - L->top > n) /* stack large enough? */ + if (L->stack_last - L->top > n) /* stack large enough? */ res = 1; /* yes; check is OK */ else { /* no; need to grow stack */ int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; @@ -124,8 +123,8 @@ LUA_API int lua_checkstack (lua_State *L, int n) { else /* try to grow stack */ res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); } - if (res && L->func->stkci.framesize < frameuse + n) - L->func->stkci.framesize = frameuse + n; /* adjust frame size */ + if (res && ci->top < L->top + n) + ci->top = L->top + n; /* adjust frame top */ lua_unlock(L); return res; } @@ -137,7 +136,7 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { lua_lock(to); api_checknelems(from, n); api_check(from, G(from) == G(to), "moving among independent states"); - api_check(from, functop(to->func) - to->top >= n, "stack overflow"); + api_check(from, to->ci->top - to->top >= n, "stack overflow"); from->top -= n; for (i = 0; i < n; i++) { setobjs2s(to, to->top, from->top + i); @@ -176,17 +175,17 @@ LUA_API const lua_Number *lua_version (lua_State *L) { LUA_API int lua_absindex (lua_State *L, int idx) { return (idx > 0 || ispseudo(idx)) ? idx - : cast_int(L->top - L->func) + idx; + : cast_int(L->top - L->ci->func) + idx; } LUA_API int lua_gettop (lua_State *L) { - return cast_int(L->top - (L->func + 1)); + return cast_int(L->top - (L->ci->func + 1)); } LUA_API void lua_settop (lua_State *L, int idx) { - StkId func = L->func; + StkId func = L->ci->func; lua_lock(L); if (idx >= 0) { api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); @@ -244,7 +243,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { api_checkvalidindex(L, to); setobj(L, to, fr); if (isupvalue(toidx)) /* function upvalue? */ - luaC_barrier(L, clCvalue(s2v(L->func)), fr); + luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr); /* LUA_REGISTRYINDEX does not need gc barrier (collector revisits it before finishing collection) */ lua_unlock(L); @@ -932,24 +931,23 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) { #define checkresults(L,na,nr) \ - api_check(L, (nr) == LUA_MULTRET || \ - (functop(L->func) - L->top >= (nr) - (na)), \ - "results from function overflow current frame size") + api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ + "results from function overflow current stack size") LUA_API void lua_callk (lua_State *L, int nargs, int nresults, lua_KContext ctx, lua_KFunction k) { StkId func; lua_lock(L); - api_check(L, k == NULL || !isLua(L->func), + api_check(L, k == NULL || !isLua(L->ci), "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); checkresults(L, nargs, nresults); func = L->top - (nargs+1); if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ - L->func->stkci.u.c.k = k; /* save continuation */ - L->func->stkci.u.c.ctx = ctx; /* save context */ + L->ci->u.c.k = k; /* save continuation */ + L->ci->u.c.ctx = ctx; /* save context */ luaD_call(L, func, nresults); /* do the call */ } else /* no continuation or no yieldable */ @@ -980,38 +978,37 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, lua_KContext ctx, lua_KFunction k) { struct CallS c; int status; - ptrdiff_t efunc; + ptrdiff_t func; lua_lock(L); - api_check(L, k == NULL || !isLua(L->func), + api_check(L, k == NULL || !isLua(L->ci), "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); checkresults(L, nargs, nresults); if (errfunc == 0) - efunc = 0; + func = 0; else { StkId o = index2stack(L, errfunc); - efunc = savestack(L, o); + func = savestack(L, o); } c.func = L->top - (nargs+1); /* function to be called */ if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */ c.nresults = nresults; /* do a 'conventional' protected call */ - status = luaD_pcall(L, f_call, &c, savestack(L, c.func), efunc); + status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); } else { /* prepare continuation (call is already protected by 'resume') */ - StkId func = L->func; - func->stkci.u.c.k = k; /* save continuation */ - func->stkci.u.c.ctx = ctx; /* save context */ + CallInfo *ci = L->ci; + ci->u.c.k = k; /* save continuation */ + ci->u.c.ctx = ctx; /* save context */ /* save information for error recovery */ - func->stkci.u2.funcidx = c.func - func; - func->stkci.u.c.old_errfunc = L->errfunc; - L->errfunc = efunc; - setoah(callstatus(func), L->allowhook); /* save value of 'allowhook' */ - callstatus(func) |= CIST_YPCALL; /* function can do error recovery */ + ci->u2.funcidx = savestack(L, c.func); + ci->u.c.old_errfunc = L->errfunc; + L->errfunc = func; + setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ + ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ luaD_call(L, c.func, nresults); /* do the call */ - func = L->func; /* previous call can reallocate stack */ - callstatus(func) &= ~CIST_YPCALL; - L->errfunc = func->stkci.u.c.old_errfunc; + ci->callstatus &= ~CIST_YPCALL; + L->errfunc = ci->u.c.old_errfunc; status = LUA_OK; /* if it is here, there were no errors */ } adjustresults(L, nresults); diff --git a/lapi.h b/lapi.h index d851d161..77ebb300 100644 --- a/lapi.h +++ b/lapi.h @@ -1,5 +1,5 @@ /* -** $Id: lapi.h,v 2.10 2017/11/01 18:20:48 roberto Exp roberto $ +** $Id: lapi.h,v 2.10 2017/11/01 18:20:48 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ @@ -11,14 +11,13 @@ #include "llimits.h" #include "lstate.h" -#define api_incr_top(L) {L->top++; api_check(L, L->top <= functop(L->func), \ +#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ "stack overflow");} #define adjustresults(L,nres) \ - { if ((nres) == LUA_MULTRET && functop(L->func) < L->top) \ - setfunctop(L->func, L->top); } + { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } -#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->func), \ +#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ "not enough elements in the stack") diff --git a/ldebug.c b/ldebug.c index 100b9b7a..83ddde72 100644 --- a/ldebug.c +++ b/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.138 2017/11/03 19:33:22 roberto Exp roberto $ +** $Id: ldebug.c,v 2.135 2017/11/02 11:28:56 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -34,17 +34,17 @@ #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) -/* Active Lua function (given stack function) */ -#define ci_func(func) (clLvalue(s2v(func))) +/* Active Lua function (given call info) */ +#define ci_func(ci) (clLvalue(s2v((ci)->func))) -static const char *funcnamefromcode (lua_State *L, StkId stkf, +static const char *funcnamefromcode (lua_State *L, CallInfo *ci, const char **name); -static int currentpc (StkId func) { - lua_assert(isLua(func)); - return pcRel(func->stkci.u.l.savedpc, ci_func(func)->p); +static int currentpc (CallInfo *ci) { + lua_assert(isLua(ci)); + return pcRel(ci->u.l.savedpc, ci_func(ci)->p); } @@ -101,8 +101,8 @@ int luaG_getfuncline (Proto *f, int pc) { } -static int currentline (StkId func) { - return luaG_getfuncline(ci_func(func)->p, currentpc(func)); +static int currentline (CallInfo *ci) { + return luaG_getfuncline(ci_func(ci)->p, currentpc(ci)); } @@ -120,8 +120,8 @@ LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { mask = 0; func = NULL; } - if (isLua(L->func)) - L->oldpc = L->func->stkci.u.l.savedpc; + if (isLua(L->ci)) + L->oldpc = L->ci->u.l.savedpc; L->hook = func; L->basehookcount = count; resethookcount(L); @@ -146,17 +146,14 @@ LUA_API int lua_gethookcount (lua_State *L) { LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { int status; - StkId func; + CallInfo *ci; if (level < 0) return 0; /* invalid (negative) level */ lua_lock(L); - for (func = L->func; - level > 0 && func->stkci.previous != 0; - func -= func->stkci.previous) + for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) level--; - if (level == 0 && func->stkci.previous != 0) { /* level found? */ + if (level == 0 && ci != &L->base_ci) { /* level found? */ status = 1; - ar->i_actf = func - L->stack; - ar->i_actL = L; + ar->i_ci = ci; } else status = 0; /* no such level */ lua_unlock(L); @@ -171,34 +168,24 @@ static const char *upvalname (Proto *p, int uv) { } -static StkId findcalled (lua_State *L, StkId caller) { - StkId func = L->func; - for (;;) { - StkId previous = func - func->stkci.previous; - lua_assert(previous < func); - if (previous == caller) - return func; - else - func = previous; - } -} - - -static const char *findlocal (lua_State *L, const lua_Debug *ar, - int n, StkId *pos) { +static const char *findlocal (lua_State *L, CallInfo *ci, int n, + StkId *pos) { const char *name = NULL; - StkId stkf = ar->i_actL->stack + ar->i_actf; - if (isLua(stkf)) { - name = luaF_getlocalname(ci_func(stkf)->p, n, currentpc(stkf)); + StkId base; + if (isLua(ci)) { + base = ci->func + 1; + name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); } + else + base = ci->func + 1; if (name == NULL) { /* no 'standard' name? */ - StkId limit = (stkf == L->func) ? L->top : findcalled(L, stkf); - if (limit - stkf > n && n > 0) /* is 'n' inside 'ci' stack? */ + StkId limit = (ci == L->ci) ? L->top : ci->next->func; + if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ name = "(*temporary)"; /* generic name for any valid slot */ else return NULL; /* no name */ } - *pos = stkf + n; + *pos = base + (n - 1); return name; } @@ -214,7 +201,7 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { } else { /* active function; get information through 'ar' */ StkId pos = NULL; /* to avoid warnings */ - name = findlocal(L, ar, n, &pos); + name = findlocal(L, ar->i_ci, n, &pos); if (name) { setobjs2s(L, L->top, pos); api_incr_top(L); @@ -229,7 +216,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { StkId pos = NULL; /* to avoid warnings */ const char *name; lua_lock(L); - name = findlocal(L, ar, n, &pos); + name = findlocal(L, ar->i_ci, n, &pos); if (name) { setobjs2s(L, pos, L->top - 1); L->top--; /* pop value */ @@ -287,25 +274,22 @@ static void collectvalidlines (lua_State *L, Closure *f) { } -static const char *getfuncname (lua_State *L, StkId stkf, const char **name) { - if (stkf == NULL) /* no function? */ +static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { + if (ci == NULL) /* no 'ci'? */ return NULL; /* no info */ - else if (callstatus(stkf) & CIST_FIN) { /* is this a finalizer? */ + else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */ *name = "__gc"; return "metamethod"; /* report it as such */ } /* calling function is a known Lua function? */ - else { - StkId previous = stkf - stkf->stkci.previous; - if (!(callstatus(stkf) & CIST_TAIL) && isLua(previous)) - return funcnamefromcode(L, previous, name); - else return NULL; /* no way to find a name */ - } + else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous)) + return funcnamefromcode(L, ci->previous, name); + else return NULL; /* no way to find a name */ } static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, - Closure *f, StkId stkf) { + Closure *f, CallInfo *ci) { int status = 1; for (; *what; what++) { switch (*what) { @@ -314,7 +298,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, break; } case 'l': { - ar->currentline = (stkf && isLua(stkf)) ? currentline(stkf) : -1; + ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; break; } case 'u': { @@ -330,11 +314,11 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, break; } case 't': { - ar->istailcall = (stkf) ? callstatus(stkf) & CIST_TAIL : 0; + ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; break; } case 'n': { - ar->namewhat = getfuncname(L, stkf, &ar->name); + ar->namewhat = getfuncname(L, ci, &ar->name); if (ar->namewhat == NULL) { ar->namewhat = ""; /* not found */ ar->name = NULL; @@ -354,23 +338,23 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { int status; Closure *cl; - StkId stkf; + CallInfo *ci; TValue *func; lua_lock(L); if (*what == '>') { - stkf = NULL; + ci = NULL; func = s2v(L->top - 1); api_check(L, ttisfunction(func), "function expected"); what++; /* skip the '>' */ L->top--; /* pop function */ } else { - stkf = ar->i_actL->stack + ar->i_actf; - func = s2v(stkf); + ci = ar->i_ci; + func = s2v(ci->func); lua_assert(ttisfunction(func)); } cl = ttisclosure(func) ? clvalue(func) : NULL; - status = auxgetinfo(L, what, ar, cl, stkf); + status = auxgetinfo(L, what, ar, cl, ci); if (strchr(what, 'f')) { setobj2s(L, L->top, func); api_incr_top(L); @@ -559,13 +543,13 @@ static const char *gxf (Proto *p, int pc, Instruction i, int isup) { ** Returns what the name is (e.g., "for iterator", "method", ** "metamethod") and sets '*name' to point to the name. */ -static const char *funcnamefromcode (lua_State *L, StkId stkf, +static const char *funcnamefromcode (lua_State *L, CallInfo *ci, const char **name) { TMS tm = (TMS)0; /* (initial value avoids warnings) */ - Proto *p = ci_func(stkf)->p; /* calling function */ - int pc = currentpc(stkf); /* calling instruction index */ + Proto *p = ci_func(ci)->p; /* calling function */ + int pc = currentpc(ci); /* calling instruction index */ Instruction i = p->code[pc]; /* calling instruction */ - if (callstatus(stkf) & CIST_HOOKED) { /* was it called inside a hook? */ + if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ *name = "?"; return "hook"; } @@ -621,10 +605,10 @@ static const char *funcnamefromcode (lua_State *L, StkId stkf, ** not ISO C, but it should not crash a program; the subsequent ** checks are ISO C and ensure a correct result. */ -static int isinstack (lua_State *L, const TValue *o) { - StkId base = L->stack; +static int isinstack (CallInfo *ci, const TValue *o) { + StkId base = ci->func + 1; ptrdiff_t i = cast(StkId, o) - base; - return (0 <= i && i < (L->top - base) && s2v(base + i) == o); + return (0 <= i && i < (ci->top - base) && s2v(base + i) == o); } @@ -633,9 +617,9 @@ static int isinstack (lua_State *L, const TValue *o) { ** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on ** upvalues.) */ -static const char *getupvalname (StkId stkf, const TValue *o, +static const char *getupvalname (CallInfo *ci, const TValue *o, const char **name) { - LClosure *c = ci_func(stkf); + LClosure *c = ci_func(ci); int i; for (i = 0; i < c->nupvalues; i++) { if (c->upvals[i]->v == o) { @@ -649,13 +633,13 @@ static const char *getupvalname (StkId stkf, const TValue *o, static const char *varinfo (lua_State *L, const TValue *o) { const char *name = NULL; /* to avoid warnings */ - StkId stkf = L->func; + CallInfo *ci = L->ci; const char *kind = NULL; - if (isLua(stkf)) { - kind = getupvalname(stkf, o, &name); /* check whether 'o' is an upvalue */ - if (!kind && isinstack(L, o)) /* no? try a register */ - kind = getobjname(ci_func(stkf)->p, currentpc(stkf), - cast_int(cast(StkId, o) - (stkf + 1)), &name); + if (isLua(ci)) { + kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ + if (!kind && isinstack(ci, o)) /* no? try a register */ + kind = getobjname(ci_func(ci)->p, currentpc(ci), + cast_int(cast(StkId, o) - (ci->func + 1)), &name); } return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; } @@ -728,16 +712,15 @@ l_noret luaG_errormsg (lua_State *L) { l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { - StkId func; + CallInfo *ci = L->ci; const char *msg; va_list argp; luaC_checkGC(L); /* error message uses memory */ va_start(argp, fmt); msg = luaO_pushvfstring(L, fmt, argp); /* format message */ va_end(argp); - func = L->func; /* previous calls can change the stack */ - if (isLua(func)) /* if Lua function, add source:line information */ - luaG_addinfo(L, msg, ci_func(func)->p->source, currentline(func)); + if (isLua(ci)) /* if Lua function, add source:line information */ + luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci)); luaG_errormsg(L); } @@ -756,37 +739,35 @@ static int changedline (Proto *p, int oldpc, int newpc) { void luaG_traceexec (lua_State *L) { - StkId func = L->func; + CallInfo *ci = L->ci; lu_byte mask = L->hookmask; int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); if (counthook) resethookcount(L); /* reset count */ else if (!(mask & LUA_MASKLINE)) return; /* no line hook and count != 0; nothing to be done */ - if (callstatus(func) & CIST_HOOKYIELD) { /* called hook last time? */ - callstatus(func) &= ~CIST_HOOKYIELD; /* erase mark */ + if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ return; /* do not call hook again (VM yielded, so it did not move) */ } if (counthook) luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ if (mask & LUA_MASKLINE) { - Proto *p = ci_func(func)->p; - int npc = pcRel(func->stkci.u.l.savedpc, p); + Proto *p = ci_func(ci)->p; + int npc = pcRel(ci->u.l.savedpc, p); if (npc == 0 || /* call linehook when enter a new function, */ - func->stkci.u.l.savedpc <= L->oldpc || /* when jump back (loop), */ - changedline(p, pcRel(L->oldpc, p), npc)) { /* when enter new line */ + ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ + changedline(p, pcRel(L->oldpc, p), npc)) { /* enter new line */ int newline = luaG_getfuncline(p, npc); /* new line */ luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ } } - func = L->func; /* previous calls can reallocate stack */ - L->oldpc = func->stkci.u.l.savedpc; + L->oldpc = ci->u.l.savedpc; if (L->status == LUA_YIELD) { /* did hook yield? */ if (counthook) L->hookcount = 1; /* undo decrement to zero */ - /* undo increment (resume will increment it again) */ - func->stkci.u.l.savedpc--; - callstatus(func) |= CIST_HOOKYIELD; /* mark that it yielded */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ luaD_throw(L, LUA_YIELD); } } diff --git a/ldo.c b/ldo.c index bb189565..efdcbc1b 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.168 2017/11/03 20:41:05 roberto Exp roberto $ +** $Id: ldo.c,v 2.165 2017/11/02 11:28:56 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -123,8 +123,8 @@ l_noret luaD_throw (lua_State *L, int errcode) { else { /* no handler at all; abort */ if (g->panic) { /* panic function? */ seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ - if (functop(L->func) < L->top) /* check invariant */ - setfunctop(L->func, L->top); + if (L->ci->top < L->top) + L->ci->top = L->top; /* pushing msg. can break this invariant */ lua_unlock(L); g->panic(L); /* call panic function (last chance to jump out) */ } @@ -157,11 +157,15 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { ** =================================================================== */ static void correctstack (lua_State *L, StkId oldstack) { + CallInfo *ci; UpVal *up; L->top = (L->top - oldstack) + L->stack; - L->func = (L->func - oldstack) + L->stack; for (up = L->openupval; up != NULL; up = up->u.open.next) up->v = s2v((uplevel(up) - oldstack) + L->stack); + for (ci = L->ci; ci != NULL; ci = ci->previous) { + ci->top = (ci->top - oldstack) + L->stack; + ci->func = (ci->func - oldstack) + L->stack; + } } @@ -203,11 +207,10 @@ void luaD_growstack (lua_State *L, int n) { static int stackinuse (lua_State *L) { + CallInfo *ci; StkId lim = L->top; - StkId func = L->func; - for (; func->stkci.previous != 0; func -= func->stkci.previous) { - if (lim < functop(func)) - lim = functop(func); + for (ci = L->ci; ci != NULL; ci = ci->previous) { + if (lim < ci->top) lim = ci->top; } lua_assert(lim <= L->stack_last); return cast_int(lim - L->stack) + 1; /* part of stack in use */ @@ -219,6 +222,10 @@ void luaD_shrinkstack (lua_State *L) { int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK; /* respect stack limit */ + if (L->stacksize > LUAI_MAXSTACK) /* had been handling stack overflow? */ + luaE_freeCI(L); /* free all CIs (list grew because of an error) */ + else + luaE_shrinkCI(L); /* shrink list */ /* if thread is currently not handling a stack overflow and its good size is smaller than current size, shrink its stack */ if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && @@ -245,46 +252,40 @@ void luaD_inctop (lua_State *L) { void luaD_hook (lua_State *L, int event, int line) { lua_Hook hook = L->hook; if (hook && L->allowhook) { /* make sure there is a hook */ + CallInfo *ci = L->ci; ptrdiff_t top = savestack(L, L->top); - int origframesize = L->func->stkci.framesize; - int tmpframesize; /* frame size to run hook */ + ptrdiff_t ci_top = savestack(L, ci->top); lua_Debug ar; ar.event = event; ar.currentline = line; - ar.i_actf = L->func - L->stack; - ar.i_actL = L; + ar.i_ci = ci; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - tmpframesize = L->top - L->func + LUA_MINSTACK; - if (tmpframesize > origframesize) /* need to grow frame? */ - L->func->stkci.framesize = tmpframesize; - lua_assert(functop(L->func) <= L->stack_last); + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); L->allowhook = 0; /* cannot call hooks inside a hook */ - callstatus(L->func) |= CIST_HOOKED; + ci->callstatus |= CIST_HOOKED; lua_unlock(L); (*hook)(L, &ar); lua_lock(L); lua_assert(!L->allowhook); L->allowhook = 1; - L->func->stkci.framesize = origframesize; + ci->top = restorestack(L, ci_top); L->top = restorestack(L, top); - callstatus(L->func) &= ~CIST_HOOKED; + ci->callstatus &= ~CIST_HOOKED; } } -static void callhook (lua_State *L) { +static void callhook (lua_State *L, CallInfo *ci) { int hook = LUA_HOOKCALL; - StkId func = L->func; - StkId previous = func - L->func->stkci.previous; - func->stkci.u.l.savedpc++; /* hooks assume 'pc' is already incremented */ - if (isLua(previous) && - GET_OPCODE(*(previous->stkci.u.l.savedpc - 1)) == OP_TAILCALL) { - callstatus(L->func) |= CIST_TAIL; + ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ + if (isLua(ci->previous) && + GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) { + ci->callstatus |= CIST_TAIL; hook = LUA_HOOKTAILCALL; } luaD_hook(L, hook, -1); - func = L->func; /* previous call can change stack */ - func->stkci.u.l.savedpc--; /* correct 'pc' */ + ci->u.l.savedpc--; /* correct 'pc' */ } @@ -355,25 +356,28 @@ static int moveresults (lua_State *L, StkId firstResult, StkId res, ** moves current number of results to proper place; returns 0 iff call ** wanted multiple (variable number of) results. */ -int luaD_poscall (lua_State *L, StkId firstResult, int nres) { - StkId res = L->func; /* res == final position of 1st result */ - int wanted = res->stkci.nresults; +int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { + StkId res; + int wanted = ci->nresults; if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { if (L->hookmask & LUA_MASKRET) { ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ luaD_hook(L, LUA_HOOKRET, -1); firstResult = restorestack(L, fr); - res = L->func; } - /* 'oldpc' for caller function */ - L->oldpc = (res - res->stkci.previous)->stkci.u.l.savedpc; + L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ } - L->func = res - res->stkci.previous; + res = ci->func; /* res == final position of 1st result */ + L->ci = ci->previous; /* back to caller */ /* move results to proper place */ return moveresults(L, firstResult, res, nres, wanted); } + +#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L))) + + /* ** Prepares a function call: checks the stack, creates a new CallInfo ** entry, fills in the relevant information, calls hook if needed. @@ -384,6 +388,7 @@ int luaD_poscall (lua_State *L, StkId firstResult, int nres) { int luaD_precall (lua_State *L, StkId func, int nresults) { lua_CFunction f; TValue *funcv = s2v(func); + CallInfo *ci; switch (ttype(funcv)) { case LUA_TCCL: /* C closure */ f = clCvalue(funcv)->f; @@ -393,19 +398,19 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { Cfunc: { int n; /* number of returns */ checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ - func->stkci.nresults = nresults; - func->stkci.previous = func - L->func; - L->func = func; - setfunctop(func, L->top + LUA_MINSTACK); - lua_assert(functop(func) <= L->stack_last); - callstatus(func) = 0; + ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; + ci->func = func; + ci->top = L->top + LUA_MINSTACK; + lua_assert(ci->top <= L->stack_last); + ci->callstatus = 0; if (L->hookmask & LUA_MASKCALL) luaD_hook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*f)(L); /* do the actual call */ lua_lock(L); api_checknelems(L, n); - luaD_poscall(L, L->top - n, n); + luaD_poscall(L, ci, L->top - n, n); return 1; } case LUA_TLCL: { /* Lua function: prepare its call */ @@ -417,16 +422,15 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { setnilvalue(s2v(L->top++)); /* complete missing arguments */ if (p->is_vararg) luaT_adjustvarargs(L, p, n); - func->stkci.nresults = nresults; - func->stkci.previous = func - L->func; - func->stkci.framesize = fsize + 1; /* size includes function itself */ - L->func = func; - L->top = func + 1 + fsize; - lua_assert(functop(func) <= L->stack_last); - func->stkci.u.l.savedpc = p->code; /* starting point */ - callstatus(func) = 0; + ci = next_ci(L); /* now 'enter' new function */ + ci->nresults = nresults; + ci->func = func; + L->top = ci->top = func + 1 + fsize; + lua_assert(ci->top <= L->stack_last); + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus = CIST_LUA; if (L->hookmask & LUA_MASKCALL) - callhook(L); + callhook(L, ci); return 0; } default: { /* not a function */ @@ -483,25 +487,24 @@ void luaD_callnoyield (lua_State *L, StkId func, int nResults) { ** continuation function. */ static void finishCcall (lua_State *L, int status) { - StkId func = L->func; + CallInfo *ci = L->ci; int n; /* must have a continuation and must be able to call it */ - lua_assert(func->stkci.u.c.k != NULL && L->nny == 0); + lua_assert(ci->u.c.k != NULL && L->nny == 0); /* error status can only happen in a protected call */ - lua_assert((callstatus(func) & CIST_YPCALL) || status == LUA_YIELD); - if (callstatus(func) & CIST_YPCALL) { /* was inside a pcall? */ - callstatus(func) &= ~CIST_YPCALL; /* continuation is also inside it */ - L->errfunc = func->stkci.u.c.old_errfunc; /* with same error function */ + lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); + if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ + ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */ + L->errfunc = ci->u.c.old_errfunc; /* with the same error function */ } /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already handled */ - adjustresults(L, func->stkci.nresults); + adjustresults(L, ci->nresults); lua_unlock(L); - /* call continuation function */ - n = (*func->stkci.u.c.k)(L, status, func->stkci.u.c.ctx); + n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ lua_lock(L); api_checknelems(L, n); - luaD_poscall(L, L->top - n, n); /* finish 'luaD_precall' */ + luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */ } @@ -516,8 +519,8 @@ static void finishCcall (lua_State *L, int status) { static void unroll (lua_State *L, void *ud) { if (ud != NULL) /* error status? */ finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ - while (L->func != L->stack) { /* something in the stack */ - if (!isLua(L->func)) /* C function? */ + while (L->ci != &L->base_ci) { /* something in the stack */ + if (!isLua(L->ci)) /* C function? */ finishCcall(L, LUA_YIELD); /* complete its execution */ else { /* Lua function */ luaV_finishOp(L); /* finish interrupted instruction */ @@ -531,13 +534,11 @@ static void unroll (lua_State *L, void *ud) { ** Try to find a suspended protected call (a "recover point") for the ** given thread. */ -static StkId findpcall (lua_State *L) { - StkId func; - for (func = L->func; - func->stkci.previous != 0; - func -= func->stkci.previous) { - if (callstatus(func) & CIST_YPCALL) - return func; +static CallInfo *findpcall (lua_State *L) { + CallInfo *ci; + for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */ + if (ci->callstatus & CIST_YPCALL) + return ci; } return NULL; /* no pending pcall */ } @@ -550,17 +551,17 @@ static StkId findpcall (lua_State *L) { */ static int recover (lua_State *L, int status) { StkId oldtop; - StkId recf = findpcall(L); - if (recf == NULL) return 0; /* no recovery point */ + CallInfo *ci = findpcall(L); + if (ci == NULL) return 0; /* no recovery point */ /* "finish" luaD_pcall */ - oldtop = recf + recf->stkci.u2.funcidx; + oldtop = restorestack(L, ci->u2.funcidx); luaF_close(L, oldtop); seterrorobj(L, status, oldtop); - L->func = recf; - L->allowhook = getoah(callstatus(recf)); /* restore original 'allowhook' */ + L->ci = ci; + L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ L->nny = 0; /* should be zero to be yieldable */ luaD_shrinkstack(L); - L->errfunc = recf->stkci.u.c.old_errfunc; + L->errfunc = ci->u.c.old_errfunc; return 1; /* continue running the coroutine */ } @@ -589,7 +590,7 @@ static int resume_error (lua_State *L, const char *msg, int narg) { static void resume (lua_State *L, void *ud) { int n = *(cast(int*, ud)); /* number of arguments */ StkId firstArg = L->top - n; /* first argument */ - StkId func = L->func; + CallInfo *ci = L->ci; if (L->status == LUA_OK) { /* starting a coroutine? */ if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ luaV_execute(L); /* call it */ @@ -597,18 +598,17 @@ static void resume (lua_State *L, void *ud) { else { /* resuming from previous yield */ lua_assert(L->status == LUA_YIELD); L->status = LUA_OK; /* mark that it is running (again) */ - if (isLua(func)) /* yielded inside a hook? */ + if (isLua(ci)) /* yielded inside a hook? */ luaV_execute(L); /* just continue running Lua code */ else { /* 'common' yield */ - if (func->stkci.u.c.k != NULL) { /* does it have a continuation? */ + if (ci->u.c.k != NULL) { /* does it have a continuation function? */ lua_unlock(L); - /* call continuation */ - n = (*func->stkci.u.c.k)(L, LUA_YIELD, func->stkci.u.c.ctx); + n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ lua_lock(L); api_checknelems(L, n); firstArg = L->top - n; /* yield results come from continuation */ } - luaD_poscall(L, firstArg, n); /* finish 'luaD_precall' */ + luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */ } unroll(L, NULL); /* run continuation */ } @@ -621,7 +621,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ lua_lock(L); if (L->status == LUA_OK) { /* may be starting a coroutine */ - if (L->func != L->stack) /* not in base level? */ + if (L->ci != &L->base_ci) /* not in base level? */ return resume_error(L, "cannot resume non-suspended coroutine", nargs); } else if (L->status != LUA_YIELD) @@ -643,12 +643,12 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, if (errorstatus(status)) { /* unrecoverable error? */ L->status = cast_byte(status); /* mark thread as 'dead' */ seterrorobj(L, status, L->top); /* push error message */ - L->func->stkci.framesize = L->top - L->func; + L->ci->top = L->top; } else lua_assert(status == L->status); /* normal end or yield */ } - *nresults = (status == LUA_YIELD) ? L->func->stkci.u2.nyield - : L->top - (L->func + 1); + *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield + : L->top - (L->ci->func + 1); L->nny = oldnny; /* restore 'nny' */ L->nCcalls--; lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); @@ -664,7 +664,7 @@ LUA_API int lua_isyieldable (lua_State *L) { LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, lua_KFunction k) { - StkId func = L->func; + CallInfo *ci = L->ci; luai_userstateyield(L, nresults); lua_lock(L); api_checknelems(L, nresults); @@ -675,17 +675,17 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, luaG_runerror(L, "attempt to yield from outside a coroutine"); } L->status = LUA_YIELD; - if (isLua(func)) { /* inside a hook? */ + if (isLua(ci)) { /* inside a hook? */ api_check(L, k == NULL, "hooks cannot continue after yielding"); - func->stkci.u2.nyield = 0; /* no results */ + ci->u2.nyield = 0; /* no results */ } else { - if ((func->stkci.u.c.k = k) != NULL) /* is there a continuation? */ - func->stkci.u.c.ctx = ctx; /* save context */ - func->stkci.u2.nyield = nresults; /* save number of results */ + if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ + ci->u.c.ctx = ctx; /* save context */ + ci->u2.nyield = nresults; /* save number of results */ luaD_throw(L, LUA_YIELD); } - lua_assert(callstatus(func) & CIST_HOOKED); /* must be inside a hook */ + lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ lua_unlock(L); return 0; /* return to 'luaD_hook' */ } @@ -694,7 +694,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; - ptrdiff_t oldfunc = savestack(L, L->func); + CallInfo *old_ci = L->ci; lu_byte old_allowhooks = L->allowhook; unsigned short old_nny = L->nny; ptrdiff_t old_errfunc = L->errfunc; @@ -704,7 +704,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, StkId oldtop = restorestack(L, old_top); luaF_close(L, oldtop); /* close possible pending closures */ seterrorobj(L, status, oldtop); - L->func = restorestack(L, oldfunc); + L->ci = old_ci; L->allowhook = old_allowhooks; L->nny = old_nny; luaD_shrinkstack(L); diff --git a/ldo.h b/ldo.h index 4c03d594..3dc16d71 100644 --- a/ldo.h +++ b/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.31 2017/06/29 15:06:44 roberto Exp roberto $ +** $Id: ldo.h,v 2.31 2017/06/29 15:06:44 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -52,7 +52,8 @@ LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); -LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult, int nres); +LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, + int nres); LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); LUAI_FUNC void luaD_growstack (lua_State *L, int n); LUAI_FUNC void luaD_shrinkstack (lua_State *L); diff --git a/lgc.c b/lgc.c index 2155b28d..036020ae 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.236 2017/10/31 15:29:28 roberto Exp roberto $ +** $Id: lgc.c,v 2.236 2017/10/31 15:29:28 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -866,9 +866,9 @@ static void GCTM (lua_State *L, int propagateerrors) { setobj2s(L, L->top, tm); /* push finalizer... */ setobj2s(L, L->top + 1, &v); /* ... and its argument */ L->top += 2; /* and (next line) call the finalizer */ - callstatus(L->func) |= CIST_FIN; /* will run a finalizer */ + L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); - callstatus(L->func) &= ~CIST_FIN; /* not running a finalizer anymore */ + L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ L->allowhook = oldah; /* restore hooks */ g->gcrunning = running; /* restore state */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ diff --git a/lobject.h b/lobject.h index 56dfebba..372ec13b 100644 --- a/lobject.h +++ b/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.128 2017/11/03 17:22:54 roberto Exp roberto $ +** $Id: lobject.h,v 2.125 2017/06/29 15:06:44 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -311,39 +311,9 @@ typedef struct TValue { typedef union StackValue { TValue val; - struct { - TValuefields; - lu_byte callstatus_; - char nresults; /* expected number of results from this function */ - union { - unsigned char funcidx; /* called-function index */ - unsigned char nyield; /* number of values yielded */ - } u2; - unsigned short previous; /* difference to previous 'func' */ - unsigned short framesize; /* stack space available for this function */ - union { - struct { /* only for Lua functions */ - const Instruction *savedpc; - } l; - struct { /* only for C functions */ - lua_KFunction k; /* continuation in case of yields */ - int old_errfunc; - int ctx; /* context info. in case of yields */ - } c; - } u; - } stkci; } StackValue; -#define callstatus(ar) ((ar)->stkci.callstatus_) - -/* top of a function (first element after its frame) */ -#define functop(func) ((func) + (func)->stkci.framesize) - -/* set top of a function to a specific value */ -#define setfunctop(func,v) ((func)->stkci.framesize = (v) - (func)) - - typedef StackValue *StkId; /* index to stack elements */ /* convert a 'StackValue' to a 'TValue' */ diff --git a/lstate.c b/lstate.c index 76daa2e7..7f67527b 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.144 2017/11/03 12:12:30 roberto Exp roberto $ +** $Id: lstate.c,v 2.143 2017/10/31 17:54:35 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -97,8 +97,51 @@ void luaE_setdebt (global_State *g, l_mem debt) { } +CallInfo *luaE_extendCI (lua_State *L) { + CallInfo *ci = luaM_new(L, CallInfo); + lua_assert(L->ci->next == NULL); + L->ci->next = ci; + ci->previous = L->ci; + ci->next = NULL; + L->nci++; + return ci; +} + + +/* +** free all CallInfo structures not in use by a thread +*/ +void luaE_freeCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next = ci->next; + ci->next = NULL; + while ((ci = next) != NULL) { + next = ci->next; + luaM_free(L, ci); + L->nci--; + } +} + + +/* +** free half of the CallInfo structures not in use by a thread +*/ +void luaE_shrinkCI (lua_State *L) { + CallInfo *ci = L->ci; + CallInfo *next2; /* next's next */ + /* while there are two nexts */ + while (ci->next != NULL && (next2 = ci->next->next) != NULL) { + luaM_free(L, ci->next); /* free next */ + L->nci--; + ci->next = next2; /* remove 'next' from the list */ + next2->previous = ci; + ci = next2; /* keep next's next */ + } +} + + static void stack_init (lua_State *L1, lua_State *L) { - int i; + int i; CallInfo *ci; /* initialize stack array */ L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, StackValue); L1->stacksize = BASIC_STACK_SIZE; @@ -106,19 +149,23 @@ static void stack_init (lua_State *L1, lua_State *L) { setnilvalue(s2v(L1->stack + i)); /* erase new stack */ L1->top = L1->stack; L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; - /* initialize first 'function' */ - L1->func = L1->stack; - L1->func->stkci.previous = 0; /* end of linked list */ - L1->func->stkci.framesize = LUA_MINSTACK + 1; - callstatus(L1->func) = 0; + /* initialize first ci */ + ci = &L1->base_ci; + ci->next = ci->previous = NULL; + ci->callstatus = 0; + ci->func = L1->top; setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */ L1->top++; + ci->top = L1->top + LUA_MINSTACK; + L1->ci = ci; } static void freestack (lua_State *L) { if (L->stack == NULL) return; /* stack not completely built yet */ + L->ci = &L->base_ci; /* free the entire 'ci' list */ + luaE_freeCI(L); lua_assert(L->nci == 0); luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ } @@ -168,7 +215,7 @@ static void f_luaopen (lua_State *L, void *ud) { static void preinit_thread (lua_State *L, global_State *g) { G(L) = g; L->stack = NULL; - L->func = NULL; + L->ci = NULL; L->nci = 0; L->stacksize = 0; L->twups = L; /* thread has no upvalues */ diff --git a/lstate.h b/lstate.h index 07cb3d3d..4798474c 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.148 2017/11/03 17:22:54 roberto Exp roberto $ +** $Id: lstate.h,v 2.146 2017/11/02 11:28:56 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -81,21 +81,47 @@ typedef struct stringtable { } stringtable; +/* +** Information about a call. +*/ +typedef struct CallInfo { + StkId func; /* function index in the stack */ + StkId top; /* top for this function */ + struct CallInfo *previous, *next; /* dynamic call link */ + union { + struct { /* only for Lua functions */ + const Instruction *savedpc; + } l; + struct { /* only for C functions */ + lua_KFunction k; /* continuation in case of yields */ + ptrdiff_t old_errfunc; + lua_KContext ctx; /* context info. in case of yields */ + } c; + } u; + union { + int funcidx; /* called-function index */ + int nyield; /* number of values yielded */ + } u2; + short nresults; /* expected number of results from this function */ + unsigned short callstatus; +} CallInfo; + /* ** Bits in CallInfo status */ #define CIST_OAH (1<<0) /* original value of 'allowhook' */ -#define CIST_HOOKED (1<<1) /* call is running a debug hook */ -#define CIST_FRESH (1<<2) /* call is running on a fresh invocation +#define CIST_LUA (1<<1) /* call is running a Lua function */ +#define CIST_HOOKED (1<<2) /* call is running a debug hook */ +#define CIST_FRESH (1<<3) /* call is running on a fresh invocation of luaV_execute */ -#define CIST_YPCALL (1<<3) /* call is a yieldable protected call */ -#define CIST_TAIL (1<<4) /* call was tail called */ -#define CIST_HOOKYIELD (1<<5) /* last hook called yielded */ -#define CIST_LEQ (1<<6) /* using __lt for __le */ -#define CIST_FIN (1<<7) /* call is running a finalizer */ +#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ +#define CIST_TAIL (1<<5) /* call was tail called */ +#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ +#define CIST_LEQ (1<<7) /* using __lt for __le */ +#define CIST_FIN (1<<8) /* call is running a finalizer */ -#define isLua(func) isLfunction(s2v(func)) +#define isLua(ci) ((ci)->callstatus & CIST_LUA) /* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ #define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) @@ -162,7 +188,7 @@ struct lua_State { lu_byte status; StkId top; /* first free slot in the stack */ global_State *l_G; - StkId func; /* current function */ + CallInfo *ci; /* call info for current function */ const Instruction *oldpc; /* last pc traced */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ @@ -170,6 +196,7 @@ struct lua_State { GCObject *gclist; struct lua_State *twups; /* list of threads with open upvalues */ struct lua_longjmp *errorJmp; /* current error recover point */ + CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ volatile lua_Hook hook; ptrdiff_t errfunc; /* current error handling function (stack index) */ int stacksize; @@ -225,6 +252,9 @@ union GCUnion { LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); +LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); +LUAI_FUNC void luaE_freeCI (lua_State *L); +LUAI_FUNC void luaE_shrinkCI (lua_State *L); #endif diff --git a/ltests.c b/ltests.c index ebf73840..bee734f3 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 2.228 2017/11/03 12:12:30 roberto Exp roberto $ +** $Id: ltests.c,v 2.227 2017/11/02 11:28:56 roberto Exp $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -46,7 +46,7 @@ void *l_Trick = 0; int islocked = 0; -#define obj_at(L,k) s2v(L->func + (k)) +#define obj_at(L,k) s2v(L->ci->func + (k)) static int runC (lua_State *L, lua_State *L1, const char *pc); @@ -309,27 +309,28 @@ static void checkLclosure (global_State *g, LClosure *cl) { } -static int lua_checkpc (StkId func) { - if (!isLua(func)) return 1; +static int lua_checkpc (CallInfo *ci) { + if (!isLua(ci)) return 1; else { - Proto *p = clLvalue(s2v(func))->p; - return p->code <= func->stkci.u.l.savedpc && - func->stkci.u.l.savedpc <= p->code + p->sizecode; + StkId f = ci->func; + Proto *p = clLvalue(s2v(f))->p; + return p->code <= ci->u.l.savedpc && + ci->u.l.savedpc <= p->code + p->sizecode; } } static void checkstack (global_State *g, lua_State *L1) { StkId o; + CallInfo *ci; UpVal *uv; lua_assert(!isdead(g, L1)); for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next) lua_assert(upisopen(uv)); /* must be open */ - for (o = L1->func; o->stkci.previous != 0; o -= o->stkci.previous) { - lua_assert(functop(o) <= L1->stack_last); - lua_assert(lua_checkpc(o)); + for (ci = L1->ci; ci != NULL; ci = ci->previous) { + lua_assert(ci->top <= L1->stack_last); + lua_assert(lua_checkpc(ci)); } - lua_assert(o == L1->stack); if (L1->stack) { /* complete thread? */ for (o = L1->stack; o < L1->stack_last + EXTRA_STACK; o++) checkliveness(L1, s2v(o)); /* entire stack must have valid values */ diff --git a/ltm.c b/ltm.c index 6c13e8d1..91f622e4 100644 --- a/ltm.c +++ b/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.45 2017/10/04 15:49:05 roberto Exp roberto $ +** $Id: ltm.c,v 2.45 2017/10/04 15:49:05 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -108,7 +108,7 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, setobj2s(L, func + 3, p3); /* 3rd argument */ L->top += 4; /* metamethod may yield only when called from Lua code */ - if (isLua(L->func)) + if (isLua(L->ci)) luaD_call(L, func, 0); else luaD_callnoyield(L, func, 0); @@ -124,7 +124,7 @@ void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, setobj2s(L, func + 2, p2); /* 2nd argument */ L->top += 3; /* metamethod may yield only when called from Lua code */ - if (isLua(L->func)) + if (isLua(L->ci)) luaD_call(L, func, 1); else luaD_callnoyield(L, func, 1); diff --git a/lua.h b/lua.h index fe97e8a6..2d8ff838 100644 --- a/lua.h +++ b/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.337 2017/11/02 11:28:56 roberto Exp roberto $ +** $Id: lua.h,v 1.337 2017/11/02 11:28:56 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file @@ -456,8 +456,7 @@ struct lua_Debug { char istailcall; /* (t) */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ - int i_actf; /* active function */ - lua_State *i_actL; /* where active function is active */ + struct CallInfo *i_ci; /* active function */ }; /* }====================================================================== */ diff --git a/lvm.c b/lvm.c index b1cf4666..b5e1c813 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.304 2017/11/03 19:33:22 roberto Exp roberto $ +** $Id: lvm.c,v 2.301 2017/11/01 18:20:48 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -390,9 +390,9 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */ return res; else { /* try 'lt': */ - callstatus(L->func) |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ res = luaT_callorderTM(L, r, l, TM_LT); - callstatus(L->func) ^= CIST_LEQ; /* clear mark */ + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ if (res < 0) luaG_ordererror(L, l, r); return !res; /* result is negated */ @@ -654,14 +654,13 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, } -#define basepc(base) ((base - 1)->stkci.u.l.savedpc) - /* ** finish execution of an opcode interrupted by an yield */ void luaV_finishOp (lua_State *L) { - StkId base = L->func + 1; - Instruction inst = *(basepc(base) - 1); /* interrupted instruction */ + CallInfo *ci = L->ci; + StkId base = ci->func + 1; + Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ OpCode op = GET_OPCODE(inst); switch (op) { /* finish its execution */ case OP_ADDI: case OP_SUBI: @@ -680,14 +679,14 @@ void luaV_finishOp (lua_State *L) { case OP_LE: case OP_LT: case OP_EQ: { int res = !l_isfalse(s2v(L->top - 1)); L->top--; - if (callstatus(base - 1) & CIST_LEQ) { /* "<=" using "<" ? */ + if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ lua_assert(op == OP_LE); - callstatus(base - 1) ^= CIST_LEQ; /* clear mark */ + ci->callstatus ^= CIST_LEQ; /* clear mark */ res = !res; /* negate result */ } - lua_assert(GET_OPCODE(*basepc(base)) == OP_JMP); + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); if (res != GETARG_A(inst)) /* condition failed? */ - basepc(base)++; /* skip jump instruction */ + ci->u.l.savedpc++; /* skip jump instruction */ break; } case OP_CONCAT: { @@ -700,18 +699,18 @@ void luaV_finishOp (lua_State *L) { luaV_concat(L, total); /* concat them (may yield again) */ } /* move final result to final position */ - setobjs2s(L, L->func + 1 + GETARG_A(inst), L->top - 1); - L->top = functop(base - 1); /* restore top */ + setobjs2s(L, ci->func + 1 + GETARG_A(inst), L->top - 1); + L->top = ci->top; /* restore top */ break; } case OP_TFORCALL: { - lua_assert(GET_OPCODE(*basepc(base)) == OP_TFORLOOP); - L->top = functop(base - 1); /* correct top */ + lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP); + L->top = ci->top; /* correct top */ break; } case OP_CALL: { if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ - L->top = functop(base - 1); /* adjust results */ + L->top = ci->top; /* adjust results */ break; } case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: @@ -754,33 +753,31 @@ void luaV_finishOp (lua_State *L) { ** Execute a jump instruction. The 'updatemask' allows signals to stop ** tight loops. (Without it, the local copy of 'mask' could never change.) */ -#define dojump(i,e) { pc += GETARG_sBx(i) + e; updatemask(L); } +#define dojump(ci,i,e) { pc += GETARG_sBx(i) + e; updatemask(L); } /* for test instructions, execute the jump instruction that follows it */ -#define donextjump() { i = *pc; dojump(i, 1); } +#define donextjump(ci) { i = *pc; dojump(ci, i, 1); } /* ** Whenever code can raise errors (including memory errors), the global ** 'pc' must be correct to report occasional errors. */ -#define savepc(base) (basepc(base) = pc) +#define savepc(L) (ci->u.l.savedpc = pc) -/* update internal copies to its correct values */ -#define updatestate() (base = L->func + 1, updatemask(L)) - /* ** Protect code that, in general, can raise errors, reallocate the ** stack, and change the hooks. */ -#define Protect(code) { savepc(base); {code;}; updatestate(); } +#define Protect(code) \ + { savepc(L); {code;}; base = ci->func + 1; updatemask(L); } #define checkGC(L,c) \ - { luaC_condGC(L, L->top = (c), /* limit of live values */ \ - {updatestate(); L->top = functop(base - 1);}); /* restore top */ \ - luai_threadyield(L); } + { luaC_condGC(L, L->top = (c), /* limit of live values */ \ + Protect(L->top = ci->top)); /* restore top */ \ + luai_threadyield(L); } /* fetch an instruction and prepare its execution */ @@ -796,23 +793,26 @@ void luaV_finishOp (lua_State *L) { void luaV_execute (lua_State *L) { + CallInfo *ci = L->ci; LClosure *cl; TValue *k; - StkId base = L->func + 1; /* local copy of 'L->func + 1' */ + StkId base; /* local copy of 'ci->func + 1' */ int mask; /* local copy of 'L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)' */ - const Instruction *pc; /* local copy of 'basepc(base)' */ - callstatus(base - 1) |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ + const Instruction *pc; /* local copy of 'ci->u.l.savedpc' */ + ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ newframe: /* reentry point when frame changes (call/return) */ - cl = clLvalue(s2v(L->func)); /* local reference to function's closure */ + lua_assert(ci == L->ci); + cl = clLvalue(s2v(ci->func)); /* local reference to function's closure */ k = cl->p->k; /* local reference to function's constant table */ updatemask(L); - pc = basepc(base); + base = ci->func + 1; + pc = ci->u.l.savedpc; /* main loop of interpreter */ for (;;) { Instruction i; StkId ra; vmfetch(); - lua_assert(base == L->func + 1); + lua_assert(base == ci->func + 1); lua_assert(base <= L->top && L->top < L->stack + L->stacksize); vmdispatch (GET_OPCODE(i)) { vmcase(OP_MOVE) { @@ -970,7 +970,7 @@ void luaV_execute (lua_State *L) { int b = GETARG_B(i); int c = GETARG_C(i); Table *t; - savepc(base); /* in case of allocation errors */ + savepc(L); /* in case of allocation errors */ t = luaH_new(L); sethvalue2s(L, ra, t); if (b != 0 || c != 0) @@ -1276,7 +1276,7 @@ void luaV_execute (lua_State *L) { rb = base + b; setobjs2s(L, ra, rb); checkGC(L, (ra >= rb ? ra + 1 : rb)); - L->top = functop(base - 1); /* restore top */ + L->top = ci->top; /* restore top */ vmbreak; } vmcase(OP_CLOSE) { @@ -1284,7 +1284,7 @@ void luaV_execute (lua_State *L) { vmbreak; } vmcase(OP_JMP) { - dojump(i, 0); + dojump(ci, i, 0); vmbreak; } vmcase(OP_EQ) { @@ -1294,7 +1294,7 @@ void luaV_execute (lua_State *L) { if (luaV_equalobj(L, rb, rc) != GETARG_A(i)) pc++; else - donextjump(); + donextjump(ci); ) vmbreak; } @@ -1310,7 +1310,7 @@ void luaV_execute (lua_State *L) { if (res != GETARG_A(i)) pc++; else - donextjump(); + donextjump(ci); vmbreak; } vmcase(OP_LE) { @@ -1325,14 +1325,14 @@ void luaV_execute (lua_State *L) { if (res != GETARG_A(i)) pc++; else - donextjump(); + donextjump(ci); vmbreak; } vmcase(OP_TEST) { if (GETARG_C(i) ? l_isfalse(s2v(ra)) : !l_isfalse(s2v(ra))) pc++; else - donextjump(); + donextjump(ci); vmbreak; } vmcase(OP_TESTSET) { @@ -1341,7 +1341,7 @@ void luaV_execute (lua_State *L) { pc++; else { setobj2s(L, ra, rb); - donextjump(); + donextjump(ci); } vmbreak; } @@ -1355,11 +1355,11 @@ void luaV_execute (lua_State *L) { Protect(isC = luaD_precall(L, ra, nresults)); if (isC) { /* C function? */ if (nresults >= 0) /* fixed number of results? */ - L->top = functop(base - 1); /* correct top */ + L->top = ci->top; /* correct top */ /* else leave top for next instruction */ } else { /* Lua function */ - base = L->func + 1; + ci = L->ci; goto newframe; /* restart luaV_execute over new Lua function */ } vmbreak; @@ -1368,14 +1368,16 @@ void luaV_execute (lua_State *L) { int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - savepc(base); + savepc(L); if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ - updatestate(); /* update 'base' */ + Protect((void)0); /* update 'base' */ } else { /* tail call: put called frame (n) in place of caller one (o) */ - StkId nfunc = L->func; /* called function */ - StkId ofunc = nfunc - nfunc->stkci.previous; /* caller function */ + CallInfo *nci = L->ci; /* called frame (new) */ + CallInfo *oci = nci->previous; /* caller frame (old) */ + StkId nfunc = nci->func; /* called function */ + StkId ofunc = oci->func; /* caller function */ /* last stack slot filled by 'precall' */ StkId lim = nfunc + 1 + getproto(s2v(nfunc))->numparams; int aux; @@ -1384,13 +1386,11 @@ void luaV_execute (lua_State *L) { /* move new frame into old one */ for (aux = 0; nfunc + aux < lim; aux++) setobjs2s(L, ofunc + aux, nfunc + aux); - ofunc->stkci.framesize = L->top - nfunc; - L->top = functop(ofunc); /* correct top */ - ofunc->stkci.u.l.savedpc = nfunc->stkci.u.l.savedpc; - callstatus(ofunc) |= CIST_TAIL; /* function was tail called */ - base = ofunc + 1; - L->func = ofunc; - lua_assert(L->top == base + getproto(s2v(ofunc))->maxstacksize); + oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */ + oci->u.l.savedpc = nci->u.l.savedpc; + oci->callstatus |= CIST_TAIL; /* function was tail called */ + ci = L->ci = oci; /* remove new frame */ + lua_assert(L->top == ofunc + 1 + getproto(s2v(ofunc))->maxstacksize); goto newframe; /* restart luaV_execute over new Lua function */ } vmbreak; @@ -1398,16 +1398,16 @@ void luaV_execute (lua_State *L) { vmcase(OP_RETURN) { int b = GETARG_B(i); if (cl->p->sizep > 0) luaF_close(L, base); - savepc(base); - b = luaD_poscall(L, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); - if (callstatus(base - 1) & CIST_FRESH) /* local 'base' still from callee */ + savepc(L); + b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); + if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */ return; /* external invocation: return */ else { /* invocation via reentry: continue execution */ - base = L->func + 1; - if (b) L->top = functop(base - 1); - lua_assert(isLua(base - 1)); - lua_assert(GET_OPCODE(*(basepc(base) - 1)) == OP_CALL); - goto newframe; /* restart luaV_execute over previous Lua function */ + ci = L->ci; + if (b) L->top = ci->top; + lua_assert(isLua(ci)); + lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); + goto newframe; /* restart luaV_execute over new Lua function */ } } vmcase(OP_FORLOOP) { @@ -1451,7 +1451,7 @@ void luaV_execute (lua_State *L) { } else { /* try making all values floats */ lua_Number ninit; lua_Number nlimit; lua_Number nstep; - savepc(base); /* in case of errors */ + savepc(L); /* in case of errors */ if (!tonumber(plimit, &nlimit)) luaG_runerror(L, "'for' limit must be a number"); setfltvalue(plimit, nlimit); @@ -1472,7 +1472,7 @@ void luaV_execute (lua_State *L) { setobjs2s(L, cb, ra); L->top = cb + 3; /* func. + 2 args (state and index) */ Protect(luaD_call(L, cb, GETARG_C(i))); - L->top = functop(base - 1); + L->top = ci->top; i = *(pc++); /* go to next instruction */ ra = RA(i); lua_assert(GET_OPCODE(i) == OP_TFORLOOP); @@ -1497,7 +1497,7 @@ void luaV_execute (lua_State *L) { } h = hvalue(s2v(ra)); last = ((c-1)*LFIELDS_PER_FLUSH) + n; - savepc(base); /* in case of allocation errors */ + savepc(L); /* in case of allocation errors */ if (last > h->sizearray) /* needs more space? */ luaH_resizearray(L, h, last); /* preallocate it at once */ for (; n > 0; n--) { @@ -1506,15 +1506,14 @@ void luaV_execute (lua_State *L) { last--; luaC_barrierback(L, h, val); } - /* correct top (in case of previous open call) */ - L->top = functop(base - 1); + L->top = ci->top; /* correct top (in case of previous open call) */ vmbreak; } vmcase(OP_CLOSURE) { Proto *p = cl->p->p[GETARG_Bx(i)]; LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ if (ncl == NULL) { /* no match? */ - savepc(base); /* in case of allocation errors */ + savepc(L); /* in case of allocation errors */ pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ } else