back to 'CallInfo' (no gains with its removal)

This commit is contained in:
Roberto Ierusalimschy 2017-11-07 11:25:26 -02:00
parent 5a3f26f855
commit ad0704e40c
13 changed files with 394 additions and 370 deletions

81
lapi.c
View File

@ -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 ** Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -10,7 +10,6 @@
#include "lprefix.h" #include "lprefix.h"
#include <limits.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
@ -59,14 +58,15 @@ const char lua_ident[] =
static TValue *index2value (lua_State *L, int idx) { static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
StkId o = L->func + idx; StkId o = ci->func + idx;
api_check(L, idx < L->func->stkci.framesize, "unacceptable index"); api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index");
if (o >= L->top) return NONVALIDVALUE; if (o >= L->top) return NONVALIDVALUE;
else return s2v(o); else return s2v(o);
} }
else if (!ispseudo(idx)) { /* negative index */ 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); return s2v(L->top + idx);
} }
else if (idx == LUA_REGISTRYINDEX) else if (idx == LUA_REGISTRYINDEX)
@ -74,10 +74,10 @@ static TValue *index2value (lua_State *L, int idx) {
else { /* upvalues */ else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx; idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); 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 */ return NONVALIDVALUE; /* it has no upvalues */
else { else {
CClosure *func = clCvalue(s2v(L->func)); CClosure *func = clCvalue(s2v(ci->func));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; 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) { static StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
StkId o = L->func + idx; StkId o = ci->func + idx;
api_check(L, o < L->top, "unacceptable index"); api_check(L, o < L->top, "unacceptable index");
return o; return o;
} }
else { /* non-positive index */ 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"); api_check(L, !ispseudo(idx), "invalid index");
return L->top + idx; 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) { LUA_API int lua_checkstack (lua_State *L, int n) {
int res; int res;
int frameuse = L->top - L->func; CallInfo *ci = L->ci;
lua_lock(L); lua_lock(L);
api_check(L, n >= 0, "negative 'n'"); api_check(L, n >= 0, "negative 'n'");
if (n >= USHRT_MAX - frameuse) if (L->stack_last - L->top > n) /* stack large enough? */
res = 0; /* frame size overflow */
else if (L->stack_last - L->top > n) /* stack large enough? */
res = 1; /* yes; check is OK */ res = 1; /* yes; check is OK */
else { /* no; need to grow stack */ else { /* no; need to grow stack */
int inuse = cast_int(L->top - L->stack) + EXTRA_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 */ else /* try to grow stack */
res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK);
} }
if (res && L->func->stkci.framesize < frameuse + n) if (res && ci->top < L->top + n)
L->func->stkci.framesize = frameuse + n; /* adjust frame size */ ci->top = L->top + n; /* adjust frame top */
lua_unlock(L); lua_unlock(L);
return res; return res;
} }
@ -137,7 +136,7 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to); lua_lock(to);
api_checknelems(from, n); api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states"); 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; from->top -= n;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
setobjs2s(to, to->top, from->top + 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) { LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx)) return (idx > 0 || ispseudo(idx))
? 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) { 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) { LUA_API void lua_settop (lua_State *L, int idx) {
StkId func = L->func; StkId func = L->ci->func;
lua_lock(L); lua_lock(L);
if (idx >= 0) { if (idx >= 0) {
api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); 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); api_checkvalidindex(L, to);
setobj(L, to, fr); setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */ 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 /* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */ (collector revisits it before finishing collection) */
lua_unlock(L); lua_unlock(L);
@ -932,24 +931,23 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
#define checkresults(L,na,nr) \ #define checkresults(L,na,nr) \
api_check(L, (nr) == LUA_MULTRET || \ api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
(functop(L->func) - L->top >= (nr) - (na)), \ "results from function overflow current stack size")
"results from function overflow current frame size")
LUA_API void lua_callk (lua_State *L, int nargs, int nresults, LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
lua_KContext ctx, lua_KFunction k) { lua_KContext ctx, lua_KFunction k) {
StkId func; StkId func;
lua_lock(L); lua_lock(L);
api_check(L, k == NULL || !isLua(L->func), api_check(L, k == NULL || !isLua(L->ci),
"cannot use continuations inside hooks"); "cannot use continuations inside hooks");
api_checknelems(L, nargs+1); api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults); checkresults(L, nargs, nresults);
func = L->top - (nargs+1); func = L->top - (nargs+1);
if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ if (k != NULL && L->nny == 0) { /* need to prepare continuation? */
L->func->stkci.u.c.k = k; /* save continuation */ L->ci->u.c.k = k; /* save continuation */
L->func->stkci.u.c.ctx = ctx; /* save context */ L->ci->u.c.ctx = ctx; /* save context */
luaD_call(L, func, nresults); /* do the call */ luaD_call(L, func, nresults); /* do the call */
} }
else /* no continuation or no yieldable */ 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) { lua_KContext ctx, lua_KFunction k) {
struct CallS c; struct CallS c;
int status; int status;
ptrdiff_t efunc; ptrdiff_t func;
lua_lock(L); lua_lock(L);
api_check(L, k == NULL || !isLua(L->func), api_check(L, k == NULL || !isLua(L->ci),
"cannot use continuations inside hooks"); "cannot use continuations inside hooks");
api_checknelems(L, nargs+1); api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults); checkresults(L, nargs, nresults);
if (errfunc == 0) if (errfunc == 0)
efunc = 0; func = 0;
else { else {
StkId o = index2stack(L, errfunc); StkId o = index2stack(L, errfunc);
efunc = savestack(L, o); func = savestack(L, o);
} }
c.func = L->top - (nargs+1); /* function to be called */ c.func = L->top - (nargs+1); /* function to be called */
if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */ if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */ 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') */ else { /* prepare continuation (call is already protected by 'resume') */
StkId func = L->func; CallInfo *ci = L->ci;
func->stkci.u.c.k = k; /* save continuation */ ci->u.c.k = k; /* save continuation */
func->stkci.u.c.ctx = ctx; /* save context */ ci->u.c.ctx = ctx; /* save context */
/* save information for error recovery */ /* save information for error recovery */
func->stkci.u2.funcidx = c.func - func; ci->u2.funcidx = savestack(L, c.func);
func->stkci.u.c.old_errfunc = L->errfunc; ci->u.c.old_errfunc = L->errfunc;
L->errfunc = efunc; L->errfunc = func;
setoah(callstatus(func), L->allowhook); /* save value of 'allowhook' */ setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */
callstatus(func) |= CIST_YPCALL; /* function can do error recovery */ ci->callstatus |= CIST_YPCALL; /* function can do error recovery */
luaD_call(L, c.func, nresults); /* do the call */ luaD_call(L, c.func, nresults); /* do the call */
func = L->func; /* previous call can reallocate stack */ ci->callstatus &= ~CIST_YPCALL;
callstatus(func) &= ~CIST_YPCALL; L->errfunc = ci->u.c.old_errfunc;
L->errfunc = func->stkci.u.c.old_errfunc;
status = LUA_OK; /* if it is here, there were no errors */ status = LUA_OK; /* if it is here, there were no errors */
} }
adjustresults(L, nresults); adjustresults(L, nresults);

