diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2021-11-13 08:16:41 -0800 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2021-11-13 08:16:41 -0800 |
commit | 5a44605143362c8d240c20c849593a3739bf9bed (patch) | |
tree | a2a866314c30ce299ed90a3ed31ebe526ea286d8 /src/ldo.c | |
parent | 0f4faf0e5333542040a809e3b97d05426b69d40d (diff) | |
download | teliva-5a44605143362c8d240c20c849593a3739bf9bed.tar.gz |
instrumenting function calls with their depth
Diffstat (limited to 'src/ldo.c')
-rw-r--r-- | src/ldo.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/src/ldo.c b/src/ldo.c index ffcb031..ea186d3 100644 --- a/src/ldo.c +++ b/src/ldo.c @@ -6,6 +6,7 @@ #include <setjmp.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -256,6 +257,58 @@ static StkId tryfuncTM (lua_State *L, StkId func) { } +/* based on getfuncname */ +extern Instruction symbexec (const Proto *pt, int lastpc, int reg); +extern int luaL_newmetatable (lua_State *L, const char *tname); +extern void endwin (void); +void record_depth_of_global_function (lua_State *L, CallInfo *ci) { + if (!isLua(ci)) + return; + if (ci->tailcalls > 0) + return; + if (!isLua(ci - 1)) + return; + ci--; /* calling function */ + if (ci == L->ci) + ci->savedpc = L->savedpc; + int pc = cast(int, ci->savedpc - ci_func(ci)->l.p->code) - 1; + lua_assert(pc != -1); // TODO: lua_assert not triggering + Instruction i = ci_func(ci)->l.p->code[pc]; +//? endwin(); +//? printf("AAA: %p %d %d %d\n", L->savedpc, pc, i, GET_OPCODE(i)); +//? abort(); + if (GET_OPCODE(i) != OP_CALL && GET_OPCODE(i) != OP_TAILCALL && + GET_OPCODE(i) != OP_TFORLOOP) + return; + Proto *p = ci_func(ci)->l.p; + i = symbexec(p, pc, GETARG_A(i)); /* previous instruction that writes to call's RA */ + if (GET_OPCODE(i) != OP_GETGLOBAL) + return; + int g = GETARG_Bx(i); /* global index */ + lua_assert(ttisstring(&p->k[g])); + const char *name = svalue(&p->k[g]); + int depth = ci - L->base_ci; + /* Maintain a global table mapping from function name to call-stack depth + * at first call to it. + * + * Won't be perfect; might get confused by shadowing locals. But we can't + * be perfect without a bidirectional mapping between interpreter state + * and source code. Which would make Lua either a lot less dynamic or a + * a lot more like Smalltalk. */ + // push table + luaL_newmetatable(L, "__teliva_call_graph_depth"); + int cgt = lua_gettop(L); + // if key doesn't already exist, set it + lua_getfield(L, cgt, name); + if (lua_isnil(L, -1)) { + lua_pushinteger(L, depth); + lua_setfield(L, cgt, name); + } + // clean up + lua_pop(L, 1); // key + lua_pop(L, 1); // table +} + #define inc_ci(L) \ ((L->ci == L->end_ci) ? growCI(L) : \ @@ -297,6 +350,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { for (st = L->top; st < ci->top; st++) setnilvalue(st); L->top = ci->top; + record_depth_of_global_function(L, ci); if (L->hookmask & LUA_MASKCALL) { L->savedpc++; /* hooks assume 'pc' is already incremented */ luaD_callhook(L, LUA_HOOKCALL, -1); |