📄 dynobj.cpp
字号:
// Check if side base that derives from DynI (and would require VTable correction)#if DO_ENABLE_VTABLE_CORR!=1 && !defined(DI_GET_TYPE_GLOBAL) if( it()->IsSideBase() ){ if( it()->IsA(DYNI_TYPE_ID) ){ DO_LOG1( "doBaseInit: The side-base type %s is derived from DynI. Casts FROM this base to other\n" "bases when using DynI::doGetObj / DynI::doGetType are unsafe. Use DI_GET_TYPE\n" "in that case (or enable VTable correction).", it()->_type ); } }#endif // DO_ENABLE_VTABLE_CORR } // Check if we have unresolved types for( EapIter<DynObjType*> it(doGetTypesUnres()); it(); it++ ) DO_LOG1( "doBaseInit: Unresolved - %s", it()->_type ); // Make sure types are NULL terminated now if( !doGetTypes().Size() || doGetTypes().Top() ) doGetTypes().Push(NULL); // Set up DynObjLibImpl fields if( !g_do_lib_impl._module ){ g_do_lib_impl._implements = g_do_implements; g_do_lib_impl._do_traits = doGetDoTraits(); g_do_lib_impl._types = g_do_types->GetBasePointerRef( ); g_do_lib_impl._module = &g_do_mod; } g_do_base_init = 1;#if DO_USE_RUNTIME==1 if( pdorti ) pdorti->TempDisableCreate( false );#endif return &g_do_lib_impl;}// Called on unloading a library, to remove module and types from DoRunTimeextern "C" SYM_EXPORT void doExit( ){#if defined(DO_MODULE) && DO_USE_RUNTIME==1 if( &DORT ){ for( EapIter<DynObjType*> it(doGetTypes()); it(); it++ ){ if( it()->_vtbl ) DORT.UnRegisterType(it()->_vtbl); } DORT.UnRegisterModule( &g_do_mod ); g_dort = NULL;#if DO_ENABLE_VTABLE_CORR==1 for( EapIter<VTableInfo*> it(g_do_vtbls); it(); it++ ) DORT.UnRegisterType(it()->vtbl_o);#endif }#endif}//#include "pi/compiler.h"DynObjType::DynObjType( const char *type, int type_id, int flag_ver, int size, const void *this_ptr, const void *base_ptr ) : _sh(sizeof(DynObjType),0,0), _type(NULL), _type_id(type_id), _version(0), _size(size), _base(NULL), _vtbl(NULL), _base_side(NULL), _vtbl_size(-1), _flags(0), _module(NULL), _cdofn(NULL), _dcdofn(NULL), _idc_prv(0), _idc_nxt(0) {_CFE_; //void **_ebp; //GET_FRAME_PTR(_ebp); //void *caller = _ebp ? _ebp[-1] : NULL; //printf("::DynObjType - _ebp:%p caller:%p doExit:%p &doExit:%p\n", _ebp, caller, doExit, &doExit ); // GCC ctor bug, force ordinary function Ctor( type, type_id, flag_ver, size, this_ptr, base_ptr );}void DynObjType::Ctor( const char *type, int type_id, int flag_ver, int size, const void *this_ptr, const void *base_ptr ) {_CFE_; _flags = short(flag_ver>>16); _version = short(flag_ver&0xFFFF); if( !type ){ DO_LOG_ERR(DOERR_EMPTY_TYPE_STRING,"::DynObjType: Empty type string received\n"); return; } if( type_id&(~TYPE_ID_MASK) ) DO_LOG2( "::DynObjType: type id (%08X) for %s uses bits outside default ID mask", type_id, type ); _module = &g_do_mod; // Did we get a pointer to an object? // This is only useful for user-types and side bases (which set vtable themselves) if( _flags&DOT_USER_TYPE && this_ptr ){ _vtbl = *(void***)this_ptr;#if DO_USE_RUNTIME==1 // This is best time to register the type if( &DORT ) DORT.RegisterType( _vtbl, this );#endif } // For virtual inheritance, the base pointer is different to the this_ptr // _offset ends up negative below for virtual inheritance _offset = this_ptr && base_ptr ? (short)(((const char*)this_ptr)-((const char*)base_ptr)) : 0; const char *pc = strchr(type,':'); if( !pc ){ // Simple case, no base class char *str = new char[strlen(type)+1]; if( !str ) return; // ## Set error strcpy(str,type); _type = str; } else{ int bcl = (int)strlen(pc+1); const char *br_pos = strchr(type,']'); // For side bases if( strchr(br_pos?br_pos+2:pc+1,':') ){ DO_LOG_ERR1(DOERR_EXPECTED_ONLY_ONE_BASE,"::DynObjType: More than one direct base class given: %s\n",type); // An error return; } if( !strncmp(pc+1,type,bcl) && type[bcl]==':' ){ DO_LOG_ERR1(DOERR_TYPE_USES_SELF_AS_BASE,"::DynObjType: Type referring to itself as base class found: %s\n",type); // An error return; } // Look for base type in our module DynObjType *pdt = doGetTypes().Find(pc+1); if( pdt ){ if( pdt==this ){ DO_LOG_ERR1(DOERR_TYPE_USES_SELF_AS_BASE,"::DynObjType: Type referring to itself as base class found: %s\n",type); // An error return; } _base = pdt; } else{ // Resolve base type later doGetTypesUnres().Push(this); //DO_TRACE1( "Unresolved type: %s\n", type ); pc = pc+strlen(pc); } char *str = new char[pc+1-type]; if( !str ) return; // ## Set error strncpy(str,type,pc-type); str[pc-type] = 0; _type = str; } // Before pushing, check that we don't have this class already // (also, protect from instances created on the stack and repeatedly // registered/destroyed). DynObjType *pdt; for( int ix=doGetTypes().Size()-1; ix>=0; ix-- ){ pdt = doGetTypes()[ix]; if( pdt->_sh.m_magic!=SH_MAGIC ){ DO_LOG1("Invalid DynObjType structure at %p\n",pdt); doGetTypes().RemoveIndexUnordered(ix); } if( pdt->_type_id==_type_id ){ if( SIDEBASE_TYPE_ID!=_type_id || !strcmp(pdt->_type,_type) ){ DynObjType_BpDummy(); DO_LOG_ERR2(DOERR_TYPE_ALREADY_EXISTS,"::DynObjType: Constructing already existing DynObjType structure %s (%p)\n",pdt->_type,pdt); return; } } } // Register it doGetTypes().Push(this); //DO_TRACE1( "Registering type: %s\n", _type ); // Does this new type resolve base for some other types? for( EapIter<DynObjType*> it(doGetTypesUnres()); it(); it++ ){ const char *pc = strchr(it()->_type,':'); if( pc ){ int tl = (int)strlen(pc+1); if( !strncmp(_type,pc+1,tl) && (!_type[tl] || _type[tl]==':') ){ //DO_TRACE1( "Resolving type: %s\n", it()->_type ); *(char*)pc = 0; // Know base class, remove ':' it()->_base = this; doGetTypesUnres().RemoveIndexUnordered(it.Index()); it--; } } }}MIBSideType::MIBSideType( DynObjType *compound, short offset, const char *type, int type_id, int ver, int size, const void *_this, int vtbl_size ) : DynObjType( type, type_id, ver, size, _this?((const char*)_this)+offset:NULL ), _compound(compound) {_CFE_; _sh.SetFlags(_sh.Flags()|DOT_SIDE_TYPE); // So that it's possible to tell we're a derived object _offset = offset; // Override 0 from DynObjType ctor _vtbl_size = vtbl_size; if( _this ){ // Since we're a side base, we know that this VTable is ours _vtbl = *(void***)_this;#if DO_USE_RUNTIME==1 if( &DORT ) DORT.RegisterType( _vtbl, this );#endif }}DynObjType::~DynObjType(){_CFE_; _sh.m_magic = 0; // Erase the magic marker delete [] _type; }bool DynObjType::operator==(const char *type) const { if( !type ) return false; // Need to match also when unresolved int tl = (int)strlen(type); if( strncmp(_type,type,tl) ) return false; return !_type[tl] || _type[tl]==':'; }bool DynObjType::IsA( int type_id ) const { return _type_id==type_id ? true : (_base?_base->IsA(type_id):false);}bool DynObjType::CanBeAInternal( int type_id ) const { if( _type_id==type_id ) return true; if( _base && _base->CanBeAInternal(type_id) ) return true; if( IsSideBase() ) return false; for( DynObjType *psb=_base_side; psb; psb=psb->_base_side ) if( psb->CanBeAInternal(type_id) ) return true; return false;}// This searches for the requested type from the outermost type// (global, exhaustive)bool DynObjType::CanBeA( int type_id ) const { if( !this ) return false; const DynObjType *pdt = GetOuterMost(); return pdt->CanBeAInternal( type_id );}DynObjType* DynObjType::GetOuterMost() const { if( !this ) return NULL; const DynObjType *pdt = this; while( pdt->IsSideBase() ){ pdt = ((MIBSideType*)pdt)->_compound; DO_ASSERT_MSG( pdt, "GetOuterMost - No outermost type found" ); } return (DynObjType*)pdt;}DynObjType* DynObjType::GetTypeAtOffset( int off ) const { if( !this || off<0 ) return NULL; // We could do it for <0 also, but no point if( !off ) return (DynObjType*)this; // Walk side bases until we know where to find type const DynObjType *pdt = this; while( pdt->_base_side && off>=pdt->_base_side->_offset ) pdt = pdt->_base_side; if( !pdt ) return NULL; off -= pdt->_offset; /* // This could happen for virtual base classes (?) while( off>0 && pdt->_base ) { off -= pdt->_offset; pdt = pdt->_base; } */ return !off ? (DynObjType*)pdt : NULL;}// Recursive casting on type stringvoid* DynObjType::GetObj( void *pobj, const char *type, DynObjType **found_type ){_CFE_; // No checking of args, this function can only be called from inside DynObj.cpp DynObjType *pdt; // Self? if( !strcmp(_type,type) ){ if( found_type ) *found_type=this; return pobj; } // Try all main bases int off = IsSideBase() ? 0 : _offset; for( pdt=_base; pdt; pdt=pdt->_base ){ if( !strcmp(pdt->_type,type) ) return ((char*)pobj) - off; off += pdt->_offset; } // Try each side type (start at its base) if( !IsSideBase() ){ DynObjType *pst; for( pst=_base_side; pst; pst=pst->_base_side ){ off = pst->_offset; // Side base class offset for( pdt=pst->_base; pdt; pdt=pdt->_base ){ if( !strcmp(pdt->_type,type) ){ if( found_type ) *found_type=pdt; return ((char*)pobj) + off; } off -= pdt->_offset; // These are virtual base class offsets } } } // Done return NULL;}// Recursive casting on type stringvoid* DynObjType::GetObjExh( void *pobj, const char *type, DynObjType **found_type ){_CFE_; // No checking of args, this function can only be called from inside DynObj.cpp // We try the direct bases from left to right if( !strcmp(_base->_type,type) ){ if( found_type ) *found_type=this; return ((char*)pobj) - (IsSideBase() ? 0 : _offset); } // Try each side type if( !IsSideBase() ){ for( DynObjType *pdt=_base_side; pdt; pdt=pdt->_base_side ) if( !strcmp(pdt->_type,type) ){ if( found_type ) *found_type=pdt; return ((char*)pobj) + pdt->_offset; } } // recursively do the same iteration void *pco; if( _base->_base && (pco=_base->GetObjExh(((char*)pobj)-(IsSideBase() ? 0 : _offset),type,found_type)) ) return pco; // Try each side type if( !IsSideBase() ){ DynObjType *pst; for( pst=_base_side; pst; pst=pst->_base_side ) if( pst->_base && (pco=pst->GetObjExh(((char*)pobj)+pst->_offset,type,found_type)) ) return pco; } // Exhausted return NULL;}// Recursive casting on type stringvoid* DynObjType::GetObj( void *pobj, int type_id, DynObjType **found_type ){_CFE_; // No checking of args, this function can only be called from inside DynObj.cpp DynObjType *pdt; // Self? if( _type_id==type_id ){ if( found_type ) *found_type=this; return pobj; } // Try all main bases int off = IsSideBase() ? 0 : _offset; for( pdt=_base; pdt; pdt=pdt->_base ){ if( pdt->_type_id==type_id ){ if( found_type ) *found_type=pdt; return ((char*)pobj) - off; } off += pdt->_offset; } // Try each side type (start at its base) if( !IsSideBase() ){ DynObjType *pst; for( pst=_base_side; pst; pst=pst->_base_side ){ off = pst->_offset; // Side base class offset for( pdt=pst->_base; pdt; pdt=pdt->_base ){ if( pdt->_type_id==type_id ){ if( found_type ) *found_type=pdt; return ((char*)pobj) + off; } off -= pdt->_offset; // These are virtual base class offsets } } } // Done return NULL;}// Recursive casting on type idvoid* DynObjType::GetObjExh( void *pobj, int type_id, DynObjType **found_type ){_CFE_; // No checking of args, this function can only be called from inside DynObj.cpp // We try the direct bases from left to right if( _base->_type_id==type_id ){ if( found_type ) *found_type=this; return ((char*)pobj) - (IsSideBase() ? 0 : _offset); } // Side bases themselves, per definition have no side bases. // If ordinary base, Try each side type if( !IsSideBase() ){ for( DynObjType* pdt=_base_side; pdt; pdt=pdt->_base_side ) if( pdt->_type_id==type_id ){ if( found_type ) *found_type=pdt; return ((char*)pobj) + pdt->_offset; } } // recursively do the same iteration void *pco; if( _base->_base && (pco=_base->GetObjExh(((char*)pobj)-(IsSideBase() ? 0 : _offset),type_id,found_type)) ) return pco; // Try each side type recursively if( !IsSideBase() ){ DynObjType *pst; for( pst=_base_side; pst; pst=pst->_base_side ) if( pst->_base && (pco=pst->GetObjExh(((char*)pobj)+pst->_offset,type_id,found_type)) ) return pco; } // Exhausted return NULL;} // Instantiated to add a side base class to the typevoid SideBaseDecl::Ctor( const char *main_cl, const char *side_base_cl, int size, int off, const void *_this, int vtbl_size, void **vtbl_o ){_CFE_; //BPDummy(); if( !main_cl || !side_base_cl ) return; DynObjType *ptype = doGetTypes().Find( main_cl ); if( !ptype ){ DO_LOG_ERR1(DOERR_SIDEBASE_NOT_FOUND,"SideBaseDecl: Main class not found: %s\n",main_cl); return; } if( off<=0 || off>32767){ DO_LOG_ERR2(DOERR_SIDEBASE_OFFSET_OUT_OF_RANGE,"SideBaseDecl: [%s] Invalid offset: %d\n",side_base_cl,off); return; } // Check that there is space in main object if( off+size>ptype->_size ){ DO_LOG_ERR(DOERR_SIDEBASE_NO_SPACE_IN_MAIN,"SideBaseDecl: Not enough space in containing object."); return; } // Side types are their own types, derived from side_base_cl given above. // (unless a type with no virtual functions) // make new name and allocate new structure for it. // ## We could make a template to test for a virtual class int ptl = (int)strlen(ptype->_type); int sbl = (int)strlen(side_base_cl); char *str = new char[sbl+2+ptl+1+sbl+1]; if( !str ){ DO_LOG_ERR(DOERR_NO_MEMORY,"SideBaseDecl: Mem alloc failed."); return; } strcpy(str,side_base_cl); strcat(str,"["); strcat(str,ptype->_type); // Don't want to include unresolved base of our base in name char *pc = strchr(str+sbl,':'); if( pc ) *pc=0; strcat(str,"]:"); strcat(str,side_base_cl); // This will auto register new type // Side types don't need unique IDs since they're not addressed from outside MIBSideType *pst = new MIBSideType(ptype,off,str,SIDEBASE_TYPE_ID,1,size,_this,vtbl_size); //MIBSideType *pst = new MIBSideType(ptype,off,str,g_do_side_type_id,1,size,_this,vtbl_size); //g_do_side_type_id -= STEP_TYPE_ID; if( pst->_base ){ // The VTable given as an argument is the one of the base of the side class if( vtbl_o && !pst->_base->_vtbl ) pst->_base->_vtbl = vtbl_o; // For a side type, VTable size is identical to parent VTable size if( vtbl_size<=0 && pst->_base->_vtbl_size>=0 ) pst->_vtbl_size = pst->_base->_vtbl_size; } delete [] str; if( !pst ) { DO_LOG_ERR(DOERR_NO_MEMORY,"SideBaseDecl: Mem alloc failed."); return; } DoGetMibst().Push(pst); // Add last among side bases (order does not matter, since offset is absolute) while( ptype->_base_side ) ptype = ptype->_base_side; ptype->_base_side = pst;}// Main init function (manually called after global construction is done)bool doInit( ){_CFE_;#if defined(DO_MAIN) #if DO_USE_RUNTIME==1 // Make sure DoRunTime VTable is known doConstruct(&DORT,DORT.doGetType(NULL),true); #endif // This will setup any registered types doBaseInit( NULL );#endif return !doGetTypesUnres().Size();}//// Resolve type for arbitrary object with VTable// DynObjType* doGetType( const void* pobj ){_CFE_; if( !pobj ){ DO_LOG( "doGetType called on NULL instance" ); return NULL; } void **vtbl = *(void***)pobj; DynObjType *pdt;#if DO_USE_RUNTIME==1 DoRunTimeI *pdort = &DORT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -