diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 2d5ee44e47198c28135fb314e9cc03c60ee72fc3..02c4279794f64f377fc91e3d02227f639738c33a 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -52,17 +52,24 @@ static inline int in_bit_array (const UINT8 *array, const int n) { return array[n >> 3] & (1 << (n & 7)); } +typedef struct { + int numHooks; + int *ids; +} hook_t; + typedef struct { int numGeneric; int ref; } stringhook_t; -static int hookRefs[Hook(MAX)]; -static int mobjHookRefs[NUMMOBJTYPES][Mobj_Hook(MAX)]; +static hook_t hookIds[Hook(MAX)]; +static hook_t mobjHookIds[NUMMOBJTYPES][Mobj_Hook(MAX)]; +// Lua tables are used to lookup string hook ids. static stringhook_t stringHooks[String_Hook(MAX)]; -static int hookReg; +// This will be indexed by hook id, the value of which fetches the registry. +static int * hookRefs; // After a hook errors once, don't print the error again. static UINT8 * hooksErrored; @@ -71,8 +78,8 @@ static boolean mobj_hook_available(int hook_type, mobjtype_t mobj_type) { return ( - mobjHookRefs [MT_NULL] [hook_type] > 0 || - mobjHookRefs[mobj_type][hook_type] > 0 + mobjHookIds [MT_NULL] [hook_type].numHooks > 0 || + mobjHookIds[mobj_type][hook_type].numHooks > 0 ); } @@ -109,32 +116,10 @@ static void get_table(lua_State *L) lua_remove(L, -2); } -static void new_hook_table(lua_State *L, int *ref) +static void add_hook_to_table(lua_State *L, int id, int n) { - if (*ref > 0) - lua_getref(L, *ref); - else - { - lua_newtable(L); - lua_pushvalue(L, -1); - *ref = luaL_ref(L, LUA_REGISTRYINDEX); - } -} - -static void add_hook(lua_State *L, int id) -{ - lua_pushnumber(L, 1 + id); - lua_rawseti(L, -2, 1 + lua_objlen(L, -2)); -} - -static void add_mobj_hook(lua_State *L, int hook_type, int id) -{ - mobjtype_t mobj_type = luaL_optnumber(L, 3, MT_NULL); - - luaL_argcheck(L, mobj_type < NUMMOBJTYPES, 3, "invalid mobjtype_t"); - - new_hook_table(L, &mobjHookRefs[mobj_type][hook_type]); - add_hook(L, id); + lua_pushnumber(L, id); + lua_rawseti(L, -2, n); } static void add_string_hook(lua_State *L, int type, int id) @@ -160,19 +145,39 @@ static void add_string_hook(lua_State *L, int type, int id) break; } - new_hook_table(L, &hook->ref); + if (hook->ref > 0) + lua_getref(L, hook->ref); + else + { + lua_newtable(L); + lua_pushvalue(L, -1); + hook->ref = luaL_ref(L, LUA_REGISTRYINDEX); + } if (string) { lua_pushstring(L, string); get_table(L); - add_hook(L, id); + add_hook_to_table(L, id, 1 + lua_objlen(L, -1)); } else - { - lua_pushnumber(L, 1 + id); - lua_rawseti(L, -2, ++hook->numGeneric); - } + add_hook_to_table(L, id, ++hook->numGeneric); +} + +static void add_hook(hook_t *map, int id) +{ + Z_Realloc(map->ids, (map->numHooks + 1) * sizeof *map->ids, + PU_STATIC, &map->ids); + map->ids[map->numHooks++] = id; +} + +static void add_mobj_hook(lua_State *L, int hook_type, int id) +{ + mobjtype_t mobj_type = luaL_optnumber(L, 3, MT_NULL); + + luaL_argcheck(L, mobj_type < NUMMOBJTYPES, 3, "invalid mobjtype_t"); + + add_hook(&mobjHookIds[mobj_type][hook_type], id); } // Takes hook, function, and additional arguments (mobj type to act on, etc.) @@ -200,8 +205,7 @@ static int lib_addHook(lua_State *L) } else if (( type = hook_in_list(name, hookNames) ) < Hook(MAX)) { - new_hook_table(L, &hookRefs[type]); - add_hook(L, nextid); + add_hook(&hookIds[type], nextid); } else { @@ -216,17 +220,17 @@ static int lib_addHook(lua_State *L) hooksErrored[nextid >> 3] = 0; } + Z_Realloc(hookRefs, (nextid + 1) * sizeof *hookRefs, PU_STATIC, &hookRefs); + // set the hook function in the registry. - lua_getref(L, hookReg); lua_pushvalue(L, 2);/* the function */ - lua_rawseti(L, -2, ++nextid); + hookRefs[nextid++] = luaL_ref(L, LUA_REGISTRYINDEX); return 0; } int LUA_HookLib(lua_State *L) { - new_hook_table(L, &hookReg); lua_register(L, "addHook", lib_addHook); return 0; } @@ -237,21 +241,19 @@ typedef void (*Hook_Callback)(Hook_State *); struct Hook_State { int status;/* return status to calling function */ void * userdata; - int ref;/* ref for primary hook table */ - int hook_type;/* Hook or Hook(MAX) + Mobj_Hook */ - mobjtype_t mobj_type; + int hook_type; + mobjtype_t mobj_type;/* >0 if mobj hook */ const char * string;/* used to fetch table, ran first if set */ int top;/* index of last argument passed to hook */ - int id;/* id to fetch function from registry */ + int id;/* id to fetch ref */ int values;/* num arguments passed to hook */ int results;/* num values returned by hook */ Hook_Callback results_handler;/* callback when hook successfully returns */ }; enum { - HINDEX = 1,/* hook registry */ - EINDEX = 2,/* error handler */ - SINDEX = 3,/* string itself is pushed in case of string hook */ + EINDEX = 1,/* error handler */ + SINDEX = 2,/* string itself is pushed in case of string hook */ }; static void push_error_handler(void) @@ -268,7 +270,6 @@ static void push_string(void) static boolean start_hook_stack(void) { lua_settop(gL, 0); - lua_getref(gL, hookReg); push_error_handler(); return true; } @@ -280,20 +281,12 @@ static boolean init_hook_type int hook_type, mobjtype_t mobj_type, const char * string, - int ref + int nonzero ){ - boolean ready; - hook->status = status; - if (mobj_type > 0) - ready = mobj_hook_available(hook_type, mobj_type); - else - ready = ref > 0; - - if (ready) + if (nonzero) { - hook->ref = ref; hook->hook_type = hook_type; hook->mobj_type = mobj_type; hook->string = string; @@ -311,7 +304,7 @@ static boolean prepare_hook ){ return init_hook_type(hook, default_status, hook_type, 0, NULL, - hookRefs[hook_type]); + hookIds[hook_type].numHooks); } static boolean prepare_mobj_hook @@ -323,7 +316,7 @@ static boolean prepare_mobj_hook ){ return init_hook_type(hook, default_status, hook_type, mobj_type, NULL, - mobjHookRefs[mobj_type][hook_type]); + mobj_hook_available(hook_type, mobj_type)); } static boolean prepare_string_hook @@ -357,16 +350,17 @@ static void init_hook_call hook->results_handler = results_handler; } -static void get_hook_table(Hook_State *hook) +static void get_hook(Hook_State *hook, const int *ids, int n) { - lua_getref(gL, hook->ref); + hook->id = ids[n]; + lua_getref(gL, hookRefs[hook->id]); } -static void get_hook(Hook_State *hook, int n) +static void get_hook_from_table(Hook_State *hook, int n) { lua_rawgeti(gL, -1, n); - hook->id = lua_tonumber(gL, -1) - 1; - lua_rawget(gL, HINDEX); + hook->id = lua_tonumber(gL, -1); + lua_getref(gL, hookRefs[hook->id]); } static int call_single_hook_no_copy(Hook_State *hook) @@ -409,7 +403,7 @@ static int call_hook_table_for(Hook_State *hook, int n) for (k = 1; k <= n; ++k) { - get_hook(hook, k); + get_hook_from_table(hook, k); call_single_hook(hook); } @@ -421,31 +415,29 @@ static int call_hook_table(Hook_State *hook) return call_hook_table_for(hook, lua_objlen(gL, -1)); } -static int call_ref(Hook_State *hook, int ref) +static int call_mapped(Hook_State *hook, const hook_t *map) { - int calls; + int k; - if (ref > 0) + for (k = 0; k < map->numHooks; ++k) { - lua_getref(gL, ref); - calls = call_hook_table(hook); - - return calls; + get_hook(hook, map->ids, k); + call_single_hook(hook); } - else - return 0; + + return map->numHooks; } static int call_string_hooks(Hook_State *hook) { - const int numGeneric = stringHooks[hook->hook_type].numGeneric; + const stringhook_t *map = &stringHooks[hook->hook_type]; int calls = 0; - get_hook_table(hook); + lua_getref(gL, map->ref); /* call generic string hooks first */ - calls += call_hook_table_for(hook, numGeneric); + calls += call_hook_table_for(hook, map->numGeneric); push_string(); lua_rawget(gL, -2); @@ -454,10 +446,9 @@ static int call_string_hooks(Hook_State *hook) return calls; } -static int call_generic_mobj_hooks(Hook_State *hook) +static int call_mobj_type_hooks(Hook_State *hook, mobjtype_t mobj_type) { - const int ref = mobjHookRefs[MT_NULL][hook->hook_type]; - return call_ref(hook, ref); + return call_mapped(hook, &mobjHookIds[mobj_type][hook->hook_type]); } static int call_hooks @@ -475,16 +466,16 @@ static int call_hooks { calls += call_string_hooks(hook); } - else + else if (hook->mobj_type > 0) { - if (hook->mobj_type > 0) - calls += call_generic_mobj_hooks(hook); - - calls += call_ref(hook, hook->ref); + /* call generic mobj hooks first */ + calls += call_mobj_type_hooks(hook, MT_NULL); + calls += call_mobj_type_hooks(hook, hook->mobj_type); - if (hook->mobj_type > 0) - ps_lua_mobjhooks += calls; + ps_lua_mobjhooks += calls; } + else + calls += call_mapped(hook, &hookIds[hook->hook_type]); lua_settop(gL, 0); @@ -600,25 +591,24 @@ int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type) void LUA_HookThinkFrame(void) { + const int type = Hook(ThinkFrame); + // variables used by perf stats int hook_index = 0; precise_t time_taken = 0; Hook_State hook; - int n; + const hook_t * map = &hookIds[type]; int k; - if (prepare_hook(&hook, 0, Hook(ThinkFrame))) + if (prepare_hook(&hook, 0, type)) { init_hook_call(&hook, 0, 0, res_none); - get_hook_table(&hook); - n = lua_objlen(gL, -1); - - for (k = 1; k <= n; ++k) + for (k = 0; k < map->numHooks; ++k) { - get_hook(&hook, k); + get_hook(&hook, map->ids, k); if (cv_perfstats.value == 3) { @@ -839,19 +829,16 @@ int LUA_HookHurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 d void LUA_HookNetArchive(lua_CFunction archFunc) { - const int ref = hookRefs[Hook(NetVars)]; + const hook_t * map = &hookIds[Hook(NetVars)]; Hook_State hook; /* this is a remarkable case where the stack isn't reset */ - if (ref > 0) + if (map->numHooks > 0) { // stack: tables I_Assert(lua_gettop(gL) > 0); I_Assert(lua_istable(gL, -1)); push_error_handler(); - lua_getref(gL, hookReg); - - lua_insert(gL, HINDEX); lua_insert(gL, EINDEX); // tables becomes an upvalue of archFunc @@ -860,11 +847,10 @@ void LUA_HookNetArchive(lua_CFunction archFunc) // stack: tables, archFunc init_hook_call(&hook, 1, 0, res_none); - call_ref(&hook, ref); + call_mapped(&hook, map); lua_pop(gL, 2); // pop hook table and archFunc lua_remove(gL, EINDEX); // pop error handler - lua_remove(gL, HINDEX); // pop hook registry // stack: tables } } @@ -1031,22 +1017,25 @@ static void res_musicchange(Hook_State *hook) int LUA_HookMusicChange(const char *oldname, struct MusicChange *param) { + const int type = Hook(MusicChange); + const hook_t * map = &hookIds[type]; + Hook_State hook; - if (prepare_hook(&hook, false, Hook(MusicChange))) - { - int n; - int k; + int k; + + if (prepare_hook(&hook, false, type)) + { init_hook_call(&hook, 7, 6, res_musicchange); hook.userdata = param; lua_pushstring(gL, oldname);/* the only constant value */ lua_pushstring(gL, param->newname);/* semi constant */ - get_hook_table(&hook); - n = lua_objlen(gL, -1); + for (k = 0; k <= map->numHooks; ++k) + { + get_hook(&hook, map->ids, k); - for (k = 1; k <= n; ++k) { lua_pushvalue(gL, -3); lua_pushvalue(gL, -3); lua_pushinteger(gL, *param->mflags); @@ -1060,5 +1049,6 @@ int LUA_HookMusicChange(const char *oldname, struct MusicChange *param) lua_settop(gL, 0); } + return hook.status; }