📄 dynobj.cpp
字号:
// This should be fastest, DoRunTime has a hash table for lookup if( pdort && (pdt=pdort->GetTypeOf(vtbl)) ) return pdt;#endif // Look among all our types pdt = doGetTypes().Find(vtbl); if( pdt ) return pdt;#if DO_ENABLE_VTABLE_CORR==1 // Look among SideBase types with modified VTables VTableInfo *vtp = g_do_vtbls.Find(vtbl); if( vtp ) return vtp->pdt;#endif return pdt;}DynObjType* doGetType( const DynI* pdi ){_CFE_; if( !pdi ){ DO_LOG( "doGetType called on NULL instance" ); return NULL; } const DynI *pself = NULL; DynObjType *pdt = pdi->doGetType( &pself ); if( !pdt ) return NULL; if( pself==pdi ) return pdt; if( !pself ){ DO_LOG1("Warning: ::doGetType - The type %s does not fill in pself in diGetType", pdt->_type ); return NULL; } // Case where we received pointer to the compound type DynObjType *pdt_sub = pdt->GetTypeAtOffset( int(((char*)pdi) - ((char*)pself)) ); if( pdt_sub ) return pdt_sub; DO_LOG_ERR2( DOERR_UNKNOWN_TYPE, "::doGetType - Retrieved compound type but failed finding sub-type: (instance:%p, type:%s)", pdi, pdt->_type ); return NULL;}//// This is the casting based on DynObjType structure//// NOTE: We can also support a cast to an outermost main object// by repeatedly moving from side base and doing a new type lookup//// Helper function for common string casevoid* doGetObjCommon( void* pobj, DynObjType *pdt, const char *type, DynObjType **pdt_found ){_CFE_; // Request for itself? if( type && !strcmp(type,pdt->_type) ){ if( pdt_found ) *pdt_found=pdt; return pobj; } // Request for compound object? if( !type || !strcmp(type,"COMPOUND") ){ if( pdt->IsSideBase() ){ if( pdt_found ) *pdt_found=pdt; // Adjust object pointer return ((char*)pobj) - pdt->_offset; } else return NULL; } // Request for compound object? if( !strcmp(type,"OUTERMOST") ){ while( pdt && pdt->IsSideBase() ){ pobj = ((char*)pobj) - pdt->_offset; pdt = ((MIBSideType*)pdt)->_compound; } if( pdt_found ) *pdt_found=pdt; return pobj; } return NULL;}void* doGetObj( void* pobj, const char *type, DynObjType *pdt, doCastAlgo algo, DynObjType **pdt_found ){_CFE_; if( !pobj ) return NULL; // No type yet? if( !pdt ){ pdt = ::doGetType(pobj); if( !pdt ) return NULL; } // Sort out common simple cases void* pco = doGetObjCommon( pobj, pdt, type, pdt_found ); if( pco ) return pco; // If caller is a DynI we should route to the specialized function if( pdt->IsA(DYNI_TYPE_ID) ) return doGetObj( (DynI*)pobj, type, algo, pdt_found, false ); // If we have base class, do a full GetObj at this level if( pdt->_base ) pco = pdt->GetObjExh(pobj,type,pdt_found); if( pco ) return pco; // If we're a side base in a compund object, do casting from point // of view of compound object. if( !pdt->IsSideBase() || algo==doCastLocal ) return NULL; // Try cross cast at next compound level while( true ){ pobj = ((char*)pobj)-pdt->_offset; pdt = ((MIBSideType*)pdt)->_compound; if( !pdt ) break; pco = pdt->GetObjExh(pobj,type,pdt_found); if( pco ) return pco; if( algo<doCastFull || !pdt->IsSideBase() ) break; } return NULL;}void* doGetObj( void* pobj, int type_id, DynObjType *pdt, doCastAlgo algo, DynObjType **pdt_found ){_CFE_; if( !pobj ) return NULL; if( !pdt && !(pdt = ::doGetType(pobj)) ) return NULL; void* pco; switch( type_id ){ case COMPOUND_TYPE_ID: // If we are the compound object, return self if( pdt->IsSideBase() ){ if( pdt_found ) *pdt_found=pdt; // Adjust object pointer return ((char*)pobj) - pdt->_offset; } else return NULL; case OUTERMOST_TYPE_ID: while( pdt && pdt->IsSideBase() ){ pobj = ((char*)pobj) - pdt->_offset; pdt = ((MIBSideType*)pdt)->_compound; } if( pdt_found ) *pdt_found = pdt; return pobj; default: // Request for itself? if( type_id==pdt->_type_id ){ if( pdt_found ) *pdt_found=pdt; return pobj; } // If we have base class, do a full GetObj at this level if( pdt->_base ){ pco = pdt->GetObjExh(pobj,type_id,pdt_found); if( pco ) return pco; } // If we're a side base in a compund object, do casting from point // of view of compound object. if( !pdt->IsSideBase() ) return NULL; break; } // Try cross cast at next compound level while( true ){ pobj = ((char*)pobj)-pdt->_offset; pdt = ((MIBSideType*)pdt)->_compound; if( !pdt ) break; pco = pdt->GetObjExh(pobj,type_id,pdt_found); if( pco ) return pco; if( algo<doCastFull || !pdt->IsSideBase() ) return NULL; } return NULL;}// Declare as non member function//typedef void* docall (*doGetObjFn)(DynI* _this, const char *type);typedef void* (*doGetObjFn)(DynI* _this, const char *type);//// Version for ::doGetObj with a string for DynI which gives priority // to DynI::doGetObj, allowing custom types to be accessed recursively.// // This is also entry point for call from from DynI::doGetObj void* doGetObj( DynI *pdi, const char *type, doCastAlgo algo, DynObjType **pdt_found, bool internal_from_dyni ){_CFE_; if( !pdi ) return NULL; DynObjType *pdt = DI_GET_TYPE(pdi); if( !pdt ){ DO_LOG_ERR1(DOERR_UNKNOWN_TYPE, "::doGetObj - failed looking up type", pdi ); return NULL; } #if DO_ENABLE_VTABLE_DISPATCH==1 // Lock so only one thread can enter static SpinLock st_sl_getobj; SpinLocker sl(st_sl_getobj); if( !sl.IsOk() ) return NULL;#endif // Last caller context static DynI *pdi_last; DynI *pdi_prev = pdi_last; pdi_last = pdi; void *pobj = NULL; if( !internal_from_dyni ){ // First entry into function // Call derived DynI::doGetObj for custom casts. That will call back to us pobj = pdi->doGetObj(type); } else{#if DO_ENABLE_VTABLE_DISPATCH==1 // Recursive entry (always from inside DynI::doGetObj) // The derived class is responsible for calling its base // class version of doGetObj until DynI::doGetObj calls here // So we only have to check side bases now if( !pdt->IsSideBase() ){ // for all bases for( DynObjType* pst=pdt->_base_side; pst && !pobj; pst=pst->_base_side ){ // Only if Dyni or more derived if( pst->IsA(DYNI_TYPE_ID) && pst->_vtbl ){ doGetObjFn fn = (doGetObjFn)pst->_vtbl[VTableIndex(DYNI_DOGETOBJ)]; if( fn ){ // This invokes the virtual function for the side base class // Add base offset DynI *pdi_rec = (DynI*)(((char*)pdi)+pst->_offset); pdi_last = pdi_rec; pobj = fn(pdi_rec,type); } } } }#endif // DO_ENABLE_VTABLE_DISPATCH } // Restore caller context pdi_last = pdi_prev; if( !pobj ){ // No result yet? if( !pdi_prev ){ // If this is outermost call // Resolve in same way as ::doGetObj // Sort out common simple cases (self, compound) pobj = doGetObjCommon( pdi, pdt, type, pdt_found ); if( !pobj && type ){ // Use DynObjType cast if( pdt->_base ) pobj = pdt->GetObjExh(pdi,type,pdt_found); // With 1st entry, we're safe to expand the call to compound type if( !pobj && pdt->IsSideBase() ){ // Try cross cast at compound levels while( true ){ pdi = (DynI*)(((char*)pdi)-pdt->_offset); pdt = ((MIBSideType*)pdt)->_compound; if( !pdt ) break; pobj = pdt->GetObjExh(pdi,type,pdt_found); if( pobj ) break; if( algo<doCastFull || !pdt->IsSideBase() ) break; } } } } } return pobj;}void* doGetObj( DynI* pdi, const char *type, doCastAlgo algo, DynObjType **found_type ) {_CFE_; return pdi ? ::doGetObj( pdi, type, ::doGetType(pdi), algo, found_type ) : NULL;}void* doGetObj( DynI* pdi, int type_id, doCastAlgo algo, DynObjType **found_type ) {_CFE_; return pdi ? ::doGetObj( pdi, type_id, ::doGetType(pdi), algo, found_type ) : NULL;}//// Logging/Error reporting functions//void DO_PUTS(const char *str){_CFE_; if( !str || !*str ) return;#if DO_USE_RUNTIME==1 if( &DORT ){ DORT.GetTextIo()->puts(str); return; }#endif puts(str);}// Appends new linevoid DO_LOG( const char *str ){_CFE_; if( !str ) str=""; DO_PUTS( str ); int sl = (int)strlen(str); if( sl==0 || str[sl-1]!='\n' ) DO_PUTS( "\n" );}void DO_LOG_ERR(int code, const char *str ){_CFE_; if( !str ) str="";#if DO_USE_RUNTIME==1 if(&DORT){ DORT.SetLastError(code,str); return; }#endif char buf[32]; int sl = (int)strlen(str); sprintf( buf, "(Error: 0x08%X) - ", code ); fprintf(stderr, "(Error: 0x08%X) - %s%c", code, str, sl && str[sl-1]=='\n' ? ' ' : '\n' );}// This will do one or two things:// 1 - For a DynI derived object, it will set soft VTable for each side // base object (restore doGetType and doGetObj)// 2 - For all objects it will register all contained // types with DoRunTime (including side types with their own VTables)// Note: If not using VTable correction nor DoRunTime, this method does no workbool doConstruct( const VObj *pobj, DynObjType *pdt, bool is_outer ){_CFE_; if( !pobj ) return false; // This method goes from compound objects to sub-objects. if( !pdt && !(pdt=::doGetType(pobj)) ){ DO_LOG_ERR1(DOERR_CANT_FIND_TYPE,"doConstruct: Cannot find type (NULL in doGetType (%P))\n",pobj); return false; } // Non VObj:s, stop here (nothing to do) if( !pdt->IsA(VOBJ_TYPE_ID) ) return false; // If we've done this type before, stop here bool do_set_init = true; if( is_outer ){#if DO_ENABLE_VTABLE_CORR==0 // If not VTable correction, nothing to do after registering 1st instance. if( pdt->_flags&DOT_DID_INIT ) return true;#endif #if DO_USE_RUNTIME==1 // Only want to set flag if DoRunTime is initialized by now if( !&DORT ) do_set_init=false;#endif } // If VTable for this type not set, do so now, but not recursively on main branch // Also OK to do for virtual base class (offset!=0) and side bases if( ((!pdt->_flags&DOT_DID_INIT) || !pdt->_vtbl) && pdt->_base && (is_outer || pdt->IsSideBase() || pdt->_offset) ){ pdt->_vtbl = *(void***)pobj;#if DO_USE_RUNTIME==1 // The right time to register, since we run this recursively, on all // base types and derived types. if( &DORT ) DORT.RegisterType( pdt->_vtbl, pdt ); } // This catches the case when type already have a VTable set, but we encounter it // with yet another VTable (happens with nested multi base class) else if( pdt->IsSideBase() && pdt->_vtbl!=*(void***)pobj ) if( &DORT ) DORT.RegisterType( *(void***)pobj, pdt );#else }#endif if( do_set_init ) pdt->_flags |= DOT_DID_INIT; // Iterate over main base classes - invoke doConstruct recursively // But do not do it for VObj itself (nothing to setup for it) int off = pdt->IsSideBase() ? 0 : -pdt->_offset; if( pdt->_base && pdt->_base->_base && !doConstruct( (VObj*)((char*)pobj)+off,pdt->_base,false) ) return false; // Everything below relates to setting up side-base VTables, so return early if possible if( pdt->IsSideBase() || !pdt->_base_side ) return true; bool is_di = pdt->IsA(DYNOBJ_TYPE_ID); bool is_do = is_di && pdt->IsA(DYNI_TYPE_ID); // Iterate over each of the side bases for( MIBSideType *pst = pdt->_base_side; pst; pst=pst->_base_side ){ // For a side type, VTable size is identical to parent VTable size if( pst->_vtbl_size<=0 && pst->_base->_vtbl_size>=0 ) pst->_vtbl_size = pst->_base->_vtbl_size; void *po = ((char*)pobj)+pst->_offset; bool should_install = is_di && pst->IsA(DYNI_TYPE_ID); bool did_install = false; if( pst->_base->_flags&DOT_NO_VTABLE_CORR ) should_install = false; // If known VTable size#if DO_ENABLE_VTABLE_CORR==1 if( should_install && pst->_vtbl_size>0 ) { void **vtbl = *(void***)po; // If actual VTable don't match type VTableInfo *vtp = g_do_vtbls.Find(vtbl); if( !vtp ){ vtp = new VTableInfo(vtbl,pst->_base->_vtbl,pst->_vtbl_size); if( !vtp ) return false; if( !vtp->AllocSoftVTbl() ){ delete vtp; DO_LOG_ERR(DOERR_NO_MEMORY,"doConstruct: AllocSoftVTbl failed."); return false; } vtp->pdt = pst; // Bind back to type g_do_vtbls.Push(vtp); // Restore entries in soft vtable /*if( pst->IsA(DynI) )*/{ static DynObjSideType dost; // Restoring doGetType and doGetObj to local methods vtp->vtbl_r[VTableIndex(DYNI_DOGETTYPE)] = (*(void***)&dost)[VTableIndex(DYNI_DOGETTYPE)]; // doGetType for side objects vtp->vtbl_r[VTableIndex(DYNI_DOGETOBJ)] = vtp->vtbl_o[VTableIndex(DYNI_DOGETOBJ)]; // doGetObj if( pst->_flags&DOT_DESTROY_SOFT && is_do ) // Set doDestroy to 'harmless' method vtp->vtbl_r[VTableIndex(DYNOBJ_DODESTROY)] = (*(void***)&dost)[VTableIndex(DYNOBJ_DODESTROY)]; // doDestroy for side objects DO_TRACE1("doConstruct: Restoring VTable DynI methods for %s", pst->_type ); } // # We could have mechanism in type to specify which methods to restore } // Already set? (should not be) if( vtbl!=vtp->vtbl_r ){ // Install soft VTable *(void***)po = vtp->vtbl_r; pst->_vtbl = vtp->vtbl_r; } did_install = true; } if( should_install && !did_install ) DO_LOG1("doConstruct (%s): A sidebase (derived from DynI), but could not restore original methods.\nCasts FROM this type will not work.", pst->_type ); #endif if( !doConstruct((VObj*)po,pst,false) ) return false; } return true;}void doReleaseDestroy( DynObj *pdo ){_CFE_; if( !pdo ) return; DynSharedI *pds = (DynSharedI*)::doGetObj(pdo,DYNSHAREDI_TYPE_ID,DI_GET_TYPE(pdo)); if( pds ) pds->doRelease(); else pdo->doDestroy( );}#include "pi/compiler.h"bool doIsStatic( const VObj *pvo, DynObjType *pdt ){_CFE_; if( !pvo ) return false; if( !pdt ) pdt = doGetType(pvo); // It is enough that it derives from a type that is static DynObjType *pdt1 = pdt->GetOuterMost(); for( pdt1=pdt; pdt1; pdt1=pdt1->_base ) if( pdt1->_flags&DOT_STATIC_TYPE ) break; if( !pdt1 ) return false; #if DO_USE_RUNTIME==1 if( !&DORT ) return false; // If object type is in the same module as DORT, then accept if( DORT.doGetType(NULL)->_module==pdt->_module ) return true; // Get callers address (return address is in callers module) void **_ebp; GET_FRAME_PTR(_ebp); void *caller = _ebp ? _ebp[-1] : NULL; // If callers module is same as module for type, then accept // # Need DoRunTimeI support //if( DORT.GetModuleFor(caller)==pdt->_module ) // return true; #else // Accept if the type of the object is from the same module as this one if( pdt->_module = &g_do_mod ) return true;#endif return false;}bool doIsStatic( const DynI *pdi ){_CFE_; return pdi ? doIsStatic((VObj*)pdi,DI_GET_TYPE(pdi)) : false; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -