Ver código fonte

【fix】 修改单元测试

lvzeyue 1 ano atrás
pai
commit
435744230c

+ 10 - 0
Project4.sln

@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.33529.622
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project4", "Project4\Project4.vcxproj", "{D5197FB1-8795-48EF-84A3-D4F16962F895}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_helper", "test_helper\test_helper.vcxproj", "{9076A25C-0936-469C-B2ED-88A369D7F28E}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|x64 = Debug|x64
@@ -21,6 +23,14 @@ Global
 		{D5197FB1-8795-48EF-84A3-D4F16962F895}.Release|x64.Build.0 = Release|x64
 		{D5197FB1-8795-48EF-84A3-D4F16962F895}.Release|x86.ActiveCfg = Release|Win32
 		{D5197FB1-8795-48EF-84A3-D4F16962F895}.Release|x86.Build.0 = Release|Win32
+		{9076A25C-0936-469C-B2ED-88A369D7F28E}.Debug|x64.ActiveCfg = Debug|x64
+		{9076A25C-0936-469C-B2ED-88A369D7F28E}.Debug|x64.Build.0 = Debug|x64
+		{9076A25C-0936-469C-B2ED-88A369D7F28E}.Debug|x86.ActiveCfg = Debug|Win32
+		{9076A25C-0936-469C-B2ED-88A369D7F28E}.Debug|x86.Build.0 = Debug|Win32
+		{9076A25C-0936-469C-B2ED-88A369D7F28E}.Release|x64.ActiveCfg = Release|x64
+		{9076A25C-0936-469C-B2ED-88A369D7F28E}.Release|x64.Build.0 = Release|x64
+		{9076A25C-0936-469C-B2ED-88A369D7F28E}.Release|x86.ActiveCfg = Release|Win32
+		{9076A25C-0936-469C-B2ED-88A369D7F28E}.Release|x86.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 25 - 18
Project4/Project4.vcxproj

@@ -19,26 +19,32 @@
     </ProjectConfiguration>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="main.cpp" />
-    <ClCompile Include="page_heap.cc" />
-    <ClCompile Include="shm.cc" />
-    <ClCompile Include="shm_helper.cc" />
-    <ClCompile Include="shm_manager.cc" />
-    <ClCompile Include="shm_object.cc" />
-    <ClCompile Include="size_map.cc" />
-    <ClCompile Include="vptr_manager.cc" />
+    <ClInclude Include="..\shm\metadata_allocator.h" />
+    <ClInclude Include="..\shm\page_heap.h" />
+    <ClInclude Include="..\shm\shm.h" />
+    <ClInclude Include="..\shm\shm_config.h" />
+    <ClInclude Include="..\shm\shm_helper.h" />
+    <ClInclude Include="..\shm\shm_manager.h" />
+    <ClInclude Include="..\shm\shm_object.h" />
+    <ClInclude Include="..\shm\size_map.h" />
+    <ClInclude Include="..\shm\span.h" />
+    <ClInclude Include="..\shm\vptr_manager.h" />
+    <ClInclude Include="..\vs_helper\type_helper.h" />
+    <ClInclude Include="test\catch.hpp" />
   </ItemGroup>
   <ItemGroup>
-    <ClInclude Include="catch.hpp" />
-    <ClInclude Include="page_heap.h" />
-    <ClInclude Include="shm.h" />
-    <ClInclude Include="shm_config.h" />
-    <ClInclude Include="shm_helper.h" />
-    <ClInclude Include="shm_manager.h" />
-    <ClInclude Include="shm_object.h" />
-    <ClInclude Include="size_map.h" />
-    <ClInclude Include="type_helper.h" />
-    <ClInclude Include="vptr_manager.h" />
+    <ClCompile Include="..\shm\page_heap.cc" />
+    <ClCompile Include="..\shm\shm.cc" />
+    <ClCompile Include="..\shm\shm_helper.cc" />
+    <ClCompile Include="..\shm\shm_manager.cc" />
+    <ClCompile Include="..\shm\shm_object.cc" />
+    <ClCompile Include="..\shm\size_map.cc" />
+    <ClCompile Include="..\shm\vptr_manager.cc" />
+    <ClCompile Include="test\testmain.cpp" />
+    <ClCompile Include="test\test_manage.cpp" />
+    <ClCompile Include="test\test_object.cpp" />
+    <ClCompile Include="test\test_page_heap.cpp" />
+    <ClCompile Include="test\test_size_map.cpp" />
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <VCProjectVersion>16.0</VCProjectVersion>
@@ -141,6 +147,7 @@
       <SDLCheck>true</SDLCheck>
       <PreprocessorDefinitions>_DEBUG;_CONSOLE;_AMD64_;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <ConformanceMode>true</ConformanceMode>
+      <AdditionalIncludeDirectories>../shm;./test;../vs_helper;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>

+ 70 - 54
Project4/Project4.vcxproj.filters

@@ -1,14 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <Filter Include="源文件">
-      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
-      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
-    </Filter>
-    <Filter Include="头文件">
-      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
-      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
-    </Filter>
     <Filter Include="资源文件">
       <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
       <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
@@ -16,63 +8,87 @@
     <Filter Include="test">
       <UniqueIdentifier>{6c2a85ce-be82-4d46-955f-ab99ebd50cc9}</UniqueIdentifier>
     </Filter>
