new scheme for debug info about tail calls: no more 'fake' stack entries,
but stack entry knows whether it was tail called
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lauxlib.c,v 1.192 2009/09/28 12:36:40 roberto Exp roberto $
|
||||
** $Id: lauxlib.c,v 1.193 2009/10/05 16:44:33 roberto Exp roberto $
|
||||
** Auxiliary functions for building Lua libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -97,7 +97,7 @@ static void pushfuncname (lua_State *L, lua_Debug *ar) {
|
||||
lua_remove(L, -2); /* remove name */
|
||||
}
|
||||
else
|
||||
lua_pushliteral(L, "?"); /* C function or tail call */
|
||||
lua_pushliteral(L, "?");
|
||||
}
|
||||
else
|
||||
lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
|
||||
@@ -133,12 +133,14 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
|
||||
level = numlevels - LEVELS2; /* and skip to last ones */
|
||||
}
|
||||
else {
|
||||
lua_getinfo(L1, "Sln", &ar);
|
||||
lua_getinfo(L1, "Slnt", &ar);
|
||||
lua_pushfstring(L, "\n\t%s:", ar.short_src);
|
||||
if (ar.currentline > 0)
|
||||
lua_pushfstring(L, "%d:", ar.currentline);
|
||||
lua_pushliteral(L, " in ");
|
||||
pushfuncname(L, &ar);
|
||||
if (ar.istailcall)
|
||||
lua_pushliteral(L, "\n\t(...tail calls...)");
|
||||
lua_concat(L, lua_gettop(L) - top);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lbaselib.c,v 1.225 2009/11/19 16:26:29 roberto Exp roberto $
|
||||
** $Id: lbaselib.c,v 1.226 2009/11/24 12:05:44 roberto Exp roberto $
|
||||
** Basic library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -119,8 +119,6 @@ static void getfunc (lua_State *L, int opt) {
|
||||
if (lua_getstack(L, level, &ar) == 0)
|
||||
luaL_argerror(L, 1, "invalid level");
|
||||
lua_getinfo(L, "f", &ar);
|
||||
if (lua_isnil(L, -1))
|
||||
luaL_error(L, "no function environment for tail call at level %d", level);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
ldblib.c
10
ldblib.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ldblib.c,v 1.116 2009/11/18 15:50:18 roberto Exp roberto $
|
||||
** $Id: ldblib.c,v 1.117 2009/11/24 12:05:44 roberto Exp roberto $
|
||||
** Interface from Lua to its debug API
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -100,7 +100,7 @@ static int db_getinfo (lua_State *L) {
|
||||
lua_Debug ar;
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
const char *options = luaL_optstring(L, arg+2, "flnSu");
|
||||
const char *options = luaL_optstring(L, arg+2, "flnStu");
|
||||
if (lua_isnumber(L, arg+1)) {
|
||||
if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
|
||||
lua_pushnil(L); /* level out of range */
|
||||
@@ -133,6 +133,10 @@ static int db_getinfo (lua_State *L) {
|
||||
settabss(L, "name", ar.name);
|
||||
settabss(L, "namewhat", ar.namewhat);
|
||||
}
|
||||
if (strchr(options, 't')) {
|
||||
lua_pushboolean(L, ar.istailcall);
|
||||
lua_setfield(L, -2, "istailcall");
|
||||
}
|
||||
if (strchr(options, 'L'))
|
||||
treatstackoption(L, L1, "activelines");
|
||||
if (strchr(options, 'f'))
|
||||
@@ -232,7 +236,7 @@ static const char KEY_HOOK = 'h';
|
||||
|
||||
static void hookf (lua_State *L, lua_Debug *ar) {
|
||||
static const char *const hooknames[] =
|
||||
{"call", "return", "line", "count", "tail return"};
|
||||
{"call", "return", "line", "count", "tail call"};
|
||||
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_pushlightuserdata(L, L);
|
||||
|
||||
42
ldebug.c
42
ldebug.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ldebug.c,v 2.56 2009/09/28 16:32:50 roberto Exp roberto $
|
||||
** $Id: ldebug.c,v 2.57 2009/10/13 19:07:40 roberto Exp roberto $
|
||||
** Debug Interface
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -83,23 +83,14 @@ LUA_API int lua_gethookcount (lua_State *L) {
|
||||
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
|
||||
int status;
|
||||
CallInfo *ci;
|
||||
if (level < 0) return 0; /* invalid (negative) level */
|
||||
lua_lock(L);
|
||||
for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) {
|
||||
for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)
|
||||
level--;
|
||||
if (isLua(ci)) /* Lua function? */
|
||||
level -= ci->u.l.tailcalls; /* skip lost tail calls */
|
||||
}
|
||||
if (level == 0 && ci != &L->base_ci) { /* level found? */
|
||||
status = 1;
|
||||
ar->i_ci = ci;
|
||||
}
|
||||
else if (level < 0) {
|
||||
if (ci == L->ci) status = 0; /* level was negative? */
|
||||
else { /* level is of a lost tail call */
|
||||
status = 1;
|
||||
ar->i_ci = NULL;
|
||||
}
|
||||
}
|
||||
else status = 0; /* no such level */
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
@@ -110,7 +101,6 @@ static const char *findlocal (lua_State *L, CallInfo *ci, int n,
|
||||
StkId *pos) {
|
||||
const char *name = NULL;
|
||||
StkId base;
|
||||
if (ci == NULL) return NULL; /* tail call? */
|
||||
if (isLua(ci)) {
|
||||
base = ci->u.l.base;
|
||||
name = luaF_getlocalname(ci_func(ci)->l.p, n, currentpc(ci));
|
||||
@@ -170,17 +160,6 @@ static void funcinfo (lua_Debug *ar, Closure *cl) {
|
||||
}
|
||||
|
||||
|
||||
static void info_tailcall (lua_Debug *ar) {
|
||||
ar->name = NULL;
|
||||
ar->namewhat = "";
|
||||
ar->what = "tail";
|
||||
ar->lastlinedefined = ar->linedefined = ar->currentline = -1;
|
||||
ar->source = "=(tail call)";
|
||||
luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
|
||||
ar->nups = 0;
|
||||
}
|
||||
|
||||
|
||||
static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
if (f == NULL || f->c.isC) {
|
||||
setnilvalue(L->top);
|
||||
@@ -201,10 +180,6 @@ static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||
Closure *f, CallInfo *ci) {
|
||||
int status = 1;
|
||||
if (f == NULL) {
|
||||
info_tailcall(ar);
|
||||
return status;
|
||||
}
|
||||
for (; *what; what++) {
|
||||
switch (*what) {
|
||||
case 'S': {
|
||||
@@ -219,6 +194,10 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||
ar->nups = f->c.nupvalues;
|
||||
break;
|
||||
}
|
||||
case 't': {
|
||||
ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL;
|
||||
if (ar->namewhat == NULL) {
|
||||
@@ -249,15 +228,14 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
||||
f = clvalue(func);
|
||||
L->top--; /* pop function */
|
||||
}
|
||||
else if (ar->i_ci != NULL) { /* no tail call? */
|
||||
else {
|
||||
ci = ar->i_ci;
|
||||
lua_assert(ttisfunction(ci->func));
|
||||
f = clvalue(ci->func);
|
||||
}
|
||||
status = auxgetinfo(L, what, ar, f, ci);
|
||||
if (strchr(what, 'f')) {
|
||||
if (f == NULL) setnilvalue(L->top);
|
||||
else setclvalue(L, L->top, f);
|
||||
setclvalue(L, L->top, f);
|
||||
incr_top(L);
|
||||
}
|
||||
if (strchr(what, 'L'))
|
||||
@@ -379,7 +357,7 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
|
||||
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
|
||||
TMS tm = 0;
|
||||
Instruction i;
|
||||
if ((isLua(ci) && ci->u.l.tailcalls > 0) || !isLua(ci->previous))
|
||||
if ((ci->callstatus & CIST_TAIL) || !isLua(ci->previous))
|
||||
return NULL; /* calling function is not Lua (or is unknown) */
|
||||
ci = ci->previous; /* calling function */
|
||||
i = ci_func(ci)->l.p->code[currentpc(ci)];
|
||||
|
||||
52
ldo.c
52
ldo.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ldo.c,v 2.71 2009/11/17 16:33:38 roberto Exp roberto $
|
||||
** $Id: ldo.c,v 2.72 2009/11/17 16:46:44 roberto Exp roberto $
|
||||
** Stack and Call structure of Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -184,7 +184,7 @@ void luaD_shrinkstack (lua_State *L) {
|
||||
}
|
||||
|
||||
|
||||
void luaD_callhook (lua_State *L, int event, int line) {
|
||||
void luaD_hook (lua_State *L, int event, int line) {
|
||||
lua_Hook hook = L->hook;
|
||||
if (hook && L->allowhook) {
|
||||
CallInfo *ci = L->ci;
|
||||
@@ -193,9 +193,6 @@ void luaD_callhook (lua_State *L, int event, int line) {
|
||||
lua_Debug ar;
|
||||
ar.event = event;
|
||||
ar.currentline = line;
|
||||
if (event == LUA_HOOKTAILRET)
|
||||
ar.i_ci = NULL; /* tail call; no debug information about it */
|
||||
else
|
||||
ar.i_ci = ci;
|
||||
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
|
||||
ci->top = L->top + LUA_MINSTACK;
|
||||
@@ -214,6 +211,19 @@ void luaD_callhook (lua_State *L, int event, int line) {
|
||||
}
|
||||
|
||||
|
||||
static void callhook (lua_State *L, CallInfo *ci) {
|
||||
int hook = LUA_HOOKCALL;
|
||||
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);
|
||||
ci->u.l.savedpc--; /* correct 'pc' */
|
||||
}
|
||||
|
||||
|
||||
static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
|
||||
int i;
|
||||
int nfixargs = p->numparams;
|
||||
@@ -281,14 +291,10 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
|
||||
ci->top = base + p->maxstacksize;
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
ci->u.l.savedpc = p->code; /* starting point */
|
||||
ci->u.l.tailcalls = 0;
|
||||
ci->callstatus = CIST_LUA;
|
||||
L->top = ci->top;
|
||||
if (L->hookmask & LUA_MASKCALL) {
|
||||
ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */
|
||||
luaD_callhook(L, LUA_HOOKCALL, -1);
|
||||
ci->u.l.savedpc--; /* correct 'pc' */
|
||||
}
|
||||
if (L->hookmask & LUA_MASKCALL)
|
||||
callhook(L, ci);
|
||||
return 0;
|
||||
}
|
||||
else { /* if is a C function, call it */
|
||||
@@ -301,7 +307,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
ci->callstatus = 0;
|
||||
if (L->hookmask & LUA_MASKCALL)
|
||||
luaD_callhook(L, LUA_HOOKCALL, -1);
|
||||
luaD_hook(L, LUA_HOOKCALL, -1);
|
||||
lua_unlock(L);
|
||||
n = (*curr_func(L)->c.f)(L); /* do the actual call */
|
||||
lua_lock(L);
|
||||
@@ -311,25 +317,17 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
|
||||
}
|
||||
|
||||
|
||||
static StkId callrethooks (lua_State *L, StkId firstResult) {
|
||||
ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */
|
||||
luaD_callhook(L, LUA_HOOKRET, -1);
|
||||
if (isLua(L->ci)) { /* Lua function? */
|
||||
while ((L->hookmask & LUA_MASKRET) && L->ci->u.l.tailcalls--)
|
||||
luaD_callhook(L, LUA_HOOKTAILRET, -1); /* ret. hooks for tail calls */
|
||||
}
|
||||
return restorestack(L, fr);
|
||||
}
|
||||
|
||||
|
||||
int luaD_poscall (lua_State *L, StkId firstResult) {
|
||||
StkId res;
|
||||
int wanted, i;
|
||||
CallInfo *ci = L->ci;
|
||||
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
|
||||
if (L->hookmask & LUA_MASKRET)
|
||||
firstResult = callrethooks(L, firstResult);
|
||||
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for returning function */
|
||||
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);
|
||||
}
|
||||
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
|
||||
}
|
||||
res = ci->func; /* res == final position of 1st result */
|
||||
L->ci = ci = ci->previous; /* back to caller */
|
||||
@@ -529,7 +527,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
|
||||
}
|
||||
lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */
|
||||
lua_unlock(L);
|
||||
return 0; /* otherwise, return to 'luaD_callhook' */
|
||||
return 0; /* return to 'luaD_hook' */
|
||||
}
|
||||
|
||||
|
||||
|
||||
4
ldo.h
4
ldo.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: ldo.h,v 2.15 2009/07/15 17:26:14 roberto Exp roberto $
|
||||
** $Id: ldo.h,v 2.16 2009/11/19 16:24:41 roberto Exp roberto $
|
||||
** Stack and Call structure of Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -27,7 +27,7 @@
|
||||
typedef void (*Pfunc) (lua_State *L, void *ud);
|
||||
|
||||
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name);
|
||||
LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line);
|
||||
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line);
|
||||
LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
|
||||
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults,
|
||||
int allowyield);
|
||||
|
||||
4
lstate.h
4
lstate.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lstate.h,v 2.47 2009/10/23 19:12:19 roberto Exp roberto $
|
||||
** $Id: lstate.h,v 2.48 2009/11/18 13:13:47 roberto Exp roberto $
|
||||
** Global State
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -80,7 +80,6 @@ typedef struct CallInfo {
|
||||
struct { /* only for Lua functions */
|
||||
StkId base; /* base for this function */
|
||||
const Instruction *savedpc;
|
||||
int tailcalls; /* number of tail calls lost under this entry */
|
||||
} l;
|
||||
struct { /* only for C functions */
|
||||
int ctx; /* context info. in case of yields */
|
||||
@@ -104,6 +103,7 @@ typedef struct CallInfo {
|
||||
#define CIST_YIELDED (1<<3) /* call reentered after suspension */
|
||||
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
|
||||
#define CIST_STAT (1<<5) /* call has an error status (pcall) */
|
||||
#define CIST_TAIL (1<<6) /* call was tail called */
|
||||
|
||||
|
||||
#define curr_func(L) (clvalue(L->ci->func))
|
||||
|
||||
5
lua.h
5
lua.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lua.h,v 1.249 2009/11/09 18:55:17 roberto Exp roberto $
|
||||
** $Id: lua.h,v 1.250 2009/11/09 19:10:48 roberto Exp roberto $
|
||||
** Lua - A Scripting Language
|
||||
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
|
||||
** See Copyright Notice at the end of this file
|
||||
@@ -356,7 +356,7 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
|
||||
#define LUA_HOOKRET 1
|
||||
#define LUA_HOOKLINE 2
|
||||
#define LUA_HOOKCOUNT 3
|
||||
#define LUA_HOOKTAILRET 4
|
||||
#define LUA_HOOKTAILCALL 4
|
||||
|
||||
|
||||
/*
|
||||
@@ -401,6 +401,7 @@ struct lua_Debug {
|
||||
int nups; /* (u) number of upvalues */
|
||||
int linedefined; /* (S) */
|
||||
int lastlinedefined; /* (S) */
|
||||
char istailcall; /* (t) */
|
||||
char short_src[LUA_IDSIZE]; /* (S) */
|
||||
/* private part */
|
||||
struct CallInfo *i_ci; /* active function */
|
||||
|
||||
8
lvm.c
8
lvm.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lvm.c,v 2.99 2009/09/30 15:38:37 roberto Exp roberto $
|
||||
** $Id: lvm.c,v 2.100 2009/10/28 12:20:07 roberto Exp roberto $
|
||||
** Lua virtual machine
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@@ -62,7 +62,7 @@ static void traceexec (lua_State *L) {
|
||||
lu_byte mask = L->hookmask;
|
||||
if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) {
|
||||
resethookcount(L);
|
||||
luaD_callhook(L, LUA_HOOKCOUNT, -1);
|
||||
luaD_hook(L, LUA_HOOKCOUNT, -1);
|
||||
}
|
||||
if (mask & LUA_MASKLINE) {
|
||||
Proto *p = ci_func(ci)->l.p;
|
||||
@@ -71,7 +71,7 @@ static void traceexec (lua_State *L) {
|
||||
if (npc == 0 || /* call linehook when enter a new function, */
|
||||
ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */
|
||||
newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */
|
||||
luaD_callhook(L, LUA_HOOKLINE, newline);
|
||||
luaD_hook(L, LUA_HOOKLINE, newline);
|
||||
}
|
||||
L->oldpc = ci->u.l.savedpc;
|
||||
}
|
||||
@@ -679,7 +679,7 @@ void luaV_execute (lua_State *L) {
|
||||
oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct base */
|
||||
oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */
|
||||
oci->u.l.savedpc = nci->u.l.savedpc;
|
||||
oci->u.l.tailcalls++; /* one more call lost */
|
||||
oci->callstatus |= CIST_TAIL; /* function was tail called */
|
||||
ci = L->ci = oci; /* remove new frame */
|
||||
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);
|
||||
break; /* restart luaV_execute over new Lua function */
|
||||
|
||||
Reference in New Issue
Block a user