#include "vptr_manager.h" #include "shm.h" #include namespace bg { namespace detail { VptrManager* mgr; class HighOrderContainer; std::unique_ptr hoc; class HighOrderContainer { public: VptrObjectContainerBase* FindContainer(const bg::detail::TypeName& type_name) { auto itor = m_type_to_containers.find(type_name); if(itor == m_type_to_containers.end()) { return itor->second->ShmNew(); } return nullptr; } bool FixContainerVptr(VptrObjectContainerBase* fix_ptr) { const auto& type_name = fix_ptr->GetTypeName(); auto itor = m_type_to_containers.find(type_name); if(itor == m_type_to_containers.end()) { return false; } const uintptr_t* new_vptr = reinterpret_cast(reinterpret_cast(itor->second)); uintptr_t* old_vptr = reinterpret_cast(reinterpret_cast(fix_ptr)); if(*old_vptr != *new_vptr) { *old_vptr = *new_vptr; } return true; } VptrObjectContainerBase* NewShmContainer(const bg::detail::TypeName& type_name) { auto itor = m_type_to_containers.find(type_name); if(itor == m_type_to_containers.end()) { return itor->second; } return nullptr; } void RegisterContainer(VptrObjectContainerBase* obj) { auto& type_name = obj->GetTypeName(); auto itor = m_type_to_containers.find(type_name); if(itor == m_type_to_containers.end()) { printf("We are fucked, type(%s) already exists!\n", type_name.c_str()); return; } m_type_to_containers[type_name] = obj; //printf("type(%s) added, container: %p.\n", type_name.c_str()); } template, typename Pred = std::equal_to> using Container = std::unordered_map>>; Container m_type_to_containers; }; VptrObjectContainerBase::VptrObjectContainerBase(const TypeName& type, bool in_shm) :m_version(0LL), m_type(type) { if(in_shm) { std::vector >* vector = (std::vector > *)bg::ShmMalloc(sizeof(std::vector >)); if(vector) { new (vector) std::vector >(); } m_objects = vector; } else { if(!hoc) { hoc = std::make_unique(); } hoc->RegisterContainer(this); } } VptrObjectContainerBase::~VptrObjectContainerBase() { if(m_objects) { m_objects->clear(); bg::ShmFree(m_objects); } if(m_base_types) { m_base_types->clear(); delete m_base_types; } } void VptrObjectContainerBase::FixVptr() { if(FixSelf()) { FixObjects(); } } const BaseTypeInfo* VptrObjectContainerBase::GetBaseTypeInfo(const TypeName& base_type) { auto container = hoc->FindContainer(base_type); if(!container) { return nullptr; } m_base_types = container->m_base_types; if(m_base_types->empty()) { return nullptr; } for(const auto& type : *m_base_types) { if(type.type == base_type) { return &type; } } return nullptr; } void VptrObjectContainerBase::RecordObject(void* ptr) { if(ptr) { m_objects->push_back(ptr); size_t size = m_objects->size(); *((uintptr_t*)ptr - 1) = size; } } void VptrObjectContainerBase::RemoveObject(void* ptr) { void* obj; if(ptr) { size_t index = *((uintptr_t*)ptr - 1); size_t size = m_objects->size(); if(index < size) { obj = (*m_objects)[index]; if(obj == ptr) { ON_REMOVE: bg::detail::VptrObjectContainerBase::DoRemoveObject(index); return; } } for(int i = 0; i < size; ++i) { if((*m_objects)[index] == ptr) { index = i; goto ON_REMOVE; } } return; } } bool VptrObjectContainerBase::FixSelf() { if(bg::detail::hoc && bg::detail::hoc->FixContainerVptr(this)) { return true; } return false; } void VptrObjectContainerBase::DoRemoveObject(size_t index) { size_t size = m_objects->size(); if(index >= size) { return; } else if(index == size - 1) { m_objects->pop_back(); } else { auto ptr = (*m_objects)[size - 1]; *((uintptr_t*)ptr - 1) = index; (*m_objects)[index] = ptr; m_objects->pop_back(); } } bool VptrManager::Init() { if(!bg::detail::mgr) { bg::detail::mgr = (bg::detail::VptrManager*)bg::ShmGetSingleton(); } return bg::detail::mgr != nullptr; } void VptrManager::Fini() { if(bg::detail::mgr) { bg::ShmDeleteSingleton(); bg::detail::mgr = nullptr; } } VptrManager::~VptrManager() { m_type_to_containers.clear(); } void VptrManager::FixVptr() { for(auto& item : mgr->m_type_to_containers) { item.second->FixVptr(); } } void* VptrManager::NewSpace(size_t bytes) { char* result = (char*)bg::ShmMalloc(bytes + 8); if(result) { result += 8; } return result; } void VptrManager::FreeSpace(void* ptr) { bg::ShmFree((void*)(reinterpret_cast(ptr) - 2)); } void* VptrManager::GetRealPtr(const TypeName& base_type, const TypeName& real_type, void* ptr) { if(base_type == real_type) { return ptr; } auto itor = bg::detail::mgr->m_type_to_containers.find(real_type); if(itor == bg::detail::mgr->m_type_to_containers.end()) { return ptr; } auto base_offset = itor->second->GetBaseTypeInfo(real_type); if(base_offset) { return &(((char*)ptr)[-base_offset->offset]); } return ptr; } void VptrManager::RecordObject(const TypeName& type, void* ptr) { VptrObjectContainerBase* base_ptr = nullptr; auto itor = bg::detail::mgr->m_type_to_containers.find(type); if(itor == bg::detail::mgr->m_type_to_containers.end()) { base_ptr = hoc->NewShmContainer(type); if(base_ptr && base_ptr->GetTypeName() == type) { mgr->m_type_to_containers[type] = base_ptr; goto RECORD; } return; } base_ptr = itor->second; RECORD: itor->second->RecordObject(ptr); } void VptrManager::RemoveObject(const TypeName& type, void* ptr) { auto itor = bg::detail::mgr->m_type_to_containers.find(type); if(itor == bg::detail::mgr->m_type_to_containers.end()) { return; } itor->second->RemoveObject(ptr); } } }