9
lapi.h
View File

@ -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 ** Auxiliary functions from Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -11,14 +11,13 @@
#include "llimits.h" #include "llimits.h"
#include "lstate.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");} "stack overflow");}
#define adjustresults(L,nres) \ #define adjustresults(L,nres) \
{ if ((nres) == LUA_MULTRET && functop(L->func) < L->top) \ { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
setfunctop(L->func, 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") "not enough elements in the stack")

161
ldebug.c
View File

@ -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 ** Debug Interface
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -34,17 +34,17 @@
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)
/* Active Lua function (given stack function) */ /* Active Lua function (given call info) */
#define ci_func(func) (clLvalue(s2v(func))) #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); const char **name);
static int currentpc (StkId func) { static int currentpc (CallInfo *ci) {
lua_assert(isLua(func)); lua_assert(isLua(ci));
return pcRel(func->stkci.u.l.savedpc, ci_func(func)->p); 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) { static int currentline (CallInfo *ci) {
return luaG_getfuncline(ci_func(func)->p, currentpc(func)); 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; mask = 0;
func = NULL; func = NULL;
} }
if (isLua(L->func)) if (isLua(L->ci))
L->oldpc = L->func->stkci.u.l.savedpc; L->oldpc = L->ci->u.l.savedpc;
L->hook = func; L->hook = func;
L->basehookcount = count; L->basehookcount = count;
resethookcount(L); 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) { LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
int status; int status;
StkId func; CallInfo *ci;
if (level < 0) return 0; /* invalid (negative) level */ if (level < 0) return 0; /* invalid (negative) level */
lua_lock(L); lua_lock(L);
for (func = L->func; for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)
level > 0 && func->stkci.previous != 0;
func -= func->stkci.previous)
level--; level--;
if (level == 0 && func->stkci.previous != 0) { /* level found? */ if (level == 0 && ci != &L->base_ci) { /* level found? */
status = 1; status = 1;
ar->i_actf = func - L->stack; ar->i_ci = ci;
ar->i_actL = L;
} }
else status = 0; /* no such level */ else status = 0; /* no such level */
lua_unlock(L); lua_unlock(L);
@ -171,34 +168,24 @@ static const char *upvalname (Proto *p, int uv) {
} }
static StkId findcalled (lua_State *L, StkId caller) { static const char *findlocal (lua_State *L, CallInfo *ci, int n,
StkId func = L->func; StkId *pos) {
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) {
const char *name = NULL; const char *name = NULL;
StkId stkf = ar->i_actL->stack + ar->i_actf; StkId base;
if (isLua(stkf)) { if (isLua(ci)) {
name = luaF_getlocalname(ci_func(stkf)->p, n, currentpc(stkf)); 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? */ if (name == NULL) { /* no 'standard' name? */
StkId limit = (stkf == L->func) ? L->top : findcalled(L, stkf); StkId limit = (ci == L->ci) ? L->top : ci->next->func;
if (limit - stkf > n && n > 0) /* is 'n' inside 'ci' stack? */ if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */
name = "(*temporary)"; /* generic name for any valid slot */ name = "(*temporary)"; /* generic name for any valid slot */
else else
return NULL; /* no name */ return NULL; /* no name */
} }
*pos = stkf + n; *pos = base + (n - 1);
return name; 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' */ else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */ StkId pos = NULL; /* to avoid warnings */
name = findlocal(L, ar, n, &pos); name = findlocal(L, ar->i_ci, n, &pos);
if (name) { if (name) {
setobjs2s(L, L->top, pos); setobjs2s(L, L->top, pos);
api_incr_top(L); 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 */ StkId pos = NULL; /* to avoid warnings */
const char *name; const char *name;
lua_lock(L); lua_lock(L);
name = findlocal(L, ar, n, &pos); name = findlocal(L, ar->i_ci, n, &pos);
if (name) { if (name) {
setobjs2s(L, pos, L->top - 1); setobjs2s(L, pos, L->top - 1);
L->top--; /* pop value */ 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) { static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
if (stkf == NULL) /* no function? */ if (ci == NULL) /* no 'ci'? */
return NULL; /* no info */ 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"; *name = "__gc";
return "metamethod"; /* report it as such */ return "metamethod"; /* report it as such */
} }
/* calling function is a known Lua function? */ /* calling function is a known Lua function? */
else { else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
StkId previous = stkf - stkf->stkci.previous; return funcnamefromcode(L, ci->previous, name);
if (!(callstatus(stkf) & CIST_TAIL) && isLua(previous)) else return NULL; /* no way to find a name */
return funcnamefromcode(L, previous, name);
else return NULL; /* no way to find a name */
}
} }
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
Closure *f, StkId stkf) { Closure *f, CallInfo *ci) {
int status = 1; int status = 1;
for (; *what; what++) { for (; *what; what++) {
switch (*what) { switch (*what) {
@ -314,7 +298,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
break; break;
} }
case 'l': { case 'l': {
ar->currentline = (stkf && isLua(stkf)) ? currentline(stkf) : -1; ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1;
break; break;
} }
case 'u': { case 'u': {
@ -330,11 +314,11 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
break; break;
} }
case 't': { case 't': {
ar->istailcall = (stkf) ? callstatus(stkf) & CIST_TAIL : 0; ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
break; break;
} }
case 'n': { case 'n': {
ar->namewhat = getfuncname(L, stkf, &ar->name); ar->namewhat = getfuncname(L, ci, &ar->name);
if (ar->namewhat == NULL) { if (ar->namewhat == NULL) {
ar->namewhat = ""; /* not found */ ar->namewhat = ""; /* not found */
ar->name = NULL; 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) { LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
int status; int status;
Closure *cl; Closure *cl;
StkId stkf; CallInfo *ci;
TValue *func; TValue *func;
lua_lock(L); lua_lock(L);
if (*what == '>') { if (*what == '>') {
stkf = NULL; ci = NULL;
func = s2v(L->top - 1); func = s2v(L->top - 1);
api_check(L, ttisfunction(func), "function expected"); api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */ what++; /* skip the '>' */
L->top--; /* pop function */ L->top--; /* pop function */
} }
else { else {
stkf = ar->i_actL->stack + ar->i_actf; ci = ar->i_ci;
func = s2v(stkf); func = s2v(ci->func);
lua_assert(ttisfunction(func)); lua_assert(ttisfunction(func));
} }
cl = ttisclosure(func) ? clvalue(func) : NULL; cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, stkf); status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) { if (strchr(what, 'f')) {
setobj2s(L, L->top, func); setobj2s(L, L->top, func);
api_incr_top(L); 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", ** Returns what the name is (e.g., "for iterator", "method",
** "metamethod") and sets '*name' to point to the name. ** "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) { const char **name) {
TMS tm = (TMS)0; /* (initial value avoids warnings) */ TMS tm = (TMS)0; /* (initial value avoids warnings) */
Proto *p = ci_func(stkf)->p; /* calling function */ Proto *p = ci_func(ci)->p; /* calling function */
int pc = currentpc(stkf); /* calling instruction index */ int pc = currentpc(ci); /* calling instruction index */
Instruction i = p->code[pc]; /* calling instruction */ 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 = "?"; *name = "?";
return "hook"; 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 ** not ISO C, but it should not crash a program; the subsequent
** checks are ISO C and ensure a correct result. ** checks are ISO C and ensure a correct result.
*/ */
static int isinstack (lua_State *L, const TValue *o) { static int isinstack (CallInfo *ci, const TValue *o) {
StkId base = L->stack; StkId base = ci->func + 1;
ptrdiff_t i = cast(StkId, o) - base; 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 ** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on
** upvalues.) ** upvalues.)
*/ */
static const char *getupvalname (StkId stkf, const TValue *o, static const char *getupvalname (CallInfo *ci, const TValue *o,
const char **name) { const char **name) {
LClosure *c = ci_func(stkf); LClosure *c = ci_func(ci);
int i; int i;
for (i = 0; i < c->nupvalues; i++) { for (i = 0; i < c->nupvalues; i++) {
if (c->upvals[i]->v == o) { 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) { static const char *varinfo (lua_State *L, const TValue *o) {
const char *name = NULL; /* to avoid warnings */ const char *name = NULL; /* to avoid warnings */
StkId stkf = L->func; CallInfo *ci = L->ci;
const char *kind = NULL; const char *kind = NULL;
if (isLua(stkf)) { if (isLua(ci)) {
kind = getupvalname(stkf, o, &name); /* check whether 'o' is an upvalue */ kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
if (!kind && isinstack(L, o)) /* no? try a register */ if (!kind && isinstack(ci, o)) /* no? try a register */
kind = getobjname(ci_func(stkf)->p, currentpc(stkf), kind = getobjname(ci_func(ci)->p, currentpc(ci),
cast_int(cast(StkId, o) - (stkf + 1)), &name); cast_int(cast(StkId, o) - (ci->func + 1)), &name);
} }
return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, 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, ...) { l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
StkId func; CallInfo *ci = L->ci;
const char *msg; const char *msg;
va_list argp; va_list argp;
luaC_checkGC(L); /* error message uses memory */ luaC_checkGC(L); /* error message uses memory */
va_start(argp, fmt); va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */ msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp); va_end(argp);
func = L->func; /* previous calls can change the stack */ if (isLua(ci)) /* if Lua function, add source:line information */
if (isLua(func)) /* if Lua function, add source:line information */ luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci));
luaG_addinfo(L, msg, ci_func(func)->p->source, currentline(func));
luaG_errormsg(L); luaG_errormsg(L);
} }
@ -756,37 +739,35 @@ static int changedline (Proto *p, int oldpc, int newpc) {
void luaG_traceexec (lua_State *L) { void luaG_traceexec (lua_State *L) {
StkId func = L->func; CallInfo *ci = L->ci;
lu_byte mask = L->hookmask; lu_byte mask = L->hookmask;
int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
if (counthook) if (counthook)
resethookcount(L); /* reset count */ resethookcount(L); /* reset count */
else if (!(mask & LUA_MASKLINE)) else if (!(mask & LUA_MASKLINE))
return; /* no line hook and count != 0; nothing to be done */ return; /* no line hook and count != 0; nothing to be done */
if (callstatus(func) & CIST_HOOKYIELD) { /* called hook last time? */ if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
callstatus(func) &= ~CIST_HOOKYIELD; /* erase mark */ ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
return; /* do not call hook again (VM yielded, so it did not move) */ return; /* do not call hook again (VM yielded, so it did not move) */
} }
if (counthook) if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */
if (mask & LUA_MASKLINE) { if (mask & LUA_MASKLINE) {
Proto *p = ci_func(func)->p; Proto *p = ci_func(ci)->p;
int npc = pcRel(func->stkci.u.l.savedpc, p); int npc = pcRel(ci->u.l.savedpc, p);
if (npc == 0 || /* call linehook when enter a new function, */ if (npc == 0 || /* call linehook when enter a new function, */
func->stkci.u.l.savedpc <= L->oldpc || /* when jump back (loop), */ ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */
changedline(p, pcRel(L->oldpc, p), npc)) { /* when enter new line */ changedline(p, pcRel(L->oldpc, p), npc)) { /* enter new line */
int newline = luaG_getfuncline(p, npc); /* new line */ int newline = luaG_getfuncline(p, npc); /* new line */
luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */
} }
} }
func = L->func; /* previous calls can reallocate stack */ L->oldpc = ci->u.l.savedpc;
L->oldpc = func->stkci.u.l.savedpc;
if (L->status == LUA_YIELD) { /* did hook yield? */ if (L->status == LUA_YIELD) { /* did hook yield? */
if (counthook) if (counthook)
L->hookcount = 1; /* undo decrement to zero */ L->hookcount = 1; /* undo decrement to zero */
/* undo increment (resume will increment it again) */ ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
func->stkci.u.l.savedpc--; ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
callstatus(func) |= CIST_HOOKYIELD; /* mark that it yielded */
luaD_throw(L, LUA_YIELD); luaD_throw(L, LUA_YIELD);
} }
} }

190
ldo.c
View File

@ -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 ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** 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 */ else { /* no handler at all; abort */
if (g->panic) { /* panic function? */ if (g->panic) { /* panic function? */
seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */
if (functop(L->func) < L->top) /* check invariant */ if (L->ci->top < L->top)
setfunctop(L->func, L->top); L->ci->top = L->top; /* pushing msg. can break this invariant */
lua_unlock(L); lua_unlock(L);
g->panic(L); /* call panic function (last chance to jump out) */ 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) { static void correctstack (lua_State *L, StkId oldstack) {
CallInfo *ci;
UpVal *up; UpVal *up;
L->top = (L->top - oldstack) + L->stack; 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) for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v = s2v((uplevel(up) - oldstack) + L->stack); 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) { static int stackinuse (lua_State *L) {
CallInfo *ci;
StkId lim = L->top; StkId lim = L->top;
StkId func = L->func; for (ci = L->ci; ci != NULL; ci = ci->previous) {
for (; func->stkci.previous != 0; func -= func->stkci.previous) { if (lim < ci->top) lim = ci->top;
if (lim < functop(func))
lim = functop(func);
} }
lua_assert(lim <= L->stack_last); lua_assert(lim <= L->stack_last);
return cast_int(lim - L->stack) + 1; /* part of stack in use */ 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; int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
if (goodsize > LUAI_MAXSTACK) if (goodsize > LUAI_MAXSTACK)
goodsize = LUAI_MAXSTACK; /* respect stack limit */ 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 /* if thread is currently not handling a stack overflow and its
good size is smaller than current size, shrink its stack */ good size is smaller than current size, shrink its stack */
if (inuse <= (LUAI_MAXSTACK - EXTRA_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) { void luaD_hook (lua_State *L, int event, int line) {
lua_Hook hook = L->hook; lua_Hook hook = L->hook;
if (hook && L->allowhook) { /* make sure there is a hook */ if (hook && L->allowhook) { /* make sure there is a hook */
CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top); ptrdiff_t top = savestack(L, L->top);
int origframesize = L->func->stkci.framesize; ptrdiff_t ci_top = savestack(L, ci->top);
int tmpframesize; /* frame size to run hook */
lua_Debug ar; lua_Debug ar;
ar.event = event; ar.event = event;
ar.currentline = line; ar.currentline = line;
ar.i_actf = L->func - L->stack; ar.i_ci = ci;
ar.i_actL = L;
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
tmpframesize = L->top - L->func + LUA_MINSTACK; ci->top = L->top + LUA_MINSTACK;
if (tmpframesize > origframesize) /* need to grow frame? */ lua_assert(ci->top <= L->stack_last);
L->func->stkci.framesize = tmpframesize;
lua_assert(functop(L->func) <= L->stack_last);
L->allowhook = 0; /* cannot call hooks inside a hook */ L->allowhook = 0; /* cannot call hooks inside a hook */
callstatus(L->func) |= CIST_HOOKED; ci->callstatus |= CIST_HOOKED;
lua_unlock(L); lua_unlock(L);
(*hook)(L, &ar); (*hook)(L, &ar);
lua_lock(L); lua_lock(L);
lua_assert(!L->allowhook); lua_assert(!L->allowhook);
L->allowhook = 1; L->allowhook = 1;
L->func->stkci.framesize = origframesize; ci->top = restorestack(L, ci_top);
L->top = restorestack(L, 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; int hook = LUA_HOOKCALL;
StkId func = L->func; ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */
StkId previous = func - L->func->stkci.previous; if (isLua(ci->previous) &&
func->stkci.u.l.savedpc++; /* hooks assume 'pc' is already incremented */ GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) {
if (isLua(previous) && ci->callstatus |= CIST_TAIL;
GET_OPCODE(*(previous->stkci.u.l.savedpc - 1)) == OP_TAILCALL) {
callstatus(L->func) |= CIST_TAIL;
hook = LUA_HOOKTAILCALL; hook = LUA_HOOKTAILCALL;
} }
luaD_hook(L, hook, -1); luaD_hook(L, hook, -1);
func = L->func; /* previous call can change stack */ ci->u.l.savedpc--; /* correct 'pc' */
func->stkci.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 ** moves current number of results to proper place; returns 0 iff call
** wanted multiple (variable number of) results. ** wanted multiple (variable number of) results.
*/ */
int luaD_poscall (lua_State *L, StkId firstResult, int nres) { int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
StkId res = L->func; /* res == final position of 1st result */ StkId res;
int wanted = res->stkci.nresults; int wanted = ci->nresults;
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
if (L->hookmask & LUA_MASKRET) { if (L->hookmask & LUA_MASKRET) {
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
luaD_hook(L, LUA_HOOKRET, -1); luaD_hook(L, LUA_HOOKRET, -1);
firstResult = restorestack(L, fr); firstResult = restorestack(L, fr);
res = L->func;
} }
/* 'oldpc' for caller function */ L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
L->oldpc = (res - res->stkci.previous)->stkci.u.l.savedpc;
} }
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 */ /* move results to proper place */
return moveresults(L, firstResult, res, nres, wanted); 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 ** Prepares a function call: checks the stack, creates a new CallInfo
** entry, fills in the relevant information, calls hook if needed. ** 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) { int luaD_precall (lua_State *L, StkId func, int nresults) {
lua_CFunction f; lua_CFunction f;
TValue *funcv = s2v(func); TValue *funcv = s2v(func);
CallInfo *ci;
switch (ttype(funcv)) { switch (ttype(funcv)) {
case LUA_TCCL: /* C closure */ case LUA_TCCL: /* C closure */
f = clCvalue(funcv)->f; f = clCvalue(funcv)->f;
@ -393,19 +398,19 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
Cfunc: { Cfunc: {
int n; /* number of returns */ int n; /* number of returns */
checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
func->stkci.nresults = nresults; ci = next_ci(L); /* now 'enter' new function */
func->stkci.previous = func - L->func; ci->nresults = nresults;
L->func = func; ci->func = func;
setfunctop(func, L->top + LUA_MINSTACK); ci->top = L->top + LUA_MINSTACK;
lua_assert(functop(func) <= L->stack_last); lua_assert(ci->top <= L->stack_last);
callstatus(func) = 0; ci->callstatus = 0;
if (L->hookmask & LUA_MASKCALL) if (L->hookmask & LUA_MASKCALL)
luaD_hook(L, LUA_HOOKCALL, -1); luaD_hook(L, LUA_HOOKCALL, -1);
lua_unlock(L); lua_unlock(L);
n = (*f)(L); /* do the actual call */ n = (*f)(L); /* do the actual call */
lua_lock(L); lua_lock(L);
api_checknelems(L, n); api_checknelems(L, n);
luaD_poscall(L, L->top - n, n); luaD_poscall(L, ci, L->top - n, n);
return 1; return 1;
} }
case LUA_TLCL: { /* Lua function: prepare its call */ 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 */ setnilvalue(s2v(L->top++)); /* complete missing arguments */
if (p->is_vararg) if (p->is_vararg)
luaT_adjustvarargs(L, p, n); luaT_adjustvarargs(L, p, n);
func->stkci.nresults = nresults; ci = next_ci(L); /* now 'enter' new function */
func->stkci.previous = func - L->func; ci->nresults = nresults;
func->stkci.framesize = fsize + 1; /* size includes function itself */ ci->func = func;
L->func = func; L->top = ci->top = func + 1 + fsize;
L->top = func + 1 + fsize; lua_assert(ci->top <= L->stack_last);
lua_assert(functop(func) <= L->stack_last); ci->u.l.savedpc = p->code; /* starting point */
func->stkci.u.l.savedpc = p->code; /* starting point */ ci->callstatus = CIST_LUA;
callstatus(func) = 0;
if (L->hookmask & LUA_MASKCALL) if (L->hookmask & LUA_MASKCALL)
callhook(L); callhook(L, ci);
return 0; return 0;
} }
default: { /* not a function */ default: { /* not a function */
@ -483,25 +487,24 @@ void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
** continuation function. ** continuation function.
*/ */
static void finishCcall (lua_State *L, int status) { static void finishCcall (lua_State *L, int status) {
StkId func = L->func; CallInfo *ci = L->ci;
int n; int n;
/* must have a continuation and must be able to call it */ /* 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 */ /* error status can only happen in a protected call */
lua_assert((callstatus(func) & CIST_YPCALL) || status == LUA_YIELD); lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
if (callstatus(func) & CIST_YPCALL) { /* was inside a pcall? */ if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
callstatus(func) &= ~CIST_YPCALL; /* continuation is also inside it */ ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */
L->errfunc = func->stkci.u.c.old_errfunc; /* with same error function */ L->errfunc = ci->u.c.old_errfunc; /* with the same error function */
} }
/* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
handled */ handled */
adjustresults(L, func->stkci.nresults); adjustresults(L, ci->nresults);
lua_unlock(L); lua_unlock(L);
/* call continuation function */ n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */
n = (*func->stkci.u.c.k)(L, status, func->stkci.u.c.ctx);
lua_lock(L); lua_lock(L);
api_checknelems(L, n); 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) { static void unroll (lua_State *L, void *ud) {
if (ud != NULL) /* error status? */ if (ud != NULL) /* error status? */
finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */
while (L->func != L->stack) { /* something in the stack */ while (L->ci != &L->base_ci) { /* something in the stack */
if (!isLua(L->func)) /* C function? */ if (!isLua(L->ci)) /* C function? */
finishCcall(L, LUA_YIELD); /* complete its execution */ finishCcall(L, LUA_YIELD); /* complete its execution */
else { /* Lua function */ else { /* Lua function */
luaV_finishOp(L); /* finish interrupted instruction */ 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 ** Try to find a suspended protected call (a "recover point") for the
** given thread. ** given thread.
*/ */
static StkId findpcall (lua_State *L) { static CallInfo *findpcall (lua_State *L) {
StkId func; CallInfo *ci;
for (func = L->func; for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */
func->stkci.previous != 0; if (ci->callstatus & CIST_YPCALL)
func -= func->stkci.previous) { return ci;
if (callstatus(func) & CIST_YPCALL)
return func;
} }
return NULL; /* no pending pcall */ return NULL; /* no pending pcall */
} }
@ -550,17 +551,17 @@ static StkId findpcall (lua_State *L) {
*/ */
static int recover (lua_State *L, int status) { static int recover (lua_State *L, int status) {
StkId oldtop; StkId oldtop;
StkId recf = findpcall(L); CallInfo *ci = findpcall(L);
if (recf == NULL) return 0; /* no recovery point */ if (ci == NULL) return 0; /* no recovery point */
/* "finish" luaD_pcall */ /* "finish" luaD_pcall */
oldtop = recf + recf->stkci.u2.funcidx; oldtop = restorestack(L, ci->u2.funcidx);
luaF_close(L, oldtop); luaF_close(L, oldtop);
seterrorobj(L, status, oldtop); seterrorobj(L, status, oldtop);
L->func = recf; L->ci = ci;
L->allowhook = getoah(callstatus(recf)); /* restore original 'allowhook' */ L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */
L->nny = 0; /* should be zero to be yieldable */ L->nny = 0; /* should be zero to be yieldable */
luaD_shrinkstack(L); luaD_shrinkstack(L);
L->errfunc = recf->stkci.u.c.old_errfunc; L->errfunc = ci->u.c.old_errfunc;
return 1; /* continue running the coroutine */ 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) { static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */ int n = *(cast(int*, ud)); /* number of arguments */
StkId firstArg = L->top - n; /* first argument */ StkId firstArg = L->top - n; /* first argument */
StkId func = L->func; CallInfo *ci = L->ci;
if (L->status == LUA_OK) { /* starting a coroutine? */ if (L->status == LUA_OK) { /* starting a coroutine? */
if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
luaV_execute(L); /* call it */ luaV_execute(L); /* call it */
@ -597,18 +598,17 @@ static void resume (lua_State *L, void *ud) {
else { /* resuming from previous yield */ else { /* resuming from previous yield */
lua_assert(L->status == LUA_YIELD); lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */ 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 */ luaV_execute(L); /* just continue running Lua code */
else { /* 'common' yield */ 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); lua_unlock(L);
/* call continuation */ n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */
n = (*func->stkci.u.c.k)(L, LUA_YIELD, func->stkci.u.c.ctx);
lua_lock(L); lua_lock(L);
api_checknelems(L, n); api_checknelems(L, n);
firstArg = L->top - n; /* yield results come from continuation */ 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 */ 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 */ unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */
lua_lock(L); lua_lock(L);
if (L->status == LUA_OK) { /* may be starting a coroutine */ 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); return resume_error(L, "cannot resume non-suspended coroutine", nargs);
} }
else if (L->status != LUA_YIELD) 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? */ if (errorstatus(status)) { /* unrecoverable error? */
L->status = cast_byte(status); /* mark thread as 'dead' */ L->status = cast_byte(status); /* mark thread as 'dead' */
seterrorobj(L, status, L->top); /* push error message */ 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 */ else lua_assert(status == L->status); /* normal end or yield */
} }
*nresults = (status == LUA_YIELD) ? L->func->stkci.u2.nyield *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
: L->top - (L->func + 1); : L->top - (L->ci->func + 1);
L->nny = oldnny; /* restore 'nny' */ L->nny = oldnny; /* restore 'nny' */
L->nCcalls--; L->nCcalls--;
lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); 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_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
lua_KFunction k) { lua_KFunction k) {
StkId func = L->func; CallInfo *ci = L->ci;
luai_userstateyield(L, nresults); luai_userstateyield(L, nresults);
lua_lock(L); lua_lock(L);
api_checknelems(L, nresults); 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"); luaG_runerror(L, "attempt to yield from outside a coroutine");
} }
L->status = LUA_YIELD; 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"); api_check(L, k == NULL, "hooks cannot continue after yielding");
func->stkci.u2.nyield = 0; /* no results */ ci->u2.nyield = 0; /* no results */
} }
else { else {
if ((func->stkci.u.c.k = k) != NULL) /* is there a continuation? */ if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
func->stkci.u.c.ctx = ctx; /* save context */ ci->u.c.ctx = ctx; /* save context */
func->stkci.u2.nyield = nresults; /* save number of results */ ci->u2.nyield = nresults; /* save number of results */
luaD_throw(L, LUA_YIELD); 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); lua_unlock(L);
return 0; /* return to 'luaD_hook' */ 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, int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t old_top, ptrdiff_t ef) { ptrdiff_t old_top, ptrdiff_t ef) {
int status; int status;
ptrdiff_t oldfunc = savestack(L, L->func); CallInfo *old_ci = L->ci;
lu_byte old_allowhooks = L->allowhook; lu_byte old_allowhooks = L->allowhook;
unsigned short old_nny = L->nny; unsigned short old_nny = L->nny;
ptrdiff_t old_errfunc = L->errfunc; 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); StkId oldtop = restorestack(L, old_top);
luaF_close(L, oldtop); /* close possible pending closures */ luaF_close(L, oldtop); /* close possible pending closures */
seterrorobj(L, status, oldtop); seterrorobj(L, status, oldtop);
L->func = restorestack(L, oldfunc); L->ci = old_ci;
L->allowhook = old_allowhooks; L->allowhook = old_allowhooks;
L->nny = old_nny; L->nny = old_nny;
luaD_shrinkstack(L); luaD_shrinkstack(L);

5
ldo.h
View File

@ -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 ** Stack and Call structure of Lua
** See Copyright Notice in lua.h ** 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 void luaD_callnoyield (lua_State *L, StkId func, int nResults);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef); 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_reallocstack (lua_State *L, int newsize);
LUAI_FUNC void luaD_growstack (lua_State *L, int n); LUAI_FUNC void luaD_growstack (lua_State *L, int n);
LUAI_FUNC void luaD_shrinkstack (lua_State *L); LUAI_FUNC void luaD_shrinkstack (lua_State *L);

6
lgc.c
View File

@ -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 ** Garbage Collector
** See Copyright Notice in lua.h ** 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, tm); /* push finalizer... */
setobj2s(L, L->top + 1, &v); /* ... and its argument */ setobj2s(L, L->top + 1, &v); /* ... and its argument */
L->top += 2; /* and (next line) call the finalizer */ 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); 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 */ L->allowhook = oldah; /* restore hooks */
g->gcrunning = running; /* restore state */ g->gcrunning = running; /* restore state */
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */

View File

@ -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 ** Type definitions for Lua objects
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -311,39 +311,9 @@ typedef struct TValue {
typedef union StackValue { typedef union StackValue {
TValue val; 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; } 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 */ typedef StackValue *StkId; /* index to stack elements */
/* convert a 'StackValue' to a 'TValue' */ /* convert a 'StackValue' to a 'TValue' */

View File

@ -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 ** Global State
** See Copyright Notice in lua.h ** 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) { static void stack_init (lua_State *L1, lua_State *L) {
int i; int i; CallInfo *ci;
/* initialize stack array */ /* initialize stack array */
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, StackValue); L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, StackValue);
L1->stacksize = BASIC_STACK_SIZE; 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 */ setnilvalue(s2v(L1->stack + i)); /* erase new stack */
L1->top = L1->stack; L1->top = L1->stack;
L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;
/* initialize first 'function' */ /* initialize first ci */
L1->func = L1->stack; ci = &L1->base_ci;
L1->func->stkci.previous = 0; /* end of linked list */ ci->next = ci->previous = NULL;
L1->func->stkci.framesize = LUA_MINSTACK + 1; ci->callstatus = 0;
callstatus(L1->func) = 0; ci->func = L1->top;
setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */ setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */
L1->top++; L1->top++;
ci->top = L1->top + LUA_MINSTACK;
L1->ci = ci;
} }
static void freestack (lua_State *L) { static void freestack (lua_State *L) {
if (L->stack == NULL) if (L->stack == NULL)
return; /* stack not completely built yet */ return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
lua_assert(L->nci == 0); lua_assert(L->nci == 0);
luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ 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) { static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g; G(L) = g;
L->stack = NULL; L->stack = NULL;
L->func = NULL; L->ci = NULL;
L->nci = 0; L->nci = 0;
L->stacksize = 0; L->stacksize = 0;
L->twups = L; /* thread has no upvalues */ L->twups = L; /* thread has no upvalues */

View File

@ -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 ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -81,21 +81,47 @@ typedef struct stringtable {
} 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 ** Bits in CallInfo status
*/ */
#define CIST_OAH (1<<0) /* original value of 'allowhook' */ #define CIST_OAH (1<<0) /* original value of 'allowhook' */
#define CIST_HOOKED (1<<1) /* call is running a debug hook */ #define CIST_LUA (1<<1) /* call is running a Lua function */
#define CIST_FRESH (1<<2) /* call is running on a fresh invocation #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 */ of luaV_execute */
#define CIST_YPCALL (1<<3) /* call is a yieldable protected call */ #define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
#define CIST_TAIL (1<<4) /* call was tail called */ #define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<5) /* last hook called yielded */ #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
#define CIST_LEQ (1<<6) /* using __lt for __le */ #define CIST_LEQ (1<<7) /* using __lt for __le */
#define CIST_FIN (1<<7) /* call is running a finalizer */ #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 */ /* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */
#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) #define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v))
@ -162,7 +188,7 @@ struct lua_State {
lu_byte status; lu_byte status;
StkId top; /* first free slot in the stack */ StkId top; /* first free slot in the stack */
global_State *l_G; global_State *l_G;
StkId func; /* current function */ CallInfo *ci; /* call info for current function */
const Instruction *oldpc; /* last pc traced */ const Instruction *oldpc; /* last pc traced */
StkId stack_last; /* last free slot in the stack */ StkId stack_last; /* last free slot in the stack */
StkId stack; /* stack base */ StkId stack; /* stack base */
@ -170,6 +196,7 @@ struct lua_State {
GCObject *gclist; GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */ struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */ struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
volatile lua_Hook hook; volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */ ptrdiff_t errfunc; /* current error handling function (stack index) */
int stacksize; int stacksize;
@ -225,6 +252,9 @@ union GCUnion {
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); 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 #endif

View File

@ -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 ** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -46,7 +46,7 @@ void *l_Trick = 0;
int islocked = 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); 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) { static int lua_checkpc (CallInfo *ci) {
if (!isLua(func)) return 1; if (!isLua(ci)) return 1;
else { else {
Proto *p = clLvalue(s2v(func))->p; StkId f = ci->func;
return p->code <= func->stkci.u.l.savedpc && Proto *p = clLvalue(s2v(f))->p;
func->stkci.u.l.savedpc <= p->code + p->sizecode; return p->code <= ci->u.l.savedpc &&
ci->u.l.savedpc <= p->code + p->sizecode;
} }
} }
static void checkstack (global_State *g, lua_State *L1) { static void checkstack (global_State *g, lua_State *L1) {
StkId o; StkId o;
CallInfo *ci;
UpVal *uv; UpVal *uv;
lua_assert(!isdead(g, L1)); lua_assert(!isdead(g, L1));
for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next) for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next)
lua_assert(upisopen(uv)); /* must be open */ lua_assert(upisopen(uv)); /* must be open */
for (o = L1->func; o->stkci.previous != 0; o -= o->stkci.previous) { for (ci = L1->ci; ci != NULL; ci = ci->previous) {
lua_assert(functop(o) <= L1->stack_last); lua_assert(ci->top <= L1->stack_last);
lua_assert(lua_checkpc(o)); lua_assert(lua_checkpc(ci));
} }
lua_assert(o == L1->stack);
if (L1->stack) { /* complete thread? */ if (L1->stack) { /* complete thread? */
for (o = L1->stack; o < L1->stack_last + EXTRA_STACK; o++) for (o = L1->stack; o < L1->stack_last + EXTRA_STACK; o++)
checkliveness(L1, s2v(o)); /* entire stack must have valid values */ checkliveness(L1, s2v(o)); /* entire stack must have valid values */

6
ltm.c
View File

@ -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 ** Tag methods
** See Copyright Notice in lua.h ** 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 */ setobj2s(L, func + 3, p3); /* 3rd argument */
L->top += 4; L->top += 4;
/* metamethod may yield only when called from Lua code */ /* metamethod may yield only when called from Lua code */
if (isLua(L->func)) if (isLua(L->ci))
luaD_call(L, func, 0); luaD_call(L, func, 0);
else else
luaD_callnoyield(L, func, 0); 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 */ setobj2s(L, func + 2, p2); /* 2nd argument */
L->top += 3; L->top += 3;
/* metamethod may yield only when called from Lua code */ /* metamethod may yield only when called from Lua code */
if (isLua(L->func)) if (isLua(L->ci))
luaD_call(L, func, 1); luaD_call(L, func, 1);
else else
luaD_callnoyield(L, func, 1); luaD_callnoyield(L, func, 1);

5
lua.h
View File

@ -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 - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file ** See Copyright Notice at the end of this file
@ -456,8 +456,7 @@ struct lua_Debug {
char istailcall; /* (t) */ char istailcall; /* (t) */
char short_src[LUA_IDSIZE]; /* (S) */ char short_src[LUA_IDSIZE]; /* (S) */
/* private part */ /* private part */
int i_actf; /* active function */ struct CallInfo *i_ci; /* active function */
lua_State *i_actL; /* where active function is active */
}; };
/* }====================================================================== */ /* }====================================================================== */

133
lvm.c
View File

@ -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 ** Lua virtual machine
** See Copyright Notice in lua.h ** 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' */ else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */
return res; return res;
else { /* try 'lt': */ 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); 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) if (res < 0)
luaG_ordererror(L, l, r); luaG_ordererror(L, l, r);
return !res; /* result is negated */ 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 ** finish execution of an opcode interrupted by an yield
*/ */
void luaV_finishOp (lua_State *L) { void luaV_finishOp (lua_State *L) {
StkId base = L->func + 1; CallInfo *ci = L->ci;
Instruction inst = *(basepc(base) - 1); /* interrupted instruction */ StkId base = ci->func + 1;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst); OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */ switch (op) { /* finish its execution */
case OP_ADDI: case OP_SUBI: 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: { case OP_LE: case OP_LT: case OP_EQ: {
int res = !l_isfalse(s2v(L->top - 1)); int res = !l_isfalse(s2v(L->top - 1));
L->top--; L->top--;
if (callstatus(base - 1) & CIST_LEQ) { /* "<=" using "<" ? */ if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
lua_assert(op == OP_LE); lua_assert(op == OP_LE);
callstatus(base - 1) ^= CIST_LEQ; /* clear mark */ ci->callstatus ^= CIST_LEQ; /* clear mark */
res = !res; /* negate result */ 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? */ if (res != GETARG_A(inst)) /* condition failed? */
basepc(base)++; /* skip jump instruction */ ci->u.l.savedpc++; /* skip jump instruction */
break; break;
} }
case OP_CONCAT: { case OP_CONCAT: {
@ -700,18 +699,18 @@ void luaV_finishOp (lua_State *L) {
luaV_concat(L, total); /* concat them (may yield again) */ luaV_concat(L, total); /* concat them (may yield again) */
} }
/* move final result to final position */ /* move final result to final position */
setobjs2s(L, L->func + 1 + GETARG_A(inst), L->top - 1); setobjs2s(L, ci->func + 1 + GETARG_A(inst), L->top - 1);
L->top = functop(base - 1); /* restore top */ L->top = ci->top; /* restore top */
break; break;
} }
case OP_TFORCALL: { case OP_TFORCALL: {
lua_assert(GET_OPCODE(*basepc(base)) == OP_TFORLOOP); lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP);
L->top = functop(base - 1); /* correct top */ L->top = ci->top; /* correct top */
break; break;
} }
case OP_CALL: { case OP_CALL: {
if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */
L->top = functop(base - 1); /* adjust results */ L->top = ci->top; /* adjust results */
break; break;
} }
case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: 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 ** Execute a jump instruction. The 'updatemask' allows signals to stop
** tight loops. (Without it, the local copy of 'mask' could never change.) ** 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 */ /* 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 ** Whenever code can raise errors (including memory errors), the global
** 'pc' must be correct to report occasional errors. ** '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 ** Protect code that, in general, can raise errors, reallocate the
** stack, and change the hooks. ** 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) \ #define checkGC(L,c) \
{ luaC_condGC(L, L->top = (c), /* limit of live values */ \ { luaC_condGC(L, L->top = (c), /* limit of live values */ \
{updatestate(); L->top = functop(base - 1);}); /* restore top */ \ Protect(L->top = ci->top)); /* restore top */ \
luai_threadyield(L); } luai_threadyield(L); }
/* fetch an instruction and prepare its execution */ /* fetch an instruction and prepare its execution */
@ -796,23 +793,26 @@ void luaV_finishOp (lua_State *L) {
void luaV_execute (lua_State *L) { void luaV_execute (lua_State *L) {
CallInfo *ci = L->ci;
LClosure *cl; LClosure *cl;
TValue *k; 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)' */ int mask; /* local copy of 'L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)' */
const Instruction *pc; /* local copy of 'basepc(base)' */ const Instruction *pc; /* local copy of 'ci->u.l.savedpc' */
callstatus(base - 1) |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */
newframe: /* reentry point when frame changes (call/return) */ 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 */ k = cl->p->k; /* local reference to function's constant table */
updatemask(L); updatemask(L);
pc = basepc(base); base = ci->func + 1;
pc = ci->u.l.savedpc;
/* main loop of interpreter */ /* main loop of interpreter */
for (;;) { for (;;) {
Instruction i; Instruction i;
StkId ra; StkId ra;
vmfetch(); vmfetch();
lua_assert(base == L->func + 1); lua_assert(base == ci->func + 1);
lua_assert(base <= L->top && L->top < L->stack + L->stacksize); lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
vmdispatch (GET_OPCODE(i)) { vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) { vmcase(OP_MOVE) {
@ -970,7 +970,7 @@ void luaV_execute (lua_State *L) {
int b = GETARG_B(i); int b = GETARG_B(i);
int c = GETARG_C(i); int c = GETARG_C(i);
Table *t; Table *t;
savepc(base); /* in case of allocation errors */ savepc(L); /* in case of allocation errors */
t = luaH_new(L); t = luaH_new(L);
sethvalue2s(L, ra, t); sethvalue2s(L, ra, t);
if (b != 0 || c != 0) if (b != 0 || c != 0)
@ -1276,7 +1276,7 @@ void luaV_execute (lua_State *L) {
rb = base + b; rb = base + b;
setobjs2s(L, ra, rb); setobjs2s(L, ra, rb);
checkGC(L, (ra >= rb ? ra + 1 : rb)); checkGC(L, (ra >= rb ? ra + 1 : rb));
L->top = functop(base - 1); /* restore top */ L->top = ci->top; /* restore top */
vmbreak; vmbreak;
} }
vmcase(OP_CLOSE) { vmcase(OP_CLOSE) {
@ -1284,7 +1284,7 @@ void luaV_execute (lua_State *L) {
vmbreak; vmbreak;
} }
vmcase(OP_JMP) { vmcase(OP_JMP) {
dojump(i, 0); dojump(ci, i, 0);
vmbreak; vmbreak;
} }
vmcase(OP_EQ) { vmcase(OP_EQ) {
@ -1294,7 +1294,7 @@ void luaV_execute (lua_State *L) {
if (luaV_equalobj(L, rb, rc) != GETARG_A(i)) if (luaV_equalobj(L, rb, rc) != GETARG_A(i))
pc++; pc++;
else else
donextjump(); donextjump(ci);
) )
vmbreak; vmbreak;
} }
@ -1310,7 +1310,7 @@ void luaV_execute (lua_State *L) {
if (res != GETARG_A(i)) if (res != GETARG_A(i))
pc++; pc++;
else else
donextjump(); donextjump(ci);
vmbreak; vmbreak;
} }
vmcase(OP_LE) { vmcase(OP_LE) {
@ -1325,14 +1325,14 @@ void luaV_execute (lua_State *L) {
if (res != GETARG_A(i)) if (res != GETARG_A(i))
pc++; pc++;
else else
donextjump(); donextjump(ci);
vmbreak; vmbreak;
} }
vmcase(OP_TEST) { vmcase(OP_TEST) {
if (GETARG_C(i) ? l_isfalse(s2v(ra)) : !l_isfalse(s2v(ra))) if (GETARG_C(i) ? l_isfalse(s2v(ra)) : !l_isfalse(s2v(ra)))
pc++; pc++;
else else
donextjump(); donextjump(ci);
vmbreak; vmbreak;
} }
vmcase(OP_TESTSET) { vmcase(OP_TESTSET) {
@ -1341,7 +1341,7 @@ void luaV_execute (lua_State *L) {
pc++; pc++;
else { else {
setobj2s(L, ra, rb); setobj2s(L, ra, rb);
donextjump(); donextjump(ci);
} }
vmbreak; vmbreak;
} }
@ -1355,11 +1355,11 @@ void luaV_execute (lua_State *L) {
Protect(isC = luaD_precall(L, ra, nresults)); Protect(isC = luaD_precall(L, ra, nresults));
if (isC) { /* C function? */ if (isC) { /* C function? */
if (nresults >= 0) /* fixed number of results? */ 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 leave top for next instruction */
} }
else { /* Lua function */ else { /* Lua function */
base = L->func + 1; ci = L->ci;
goto newframe; /* restart luaV_execute over new Lua function */ goto newframe; /* restart luaV_execute over new Lua function */
} }
vmbreak; vmbreak;
@ -1368,14 +1368,16 @@ void luaV_execute (lua_State *L) {
int b = GETARG_B(i); int b = GETARG_B(i);
if (b != 0) L->top = ra+b; /* else previous instruction set top */ if (b != 0) L->top = ra+b; /* else previous instruction set top */
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
savepc(base); savepc(L);
if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */
updatestate(); /* update 'base' */ Protect((void)0); /* update 'base' */
} }
else { else {
/* tail call: put called frame (n) in place of caller one (o) */ /* tail call: put called frame (n) in place of caller one (o) */
StkId nfunc = L->func; /* called function */ CallInfo *nci = L->ci; /* called frame (new) */
StkId ofunc = nfunc - nfunc->stkci.previous; /* caller function */ 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' */ /* last stack slot filled by 'precall' */
StkId lim = nfunc + 1 + getproto(s2v(nfunc))->numparams; StkId lim = nfunc + 1 + getproto(s2v(nfunc))->numparams;
int aux; int aux;
@ -1384,13 +1386,11 @@ void luaV_execute (lua_State *L) {
/* move new frame into old one */ /* move new frame into old one */
for (aux = 0; nfunc + aux < lim; aux++) for (aux = 0; nfunc + aux < lim; aux++)
setobjs2s(L, ofunc + aux, nfunc + aux); setobjs2s(L, ofunc + aux, nfunc + aux);
ofunc->stkci.framesize = L->top - nfunc; oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */
L->top = functop(ofunc); /* correct top */ oci->u.l.savedpc = nci->u.l.savedpc;
ofunc->stkci.u.l.savedpc = nfunc->stkci.u.l.savedpc; oci->callstatus |= CIST_TAIL; /* function was tail called */
callstatus(ofunc) |= CIST_TAIL; /* function was tail called */ ci = L->ci = oci; /* remove new frame */
base = ofunc + 1; lua_assert(L->top == ofunc + 1 + getproto(s2v(ofunc))->maxstacksize);
L->func = ofunc;
lua_assert(L->top == base + getproto(s2v(ofunc))->maxstacksize);
goto newframe; /* restart luaV_execute over new Lua function */ goto newframe; /* restart luaV_execute over new Lua function */
} }
vmbreak; vmbreak;
@ -1398,16 +1398,16 @@ void luaV_execute (lua_State *L) {
vmcase(OP_RETURN) { vmcase(OP_RETURN) {
int b = GETARG_B(i); int b = GETARG_B(i);
if (cl->p->sizep > 0) luaF_close(L, base); if (cl->p->sizep > 0) luaF_close(L, base);
savepc(base); savepc(L);
b = luaD_poscall(L, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
if (callstatus(base - 1) & CIST_FRESH) /* local 'base' still from callee */ if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */
return; /* external invocation: return */ return; /* external invocation: return */
else { /* invocation via reentry: continue execution */ else { /* invocation via reentry: continue execution */
base = L->func + 1; ci = L->ci;
if (b) L->top = functop(base - 1); if (b) L->top = ci->top;
lua_assert(isLua(base - 1)); lua_assert(isLua(ci));
lua_assert(GET_OPCODE(*(basepc(base) - 1)) == OP_CALL); lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL);
goto newframe; /* restart luaV_execute over previous Lua function */ goto newframe; /* restart luaV_execute over new Lua function */
} }
} }
vmcase(OP_FORLOOP) { vmcase(OP_FORLOOP) {
@ -1451,7 +1451,7 @@ void luaV_execute (lua_State *L) {
} }
else { /* try making all values floats */ else { /* try making all values floats */
lua_Number ninit; lua_Number nlimit; lua_Number nstep; 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)) if (!tonumber(plimit, &nlimit))
luaG_runerror(L, "'for' limit must be a number"); luaG_runerror(L, "'for' limit must be a number");
setfltvalue(plimit, nlimit); setfltvalue(plimit, nlimit);
@ -1472,7 +1472,7 @@ void luaV_execute (lua_State *L) {
setobjs2s(L, cb, ra); setobjs2s(L, cb, ra);
L->top = cb + 3; /* func. + 2 args (state and index) */ L->top = cb + 3; /* func. + 2 args (state and index) */
Protect(luaD_call(L, cb, GETARG_C(i))); Protect(luaD_call(L, cb, GETARG_C(i)));
L->top = functop(base - 1); L->top = ci->top;
i = *(pc++); /* go to next instruction */ i = *(pc++); /* go to next instruction */
ra = RA(i); ra = RA(i);
lua_assert(GET_OPCODE(i) == OP_TFORLOOP); lua_assert(GET_OPCODE(i) == OP_TFORLOOP);
@ -1497,7 +1497,7 @@ void luaV_execute (lua_State *L) {
} }
h = hvalue(s2v(ra)); h = hvalue(s2v(ra));
last = ((c-1)*LFIELDS_PER_FLUSH) + n; 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? */ if (last > h->sizearray) /* needs more space? */
luaH_resizearray(L, h, last); /* preallocate it at once */ luaH_resizearray(L, h, last); /* preallocate it at once */
for (; n > 0; n--) { for (; n > 0; n--) {
@ -1506,15 +1506,14 @@ void luaV_execute (lua_State *L) {
last--; last--;
luaC_barrierback(L, h, val); luaC_barrierback(L, h, val);
} }
/* correct top (in case of previous open call) */ L->top = ci->top; /* correct top (in case of previous open call) */
L->top = functop(base - 1);
vmbreak; vmbreak;
} }
vmcase(OP_CLOSURE) { vmcase(OP_CLOSURE) {
Proto *p = cl->p->p[GETARG_Bx(i)]; Proto *p = cl->p->p[GETARG_Bx(i)];
LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */
if (ncl == NULL) { /* no match? */ 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 */ pushclosure(L, p, cl->upvals, base, ra); /* create a new one */
} }
else else