instrumenting function calls with their depth

This commit is contained in:
Kartik K. Agaram 2021-11-13 08:16:41 -08:00
parent 0f4faf0e53
commit 5a44605143
4 changed files with 66 additions and 2 deletions

View File

@ -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

View File

@ -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) */

View File

@ -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);

View File

@ -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*/ "");