diff --git a/polymer/eduke32/source/astub.c b/polymer/eduke32/source/astub.c index a92b2da24..714bd4131 100644 --- a/polymer/eduke32/source/astub.c +++ b/polymer/eduke32/source/astub.c @@ -8473,12 +8473,19 @@ static void G_ShowParameterHelp(void) extern char forcegl; #endif +#ifdef LUNATIC +const char **g_argv; +#endif + static void G_CheckCommandLine(int32_t argc, const char **argv) { int32_t i = 1, j, maxlen=0, *lengths; const char *c, *k; mapster32_fullpath = argv[0]; +#ifdef LUNATIC + g_argv = argv; +#endif #ifdef HAVE_CLIPSHAPE_FEATURE // pre-form the default 10 clipmaps diff --git a/polymer/eduke32/source/game.c b/polymer/eduke32/source/game.c index b4c25b977..799a31ff2 100644 --- a/polymer/eduke32/source/game.c +++ b/polymer/eduke32/source/game.c @@ -9065,6 +9065,11 @@ static void G_ShowDebugHelp(void) "-q#\t\tFake multiplayer with # (2-8) players\n" "-z#/-condebug\tEnable line-by-line CON compile debugging at level #\n" "-conversion YYYYMMDD\tSelects CON script version for compatibility with older mods\n" +#ifdef LUNATIC + "-Lopts=,,...\n" + " Pass options to Lunatic, valid ones are:\n" + " diag, nojit, traces, dump, strict\n" +#endif ; #if defined RENDERTYPEWIN Bsnprintf(tempbuf, sizeof(tempbuf), HEAD2 " %s", s_buildRev); @@ -9983,9 +9988,13 @@ static void G_CheckCommandLine(int32_t argc, const char **argv) G_AddPath(c); break; case 'l': - ud.warp_on = 1; - c++; - ud.m_level_number = ud.level_number = ((unsigned)(Batoi(c)-1))%MAXLEVELS; + // NOTE: Overlaid with -Lopts=... options for Lunatic, hence the check. + if (Bisdigit(c[1])) + { + ud.warp_on = 1; + c++; + ud.m_level_number = ud.level_number = ((unsigned)(Batoi(c)-1))%MAXLEVELS; + } break; case 'm': if (*(c+1) != 'a' && *(c+1) != 'A') diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index 7d076edfe..18bd75db3 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -602,7 +602,6 @@ const char *g_sizes_of_what[]; int32_t g_sizes_of[]; int32_t g_elCallDepth; int32_t block_deletesprite; -const char **g_argv; const char **g_elModules; char g_modDir[]; actor_t actor[MAXSPRITES]; diff --git a/polymer/eduke32/source/lunatic/defs_common.lua b/polymer/eduke32/source/lunatic/defs_common.lua index e6605055d..6fbc34227 100644 --- a/polymer/eduke32/source/lunatic/defs_common.lua +++ b/polymer/eduke32/source/lunatic/defs_common.lua @@ -11,21 +11,56 @@ local ffi = require("ffi") local ffiC = ffi.C local bit = require("bit") --- Lunatic debugging (mostly bitfield): --- ~=0: print diagnostic information --- 2: disable JIT compilation --- 4: load LuaJIT's 'v' module, printing trace info --- 8: load LuaJIT's 'dump' module, printing generated IR/machine code -ffi.cdef "enum { _DEBUG_LUNATIC=0 }" +local bor = bit.bor -if (bit.band(ffiC._DEBUG_LUNATIC, 2)~=0) then +ffi.cdef "const char **g_argv;" + +-- Lunatic debugging options (-Lopts=,,... from the command line): +-- diag: print diagnostic information +-- nojit: disable JIT compilation +-- traces: load LuaJIT's 'v' module, printing trace info +-- (env var: LUAJIT_VERBOSEFILE) +-- dump: load LuaJIT's 'dump' module, printing generated IR/machine code +-- (env var: LUAJIT_DUMPFILE) +-- strict: catch various conditions that may indicate an logical error +local debug_flags = {} +local IS_DEBUG_FLAG = { + diag=true, nojit=true, traces=true, dump=true, + strict=true, +} + +-- Handle command-line argument. (Look for -Lopts=...) +local function handle_cmdline_arg(str) + local opts = str:match("^-Lopts=(.*)") + + if (opts ~= nil) then + for opt in opts:gmatch("[^,]+") do + if (IS_DEBUG_FLAG[opt]) then + debug_flags[opt] = true + end + end + end +end + +local i=0 +while (ffiC.g_argv[i] ~= nil) do + handle_cmdline_arg(ffi.string(ffiC.g_argv[i])) + i = i+1 +end + +-- Print diagnostic information? +ffi.cdef("enum { _DEBUG_LUNATIC="..(debug_flags.diag and 1 or 0).." }") +-- Be strict? +ffi.cdef("enum { _LUNATIC_STRICT="..(debug_flags.strict and 1 or 0).." }") + +if (debug_flags.nojit) then require("jit").off() end if (not _LUNATIC_AUX) then - if (bit.band(ffiC._DEBUG_LUNATIC, 8)~=0) then + if (debug_flags.dump) then require("dump").on("+rs") - elseif (bit.band(ffiC._DEBUG_LUNATIC, 4)~=0) then + elseif (debug_flags.traces) then require("v").on() end end @@ -964,11 +999,35 @@ function static_members.sprite.updatesect(spritenum, flags) return newsect end +local strictp = debug_flags.strict + function GenStructMetatable(Structname, Boundname, StaticMembersTab) StaticMembersTab = StaticMembersTab or static_members[Structname] - return { - __index = function(tab, key) + -- If we're running with the 'strict' option, disallow accesses to void + -- sprites. + local index_func = (strictp and Structname=="sprite") and + + -- Mostly CODEDUP of lower function, ... + function(tab, key) + if (type(key)=="number") then + if (key >= 0 and key < ffiC[Boundname]) then + -- ... except this. + -- (Inlining into the other function did slow things down.) + if (ffiC.sprite[key].statnum == ffiC.MAXSTATUS) then + error("attempt to access void sprite with index "..key, 2) + end + return ffiC[Structname][key] + end + error("out-of-bounds "..Structname.."[] read access with index "..key, 2) + elseif (type(key)=="string") then + return StaticMembersTab[key] + end + end + + or + + function(tab, key) if (type(key)=="number") then if (key >= 0 and key < ffiC[Boundname]) then return ffiC[Structname][key] @@ -977,8 +1036,10 @@ function GenStructMetatable(Structname, Boundname, StaticMembersTab) elseif (type(key)=="string") then return StaticMembersTab[key] end - end, + end + return { + __index = index_func, __newindex = function() error("cannot write directly to "..Structname.."[]", 2) end, } end diff --git a/polymer/eduke32/source/lunatic/test.lua b/polymer/eduke32/source/lunatic/test.lua index 36ae83852..edace2eb8 100644 --- a/polymer/eduke32/source/lunatic/test.lua +++ b/polymer/eduke32/source/lunatic/test.lua @@ -353,28 +353,30 @@ gameevent proj.drop = 0 proj:set_trail(D.SMALLSMOKE) - t = gv.gethiticks() - local N=1 - for n=1,N do - for i=0,gv.MAXSPRITES-1 do - sprite[i].filler = 1 - end - for i=gv.MAXSPRITES-1,0,-1 do - sprite[i].shade = 1 - end - for i=0,gv.MAXSPRITES-1 do - sprite[i].xoffset = 0 - end - for i=gv.MAXSPRITES-1,0,-1 do - sprite[i].yoffset = 1 + if (gv._LUNATIC_STRICT == 0) then + t = gv.gethiticks() + local N=1 + for n=1,N do + for i=0,gv.MAXSPRITES-1 do + sprite[i].filler = 1 + end + for i=gv.MAXSPRITES-1,0,-1 do + sprite[i].shade = 1 + end + for i=0,gv.MAXSPRITES-1 do + sprite[i].xoffset = 0 + end + for i=gv.MAXSPRITES-1,0,-1 do + sprite[i].yoffset = 1 + end end + t = gv.gethiticks()-t + printf("%d x four 0..MAXSPRITES-1 iterations took %.03f us per outer iteration", N, (1000*t)/N) + -- Results on x86: + -- N=1: 480-1000 us (too large variance) + -- N=10: 190-210 us * 10 = 1.9-2.1 ms + -- N=100: about 160 us * 100 = about 16 ms end - t = gv.gethiticks()-t - printf("%d x four 0..MAXSPRITES-1 iterations took %.03f us per outer iteration", N, (1000*t)/N) - -- Results on x86: - -- N=1: 480-1000 us (too large variance) - -- N=10: 190-210 us * 10 = 1.9-2.1 ms - -- N=100: about 160 us * 100 = about 16 ms -- Make the DUKECAR in E1L1 into a zombie actor (temporarily) -- NOTE: Use static value (not the one from 'D').