[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: late binding functions to save ram on embedded systems
- From: me the user <me.theuser@...>
- Date: Wed, 12 Sep 2018 04:06:21 +0000 (UTC)
I was looking for ways to free up ram on embedded systems using lua and ran across e-lua
specifically the LuaTinyRam patches I looked through the source and replicated it on my side
to see what kind of ram savings it brought around 10-15k on this specific application pretty good!
Anyways, having hand applied the patches I realized how much of a maintenance nightmare
these changes would add, So I came up with something I think might work well and would like
to get some opinions.
My Idea is to use a form of late binding basically instead of luaL_register adding tables instead
it would store the address of the table and add an __index and __pairs method to the meta table
this is lua 5.1 so I also had to change the pairs function a bit
[lauxlib.c]
------------------------------------------------------------------------------------
static int lookup_latebind_func(lua_State *L)
{
const luaL_Reg *l;
/* name is top of stack */
const char * name = lua_tostring (L, -1);
luaL_argcheck(L, lua_istable(L, -2), -2, "table expected");
lua_getmetatable (L, -2);
/* lookup our virtual function(s) */
for(int i = lua_objlen(L, -1); i > 0; i--) {
lua_rawgeti (L, -1, i);
l = (const luaL_Reg *) lua_touserdata (L, -1);
lua_pop(L, 1);
if(!l)
break;
for (; l->name; l++) {
if(!name || strcmp(name, l->name) == 0) {
/* if we use a function it gets added to the base table*/
lua_pushcclosure(L, l->func, 0);
if(name) {
lua_pushvalue(L, -1); /* dupe closure */
lua_setfield (L, -5, l->name);
/* returns the closure */
return 1;
}
else
lua_setfield (L, -4, l->name);
}
}
}
lua_pop(L, 2); /* base table is top of stack */
return 0;
}
static int latebind_func_pairs(lua_State *L)
{
const luaL_Reg *l;
/* base table is top of stack */
luaL_argcheck(L, lua_istable(L, -1), -1, "table expected");
lua_getmetatable (L, -1);
lua_getglobal(L, "pairs"); /* function to be called / returned */
/* clone the base table */
lua_newtable(L);
lua_pushnil(L);
while(lua_next(L, -5) != 0) {
lua_pushvalue(L, -2); /* dupe key */
lua_insert(L, -2);
lua_settable(L, -4);
}
/* add our dynamic functions */
for(int i = lua_objlen(L, -3); i > 0; i--) {
lua_rawgeti (L, -3, i);
l = (const luaL_Reg *) lua_touserdata (L, -1);
lua_pop(L, 1);
if(!l)
break;
for (; l->name; l++)
{
lua_pushcclosure(L, l->func, 0);
lua_setfield (L, -2, l->name);
}
}
lua_call(L, 1, 3);
return 3;
}
LUALIB_API void (luaL_register_late) (lua_State *L, const char *libname,
const luaL_Reg *l) {
if(!libname)
{
/* if there is no libname register normally */
luaI_openlib(L, libname, l, 0);
return;
}
static const struct luaL_reg virt_lib [] =
{
{"__latebind", lookup_latebind_func},
{NULL, NULL}
};
luaI_openlib(L, libname, virt_lib, 0);
if(!lua_getmetatable(L, -1))
lua_createtable(L, 5, 2); //-2
lua_pushcfunction(L, latebind_func_pairs);
lua_setfield(L, -2, "__pairs");
lua_pushcfunction(L, lookup_latebind_func);
lua_setfield(L, -2, "__index");
lua_pushinteger(L, lua_objlen(L, -1) + 1);
lua_pushlightuserdata (L, (void *) l);
lua_settable(L, -3);
lua_setmetatable(L, -2);
}
[lbaselib.c]
-------------------------------------------------------------------------------------
static int luaB_pairs (lua_State *L) {
if (!luaL_getmetafield(L, 1, "__pairs")) { /* no metamethod? */
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */
lua_pushvalue(L, 1); /* state, */
lua_pushnil(L); /* and initial value */
}
else {
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
lua_call(L, 1, 3); /* get 3 values from metamethod */
}
return 3;
}
By adding the __pairs metamethod it allows us to still lookup functions within the tables
when functions are called within a latebound table the __index metamethod adds them
to the table and returns the closure this makes it faster after the first call to a function
The __latebind key allows a way to see which tables are latebound and if desired
bind all the functions by passing nil as the name __latebind(nil, t)