From 422318f6777d8d3bac13ade797d9c8eaa38686b6 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Sat, 17 Feb 2018 17:29:29 -0200 Subject: [PATCH] two new fields 'fTransfer'/'nTransfer' in 'lua_Debug' structure (for information about values being given and returned in function calls) --- ldblib.c | 8 ++++++-- ldebug.c | 14 +++++++++++--- ldo.c | 31 ++++++++++++++++++++++--------- ldo.h | 5 +++-- lstate.h | 9 +++++++-- lua.h | 4 +++- 6 files changed, 52 insertions(+), 19 deletions(-) diff --git a/ldblib.c b/ldblib.c index 0bcd2e9e..c1e26e0d 100644 --- a/ldblib.c +++ b/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.150 2015/11/19 19:16:22 roberto Exp roberto $ +** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp roberto $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -146,7 +146,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, "flnStu"); + const char *options = luaL_optstring(L, arg+2, "flnSrtu"); checkstack(L, L1, 3); if (lua_isfunction(L, arg + 1)) { /* info about a function? */ options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ @@ -180,6 +180,10 @@ static int db_getinfo (lua_State *L) { settabss(L, "name", ar.name); settabss(L, "namewhat", ar.namewhat); } + if (strchr(options, 'r')) { + settabsi(L, "fTransfer", ar.fTransfer); + settabsi(L, "nTransfer", ar.nTransfer); + } if (strchr(options, 't')) settabsb(L, "istailcall", ar.istailcall); if (strchr(options, 'L')) diff --git a/ldebug.c b/ldebug.c index 3ddac547..bede7e37 100644 --- a/ldebug.c +++ b/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.153 2018/02/06 19:16:56 roberto Exp roberto $ +** $Id: ldebug.c,v 2.154 2018/02/09 15:16:06 roberto Exp roberto $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -356,6 +356,14 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, } break; } + case 'r': { + if (ci == NULL || !(ci->callstatus & CIST_TRAN)) + ar->fTransfer = ar->nTransfer = 0; + else { + ar->fTransfer = ci->u2.transferinfo.fTransfer; + ar->nTransfer = ci->u2.transferinfo.nTransfer; + } + } case 'L': case 'f': /* handled by lua_getinfo */ break; @@ -790,7 +798,7 @@ void luaG_traceexec (lua_State *L) { if (!isIT(*(ci->u.l.savedpc - 1))) L->top = ci->top; /* prepare top */ if (counthook) - luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ + luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ if (mask & LUA_MASKLINE) { Proto *p = ci_func(ci)->p; const Instruction *npc = ci->u.l.savedpc; @@ -799,7 +807,7 @@ void luaG_traceexec (lua_State *L) { npc <= L->oldpc || /* when jump back (loop), or when */ changedline(p, pcRel(L->oldpc, p), npci)) { /* enter new line */ int newline = luaG_getfuncline(p, npci); /* new line */ - luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ + luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */ } L->oldpc = npc; } diff --git a/ldo.c b/ldo.c index f797df29..6acd2f64 100644 --- a/ldo.c +++ b/ldo.c @@ -267,9 +267,11 @@ void luaD_inctop (lua_State *L) { ** called. (Both 'L->hook' and 'L->hookmask', which triggers this ** function, can be changed asynchronously by signals.) */ -void luaD_hook (lua_State *L, int event, int line) { +void luaD_hook (lua_State *L, int event, int line, + int fTransfer, int nTransfer) { lua_Hook hook = L->hook; if (hook && L->allowhook) { /* make sure there is a hook */ + int mask = CIST_HOOKED; CallInfo *ci = L->ci; ptrdiff_t top = savestack(L, L->top); ptrdiff_t ci_top = savestack(L, ci->top); @@ -277,11 +279,16 @@ void luaD_hook (lua_State *L, int event, int line) { ar.event = event; ar.currentline = line; ar.i_ci = ci; + if (nTransfer != 0) { + mask |= CIST_TRAN; /* 'ci' has transfer information */ + ci->u2.transferinfo.fTransfer = fTransfer; + ci->u2.transferinfo.nTransfer = nTransfer; + } luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ if (L->top + LUA_MINSTACK > ci->top) ci->top = L->top + LUA_MINSTACK; L->allowhook = 0; /* cannot call hooks inside a hook */ - ci->callstatus |= CIST_HOOKED; + ci->callstatus |= mask; lua_unlock(L); (*hook)(L, &ar); lua_lock(L); @@ -289,7 +296,7 @@ void luaD_hook (lua_State *L, int event, int line) { L->allowhook = 1; ci->top = restorestack(L, ci_top); L->top = restorestack(L, top); - ci->callstatus &= ~CIST_HOOKED; + ci->callstatus &= ~mask; } } @@ -301,16 +308,18 @@ void luaD_hook (lua_State *L, int event, int line) { */ void luaD_hookcall (lua_State *L, CallInfo *ci) { int hook = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL : LUA_HOOKCALL; + Proto *p; if (!(L->hookmask & LUA_MASKCALL)) /* some other hook? */ return; /* don't call hook */ + p = clLvalue(s2v(ci->func))->p; L->top = ci->top; /* prepare top */ ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ - luaD_hook(L, hook, -1); + luaD_hook(L, hook, -1, 1, p->numparams); ci->u.l.savedpc--; /* correct 'pc' */ } -static void rethook (lua_State *L, CallInfo *ci) { +static void rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) { int delta = 0; if (isLuacode(ci)) { Proto *p = clLvalue(s2v(ci->func))->p; @@ -320,8 +329,10 @@ static void rethook (lua_State *L, CallInfo *ci) { L->top = ci->top; /* correct top */ } if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ + int fTransfer; ci->func += delta; /* if vararg, back to virtual 'func' */ - luaD_hook(L, LUA_HOOKRET, -1); /* call it */ + fTransfer = cast(unsigned short, firstres - ci->func); + luaD_hook(L, LUA_HOOKRET, -1, fTransfer, nres); /* call it */ ci->func -= delta; } if (isLua(ci->previous)) @@ -396,7 +407,7 @@ static void moveresults (lua_State *L, StkId firstResult, StkId res, void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { if (L->hookmask) { ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ - rethook(L, ci); + rethook(L, ci, firstResult, nres); firstResult = restorestack(L, fr); } L->ci = ci->previous; /* back to caller */ @@ -458,8 +469,10 @@ void luaD_call (lua_State *L, StkId func, int nresults) { ci->top = L->top + LUA_MINSTACK; ci->func = func; lua_assert(ci->top <= L->stack_last); - if (L->hookmask & LUA_MASKCALL) - luaD_hook(L, LUA_HOOKCALL, -1); + if (L->hookmask & LUA_MASKCALL) { + int narg = cast_int(L->top - func) - 1; + luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); + } lua_unlock(L); n = (*f)(L); /* do the actual call */ lua_lock(L); diff --git a/ldo.h b/ldo.h index 9d976b32..1fdc75be 100644 --- a/ldo.h +++ b/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.41 2018/02/09 15:16:06 roberto Exp roberto $ +** $Id: ldo.h,v 2.42 2018/02/15 15:34:29 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -52,7 +52,8 @@ typedef void (*Pfunc) (lua_State *L, void *ud); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, const char *mode); -LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); +LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, + int fTransfer, int nTransfer); LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); diff --git a/lstate.h b/lstate.h index 65229491..06581b01 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.154 2018/02/09 15:16:06 roberto Exp roberto $ +** $Id: lstate.h,v 2.155 2018/02/15 18:06:24 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -103,9 +103,13 @@ typedef struct CallInfo { union { int funcidx; /* called-function index */ int nyield; /* number of values yielded */ + struct { /* info about transfered values (for call/return hooks) */ + unsigned short fTransfer; /* offset of first value transfered */ + unsigned short nTransfer; /* number of values transfered */ + } transferinfo; } u2; short nresults; /* expected number of results from this function */ - lu_byte callstatus; + unsigned short callstatus; } CallInfo; @@ -120,6 +124,7 @@ typedef struct CallInfo { #define CIST_HOOKYIELD (1<<5) /* last hook called yielded */ #define CIST_LEQ (1<<6) /* using __lt for __le */ #define CIST_FIN (1<<7) /* call is running a finalizer */ +#define CIST_TRAN (1<<8) /* 'ci' has transfer information */ /* active function is a Lua function */ #define isLua(ci) (!((ci)->callstatus & CIST_C)) diff --git a/lua.h b/lua.h index 2d8ff838..d6277b4e 100644 --- a/lua.h +++ b/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.337 2017/11/02 11:28:56 roberto Exp $ +** $Id: lua.h,v 1.339 2017/11/07 13:25:26 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 @@ -452,6 +452,8 @@ struct lua_Debug { int lastlinedefined; /* (S) */ unsigned char nups; /* (u) number of upvalues */ unsigned char nparams;/* (u) number of parameters */ + unsigned char fTransfer;/* (r) index of first value transfered */ + unsigned char nTransfer; /* (r) number of transfered values */ char isvararg; /* (u) */ char istailcall; /* (t) */ char short_src[LUA_IDSIZE]; /* (S) */