diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 816b2e5b..2f413b8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,6 +77,13 @@ jobs: make sudo make install + - name: Install Pallene Tracer + run: | + git clone https://github.com/pallene-lang/pallene-tracer + cd pallene-tracer + sudo make install + luarocks --local make + - name: Build run: luarocks --local make @@ -87,3 +94,4 @@ jobs: run: | eval "$(luarocks path)" busted -o gtest -v ./spec + diff --git a/pallene-dev-1.rockspec b/pallene-dev-1.rockspec index cbcd2475..5cacff15 100644 --- a/pallene-dev-1.rockspec +++ b/pallene-dev-1.rockspec @@ -15,6 +15,12 @@ dependencies = { "lua == 5.4", "lpeg >= 1.0", "argparse >= 0.7.0", + "pallene-tracer >= 0.5.0a" +} +external_dependencies = { + PTRACER = { + header = "ptracer.h", + } } build = { type = "builtin", diff --git a/run-tests b/run-tests index e804cbe1..dd3bfcfe 100755 --- a/run-tests +++ b/run-tests @@ -19,7 +19,7 @@ FLAGS=(--verbose --no-keep-going) # To speed things up, we tell the C compiler to skip optimizations. (It's OK, the CI still uses -O2) # Also, add some compiler flags to verify standard compliance. -export CFLAGS='-O0 -std=c99 -Wall -Werror -Wundef -Wpedantic -Wno-unused' +export CFLAGS='-O0 -std=c99 -Wall -Werror -Wundef -Wno-unused' if [ "$#" -eq 0 ]; then if command -v parallel >/dev/null; then diff --git a/src/pallene/c_compiler.lua b/src/pallene/c_compiler.lua index ca204b66..6fad4c7d 100644 --- a/src/pallene/c_compiler.lua +++ b/src/pallene/c_compiler.lua @@ -18,6 +18,7 @@ local c_compiler = {} local CC = os.getenv("CC") or "cc" local CFLAGS = os.getenv("CFLAGS") or "-O2" +local PTLIBDIR = os.getenv("PTLIBDIR") or "/usr/local/lib" local function get_uname() local ok, err, uname = util.outputs_of_execute("uname -s") @@ -61,6 +62,8 @@ function c_compiler.compile_o_to_so(in_filename, out_filename) CFLAGS_SHARED, "-o", util.shell_quote(out_filename), util.shell_quote(in_filename), + "-lptracer", + "-Wl,-rpath="..PTLIBDIR, }) end diff --git a/src/pallene/coder.lua b/src/pallene/coder.lua index ede52bda..10bd6324 100644 --- a/src/pallene/coder.lua +++ b/src/pallene/coder.lua @@ -214,10 +214,7 @@ end -- these cases instead of invoking the metatable operations, which may impair program optimization -- even if they are never called. local function check_no_metatable(self, src, loc) - local setline = "" - if self.flags.use_traceback then - setline = string.format("PALLENE_SETLINE(%d);", loc.line) - end + local setline = string.format("PALLENE_SETLINE(%d);", loc.line) return (util.render([[ if ($src->metatable) { @@ -254,10 +251,7 @@ function Coder:get_stack_slot(typ, dst, slot, loc, description_fmt, ...) assert(not typ.is_upvalue_box) local extra_args = table.pack(...) - local setline = "" - if self.flags.use_traceback then - setline = string.format("PALLENE_SETLINE(%d);", loc.line) - end + local setline = string.format("PALLENE_SETLINE(%d);", loc.line) check_tag = util.render([[ if (l_unlikely(!$test)) { @@ -461,18 +455,12 @@ function Coder:pallene_entry_point_definition(f_id) local max_frame_size = self.gc[func].max_frame_size local slots_needed = max_frame_size + self.max_lua_call_stack_usage[func] - local setline = "" - local frameexit = "" - if self.flags.use_traceback then - table.insert(prologue, util.render([[ - PALLENE_C_FRAMEENTER(L, "$name"); - ]], { - name = func.name - })); - - setline = string.format("PALLENE_SETLINE(%d);", func.loc and func.loc.line or 0) - frameexit = "PALLENE_FRAMEEXIT();" - end + table.insert(prologue, util.render([[ + PALLENE_C_FRAMEENTER("$name"); + ]], { + name = func.name + })); + local setline = string.format("PALLENE_SETLINE(%d);", func.loc and func.loc.line or 0) if slots_needed > 0 then table.insert(prologue, util.render([[ @@ -527,7 +515,7 @@ function Coder:pallene_entry_point_definition(f_id) ${prologue} /**/ ${body} - ${frameexit} + PALLENE_FRAMEEXIT(); ${ret_mult} ${ret_stat} } @@ -537,7 +525,6 @@ function Coder:pallene_entry_point_definition(f_id) prologue = table.concat(prologue, "\n"), body = body, ret_mult = ret_mult, - frameexit = frameexit, ret_stat = ret_stat, })) end @@ -615,22 +602,18 @@ function Coder:lua_entry_point_definition(f_id) Udata *K = uvalue(&func->upvalue[0]); ]] - local frameenter = "" - local frameexit = "" local nargs = #arg_types + -- We will be having our call-stack finalizer object on top of our stack when debugging mode is + -- enabled local cargs = nargs if self.flags.use_traceback then - frameenter = util.render([[ - PALLENE_LUA_FRAMEENTER(L, $fun_name); - ]], { - fun_name = self:lua_entry_point_name(f_id), - }) - -- It's as simple as popping the finalizer. - frameexit = "lua_pop(L, 1);" - - -- We will be having our finalizer on top of our stack. cargs = cargs + 1 end + local frameenter = util.render([[ + PALLENE_LUA_FRAMEENTER($fun_name); + ]], { + fun_name = self:lua_entry_point_name(f_id), + }) local arity_check = util.render([[ int nargs = lua_gettop(L); @@ -694,7 +677,6 @@ function Coder:lua_entry_point_definition(f_id) /**/ ${ret_decls} ${call_pallene} - ${lua_fexit} ${push_results} return $nresults; } @@ -708,7 +690,6 @@ function Coder:lua_entry_point_definition(f_id) ret_decls = table.concat(ret_decls, "\n"), call_pallene = call_pallene, push_results = table.concat(push_results, "\n"), - lua_fexit = frameexit, nresults = C.integer(#ret_types) })) end @@ -728,11 +709,9 @@ define_union("Constant", { function Coder:init_upvalues() - -- If we are using tracebacks - if self.flags.use_traceback then - table.insert(self.constants, coder.Constant.DebugUserdata) - table.insert(self.constants, coder.Constant.DebugMetatable) - end + -- Debug traceback constants + table.insert(self.constants, coder.Constant.DebugUserdata) + table.insert(self.constants, coder.Constant.DebugMetatable) -- Metatables for _, typ in ipairs(self.module.record_types) do @@ -1490,11 +1469,8 @@ gen_cmd["CallStatic"] = function(self, args) end table.insert(parts, self:update_stack_top(args.position)) - - if self.flags.use_traceback then - table.insert(parts, string.format("PALLENE_SETLINE(%d);\n", - args.func.loc and args.func.loc.line or 0)) - end + table.insert(parts, string.format("PALLENE_SETLINE(%d);\n", + args.func.loc and args.func.loc.line or 0)) table.insert(parts, self:call_pallene_function(dsts, f_id, cclosure, xs, nil)) table.insert(parts, self:restorestack()) @@ -1531,12 +1507,9 @@ gen_cmd["CallDyn"] = function(self, args) })) end - local setline = "" - if self.flags.use_traceback then - setline = util.render([[ PALLENE_SETLINE($line); ]], { - line = C.integer(args.func.loc and args.func.loc.line or 0) - }) - end + local setline = util.render([[ PALLENE_SETLINE($line); ]], { + line = C.integer(args.func.loc and args.func.loc.line or 0) + }) return util.render([[ ${update_stack_top} @@ -1808,6 +1781,10 @@ function Coder:generate_module_header() table.insert(out, "/* This file was generated by the Pallene compiler. Do not edit by hand */") table.insert(out, "") table.insert(out, string.format("#define PALLENE_SOURCE_FILE %s", C.string(self.filename))) + if self.flags.use_traceback then + table.insert(out, "/* Enable Pallene Tracer debugging. */") + table.insert(out, "#define PT_DEBUG") + end table.insert(out, "") table.insert(out, "/* ------------------------ */") diff --git a/src/pallene/pallenec.lua b/src/pallene/pallenec.lua index 77c41562..be6cbbc8 100644 --- a/src/pallene/pallenec.lua +++ b/src/pallene/pallenec.lua @@ -34,7 +34,7 @@ do ) -- No Pallene tracebacks - p:flag("--use-traceback", "Use function traceback for debugging") + p:flag("--use-traceback", "Enable call-stack tracing") p:option("-O", "Optimization level") :args(1):convert(tonumber) diff --git a/src/pallene/pallenelib.lua b/src/pallene/pallenelib.lua index 7f69ada0..6cb03050 100644 --- a/src/pallene/pallenelib.lua +++ b/src/pallene/pallenelib.lua @@ -46,100 +46,52 @@ return [==[ #include #include +/* Pallene Tracer for function call tracebacks. */ +/* Look at `https://github.com/pallene-lang/pallene-tracer` for more info. */ +#include + #define PALLENE_UNREACHABLE __builtin_unreachable() -/* PALLENE TRACER MACROS */ +/* PALLENE TRACER HELPER MACROS */ +#ifdef PT_DEBUG /* Prepares finalizer function for Lua interface calls. */ #define PALLENE_PREPARE_FINALIZER() \ - setobj(L, s2v(L->top.p++), &K->uv[1].uv); \ - lua_toclose(L, -1) - -#define PALLENE_C_FRAMEENTER(L, name) \ - pt_cont_t *cont = pvalue(&K->uv[0].uv); \ - static pt_fn_details_t _details = { \ - .fn_name = name, \ - .mod_name = PALLENE_SOURCE_FILE \ - }; \ - pt_frame_t _frame = { \ - .type = PALLENE_TRACER_FRAME_TYPE_C, \ - .shared = { \ - .details = &_details \ - } \ - }; \ - pallene_tracer_frameenter(L, cont, &_frame) - -#define PALLENE_LUA_FRAMEENTER(L, sig) \ - pt_cont_t *cont = pvalue(&K->uv[0].uv); \ - pt_frame_t _frame = { \ - .type = PALLENE_TRACER_FRAME_TYPE_LUA, \ - .shared = { \ - .frame_sig = sig \ - } \ - }; \ - pallene_tracer_frameenter(L, cont, &_frame); \ - PALLENE_PREPARE_FINALIZER() - -#define PALLENE_SETLINE(line) pallene_tracer_setline(cont, line) -#define PALLENE_FRAMEEXIT() pallene_tracer_frameexit(cont) - -/* Pallene stack reference entry for the registry. */ -#define PALLENE_TRACER_CONTAINER_ENTRY "__PALLENE_TRACER_CONTAINER" - -/* Finalizer metatable key. */ -#define PALLENE_TRACER_METATABLE_ENTRY "__PALLENE_TRACER_METATABLE" - -/* The size of the Pallene call stack. */ -#define PALLENE_MAX_CALLSTACK 2000000 - -/* Traceback elipsis threshold. */ -#define PALLENE_TRACEBACK_TOP_THRESHOLD 10 -/* This should always be 2 fewer than top threshold, for symmetry. - Becuase we will always have 2 tail frames lingering around at - at the end which is not captured by '_countlevels'. */ -#define PALLENE_TRACEBACK_BOTTOM_THRESHOLD 8 - -/* PALLENE TRACER RELATED DATA-STRUCTURES. */ - -/* Whether the frame is a Pallene->Pallene or Lua->Pallene call. */ -typedef enum frame_type { - PALLENE_TRACER_FRAME_TYPE_C, - PALLENE_TRACER_FRAME_TYPE_LUA -} frame_type_t; - -/* Details of a single function such as what is the name - and where it is from. */ -typedef struct pt_fn_details { - const char *const fn_name; - const char *const mod_name; -} pt_fn_details_t; - -/* A single frame representation. */ -typedef struct pt_frame { - frame_type_t type; - int line; - - union { - pt_fn_details_t *details; - lua_CFunction frame_sig; - } shared; -} pt_frame_t; - -/* For Full Userdata allocation. That userdata is the module singular - point for Pallene stack. */ -/* 'cont' stands for 'container'. */ -typedef struct pt_cont { - pt_frame_t *stack; - int count; -} pt_cont_t; - -/* Pallene Tracer. */ -static void pallene_tracer_frameenter(lua_State *L, pt_cont_t *cont, pt_frame_t *restrict frame); -static void pallene_tracer_setline(pt_cont_t *cont, int line); -static void pallene_tracer_frameexit(pt_cont_t *cont); -static int pallene_tracer_debug_traceback(lua_State *L); -static pt_cont_t *pallene_tracer_init(lua_State *L); -static int pallene_tracer_finalizer(lua_State *L); + setobj(L, s2v(L->top.p++), &K->uv[1].uv); \ + lua_toclose(L, -1) + +#define PALLENE_GET_FNSTACK() \ + pt_fnstack_t *fnstack = pvalue(&K->uv[0].uv) + +#define PALLENE_PREPARE_C_FRAME(name) \ + PALLENE_GET_FNSTACK(); \ + static pt_fn_details_t _details = \ + PALLENE_TRACER_FN_DETAILS(name, PALLENE_SOURCE_FILE); \ + pt_frame_t _frame = \ + PALLENE_TRACER_C_FRAME(_details) + +#define PALLENE_PREPARE_LUA_FRAME(fnptr) \ + PALLENE_GET_FNSTACK(); \ + pt_frame_t _frame = \ + PALLENE_TRACER_LUA_FRAME(fnptr) + +#else +#define PALLENE_PREPARE_FINALIZER() +#define PALLENE_PREPARE_C_FRAME(name) +#define PALLENE_PREPARE_LUA_FRAME(fnptr) +#endif // PT_DEBUG + +#define PALLENE_C_FRAMEENTER(name) \ + PALLENE_PREPARE_C_FRAME(name); \ + PALLENE_TRACER_FRAMEENTER(fnstack, &_frame); + +#define PALLENE_LUA_FRAMEENTER(fnptr) \ + PALLENE_PREPARE_LUA_FRAME(fnptr); \ + PALLENE_TRACER_FRAMEENTER(fnstack, &_frame); \ + PALLENE_PREPARE_FINALIZER() + +#define PALLENE_SETLINE(line) PALLENE_TRACER_SETLINE(fnstack, line) +#define PALLENE_FRAMEEXIT() PALLENE_TRACER_FRAMEEXIT(fnstack) /* Type tags */ static const char *pallene_type_name(lua_State *L, const TValue *v); @@ -160,7 +112,6 @@ static l_noret pallene_runtime_mod_by_zero_error(lua_State *L, const char* file, static l_noret pallene_runtime_number_to_integer_error(lua_State *L, const char* file, int line); static l_noret pallene_runtime_array_metatable_error(lua_State *L, const char* file, int line); static l_noret pallene_runtime_cant_grow_stack_error(lua_State *L); -static l_noret pallene_runtime_callstack_overflow_error(lua_State *L); /* Arithmetic operators */ static lua_Integer pallene_int_divi(lua_State *L, lua_Integer m, lua_Integer n, const char* file, int line); @@ -192,317 +143,6 @@ static TString *pallene_type_builtin(lua_State *L, TValue v); static TString *pallene_tostring(lua_State *L, const char* file, int line, TValue v); static void pallene_io_write(lua_State *L, TString *str); -/* PALLENE TRACER IMPLEMENTATION */ - -/* Private routines. */ - -static bool _findfield(lua_State *L, int fn_idx, int level) { - if(level == 0 || !lua_istable(L, -1)) - return false; - - lua_pushnil(L); /* Initial key. */ - - while(lua_next(L, -2)) { - /* We are only interested in String keys. */ - if(lua_type(L, -2) == LUA_TSTRING) { - /* Avoid "_G" recursion in global table. The global table is also part of - global table. */ - if(!strcmp(lua_tostring(L, -2), "_G")) { - /* Remove value and continue. */ - lua_pop(L, 1); - continue; - } - - /* Is it the function we are looking for? */ - if(lua_rawequal(L, fn_idx, -1)) { - /* Remove value and keep name. */ - lua_pop(L, 1); - - return true; - } - /* If not go one level deeper and get the value recursively. */ - else if(_findfield(L, fn_idx, level - 1)) { - /* Remove the table but keep name. */ - lua_remove(L, -2); - - /* Add a "." in between. */ - lua_pushliteral(L, "."); - lua_insert(L, -2); - - /* Concatenate last 3 values, resulting "table.some_func". */ - lua_concat(L, 3); - - return true; - } - } - - /* Pop the value. */ - lua_pop(L, 1); - } - - return false; -} - -/* Pushes a function name if found in the global table and returns true. - Returns false otherwise. */ -/* Expects the function to be pushed in the stack. */ -static bool _pgf_name(lua_State *L) { - int top = lua_gettop(L); - - lua_pushglobaltable(L); - - if(_findfield(L, top, 2)) { - lua_remove(L, -2); - - return true; - } - - lua_pop(L, 1); - return false; -} - -/* Returns the maximum number of levels in Lua stack. */ -static int _countlevels (lua_State *L) { - lua_Debug ar; - int li = 1, le = 1; - - /* Find an upper bound */ - while (lua_getstack(L, le, &ar)) { - li = le, le *= 2; - } - - /* Do a binary search */ - while (li < le) { - int m = (li + le)/2; - - if (lua_getstack(L, m, &ar)) li = m + 1; - else le = m; - } - - return le - 1; -} - -/* Counts the number of white and black frames in the Pallene call stack. */ -static void _countframes(pt_cont_t *cont, int *mwhite, int *mblack) { - *mwhite = *mblack = 0; - - for(int i = 0; i < cont->count; i++) { - *mwhite += (cont->stack[i].type == PALLENE_TRACER_FRAME_TYPE_C); - *mblack += (cont->stack[i].type == PALLENE_TRACER_FRAME_TYPE_LUA); - } -} - -/* Responsible for printing and controlling some of the traceback fn parameters. */ -static void _dbg_print(const char *buf, bool *elipsis, int *pframes, int nframes) { - /* We have printed the frame, even tho it might not be visible ;). */ - (*pframes)++; - - /* Should we print? Are we in the point in top or bottom printing threshold? */ - bool should_print = (*pframes <= PALLENE_TRACEBACK_TOP_THRESHOLD) - || ((nframes - *pframes) <= PALLENE_TRACEBACK_BOTTOM_THRESHOLD); - - if(should_print) - fprintf(stderr, buf); - else if(*elipsis) { - fprintf(stderr, "\n ... (Skipped %d frames) ...\n\n", - nframes - (PALLENE_TRACEBACK_TOP_THRESHOLD - + PALLENE_TRACEBACK_BOTTOM_THRESHOLD)); - - *elipsis = false; - } -} - -/* Frees the heap-allocated resources. */ -static int _free_resources(lua_State *L) { - pt_cont_t *cont = (pt_cont_t *) lua_touserdata(L, 1); - - free(cont->stack); - - return 0; -} - -/* Private routines end. */ - -static void pallene_tracer_frameenter(lua_State *L, pt_cont_t *cont, pt_frame_t *restrict frame) { - /* If we ran out of Pallene frames. */ - if(l_unlikely(cont->count + 1 >= PALLENE_MAX_CALLSTACK)) { - pallene_runtime_callstack_overflow_error(L); - } - - cont->stack[cont->count++] = *frame; -} - -static void pallene_tracer_setline(pt_cont_t *cont, int line) { - if(cont->count != 0) - cont->stack[cont->count - 1].line = line; -} - -static void pallene_tracer_frameexit(pt_cont_t *cont) { - cont->count -= (cont->count > 0); -} - -/* Helper macro specific to this function only :). */ -#define DBG_PRINT() _dbg_print(buf, &elipsis, &pframes, nframes) -static int pallene_tracer_debug_traceback(lua_State *L) { - lua_getfield(L, LUA_REGISTRYINDEX, PALLENE_TRACER_CONTAINER_ENTRY); - pt_cont_t *cont = (pt_cont_t *) lua_touserdata(L, -1); - pt_frame_t *stack = cont->stack; - /* The point where we are in the Pallene stack. */ - int index = cont->count - 1; - lua_pop(L, 1); - - /* Max number of white and black frames. */ - int mwhite, mblack; - _countframes(cont, &mwhite, &mblack); - /* Max levels of Lua stack. */ - int mlevel = _countlevels(L); - - /* Total frames we are going to print. */ - /* Black frames are used for switching and we will start from - Lua stack level 1. */ - int nframes = mlevel + mwhite - mblack - 1; - /* Amount of frames printed. */ - int pframes = 0; - /* Should we print elipsis? */ - bool elipsis = nframes > (PALLENE_TRACEBACK_TOP_THRESHOLD - + PALLENE_TRACEBACK_BOTTOM_THRESHOLD); - - /* Buffer to store a single frame line to be printed. */ - char buf[1024]; - - const char *message = lua_tostring(L, 1); - fprintf(stderr, "Runtime error: %s\nStack traceback:\n", message); - - lua_Debug ar; - int top = lua_gettop(L); - int level = 1; - - while(lua_getstack(L, level++, &ar)) { - /* Get additional information regarding the frame. */ - lua_getinfo(L, "Slntf", &ar); - - /* If the frame is a C frame. */ - if(lua_iscfunction(L, -1)) { - if(index >= 0) { - /* Check whether this frame is tracked (Pallene C frames). */ - int check = index; - while(stack[check].type != PALLENE_TRACER_FRAME_TYPE_LUA) - check--; - - /* If the frame signature matches, we switch to printing Pallene frames. */ - if(lua_tocfunction(L, -1) == stack[check].shared.frame_sig) { - /* Now print all the frames in Pallene stack. */ - for(; index > check; index--) { - sprintf(buf, " %s:%d: in function '%s'\n", - stack[index].shared.details->mod_name, - stack[index].line, stack[index].shared.details->fn_name); - DBG_PRINT(); - } - - /* 'check' idx is guaranteed to be a Lua interface frame. - Which is basically our 'stack' index at this point. So, - we simply ignore the Lua interface frame. */ - index--; - - /* We are done. */ - lua_settop(L, top); - continue; - } - } - - /* Then it's an untracked C frame. */ - if(_pgf_name(L)) - lua_pushfstring(L, "%s", lua_tostring(L, -1)); - else lua_pushliteral(L, ""); - - sprintf(buf, " C: in function '%s'\n", lua_tostring(L, -1)); - DBG_PRINT(); - } else { - /* It's a Lua frame. */ - - /* Do we have a name? */ - if(*ar.namewhat != '\0') - lua_pushfstring(L, "function '%s'", ar.name); - /* Is it the main chunk? */ - else if(*ar.what == 'm') - lua_pushliteral(L, "
"); - /* Can we deduce the name from the global table? */ - else if(_pgf_name(L)) - lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); - else lua_pushliteral(L, "function ''"); - - sprintf(buf, " %s:%d: in %s\n", ar.short_src, - ar.currentline, lua_tostring(L, -1)); - DBG_PRINT(); - } - - lua_settop(L, top); - } - - return 0; -} -#undef DBG_PRINT - -/* This function is expected to push the finalizer metatable in the stack. */ -static pt_cont_t *pallene_tracer_init(lua_State *L) { - pt_cont_t *cont = NULL; - - /* Try getting the userdata. */ - lua_getfield(L, LUA_REGISTRYINDEX, PALLENE_TRACER_CONTAINER_ENTRY); - - /* If we don't find any userdata, create one. */ - if(l_unlikely(lua_isnil(L, -1) == 1)) { - cont = (pt_cont_t *) lua_newuserdata(L, sizeof(pt_cont_t)); - cont->stack = malloc(PALLENE_MAX_CALLSTACK * sizeof(pt_frame_t)); - cont->count = 0; - - lua_newtable(L); - lua_pushcfunction(L, _free_resources); - lua_setfield(L, -2, "__gc"); - lua_setmetatable(L, -2); - - /* This is our finalizer which will reside in the value stack. */ - lua_newtable(L); - lua_newtable(L); - lua_pushvalue(L, -3); - - /* Our finalizer fn. */ - lua_pushcclosure(L, pallene_tracer_finalizer, 1); - lua_setfield(L, -2, "__close"); - lua_setmetatable(L, -2); - - /* Metatable registry. */ - lua_setfield(L, LUA_REGISTRYINDEX, PALLENE_TRACER_METATABLE_ENTRY); - - /* Stack container registry .*/ - lua_setfield(L, LUA_REGISTRYINDEX, PALLENE_TRACER_CONTAINER_ENTRY); - - /* The debug traceback fn. */ - lua_register(L, "pallene_tracer_debug_traceback", pallene_tracer_debug_traceback); - - /* Push the metatable in the stack. */ - lua_getfield(L, LUA_REGISTRYINDEX, PALLENE_TRACER_METATABLE_ENTRY); - } else { - cont = lua_touserdata(L, -1); - lua_getfield(L, LUA_REGISTRYINDEX, PALLENE_TRACER_METATABLE_ENTRY); - } - - return cont; -} - -static int pallene_tracer_finalizer(lua_State *L) { - /* Get the userdata. */ - pt_cont_t *cont = (pt_cont_t *) lua_touserdata(L, lua_upvalueindex(1)); - - int idx = cont->count - 1; - while(cont->stack[idx].type != PALLENE_TRACER_FRAME_TYPE_LUA) - idx--; - - cont->count = idx; - - return 0; -} - static const char *pallene_type_name(lua_State *L, const TValue *v) { if (rawtt(v) == LUA_VNUMINT) { @@ -621,11 +261,6 @@ static l_noret pallene_runtime_cant_grow_stack_error(lua_State *L) PALLENE_UNREACHABLE; } -static l_noret pallene_runtime_callstack_overflow_error(lua_State *L) { - luaL_error(L, "pallene callstack overflow"); - PALLENE_UNREACHABLE; -} - /* Lua and Pallene round integer division towards negative infinity, while C rounds towards zero. * Here we inline luaV_div, to allow the C compiler to constant-propagate. For an explanation of the * algorithm, see the comments for luaV_div. */