From: John L. <jr...@us...> - 2009-09-25 18:48:19
|
Update of /cvsroot/wxlua/wxLua/modules/wxlua/src In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv3461/wxLua/modules/wxlua/src Modified Files: wxlbind.cpp wxlcallb.cpp wxlstate.cpp wxlua_bind.cpp Log Message: Fix multiple inheritance by adding the offset to the vtable for base classes that are second or higher. Index: wxlstate.cpp =================================================================== RCS file: /cvsroot/wxlua/wxLua/modules/wxlua/src/wxlstate.cpp,v retrieving revision 1.182 retrieving revision 1.183 diff -C2 -d -r1.182 -r1.183 *** wxlstate.cpp 23 Jun 2009 23:08:12 -0000 1.182 --- wxlstate.cpp 25 Sep 2009 18:47:58 -0000 1.183 *************** *** 1097,1100 **** --- 1097,1149 ---- } + // Note about multiple inheritance in wxLua : + // See wxLuaBindClass::baseclass_vtable_offsets + // + // class A { int x; }; class B { int y; }; class AB : public A, public B { int z; }; + // AB ab; void *v_ab_a = (A*)&ab; void *v_ab_b = (B*)&ab; + // long int dummy = 0; + // long int AB_diff = ((long int)(B*)(AB*)&dummy) - ((long int)(A*)(AB*)&dummy); + // wxPrintf(wxT("AB*=%p, A*=%p, B*=%p, B*-A*=%d\n"), &ab, v_ab_a, v_ab_b, AB_diff); + // prints: "AB*=0x614dfc, A*=0x614dfc, B*=0x614e00, B*-A*=4" + // + // In order to call B's functions from a void* pointer to an AB object : + // 1) Ideally, we cast to an AB object and the compiler will appropriately lookup + // and handle calls to B's functions. + // 2) Cast to an AB object then to a B object where the compiler has already + // shifted the pointer and calls to B's functions are made directly. + // 3) Explicitly shift the void* pointer to the AB object to where the vtable for + // B is. We now have an object that only knows about B and what B was derived from. + // I'm sure this is frowned upon by C++ enthusiasts. + // + // Ways of doing 1 and 2 in wxLua with C++ constraints, wxLua does #3 above. + // + // 1) wxLua would duplicate all the the binding functions for second + // and higher base classes and therefore each binding function will cast the + // void* we get from Lua to exactly the object type that it is. This is best, + // but it adds bloat. + // 2) Come up with a clever way using overloaded functions, templates, + // or some sort of variant class to convert the void* pointer from Lua to + // type of object that it really is (we know by the wxLuaType integer) + // and then the binding function will cast it whatever base class it may be. + // The problem is that we really need to overload this casting function by + // return type, the function takes void* and returns ClassXYZ*, but this + // is not allowed in C++. + // 3) Store an array of the offsets in each classes' wxLuaBindClass struct + // to the second or higher base classes and automatically add this offset in + // wxluaT_getuserdatatype(). The offsets are calculated at compile time + // using the AB_diff method above. + // + // Various ways to cast a void* pointer to the second base class : + // void* v_ab = &ab; // compilier doesn't know what v_ab is anymore + // AB* ab = (AB*)v_ab; // ok since we cast right back to original type + // A* a = (A*)v_ab; // ok in GCC & MSVC since we are casting to 1st base class + // B* b = (B*)v_ab; // segfault! since B*'s vtable is +4 bytes as shown above + // B* b1 = (B*)(AB*)v_ab; // ok since compiler converts to AB* and knows that B* is shifted + // B* b2 = (B*)((long int)v_ab + AB_diff); // ok since we've shifted to B + + + // forward declaration + static int wxluaT_isderivedtype_recurser(const wxLuaBindClass *wxlClass, int base_wxl_type, int levels, int* baseclass_n); + void* LUACALL wxluaT_getuserdatatype(lua_State* L, int stack_idx, int wxl_type) { *************** *** 1103,1108 **** if (wxluatype_NULL == stack_type) return NULL; ! else if (wxluaT_isderivedtype(L, stack_type, wxl_type) >= 0) return wxlua_touserdata(L, stack_idx, false); wxlua_argerror(L, stack_idx, wxT("a '") + wxluaT_typename(L, wxl_type) + wxT("'")); --- 1152,1195 ---- if (wxluatype_NULL == stack_type) return NULL; ! ! // Note: we directly use the recurser function since we may need the wxLuaBindClass ! //int level = wxluaT_isderivedtype(L, stack_type, wxl_type); ! ! int baseclass_n = 0; ! const wxLuaBindClass* wxlClass = wxluaT_getclass(L, stack_type); ! int level = wxluaT_isderivedtype_recurser(wxlClass, wxl_type, 0, &baseclass_n); ! ! if ((level >= 0) && (baseclass_n == 0)) ! { ! // We can directly cast the void* pointer to the baseclass if baseclass_n == 0 return wxlua_touserdata(L, stack_idx, false); + } + else if (level > 0) + { + // The class on the stack is derived from a second or higher base class + // and therefore the pointer to the base class is not the same as the + // pointer to the class object on the stack. We need to shift the + // pointer by the number of bytes in wxLuaBindClass::baseclass_vtable_offsets + // so that when it is casted to the base class we don't segfault. + long int o = (long int)wxlua_touserdata(L, stack_idx, false); + + if (wxlClass->baseclass_wxluatypes) + { + int i = 0; + while (wxlClass->baseclass_wxluatypes[i]) // NULL terminated, the baseclass_vtable_offsets is not + { + if (*(wxlClass->baseclass_wxluatypes[i]) == wxl_type) + { + o += wxlClass->baseclass_vtable_offsets[i]; + break; + } + i++; + } + } + + return (void*)o; + } + + wxlua_argerror(L, stack_idx, wxT("a '") + wxluaT_typename(L, wxl_type) + wxT("'")); *************** *** 1196,1203 **** // ---------------------------------------------------------------------------- ! static int wxluaT_isderivedtype_recurser(const wxLuaBindClass *wxlClass, int base_wxl_type, int levels) { if (wxlClass != NULL) { if (*wxlClass->wxluatype == base_wxl_type) return levels; --- 1283,1291 ---- // ---------------------------------------------------------------------------- ! static int wxluaT_isderivedtype_recurser(const wxLuaBindClass *wxlClass, int base_wxl_type, int levels, int* baseclass_n) { if (wxlClass != NULL) { + // check that input isn't what we want first since this func is used in a couple places if (*wxlClass->wxluatype == base_wxl_type) return levels; *************** *** 1212,1221 **** { if (*baseClass->wxluatype == base_wxl_type) ! return levels; else { ! int ret = wxluaT_isderivedtype_recurser(baseClass, base_wxl_type, levels+1); if (ret > -1) return ret; } } --- 1300,1319 ---- { if (*baseClass->wxluatype == base_wxl_type) ! { ! if (baseclass_n) *baseclass_n = wxMax(*baseclass_n, (int)i); ! return levels+1; ! } else { ! // create a new baseclass_n since we may be going down the wrong path ! // and we do not want to change the original. ! int baseclass_n_tmp = wxMax(baseclass_n ? *baseclass_n : 0, (int)i); ! int ret = wxluaT_isderivedtype_recurser(baseClass, base_wxl_type, levels+1, &baseclass_n_tmp); if (ret > -1) + { + // now set the baseclass_n var to the tmp one + if (baseclass_n) *baseclass_n = wxMax(baseclass_n_tmp, (int)i); return ret; + } } } *************** *** 1227,1231 **** } ! int LUACALL wxluaT_isderivedtype(lua_State* L, int wxl_type, int base_wxl_type) { // couldn't possibly be derived from each other --- 1325,1329 ---- } ! int LUACALL wxluaT_isderivedtype(lua_State* L, int wxl_type, int base_wxl_type, int* baseclass_n) { // couldn't possibly be derived from each other *************** *** 1233,1237 **** return -1; ! // These two types are the same if (wxl_type == base_wxl_type) return 0; --- 1331,1335 ---- return -1; ! // These two types are the same, yes recurser also checks, but this is faster if (wxl_type == base_wxl_type) return 0; *************** *** 1239,1246 **** const wxLuaBindClass *wxlClass = wxluaT_getclass(L, wxl_type); ! return wxluaT_isderivedtype_recurser(wxlClass, base_wxl_type, 1); } ! int LUACALL wxluaT_isderivedclass(const wxLuaBindClass* wxlClass, const wxLuaBindClass* base_wxlClass) { // Ok if either is NULL to allow blindly calling this --- 1337,1346 ---- const wxLuaBindClass *wxlClass = wxluaT_getclass(L, wxl_type); ! if (baseclass_n != NULL) *baseclass_n = 0; ! ! return wxluaT_isderivedtype_recurser(wxlClass, base_wxl_type, 0, baseclass_n); } ! int LUACALL wxluaT_isderivedclass(const wxLuaBindClass* wxlClass, const wxLuaBindClass* base_wxlClass, int* baseclass_n) { // Ok if either is NULL to allow blindly calling this *************** *** 1252,1256 **** return 0; ! return wxluaT_isderivedtype_recurser(wxlClass, *base_wxlClass->wxluatype, 1); } --- 1352,1358 ---- return 0; ! if (baseclass_n != NULL) *baseclass_n = 0; ! ! return wxluaT_isderivedtype_recurser(wxlClass, *base_wxlClass->wxluatype, 1, baseclass_n); } *************** *** 2913,2920 **** } ! int wxLuaState::IsDerivedType(int wxl_type, int base_wxl_type) const { wxCHECK_MSG(Ok(), -1, wxT("Invalid wxLuaState")); ! return wxluaT_isderivedtype(M_WXLSTATEDATA->m_lua_State, wxl_type, base_wxl_type); } --- 3015,3022 ---- } ! int wxLuaState::IsDerivedType(int wxl_type, int base_wxl_type, int* baseclass_n) const { wxCHECK_MSG(Ok(), -1, wxT("Invalid wxLuaState")); ! return wxluaT_isderivedtype(M_WXLSTATEDATA->m_lua_State, wxl_type, base_wxl_type, baseclass_n); } Index: wxlbind.cpp =================================================================== RCS file: /cvsroot/wxlua/wxLua/modules/wxlua/src/wxlbind.cpp,v retrieving revision 1.123 retrieving revision 1.124 diff -C2 -d -r1.123 -r1.124 *** wxlbind.cpp 19 May 2009 03:20:53 -0000 1.123 --- wxlbind.cpp 25 Sep 2009 18:47:58 -0000 1.124 *************** *** 30,35 **** wxLuaArgType g_wxluaargtypeArray_None[1] = {0}; - wxLuaBindNumber g_wxluanumberArray_None[1] = {{0, 0}}; int wxluatype_TNONE = WXLUA_TNONE; int wxluatype_TNIL = WXLUA_TNIL; --- 30,35 ---- wxLuaArgType g_wxluaargtypeArray_None[1] = {0}; + int wxluatype_TUNKNOWN = WXLUA_TUNKNOWN; int wxluatype_TNONE = WXLUA_TNONE; int wxluatype_TNIL = WXLUA_TNIL; *************** *** 48,60 **** wxLuaBindClass wxLuaBindClass_NULL = ! { "NULL", NULL, 0, NULL, &wxluatype_NULL, NULL, NULL, g_wxluanumberArray_None, 0, }; ! static int wxluatype_dummy = WXLUA_TUNKNOWN; ! int* p_wxluatype_wxEvent = &wxluatype_dummy; ! int* p_wxluatype_wxWindow = &wxluatype_dummy; ! int* p_wxluatype_wxString = &wxluatype_dummy; ! int* p_wxluatype_wxArrayString = &wxluatype_dummy; ! int* p_wxluatype_wxSortedArrayString = &wxluatype_dummy; ! int* p_wxluatype_wxArrayInt = &wxluatype_dummy; //----------------------------------------------------------------------------- --- 48,59 ---- wxLuaBindClass wxLuaBindClass_NULL = ! { "NULL", NULL, 0, NULL, &wxluatype_NULL, NULL, NULL, NULL, NULL, NULL, 0, }; ! int* p_wxluatype_wxEvent = &wxluatype_TUNKNOWN; ! int* p_wxluatype_wxWindow = &wxluatype_TUNKNOWN; ! int* p_wxluatype_wxString = &wxluatype_TUNKNOWN; ! int* p_wxluatype_wxArrayString = &wxluatype_TUNKNOWN; ! int* p_wxluatype_wxSortedArrayString = &wxluatype_TUNKNOWN; ! int* p_wxluatype_wxArrayInt = &wxluatype_TUNKNOWN; //----------------------------------------------------------------------------- Index: wxlcallb.cpp =================================================================== RCS file: /cvsroot/wxlua/wxLua/modules/wxlua/src/wxlcallb.cpp,v retrieving revision 1.59 retrieving revision 1.60 diff -C2 -d -r1.59 -r1.60 *** wxlcallb.cpp 19 May 2009 03:20:53 -0000 1.59 --- wxlcallb.cpp 25 Sep 2009 18:47:58 -0000 1.60 *************** *** 131,135 **** wxLuaState wxlState(m_wxlState); ! int event_wxl_type = WXLUA_TUNKNOWN; // If !m_wxlBindEvent, we would have errored in Connect(), but don't crash... --- 131,136 ---- wxLuaState wxlState(m_wxlState); ! // initialize to the generic wxluatype_wxEvent ! int event_wxl_type = *p_wxluatype_wxEvent; // inits to wxluatype_TUNKNOWN == WXLUA_TUNKNOWN // If !m_wxlBindEvent, we would have errored in Connect(), but don't crash... *************** *** 138,142 **** event_wxl_type = *m_wxlBindEvent->wxluatype; ! // These wxEventTypes can be wxScrollEvents or wxSpinEvents // wxEVT_SCROLL_LINEUP, wxEVT_SCROLL_LINEDOWN, wxEVT_SCROLL_THUMBTRACK --- 139,143 ---- event_wxl_type = *m_wxlBindEvent->wxluatype; ! // These wxEventTypes can be wxScrollEvents or wxSpinEvents - FIXME this could be cleaner // wxEVT_SCROLL_LINEUP, wxEVT_SCROLL_LINEDOWN, wxEVT_SCROLL_THUMBTRACK *************** *** 151,156 **** } } - else - event_wxl_type = *p_wxluatype_wxEvent; // get the generic wxluatype_wxEvent // Should know our event type, but error out in case we don't --- 152,155 ---- Index: wxlua_bind.cpp =================================================================== RCS file: /cvsroot/wxlua/wxLua/modules/wxlua/src/wxlua_bind.cpp,v retrieving revision 1.32 retrieving revision 1.33 diff -C2 -d -r1.32 -r1.33 *** wxlua_bind.cpp 19 May 2009 03:20:53 -0000 1.32 --- wxlua_bind.cpp 25 Sep 2009 18:47:58 -0000 1.33 *************** *** 1225,1230 **** static wxLuaBindClass classList[] = { ! { wxluaclassname_wxLuaObject, wxLuaObject_methods, wxLuaObject_methodCount, CLASSINFO(wxLuaObject), &wxluatype_wxLuaObject, wxluabaseclassnames_wxLuaObject, wxluabaseclassbinds_wxLuaObject, g_wxluanumberArray_None, 0, }, ! { wxluaclassname_wxLuaState, wxLuaState_methods, wxLuaState_methodCount, CLASSINFO(wxLuaState), &wxluatype_wxLuaState, wxluabaseclassnames_wxLuaState, wxluabaseclassbinds_wxLuaState, g_wxluanumberArray_None, 0, }, { 0, 0, 0, 0, 0, 0, 0 }, --- 1225,1230 ---- static wxLuaBindClass classList[] = { ! { wxluaclassname_wxLuaObject, wxLuaObject_methods, wxLuaObject_methodCount, CLASSINFO(wxLuaObject), &wxluatype_wxLuaObject, wxluabaseclassnames_wxLuaObject, wxluabaseclassbinds_wxLuaObject, NULL, NULL, NULL, 0, }, ! { wxluaclassname_wxLuaState, wxLuaState_methods, wxLuaState_methodCount, CLASSINFO(wxLuaState), &wxluatype_wxLuaState, wxluabaseclassnames_wxLuaState, wxluabaseclassbinds_wxLuaState, NULL, NULL, NULL, 0, }, { 0, 0, 0, 0, 0, 0, 0 }, |