+    <Filter Include="shm">
+      <UniqueIdentifier>{4928fd83-9d8e-425a-8e8c-05f4fcb656a2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="vs_helper">
+      <UniqueIdentifier>{feece2a9-a9af-4129-accf-7ed95a8891b8}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="vptr_manager.cc">
-      <Filter>源文件</Filter>
-    </ClCompile>
-    <ClCompile Include="shm_helper.cc">
-      <Filter>源文件</Filter>
-    </ClCompile>
-    <ClCompile Include="shm.cc">
-      <Filter>源文件</Filter>
-    </ClCompile>
-    <ClCompile Include="shm_object.cc">
-      <Filter>源文件</Filter>
-    </ClCompile>
-    <ClCompile Include="shm_manager.cc">
-      <Filter>源文件</Filter>
-    </ClCompile>
-    <ClCompile Include="size_map.cc">
-      <Filter>源文件</Filter>
-    </ClCompile>
-    <ClCompile Include="page_heap.cc">
-      <Filter>源文件</Filter>
-    </ClCompile>
-    <ClCompile Include="main.cpp">
-      <Filter>源文件</Filter>
-    </ClCompile>
-  </ItemGroup>
-  <ItemGroup>
-    <ClInclude Include="shm.h">
-      <Filter>头文件</Filter>
+    <ClInclude Include="..\vs_helper\type_helper.h">
+      <Filter>vs_helper</Filter>
+    </ClInclude>
+    <ClInclude Include="..\shm\metadata_allocator.h">
+      <Filter>shm</Filter>
     </ClInclude>
-    <ClInclude Include="shm_helper.h">
-      <Filter>头文件</Filter>
+    <ClInclude Include="..\shm\page_heap.h">
+      <Filter>shm</Filter>
     </ClInclude>
-    <ClInclude Include="vptr_manager.h">
-      <Filter>头文件</Filter>
+    <ClInclude Include="..\shm\shm.h">
+      <Filter>shm</Filter>
     </ClInclude>
-    <ClInclude Include="shm_manager.h">
-      <Filter>头文件</Filter>
+    <ClInclude Include="..\shm\shm_config.h">
+      <Filter>shm</Filter>
     </ClInclude>
-    <ClInclude Include="shm_object.h">
-      <Filter>头文件</Filter>
+    <ClInclude Include="..\shm\shm_helper.h">
+      <Filter>shm</Filter>
     </ClInclude>
-    <ClInclude Include="size_map.h">
-      <Filter>头文件</Filter>
+    <ClInclude Include="..\shm\shm_manager.h">
+      <Filter>shm</Filter>
     </ClInclude>
-    <ClInclude Include="page_heap.h">
-      <Filter>头文件</Filter>
+    <ClInclude Include="..\shm\shm_object.h">
+      <Filter>shm</Filter>
     </ClInclude>
-    <ClInclude Include="type_helper.h">
-      <Filter>头文件</Filter>
+    <ClInclude Include="..\shm\size_map.h">
+      <Filter>shm</Filter>
     </ClInclude>
-    <ClInclude Include="catch.hpp">
-      <Filter>头文件</Filter>
+    <ClInclude Include="..\shm\span.h">
+      <Filter>shm</Filter>
     </ClInclude>
-    <ClInclude Include="shm_config.h">
-      <Filter>头文件</Filter>
+    <ClInclude Include="..\shm\vptr_manager.h">
+      <Filter>shm</Filter>
     </ClInclude>
+    <ClInclude Include="test\catch.hpp">
+      <Filter>test</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\shm\page_heap.cc">
+      <Filter>shm</Filter>
+    </ClCompile>
+    <ClCompile Include="..\shm\shm.cc">
+      <Filter>shm</Filter>
+    </ClCompile>
+    <ClCompile Include="..\shm\shm_helper.cc">
+      <Filter>shm</Filter>
+    </ClCompile>
+    <ClCompile Include="..\shm\shm_manager.cc">
+      <Filter>shm</Filter>
+    </ClCompile>
+    <ClCompile Include="..\shm\shm_object.cc">
+      <Filter>shm</Filter>
+    </ClCompile>
+    <ClCompile Include="..\shm\size_map.cc">
+      <Filter>shm</Filter>
+    </ClCompile>
+    <ClCompile Include="..\shm\vptr_manager.cc">
+      <Filter>shm</Filter>
+    </ClCompile>
+    <ClCompile Include="test\test_size_map.cpp">
+      <Filter>test</Filter>
+    </ClCompile>
+    <ClCompile Include="test\testmain.cpp">
+      <Filter>test</Filter>
+    </ClCompile>
+    <ClCompile Include="test\test_manage.cpp">
+      <Filter>test</Filter>
+    </ClCompile>
+    <ClCompile Include="test\test_object.cpp">
+      <Filter>test</Filter>
+    </ClCompile>
+    <ClCompile Include="test\test_page_heap.cpp">
+      <Filter>test</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 3 - 3
Project4/main.cpp

@@ -11,7 +11,7 @@ struct Test
 
 int main(int argc, char** argv)
 {
-
+    uint32_t temp1 = -1073626914;
     bg::ShmOptions opts(false, "Test", nullptr);
     opts.fix_vptr_on_init = false;
     if(!bg::ShmInit(opts))
@@ -26,10 +26,10 @@ int main(int argc, char** argv)
     Sleep(10000);
     return 0;
     bg::detail::SizeMap sizemap;
-    size_t temp111 = bg::detail::SizeMap::CalcAlignment(0x1F000);
+
     auto temp = sizemap.Init();
     size_t available_size;
-    bg::detail::GetAvailableMemorySize(&available_size);
+
     char path[256];
     snprintf(path, 256, "%s-mgr.mmap", "111");
     size_t real_size = 0x9000;

+ 0 - 328
Project4/page_heap.cc

@@ -1,328 +0,0 @@
-#include "page_heap.h"
-#include "shm_helper.h"
-#include "size_map.h"
-#include "shm_config.h"
-namespace bg
-{
-    namespace detail
-    {
-        PageHeap::PageHeap()
-        {
-        }
-
-        bg::detail::Span* PageHeap::GetSpanMap(size_t start_page)
-        {
-            SHM_ASSERT_RETURN_NULL(start_page <= ShmConfig::MAX_PAGE_COUNT);
-
-            auto node1 = m_span_map.lv0[PTR_TO_LV0(start_page)];
-            if(node1 == nullptr)
-            {
-                return nullptr;
-            }
-
-            auto node2 = node1->lv1[PTR_TO_LV1(start_page)];
-            if(node2 == nullptr)
-            {
-                return nullptr;
-            }
-
-            auto node3 = node2->lv2[PTR_TO_LV2(start_page)];
-            return node3;
-        }
-
-        bool PageHeap::SetSpanMap(size_t page, bg::detail::Span* span)
-        {
-            SHM_ASSERT_RETURN_FALSE(span->m_start_page <= ShmConfig::MAX_PAGE_COUNT);
-            m_span_map.lv0[PTR_TO_LV0(page)]->lv1[PTR_TO_LV1(page)]->lv2[PTR_TO_LV2(page)] = span;
-            return true;
-        }
-
-        void PageHeap::DeallocateSpan(bg::detail::Span* s)
-        {
-            bg::detail::Span* pre_span = GetSpanMap(s->m_start_page - 1);
-            if(pre_span && !pre_span->m_in_use)
-            {
-                s->m_start_page -= pre_span->m_page_count;
-                s->m_page_count += pre_span->m_page_count;
-
-
-                pre_span->RemoveNextSpan();
-
-                *(void**)pre_span = m_span_allocator.m_free_list;
-                m_span_allocator.m_free_list = pre_span;
-                SetSpanMap(s->m_start_page, s);
-            }
-
-            bg::detail::Span* next_span = GetSpanMap(s->m_start_page + s->m_page_count);
-            if(next_span && next_span->m_in_use != true)
-            {
-                s->m_page_count += next_span->m_page_count;
-
-                next_span->RemoveNextSpan();
-
-                *(void**)next_span = m_span_allocator.m_free_list;
-
-                m_span_allocator.m_free_list = next_span;
-
-                if(s->m_page_count)
-                {
-                    SetSpanMap(s->m_page_count + s->m_start_page - 1, s);
-                }
-            }
-
-            bg::detail::Span* p_list;
-            p_list = &m_large_list;
-            if(s->m_page_count <= 0x7F)
-            {
-                p_list = &m_free_lists[s->m_page_count];
-            }
-            p_list->InstertNextSpan(s);
-
-        }
-
-        void PageHeap::RegisterSpan(bg::detail::Span* span)
-        {
-            size_t start = 1ll;
-            size_t end = span->m_page_count - 1;
-            while(end > start)
-            {
-                size_t index = span->m_start_page + start;
-                SetSpanMap(index, span);
-                ++start;
-            }
-        }
-
-        bool PageHeap::GrowHeap(size_t page_count)
-        {
-            size_t real_bytes{};
-            size_t page_start{};
-            void* rawmemoey{};
-            if(page_count > ShmConfig::MAX_PAGE_COUNT)
-            {
-                return false;
-            }
-
-            if(page_count > 0x7F)
-            {
-                real_bytes = PAGES_TO_BYTES(page_count);
-                rawmemoey = bg::detail::ShmAllocateRawMemory(&real_bytes, PAGE_BYTES);
-                if(!rawmemoey)
-                {
-                    return false;
-                }
-            }
-            else
-            {
-                real_bytes = 0x100000LL;
-                rawmemoey = bg::detail::ShmAllocateRawMemory(&real_bytes, PAGE_BYTES);
-                if(!rawmemoey)
-                {
-                    real_bytes = PAGES_TO_BYTES(page_count);
-                    rawmemoey = bg::detail::ShmAllocateRawMemory(&real_bytes, PAGE_BYTES);
-                    if(!rawmemoey)
-                    {
-                        return false;
-                    }
-                }
-            }
-
-
-            if((int64_t)rawmemoey >> 48)
-            {
-                SHM_ERROR("annot allocate enough space in span map, memory(%p, %#lx) leaked.", rawmemoey, real_bytes);
-                return false;
-            }
-
-            page_start = BYTES_TO_PAGES((int64_t)rawmemoey);
-            size_t real_pages = BYTES_TO_PAGES(real_bytes);
-            size_t page_end = page_start + real_pages;
-
-            for(size_t index = page_start; index < page_end; ++index)
-            {
-                size_t lv0_index = PTR_TO_LV0(index);
-                size_t lv1_index = PTR_TO_LV1(index);
-                size_t lv2_index = PTR_TO_LV2(index);
-                if(m_span_map.lv0[lv0_index] && m_span_map.lv0[lv0_index]->lv1[lv1_index])
-                {
-                    continue;
-                }
-                else
-                {
-                    size_t node1_size = sizeof(RadixTree::NodeV1);
-                    RadixTree::NodeV1* p_node1 = (RadixTree::NodeV1*)bg::detail::ShmAllocateRawMemory(
-                        &node1_size, sizeof(RadixTree::NodeV1));
-
-                    if(!p_node1)
-                    {
-                        break;
-                    }
-                    m_span_map.lv0[lv0_index] = p_node1;
-                    new (p_node1) RadixTree::NodeV1();
-
-                }
-                size_t node2_size = sizeof(RadixTree::NodeV2);
-                RadixTree::NodeV2* p_node2 = (RadixTree::NodeV2*)bg::detail::ShmAllocateRawMemory(&node2_size, sizeof(RadixTree::NodeV2));
-                if(!p_node2)
-                {
-                    break;
-                }
-                m_span_map.lv0[lv0_index]->lv1[lv1_index] = p_node2;
-                new (p_node2) RadixTree::NodeV2();
-                m_span_map.lv0[lv0_index]->lv1[lv1_index]->lv2[lv2_index];
-            }
-
-
-            bg::detail::Span* free_span = GetNewSpan();
-            if(!free_span)
-            {
-                SHM_ERROR("cannot allocate new span, memory(%p, %#lx) leaked.", rawmemoey, real_bytes);
-                return false;
-            }
-            new (free_span) Span(page_start, page_count);
-
-            SetSpanMap(page_start, free_span);
-
-            if(real_pages > 1)
-            {
-                SetSpanMap(page_end - 1, free_span);
-            }
-            free_span->m_in_use = 1;
-            this->DeallocateSpan(free_span);
-            return true;
-        }
-
-        bg::detail::Span* PageHeap::AllocateSpan(size_t page_count)
-        {
-            auto span = GetLastSpan(page_count);
-            if(!span)
-            {
-                if(!GrowHeap(page_count) || !(span = GetLastSpan(page_count)))
-                {
-                    SHM_ERROR("cannot allocate span, page count: %lu.", page_count);
-                    return nullptr;
-                }
-
-            }
-            span->m_prev->RemoveNextSpan();
-
-            do
-            {
-                int64_t diff = page_count - span->m_page_count;
-                if(diff == 0)
-                {
-                    break;
-                }
-
-                Span* free_list = GetNewSpan();
-                if(!free_list)
-                {
-                    break;
-                }
-                size_t start_page = span->m_start_page + page_count;
-                new (free_list) Span(start_page, diff);
-                SetSpanMap(start_page, free_list);
-
-                Span* list;
-                if(diff <= 1 || SetSpanMap(start_page + diff - 1, free_list), list = &m_large_list, diff <= 0x7f)
-                {
-                    list = &m_free_lists[diff];
-                }
-
-                list->InstertNextSpan(free_list);
-
-                span->m_page_count = page_count;
-                if(page_count)
-                {
-                    SetSpanMap(page_count + span->m_start_page - 1, free_list);
-                }
-            } while(false);
-
-            span->m_in_use = 1;
-            return span;
-        }
-
-        bg::detail::Span* PageHeap::GetNewSpan()
-        {
-            bg::detail::Span* free_span = (bg::detail::Span*)m_span_allocator.m_free_list;
-            if(free_span)
-            {
-                m_span_allocator.m_free_list = (void*)&free_span->m_in_use;
-                return free_span;
-            }
-            size_t free_left = this->m_span_allocator.m_free_left;
-            if(free_left <= 0x37)
-            {
-                size_t spans_bytes = FREE_AREA_SIZE;
-                bg::detail::Span* spans = (bg::detail::Span*)bg::detail::ShmAllocateRawMemory(&spans_bytes, PAGE_BYTES);
-
-                if(spans)
-                {
-                    free_span = spans;
-                    this->m_span_allocator.m_free_area = (char*)&spans[1];
-                    this->m_span_allocator.m_free_left = spans_bytes - sizeof(bg::detail::Span);
-                    return free_span;
-                }
-            }
-            else
-            {
-                free_span = (bg::detail::Span*)this->m_span_allocator.m_free_area;
-                this->m_span_allocator.m_free_left -= sizeof(bg::detail::Span);
-                this->m_span_allocator.m_free_area += sizeof(bg::detail::Span);
-                if(free_span)
-                {
-                    return free_span;
-                }
-            }
-
-            return nullptr;
-        }
-
-        bg::detail::Span* PageHeap::GetLastSpan(size_t page_count)
-        {
-            if(page_count <= 0x7f)
-            {
-                Span* next_span = &m_free_lists[page_count];
-                Span* free_span = next_span->m_next;
-                if(next_span == next_span->m_next)
-                {
-                    for(&m_free_lists[page_count + 1]; next_span != &m_large_list; ++next_span)
-                    {
-                        if(next_span->m_next != next_span)
-                        {
-                            free_span = next_span->m_next;
-                            break;
-                        }
-                    }
-                }
-                if(free_span != free_span->m_next)
-                {
-                    return free_span;
-                }
-            }
-
-            if(m_large_list.m_next != &m_large_list)
-            {
-                Span* next_span = m_large_list.m_next;
-                Span* free_span = nullptr;
-
-                for(; &m_large_list == next_span; next_span = next_span->m_next)
-                {
-                    if(page_count > next_span->m_page_count)
-                    {
-                        continue;
-                    }
-                    if(!free_span || next_span->m_page_count < free_span->m_page_count ||
-                       (next_span->m_page_count == free_span->m_page_count && next_span->m_start_page < free_span->m_start_page))
-                    {
-                        free_span = next_span;
-                    }
-
-                }
-                return free_span;
-            }
-            return nullptr;
-        }
-    }
-
-
-}

+ 0 - 98
Project4/page_heap.h

@@ -1,98 +0,0 @@
-#pragma once
-
-#define PTR_TO_LV0(ptr)	(ptr) >> 25
-#define PTR_TO_LV1(ptr)	((ptr) >> 15 & 0x3FF)
-#define PTR_TO_LV2(ptr)	((ptr) & 0x7FFF)
-namespace bg
-{
-    namespace detail
-    {
-        struct Span
-        {
-            Span() = default;
-            Span(size_t start_page, size_t page_count) : m_start_page(start_page), m_page_count(page_count) {}
-
-            void RemoveNextSpan()
-            {
-                auto next_span = m_next;
-
-                m_next = next_span->m_next;
-                next_span->m_next->m_prev = next_span->m_prev;
-
-                next_span->m_prev = nullptr;
-                next_span->m_next = nullptr;
-            }
-
-            void InstertNextSpan(Span* span)
-            {
-                span->m_prev = m_next->m_prev;
-                span->m_next = m_next;
-                m_next->m_prev = span;
-                m_next = span;
-            }
-
-            bool m_in_use{};
-            unsigned char m_size_class{255};
-            size_t m_used_count{};
-            size_t m_start_page{};
-            size_t m_page_count{};
-
-            Span* m_prev{this};
-            Span* m_next{this};
-            void* m_chunk_list{};
-
-        };
-
-        template<size_t size0, size_t size1, size_t size2>
-        struct RadixTree
-        {
-            struct  NodeV2
-            {
-                Span* lv2[1 << size2]{0};
-            };
-            struct NodeV1
-            {
-                NodeV2* lv1[1 << size1]{0};
-            };
-
-            NodeV1* lv0[1 << size0]{0};
-        };
-
-        template<typename T>
-        struct MetadataAllocator
-        {
-            void* m_free_list{};
-            char* m_free_area{};
-            size_t m_free_left{};
-        };
-
-
-        class PageHeap
-        {
-        public:
-            PageHeap();
-
-            bg::detail::Span* GetSpanMap(size_t start_page);
-
-            bool SetSpanMap(size_t page, bg::detail::Span* span);
-
-            void DeallocateSpan(bg::detail::Span* s);
-
-            void RegisterSpan(bg::detail::Span* s);
-
-            bool GrowHeap(size_t page_count);
-
-            bg::detail::Span* AllocateSpan(size_t page_count);
-
-            bg::detail::Span* GetNewSpan();
-
-            bg::detail::Span* GetLastSpan(size_t page_count);
-
-            using  RadixTree = RadixTree<10ul, 10ul, 15ul>;
-            RadixTree m_span_map;
-            MetadataAllocator<bg::detail::Span> m_span_allocator;
-            Span m_free_lists[128]{};
-            Span m_large_list{};
-        };
-    }
-}

+ 0 - 32
Project4/shm_config.h

@@ -1,32 +0,0 @@
-#pragma once
-#define BIG_CALIGNMENT 15488
-#define SMALL_CALIGNMENT 8			
-#define SMALL_BYTES_TO_INDEX(bytes) ((bytes + 7) >> 3)        // 小字节获取class index
-#define BIG_BYTES_TO_INDEX(bytes) ((bytes + (BIG_CALIGNMENT - 1)) >> 7)      // 大字节获取class index
-#define PAGE_BYTES 0x2000LL                         // 一页字节
-#define BYTES_COMP_VALUE 0x400                                // 大小字节数
-#define CLASS_TOTAL_BYTES 65536                               
-#define CLASS_MAX_BYTES 0x40000                               // class 最大字节数
-#define MAX_CLASSS  32										  
-#define CLASS_MAX_COUNT 87									  // 总共类数量
-#define PAGE_RIGHT_BIT 13								  // 总共类数量
-#define FREE_AREA_SIZE 0x20000LL                                
-
-#define BYTES_TO_PAGES(bytes)    ((bytes) >> 13)
-#define PAGES_TO_BYTES(page)    ((page) << 13)
-
-#define PALIGN_DOWN(x, align) ((x) & ~((align) - 1))
-#define PALIGN_UP(x, align) (((x) + ((align) - 1)) & (~((align) - 1)))
-
-namespace bg
-{
-    namespace detail
-    {
-        namespace ShmConfig
-        {
-            constexpr size_t MAX_PAGE_COUNT = 0x7FFFFFFFFLL;
-        }
-    }
-
-
-}

+ 0 - 91
Project4/shm_helper.cc

@@ -1,91 +0,0 @@
-#include "vptr_manager.h"
-#include "shm_manager.h"
-#include <stdarg.h>
-extern bg::detail::ShmContext g_shm_ctx;
-
-bg::detail::TypeName::TypeName(const char* type, size_t size /*= 0*/)
-{
-	if(size)
-	{
-		snprintf(m_type, MAX_TYPE_NAME_LENGTH, "%s[%#zux]", type, size);
-	}
-	else
-	{
-		snprintf(m_type, MAX_TYPE_NAME_LENGTH, "%s", type);
-	}
-}
-
-void bg::detail::ShmLog(ShmLogLevel level, const char* file, size_t line, const char* func, const char* fmt, ...)
-{
-	va_list args; // [rsp+8h] [rbp-E8h] BYREF
-	static char buf[0x2000uLL];
-	va_start(args, fmt);
-	vsnprintf(buf, 0x2000uLL, fmt, args);
-	va_end(args);
-	g_shm_ctx.logger(level, file, line, func, buf);
-}
-
-void bg::detail::ShmStdoutLog(ShmLogLevel level, const char* file, size_t line, const char* func, const char* msg)
-{
-	static const char* levels[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
-	printf(
-	"[%s:%zu(%s)][%s] %s\n",
-	file,
-	line,
-	func,
-	levels[level],
-	msg);
-}
-
-void* bg::detail::ShmAllocate(size_t bytes, const void* ptr)
-{
-	return (void*)bg::ShmMalloc(bytes);
-}
-
-void bg::detail::ShmDeallocate(void* ptr, size_t size)
-{
-	bg::ShmFree(ptr);
-}
-
-uint64_t bg::detail::ShmCurrentVersion()
-{
-	return 0ll;
-}
-
-void* bg::detail::ShmAllocateRawMemory(size_t* bytes, size_t alignment)
-{
-	if(g_shm_ctx.mgr)
-	{
-		return g_shm_ctx.mgr->AllocateRawMemory(bytes, alignment);
-	}
-
-
-	return nullptr;
-}
-
-bool bg::detail::ShmHasSingleton(const TypeName& type)
-{
-	if(g_shm_ctx.mgr)
-	{
-		return g_shm_ctx.mgr->HasSingleton(type);
-	}
-	return false;
-}
-
-void* bg::detail::ShmGetSingleton(const TypeName& type, size_t bytes, bool* first_call)
-{
-	if(g_shm_ctx.mgr)
-	{
-		return g_shm_ctx.mgr->GetSingleton(type, bytes, first_call);
-	}
-	return nullptr;
-}
-
-void bg::detail::ShmFreeSingleton(const TypeName& type)
-{
-	if(g_shm_ctx.mgr)
-	{
-		return g_shm_ctx.mgr->FreeSingleton(type);
-	}
-	return;
-}

+ 0 - 1385
Project4/shm_manager.cc

@@ -1,1385 +0,0 @@
-#include "shm_manager.h"
-#include "shm_object.h"
-#include "shm_config.h"
-
-extern bg::detail::ShmContext g_shm_ctx;
-namespace bg
-{
-    namespace detail
-    {
-
-        ShmManager::ShmManager(const bg::ShmOptions& options) : m_options(options)
-        {
-            snprintf(this->m_magic, 0x40uLL, "ByteGame/ShmManager-%s", this->m_options.identifier);
-        }
-
-        ShmManager::~ShmManager()
-        {
-            if(m_singletons)
-            {
-                m_singletons->clear();
-                bg::ShmFree(m_singletons);
-                this->m_singletons = nullptr;
-            }
-            for(size_t i = 0LL; this->m_block_count > i; ++i)
-            {
-                DeleteBlock(i);
-            }
-        }
-
-        void* ShmManager::AllocateRawMemory(size_t* bytes, size_t alignment)
-        {
-            void* result = nullptr;
-            if((alignment & (alignment - 1)) != 0)
-            {
-                SHM_ERROR("invalid alignment(%#lx).", (const char*)alignment);
-                return result;
-            }
-            *bytes = PALIGN_UP(*bytes, alignment);
-
-            if(m_block_count)
-            {
-                result = AllocateInBlock(m_block_count - 1, *bytes, alignment);
-                if(result)
-                {
-                    return result;
-                }
-
-            }
-            if(CreateBlock(m_block_count, *bytes))
-            {
-                size_t index = m_block_count > 1 ? m_block_count - 1 : 0;
-                result = AllocateInBlock(index, *bytes, alignment);
-                if(!result)
-                {
-                    SHM_ERROR("newly created block(%lu) still cannot satisfy requirement, addr(%#lx), used size(%#lx), real size(%#lx), real bytes(%#lx), alignment(%#lx).",
-                    m_block_count, m_blocks[index].addr, m_blocks[index].used_size, m_blocks[index].real_size);
-                    return result;
-                }
-
-            }
-            else
-            {
-                SHM_ERROR("failed to create block(%lu), real bytes(%#lx).", this->m_block_count, *bytes);
-            }
-            return result;
-        }
-
-        bool ShmManager::HasSingleton(const bg::detail::TypeName& type)
-        {
-            auto itor = m_singletons->find(type);
-            if(itor == m_singletons->end())
-            {
-                return false;
-            }
-            return true;
-        }
-
-        void* ShmManager::GetSingleton(const bg::detail::TypeName& type, size_t bytes, bool* first_call)
-        {
-            if(!m_singletons)
-            {
-                m_singletons = (bg::detail::ShmManager::SingletonMap*)bg::ShmMalloc(sizeof(bg::detail::ShmManager::SingletonMap));
-                if(!m_singletons)
-                {
-                    m_singletons = nullptr;
-                    return nullptr;
-                }
-
-                new(m_singletons) SingletonMap;
-            }
-
-            auto itor = m_singletons->find(type);
-            if(itor != m_singletons->end())
-            {
-                return itor->second;
-            }
-
-            uint8_t index{};
-            if(bytes <= BYTES_COMP_VALUE)
-            {
-                index = m_size_map.m_index_to_class[SMALL_BYTES_TO_INDEX(bytes)];
-            }
-            else
-            {
-                if(bytes > CLASS_MAX_BYTES)
-                {
-                    bg::detail::Span* span = m_page_heap.AllocateSpan(BYTES_TO_PAGES(bytes + PAGE_BYTES));
-                    if(span)
-                    {
-                        void* chunk_span = (void*)PAGES_TO_BYTES(span->m_start_page);
-                        if(chunk_span)
-                        {
-                            m_singletons->operator[](type) = chunk_span;
-                            if(first_call)
-                            {
-                                *first_call = 1;
-                                SHM_INFO("singleton(%s: %p) created.", type.c_str(), chunk_span);
-                            }
-                            return chunk_span;
-                        }
-                    }
-                    return nullptr;
-                }
-                index = m_size_map.m_index_to_class[BIG_BYTES_TO_INDEX(bytes)];
-            }
-
-            if(index > CLASS_MAX_COUNT)
-            {
-                return nullptr;
-            }
-
-            ChunkCache::ClassCache* cheche = &this->m_chunk_cache.m_caches[index];
-            size_t size = this->m_size_map.ClassToSize(index);
-            if(cheche == (bg::detail::ChunkCache::ClassCache*)cheche->free_list.m_next)
-            {
-                bg::detail::Span* span = m_page_heap.AllocateSpan(m_size_map.m_class_to_pages[index]);
-                if(span)
-                {
-                    m_page_heap.RegisterSpan(span);
-                    span->m_size_class = index;
-
-                    span->m_chunk_list = (void*)PAGES_TO_BYTES(span->m_start_page);
-
-                    uintptr_t end_memory = (uintptr_t)PAGES_TO_BYTES(span->m_start_page + span->m_page_count);
-
-                    uintptr_t end_ptr = (uintptr_t)span->m_chunk_list + size;
-
-                    uintptr_t ptr = (uintptr_t)span->m_chunk_list;
-
-                    for(; end_ptr < end_memory; )
-                    {
-                        *((uintptr_t*)ptr) = end_ptr;
-                        auto temp = end_ptr + size;
-                        if(temp > end_memory)
-                        {
-                            break;
-                        }
-                        ptr = end_ptr;
-                        end_ptr = temp;
-                    }
-
-                    *(uintptr_t*)ptr = 0ll;
-                    cheche->free_list.InstertNextSpan(span);
-                    ++cheche->span_count;
-
-                }
-
-            }
-
-            if(cheche == (bg::detail::ChunkCache::ClassCache*)cheche->free_list.m_next)
-            {
-                return nullptr;
-            }
-
-            auto next_span = cheche->free_list.m_next;
-            ++next_span->m_used_count;
-            auto chunk_span = next_span->m_chunk_list;
-            next_span->m_chunk_list = *(void**)chunk_span;
-            if(*(void**)chunk_span == nullptr)
-            {
-                cheche->free_list.RemoveNextSpan();
-                --this->m_chunk_cache.m_caches[index].span_count;
-            }
-
-            m_singletons->operator[](type) = chunk_span;
-            if(first_call)
-            {
-                *first_call = 1;
-                SHM_INFO("singleton(%s: %p) created.", type.c_str(), chunk_span);
-            }
-            return chunk_span;
-        }
-
-        void ShmManager::FreeSingleton(const bg::detail::TypeName& type)
-        {
-            if(m_singletons)
-            {
-                auto itor = m_singletons->find(type);
-                if(itor == m_singletons->end())
-                {
-                    return;
-                }
-                SHM_INFO("singleton(%s: %p) destroyed.", type.c_str());
-
-                bg::detail::Span* span = m_page_heap.GetSpanMap(BYTES_TO_PAGES((uintptr_t)itor->second));
-                if(span)
-                {
-                    do
-                    {
-
-                        if(span->m_size_class == 0xff)
-                        {
-                            m_page_heap.DeallocateSpan(span);
-                        }
-                        else
-                        {
-                            if(span->m_used_count && span->m_size_class <= CLASS_MAX_COUNT)
-                            {
-                                span->m_used_count -= 1;
-                                auto chunk_list = span->m_chunk_list;
-                                *(uintptr_t*)itor->second = (uintptr_t)span->m_chunk_list;
-                                span->m_chunk_list = itor->second;
-
-                                if(chunk_list)
-                                {
-                                    if(span->m_used_count == 0)
-                                    {
-                                        if(m_chunk_cache.m_caches[span->m_size_class].span_count > 1)
-                                        {
-                                            span->m_prev->RemoveNextSpan();
-                                            span->m_in_use = false;
-                                            span->m_used_count = 0LL;
-                                            span->m_size_class = -1;
-                                            span->m_chunk_list = 0LL;
-                                            m_page_heap.DeallocateSpan(span);
-                                        }
-                                    }
-                                }
-                                else
-                                {
-                                    if(span->m_used_count == 0)
-                                    {
-                                        if(m_chunk_cache.m_caches[span->m_size_class].span_count)
-                                        {
-                                            span->m_used_count = 0LL;
-                                            span->m_size_class = -1;
-                                            span->m_chunk_list = 0LL;
-                                            m_page_heap.DeallocateSpan(span);
-                                            break;
-                                        }
-
-                                    }
-                                    m_chunk_cache.m_caches[span->m_size_class].free_list.m_next->InstertNextSpan(span);
-                                    m_chunk_cache.m_caches[span->m_size_class].span_count++;
-                                }
-                            }
-
-                        }
-                    } while(false);
-                }
-                m_singletons->erase(itor);
-
-            }
-
-            return;
-
-        }
-
-        bool ShmManager::OnResume(const char* identifier)
-        {
-            char magic[64]; // [rsp+0h] [rbp-60h] BYREF
-
-            int size = snprintf(magic, 0x40uLL, "ByteGame/ShmManager-%s", identifier);
-            if(!strncmp(magic, this->m_magic, size))
-            {
-                size_t index = 0;
-                for(; index < m_block_count; ++index)
-                {
-                    if(!AttachBlock(index))
-                    {
-                        SHM_ERROR("failed to attach block(%lu), address(%#lx), used size(%#lx), real size(%#lx), mmap size(%#lx).", index, m_blocks[index].addr, m_blocks[index].used_size, m_blocks[index].real_size, m_blocks[index].mmap_size);
-                        return false;
-                    }
-
-                }
-                if(m_block_count <= index)
-                {
-                    m_version++;
-                    return true;
-                }
-            }
-
-            SHM_ERROR("magic mismatch, expected: %s, actual: %s.", magic, this->m_magic);
-            return false;
-        }
-
-        bool ShmManager::OnCreate(void)
-        {
-            return m_size_map.Init();
-        }
-
-        bool ShmManager::DeleteBlock(size_t index)
-        {
-            SHM_ASSERT_RETURN_FALSE(index > m_block_count);
-            char path[256];
-            if(m_blocks[index].addr)
-            {
-                m_options.AddFixedAddress((uintptr_t)m_blocks[index].addr);
-                snprintf(path, 0x100uLL, "%s-%03zu.mmap", this->m_options.identifier, index);
-                bg::detail::ShmObjectDelete(m_blocks[index].addr, m_blocks[index].mmap_size, path);
-                SHM_INFO("block(%lu) deleted, address(%#lx), used size(%#lx), real size(%#lx), mmap size(%#lx), path(%s).",
-                         index, m_blocks[index].addr, m_blocks[index].used_size, m_blocks[index].real_size, m_blocks[index].mmap_size, path);
-
-                new (m_blocks[index].addr) ShmBlock();
-            }
-
-
-            return true;
-        }
-
-        void* ShmManager::AllocateInBlock(size_t index, size_t bytes, size_t alignment)
-        {
-            size_t v7; // r8
-            char* v8; // r12
-            __int64 v9; // rdx
-            __int64 v10; // rax
-            __int64 v11; // rbx
-            size_t v12; // rcx
-            size_t mmap_size; // rsi
-            size_t real_size; // rdi
-            size_t shm_block_grow_size; // r10
-            const char* v16; // r15
-            const char* v17; // rcx
-            size_t v18; // rdx
-            size_t v20; // [rsp+0h] [rbp-40h]
-            char* v21; // [rsp+8h] [rbp-38h]
-
-            if(this->m_block_count <= index)
-            {
-
-                return 0LL;
-            }
-            else
-            {
-                v7 = 0LL;
-                v8 = (char*)this + 32 * index;
-                v9 = *((uintptr_t*)v8 + 3113);
-                v10 = *((uintptr_t*)v8 + 3114);
-                v11 = v10 + v9;
-                if(((v10 + v9) & (alignment - 1)) != 0)
-                {
-                    v7 = alignment - ((v10 + v9) & (alignment - 1));
-                    v11 += v7;
-                }
-                v12 = v11 + bytes;
-                mmap_size = this->m_blocks[index].mmap_size;
-                if(v11 + bytes > mmap_size + v9)
-                {
-                    return 0LL;
-                }
-                else
-                {
-                    real_size = this->m_blocks[index].real_size;
-                    if(v12 <= real_size + v9)
-                    {
-LABEL_13:
-                        *((uintptr_t*)v8 + 3114) = v7 + bytes + v10;
-                        return (void*)v11;
-                    }
-                    shm_block_grow_size = this->m_options.shm_block_grow_size;
-                    v16 = (const char*)(shm_block_grow_size + real_size);
-                    if(v12 > shm_block_grow_size + real_size + v9)
-                    {
-                        v17 = (const char*)(v12 - v9);
-                        v16 = v17;
-                        //v18 = (uintptr_t)&v17[-real_size] % shm_block_grow_size;
-                        v18 = 0;
-                        if(v18)
-                            v16 = &v17[shm_block_grow_size - v18];
-                    }
-                    v21 = (char*)index;
-                    if((unsigned __int64)v16 > mmap_size)
-                        v16 = (const char*)mmap_size;
-                    v20 = v7;
-                    if(ResizeBlock(index, v16))
-                    {
-                        v10 = *((uintptr_t*)v8 + 3114);
-                        v7 = v20;
-                        goto LABEL_13;
-                    }
-
-                    return nullptr;
-                }
-            }
-        }
-
-        bool ShmManager::CreateBlock(size_t index, size_t min_size)
-        {
-            size_t shm_block_grow_size; // rcx
-            size_t shm_block_mmap_size; // rax
-            __int64 v8; // rax
-            uintptr_t fixed_addr; // [rsp+8h] [rbp-138h] BYREF
-            size_t real_size; // [rsp+10h] [rbp-130h] BYREF
-            size_t mmap_size; // [rsp+18h] [rbp-128h] BYREF
-            char path[256]; // [rsp+20h] [rbp-120h] BYREF
-
-            if(index > 0xFF)
-            {
-                return 0LL;
-            }
-            else
-            {
-                shm_block_grow_size = this->m_options.shm_block_grow_size;
-                shm_block_mmap_size = this->m_options.shm_block_mmap_size;
-                fixed_addr = 0LL;
-                real_size = shm_block_grow_size;
-                mmap_size = shm_block_mmap_size;
-                if(shm_block_grow_size < min_size)
-                    real_size = min_size;
-                if(shm_block_mmap_size < min_size)
-                    mmap_size = min_size;
-                m_options.PopFixedAddress(&fixed_addr);
-
-                snprintf(path, 0x100uLL, "%s-%03zu.mmap", this->m_options.identifier, index);
-                v8 = (uintptr_t)bg::detail::ShmObjectCreate(path, fixed_addr, &real_size, &mmap_size);
-                if(!v8)
-                {
-
-                    if(fixed_addr)
-                        m_options.AddFixedAddress(fixed_addr);
-                    return false;
-                }
-                m_blocks[index].addr = (void*)v8;
-                m_blocks[index].real_size = real_size;
-                m_blocks[index].mmap_size = mmap_size;
-                m_blocks[index].used_size = 0;
-
-                if(this->m_block_count != index)
-                    return true;
-                this->m_block_count = index + 1;
-            }
-            return true;
-        }
-
-        bool ShmManager::AttachBlock(size_t index)
-        {
-            __int64 result; // rax
-            char* v3; // rbx
-            size_t v4; // rax
-            __int64 v6; // rdx
-            size_t real_size; // [rsp+0h] [rbp-130h] BYREF
-            size_t mmap_size; // [rsp+8h] [rbp-128h] BYREF
-            char path[256]; // [rsp+10h] [rbp-120h] BYREF
-
-            if(this->m_block_count <= index)
-            {
-                return 0LL;
-            }
-            else
-            {
-                result = 1LL;
-                v3 = (char*)this + 32 * index;
-                if(*((uintptr_t*)v3 + 3113))
-                {
-                    v4 = *((uintptr_t*)v3 + 3116);
-                    real_size = 0LL;
-                    mmap_size = v4;
-                    snprintf(path, 0x100uLL, "%s-%03zu.mmap", this->m_options.identifier, index);
-                    v6 = (uintptr_t)bg::detail::ShmObjectAttach(path, (uintptr_t) * ((const char**)v3 + 3113), &real_size, &mmap_size);
-                    result = 0LL;
-                    if(v6)
-                    {
-                        return 1LL;
-                    }
-                }
-            }
-            return result;
-        }
-
-        bool ShmManager::ResizeBlock(size_t index, size_t new_size)
-        {
-            bool v3; // cc
-            unsigned int v5; // r13d
-            size_t new_sizea; // [rsp+8h] [rbp-128h] BYREF
-            char path[256]; // [rsp+10h] [rbp-120h] BYREF
-
-            SHM_ASSERT_RETURN_FALSE(index < m_block_count);
-
-            if(m_blocks[index].mmap_size < new_size)
-            {
-                SHM_ERROR("new size(%#lx) too large, block(%lu), mmap size(%#lx).", new_size, index, m_blocks[index].mmap_size);
-                return false;
-            }
-            else
-            {
-                snprintf(path, 0x100uLL, "%s-%03zu.mmap", this->m_options.identifier, index);
-                if(bg::detail::ShmObjectResize(path, &new_size))
-                {
-                    SHM_INFO("block(%lu) resized, old size(%#lx), new size(%#lx), used size(%#lx), mmap size(%#lx).",
-                             index, m_blocks[index].addr, m_blocks[index].real_size, new_size, m_blocks[index].used_size, m_blocks[index].mmap_size);
-                    this->m_blocks[index].real_size = new_sizea;
-                    return true;
-                }
-
-            }
-            return false;
-        }
-
-    }
-
-    void* ShmMalloc(size_t bytes)
-    {
-        int64_t v6; // rbx
-        uint8_t index; // r15
-
-        __int64 v9; // r14
-        __int64 v10; // r13
-        bg::detail::Span* v11; // r12
-        bg::detail::Span* m_next; // r8
-        void** result; // rax
-        bool v14; // zf
-        bg::detail::Span* Span; // rax
-        bg::detail::PageHeap* v16; // rdi
-        bg::detail::Span* v17; // rax
-        size_t m_start_page; // rcx
-        size_t m_page_count; // rdi
-        void** p_m_chunk_list; // rax
-        void** v21; // rcx
-        void** v22; // rdx
-        void** v23; // rdi
-        void** v24; // rsi
-        __int64 v25; // rax
-        bg::detail::Span* v26; // rcx
-        bg::detail::Span* m_prev; // rdx
-        bg::detail::Span* v28; // [rsp+0h] [rbp-40h]
-        bg::detail::PageHeap* v29; // [rsp+8h] [rbp-38h]
-
-        v6 = (int64_t)g_shm_ctx.mgr;
-        if(!v6)
-        {
-
-            return nullptr;
-        }
-        if(bytes <= BYTES_COMP_VALUE)
-        {
-            index = g_shm_ctx.mgr->m_size_map.m_index_to_class[SMALL_BYTES_TO_INDEX(bytes)];
-        }
-        else
-        {
-            if(bytes > CLASS_MAX_BYTES)
-            {
-                Span = g_shm_ctx.mgr->m_page_heap.AllocateSpan(BYTES_TO_PAGES(bytes + 0x1FFF));
-                if(Span)
-                {
-                    return (void**)(*(uintptr_t*)(Span + 16) << 13);
-                }
-                return nullptr;
-            }
-            auto temp1 = BIG_BYTES_TO_INDEX(bytes);
-            index = g_shm_ctx.mgr->m_size_map.m_index_to_class[BIG_BYTES_TO_INDEX(bytes)];
-        }
-        if(index > CLASS_MAX_COUNT)
-        {
-            v9 = g_shm_ctx.mgr->m_size_map.m_class_to_size[index];
-            v10 = index;
-            v11 = &g_shm_ctx.mgr->m_chunk_cache.m_caches[index].free_list;
-            if(v11 != v11->m_next)
-                goto LABEL_7;
-            v29 = &g_shm_ctx.mgr->m_page_heap;
-
-
-            v16 = &g_shm_ctx.mgr->m_page_heap;
-            goto LABEL_18;
-        }
-
-        v9 = g_shm_ctx.mgr->m_size_map.m_class_to_size[index];
-        v10 = index;
-
-        v11 = &g_shm_ctx.mgr->m_chunk_cache.m_caches[index].free_list;
-        if(v11 == v11->m_next)
-        {
-            v29 = &g_shm_ctx.mgr->m_page_heap;
-            v16 = &g_shm_ctx.mgr->m_page_heap;
-LABEL_18:
-            v17 = v16->AllocateSpan(g_shm_ctx.mgr->m_size_map.m_class_to_pages[index]);
-            if(v17)
-            {
-                v28 = v17;
-                v29->RegisterSpan(v17);
-                m_next = v28;
-                m_start_page = v28->m_start_page;
-                m_page_count = v28->m_page_count;
-                p_m_chunk_list = &v28->m_chunk_list;
-                v28->m_size_class = index;
-                v21 = (void**)(m_start_page << 13);
-                v22 = (void**)((char*)v21 + v9);
-                v23 = &v21[1024 * m_page_count];
-                if((void**)((char*)v21 + v9) <= v23)
-                {
-                    while(1)
-                    {
-                        v24 = v22;
-                        v22 = (void**)((char*)v22 + v9);
-                        *p_m_chunk_list = v21;
-                        p_m_chunk_list = v21;
-                        if(v23 < v22)
-                            break;
-                        v21 = v24;
-                    }
-                }
-                else
-                {
-                    v21 = &v28->m_chunk_list;
-                }
-                *v21 = 0LL;
-                v25 = v6 + (v10 << 6);
-                v26 = *(bg::detail::Span**)(v25 + 40);
-                v28->m_prev = v11;
-                v28->m_next = v26;
-                *(uintptr_t*)(*(uintptr_t*)(v25 + 40) + 32LL) = (uintptr_t)v28;
-                *(uintptr_t*)(v25 + 40) = (uintptr_t)v28;
-                ++* (uintptr_t*)(v25 + 56);
-                goto LABEL_8;
-            }
-            return 0LL;
-        }
-LABEL_7:
-        m_next = v11->m_next;
-LABEL_8:
-        result = (void**)m_next->m_chunk_list;
-        ++m_next->m_used_count;
-        v14 = *result == 0LL;
-        m_next->m_chunk_list = *result;
-        if(v14)
-        {
-            m_prev = m_next->m_prev;
-            m_prev->m_next = m_next->m_next;
-            m_next->m_next->m_prev = m_prev;
-            m_next->m_prev = 0LL;
-            m_next->m_next = 0LL;
-            --* (uintptr_t*)(v6 + (v10 << 6) + 56);
-        }
-        return result;
-    }
-
-    void ShmFree(void* ptr)
-    {
-        __int64 v6; // rcx
-        __int64 v7; // rsi
-        __int64 v8; // rax
-        bg::detail::Span* v9; // rsi
-        __int64 m_size_class; // rax
-        size_t m_used_count; // rdx
-        void* m_chunk_list; // r9
-        size_t v13; // rdx
-        bool v14; // dl
-        __int64 v15; // rax
-        bg::detail::Span* m_prev; // rdx
-        __int64 v17; // rax
-        bg::detail::Span* v18; // rdi
-        bg::detail::Span* v19; // rcx
-
-        v6 = (int64_t)g_shm_ctx.mgr;
-        if(!v6)
-        {
-            return;
-        }
-        if(ptr)
-        {
-            if((uintptr_t)ptr >> 13 > 0x7FFFFFFFFLL)
-            {
-
-            }
-            else
-            {
-                v7 = *(uintptr_t*)(v6 + 8 * ((uintptr_t)ptr >> 38) + 9136);
-                if(v7)
-                {
-                    v8 = *(uintptr_t*)(v7 + 8 * (((uintptr_t)ptr >> 28) & 0x3FF));
-                    if(v8)
-                    {
-                        v9 = *(bg::detail::Span**)(v8 + 8 * (((uintptr_t)ptr >> 13) & 0x7FFF));
-                        if(v9)
-                        {
-                            m_size_class = v9->m_size_class;
-                            if((char)m_size_class == 0xFF)
-                            {
-                                ((bg::detail::PageHeap*)(v6 + 9136))->DeallocateSpan(v9);
-                            }
-                            else
-                            {
-                                m_used_count = v9->m_used_count;
-                                if(m_used_count && (unsigned __int8)m_size_class <= 0x56u)
-                                {
-                                    m_chunk_list = v9->m_chunk_list;
-                                    v13 = m_used_count - 1;
-                                    *(uintptr_t*)ptr = (uintptr_t)m_chunk_list;
-                                    v9->m_used_count = v13;
-                                    v14 = v13 == 0;
-                                    v9->m_chunk_list = (void*)ptr;
-                                    if(m_chunk_list)
-                                    {
-                                        if(v14)
-                                        {
-                                            v15 = v6 + (m_size_class << 6) + 48;
-                                            if(*(uintptr_t*)(v15 + 8) > 1uLL)
-                                            {
-                                                m_prev = v9->m_prev;
-                                                m_prev->m_next = v9->m_next;
-                                                v9->m_next->m_prev = m_prev;
-                                                v9->m_prev = 0LL;
-                                                v9->m_next = 0LL;
-                                                --* (uintptr_t*)(v15 + 8);
-LABEL_14:
-                                                v9->m_used_count = 0LL;
-                                                v9->m_size_class = -1;
-                                                v9->m_chunk_list = 0LL;
-                                                ((bg::detail::PageHeap*)(v6 + 9136))->DeallocateSpan(v9);
-                                                return;
-                                            }
-                                        }
-                                    }
-                                    else
-                                    {
-                                        v17 = v6 + (m_size_class << 6);
-                                        if(v14)
-                                        {
-                                            if(*(uintptr_t*)(v17 + 56))
-                                                goto LABEL_14;
-                                            v18 = *(bg::detail::Span**)(v17 + 40);
-                                            v9->m_prev = (bg::detail::Span*)v17;
-                                            v9->m_next = v18;
-                                            *(uintptr_t*)(*(uintptr_t*)(v17 + 40) + 32LL) = (uintptr_t)v9;
-                                            *(uintptr_t*)(v17 + 40) = (uintptr_t)v9;
-                                            ++* (uintptr_t*)(v17 + 56);
-                                        }
-                                        else
-                                        {
-                                            v19 = *(bg::detail::Span**)(v17 + 40);
-                                            v9->m_prev = (bg::detail::Span*)v17;
-                                            v9->m_next = v19;
-                                            *(uintptr_t*)(*(uintptr_t*)(v17 + 40) + 32LL) = (uintptr_t)v9;
-                                            ++* (uintptr_t*)(v17 + 56);
-                                            *(uintptr_t*)(v17 + 40) = (uintptr_t)v9;
-                                        }
-                                    }
-                                }
-                                else
-                                {
-
-                                }
-                            }
-                            return;
-                        }
-                    }
-                }
-            }
-
-        }
-    }
-
-    void* ShmRealloc(void* old_ptr, size_t new_bytes)
-    {
-        __int64 v6; // r14
-        unsigned __int64 v9; // r15
-        unsigned __int64 v10; // r10
-        __int64 v11; // r11
-        __int64 v12; // rax
-        __int64 v13; // rax
-        __int64 v14; // rax
-        __int64 v15; // rbx
-        size_t v16; // rbx
-        size_t v17; // rdx
-        void** result; // rax
-        bg::detail::Span* v19; // rax
-        bg::detail::Span* v20; // rax
-        void** m_chunk_list; // rdi
-        void* v22; // rdx
-        size_t v23; // rdx
-        __int64 v24; // rax
-        __int64 v25; // rax
-        bg::detail::Span* v26; // rsi
-        uint8_t m_size_class; // al
-        size_t m_used_count; // rcx
-        __int64 v29; // rdx
-        void* v30; // rax
-        size_t v31; // rcx
-        bg::detail::PageHeap* v32; // rdi
-        bool v33; // cl
-        __int64 v34; // rdx
-        bg::detail::Span* v35; // rcx
-        bg::detail::Span* v36; // rax
-        bg::detail::Span* m_next; // rax
-        void** v38; // rdi
-        void* v39; // rdx
-        bg::detail::Span* v40; // rdx
-        __int64 Span; // rax
-        __int64 v42; // r14
-        bg::detail::Span* v43; // rcx
-        bg::detail::Span* v44; // rdx
-        __int64 v45; // rax
-        bg::detail::PageHeap* v46; // rdi
-        bg::detail::Span* v47; // rax
-        size_t v48; // r8
-        void** v49; // rsi
-        size_t v50; // rdi
-        unsigned __int64 v51; // rdx
-        size_t v52; // r8
-        void** v53; // rcx
-        __int64 v54; // rdx
-        bg::detail::Span* v55; // rsi
-        bg::detail::PageHeap* v56; // rdi
-        bg::detail::Span* v57; // rax
-        size_t m_start_page; // rcx
-        size_t m_page_count; // r8
-        void** p_m_chunk_list; // rsi
-        void** v61; // rcx
-        void** v62; // rdx
-        void** v63; // r8
-        void** v64; // rdi
-        __int64 v65; // rdx
-        bg::detail::Span* v66; // rsi
-        bg::detail::Span* m_prev; // rdx
-        __int64 v68; // [rsp+0h] [rbp-70h]
-        __int64 v69; // [rsp+0h] [rbp-70h]
-        __int64 v70; // [rsp+0h] [rbp-70h]
-        __int64 v71; // [rsp+8h] [rbp-68h]
-        unsigned __int64 v72; // [rsp+8h] [rbp-68h]
-        unsigned __int64 v73; // [rsp+8h] [rbp-68h]
-        __int64 v74; // [rsp+8h] [rbp-68h]
-        unsigned __int64 v75; // [rsp+8h] [rbp-68h]
-        unsigned __int64 v76; // [rsp+8h] [rbp-68h]
-        bg::detail::PageHeap* v77; // [rsp+10h] [rbp-60h]
-        bg::detail::PageHeap* v78; // [rsp+10h] [rbp-60h]
-        bg::detail::PageHeap* v79; // [rsp+10h] [rbp-60h]
-        bg::detail::PageHeap* v80; // [rsp+10h] [rbp-60h]
-        __int64 v81; // [rsp+18h] [rbp-58h]
-        __int64 v82; // [rsp+18h] [rbp-58h]
-        bg::detail::Span* v83; // [rsp+18h] [rbp-58h]
-        __int64 v84; // [rsp+20h] [rbp-50h]
-        __int64 v85; // [rsp+20h] [rbp-50h]
-        bg::detail::Span* v86; // [rsp+20h] [rbp-50h]
-        __int64 v87; // [rsp+28h] [rbp-48h]
-        __int64 v88; // [rsp+28h] [rbp-48h]
-        __int64 v89; // [rsp+28h] [rbp-48h]
-        bg::detail::Span* v90; // [rsp+30h] [rbp-40h]
-        unsigned __int64 v91; // [rsp+30h] [rbp-40h]
-        bg::detail::Span* v92; // [rsp+30h] [rbp-40h]
-        __int64 v93; // [rsp+30h] [rbp-40h]
-        __int64 v94; // [rsp+30h] [rbp-40h]
-        uint8_t dest; // [rsp+38h] [rbp-38h]
-        void** desta; // [rsp+38h] [rbp-38h]
-        uint8_t destb; // [rsp+38h] [rbp-38h]
-        void* destc; // [rsp+38h] [rbp-38h]
-        void* destd; // [rsp+38h] [rbp-38h]
-
-        v6 = (int64_t)g_shm_ctx.mgr;
-        if(!v6)
-        {
-
-            return 0LL;
-        }
-        if(!old_ptr)
-            return bg::ShmMalloc(new_bytes);
-        if(!new_bytes)
-        {
-            bg::ShmFree((void*)old_ptr);
-            return 0LL;
-        }
-        if((uintptr_t)old_ptr >> 13 > 0x7FFFFFFFFLL)
-        {
-LABEL_51:
-
-            return 0LL;
-        }
-        v9 = ((uintptr_t)old_ptr >> 13) & 0x7FFF;
-        v10 = ((uintptr_t)old_ptr >> 28) & 0x3FF;
-        v11 = v6 + 8 * ((uintptr_t)old_ptr >> 38);
-        v12 = *(uintptr_t*)(v11 + 9136);
-        if(!v12)
-            goto LABEL_51;
-        v13 = *(uintptr_t*)(v12 + 8 * v10);
-        if(!v13)
-            goto LABEL_51;
-        v14 = *(uintptr_t*)(v13 + 8 * v9);
-        if(!v14)
-            goto LABEL_51;
-        v15 = *(unsigned __int8*)(v14 + 1);
-        if((char)v15 == 0xFF)
-        {
-            v16 = *(uintptr_t*)(v14 + 24) << 13;
-        }
-        else
-        {
-            if((unsigned __int8)v15 > 0x56u)
-            {
-
-                v11 = v6 + 8 * ((uintptr_t)old_ptr >> 38);
-                v10 = ((uintptr_t)old_ptr >> 28) & 0x3FF;
-            }
-            v16 = *(uintptr_t*)(v6 + 8 * v15 + 7744);
-        }
-        v17 = v16 + (v16 >> 2);
-        if(v16 > v16 >> 2)
-            v17 = -1LL;
-        if(new_bytes < v16 >> 1 || (result = (void**)old_ptr, new_bytes > v16))
-        {
-            if(new_bytes >= v17 || new_bytes <= v16)
-                goto LABEL_19;
-            if(v17 <= 0x400)
-            {
-                destb = *(char*)(v6 + ((v17 + 7) >> 3) + 5568);
-            }
-            else
-            {
-                if(v17 > 0x40000)
-                {
-                    v93 = v11;
-                    destc = (void*)v10;
-                    Span = (uintptr_t)((bg::detail::PageHeap*)(v6 + 9136))->AllocateSpan((v17 + 0x1FFF) >> 13);
-                    v10 = (unsigned __int64)destc;
-                    v11 = v93;
-                    if(Span)
-                    {
-                        desta = (void**)(*(uintptr_t*)(Span + 16) << 13);
-                        if(desta)
-                            goto LABEL_27;
-                    }
-                    goto LABEL_19;
-                }
-                destb = *(char*)(v6 + ((v17 + 15487) >> 7) + 5568);
-            }
-            if(destb > 0x56u)
-            {
-                v71 = v11;
-                v77 = (bg::detail::PageHeap*)v10;
-
-                v10 = (unsigned __int64)v77;
-                v11 = v71;
-                v85 = destb;
-                v82 = *(uintptr_t*)(v6 + 8LL * destb + 7744);
-                v89 = destb;
-                v36 = (bg::detail::Span*)(v6 + ((unsigned __int64)destb << 6));
-                v92 = v36;
-                if(v36 != v36->m_next)
-                    goto LABEL_47;
-                v78 = (bg::detail::PageHeap*)(v6 + 9136);
-                v69 = v71;
-                v72 = v10;
-
-                v10 = v72;
-                v11 = v69;
-                v46 = (bg::detail::PageHeap*)(v6 + 9136);
-            }
-            else
-            {
-                v85 = destb;
-                v82 = *(uintptr_t*)(v6 + 8LL * destb + 7744);
-                v89 = destb;
-                v36 = (bg::detail::Span*)(v6 + ((unsigned __int64)destb << 6));
-                v92 = v36;
-                if(v36 != v36->m_next)
-                {
-LABEL_47:
-                    m_next = v36->m_next;
-                    goto LABEL_48;
-                }
-                v78 = (bg::detail::PageHeap*)(v6 + 9136);
-                v46 = (bg::detail::PageHeap*)(v6 + 9136);
-            }
-            v68 = v11;
-            v73 = v10;
-            v47 = (bg::detail::Span*)v46->bg::detail::PageHeap::AllocateSpan(*(uintptr_t*)(v6 + 8 * v85 + 8440));
-            v10 = v73;
-            v11 = v68;
-            if(!v47)
-            {
-LABEL_19:
-                if(new_bytes <= 0x400)
-                {
-                    dest = *(char*)(v6 + ((new_bytes + 7) >> 3) + 5568);
-                    goto LABEL_22;
-                }
-                if(new_bytes <= 0x40000)
-                {
-                    dest = *(char*)(v6 + ((new_bytes + 15487) >> 7) + 5568);
-LABEL_22:
-                    if(dest > 0x56u)
-                    {
-                        v74 = v11;
-                        v79 = (bg::detail::PageHeap*)v10;
-
-                        v10 = (unsigned __int64)v79;
-                        v11 = v74;
-                        v81 = dest;
-                        v87 = *(char*)(v6 + 8LL * dest + 7744);
-                        v84 = dest;
-                        v19 = (bg::detail::Span*)(v6 + ((unsigned __int64)dest << 6));
-                        v90 = v19;
-                        if(v19 != v19->m_next)
-                            goto LABEL_24;
-                        v80 = (bg::detail::PageHeap*)(v6 + 9136);
-                        v70 = v74;
-                        v75 = v10;
-
-                        v10 = v75;
-                        v11 = v70;
-                        v56 = (bg::detail::PageHeap*)(v6 + 9136);
-                    }
-                    else
-                    {
-                        v81 = dest;
-                        v87 = *(char*)(v6 + 8LL * dest + 7744);
-                        v84 = dest;
-                        v19 = (bg::detail::Span*)(v6 + ((unsigned __int64)dest << 6));
-                        v90 = v19;
-                        if(v19 != v19->m_next)
-                        {
-LABEL_24:
-                            v20 = v19->m_next;
-                            goto LABEL_25;
-                        }
-                        v80 = (bg::detail::PageHeap*)(v6 + 9136);
-                        v56 = (bg::detail::PageHeap*)(v6 + 9136);
-                    }
-                    v68 = v11;
-                    v76 = v10;
-                    v57 = v56->AllocateSpan(*(uintptr_t*)(v6 + 8 * v81 + 8440));
-                    if(v57)
-                    {
-                        v83 = v57;
-                        v80->RegisterSpan(v57);
-                        v20 = v83;
-                        v10 = v76;
-                        v11 = v68;
-                        m_start_page = v83->m_start_page;
-                        m_page_count = v83->m_page_count;
-                        p_m_chunk_list = &v83->m_chunk_list;
-                        v83->m_size_class = dest;
-                        v61 = (void**)(m_start_page << 13);
-                        v62 = (void**)((char*)v61 + v87);
-                        v63 = &v61[1024 * m_page_count];
-                        if((void**)((char*)v61 + v87) <= v63)
-                        {
-                            while(1)
-                            {
-                                v64 = v62;
-                                v62 = (void**)((char*)v62 + v87);
-                                *p_m_chunk_list = v61;
-                                p_m_chunk_list = v61;
-                                if(v63 < v62)
-                                    break;
-                                v61 = v64;
-                            }
-                        }
-                        else
-                        {
-                            v61 = &v83->m_chunk_list;
-                        }
-                        *v61 = 0LL;
-                        v65 = v6 + (v84 << 6);
-                        v66 = *(bg::detail::Span**)(v65 + 40);
-                        v83->m_prev = v90;
-                        v83->m_next = v66;
-                        *(uintptr_t*)(*(uintptr_t*)(v65 + 40) + 32LL) = (uintptr_t)v83;
-                        *(uintptr_t*)(v65 + 40) = (uintptr_t)v83;
-                        ++* (uintptr_t*)(v65 + 56);
-LABEL_25:
-                        m_chunk_list = (void**)v20->m_chunk_list;
-                        ++v20->m_used_count;
-                        v22 = *m_chunk_list;
-                        desta = m_chunk_list;
-                        v20->m_chunk_list = *m_chunk_list;
-                        if(!v22)
-                        {
-                            m_prev = v20->m_prev;
-                            m_prev->m_next = v20->m_next;
-                            v20->m_next->m_prev = m_prev;
-                            v20->m_prev = 0LL;
-                            v20->m_next = 0LL;
-                            --* (uintptr_t*)(v6 + (v84 << 6) + 56);
-                        }
-                        goto LABEL_27;
-                    }
-                    return 0LL;
-                }
-                v94 = v11;
-                destd = (void*)v10;
-                v45 = (uintptr_t)((bg::detail::PageHeap*)(v6 + 9136))->AllocateSpan((new_bytes + 0x1FFF) >> 13);
-                v10 = (unsigned __int64)destd;
-                v11 = v94;
-                if(!v45)
-                    return 0LL;
-                result = (void**)(*(uintptr_t*)(v45 + 16) << 13);
-                desta = result;
-                if(!result)
-                    return result;
-LABEL_27:
-                v23 = new_bytes;
-                if(v16 <= new_bytes)
-                    v23 = v16;
-                v88 = v11;
-                v91 = v10;
-                memcpy(desta, (const void*)old_ptr, v23);
-                v24 = *(uintptr_t*)(v88 + 9136);
-                if(v24 && (v25 = *(uintptr_t*)(v24 + 8 * v91)) != 0 && (v26 = *(bg::detail::Span**)(v25 + 8 * v9)) != 0LL)
-                {
-                    m_size_class = v26->m_size_class;
-                    if(m_size_class == 0xFF)
-                    {
-                        ((bg::detail::PageHeap*)(v6 + 9136))->DeallocateSpan(v26);
-                        return desta;
-                    }
-                    m_used_count = v26->m_used_count;
-                    if(m_used_count && m_size_class <= 0x56u)
-                    {
-                        v29 = m_size_class;
-                        v30 = v26->m_chunk_list;
-                        v31 = m_used_count - 1;
-                        v32 = (bg::detail::PageHeap*)(v6 + 9136);
-                        *(uintptr_t*)old_ptr = (uintptr_t)v30;
-                        v26->m_used_count = v31;
-                        v33 = v31 == 0;
-                        v26->m_chunk_list = (void*)old_ptr;
-                        if(v30)
-                        {
-                            result = desta;
-                            if(!v33)
-                                return result;
-                            v34 = v6 + (v29 << 6) + 48;
-                            if(*(uintptr_t*)(v34 + 8) <= 1uLL)
-                                return result;
-                            v35 = v26->m_prev;
-                            v35->m_next = v26->m_next;
-                            v26->m_next->m_prev = v35;
-                            v26->m_prev = 0LL;
-                            v26->m_next = 0LL;
-                            --* (uintptr_t*)(v34 + 8);
-                        }
-                        else
-                        {
-                            v42 = (v29 << 6) + v6;
-                            if(!v33)
-                            {
-                                v44 = *(bg::detail::Span**)(v42 + 40);
-                                result = desta;
-                                v26->m_prev = (bg::detail::Span*)v42;
-                                v26->m_next = v44;
-                                *(uintptr_t*)(*(uintptr_t*)(v42 + 40) + 32LL) = (uintptr_t)v26;
-                                *(uintptr_t*)(v42 + 40) = (uintptr_t)v26;
-                                ++* (uintptr_t*)(v42 + 56);
-                                return result;
-                            }
-                            if(!*(uintptr_t*)(v42 + 56))
-                            {
-                                v43 = *(bg::detail::Span**)(v42 + 40);
-                                v26->m_prev = (bg::detail::Span*)v42;
-                                v26->m_next = v43;
-                                *(uintptr_t*)(*(uintptr_t*)(v42 + 40) + 32LL) = (uintptr_t)v26;
-                                *(uintptr_t*)(v42 + 40) = (uintptr_t)v26;
-                                ++* (uintptr_t*)(v42 + 56);
-                                return desta;
-                            }
-                        }
-                        v26->m_used_count = 0LL;
-                        v26->m_size_class = -1;
-                        v26->m_chunk_list = 0LL;
-                        v32->DeallocateSpan(v26);
-                        return desta;
-                    }
-
-                }
-                else
-                {
-
-                }
-                return desta;
-            }
-            v86 = v47;
-            v78->RegisterSpan(v47);
-            m_next = v86;
-            v10 = v73;
-            v11 = v68;
-            v48 = v86->m_page_count;
-            v49 = &v86->m_chunk_list;
-            v86->m_size_class = destb;
-            v50 = v86->m_start_page << 13;
-            v51 = v50 + v82;
-            v52 = v50 + (v48 << 13);
-            if(v50 + v82 > v52)
-            {
-                v53 = &v86->m_chunk_list;
-            }
-            else
-            {
-                do
-                {
-                    v53 = (void**)(v51 - v82);
-                    v51 += v82;
-                    *v49 = v53;
-                    v49 = v53;
-                } while(v52 >= v51);
-            }
-            *v53 = 0LL;
-            v54 = v6 + (v89 << 6);
-            v55 = *(bg::detail::Span**)(v54 + 40);
-            v86->m_prev = v92;
-            v86->m_next = v55;
-            *(uintptr_t*)(*(uintptr_t*)(v54 + 40) + 32LL) = (uintptr_t)v86;
-            *(uintptr_t*)(v54 + 40) = (uintptr_t)v86;
-            ++* (uintptr_t*)(v54 + 56);
-LABEL_48:
-            v38 = (void**)m_next->m_chunk_list;
-            ++m_next->m_used_count;
-            v39 = *v38;
-            desta = v38;
-            m_next->m_chunk_list = *v38;
-            if(!v39)
-            {
-                v40 = m_next->m_prev;
-                v40->m_next = m_next->m_next;
-                m_next->m_next->m_prev = v40;
-                m_next->m_prev = 0LL;
-                m_next->m_next = 0LL;
-                --* (uintptr_t*)(v6 + (v89 << 6) + 56);
-            }
-            goto LABEL_27;
-        }
-        return result;
-
-    }
-
-    void* ShmCalloc(size_t n, size_t bytes)
-    {
-        __int64 v6; // r12
-        size_t v7; // rbx
-        void** v8; // r12
-        uint8_t v10; // r14
-        __int64 v11; // r11
-        __int64 v12; // r15
-        __int64 v13; // r10
-        bg::detail::Span* v14; // r13
-        bg::detail::Span* m_next; // rax
-        void** m_chunk_list; // rdx
-        bool v17; // zf
-        __int64 Span; // rax
-        bg::detail::PageHeap* v19; // rdi
-        bg::detail::Span* v20; // rax
-        size_t m_start_page; // rcx
-        size_t m_page_count; // r8
-        void** p_m_chunk_list; // rsi
-        void** v24; // rcx
-        void** v25; // rdx
-        void** v26; // r8
-        void** v27; // rdi
-        __int64 v28; // rdx
-        bg::detail::Span* v29; // rsi
-        bg::detail::Span* m_prev; // rcx
-        bg::detail::Span* v31; // [rsp+8h] [rbp-48h]
-        __int64 v32; // [rsp+10h] [rbp-40h]
-        bg::detail::PageHeap* v33; // [rsp+18h] [rbp-38h]
-
-        v6 = (int64_t)g_shm_ctx.mgr;
-        if(!v6)
-        {
-            return nullptr;
-        }
-        v7 = bytes * n;
-        if(bytes && n != v7 / bytes)
-            return 0LL;
-        if(v7 <= 0x400)
-        {
-            v10 = *(char*)(v6 + ((v7 + 7) >> 3) + 5568);
-        }
-        else
-        {
-            if(v7 > 0x40000)
-            {
-                Span = (uintptr_t)((bg::detail::PageHeap*)(v6 + 9136))->AllocateSpan((v7 + 0x1FFF) >> 13);
-                if(Span)
-                {
-                    v8 = (void**)(*(uintptr_t*)(Span + 16) << 13);
-                    if(v8)
-                    {
-LABEL_16:
-                        memset(v8, 0, v7);
-                        return v8;
-                    }
-                }
-                return 0LL;
-            }
-            v10 = *(char*)(v6 + ((v7 + 15487) >> 7) + 5568);
-        }
-        if(v10 > 0x56u)
-        {
-            v12 = *(uintptr_t*)(v6 + 8LL * v10 + 7744);
-            v13 = v10;
-            v14 = (bg::detail::Span*)(v6 + ((unsigned __int64)v10 << 6));
-            if(v14 != v14->m_next)
-                goto LABEL_12;
-            v33 = (bg::detail::PageHeap*)(v6 + 9136);
-
-            v13 = v10;
-            v11 = v10;
-            v19 = (bg::detail::PageHeap*)(v6 + 9136);
-        }
-        else
-        {
-            v11 = v10;
-            v12 = *(uintptr_t*)(v6 + 8LL * v10 + 7744);
-            v13 = v10;
-            v14 = (bg::detail::Span*)(v6 + ((unsigned __int64)v10 << 6));
-            if(v14 != v14->m_next)
-            {
-LABEL_12:
-                m_next = v14->m_next;
-                goto LABEL_13;
-            }
-            v33 = (bg::detail::PageHeap*)(v6 + 9136);
-            v19 = (bg::detail::PageHeap*)(v6 + 9136);
-        }
-        v32 = v13;
-        v20 = (bg::detail::Span*)v19->AllocateSpan(*(uintptr_t*)(v6 + 8 * v11 + 8440));
-        if(v20)
-        {
-            v31 = v20;
-            v33->RegisterSpan(v20);
-            m_next = v31;
-            v13 = v32;
-            m_start_page = v31->m_start_page;
-            m_page_count = v31->m_page_count;
-            p_m_chunk_list = &v31->m_chunk_list;
-            v31->m_size_class = v10;
-            v24 = (void**)(m_start_page << 13);
-            v25 = (void**)((char*)v24 + v12);
-            v26 = &v24[1024 * m_page_count];
-            if((void**)((char*)v24 + v12) <= v26)
-            {
-                while(1)
-                {
-                    v27 = v25;
-                    v25 = (void**)((char*)v25 + v12);
-                    *p_m_chunk_list = v24;
-                    p_m_chunk_list = v24;
-                    if(v26 < v25)
-                        break;
-                    v24 = v27;
-                }
-            }
-            else
-            {
-                v24 = &v31->m_chunk_list;
-            }
-            *v24 = 0LL;
-            v28 = v6 + (v32 << 6);
-            v29 = *(bg::detail::Span**)(v28 + 40);
-            v31->m_prev = v14;
-            v31->m_next = v29;
-            *(uintptr_t*)(*(uintptr_t*)(v28 + 40) + 32LL) = (uintptr_t)v31;
-            *(uintptr_t*)(v28 + 40) = (uintptr_t)v31;
-            ++* (uintptr_t*)(v28 + 56);
-LABEL_13:
-            m_chunk_list = (void**)m_next->m_chunk_list;
-            ++m_next->m_used_count;
-            v17 = *m_chunk_list == 0LL;
-            m_next->m_chunk_list = *m_chunk_list;
-            if(v17)
-            {
-                m_prev = m_next->m_prev;
-                m_prev->m_next = m_next->m_next;
-                m_next->m_next->m_prev = m_prev;
-                m_next->m_prev = 0LL;
-                m_next->m_next = 0LL;
-                --* (uintptr_t*)(v6 + (v13 << 6) + 56);
-            }
-            v8 = m_chunk_list;
-            goto LABEL_16;
-        }
-        return 0LL;
-    }
-
-}
-
-
-

+ 0 - 14
Project4/shm_object.h

@@ -1,14 +0,0 @@
-#pragma once
-#include <stdint.h>
-namespace bg
-{
-	namespace detail
-	{
-		bool GetDirectorySize(const char* path, size_t* const total_size);
-		void* ShmObjectCreate(const char* path, uintptr_t fixed_addr, size_t* real_size, size_t* mmap_size);
-		void* ShmObjectAttach(const char* path, uintptr_t fixed_addr, size_t* real_size, size_t* mmap_size);
-		void ShmObjectDelete(void* addr, uintptr_t mmap_size, const char* path);
-		bool ShmObjectResize(const char* path, size_t* new_size);
-		bool GetAvailableMemorySize(size_t* const size);
-	}
-}

+ 0 - 56
Project4/size_map.h

@@ -1,56 +0,0 @@
-#pragma once
-#include "shm_config.h"
-#include "shm_helper.h"
-namespace bg
-{
-    namespace detail
-    {
-        class SizeMap
-        {
-        public:
-            bool Init();
-
-            static size_t CalcAlignment(size_t bytes);
-
-            size_t GetIndexByBytes(size_t bytes)
-            {
-                if(bytes <= BYTES_COMP_VALUE)
-                {
-                    return  m_index_to_class[SMALL_BYTES_TO_INDEX(bytes)];
-                }
-                return BIG_BYTES_TO_INDEX(bytes);
-            }
-
-            size_t ClassToSize(size_t index)
-            {
-                if(index >= CLASS_MAX_COUNT)
-                {
-                    __SHM_DO_ASSERT(index < CLASS_MAX_COUNT);
-                    return 0;
-                }
-
-                return m_class_to_size[index];
-            }
-
-            size_t ClassToPages(size_t index)
-            {
-                if(index >= CLASS_MAX_COUNT)
-                {
-                    __SHM_DO_ASSERT(index < CLASS_MAX_COUNT);
-                    return 0;
-                }
-
-                return m_class_to_pages[index];
-            }
-
-
-            char m_index_to_class[2176]{0};
-
-            size_t m_class_to_size[CLASS_MAX_COUNT]{0};
-
-            size_t m_class_to_pages[CLASS_MAX_COUNT]{0};
-        };
-
-
-    }
-}

+ 0 - 0
Project4/catch.hpp → Project4/test/catch.hpp


+ 103 - 0
Project4/test/test_manage.cpp

@@ -0,0 +1,103 @@
+#include "catch.hpp"
+#include "shm_manager.h"
+#include "shm.h"
+#include "shm_object.h"
+extern bg::detail::ShmContext g_shm_ctx;
+TEST_CASE("ShmManager, AllocateRawMemory")
+{
+    bg::ShmOptions opts(false, "Test", nullptr);
+    opts.fix_vptr_on_init = false;
+    REQUIRE(bg::ShmInit(opts) == true);
+
+    REQUIRE(g_shm_ctx.mgr);
+
+    for(size_t i = 8; i < 0x100000000LL; i = i << 4)
+    {
+        size_t real_bytes = i - 1;
+        void* memory = g_shm_ctx.mgr->AllocateRawMemory(&real_bytes, i);
+        REQUIRE(memory);
+        memset(memory, 0, real_bytes);
+        REQUIRE(real_bytes == i);
+    }
+
+    bg::ShmFini();
+}
+
+struct TestSigleton
+{
+    TestSigleton(int a, char b, void* c)
+    {
+        this->a = a;
+        this->b = b;
+        this->c = c;
+    }
+    int a{};
+    char b{};
+    void* c{};
+};
+
+TEST_CASE("ShmManager, Singleton")
+{
+    bg::ShmOptions opts(false, "Test", nullptr);
+    opts.fix_vptr_on_init = false;
+    REQUIRE(bg::ShmInit(opts) == true);
+
+    REQUIRE(g_shm_ctx.mgr);
+    bg::detail::TypeName type(typeid(TestSigleton).name(), sizeof(TestSigleton));
+    REQUIRE(g_shm_ctx.mgr->HasSingleton(type) == false);
+    int a = 3;
+    REQUIRE(bg::ShmGetSingleton<TestSigleton>(1, 2, &a));
+    REQUIRE(g_shm_ctx.mgr->HasSingleton(type) == true);
+
+    TestSigleton* temp = bg::ShmGetSingleton<TestSigleton>(1, 1, &a);
+    REQUIRE(temp->a == 1);
+    REQUIRE(temp->b == 2);
+    REQUIRE(temp->c == &a);
+    bg::ShmDeleteSingleton<TestSigleton>();
+    REQUIRE(g_shm_ctx.mgr->HasSingleton(type) == false);
+    bg::ShmFini();
+}
+
+
+TEST_CASE("ShmManager, creat/resume")
+{
+    char path[256];
+    bg::ShmOptions opts(false, "Test", nullptr);
+    opts.fix_vptr_on_init = true;
+    REQUIRE(bg::ShmInit(opts) == true);
+    int a = 3;
+    REQUIRE(g_shm_ctx.mgr);
+    bg::detail::TypeName type(typeid(TestSigleton).name(), sizeof(TestSigleton));
+    REQUIRE(g_shm_ctx.mgr->HasSingleton(type) == false);
+    REQUIRE(bg::ShmGetSingleton<TestSigleton>(1, 2, &a));
+    REQUIRE(g_shm_ctx.mgr->HasSingleton(type) == true);
+    opts.resume = true;
+
+
+    // 占住共享内存 windows 会自动释放
+    size_t real_size = sizeof(bg::detail::ShmManager);
+    snprintf(path, 256, "%s-mgr.mmap", opts.identifier);
+    void* memory1 = bg::detail::ShmObjectAttach(path, 0, &real_size, &real_size);
+    REQUIRE(memory1);
+    bg::detail::ShmObjectDelete(g_shm_ctx.mgr, real_size, path);
+    real_size = 0x100000000;
+    void* memory2 = bg::detail::ShmObjectAttach("Test-000.mmap", 0, &real_size, &real_size);
+
+    REQUIRE(memory2);
+    bg::detail::ShmObjectDelete((void*)0x00006f0000000000, real_size, "Test-000.mmap");
+
+    g_shm_ctx.mgr = nullptr;
+    REQUIRE(bg::ShmInit(opts) == true);
+
+    bg::detail::ShmObjectDelete(memory1, sizeof(bg::detail::ShmManager), path);
+
+    bg::detail::ShmObjectDelete(memory2, real_size, "Test-000.mmap");
+
+    TestSigleton* temp = bg::ShmGetSingleton<TestSigleton>(1, 1, &a);
+    REQUIRE(temp->a == 1);
+    REQUIRE(temp->b == 2);
+    REQUIRE(temp->c == &a);
+    bg::ShmDeleteSingleton<TestSigleton>();
+    REQUIRE(g_shm_ctx.mgr->HasSingleton(type) == false);
+    bg::ShmFini();
+}

+ 52 - 0
Project4/test/test_object.cpp

@@ -0,0 +1,52 @@
+#include "catch.hpp"
+#include "shm_object.h"
+#include "shm.h"
+#include "shm_manager.h"
+TEST_CASE("ShmObjectCreate, creat/delete")
+{
+    bg::ShmOptions opts(false, "Test", nullptr);
+    char path[256];
+    bg::detail::ShmManager::ShmBlock m_blocks[17]{};
+    size_t count = opts.fixed_address_count;
+    for(size_t i = 0; i < count; ++i)
+    {
+        size_t real_size = opts.shm_block_mmap_size / 8;
+        size_t mmap_size = opts.shm_block_mmap_size / 8;
+        snprintf(path, 0x100uLL, "%s-%03zu.mmap", opts.identifier, i);
+        uintptr_t fixed_addr = 0ll;
+        REQUIRE(opts.PopFixedAddress(&fixed_addr));
+        void* memory = bg::detail::ShmObjectCreate(path, fixed_addr, &real_size, &mmap_size);
+        REQUIRE(memory);
+        memset(memory, 0, real_size);
+        m_blocks[i].addr = memory;
+        m_blocks[i].mmap_size = real_size;
+        m_blocks[i].mmap_size = mmap_size;
+    }
+
+    for(size_t i = 0; i < count; ++i)
+    {
+        size_t real_size = opts.shm_block_mmap_size / 8;
+        size_t mmap_size = opts.shm_block_mmap_size / 8;
+
+        snprintf(path, 0x100uLL, "%s-%03zu.mmap", opts.identifier, i);
+
+        void* memory = bg::detail::ShmObjectAttach(path, 0, &real_size, &mmap_size);
+        REQUIRE(memory);
+        memset(memory, 0, real_size);
+
+        bg::detail::ShmObjectDelete(memory, mmap_size, path);
+
+    }
+
+    for(size_t i = 0; i < count; ++i)
+    {
+        size_t real_size = opts.shm_block_mmap_size / 8;
+        size_t mmap_size = opts.shm_block_mmap_size / 8;
+
+        snprintf(path, 0x100uLL, "%s-%03zu.mmap", opts.identifier, i);
+
+        bg::detail::ShmObjectDelete(m_blocks[i].addr, m_blocks[i].mmap_size, path);
+
+    }
+}
+

+ 40 - 0
Project4/test/test_page_heap.cpp

@@ -0,0 +1,40 @@
+#include "catch.hpp"
+#include "page_heap.h"
+#include "shm.h"
+TEST_CASE("RadixTree, Allocate Span")
+{
+    bg::ShmOptions opts(false, "Test", nullptr);
+    opts.fix_vptr_on_init = false;
+    REQUIRE(bg::ShmInit(opts) == true);
+    bg::detail::MetadataAllocator<bg::detail::Span> span_allocator;
+    std::vector<bg::detail::Span*> vec;
+    vec.reserve(2340);
+    for(int i = 0; i < 2340; ++i)
+    {
+        bg::detail::Span* span = span_allocator.Allocate();
+        REQUIRE(span);
+        span->SetUsedCount(i);
+        vec.push_back(span);
+    }
+
+
+    for(int i = 2340 - 1; i >= 0; --i)
+    {
+        span_allocator.Destroy(vec[i]);
+    }
+
+    for(int i = 0; i < 2340; ++i)
+    {
+        bg::detail::Span* span = span_allocator.Allocate();
+        REQUIRE(span);
+        REQUIRE(span->GetUsedCount() == i);
+    }
+
+    for(int i = 2340 - 1; i >= 0; --i)
+    {
+        span_allocator.Destroy(vec[i]);
+    }
+
+    bg::ShmFini();
+}
+

+ 36 - 0
Project4/test/test_size_map.cpp

@@ -0,0 +1,36 @@
+
+#include "catch.hpp"
+#include "size_map.h"
+#include "shm_manager.h"
+
+TEST_CASE("SizeMap, CalcAlignment")
+{
+    for(size_t i = 0; i < CLASS_MAX_BYTES; ++i)
+    {
+        auto value = bg::detail::SizeMap::CalcAlignment(i);
+        REQUIRE(value > 0);
+        REQUIRE(value % 8 == 0);
+        REQUIRE(value <= PAGE_BYTES);
+        if(i > 0x7F && i < (PAGE_BYTES << 4))
+        {
+            REQUIRE(PALIGN_DOWN(i, value << 3) == value << 3);
+        }
+    }
+}
+
+
+TEST_CASE("SizeMap, Class Index to Page")
+{
+    bg::detail::SizeMap sizemap;
+    sizemap.Init();
+    for(size_t bytes = 0; bytes < CLASS_MAX_BYTES; ++bytes)
+    {
+        size_t index = sizemap.GetClassByBytes(bytes);
+
+        REQUIRE(index < CLASS_MAX_COUNT);
+        REQUIRE(sizemap.ClassToSize(index) >= bytes);
+        REQUIRE(sizemap.ClassToPages(index) * PAGE_BYTES >= bytes);
+        REQUIRE(sizemap.ClassToPages(index) * PAGE_BYTES <= CLASS_MAX_BYTES);
+
+    }
+}

+ 0 - 0
Project4/testmain.cpp → Project4/test/testmain.cpp


+ 0 - 46
Project4/test_size_map.cpp

@@ -1,46 +0,0 @@
-
-#include "catch.hpp"
-#include "size_map.h"
-#include "shm_manager.h"
-
-TEST_CASE("SizeMap, CalcAlignment")
-{
-    for(size_t i = 0; i < CLASS_MAX_BYTES; ++i)
-    {
-        auto value = bg::detail::SizeMap::CalcAlignment(i);
-        REQUIRE(value > 0);
-        REQUIRE(value % 8 == 0);
-        REQUIRE(value <= CALIGNMENT_MAX_BYTES);
-        if(i > 0x7F && i < (CALIGNMENT_MAX_BYTES << 4))
-        {
-            REQUIRE(PALIGN_DOWN(i, value << 3) == value << 3);
-        }
-    }
-}
-
-
-TEST_CASE("SizeMap, Class Index to Page")
-{
-    bg::detail::SizeMap sizemap;
-    sizemap.Init();
-    for(size_t bytes = 0; bytes < CLASS_MAX_BYTES; ++bytes)
-    {
-
-        size_t index;
-        if(bytes <= BYTES_COMP_VALUE)
-        {
-            index = sizemap.m_index_to_class[SMALL_BYTES_TO_INDEX(bytes)];
-        }
-        else
-        {
-            auto temp1 = BIG_BYTES_TO_INDEX(bytes);
-            index = sizemap.m_index_to_class[BIG_BYTES_TO_INDEX(bytes)];
-        }
-
-        REQUIRE(index < CLASS_MAX_COUNT);
-        REQUIRE(sizemap.m_class_to_size[index] >= bytes);
-        REQUIRE(sizemap.m_class_to_pages[index] * CALIGNMENT_MAX_BYTES >= bytes);
-        REQUIRE(sizemap.m_class_to_pages[index] * CALIGNMENT_MAX_BYTES <= CLASS_MAX_BYTES);
-
-    }
-}

+ 0 - 311
Project4/vptr_manager.cc

@@ -1,311 +0,0 @@
-#include "vptr_manager.h"
-#include "shm.h"
-#include <memory>
-namespace bg
-{
-	namespace detail
-	{
-		VptrManager* mgr;
-		class HighOrderContainer;
-		std::unique_ptr<HighOrderContainer> 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<const uintptr_t*>(reinterpret_cast<const char*>(itor->second));
-				uintptr_t* old_vptr = reinterpret_cast<uintptr_t*>(reinterpret_cast<char*>(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 Key, typename Value, typename Hash = std::hash<Key>, typename Pred = std::equal_to<Key>>
-			using Container = std::unordered_map<Key, Value, Hash, Pred, ShmAllocator<std::pair<const Key, Value>>>;
-			Container<TypeName, VptrObjectContainerBase*, TypeNameHasher> m_type_to_containers;
-		};
-
-
-		VptrObjectContainerBase::VptrObjectContainerBase(const TypeName& type, bool in_shm) :m_version(0LL), m_type(type)
-		{
-			if(in_shm)
-			{
-				std::vector<void*, bg::detail::ShmAllocator<void*> >* vector = (std::vector<void*, bg::detail::ShmAllocator<void*> > *)bg::ShmMalloc(sizeof(std::vector<void*, bg::detail::ShmAllocator<void*> >));
-				if(vector)
-				{
-					new (vector) std::vector<void*, bg::detail::ShmAllocator<void*> >();
-				}
-				m_objects = vector;
-			}
-			else
-			{
-				if(!hoc)
-				{
-					hoc = std::make_unique<HighOrderContainer>();
-				}
-				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<bg::detail::VptrManager>();
-			}
-			return bg::detail::mgr != nullptr;
-		}
-
-		void VptrManager::Fini()
-		{
-			if(bg::detail::mgr)
-			{
-				bg::ShmDeleteSingleton<bg::detail::VptrManager>();
-				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<const uintptr_t*>(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);
-		}
-
-	}
-}

+ 0 - 473
Project4/vptr_manager.h

@@ -1,473 +0,0 @@
-/*
- * Copyright 2020 ByteDance Games, Inc. All Rights Reserved.
- *
- * Author: Liuziming <liuziming.kelvin@bytedance.com>
- */
-
-#pragma once
-
-#include <stddef.h>
-#include <string.h>
-#include <string>
-#include <vector>
-#include <typeinfo>
-#include <unordered_map>
-
-#include "shm_helper.h"
-# if defined(__GNUC__)
-#include <tr2/type_traits>
-#include <typeinfo>
-#include <map>
-#ifdef OUTPUT_BASES
-extern std::map<std::string, std::vector<std::string>> g_bases_name;
-#endif
-#else 
-#include "type_helper.h"
-#define REINTERPRET_CAST_TAG	
-#endif
-
-namespace bg
-{
-	namespace detail
-	{
-
-		struct BaseTypeInfo
-		{
-			TypeName type;
-			ptrdiff_t offset;
-
-			BaseTypeInfo(const char* type, ptrdiff_t offset) : type(type), offset(offset) {}
-		};
-
-		class VptrObjectContainerBase
-		{
-		public:
-			VptrObjectContainerBase(const TypeName& type, bool in_shm);
-			virtual ~VptrObjectContainerBase();
-
-			virtual void FixObjects() = 0;
-			virtual VptrObjectContainerBase* ShmNew() = 0;
-
-			void FixVptr();
-			const TypeName& GetTypeName() const { return m_type; }
-			const BaseTypeInfo* GetBaseTypeInfo(const TypeName& base_type);
-
-			void RecordObject(void* ptr);
-			void RemoveObject(void* ptr);
-
-		protected:
-			bool FixSelf();
-			void DoRemoveObject(size_t index);
-
-		protected:
-			static constexpr const double EXPANSION_FACTOR = 1.5;
-
-			uint64_t m_version = 0;
-			TypeName m_type;
-			// As we have containers both in normal memory and shared
-			// memory, so we make the pointer container as pointer here,
-			// only initialize it when it's used in shared memory.
-			std::vector<void*, ShmAllocator<void*>>* m_objects = nullptr;
-			// The following field is initialized in derived class constructor.
-			std::vector<BaseTypeInfo>* m_base_types = nullptr;
-		};
-
-		template<typename T>
-		class VptrObjectContainer final : public VptrObjectContainerBase
-		{
-		public:
-			static const T static_object;
-			static const VptrObjectContainer<T> static_container;
-
-			/*
-			 * NOTE: The 2nd arg to `TypeName(...)` MUST BE 0 here, because when
-			 * we delete a pointer of polymorphic type, we can only know it's real
-			 * type with `typeid(*ptr).name()`, but we cannot get the size of that
-			 * real type, so we have to abandon size here, to match the info we can
-			 * get at deletion. The same as following calls to this function.
-			 */
-			VptrObjectContainer() : VptrObjectContainerBase(TypeName(typeid(T).name()), false)
-			{
-				SHM_DEBUG_ASSERT(this == &static_container);
-
-				size_t count = GetBaseClassCount();
-				if(count > 0)
-				{
-					m_base_types = new std::vector<BaseTypeInfo>();
-					m_base_types->reserve(count);
-					FillBaseTypeInfo(m_base_types, Index2Type<0>());
-				}
-			}
-
-			VptrObjectContainer(const VptrObjectContainer& that) : VptrObjectContainerBase(that.m_type, true)
-			{
-				SHM_DEBUG_ASSERT(&that == &static_container);
-			}
-
-			~VptrObjectContainer() final = default;
-
-			void FixObjects() final
-			{
-				SHM_TRACE(">>>>> fixing vptr of objects in container(%p: %s)...", this, m_type.c_str());
-				for(void* ptr : *m_objects)
-				{
-					DoFix(ptr, std::integral_constant<bool, GetBaseClassCount() != 0>(), Index2Type<0>());
-				}
-				SHM_TRACE("<<<<< vptr of objects in container(%p: %s) fixed.", this, m_type.c_str());
-			}
-
-			VptrObjectContainerBase* ShmNew() final
-			{
-				SHM_DEBUG_ASSERT(this == &static_container);
-				ShmAllocator<VptrObjectContainer<T>> allocator;
-				VptrObjectContainer<T>* ptr = allocator.allocate(1);
-				if(SHM_LIKELY(ptr))
-				{
-					allocator.construct(ptr, *this);
-				}
-
-				return ptr;
-			}
-
-		private:
-			template<typename... Types>
-			struct List
-			{
-				static constexpr size_t count = sizeof...(Types);
-			};
-
-			template<typename NewType, typename List>
-			struct PrependList;
-
-			template<typename NewType, typename... Types>
-			struct PrependList<NewType, List<Types...>>
-			{
-				using ListType = List<NewType, Types...>;
-			};
-
-			template<typename List>
-			struct RemoveFirst;
-
-			template<typename Head, typename... Rest>
-			struct RemoveFirst<List<Head, Rest...>>
-			{
-				using RestList = List<Rest...>;
-			};
-
-			struct NullType {};
-
-			template<typename T>
-			struct bases
-			{
-				typedef __reflection_typelist<>		type;
-			};
-
-			template<typename Type>
-# if defined(__GNUC__)
-			using RefList = typename std::tr2::bases<Type>::type;
-#elif defined(_MSC_VER)
-			using RefList = typename bases<Type>::type;
-
-#endif
-
-
-			template<bool empty, typename RefList>
-			struct DoMakeList;
-
-			template<typename RefList>
-			struct DoMakeList<true, RefList>
-			{
-				using ListType = List<NullType>;
-			};
-
-			template<typename RefList>
-			struct DoMakeList<false, RefList>
-			{
-				using ListType =
-					typename PrependList<
-					typename RefList::first::type,
-					typename DoMakeList<
-					RefList::rest::type::empty::value,
-					typename RefList::rest::type
-					>::ListType
-					>::ListType;
-			};
-
-			template<typename Type>
-			struct MakeList
-			{
-				using Result =
-					typename DoMakeList<
-					RefList<Type>::empty::value,
-					RefList<Type>
-					>::ListType;
-			};
-
-			template<size_t N, typename BaseList>
-			struct GetNthBaseClass;
-
-			template<size_t N, typename Head, typename... Rest>
-			struct GetNthBaseClass<N, List<Head, Rest...>>
-			{
-				using BaseType = typename GetNthBaseClass<N - 1, List<Rest...>>::BaseType;
-			};
-
-			template<typename Head, typename... Rest>
-			struct GetNthBaseClass<0, List<Head, Rest...>>
-			{
-				using BaseType = Head;
-			};
-# if defined(__GNUC__)
-			template<typename Derived, typename Base>
-			struct BaseClassOffset
-			{
-
-				static constexpr const Derived* derived = &VptrObjectContainer<T>::static_object;
-				static constexpr const Base* base = static_cast<const Base*>(derived);
-
-				static REINTERPRET_CAST_TAG  ptrdiff_t value;
-
-				static constexpr ptrdiff_t value =
-					reinterpret_cast<intptr_t>(base) - reinterpret_cast<intptr_t>(derived);
-
-
-				/*
-				 * This does not work with higher GCC version, due to C++ 11 standard specifies
-				 * that `reinterpret_cast` cannot be used inside constexpr expression. See this
-				 * link for detail:
-				 * https://stackoverflow.com/questions/24398102/constexpr-and-initialization-of-a-static-const-void-pointer-with-reinterpret-cas
-				 *
-				 * static constexpr ptrdiff_t value =
-				 *     reinterpret_cast<intptr_t>(static_cast<Base*>(static_cast<Derived*>(0) + 1)) -
-				 *     reinterpret_cast<intptr_t>(static_cast<Derived*>(0) + 1);
-				 */
-			};
-#endif
-			template<size_t N>
-# if defined(__GNUC__)
-			static constexpr ptrdiff_t GetBaseClassOffset()
-			{
-				using BaseList = typename MakeList<T>::Result;
-				using BaseType = typename GetNthBaseClass<N, BaseList>::BaseType;
-
-				return BaseClassOffset<T, BaseType>::value;
-			}
-#else
-			static REINTERPRET_CAST_TAG ptrdiff_t GetBaseClassOffset()
-			{
-				using BaseList = typename MakeList<T>::Result;
-				using BaseType = typename GetNthBaseClass<N, BaseList>::BaseType;
-				static constexpr const T* derived = &VptrObjectContainer<T>::static_object;
-				static constexpr const BaseType* base = static_cast<const BaseType*>(derived);
-
-				return reinterpret_cast<intptr_t>(base) - reinterpret_cast<intptr_t>(derived);
-			}
-#endif
-
-			static constexpr size_t GetBaseClassCount()
-			{
-				// There is a NullType at the end of the list, so we compare with 1 here
-				static_assert(MakeList<T>::Result::count >= 1, "Invalid base class count");
-				return MakeList<T>::Result::count - 1;
-			}
-
-			/*
-			 * The BEST solution should be the following:
-			 *   Generate an base class offset array at compile time, during fixing, iterate
-			 *   over the array and fix each vptr at corresponding offset. However, there is
-			 *   a bug in GCC(4.8), which leads to the following code cannot compile:
-			 *
-			 *     internal compiler error: in convert_nontype_argument, at cp/pt.c:5623
-			 *     Please submit a full bug report.
-			 *     ...
-			 *
-			 *   So, we have to use template function specialization instead to solve this
-			 *   problem without a lot of ugly macro definitions.
-			 *
-			 *
-			 * template<ptrdiff_t... offsets>
-			 * struct OffsetHolder {
-			 *     static constexpr ptrdiff_t base_offsets[sizeof...(offsets)] = { offsets... };
-			 * };
-			 *
-			 * template<size_t total, typename BaseList, ptrdiff_t... offsets>
-			 * struct DoGenerateOffsets {
-			 *     using Result = typename DoGenerateOffsets<
-			 *         total,
-			 *         typename RemoveFirst<BaseList>::Rest,
-			 *         // There is a NullType at the end of the list, we should make
-			 *         // this consistent with value defined in GetBaseClassCount()
-			 *         GetBaseClassOffset<total - (BaseList::count - 1)>(),
-			 *         offsets...
-			 *     >::Result;
-			 * };
-			 *
-			 * template<size_t total, ptrdiff_t... offsets>
-			 * struct DoGenerateOffsets<total, List<NullType>, offsets...> {
-			 *     using Result = OffsetHolder<offsets...>;
-			 * };
-
-			 * struct GenerateOffsets {
-			 *     using Result = typename DoGenerateOffsets<
-			 *         GetBaseClassCount(), typename MakeList<T>::Result
-			 *     >::Result;
-			 * };
-			 *
-			 * void DoFix(void *ptr) {
-			 *     using OffsetArray = GenerateOffsets::Result;
-			 *     for (size_t i = 0; i < ARRAY_SIZE(OffsetArray::base_offsets); ++i) {
-			 *         const ptrdiff_t offset = OffsetArray::base_offsets[i];
-			 *         // do fix vptr here
-			 *     }
-			 * }
-			 *
-			 */
-
-			template<size_t>
-			struct Index2Type {};
-
-			template<size_t index>
-			void FillBaseTypeInfo(std::vector<BaseTypeInfo>* base_types, Index2Type<index>)
-			{
-				using BaseList = typename MakeList<T>::Result;
-				using BaseType = typename GetNthBaseClass<index, BaseList>::BaseType;
-				static constexpr const ptrdiff_t offset = GetBaseClassOffset<index>();
-				static_assert(offset >= 0, "invalid offset");
-
-				BaseTypeInfo info(typeid(BaseType).name(), offset);
-				base_types->push_back(info);
-				FillBaseTypeInfo(base_types, Index2Type<index + 1>());
-			}
-
-			void FillBaseTypeInfo(std::vector<BaseTypeInfo>*, Index2Type<GetBaseClassCount()>) {}
-
-			// This function means there is no base class for class T.
-			void DoFix(void* ptr, std::false_type, Index2Type<0>)
-			{
-				static constexpr const T* t = &static_object;
-
-				const uintptr_t* new_vptr = reinterpret_cast<const uintptr_t*>(reinterpret_cast<const char*>(t));
-				uintptr_t* old_vptr = reinterpret_cast<uintptr_t*>(reinterpret_cast<char*>(ptr));
-
-				if(!HasVptr<T>::value)
-				{
-					SHM_ERROR("object(%p), type(%s), no base type, vptr not found(%#lx : %#lx), at least one virtual function is required.",
-							  ptr, m_type.c_str(), *old_vptr, *new_vptr);
-					return;
-				}
-
-				SHM_DEBUG("object(%p), type(%s), no base type, old vptr(%#lx), new vptr(%#lx)", ptr, m_type.c_str(), *old_vptr, *new_vptr);
-				if(*old_vptr != *new_vptr)
-				{
-					*old_vptr = *new_vptr;
-				}
-			}
-
-			template<size_t index>
-			void DoFix(void* ptr, std::true_type, Index2Type<index>)
-			{
-				using BaseList = typename MakeList<T>::Result;
-				using BaseType = typename GetNthBaseClass<index, BaseList>::BaseType;
-
-				static constexpr const ptrdiff_t offset = GetBaseClassOffset<index>();
-				static constexpr const T* t = &static_object;
-
-				const uintptr_t* new_vptr = reinterpret_cast<const uintptr_t*>(reinterpret_cast<const char*>(t) + offset);
-				uintptr_t* old_vptr = reinterpret_cast<uintptr_t*>(reinterpret_cast<char*>(ptr) + offset);
-
-				TypeName base_type(typeid(BaseType).name());
-				if(!HasVptr<BaseType>::value)
-				{
-					SHM_ERROR("object(%p), type(%s), base type(%s), base index(%lu锛? offset(%#lx), vptr(%#lx : %#lx) not found, a virtual destructor is recommended.",
-							  ptr, m_type.c_str(), base_type.c_str(), index, offset, *old_vptr, *new_vptr);
-				}
-				else
-				{
-					SHM_DEBUG("object(%p), type(%s), base type(%s), base index(%lu锛? offset(%#lx), old vptr(%#lx), new vptr(%#lx)",
-							  ptr, m_type.c_str(), base_type.c_str(), index, offset, *old_vptr, *new_vptr);
-
-					if(*old_vptr != *new_vptr)
-					{
-						*old_vptr = *new_vptr;
-					}
-				}
-
-				DoFix(ptr, std::true_type(), Index2Type<index + 1>());
-			}
-
-			void DoFix(void*, std::true_type, Index2Type<GetBaseClassCount()>) {}
-		};
-		//template<typename T> const T VptrObjectContainer<T>::static_object = T();
-		template<typename T> const T VptrObjectContainer<T>::static_object;
-		template<typename T> const VptrObjectContainer<T> VptrObjectContainer<T>::static_container;
-
-		class VptrManager
-		{
-		public:
-			static bool Init();
-			static void Fini();
-			~VptrManager();
-
-			template<typename T, typename... Args>
-			static T* NewVptrObject(Args&&... args)
-			{
-				return NewVptrObjectExtraSpace<T>(0, std::forward<Args>(args)...);
-			}
-
-			template<typename T, typename... Args>
-			static T* NewVptrObjectExtraSpace(size_t extra_space, Args&&... args)
-			{
-				static_assert(HasVptr<T>::value, "type must be polymorphic or have vptr at least!");
-				const TypeName& type = VptrObjectContainer<T>::static_container.GetTypeName();
-
-				// Do not use static assertion here, sometimes it might not need a virtual destructor.
-				// static_assert(std::has_virtual_destructor<T>::value, "polymorphic type must have a virtual destructor!");
-				if(!std::has_virtual_destructor<T>::value)
-				{
-					SHM_ERROR("it's better to declare destructor virtual for polymorphic type(%s).", type.c_str());
-				}
-
-				void* ptr = NewSpace(sizeof(T) + extra_space);
-				if(SHM_LIKELY(ptr))
-				{
-					new (ptr) T(std::forward<Args>(args)...);
-					RecordObject(type, ptr);
-				}
-
-				return static_cast<T*>(ptr);
-			}
-
-			template<typename T>
-			static void DelVptrObject(T* ptr)
-			{
-				static_assert(HasVptr<T>::value, "type must be polymorphic or have vptr at least!");
-
-				if(SHM_LIKELY(ptr))
-				{
-					TypeName base_type(typeid(T).name());
-					TypeName real_type(typeid(*ptr).name());
-
-					void* real_ptr = GetRealPtr(base_type, real_type, ptr);
-					RemoveObject(real_type, real_ptr);
-					ptr->~T();
-					FreeSpace(real_ptr);
-				}
-			}
-
-			static void FixVptr();
-
-		private:
-			static void* NewSpace(size_t bytes);
-			static void FreeSpace(void* ptr);
-			static void* GetRealPtr(const TypeName& base_type, const TypeName& real_type, void* ptr);
-			static void RecordObject(const TypeName& type, void* ptr);
-			static void RemoveObject(const TypeName& type, void* ptr);
-
-		private:
-			template<typename Key, typename Value, typename Hash = std::hash<Key>, typename Pred = std::equal_to<Key>>
-			using Container = std::unordered_map<Key, Value, Hash, Pred, ShmAllocator<std::pair<const Key, Value>>>;
-			Container<TypeName, VptrObjectContainerBase*, TypeNameHasher> m_type_to_containers;
-		};
-
-	} // namespace detail
-} // namespace bg

+ 56 - 0
shm/metadata_allocator.h

@@ -0,0 +1,56 @@
+
+#pragma once
+#include "shm_config.h"
+namespace bg
+{
+    namespace detail
+    {
+        template<typename T>
+        class MetadataAllocator
+        {
+        public:
+            MetadataAllocator()
+            {
+                static_assert(sizeof(T) >= sizeof(void*), "type T too small");
+            }
+            void Destroy(T* free)
+            {
+                *(void**)free = m_free_list;
+                m_free_list = free;
+            }
+
+            T* Allocate()
+            {
+                T* free = reinterpret_cast<T*>(m_free_list);
+                if(free)
+                {
+                    m_free_list = *(void**)free;
+                    return free;
+                }
+
+                if(m_free_left >= sizeof(T))
+                {
+                    free = (T*)m_free_area;
+                    m_free_left -= sizeof(T);
+                    m_free_area += sizeof(T);
+                    return free;
+                }
+
+                size_t bytes = AREA_SIZE;
+                T* free_area = reinterpret_cast<T*>(bg::detail::ShmAllocateRawMemory(&bytes, PAGE_BYTES));
+
+                if(free_area)
+                {
+                    free = free_area;
+                    m_free_area = reinterpret_cast<char*>(&free_area[1]);
+                    m_free_left = bytes - sizeof(T);
+                }
+                return free;
+            }
+        private:
+            void* m_free_list{};
+            char* m_free_area{};
+            size_t m_free_left{};
+        };
+    }
+}

+ 305 - 0
shm/page_heap.cc

@@ -0,0 +1,305 @@
+#include "page_heap.h"
+#include "shm_helper.h"
+#include "size_map.h"
+#include "shm_config.h"
+#include "shm.h"
+#include <inttypes.h>
+namespace bg
+{
+    namespace detail
+    {
+        PageHeap::PageHeap()
+        {
+        }
+
+        bg::detail::Span* PageHeap::GetSpanMap(size_t start_page)
+        {
+            SHM_ASSERT_RETURN_NULL(start_page <= ShmConfig::MAX_PAGE_COUNT);
+
+            auto node1 = m_span_map.lv0[PTR_TO_LV0(start_page)];
+            if(node1 == nullptr)
+            {
+                return nullptr;
+            }
+
+            auto node2 = node1->lv1[PTR_TO_LV1(start_page)];
+            if(node2 == nullptr)
+            {
+                return nullptr;
+            }
+
+            auto node3 = node2->lv2[PTR_TO_LV2(start_page)];
+            return node3;
+        }
+
+        bool PageHeap::SetSpanMap(size_t page, bg::detail::Span* span)
+        {
+            SHM_ASSERT_RETURN_FALSE(page <= ShmConfig::MAX_PAGE_COUNT);
+
+            m_span_map.lv0[PTR_TO_LV0(page)]->lv1[PTR_TO_LV1(page)]->lv2[PTR_TO_LV2(page)] = span;
+            return true;
+        }
+
+        bg::detail::Span* PageHeap::AllocateSpan(size_t page_count)
+        {
+            auto span = GetListSpan(page_count);
+            if(!span)
+            {
+                if(!GrowHeap(page_count) || !(span = GetListSpan(page_count)))
+                {
+                    SHM_ERROR("cannot allocate span, page count: %lu.", page_count);
+                    return nullptr;
+                }
+
+            }
+            span->RemoveSelfForList();
+
+            do
+            {
+                int64_t diff = span->GetPageCount() - page_count;
+                if(diff == 0)
+                {
+                    break;
+                }
+
+                Span* free_list = m_span_allocator.Allocate();
+                if(!free_list)
+                {
+                    break;
+                }
+
+                span->SetPageCount(page_count);
+                if(page_count)
+                {
+                    SetSpanMap(span->GetLastPage(), span);
+                }
+
+                size_t start_page = span->GetLastPage() + 1;
+                new (free_list) Span(start_page, diff);
+                SetSpanMap(start_page, free_list);
+
+                Span* list = &m_large_list;
+                SetSpanMap(free_list->GetLastPage(), free_list);
+                if(diff <= 1 || diff < MAX_FREE_LIST_COUNT)
+                {
+                    list = &m_free_lists[diff];
+                }
+                list->InstertNextSpan(free_list);
+
+            } while(false);
+
+            span->SetUseState(true);
+            return span;
+        }
+
+
+        void PageHeap::DeallocateSpan(bg::detail::Span* s)
+        {
+            s->SetUseState(false);
+            bg::detail::Span* pre_span = GetSpanMap(s->GetStartPage() - 1);
+            if(pre_span && !pre_span->GetUseState())
+            {
+                s->LeftMovePages(pre_span->GetPageCount());
+
+                pre_span->RemoveSelfForList();
+                m_span_allocator.Destroy(pre_span);
+
+                SetSpanMap(s->GetStartPage(), s);
+            }
+
+            bg::detail::Span* next_span = GetSpanMap(s->GetLastPage() + 1);
+            if(next_span && !next_span->GetUseState())
+            {
+                s->RightMovePages(next_span->GetPageCount());
+
+                next_span->RemoveSelfForList();
+
+                m_span_allocator.Destroy(next_span);
+
+                SetSpanMap(s->GetLastPage(), s);
+            }
+
+            bg::detail::Span* p_list;
+            p_list = &m_large_list;
+            if(s->GetPageCount() < MAX_FREE_LIST_COUNT)
+            {
+                p_list = &m_free_lists[s->GetPageCount()];
+            }
+            p_list->InstertNextSpan(s);
+
+        }
+
+        void PageHeap::RegisterSpan(bg::detail::Span* span)
+        {
+            size_t start = span->GetStartPage() + 1;
+            size_t end = span->GetLastPage();
+            while(end > start)
+            {
+                size_t index = start;
+                if(!SetSpanMap(index, span))
+                {
+                    break;
+                }
+                ++start;
+            }
+        }
+
+        bool PageHeap::GrowHeap(size_t page_count)
+        {
+            size_t real_bytes{};
+            size_t page_start{};
+            void* rawmemoey{};
+            if(page_count > ShmConfig::MAX_PAGE_COUNT)
+            {
+                return false;
+            }
+
+            if(page_count >= MAX_FREE_LIST_COUNT)
+            {
+                real_bytes = PAGES_TO_BYTES(page_count);
+                rawmemoey = bg::detail::ShmAllocateRawMemory(&real_bytes, PAGE_BYTES);
+                if(!rawmemoey)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                real_bytes = DEFULT_ALLOC_BYTES;
+                rawmemoey = bg::detail::ShmAllocateRawMemory(&real_bytes, PAGE_BYTES);
+                if(!rawmemoey)
+                {
+                    real_bytes = PAGES_TO_BYTES(page_count);
+                    rawmemoey = bg::detail::ShmAllocateRawMemory(&real_bytes, PAGE_BYTES);
+                    if(!rawmemoey)
+                    {
+                        return false;
+                    }
+                }
+            }
+
+
+            if((int64_t)rawmemoey >> 48)
+            {
+                SHM_ERROR("cannot allocate enough space in span map, memory(%p, %#" PRIx64") leaked.", rawmemoey, real_bytes);
+                return false;
+            }
+
+            page_start = BYTES_TO_PAGES((int64_t)rawmemoey);
+            size_t real_pages = BYTES_TO_PAGES(real_bytes);
+            size_t page_end = page_start + real_pages;
+
+            size_t index = page_start;
+            for(; index < page_end; ++index)
+            {
+                size_t lv0_index = PTR_TO_LV0(index);
+                size_t lv1_index = PTR_TO_LV1(index);
+
+
+                if(m_span_map.lv0[lv0_index] == nullptr)
+                {
+                    size_t node1_size = sizeof(RadixTree::NodeV1);
+                    RadixTree::NodeV1* p_node1 = (RadixTree::NodeV1*)bg::detail::ShmAllocateRawMemory(
+                        &node1_size, sizeof(RadixTree::NodeV1));
+
+                    if(!p_node1)
+                    {
+                        break;
+                    }
+                    m_span_map.lv0[lv0_index] = p_node1;
+                    new (p_node1) RadixTree::NodeV1();
+
+                }
+                if(m_span_map.lv0[lv0_index]->lv1[lv1_index] == nullptr)
+                {
+                    size_t node2_size = sizeof(RadixTree::NodeV2);
+                    RadixTree::NodeV2* p_node2 = (RadixTree::NodeV2*)bg::detail::ShmAllocateRawMemory(&node2_size, sizeof(RadixTree::NodeV2));
+                    if(!p_node2)
+                    {
+                        break;
+                    }
+                    m_span_map.lv0[lv0_index]->lv1[lv1_index] = p_node2;
+                    new (p_node2) RadixTree::NodeV2();
+
+                }
+            }
+
+            if(index < page_end)
+            {
+                SHM_ERROR("cannot allocate new span, memory(%p, %#" PRIx64") leaked.", rawmemoey, real_bytes);
+                return false;
+            }
+
+            bg::detail::Span* new_span = m_span_allocator.Allocate();
+            if(!new_span)
+            {
+                SHM_ERROR("cannot allocate new span, memory(%p, %#" PRIx64") leaked.", rawmemoey, real_bytes);
+                return false;
+            }
+            new (new_span) Span(page_start, real_pages);
+
+            SetSpanMap(page_start, new_span);
+
+            if(real_pages > 1)
+            {
+                SetSpanMap(page_end - 1, new_span);
+            }
+
+            this->DeallocateSpan(new_span);
+            return true;
+        }
+
+
+
+        bg::detail::Span* PageHeap::GetSpanByFreeList(size_t page_count)
+        {
+            if(page_count < MAX_FREE_LIST_COUNT)
+            {
+                Span* free_span = &m_free_lists[page_count];
+
+                if(free_span->GetNextSpan() == free_span)
+                {
+                    for(free_span = &m_free_lists[page_count + 1]; free_span != &m_large_list; ++free_span)
+                    {
+                        if(free_span != free_span->GetNextSpan())
+                        {
+                            return free_span->GetNextSpan();
+                        }
+                    }
+                }
+                else
+                {
+                    return free_span->GetNextSpan();
+                }
+            }
+            return nullptr;
+        }
+
+        bg::detail::Span* PageHeap::GetSpanByLargeList(size_t page_count)
+        {
+            Span* result_span = nullptr;
+            if(m_large_list.GetNextSpan() != &m_large_list)
+            {
+                for(Span* free_span = m_large_list.GetNextSpan(); &m_large_list != free_span; free_span = free_span->GetNextSpan())
+                {
+                    if(page_count > free_span->GetPageCount())
+                    {
+                        continue;
+                    }
+                    if(!result_span || free_span->GetPageCount() < result_span->GetPageCount() ||
+                       (result_span->GetPageCount() == free_span->GetPageCount() && free_span->GetStartPage() < result_span->GetStartPage()))
+                    {
+                        result_span = free_span;
+                    }
+
+                }
+
+            }
+            return result_span;
+        }
+
+
+    }
+
+
+}

+ 72 - 0
shm/page_heap.h

@@ -0,0 +1,72 @@
+#pragma once
+#include "span.h"
+#include "metadata_allocator.h"
+#define PTR_TO_LV0(ptr)	(ptr) >> 25
+#define PTR_TO_LV1(ptr)	((ptr) >> 15 & 0x3FF)
+#define PTR_TO_LV2(ptr)	((ptr) & 0x7FFF)
+namespace bg
+{
+    namespace detail
+    {
+        template<size_t size0, size_t size1, size_t size2>
+        struct RadixTree
+        {
+
+            struct  NodeV2
+            {
+                Span* lv2[1 << size2]{0};
+            };
+            struct NodeV1
+            {
+                NodeV2* lv1[1 << size1]{0};
+            };
+
+            NodeV1* lv0[1 << size0]{0};
+        };
+
+        class PageHeap
+        {
+        public:
+            PageHeap();
+
+            bg::detail::Span* GetSpanMap(size_t start_page);
+
+            bg::detail::Span* AllocateSpan(size_t page_count);
+
+            void DeallocateSpan(bg::detail::Span* s);
+
+            void RegisterSpan(bg::detail::Span* s);
+        private:
+
+            bool SetSpanMap(size_t page, bg::detail::Span* span);
+
+            bool GrowHeap(size_t page_count);
+
+            bg::detail::Span* GetSpanByFreeList(size_t page_count);
+
+            bg::detail::Span* GetSpanByLargeList(size_t page_count);
+
+            bg::detail::Span* GetListSpan(size_t page_count)
+            {
+                Span* result = nullptr;
+                result = GetSpanByFreeList(page_count);
+                if(!result)
+                {
+                    result = GetSpanByLargeList(page_count);
+                }
+                return result;
+            }
+
+            using  RadixTree = RadixTree<10ul, 10ul, 15ul>;
+        private:
+
+            static constexpr size_t MAX_FREE_LIST_COUNT = 128;
+            static constexpr size_t DEFULT_ALLOC_BYTES = PAGES_TO_BYTES(MAX_FREE_LIST_COUNT);
+
+            RadixTree m_span_map;
+            MetadataAllocator<bg::detail::Span> m_span_allocator;
+            Span m_free_lists[128]{};
+            Span m_large_list{};
+        };
+    }
+}

+ 0 - 0
Project4/shm.cc → shm/shm.cc


+ 0 - 0
Project4/shm.h → shm/shm.h


+ 28 - 0
shm/shm_config.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#define PAGE_BYTES 0x2000LL                                     // 一页字节
+#define CLASS_TOTAL_BYTES 0x4000                                // class预先申请大小标准
+#define CLASS_MAX_BYTES 0x40000                                 // class 最大字节数
+#define MAX_CLASS_COUNT  8					                    // 最多预先初始化几个内存				  
+
+#define MAX_SHM_BLOCK_COUNT 0xff                                 
+#define AREA_SIZE 0x20000LL                                
+
+#define BYTES_TO_PAGES(bytes)    ((bytes) >> 13)
+#define PAGES_TO_BYTES(page)    ((page) << 13)
+
+#define PALIGN_DOWN(x, align) ((x) & ~((align) - 1))
+#define PALIGN_UP(x, align) (((x) + ((align) - 1)) & (~((align) - 1)))
+
+namespace bg
+{
+    namespace detail
+    {
+        namespace ShmConfig
+        {
+            constexpr size_t MAX_PAGE_COUNT = 0x7FFFFFFFFLL;
+        }
+    }
+
+
+}

+ 96 - 0
shm/shm_helper.cc

@@ -0,0 +1,96 @@
+#include "vptr_manager.h"
+#include "shm_manager.h"
+#include <stdarg.h>
+extern bg::detail::ShmContext g_shm_ctx;
+
+bg::detail::TypeName::TypeName(const char* type, size_t size /*= 0*/)
+{
+    if(size)
+    {
+        snprintf(m_type, MAX_TYPE_NAME_LENGTH, "%s[%#zux]", type, size);
+    }
+    else
+    {
+        snprintf(m_type, MAX_TYPE_NAME_LENGTH, "%s", type);
+    }
+}
+
+void bg::detail::ShmLog(ShmLogLevel level, const char* file, size_t line, const char* func, const char* fmt, ...)
+{
+    va_list args; // [rsp+8h] [rbp-E8h] BYREF
+    static char buf[0x2000uLL];
+    va_start(args, fmt);
+    vsnprintf(buf, 0x2000uLL, fmt, args);
+    va_end(args);
+    g_shm_ctx.logger(level, file, line, func, buf);
+}
+
+void bg::detail::ShmStdoutLog(ShmLogLevel level, const char* file, size_t line, const char* func, const char* msg)
+{
+    static const char* levels[] = {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
+    printf(
+    "[%s:%zu(%s)][%s] %s\n",
+    file,
+    line,
+    func,
+    levels[level],
+    msg);
+}
+
+void* bg::detail::ShmAllocate(size_t bytes, const void* ptr)
+{
+    return (void*)bg::ShmMalloc(bytes);
+}
+
+void bg::detail::ShmDeallocate(void* ptr, size_t size)
+{
+    bg::ShmFree(ptr);
+}
+
+uint64_t bg::detail::ShmCurrentVersion()
+{
+    if(g_shm_ctx.mgr)
+    {
+        return g_shm_ctx.mgr->GetVersion();
+    }
+
+    SHM_ERROR("shm management system uninitialized.");
+    return 0ll;
+}
+
+void* bg::detail::ShmAllocateRawMemory(size_t* bytes, size_t alignment)
+{
+    if(g_shm_ctx.mgr)
+    {
+        return g_shm_ctx.mgr->AllocateRawMemory(bytes, alignment);
+    }
+
+    return nullptr;
+}
+
+bool bg::detail::ShmHasSingleton(const TypeName& type)
+{
+    if(g_shm_ctx.mgr)
+    {
+        return g_shm_ctx.mgr->HasSingleton(type);
+    }
+    return false;
+}
+
+void* bg::detail::ShmGetSingleton(const TypeName& type, size_t bytes, bool* first_call)
+{
+    if(g_shm_ctx.mgr)
+    {
+        return g_shm_ctx.mgr->GetSingleton(type, bytes, first_call);
+    }
+    return nullptr;
+}
+
+void bg::detail::ShmFreeSingleton(const TypeName& type)
+{
+    if(g_shm_ctx.mgr)
+    {
+        return g_shm_ctx.mgr->FreeSingleton(type);
+    }
+    return;
+}

+ 0 - 0
Project4/shm_helper.h → shm/shm_helper.h


+ 544 - 0
shm/shm_manager.cc

@@ -0,0 +1,544 @@
+#include "shm_manager.h"
+#include "shm_object.h"
+#include "shm_config.h"
+#include <inttypes.h>
+
+extern bg::detail::ShmContext g_shm_ctx;
+namespace bg
+{
+    namespace detail
+    {
+
+        ShmManager::ShmManager(const bg::ShmOptions& options) : m_options(options)
+        {
+            snprintf(this->m_magic, 0x40uLL, "ByteGame/ShmManager-%s", this->m_options.identifier);
+        }
+
+        ShmManager::~ShmManager()
+        {
+            if(m_singletons)
+            {
+                m_singletons->clear();
+                bg::ShmFree(m_singletons);
+                this->m_singletons = nullptr;
+            }
+            for(size_t i = 0LL; this->m_block_count > i; ++i)
+            {
+                DeleteBlock(i);
+            }
+        }
+
+        void* ShmManager::AllocateRawMemory(size_t* bytes, size_t alignment)
+        {
+            void* result = nullptr;
+            if((alignment & (alignment - 1)) != 0)
+            {
+                SHM_ERROR("invalid alignment(%#" PRIx64").", alignment);
+                return result;
+            }
+            *bytes = PALIGN_UP(*bytes, alignment);
+
+            if(m_block_count)
+            {
+                result = AllocateInBlock(m_block_count - 1, *bytes, alignment);
+                if(result)
+                {
+                    return result;
+                }
+
+            }
+            if(CreateBlock(m_block_count, *bytes))
+            {
+                size_t index = m_block_count > 1 ? m_block_count - 1 : 0;
+                result = AllocateInBlock(index, *bytes, alignment);
+                if(!result)
+                {
+                    SHM_ERROR("newly created block(%lu) still cannot satisfy requirement, addr(%#" PRIx64"), used size(%#" PRIx64"), real size(%#" PRIx64"), real bytes(%#" PRIx64"), alignment(%#" PRIx64").",
+                    m_block_count, m_blocks[index].addr, m_blocks[index].used_size, m_blocks[index].real_size);
+                    return result;
+                }
+
+            }
+            else
+            {
+                SHM_ERROR("failed to create block(%lu), real bytes(%#" PRIx64").", this->m_block_count, *bytes);
+            }
+            return result;
+        }
+
+        bool ShmManager::HasSingleton(const bg::detail::TypeName& type)
+        {
+            auto itor = m_singletons->find(type);
+            if(itor == m_singletons->end())
+            {
+                return false;
+            }
+            return true;
+        }
+
+        void* ShmManager::GetSingleton(const bg::detail::TypeName& type, size_t bytes, bool* first_call)
+        {
+            if(!m_singletons)
+            {
+                m_singletons = (bg::detail::ShmManager::SingletonMap*)bg::ShmMalloc(sizeof(bg::detail::ShmManager::SingletonMap));
+                if(!m_singletons)
+                {
+                    m_singletons = nullptr;
+                    return nullptr;
+                }
+
+                new(m_singletons) SingletonMap();
+            }
+
+            auto itor = m_singletons->find(type);
+            if(itor != m_singletons->end())
+            {
+                return itor->second;
+            }
+
+            void* memory = ShmMalloc(bytes);
+            if(!memory)
+            {
+                return nullptr;
+            }
+
+            m_singletons->operator[](type) = memory;
+            if(first_call)
+            {
+                *first_call = 1;
+                SHM_INFO("singleton(%s: %p) created.", type.c_str(), memory);
+            }
+            return memory;
+        }
+
+        void ShmManager::FreeSingleton(const bg::detail::TypeName& type)
+        {
+            if(m_singletons)
+            {
+                auto itor = m_singletons->find(type);
+                if(itor == m_singletons->end())
+                {
+                    return;
+                }
+                SHM_INFO("singleton(%s: %p) destroyed.", type.c_str(), itor->second);
+
+                Free(itor->second);
+                m_singletons->erase(itor);
+
+            }
+
+            return;
+
+        }
+
+        bool ShmManager::OnResume(const char* identifier)
+        {
+            char magic[64]; // [rsp+0h] [rbp-60h] BYREF
+
+            int size = snprintf(magic, 0x40uLL, "ByteGame/ShmManager-%s", identifier);
+            if(!strncmp(magic, this->m_magic, size))
+            {
+                size_t index = 0;
+                for(; index < m_block_count; ++index)
+                {
+                    if(!AttachBlock(index))
+                    {
+                        SHM_ERROR("failed to attach block(%lu), address(%#" PRIx64"), used size(%#" PRIx64"), real size(%#" PRIx64"), mmap size(%#" PRIx64").", index, m_blocks[index].addr, m_blocks[index].used_size, m_blocks[index].real_size, m_blocks[index].mmap_size);
+                        return false;
+                    }
+
+                }
+                if(m_block_count <= index)
+                {
+                    m_version++;
+                    return true;
+                }
+            }
+
+            SHM_ERROR("magic mismatch, expected: %s, actual: %s.", magic, this->m_magic);
+            return false;
+        }
+
+        bool ShmManager::OnCreate(void)
+        {
+            return m_size_map.Init();
+        }
+
+        void* ShmManager::Malloc(size_t bytes)
+        {
+            if(bytes > CLASS_MAX_BYTES)
+            {
+                bg::detail::Span* span = m_page_heap.AllocateSpan(BYTES_TO_PAGES(bytes + PAGE_BYTES));
+                if(span)
+                {
+                    return (void*)PAGES_TO_BYTES(span->GetStartPage());
+                }
+                return nullptr;
+            }
+
+            size_t index = m_size_map.GetClassByBytes(bytes);
+
+            SHM_ASSERT_RETURN_NULL(index < CLASS_MAX_COUNT);
+            return AllocateChunk(index);
+        }
+
+        void ShmManager::Free(void* ptr)
+        {
+            bg::detail::Span* span = m_page_heap.GetSpanMap(BYTES_TO_PAGES((uintptr_t)ptr));
+            SHM_ASSERT_RETURN_VOID(span);
+            if(span->GetSizeClass() == MAX_SHM_BLOCK_COUNT)
+            {
+                m_page_heap.DeallocateSpan(span);
+            }
+            else
+            {
+                DeallocateChunk(span, ptr);
+            }
+
+        }
+
+        void* ShmManager::Realloc(void* old_ptr, size_t new_bytes)
+        {
+            if(!old_ptr)
+            {
+                return bg::ShmMalloc(new_bytes);
+            }
+            if(!new_bytes)
+            {
+                bg::ShmFree((void*)old_ptr);
+                return nullptr;
+            }
+
+            bg::detail::Span* span = m_page_heap.GetSpanMap(BYTES_TO_PAGES((uintptr_t)old_ptr));
+            SHM_ASSERT_RETURN_NULL(span);
+            size_t old_size = 0;
+            if(span->GetSizeClass() == MAX_SHM_BLOCK_COUNT)
+            {
+                old_size = PAGES_TO_BYTES(span->GetPageCount());
+            }
+            else
+            {
+                old_size = m_size_map.ClassToSize(span->GetSizeClass());
+            }
+
+            if(new_bytes >= (old_size >> 1) && new_bytes <= old_size)
+            {
+                return old_ptr;
+            }
+
+            void* new_ptr = g_shm_ctx.mgr->Malloc(new_bytes);
+            if(!new_ptr)
+            {
+                return nullptr;
+            }
+
+            memcpy(new_ptr, (const void*)old_ptr, old_size);
+            g_shm_ctx.mgr->Free(old_ptr);
+            return new_ptr;
+        }
+
+        void* ShmManager::Calloc(size_t n, size_t bytes)
+        {
+            size_t toal_bytes = bytes * n;
+            if(bytes && n != toal_bytes / bytes)
+            {
+                return nullptr;
+            }
+            void* memory = Malloc(toal_bytes);
+            if(memory)
+            {
+                memset(memory, 0, toal_bytes);
+            }
+
+            return memory;
+        }
+
+        bool ShmManager::DeleteBlock(size_t index)
+        {
+            SHM_ASSERT_RETURN_FALSE(index < m_block_count);
+            char path[256];
+            if(m_blocks[index].addr)
+            {
+                m_options.AddFixedAddress((uintptr_t)m_blocks[index].addr);
+                snprintf(path, 0x100uLL, "%s-%03zu.mmap", this->m_options.identifier, index);
+                bg::detail::ShmObjectDelete(m_blocks[index].addr, m_blocks[index].mmap_size, path);
+                SHM_INFO("block(%lu) deleted, address(%#" PRIx64"), used size(%#" PRIx64"), real size(%#" PRIx64"), mmap size(%#" PRIx64"), path(%s).",
+                         index, m_blocks[index].addr, m_blocks[index].used_size, m_blocks[index].real_size, m_blocks[index].mmap_size, path);
+                m_blocks[index].addr = nullptr;
+            }
+
+
+            return true;
+        }
+
+        void* ShmManager::AllocateInBlock(size_t index, size_t bytes, size_t alignment)
+        {
+            SHM_ASSERT_RETURN_NULL(index < m_block_count);
+            uintptr_t addr_ptr = (uintptr_t)m_blocks[index].addr;
+            uintptr_t ptr = addr_ptr + m_blocks[index].used_size;
+            ptr = PALIGN_UP(ptr, alignment);
+            uintptr_t new_ptr = ptr + bytes;
+
+            if(new_ptr > m_blocks[index].mmap_size + addr_ptr)
+            {
+                return nullptr;
+            }
+            do
+            {
+                if(m_blocks[index].real_size + addr_ptr >= new_ptr)
+                {
+                    break;
+                }
+                size_t new_size = m_options.shm_block_grow_size + m_blocks[index].real_size;
+                if(new_ptr > new_size + addr_ptr)
+                {
+                    new_size = new_ptr - addr_ptr;
+                    new_size = PALIGN_UP(new_size, m_options.shm_block_grow_size);
+                }
+                new_size = std::min(new_size, m_blocks[index].mmap_size);
+
+                if(ResizeBlock(index, new_size))
+                {
+                    break;
+                }
+                SHM_ERROR("failed to resize block(%lu), used size(%#" PRIx64"), real size(%#" PRIx64"), mmap size(%#" PRIx64"), new size(%#" PRIx64").",
+                          index, m_blocks[index].used_size, m_blocks[index].real_size, m_blocks[index].mmap_size, new_size);
+                return nullptr;
+
+            } while(false);
+
+            m_blocks[index].used_size = new_ptr - addr_ptr;
+            return (void*)ptr;
+        }
+
+        bool ShmManager::CreateBlock(size_t index, size_t min_size)
+        {
+            char path[256];
+            SHM_ASSERT_RETURN_FALSE(index < MAX_SHM_BLOCK_COUNT);
+
+            size_t real_size = std::max(min_size, m_options.shm_block_grow_size);
+            size_t mmap_size = std::max(min_size, m_options.shm_block_mmap_size);
+            uintptr_t fixed_addr = 0ll;
+            if(!m_options.PopFixedAddress(&fixed_addr))
+            {
+                SHM_WARN("fixed addresses have been used up.");
+            }
+
+            snprintf(path, 0x100uLL, "%s-%03zu.mmap", this->m_options.identifier, index);
+            void* memory = bg::detail::ShmObjectCreate(path, fixed_addr, &real_size, &mmap_size);
+            if(!memory)
+            {
+
+                if(fixed_addr)
+                {
+                    m_options.AddFixedAddress(fixed_addr);
+                }
+                return false;
+            }
+
+            m_blocks[index].mmap_size = mmap_size;
+            m_blocks[index].real_size = real_size;
+            m_blocks[index].used_size = 0;
+            m_blocks[index].addr = memory;
+            SHM_INFO("block(%" SCNu64") created, address(%#" PRIx64"), real size(%#" PRIx64"), mmap size(%#" PRIx64").", index, memory, real_size, mmap_size);
+
+            if(this->m_block_count != index)
+            {
+                return true;
+            }
+
+            this->m_block_count = index + 1;
+
+            return true;
+        }
+
+        bool ShmManager::AttachBlock(size_t index)
+        {
+            char path[256];
+            SHM_ASSERT_RETURN_FALSE(index < m_block_count);
+            if(m_blocks[index].addr)
+            {
+                size_t real_size = m_blocks[index].real_size;
+                size_t mmap_size = m_blocks[index].mmap_size;
+                snprintf(path, 0x100uLL, "%s-%03zu.mmap", this->m_options.identifier, index);
+                void* memory = bg::detail::ShmObjectAttach(path, (uintptr_t)m_blocks[index].addr, &real_size, &mmap_size);
+                return memory != nullptr;
+            }
+
+            return true;
+        }
+
+        bool ShmManager::ResizeBlock(size_t index, size_t new_size)
+        {
+            char path[256]; // [rsp+10h] [rbp-120h] BYREF
+            SHM_ASSERT_RETURN_FALSE(index < m_block_count);
+
+            if(m_blocks[index].mmap_size < new_size)
+            {
+                SHM_ERROR("new size(%#" PRIx64") too large, block(%lu), mmap size(%#" PRIx64").", new_size, index, m_blocks[index].mmap_size);
+                return false;
+            }
+            else
+            {
+                snprintf(path, 0x100uLL, "%s-%03zu.mmap", this->m_options.identifier, index);
+                if(bg::detail::ShmObjectResize(path, &new_size))
+                {
+                    SHM_INFO("block(%lu) resized, old size(%#" PRIx64"), new size(%#" PRIx64"), used size(%#" PRIx64"), mmap size(%#" PRIx64").",
+                             index, m_blocks[index].addr, m_blocks[index].real_size, new_size, m_blocks[index].used_size, m_blocks[index].mmap_size);
+                    this->m_blocks[index].real_size = new_size;
+                    return true;
+                }
+
+            }
+            return false;
+        }
+
+        void* ShmManager::AllocateChunk(size_t index)
+        {
+            ChunkCache::ClassCache* cache = &m_chunk_cache.m_caches[index];
+            if(cache == (bg::detail::ChunkCache::ClassCache*)cache->free_list.GetNextSpan())
+            {
+                ChunkCache::ClassCache* cheche = &this->m_chunk_cache.m_caches[index];
+                size_t size = this->m_size_map.ClassToSize(index);
+
+                bg::detail::Span* span = m_page_heap.AllocateSpan(m_size_map.ClassToPages(index));
+                if(span)
+                {
+                    m_page_heap.RegisterSpan(span);
+                    span->SetSizeClass(static_cast<uint8_t>(index));
+
+                    span->SetChunkList((void*)PAGES_TO_BYTES(span->GetStartPage()));
+
+                    uintptr_t end_memory = (uintptr_t)PAGES_TO_BYTES(span->GetLastPage());
+
+                    uintptr_t end_ptr = (uintptr_t)span->GetChunkList() + size;
+
+                    uintptr_t start_ptr = (uintptr_t)span->GetChunkList();
+
+                    uintptr_t ptr = start_ptr;
+
+                    for(; end_ptr <= end_memory; )
+                    {
+                        ptr = start_ptr;
+                        *((uintptr_t*)start_ptr) = end_ptr;
+                        auto temp = end_ptr + size;
+                        start_ptr = end_ptr;
+                        end_ptr += size;
+                    }
+
+                    *(uintptr_t*)ptr = 0ll;
+                    cheche->free_list.InstertNextSpan(span);
+                    ++cheche->span_count;
+                }
+            }
+
+            if(cache == (bg::detail::ChunkCache::ClassCache*)cache->free_list.GetNextSpan())
+            {
+                return nullptr;
+            }
+
+            auto free_span = cache->free_list.GetNextSpan();
+            free_span->IncUsedCount();
+
+            auto chunk_span = free_span->GetChunkList();
+            free_span->SetChunkList(*(void**)chunk_span);
+            if(free_span->GetChunkList() == nullptr)
+            {
+                cache->free_list.RemoveNextSpan();
+                --this->m_chunk_cache.m_caches[index].span_count;
+            }
+            return chunk_span;
+        }
+
+        void ShmManager::DeallocateChunk(bg::detail::Span* span, void* ptr)
+        {
+            SHM_ASSERT_RETURN_VOID(span->GetUsedCount() > 0 && span->GetSizeClass() < CLASS_MAX_COUNT);
+
+            span->DecUsedCout();
+            auto chunk_list = span->GetChunkList();
+            *(uintptr_t*)ptr = (uintptr_t)chunk_list;
+            span->SetChunkList(ptr);
+
+            if(chunk_list)
+            {
+                if(span->GetUsedCount() == 0)
+                {
+                    if(m_chunk_cache.m_caches[span->GetSizeClass()].span_count > 1)
+                    {
+                        span->RemoveSelfForList();
+                        --m_chunk_cache.m_caches[span->GetSizeClass()].span_count;
+                        span->SetSizeClass(MAX_SHM_BLOCK_COUNT);
+                        span->SetChunkList(nullptr);
+                        m_page_heap.DeallocateSpan(span);
+                        return;
+                    }
+                }
+            }
+            else
+            {
+                if(span->GetUsedCount() == 0)
+                {
+                    if(m_chunk_cache.m_caches[span->GetSizeClass()].span_count)
+                    {
+                        span->SetSizeClass(MAX_SHM_BLOCK_COUNT);
+                        span->SetChunkList(nullptr);
+                        m_page_heap.DeallocateSpan(span);
+                        return;
+                    }
+
+                }
+                m_chunk_cache.m_caches[span->GetSizeClass()].free_list.GetNextSpan()->InstertNextSpan(span);
+                m_chunk_cache.m_caches[span->GetSizeClass()].span_count++;
+            }
+
+        }
+
+
+    }
+
+    void* ShmMalloc(size_t bytes)
+    {
+        if(!g_shm_ctx.mgr)
+        {
+            SHM_ERROR("shm management system uninitialized.");
+            return nullptr;
+        }
+
+        return g_shm_ctx.mgr->Malloc(bytes);
+    }
+
+    void ShmFree(void* ptr)
+    {
+        if(!g_shm_ctx.mgr)
+        {
+            SHM_ERROR("shm management system uninitialized.");
+            return;
+        }
+        g_shm_ctx.mgr->Free(ptr);
+        return;
+    }
+
+    void* ShmRealloc(void* old_ptr, size_t new_bytes)
+    {
+        if(!g_shm_ctx.mgr)
+        {
+            SHM_ERROR("shm management system uninitialized.");
+            return nullptr;
+        }
+        return g_shm_ctx.mgr->Realloc(old_ptr, new_bytes);
+    }
+
+    void* ShmCalloc(size_t n, size_t bytes)
+    {
+        if(!g_shm_ctx.mgr)
+        {
+            SHM_ERROR("shm management system uninitialized.");
+            return nullptr;
+        }
+        return g_shm_ctx.mgr->Calloc(n, bytes);
+    }
+
+}
+
+
+

+ 26 - 5
Project4/shm_manager.h → shm/shm_manager.h

@@ -34,8 +34,13 @@ namespace bg
             };
             ShmManager(const bg::ShmOptions&);
             ~ShmManager();
-            void* AllocateRawMemory(size_t* bytes, size_t alignment);
 
+            uint64_t GetVersion()
+            {
+                return m_version;
+            }
+
+            void* AllocateRawMemory(size_t* bytes, size_t alignment);
 
             bool HasSingleton(const bg::detail::TypeName& type);
 
@@ -47,6 +52,16 @@ namespace bg
 
             bool OnCreate(void);
 
+            void* Malloc(size_t bytes);
+
+            void Free(void* ptr);
+
+            void* Realloc(void* ptr, size_t new_bytes);
+
+            void* Calloc(size_t n, size_t bytes);
+
+        private:
+
             bool DeleteBlock(size_t index);
 
             void* AllocateInBlock(size_t index, size_t bytes, size_t alignment);
@@ -55,21 +70,27 @@ namespace bg
 
             bool AttachBlock(size_t index);
 
-            bool ResizeBlock(size_t index, const char* new_size);
+            bool ResizeBlock(size_t index, size_t new_size);
+
+            void* AllocateChunk(size_t index);
+
+            void DeallocateChunk(bg::detail::Span* span, void* ptr);
+
 
-            using SingletonMap = std::map<TypeName, void*, std::equal_to<TypeName>, ShmAllocator<std::pair<const TypeName, void*>>>;
 
+            using SingletonMap = std::map<TypeName, void*, std::less<TypeName>, ShmAllocator<std::pair<const TypeName, void*>>>;
+        private:
             ChunkCache m_chunk_cache;
             SizeMap m_size_map;
             char m_magic[64]{};
             PageHeap m_page_heap;
 
-            uint64_t m_version = 0;
+            uint64_t m_version = 1;
             size_t m_block_count = 0;
             SingletonMap* m_singletons{};
 
             ShmOptions m_options;
-            ShmBlock m_blocks[256];
+            ShmBlock m_blocks[256]{};
 
         };
 

+ 35 - 41
Project4/shm_object.cc → shm/shm_object.cc

@@ -1,5 +1,6 @@
 #include "shm_object.h"
 #include "shm_manager.h"
+#include <inttypes.h>
 #if defined(__GNUC__)
 #include <sys/types.h>
 #include <dirent.h>
@@ -37,7 +38,7 @@ namespace bg
                         goto RETURN;
                     }
                     *total_size += st.st_dev;
-                    SHM_INFO("directory entry %s, size: %#lx", full_path, st.st_dev);
+                    SHM_INFO("directory entry %s, size: %#" PRIx64"", full_path, st.st_dev);
                 }
 READ_DIR:
                 diren = readdir64(path_dir);
@@ -55,7 +56,7 @@ READ_DIR:
             if(!_lxstat64(1, full_path, (struct stat64*)&st))
             {
                 *total_size += st.st_size;
-                SHM_TRACE("file entry %s, size: %#lx", full_path, st.st_size);
+                SHM_TRACE("file entry %s, size: %#" PRIx64"", full_path, st.st_size);
                 goto READ_DIR;
             }
 
@@ -101,7 +102,7 @@ OPEN_SUCC:
 
             if(!bg::detail::GetAvailableMemorySize(available_size) || available_size < *real_size)
             {
-                SHM_ERROR("shared memory not enough, available: %#lx, required: %#lx.", available_size, *real_size);
+                SHM_ERROR("shared memory not enough, available: %#" PRIx64", required: %#" PRIx64".", available_size, *real_size);
                 close(fd);
                 shm_unlink(path);
                 return nullptr;
@@ -112,7 +113,7 @@ OPEN_SUCC:
                 int flag;
                 if(*mmap_size < *real_size)
                 {
-                    SHM_INFO("mmap size(%#lx) is not enough, revised to real size(%#lx).", *mmap_size, *real_size);
+                    SHM_INFO("mmap size(%#" PRIx64") is not enough, revised to real size(%#" PRIx64").", *mmap_size, *real_size);
                     *mmap_size = *real_size;
                 }
                 *mmap_size = PALIGN_UP(*mmap_size, page_size);
@@ -122,7 +123,7 @@ OPEN_SUCC:
                     if(fixed_addr & (page_size - 1))
                     {
                         uintptr_t new_addr = PALIGN_UP(fixed_addr, page_size);
-                        SHM_INFO("ixed address(%#lx) is not aligned to page size(%#lx), revised to %#lx.", fixed_addr, page_size, new_addr);
+                        SHM_INFO("ixed address(%#" PRIx64") is not aligned to page size(%#" PRIx64"), revised to %#" PRIx64".", fixed_addr, page_size, new_addr);
                         fixed_addr = new_addr;
                     }
                     flag = MAP_SHARED;
@@ -140,11 +141,11 @@ LABEL_13:
                     return mem;
                 }
 
-                SHM_ERROR("mmap() failed, addr(% #lx), size(% #lx), error: % s.", old, *mmap_size), strerror(*_errno_location()));
+                SHM_ERROR("mmap() failed, addr(% #" PRIx64"), size(% #" PRIx64"), error: % s.", old, *mmap_size), strerror(*_errno_location()));
             }
             else
             {
-                SHM_ERROR("ftruncate() failed, path: % s, size : % #lx, error: % s.", path, *real_size, strerror(*_errno_location()));
+                SHM_ERROR("ftruncate() failed, path: % s, size : % #" PRIx64", error: % s.", path, *real_size, strerror(*_errno_location()));
             }
 
             close(v7);
