Optimize metamethods inheritance resolving

* a table of metamethods that should be inherited is now stored in
  SWIG registry table. It optimizes memory usage.
This commit is contained in:
Artem Serebriyskiy 2014-04-22 14:31:41 +04:00
commit d120c05fcc

View file

@ -332,6 +332,11 @@ typedef struct {
lua_pushcfunction(L, f), \ lua_pushcfunction(L, f), \
lua_rawset(L,-3)) lua_rawset(L,-3))
#define SWIG_Lua_add_boolean(L,n,b) \
(lua_pushstring(L, n), \
lua_pushboolean(L, b), \
lua_rawset(L,-3))
/* special helper for allowing 'nil' for usertypes */ /* special helper for allowing 'nil' for usertypes */
#define SWIG_isptrtype(L,I) (lua_isuserdata(L,I) || lua_isnil(L,I)) #define SWIG_isptrtype(L,I) (lua_isuserdata(L,I) || lua_isnil(L,I))
@ -1016,7 +1021,52 @@ SWIGINTERN int SWIG_Lua_class_disown(lua_State *L)
return 0; return 0;
} }
/* gets the swig class registry (or creates it) */ /* populate table at the top of the stack with metamethods that ought to be inherited */
SWIGINTERN void SWIG_Lua_populate_inheritable_metamethods(lua_State *L)
{
assert(lua_istable(L,-1)); // TODO: REMOVE
SWIG_Lua_add_boolean(L, "__add", 1);
SWIG_Lua_add_boolean(L, "__sub", 1);
SWIG_Lua_add_boolean(L, "__mul", 1);
SWIG_Lua_add_boolean(L, "__div", 1);
SWIG_Lua_add_boolean(L, "__mod", 1);
SWIG_Lua_add_boolean(L, "__pow", 1);
SWIG_Lua_add_boolean(L, "__unm", 1);
SWIG_Lua_add_boolean(L, "__len", 1 );
SWIG_Lua_add_boolean(L, "__concat", 1 );
SWIG_Lua_add_boolean(L, "__eq", 1);
SWIG_Lua_add_boolean(L, "__lt", 1);
SWIG_Lua_add_boolean(L, "__le", 1);
SWIG_Lua_add_boolean(L, "__call", 1);
SWIG_Lua_add_boolean(L, "__tostring", 1);
SWIG_Lua_add_boolean(L, "__gc", 0);
}
/* creates the swig registry */
SWIGINTERN void SWIG_Lua_create_class_registry(lua_State *L)
{
/* create main SWIG registry table */
lua_pushstring(L,"SWIG");
lua_newtable(L);
/* populate it with some predefined data */
/* .library table. Placeholder */
lua_pushstring(L,".library");
lua_newtable(L);
{
/* list of metamethods that class inherits from its bases */
lua_pushstring(L,"inheritable_metamethods");
lua_newtable(L);
/* populate with list of metamethods */
SWIG_Lua_populate_inheritable_metamethods(L);
lua_rawset(L,-3);
}
lua_rawset(L,-3);
lua_rawset(L,LUA_REGISTRYINDEX);
}
/* gets the swig registry (or creates it) */
SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L) SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L)
{ {
/* add this all into the swig registry: */ /* add this all into the swig registry: */
@ -1025,13 +1075,26 @@ SWIGINTERN void SWIG_Lua_get_class_registry(lua_State *L)
if (!lua_istable(L,-1)) /* not there */ if (!lua_istable(L,-1)) /* not there */
{ /* must be first time, so add it */ { /* must be first time, so add it */
lua_pop(L,1); /* remove the result */ lua_pop(L,1); /* remove the result */
lua_pushstring(L,"SWIG"); SWIG_Lua_create_class_registry(L);
lua_newtable(L);
lua_rawset(L,LUA_REGISTRYINDEX);
/* then get it */ /* then get it */
lua_pushstring(L,"SWIG"); lua_pushstring(L,"SWIG");
lua_rawget(L,LUA_REGISTRYINDEX); lua_rawget(L,LUA_REGISTRYINDEX);
} }
assert(!lua_isnil(L,-1)); // TODO: REMOVE
}
SWIGINTERN void SWIG_Lua_get_inheritable_metamethods(lua_State *L)
{
SWIG_Lua_get_class_registry(L);
lua_pushstring(L, ".library");
lua_rawget(L,-2);
assert( !lua_isnil(L,-1) );
lua_pushstring(L, "inheritable_metamethods");
lua_rawget(L,-2);
/* Remove class registry and library table */
lua_remove(L,-2);
lua_remove(L,-2);
} }
/* Helper function to get the classes metatable from the register */ /* Helper function to get the classes metatable from the register */
@ -1323,20 +1386,18 @@ SWIGRUNTIME int SWIG_Lua_resolve_metamethod(lua_State *L)
* Returns 1 if successfully added, 0 if not added because no base class has it, -1 * Returns 1 if successfully added, 0 if not added because no base class has it, -1
* if method is defined in the class metatable itself * if method is defined in the class metatable itself
*/ */
SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *clss) SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *clss, const int metatable_index)
{ {
const int begin = lua_gettop(L); // TODO:REMOVE const int begin = lua_gettop(L); // TODO:REMOVE
/* Class metatable must be one below the top of the stack */ assert(lua_istable(L, metatable_index)); // TODO: REMOVE
assert(lua_istable(L,-2)); /* metamethod name - on the top of the stack */
/* and metamethod name - on the top of the stack */
assert(lua_isstring(L,-1)); assert(lua_isstring(L,-1));
const int metatable_index = lua_gettop(L) - 1;
const int key_index = lua_gettop(L); const int key_index = lua_gettop(L);
/* Check whether method is already defined in metatable */ /* Check whether method is already defined in metatable */
lua_pushvalue(L,-1); /* copy of the key */ lua_pushvalue(L,key_index); /* copy of the key */
lua_gettable(L,metatable_index); lua_gettable(L,metatable_index);
if( !lua_isnil(L,-1) ) { if( !lua_isnil(L,-1) ) {
lua_pop(L,1); lua_pop(L,1);
@ -1355,6 +1416,7 @@ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *
const swig_lua_class *base = clss->bases[i]; const swig_lua_class *base = clss->bases[i];
SWIG_Lua_get_class_metatable(L, base->fqname); SWIG_Lua_get_class_metatable(L, base->fqname);
lua_pushvalue(L, key_index); lua_pushvalue(L, key_index);
assert(lua_istable(L,-2)); // TODO: REMOVE
lua_rawget(L, -2); lua_rawget(L, -2);
if( !lua_isnil(L,-1) ) { if( !lua_isnil(L,-1) ) {
assert( lua_gettop(L) == begin + 2); // TODO: REMOVE assert( lua_gettop(L) == begin + 2); // TODO: REMOVE
@ -1383,50 +1445,47 @@ SWIGINTERN int SWIG_Lua_add_class_user_metamethod(lua_State *L, swig_lua_class *
return success; return success;
} }
#define SWIG_ADD_CLASS_METAMETHOD( name ) \
lua_pushstring(L,name);\
SWIG_Lua_add_class_user_metamethod(L,clss);\
lua_pop(L,1);
SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class *clss) SWIGINTERN void SWIG_Lua_add_class_user_metamethods(lua_State *L, swig_lua_class *clss)
{ {
const int begin = lua_gettop(L); // TODO:REMOVE const int begin = lua_gettop(L); // TODO:REMOVE
/* TODO: This place desperately needs for optimization:
* 1. Hardcoded names of all metamethods is bad idea
* 2. We create a N lua strings for every class instead of creating those N strings
* only once
*/
SWIG_Lua_get_class_metatable(L, clss->fqname); SWIG_Lua_get_class_metatable(L, clss->fqname);
const int metatable_index = lua_gettop(L); const int metatable_index = lua_gettop(L);
SWIG_ADD_CLASS_METAMETHOD( "__add" ); SWIG_Lua_get_inheritable_metamethods(L);
SWIG_ADD_CLASS_METAMETHOD( "__sub" ); assert(lua_istable(L,-1));
SWIG_ADD_CLASS_METAMETHOD( "__mul" ); const int metamethods_info_index = lua_gettop(L);
SWIG_ADD_CLASS_METAMETHOD( "__div" ); lua_pushnil(L); /* first key */
SWIG_ADD_CLASS_METAMETHOD( "__mod" ); while(lua_next(L, metamethods_info_index) != 0 ) {
SWIG_ADD_CLASS_METAMETHOD( "__pow" ); /* key at index -2, value at index -1 */
SWIG_ADD_CLASS_METAMETHOD( "__unm" ); const int is_inheritable = lua_toboolean(L,-2);
SWIG_ADD_CLASS_METAMETHOD( "__concat" ); lua_pop(L,1); /* remove value - we don't need it anymore */
SWIG_ADD_CLASS_METAMETHOD( "__len" );
SWIG_ADD_CLASS_METAMETHOD( "__eq" ); if(is_inheritable) { /* if metamethod is inheritable */
SWIG_ADD_CLASS_METAMETHOD( "__lt" ); SWIG_Lua_add_class_user_metamethod(L,clss,metatable_index);
SWIG_ADD_CLASS_METAMETHOD( "__le" ); }
SWIG_ADD_CLASS_METAMETHOD( "__call" );
assert(lua_gettop(L) == metamethods_info_index + 1 ); // TODO: REMOVE
}
lua_pop(L,1); /* remove inheritable metatmethods table */
/* Special handling for __tostring method */ /* Special handling for __tostring method */
lua_pushstring(L, "__tostring"); lua_pushstring(L, "__tostring");
const int tostring_result = SWIG_Lua_add_class_user_metamethod(L,clss); lua_pushvalue(L,-1);
if (tostring_result == 0) { assert(lua_istable(L,metatable_index)); // TODO: REMOVE
lua_rawget(L,metatable_index);
const int tostring_undefined = lua_isnil(L,-1);
lua_pop(L,1);
if( tostring_undefined ) {
lua_pushcfunction(L, SWIG_Lua_class_tostring); lua_pushcfunction(L, SWIG_Lua_class_tostring);
lua_rawset(L, metatable_index); lua_rawset(L, metatable_index);
} else { } else {
lua_pop(L,1); lua_pop(L,1); /* remove copy of the key */
} }
/* Warning: __index and __newindex are SWIG-defined. For user-defined operator[] /* Warning: __index and __newindex are SWIG-defined. For user-defined operator[]
* a __getitem/__setitem method should be defined * a __getitem/__setitem method should be defined
*/ */
lua_pop(L,1); lua_pop(L,1); /* pop class metatable */
assert(lua_gettop(L) == begin ); // TODO: REMOVE assert(lua_gettop(L) == begin ); // TODO: REMOVE
} }