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 | |
parent | 0f4faf0e5333542040a809e3b97d05426b69d40d (diff) | |
download | teliva-5a44605143362c8d240c20c849593a3739bf9bed.tar.gz |
instrumenting function calls with their depth
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/ldebug.c | 2 | ||||
-rw-r--r-- | src/ldo.c | 54 | ||||
-rw-r--r-- | src/lua.c | 10 |
4 files changed, 66 insertions, 2 deletions
diff --git a/src/Makefile b/src/Makefile index c88fb28..39d2c3a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -8,7 +8,7 @@ PLAT= none CC= gcc -CFLAGS= -O2 -Wall $(MYCFLAGS) +CFLAGS= -g -O2 -Wall $(MYCFLAGS) AR= ar rc RANLIB= ranlib RM= rm -f diff --git a/src/ldebug.c b/src/ldebug.c index 50ad3d3..de643b0 100644 --- a/src/ldebug.c +++ b/src/ldebug.c @@ -314,7 +314,7 @@ static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { } -static Instruction symbexec (const Proto *pt, int lastpc, int reg) { +Instruction symbexec (const Proto *pt, int lastpc, int reg) { int pc; int last; /* stores position of last instruction that changed `reg' */ last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ 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); diff --git a/src/lua.c b/src/lua.c index 08c5f92..59c50ca 100644 --- a/src/lua.c +++ b/src/lua.c @@ -370,6 +370,16 @@ void switch_to_editor (lua_State *L, const char *message) { if (Script_name) edit(L, Script_name, message); else { + luaL_newmetatable(L, "__teliva_call_graph_depth"); + int cgt = lua_gettop(L); + printf("cgt: %d\n", cgt); + for (lua_pushnil(L); lua_next(L, cgt) != 0;) { + const char* function_name = lua_tostring(L, -2); + int depth = lua_tointeger(L, -1); + printf("%s: %d\n", function_name, depth); + lua_pop(L, 1); // pop value, leave key on stack for next iteration + } + exit(4); Current_definition = "main"; write_definition_to_file(L, Current_definition, "teliva_editbuffer"); edit(L, "teliva_editbuffer", /*status message*/ ""); |