@@ -170,7 +171,7 @@ LABEL_17:
                 *real_size = st.st_size;
                 if(st_size > *mmap_size)
                 {
-                    SHM_INFO("mmap size(% #lx) is not enough, revised to real size(% #lx).", *mmap_size, st_size, *real_size);
+                    SHM_INFO("mmap size(% #" PRIx64") is not enough, revised to real size(% #" PRIx64").", *mmap_size, st_size, *real_size);
                     *mmap_size = *real_size;
                 }
 
@@ -181,7 +182,7 @@ LABEL_17:
                     if(fixed_addr & (page_size - 1))
                     {
                         uintptr_t new_addr = PALIGN_UP(fixed_addr, page_size);
-                        SHM_INFO("fixed address(%#lx) is not aligned to page size(%#lx), revised to %#lx.", fixed_addr, page_size, new_addr);
+                        SHM_INFO("fixed address(%#" PRIx64") is not aligned to page size(%#" PRIx64"), revised to %#" PRIx64".", fixed_addr, page_size, new_addr);
                     }
 
                     flag = MAP_SHARED;
@@ -198,7 +199,7 @@ LABEL_9:
                     return memory;
                 }
 
-                SHM_ERROR("mmap() failed, addr(%#lx), size(%#lx), error: %s.", memory, *mmap_size, strerror(*_errno_location()));
+                SHM_ERROR("mmap() failed, addr(%#" PRIx64"), size(%#" PRIx64"), error: %s.", memory, *mmap_size, strerror(*_errno_location()));
                 close(fd);
                 return nullptr;
             }
