instrumenting function calls with their depth
This commit is contained in:
parent
0f4faf0e53
commit
5a44605143
|
@ -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
|
||||
|
|
|
@ -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) */
|
||||
|
|
54
src/ldo.c
54
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);
|
||||
|
|
10
src/lua.c
10
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*/ "");
|
||||
|
|
Loading…
Reference in New Issue