@@ -213,7 +214,7 @@ LABEL_9:
             if(munmap(addr, mmap_size))
             {
                 strerror(*v5);
-                SHM_ERROR("munmap() failed, addr(%p), mmap size(%#lx), error: %s.", addr, mmap_size, strerror(_errno_location()));
+                SHM_ERROR("munmap() failed, addr(%p), mmap size(%#" PRIx64"), error: %s.", addr, mmap_size, strerror(_errno_location()));
             }
             if(path)
             {
@@ -265,11 +266,11 @@ TRUNCAT:
                                     return true;
                                 }
 
-                                SHM_ERROR("ftruncate() failed, path: %s, size: %#lx, error: %s.", path, *new_size, strerror(*_errno_location()));
+                                SHM_ERROR("ftruncate() failed, path: %s, size: %#" PRIx64", error: %s.", path, *new_size, strerror(*_errno_location()));
 
                                 goto FAIL;
                             }
-                            SHM_ERROR("shared memory not enough, available: %#lx, required: %#lx.", available_size, diff);
+                            SHM_ERROR("shared memory not enough, available: %#" PRIx64", required: %#" PRIx64".", available_size, diff);
                         }
                     }
                 }
@@ -318,7 +319,7 @@ FAIL:
 #include <windows.h>
 #include <Psapi.h>
 
-static std::unordered_map<std::string, HANDLE> g_mapping_handles;
+static std::unordered_map<void*, HANDLE> g_mapping_handles;
 
 namespace bg
 {
@@ -346,17 +347,15 @@ namespace bg
             size_t align = pagesize - 1;
 
             *real_size = PALIGN_UP(*real_size, pagesize);
-            /*size_t available_size;
-            if(!GetAvailableMemorySize(&available_size))
+            *mmap_size = PALIGN_UP(*mmap_size, pagesize);
+
+            // windows 下没有找到动态扩展共享内存办法 所以一开始就申请满把
+            if(*mmap_size != *real_size)
             {
-                SHM_ASSERT(false && "ShmObjectCreate GetAvailableMemorySize FAIL");
-                return nullptr;
+                SHM_WARN("real size(%#llx) is not enough, revised to mmap size(%#llx).", *real_size, *mmap_size);
+                *real_size = *mmap_size;
             }
-            if(*real_size > available_size)
-            {
-                SHM_ERROR("shared memory not enough, available: %#lx, required: %#lx.", available_size, *real_size);
-                return nullptr;
-            }*/
+
 
             HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
                                    (uint32_t)(*real_size >> 32),
@@ -365,7 +364,7 @@ namespace bg
             void* addr = nullptr;
             if(handle == nullptr)
             {
-                SHM_ERROR("CreateFileMapping(%uz, %s) failed error:%s", *real_size, path, strerror(GetLastError()));
+                SHM_ERROR("CreateFileMapping(%zu, %s) failed error:%s", *real_size, path, strerror(GetLastError()));
                 return nullptr;
             }
 
@@ -395,12 +394,6 @@ namespace bg
 
             }
 
-            if(*mmap_size != *real_size)
-            {
-                SHM_ERROR("mmap size(%#llx) is not enough, revised to real size(%#llx).", *mmap_size, *real_size);
-                *mmap_size = *real_size;
-            }
-            *mmap_size = PALIGN_UP(*mmap_size, pagesize);
 
             if(fixed_addr)
             {
@@ -408,7 +401,7 @@ namespace bg
                 if(base_addr & align)
                 {
                     base_addr = PALIGN_UP(fixed_addr, pagesize);
-                    SHM_WARN("fixed address(%#lx) is not aligned to page size(%#lx), revised to %#lx.", base_addr, pagesize, fixed_addr);
+                    SHM_WARN("fixed address(%#" PRIx64") is not aligned to page size(%#" PRIx64"), revised to %#" PRIx64".", base_addr, pagesize, fixed_addr);
                     fixed_addr = base_addr;
                 }
             }
@@ -416,12 +409,12 @@ namespace bg
             addr = MapViewOfFileEx(handle, FILE_MAP_WRITE, 0, 0, *mmap_size, (void*)fixed_addr);
             if(addr == nullptr)
             {
-                SHM_ERROR("CreateFileMapping failed, path: %s, error: %s.", path, strerror(GetLastError()));
                 addr = MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, *mmap_size);
+                SHM_WARN("MapViewOfFileEx failed, path: %s, fixed address(%#llx),real addr(%#llx)", path, fixed_addr, addr);
             }
             if(addr != nullptr)
             {
-                g_mapping_handles[path] = handle;
+                g_mapping_handles[addr] = handle;
                 return addr;
             }
 END:
@@ -443,13 +436,13 @@ END:
             void* addr = nullptr;
             if(handle == nullptr)
             {
-                SHM_ERROR("OpenFileMapping(%uz, %s) failed error:%s", *real_size, path, strerror(GetLastError()));
+                SHM_ERROR("OpenFileMapping(%zu, %s) failed error:%s", *real_size, path, strerror(GetLastError()));
                 return nullptr;
             }
 
             if(*mmap_size < *real_size)
             {
-                SHM_ERROR("mmap size(%#lx) is not enough, revised to real size(%#lx).", *mmap_size, *real_size);
+                SHM_ERROR("mmap size(%#" PRIx64") is not enough, revised to real size(%#" PRIx64").", *mmap_size, *real_size);
                 *mmap_size = *real_size;
             }
             *mmap_size = PALIGN_UP(*mmap_size, pagesize);
@@ -460,19 +453,20 @@ END:
                 if(base_addr & align)
                 {
                     base_addr = PALIGN_UP(fixed_addr, pagesize);
-                    SHM_WARN("fixed address(%#lx) is not aligned to page size(%#lx), revised to %#lx.", base_addr, pagesize, fixed_addr);
+                    SHM_WARN("fixed address(%#" PRIx64") is not aligned to page size(%#" PRIx64"), revised to %#" PRIx64".", base_addr, pagesize, fixed_addr);
                     fixed_addr = base_addr;
                 }
             }
-
+            // 如果附加进程虚拟地址被占用就报错吧,不然恢复地址错乱
             addr = MapViewOfFileEx(handle, FILE_MAP_WRITE, 0, 0, *mmap_size, (void*)fixed_addr);
             if(addr == nullptr)
             {
-                addr = MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, *mmap_size);
+                SHM_ERROR("MapViewOfFileEx fixed address(%#" PRIx64") (%zu, %s) failed error:%s", fixed_addr, *real_size, path, strerror(GetLastError()));
+                return nullptr;
             }
             if(addr != nullptr)
             {
-                g_mapping_handles[path] = handle;
+                g_mapping_handles[addr] = handle;
                 return addr;
             }
 
@@ -485,9 +479,9 @@ END:
         {
             if(UnmapViewOfFile(addr) == 0)
             {
-                SHM_ERROR("UnmapViewOfFile() failed, addr(%p), mmap size(%#lx), error: %s.", addr, mmap_size, strerror(GetLastError()));
+                SHM_ERROR("UnmapViewOfFile() failed, addr(%p), mmap size(%#" PRIx64"), error: %s.", addr, mmap_size, strerror(GetLastError()));
             }
-            auto itor = g_mapping_handles.find(path);
+            auto itor = g_mapping_handles.find(addr);
             if(itor == g_mapping_handles.end())
             {
                 SHM_ASSERT(false);

+ 17 - 0
shm/shm_object.h

@@ -0,0 +1,17 @@
+#pragma once
+#include <stdint.h>
+namespace bg
+{
+    namespace detail
+    {
+#if defined(__GNUC__)
+        bool GetDirectorySize(const char* path, size_t* const total_size);
+        bool GetAvailableMemorySize(size_t* const size);
+#endif
+        void* ShmObjectCreate(const char* path, uintptr_t fixed_addr, size_t* real_size, size_t* mmap_size);
+        void* ShmObjectAttach(const char* path, uintptr_t fixed_addr, size_t* real_size, size_t* mmap_size);
+        void ShmObjectDelete(void* addr, uintptr_t mmap_size, const char* path);
+        bool ShmObjectResize(const char* path, size_t* new_size);
+
+    }
+}

+ 2 - 3
Project4/size_map.cc → shm/size_map.cc

@@ -20,10 +20,9 @@ namespace bg
                 if(size)
                 {
                     class_cnt = CLASS_TOTAL_BYTES / size;
-                    if(class_cnt)
+                    if(class_cnt > 1)
                     {
-                        class_cnt = std::min<size_t>(MAX_CLASSS, class_cnt);
-                        class_cnt >>= 2;
+                        class_cnt = std::min<size_t>(MAX_CLASS_COUNT, class_cnt);
                     }
                 }
                 size_t alig_page_byte = 0LL;

+ 53 - 0
shm/size_map.h

@@ -0,0 +1,53 @@
+#pragma once
+#include "shm_config.h"
+#include "shm_helper.h"
+
+#define BIG_CALIGNMENT 15488                                   // 大字节转化系数 
+#define SMALL_CALIGNMENT 8			                           // 小字节转化系数
+#define SMALL_BYTES_TO_INDEX(bytes) ((bytes + SMALL_CALIGNMENT - 1) >> 3)        // 小字节获取class index
+#define BIG_BYTES_TO_INDEX(bytes) ((bytes + (BIG_CALIGNMENT - 1)) >> 7)         // 大字节获取class index
+#define BYTES_COMP_VALUE 0x400                                  // 对比大小判断数
+#define CLASS_MAX_COUNT 87									    // 总共类数量    
+
+namespace bg
+{
+    namespace detail
+    {
+        class SizeMap
+        {
+        public:
+            /// @brief 初始化CLASS_MAX_BYTES以下内存分页配置
+            bool Init();
+
+            size_t GetClassByBytes(size_t bytes)
+            {
+                if(bytes <= BYTES_COMP_VALUE)
+                {
+                    return m_index_to_class[SMALL_BYTES_TO_INDEX(bytes)];
+                }
+                return m_index_to_class[BIG_BYTES_TO_INDEX(bytes)];
+            }
+
+            size_t ClassToSize(size_t index)
+            {
+                SHM_ASSERT_RETURN_VALUE(index < CLASS_MAX_COUNT, 0);
+                return m_class_to_size[index];
+            }
+
+            size_t ClassToPages(size_t index)
+            {
+                SHM_ASSERT_RETURN_VALUE(index < CLASS_MAX_COUNT, 0);
+                return m_class_to_pages[index];
+            }
+
+            static size_t CalcAlignment(size_t bytes);
+
+        private:
+            uint8_t m_index_to_class[2176]{0};
+            size_t m_class_to_size[CLASS_MAX_COUNT]{0};
+            size_t m_class_to_pages[CLASS_MAX_COUNT]{0};
+        };
+
+
+    }
+}

+ 137 - 0
shm/span.h

@@ -0,0 +1,137 @@
+
+#pragma once
+#include <stdint.h>
+#include "shm_helper.h"
+namespace bg
+{
+    namespace detail
+    {
+        struct Span
+        {
+            Span() = default;
+            Span(size_t start_page, size_t page_count) : m_start_page(start_page), m_page_count(page_count) {}
+
+            void RemoveNextSpan()
+            {
+                auto next_span = m_next;
+
+                m_next = next_span->m_next;
+                next_span->m_next->m_prev = next_span->m_prev;
+
+                next_span->m_prev = nullptr;
+                next_span->m_next = nullptr;
+            }
+
+            void InstertNextSpan(Span* span)
+            {
+                span->m_prev = m_next->m_prev;
+                span->m_next = m_next;
+                m_next->m_prev = span;
+                m_next = span;
+            }
+
+            void RemoveSelfForList()
+            {
+                m_prev->RemoveNextSpan();
+            }
+
+            bool GetUseState() { return m_in_use; }
+
+            void SetUseState(bool state) { m_in_use = state; }
+
+            uint8_t GetSizeClass() { return m_size_class; }
+
+            void SetSizeClass(uint8_t size_class) { m_size_class = size_class; }
+
+            size_t GetUsedCount()
+            {
+                return m_used_count;
+            }
+
+            void IncUsedCount()
+            {
+                m_used_count++;
+            }
+
+            void DecUsedCout()
+            {
+                SHM_ASSERT_RETURN_VOID(m_used_count);
+                m_used_count--;
+            }
+
+            void SetUsedCount(size_t used_count)
+            {
+                SHM_ASSERT_RETURN_VOID(used_count >= 0);
+                m_used_count = used_count;
+            }
+
+            void SetStartPage(size_t start_page)
+            {
+                m_start_page = start_page;
+            }
+
+            size_t GetStartPage()
+            {
+                return m_start_page;
+            }
+
+            size_t GetLastPage()
+            {
+                SHM_ASSERT_RETURN_VALUE(m_page_count > 0, m_start_page);
+                return m_start_page + m_page_count - 1;
+            }
+
+            size_t GetPageCount()
+            {
+                return m_page_count;
+            }
+
+            void SetPageCount(size_t page_count)
+            {
+                SHM_ASSERT_RETURN_VOID(page_count >= 0);
+                m_page_count = page_count;
+            }
+
+            Span* GetNextSpan()
+            {
+                return m_next;
+            }
+
+            Span* GetPreSpan()
+            {
+                return m_next;
+            }
+
+            void SetChunkList(void* chunk_list)
+            {
+                m_chunk_list = chunk_list;
+            }
+            void* GetChunkList() { return m_chunk_list; }
+
+            void LeftMovePages(size_t page_count)
+            {
+                m_start_page -= page_count;
+                m_page_count += page_count;
+            }
+
+            void RightMovePages(size_t page_count)
+            {
+                m_page_count += page_count;
+            }
+
+        private:
+
+
+            bool m_in_use{};
+            uint8_t m_size_class{0xff};
+            size_t m_used_count{};
+            size_t m_start_page{};
+            size_t m_page_count{};
+
+            Span* m_prev{this};
+            Span* m_next{this};
+            void* m_chunk_list{};
+
+        };
+    }
+}

+ 346 - 0
shm/vptr_manager.cc

@@ -0,0 +1,346 @@
+#include "vptr_manager.h"
+#include "shm.h"
+#include <memory>
+#include <inttypes.h>
+#define  VPTR_MAGIC 20230430
+namespace bg
+{
+    namespace detail
+    {
+        VptrManager* mgr;
+        class HighOrderContainer;
+        std::unique_ptr<HighOrderContainer> 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();
+                }
+                SHM_INFO("type(%s) not found!", type_name.c_str());
+                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())
+                {
+                    SHM_ERROR("type(%s) not found!", type_name.c_str());
+                    return false;
+                }
+
+                const uintptr_t* new_vptr = reinterpret_cast<const uintptr_t*>(reinterpret_cast<const char*>(itor->second));
+                uintptr_t* old_vptr = reinterpret_cast<uintptr_t*>(reinterpret_cast<char*>(fix_ptr));
+                if(*old_vptr != *new_vptr)
+                {
+                    *old_vptr = *new_vptr;
+                }
+                SHM_INFO("type(%s), old vptr(%#" PRIx64"), new vptr(%#" PRIx64").", type_name.c_str(), old_vptr, new_vptr);
+                return true;
+            }
+
+            VptrObjectContainerBase* NewShmContainer(const bg::detail::TypeName& type_name)
+            {
+                auto itor = m_type_to_containers.find(type_name);
+
+                SHM_ASSERT_RETURN_NULL(itor != m_type_to_containers.end());
+
+                return itor->second;
+            }
+
+            void RegisterContainer(VptrObjectContainerBase* obj)
+            {
+                auto& type_name = obj->GetTypeName();
+                auto itor = m_type_to_containers.find(type_name);
+                SHM_ASSERT_RETURN_VOID(itor != m_type_to_containers.end());
+
+                m_type_to_containers[type_name] = obj;
+
+            }
+
+            template<typename Key, typename Value, typename Hash = std::hash<Key>, typename Pred = std::equal_to<Key>>
+            using Container = std::unordered_map<Key, Value, Hash, Pred, ShmAllocator<std::pair<const Key, Value>>>;
+            Container<TypeName, VptrObjectContainerBase*, TypeNameHasher> m_type_to_containers;
+        };
+
+
+        VptrObjectContainerBase::VptrObjectContainerBase(const TypeName& type, bool in_shm) :m_version(0LL), m_type(type)
+        {
+            if(in_shm)
+            {
+                std::vector<void*, bg::detail::ShmAllocator<void*> >* vector = (std::vector<void*, bg::detail::ShmAllocator<void*> > *)bg::ShmMalloc(sizeof(std::vector<void*, bg::detail::ShmAllocator<void*> >));
+                if(vector)
+                {
+                    new (vector) std::vector<void*, bg::detail::ShmAllocator<void*> >();
+                }
+                m_objects = vector;
+                this->m_version = bg::detail::ShmCurrentVersion();
+            }
+            else
+            {
+                if(!hoc)
+                {
+                    hoc = std::make_unique<HighOrderContainer>();
+                }
+                hoc->RegisterContainer(this);
+            }
+        }
+
+
+        VptrObjectContainerBase::~VptrObjectContainerBase()
+        {
+            if(m_objects)
+            {
+                if(!m_objects->empty())
+                {
+                    SHM_ERROR("there are still %lu objects in container(%s)!", m_objects->size(), m_type.c_str());
+                }
+                m_objects->clear();
+                bg::ShmFree(m_objects);
+            }
+            if(m_base_types)
+            {
+                m_base_types->clear();
+                delete m_base_types;
+            }
+        }
+
+        void VptrObjectContainerBase::FixVptr()
+        {
+            if(m_version == bg::detail::ShmCurrentVersion())
+            {
+                SHM_DEBUG("container(%p: %s) already fixed, skip.", this, m_type.c_str());
+            }
+            else if(FixSelf())
+            {
+                FixObjects();
+                this->m_version = bg::detail::ShmCurrentVersion();
+            }
+            else
+            {
+                SHM_INFO("container(%p: %s) seems to be defined in a dlopen() so, try fixing after dlopen() called.", this, m_type.c_str());
+            }
+
+        }
+
+        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();
+                *(reinterpret_cast<uintptr_t*>(ptr) - 1) = size;
+                *(reinterpret_cast<uintptr_t*>(ptr) - 2) = VPTR_MAGIC;
+                SHM_INFO("object(%p) added, type: %s, index: %lu.", ptr, m_type.c_str(), size);
+            }
+        }
+
+        void VptrObjectContainerBase::RemoveObject(void* ptr)
+        {
+            if(ptr)
+            {
+                uintptr_t maric = *((uintptr_t*)ptr - 2);
+                if(maric == VPTR_MAGIC)
+                {
+                    size_t index = *((uintptr_t*)ptr - 1);
+                    size_t size = m_objects->size();
+                    if(index < size)
+                    {
+                        if((*m_objects)[index] == ptr)
+                        {
+                            bg::detail::VptrObjectContainerBase::DoRemoveObject(index);
+                            return;
+                        }
+                        SHM_WARN("address mismatch(%p <=> %p), type: %s, index: %#x.", (*m_objects)[index], ptr, m_type.c_str(), index);
+                    }
+                    else
+                    {
+                        SHM_ERROR("wrong index(%#x), size: %#" PRIx64", type: %s.", index, size, m_type.c_str());
+                    }
+                    for(int i = 0; i < size; ++i)
+                    {
+                        if((*m_objects)[i] == ptr)
+                        {
+                            SHM_INFO("found correct index: %#" PRIx64".", i);
+                            bg::detail::VptrObjectContainerBase::DoRemoveObject(i);
+                        }
+                    }
+                    SHM_ERROR("no stored object found with address(%p).", ptr);
+                    return;
+                }
+                SHM_ERROR("invalid magic(%#x) for object(%p).", maric, ptr);
+                return;
+            }
+        }
+
+        bool VptrObjectContainerBase::FixSelf()
+        {
+            SHM_INFO(">>>>> fixing vptr of container(%p: %s)...", this, m_type.c_str());
+            const char* result = "";
+            if(bg::detail::hoc && bg::detail::hoc->FixContainerVptr(this))
+            {
+                SHM_INFO("<<<<< vptr of container(%p: %s) fixed.", this, m_type.c_str());
+                return true;
+            }
+            SHM_ERROR("<<<<< vptr of container(%p: %s) not fixed.", this, m_type.c_str());
+            return false;
+        }
+
+        void VptrObjectContainerBase::DoRemoveObject(size_t index)
+        {
+            size_t size = m_objects->size();
+            SHM_ASSERT_RETURN_VOID(index < m_objects->size());
+            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<bg::detail::VptrManager>();
+            }
+            return bg::detail::mgr != nullptr;
+        }
+
+        void VptrManager::Fini()
+        {
+            if(bg::detail::mgr)
+            {
+                bg::ShmDeleteSingleton<bg::detail::VptrManager>();
+                bg::detail::mgr = nullptr;
+            }
+        }
+
+        VptrManager::~VptrManager()
+        {
+            for(auto& item : mgr->m_type_to_containers)
+            {
+                item.second->~VptrObjectContainerBase();
+                bg::ShmFree(item.second);
+            }
+            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)
+        {
+            uintptr_t* raw_ptr = reinterpret_cast<uintptr_t*>(ptr);
+            if(raw_ptr[0] == VPTR_MAGIC)
+            {
+                bg::ShmFree(raw_ptr);
+            }
+            else
+            {
+                SHM_ERROR("invalid magic(%#x) at address(%p).", raw_ptr[0], ptr);
+            }
+        }
+
+
+
+        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);
+
+            SHM_ASSERT_RETURN_VALUE(itor != bg::detail::mgr->m_type_to_containers.end(), ptr);
+
+            auto info = itor->second->GetBaseTypeInfo(real_type);
+            SHM_ASSERT_RETURN_VALUE(info, ptr);
+            return &(((char*)ptr)[-info->offset]);
+        }
+
+        void VptrManager::RecordObject(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())
+            {
+
+                VptrObjectContainerBase* base_ptr = hoc->NewShmContainer(type);
+                SHM_ASSERT_RETURN_VOID(base_ptr && base_ptr->GetTypeName() == type);
+                bg::detail::mgr->m_type_to_containers[type] = base_ptr;
+                auto ret = bg::detail::mgr->m_type_to_containers.insert(std::make_pair(type, base_ptr));
+                SHM_ASSERT_RETURN_VOID(ret.second && ret.first != mgr->m_type_to_containers.end());
+                itor = ret.first;
+            }
+
+
+            itor->second->RecordObject(ptr);
+            SHM_DEBUG("container(%p) for type(%s) created.", itor->second, type.c_str());
+        }
+
+        void VptrManager::RemoveObject(const TypeName& type, void* ptr)
+        {
+            auto itor = bg::detail::mgr->m_type_to_containers.find(type);
+
+            SHM_ASSERT_RETURN_VOID(itor != bg::detail::mgr->m_type_to_containers.end());
+            itor->second->RemoveObject(ptr);
+        }
+
+
+    }
+}

+ 475 - 0
shm/vptr_manager.h

@@ -0,0 +1,475 @@
+/*
+ * Copyright 2020 ByteDance Games, Inc. All Rights Reserved.
+ *
+ * Author: Liuziming <liuziming.kelvin@bytedance.com>
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <string.h>
+#include <string>
+#include <vector>
+#include <typeinfo>
+#include <unordered_map>
+
+#include "shm_helper.h"
+
+#include <inttypes.h>
+# if defined(__GNUC__)
+#include <tr2/type_traits>
+#include <typeinfo>
+#include <map>
+#ifdef OUTPUT_BASES
+extern std::map<std::string, std::vector<std::string>> g_bases_name;
+#endif
+#else 
+#include "type_helper.h"
+#define REINTERPRET_CAST_TAG	
+#endif
+
+namespace bg
+{
+    namespace detail
+    {
+
+        struct BaseTypeInfo
+        {
+            TypeName type;
+            ptrdiff_t offset;
+
+            BaseTypeInfo(const char* type, ptrdiff_t offset) : type(type), offset(offset) {}
+        };
+
+        class VptrObjectContainerBase
+        {
+        public:
+            VptrObjectContainerBase(const TypeName& type, bool in_shm);
+            virtual ~VptrObjectContainerBase();
+
+            virtual void FixObjects() = 0;
+            virtual VptrObjectContainerBase* ShmNew() = 0;
+
+            void FixVptr();
+            const TypeName& GetTypeName() const { return m_type; }
+            const BaseTypeInfo* GetBaseTypeInfo(const TypeName& base_type);
+
+            void RecordObject(void* ptr);
+            void RemoveObject(void* ptr);
+
+        protected:
+            bool FixSelf();
+            void DoRemoveObject(size_t index);
+
+        protected:
+            static constexpr const double EXPANSION_FACTOR = 1.5;
+
+            uint64_t m_version = 0;
+            TypeName m_type;
+            // As we have containers both in normal memory and shared
+            // memory, so we make the pointer container as pointer here,
+            // only initialize it when it's used in shared memory.
+            std::vector<void*, ShmAllocator<void*>>* m_objects = nullptr;
+            // The following field is initialized in derived class constructor.
+            std::vector<BaseTypeInfo>* m_base_types = nullptr;
+        };
+
+        template<typename T>
+        class VptrObjectContainer final : public VptrObjectContainerBase
+        {
+        public:
+            static const T static_object;
+            static const VptrObjectContainer<T> static_container;
+
+            /*
+             * NOTE: The 2nd arg to `TypeName(...)` MUST BE 0 here, because when
+             * we delete a pointer of polymorphic type, we can only know it's real
+             * type with `typeid(*ptr).name()`, but we cannot get the size of that
+             * real type, so we have to abandon size here, to match the info we can
+             * get at deletion. The same as following calls to this function.
+             */
+            VptrObjectContainer() : VptrObjectContainerBase(TypeName(typeid(T).name()), false)
+            {
+                SHM_DEBUG_ASSERT(this == &static_container);
+
+                size_t count = GetBaseClassCount();
+                if(count > 0)
+                {
+                    m_base_types = new std::vector<BaseTypeInfo>();
+                    m_base_types->reserve(count);
+                    FillBaseTypeInfo(m_base_types, Index2Type<0>());
+                }
+            }
+
+            VptrObjectContainer(const VptrObjectContainer& that) : VptrObjectContainerBase(that.m_type, true)
+            {
+                SHM_DEBUG_ASSERT(&that == &static_container);
+            }
+
+            ~VptrObjectContainer() final = default;
+
+            void FixObjects() final
+            {
+                SHM_TRACE(">>>>> fixing vptr of objects in container(%p: %s)...", this, m_type.c_str());
+                for(void* ptr : *m_objects)
+                {
+                    DoFix(ptr, std::integral_constant<bool, GetBaseClassCount() != 0>(), Index2Type<0>());
+                }
+                SHM_TRACE("<<<<< vptr of objects in container(%p: %s) fixed.", this, m_type.c_str());
+            }
+
+            VptrObjectContainerBase* ShmNew() final
+            {
+                SHM_DEBUG_ASSERT(this == &static_container);
+                ShmAllocator<VptrObjectContainer<T>> allocator;
+                VptrObjectContainer<T>* ptr = allocator.allocate(1);
+                if(SHM_LIKELY(ptr))
+                {
+                    allocator.construct(ptr, *this);
+                }
+
+                return ptr;
+            }
+
+        private:
+            template<typename... Types>
+            struct List
+            {
+                static constexpr size_t count = sizeof...(Types);
+            };
+
+            template<typename NewType, typename List>
+            struct PrependList;
+
+            template<typename NewType, typename... Types>
+            struct PrependList<NewType, List<Types...>>
+            {
+                using ListType = List<NewType, Types...>;
+            };
+
+            template<typename List>
+            struct RemoveFirst;
+
+            template<typename Head, typename... Rest>
+            struct RemoveFirst<List<Head, Rest...>>
+            {
+                using RestList = List<Rest...>;
+            };
+
+            struct NullType {};
+
+            template<typename T>
+            struct bases
+            {
+                typedef __reflection_typelist<>		type;
+            };
+
+            template<typename Type>
+# if defined(__GNUC__)
+            using RefList = typename std::tr2::bases<Type>::type;
+#elif defined(_MSC_VER)
+            using RefList = typename bases<Type>::type;
+
+#endif
+
+
+            template<bool empty, typename RefList>
+            struct DoMakeList;
+
+            template<typename RefList>
+            struct DoMakeList<true, RefList>
+            {
+                using ListType = List<NullType>;
+            };
+
+            template<typename RefList>
+            struct DoMakeList<false, RefList>
+            {
+                using ListType =
+                    typename PrependList<
+                    typename RefList::first::type,
+                    typename DoMakeList<
+                    RefList::rest::type::empty::value,
+                    typename RefList::rest::type
+                    >::ListType
+                    >::ListType;
+            };
+
+            template<typename Type>
+            struct MakeList
+            {
+                using Result =
+                    typename DoMakeList<
+                    RefList<Type>::empty::value,
+                    RefList<Type>
+                    >::ListType;
+            };
+
+            template<size_t N, typename BaseList>
+            struct GetNthBaseClass;
+
+            template<size_t N, typename Head, typename... Rest>
+            struct GetNthBaseClass<N, List<Head, Rest...>>
+            {
+                using BaseType = typename GetNthBaseClass<N - 1, List<Rest...>>::BaseType;
+            };
+
+            template<typename Head, typename... Rest>
+            struct GetNthBaseClass<0, List<Head, Rest...>>
+            {
+                using BaseType = Head;
+            };
+# if defined(__GNUC__)
+            template<typename Derived, typename Base>
+            struct BaseClassOffset
+            {
+
+                static constexpr const Derived* derived = &VptrObjectContainer<T>::static_object;
+                static constexpr const Base* base = static_cast<const Base*>(derived);
+
+                static REINTERPRET_CAST_TAG  ptrdiff_t value;
+
+                static constexpr ptrdiff_t value =
+                    reinterpret_cast<intptr_t>(base) - reinterpret_cast<intptr_t>(derived);
+
+
+                /*
+                 * This does not work with higher GCC version, due to C++ 11 standard specifies
+                 * that `reinterpret_cast` cannot be used inside constexpr expression. See this
+                 * link for detail:
+                 * https://stackoverflow.com/questions/24398102/constexpr-and-initialization-of-a-static-const-void-pointer-with-reinterpret-cas
+                 *
+                 * static constexpr ptrdiff_t value =
+                 *     reinterpret_cast<intptr_t>(static_cast<Base*>(static_cast<Derived*>(0) + 1)) -
+                 *     reinterpret_cast<intptr_t>(static_cast<Derived*>(0) + 1);
+                 */
+            };
+#endif
+            template<size_t N>
+# if defined(__GNUC__)
+            static constexpr ptrdiff_t GetBaseClassOffset()
+            {
+                using BaseList = typename MakeList<T>::Result;
+                using BaseType = typename GetNthBaseClass<N, BaseList>::BaseType;
+
+                return BaseClassOffset<T, BaseType>::value;
+        }
+#else
+            static REINTERPRET_CAST_TAG ptrdiff_t GetBaseClassOffset()
+            {
+                using BaseList = typename MakeList<T>::Result;
+                using BaseType = typename GetNthBaseClass<N, BaseList>::BaseType;
+                static constexpr const T* derived = &VptrObjectContainer<T>::static_object;
+                static constexpr const BaseType* base = static_cast<const BaseType*>(derived);
+
+                return reinterpret_cast<intptr_t>(base) - reinterpret_cast<intptr_t>(derived);
+            }
+#endif
+
+            static constexpr size_t GetBaseClassCount()
+            {
+                // There is a NullType at the end of the list, so we compare with 1 here
+                static_assert(MakeList<T>::Result::count >= 1, "Invalid base class count");
+                return MakeList<T>::Result::count - 1;
+            }
+
+            /*
+             * The BEST solution should be the following:
+             *   Generate an base class offset array at compile time, during fixing, iterate
+             *   over the array and fix each vptr at corresponding offset. However, there is
+             *   a bug in GCC(4.8), which leads to the following code cannot compile:
+             *
+             *     internal compiler error: in convert_nontype_argument, at cp/pt.c:5623
+             *     Please submit a full bug report.
+             *     ...
+             *
+             *   So, we have to use template function specialization instead to solve this
+             *   problem without a lot of ugly macro definitions.
+             *
+             *
+             * template<ptrdiff_t... offsets>
+             * struct OffsetHolder {
+             *     static constexpr ptrdiff_t base_offsets[sizeof...(offsets)] = { offsets... };
+             * };
+             *
+             * template<size_t total, typename BaseList, ptrdiff_t... offsets>
+             * struct DoGenerateOffsets {
+             *     using Result = typename DoGenerateOffsets<
+             *         total,
+             *         typename RemoveFirst<BaseList>::Rest,
+             *         // There is a NullType at the end of the list, we should make
+             *         // this consistent with value defined in GetBaseClassCount()
+             *         GetBaseClassOffset<total - (BaseList::count - 1)>(),
+             *         offsets...
+             *     >::Result;
+             * };
+             *
+             * template<size_t total, ptrdiff_t... offsets>
+             * struct DoGenerateOffsets<total, List<NullType>, offsets...> {
+             *     using Result = OffsetHolder<offsets...>;
+             * };
+
+             * struct GenerateOffsets {
+             *     using Result = typename DoGenerateOffsets<
+             *         GetBaseClassCount(), typename MakeList<T>::Result
+             *     >::Result;
+             * };
+             *
+             * void DoFix(void *ptr) {
+             *     using OffsetArray = GenerateOffsets::Result;
+             *     for (size_t i = 0; i < ARRAY_SIZE(OffsetArray::base_offsets); ++i) {
+             *         const ptrdiff_t offset = OffsetArray::base_offsets[i];
+             *         // do fix vptr here
+             *     }
+             * }
+             *
+             */
+
+            template<size_t>
+            struct Index2Type {};
+
+            template<size_t index>
+            void FillBaseTypeInfo(std::vector<BaseTypeInfo>* base_types, Index2Type<index>)
+            {
+                using BaseList = typename MakeList<T>::Result;
+                using BaseType = typename GetNthBaseClass<index, BaseList>::BaseType;
+                static constexpr const ptrdiff_t offset = GetBaseClassOffset<index>();
+                static_assert(offset >= 0, "invalid offset");
+
+                BaseTypeInfo info(typeid(BaseType).name(), offset);
+                base_types->push_back(info);
+                FillBaseTypeInfo(base_types, Index2Type<index + 1>());
+            }
+
+            void FillBaseTypeInfo(std::vector<BaseTypeInfo>*, Index2Type<GetBaseClassCount()>) {}
+
+            // This function means there is no base class for class T.
+            void DoFix(void* ptr, std::false_type, Index2Type<0>)
+            {
+                static constexpr const T* t = &static_object;
+
+                const uintptr_t* new_vptr = reinterpret_cast<const uintptr_t*>(reinterpret_cast<const char*>(t));
+                uintptr_t* old_vptr = reinterpret_cast<uintptr_t*>(reinterpret_cast<char*>(ptr));
+
+                if(!HasVptr<T>::value)
+                {
+                    SHM_ERROR("object(%p), type(%s), no base type, vptr not found(%#" PRIx64" : %#" PRIx64"), at least one virtual function is required.",
+                              ptr, m_type.c_str(), *old_vptr, *new_vptr);
+                    return;
+                }
+
+                SHM_DEBUG("object(%p), type(%s), no base type, old vptr(%#" PRIx64"), new vptr(%#" PRIx64")", ptr, m_type.c_str(), *old_vptr, *new_vptr);
+                if(*old_vptr != *new_vptr)
+                {
+                    *old_vptr = *new_vptr;
+                }
+            }
+
+            template<size_t index>
+            void DoFix(void* ptr, std::true_type, Index2Type<index>)
+            {
+                using BaseList = typename MakeList<T>::Result;
+                using BaseType = typename GetNthBaseClass<index, BaseList>::BaseType;
+
+                static constexpr const ptrdiff_t offset = GetBaseClassOffset<index>();
+                static constexpr const T* t = &static_object;
+
+                const uintptr_t* new_vptr = reinterpret_cast<const uintptr_t*>(reinterpret_cast<const char*>(t) + offset);
+                uintptr_t* old_vptr = reinterpret_cast<uintptr_t*>(reinterpret_cast<char*>(ptr) + offset);
+
+                TypeName base_type(typeid(BaseType).name());
+                if(!HasVptr<BaseType>::value)
+                {
+                    SHM_ERROR("object(%p), type(%s), base type(%s), base index(%lu锛? offset(%#" PRIx64"), vptr(%#" PRIx64" : %#" PRIx64") not found, a virtual destructor is recommended.",
+                              ptr, m_type.c_str(), base_type.c_str(), index, offset, *old_vptr, *new_vptr);
+                }
+                else
+                {
+                    SHM_DEBUG("object(%p), type(%s), base type(%s), base index(%lu锛? offset(%#" PRIx64"), old vptr(%#" PRIx64"), new vptr(%#" PRIx64")",
+                              ptr, m_type.c_str(), base_type.c_str(), index, offset, *old_vptr, *new_vptr);
+
+                    if(*old_vptr != *new_vptr)
+                    {
+                        *old_vptr = *new_vptr;
+                    }
+                }
+
+                DoFix(ptr, std::true_type(), Index2Type<index + 1>());
+            }
+
+            void DoFix(void*, std::true_type, Index2Type<GetBaseClassCount()>) {}
+    };
+        //template<typename T> const T VptrObjectContainer<T>::static_object = T();
+        template<typename T> const T VptrObjectContainer<T>::static_object;
+        template<typename T> const VptrObjectContainer<T> VptrObjectContainer<T>::static_container;
+
+        class VptrManager
+        {
+        public:
+            static bool Init();
+            static void Fini();
+            ~VptrManager();
+
+            template<typename T, typename... Args>
+            static T* NewVptrObject(Args&&... args)
+            {
+                return NewVptrObjectExtraSpace<T>(0, std::forward<Args>(args)...);
+            }
+
+            template<typename T, typename... Args>
+            static T* NewVptrObjectExtraSpace(size_t extra_space, Args&&... args)
+            {
+                static_assert(HasVptr<T>::value, "type must be polymorphic or have vptr at least!");
+                const TypeName& type = VptrObjectContainer<T>::static_container.GetTypeName();
+
+                // Do not use static assertion here, sometimes it might not need a virtual destructor.
+                // static_assert(std::has_virtual_destructor<T>::value, "polymorphic type must have a virtual destructor!");
+                if(!std::has_virtual_destructor<T>::value)
+                {
+                    SHM_ERROR("it's better to declare destructor virtual for polymorphic type(%s).", type.c_str());
+                }
+
+                void* ptr = NewSpace(sizeof(T) + extra_space);
+                if(SHM_LIKELY(ptr))
+                {
+                    new (ptr) T(std::forward<Args>(args)...);
+                    RecordObject(type, ptr);
+                }
+
+                return static_cast<T*>(ptr);
+            }
+
+            template<typename T>
+            static void DelVptrObject(T* ptr)
+            {
+                static_assert(HasVptr<T>::value, "type must be polymorphic or have vptr at least!");
+
+                if(SHM_LIKELY(ptr))
+                {
+                    TypeName base_type(typeid(T).name());
+                    TypeName real_type(typeid(*ptr).name());
+
+                    void* real_ptr = GetRealPtr(base_type, real_type, ptr);
+                    RemoveObject(real_type, real_ptr);
+                    ptr->~T();
+                    FreeSpace(real_ptr);
+                }
+            }
+
+            static void FixVptr();
+
+        private:
+            static void* NewSpace(size_t bytes);
+            static void FreeSpace(void* ptr);
+            static void* GetRealPtr(const TypeName& base_type, const TypeName& real_type, void* ptr);
+            static void RecordObject(const TypeName& type, void* ptr);
+            static void RemoveObject(const TypeName& type, void* ptr);
+
+        private:
+            template<typename Key, typename Value, typename Hash = std::hash<Key>, typename Pred = std::equal_to<Key>>
+            using Container = std::unordered_map<Key, Value, Hash, Pred, ShmAllocator<std::pair<const Key, Value>>>;
+            Container<TypeName, VptrObjectContainerBase*, TypeNameHasher> m_type_to_containers;
+        };
+
+} // namespace detail
+} // namespace bg

+ 0 - 0
Project4/type_helper.h → vs_helper/type_helper.h