From 19615c6c11f11dd6839dab5b18ff68fedfc7e2e3 Mon Sep 17 00:00:00 2001 From: Blair McGlashan Date: Sun, 15 Dec 2024 17:11:35 +0000 Subject: [PATCH] Use mimalloc --- Core/DolphinVM/Compiler/Compiler.vcxproj | 14 + .../Compiler/Compiler.vcxproj.filters | 89 + Core/DolphinVM/Compiler/heap.cpp | 6 + Core/DolphinVM/Compiler/stdafx.h | 3 +- Core/DolphinVM/ConsoleToGo/ConsoleToGo.def | 58 - .../DolphinVM/ConsoleToGo/ConsoleToGo.vcxproj | 9 +- Core/DolphinVM/DolphinVM.sln | 49 +- Core/DolphinVM/GC.cpp | 56 +- Core/DolphinVM/InProcToGo/IPToGo.def | 58 - Core/DolphinVM/InProcToGo/InProcToGo.vcxproj | 9 +- Core/DolphinVM/LoadImage.cpp | 19 +- Core/DolphinVM/ObjMemInit.cpp | 40 +- Core/DolphinVM/ObjMemPriv.inl | 101 -- Core/DolphinVM/SBHEAP.C | 1470 ----------------- Core/DolphinVM/SaveImage.cpp | 1 - Core/DolphinVM/ToGoStub/GuiToGo.vcxproj | 9 +- Core/DolphinVM/ToGoStub/togo.def | 57 - Core/DolphinVM/Utf16String.cpp | 12 +- Core/DolphinVM/Utf16StringBuf.h | 3 +- Core/DolphinVM/Utf8String.cpp | 8 +- Core/DolphinVM/Utf8StringBuf.h | 3 +- Core/DolphinVM/VMLib/VMLib.vcxitems | 18 +- Core/DolphinVM/VMLib/VMLib.vcxitems.filters | 12 +- Core/DolphinVM/VMLib/heap.cpp | 212 +++ Core/DolphinVM/alloc.cpp | 427 +---- Core/DolphinVM/dealloc.cpp | 37 +- Core/DolphinVM/dll.vcxproj | 3 + Core/DolphinVM/ist.h | 1 - Core/DolphinVM/objmem.cpp | 101 +- Core/DolphinVM/objmem.h | 164 +- Core/DolphinVM/ote.h | 4 +- Core/DolphinVM/realloc.cpp | 56 +- Core/DolphinVM/sbheap.h | 23 - Core/DolphinVM/zct.cpp | 1 - .../Dolphin/Lagoon/Lagoon Tests.pax | 9 - .../Tools.Tests.CRTLibraryImportTest.cls | 59 - 36 files changed, 482 insertions(+), 2719 deletions(-) create mode 100644 Core/DolphinVM/Compiler/Compiler.vcxproj.filters create mode 100644 Core/DolphinVM/Compiler/heap.cpp delete mode 100644 Core/DolphinVM/ObjMemPriv.inl delete mode 100755 Core/DolphinVM/SBHEAP.C create mode 100644 Core/DolphinVM/VMLib/heap.cpp delete mode 100644 Core/DolphinVM/sbheap.h delete mode 100644 Core/Object Arts/Dolphin/Lagoon/Tools.Tests.CRTLibraryImportTest.cls diff --git a/Core/DolphinVM/Compiler/Compiler.vcxproj b/Core/DolphinVM/Compiler/Compiler.vcxproj index f800a4763f..8378f8ab41 100644 --- a/Core/DolphinVM/Compiler/Compiler.vcxproj +++ b/Core/DolphinVM/Compiler/Compiler.vcxproj @@ -105,6 +105,7 @@ .\Compiler.def .\Release/DolphinCR008.lib + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) @@ -163,6 +164,7 @@ $(OutDir)$(TargetName).pdb DebugFastLink + $(SolutionDir)..\..\out\msvc-$(Platform)\Debug;%(AdditionalLibraryDirectories) @@ -222,6 +224,7 @@ $(OutDir)$(TargetName).pdb DebugFastLink + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) @@ -241,6 +244,17 @@ false false + + NotUsing + NotUsing + NotUsing + $(SolutionDir)mimalloc\include;$(SolutionDir);%(AdditionalIncludeDirectories) + $(SolutionDir)mimalloc\include;$(SolutionDir);%(AdditionalIncludeDirectories) + $(SolutionDir)mimalloc\include;$(SolutionDir);%(AdditionalIncludeDirectories) + Cdecl + Cdecl + Cdecl + diff --git a/Core/DolphinVM/Compiler/Compiler.vcxproj.filters b/Core/DolphinVM/Compiler/Compiler.vcxproj.filters new file mode 100644 index 0000000000..b2ff0bce64 --- /dev/null +++ b/Core/DolphinVM/Compiler/Compiler.vcxproj.filters @@ -0,0 +1,89 @@ + + + + + + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + Sources + + + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + Headers + + + + + + + + + + + + {68ffeb2c-812c-4d78-b39b-2d9db2ff22be} + *.h + + + {446335c9-9b31-4282-8670-86d8064ff18f} + + + \ No newline at end of file diff --git a/Core/DolphinVM/Compiler/heap.cpp b/Core/DolphinVM/Compiler/heap.cpp new file mode 100644 index 0000000000..7cc77d7936 --- /dev/null +++ b/Core/DolphinVM/Compiler/heap.cpp @@ -0,0 +1,6 @@ +/////////////////////// +#include + +#include "mimalloc.h" +#include "mimalloc-new-delete.h" +#pragma comment(lib, "mimalloc-static.lib") diff --git a/Core/DolphinVM/Compiler/stdafx.h b/Core/DolphinVM/Compiler/stdafx.h index 827064afbc..9b826fbc8b 100644 --- a/Core/DolphinVM/Compiler/stdafx.h +++ b/Core/DolphinVM/Compiler/stdafx.h @@ -15,7 +15,7 @@ #endif // Turn off iterator debugging as it makes the compiler very slow on large methods in debug builds -#define _HAS_ITERATOR_DEBUGGING 0 +//#define _HAS_ITERATOR_DEBUGGING 0 // Enable templated overloads for secure version of old-style CRT functions that manipulate buffers but take no size arguments #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 @@ -30,7 +30,6 @@ #include "..\DolphinSmalltalk_i.h" #include -#include #include #include #include diff --git a/Core/DolphinVM/ConsoleToGo/ConsoleToGo.def b/Core/DolphinVM/ConsoleToGo/ConsoleToGo.def index aa4a6bc672..ebebc63d6f 100644 --- a/Core/DolphinVM/ConsoleToGo/ConsoleToGo.def +++ b/Core/DolphinVM/ConsoleToGo/ConsoleToGo.def @@ -23,64 +23,6 @@ CompileForEval=_PrimCompileForEval@32 compress2 uncompress - -; CRT functions imported by the image - - _chsize_s - _clearfp - _close - _control87 - _dup - _dup2 - _errno - _fdopen - _filelengthi64 - _fileno - _fseeki64 - _ftelli64 - _get_invalid_parameter_handler - _get_osfhandle - _isatty - _makepath_s - _open_osfhandle - _setmode - _splitpath_s - _statusfp - _wcserror_s - _wcsicmp - _wfsopen - atoi - fclose - feof - fflush - fgetc - fgets - fgetwc - fgetws - fputc - fputs - fputwc - fputws - fread_s - free - fwrite - memcmp - memcpy_s - rand - setlocale - srand - strcat_s - strcmp - strcspn - strlen - strncmp - strncpy_s - ungetc - ungetwc - wcslen - wcscspn - wcsncpy_s - ; VMLibrary _snprintf_s diff --git a/Core/DolphinVM/ConsoleToGo/ConsoleToGo.vcxproj b/Core/DolphinVM/ConsoleToGo/ConsoleToGo.vcxproj index 3d81c6fcd3..ecda699247 100644 --- a/Core/DolphinVM/ConsoleToGo/ConsoleToGo.vcxproj +++ b/Core/DolphinVM/ConsoleToGo/ConsoleToGo.vcxproj @@ -101,7 +101,7 @@ _CONSOLE;STRICT;TO_GO;_CTYPE_DISABLE_MACROS;WIN32;_WINDOWS;WIN32_LEAN_AND_MEAN;WIN32_EXTRA_LEAN;ZEXPORT=__stdcall;ZEXPORTVA=__cdecl;_HAS_EXCEPTIONS=0;NDEBUG;%(PreprocessorDefinitions) false - MultiThreaded + MultiThreadedDLL Use ist.h @@ -115,6 +115,7 @@ Console false + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) @@ -137,7 +138,7 @@ true - MultiThreadedDebug + MultiThreadedDebugDLL false Use ist.h @@ -170,6 +171,7 @@ true true + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) @@ -193,7 +195,7 @@ true - MultiThreadedDebug + MultiThreadedDebugDLL false Use ist.h @@ -226,6 +228,7 @@ true true + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) diff --git a/Core/DolphinVM/DolphinVM.sln b/Core/DolphinVM/DolphinVM.sln index e160f51685..9b1dedd679 100644 --- a/Core/DolphinVM/DolphinVM.sln +++ b/Core/DolphinVM/DolphinVM.sln @@ -1,8 +1,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2027 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 d17.12 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VM", "dll.vcxproj", "{382ABBF3-B32D-4D77-B303-346AA146921C}" + ProjectSection(ProjectDependencies) = postProject + {ABB5EAE7-B3E6-432E-B636-333449892EA6} = {ABB5EAE7-B3E6-432E-B636-333449892EA6} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Launcher", "Launcher\Dull.vcxproj", "{A8454911-DE25-451D-AC38-1B6B058C050D}" ProjectSection(ProjectDependencies) = postProject @@ -10,6 +13,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Launcher", "Launcher\Dull.v EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Compiler", "Compiler\Compiler.vcxproj", "{35EB6247-4F53-4605-AA04-A9310AB3235B}" + ProjectSection(ProjectDependencies) = postProject + {ABB5EAE7-B3E6-432E-B636-333449892EA6} = {ABB5EAE7-B3E6-432E-B636-333449892EA6} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DolphinLib", "DolphinLib.vcxproj", "{241D4E3E-44C0-40B7-BE1B-5249916FE631}" EndProject @@ -21,6 +27,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InProcStub", "InProcStub\In EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InProcToGo", "InProcToGo\InProcToGo.vcxproj", "{90C32F90-C0B1-46FE-BACE-FB6566EB6F3C}" + ProjectSection(ProjectDependencies) = postProject + {ABB5EAE7-B3E6-432E-B636-333449892EA6} = {ABB5EAE7-B3E6-432E-B636-333449892EA6} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GUIStub", "GUIStub\Stub.vcxproj", "{47007458-C534-493F-9A4C-936E5E0C91C8}" ProjectSection(ProjectDependencies) = postProject @@ -28,6 +37,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GUIStub", "GUIStub\Stub.vcx EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleToGo", "ConsoleToGo\ConsoleToGo.vcxproj", "{714480A5-0779-4C59-8A08-856E5C34AC37}" + ProjectSection(ProjectDependencies) = postProject + {ABB5EAE7-B3E6-432E-B636-333449892EA6} = {ABB5EAE7-B3E6-432E-B636-333449892EA6} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Console", "ConsoleStub\Console.vcxproj", "{F6BBF41C-E4E0-4514-BA19-E248DE206820}" ProjectSection(ProjectDependencies) = postProject @@ -37,6 +49,7 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GUIToGo", "ToGoStub\GuiToGo.vcxproj", "{12B536BA-143E-4F38-BD96-77B35467DB13}" ProjectSection(ProjectDependencies) = postProject {241D4E3E-44C0-40B7-BE1B-5249916FE631} = {241D4E3E-44C0-40B7-BE1B-5249916FE631} + {ABB5EAE7-B3E6-432E-B636-333449892EA6} = {ABB5EAE7-B3E6-432E-B636-333449892EA6} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Stubs", "Stubs", "{F6CB1D3C-CC39-4BCA-AC1A-DF0D1CA27580}" @@ -51,19 +64,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VMLib", "VMLib\VMLib.vcxite EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib.vcxitems", "{1F161730-1E11-4FBD-A4DF-F6E9B5577F5E}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mimalloc", "mimalloc\ide\vs2022\mimalloc.vcxproj", "{ABB5EAE7-B3E6-432E-B636-333449892EA6}" +EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - VMLib\VMLib.vcxitems*{12b536ba-143e-4f38-bd96-77b35467db13}*SharedItemsImports = 4 - zlib\zlib.vcxitems*{12b536ba-143e-4f38-bd96-77b35467db13}*SharedItemsImports = 4 - zlib\zlib.vcxitems*{1f161730-1e11-4fbd-a4df-f6e9b5577f5e}*SharedItemsImports = 9 - VMLib\VMLib.vcxitems*{382abbf3-b32d-4d77-b303-346aa146921c}*SharedItemsImports = 4 - zlib\zlib.vcxitems*{382abbf3-b32d-4d77-b303-346aa146921c}*SharedItemsImports = 4 - VMLib\VMLib.vcxitems*{714480a5-0779-4c59-8a08-856e5c34ac37}*SharedItemsImports = 4 - zlib\zlib.vcxitems*{714480a5-0779-4c59-8a08-856e5c34ac37}*SharedItemsImports = 4 - VMLib\VMLib.vcxitems*{90c32f90-c0b1-46fe-bace-fb6566eb6f3c}*SharedItemsImports = 4 - zlib\zlib.vcxitems*{90c32f90-c0b1-46fe-bace-fb6566eb6f3c}*SharedItemsImports = 4 - VMLib\VMLib.vcxitems*{bc5d162d-46bc-42cf-85db-cb715ee8517e}*SharedItemsImports = 9 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 @@ -130,6 +133,12 @@ Global {12B536BA-143E-4F38-BD96-77B35467DB13}.Release|Win32.ActiveCfg = Release|Win32 {12B536BA-143E-4F38-BD96-77B35467DB13}.Release|Win32.Build.0 = Release|Win32 {12B536BA-143E-4F38-BD96-77B35467DB13}.VM Debug|Win32.ActiveCfg = VM Debug|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|Win32.ActiveCfg = Debug|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Debug|Win32.Build.0 = Debug|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|Win32.ActiveCfg = Release|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.Release|Win32.Build.0 = Release|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.VM Debug|Win32.ActiveCfg = Debug|Win32 + {ABB5EAE7-B3E6-432E-B636-333449892EA6}.VM Debug|Win32.Build.0 = Debug|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -145,4 +154,16 @@ Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {808FD94F-FA41-4A9A-B2BC-2010D373F582} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + VMLib\VMLib.vcxitems*{12b536ba-143e-4f38-bd96-77b35467db13}*SharedItemsImports = 4 + zlib\zlib.vcxitems*{12b536ba-143e-4f38-bd96-77b35467db13}*SharedItemsImports = 4 + zlib\zlib.vcxitems*{1f161730-1e11-4fbd-a4df-f6e9b5577f5e}*SharedItemsImports = 9 + VMLib\VMLib.vcxitems*{382abbf3-b32d-4d77-b303-346aa146921c}*SharedItemsImports = 4 + zlib\zlib.vcxitems*{382abbf3-b32d-4d77-b303-346aa146921c}*SharedItemsImports = 4 + VMLib\VMLib.vcxitems*{714480a5-0779-4c59-8a08-856e5c34ac37}*SharedItemsImports = 4 + zlib\zlib.vcxitems*{714480a5-0779-4c59-8a08-856e5c34ac37}*SharedItemsImports = 4 + VMLib\VMLib.vcxitems*{90c32f90-c0b1-46fe-bace-fb6566eb6f3c}*SharedItemsImports = 4 + zlib\zlib.vcxitems*{90c32f90-c0b1-46fe-bace-fb6566eb6f3c}*SharedItemsImports = 4 + VMLib\VMLib.vcxitems*{bc5d162d-46bc-42cf-85db-cb715ee8517e}*SharedItemsImports = 9 + EndGlobalSection EndGlobal diff --git a/Core/DolphinVM/GC.cpp b/Core/DolphinVM/GC.cpp index 8d518c92f7..a1eee99bf9 100644 --- a/Core/DolphinVM/GC.cpp +++ b/Core/DolphinVM/GC.cpp @@ -185,7 +185,7 @@ void ObjectMemory::reclaimInaccessibleObjects(uintptr_t gcFlags) nMaxUnmarked = 512; else nMaxUnmarked = nMaxUnmarked << 1; - pUnmarked = static_cast(realloc(pUnmarked, nMaxUnmarked*sizeof(OTE*))); + pUnmarked = static_cast(reallocChunk(pUnmarked, nMaxUnmarked*sizeof(OTE*))); if (pUnmarked == nullptr) { ::RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, nullptr); @@ -377,7 +377,7 @@ void ObjectMemory::reclaimInaccessibleObjects(uintptr_t gcFlags) } } - free(pUnmarked); + freeChunk(pUnmarked); #ifdef VERBOSEGC { @@ -399,7 +399,7 @@ void ObjectMemory::reclaimInaccessibleObjects(uintptr_t gcFlags) } #endif - __sbh_heapmin(); + //mi_collect(false); #ifdef _DEBUG checkReferences(); @@ -447,40 +447,6 @@ size_t ObjectMemory::CountFreeOTEs() #ifdef _DEBUG - void ObjectMemory::checkPools() - { - const size_t loopEnd = m_nOTSize; - for (size_t i=OTBase;i MaxSizeOfPoolObject) - { - if (size <= MaxSmallObjectSize) - HARDASSERT(__sbh_find_block(ote.m_location)) - else - { - tracelock lock(TRACESTREAM); - TRACESTREAM<< L"Found large object (size = " << size - << L") in space " << (int)space - << L": " << &ote << std::endl; - } - } - else - if (size != 0) - HARDASSERT(spacePoolForSize(size).isMyChunk(ote.m_location)) - } - } - } - for (auto j=0;j 3) HARDASSERT(::HeapValidate(m_hHeap, 0, 0)); #endif // HARDASSERT(_CrtCheckMemory()); - HARDASSERT(__sbh_heap_check() >= 0); //checkPools(); HARDASSERT(m_nFreeOTEs == CountFreeOTEs()); @@ -556,19 +521,6 @@ size_t ObjectMemory::CountFreeOTEs() //errors++; }*/ OTE* ote = &m_pOT[i]; - if (!ote->isFree()) - { - Spaces space = ote->heapSpace(); - if (space == Spaces::Pools) - { - HARDASSERT(ote->sizeOf() <= MaxSmallObjectSize); - } - else if (space == Spaces::Normal) - { - // Not a valid assertion as objects can be resized down below the threshold - //HARDASSERT(ote->sizeOf() > MaxSmallObjectSize); - } - } currentRefs[i] = ote->m_count; ote->m_count = 0; } diff --git a/Core/DolphinVM/InProcToGo/IPToGo.def b/Core/DolphinVM/InProcToGo/IPToGo.def index e75722b587..a8fde3ea84 100644 --- a/Core/DolphinVM/InProcToGo/IPToGo.def +++ b/Core/DolphinVM/InProcToGo/IPToGo.def @@ -34,64 +34,6 @@ AxWinTerm compress2 uncompress - -; CRT functions imported by the image - - _chsize_s - _clearfp - _close - _control87 - _dup - _dup2 - _errno - _fdopen - _filelengthi64 - _fileno - _fseeki64 - _ftelli64 - _get_invalid_parameter_handler - _get_osfhandle - _isatty - _makepath_s - _open_osfhandle - _setmode - _splitpath_s - _statusfp - _wcserror_s - _wcsicmp - _wfsopen - atoi - fclose - feof - fflush - fgetc - fgets - fgetwc - fgetws - fputc - fputs - fputwc - fputws - fread_s - free - fwrite - memcmp - memcpy_s - rand - setlocale - srand - strcat_s - strcmp - strcspn - strlen - strncmp - strncpy_s - ungetc - ungetwc - wcslen - wcscspn - wcsncpy_s - ; VMLibrary _snprintf_s diff --git a/Core/DolphinVM/InProcToGo/InProcToGo.vcxproj b/Core/DolphinVM/InProcToGo/InProcToGo.vcxproj index 32bc87b7cd..2a1f1e27ad 100644 --- a/Core/DolphinVM/InProcToGo/InProcToGo.vcxproj +++ b/Core/DolphinVM/InProcToGo/InProcToGo.vcxproj @@ -102,7 +102,7 @@ TO_GO;WIN32;_WINDOWS;WIN32_LEAN_AND_MEAN;WIN32_EXTRA_LEAN;STRICT;_MERGE_PROXYSTUB;ZEXPORT=__stdcall;ZEXPORTVA=__cdecl;_CRT_SECURE_NO_WARNINGS;_HAS_EXCEPTIONS=0;NDEBUG;%(PreprocessorDefinitions) - MultiThreaded + MultiThreadedDLL Use ist.h @@ -123,6 +123,7 @@ .\Release/IPDolphinToGo.lib false + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) @@ -143,7 +144,7 @@ Disabled TO_GO;WIN32;_WINDOWS;WIN32_LEAN_AND_MEAN;WIN32_EXTRA_LEAN;STRICT;_MERGE_PROXYSTUB;ZEXPORT=__stdcall;ZEXPORTVA=__cdecl;_CRT_SECURE_NO_WARNINGS;_HAS_EXCEPTIONS=0;DEBUG;_DEBUG;%(PreprocessorDefinitions) true - MultiThreadedDebug + MultiThreadedDebugDLL false true true @@ -184,6 +185,7 @@ true true true + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) @@ -205,7 +207,7 @@ Disabled TO_GO;WIN32;_WINDOWS;WIN32_LEAN_AND_MEAN;WIN32_EXTRA_LEAN;STRICT;_MERGE_PROXYSTUB;ZEXPORT=__stdcall;ZEXPORTVA=__cdecl;_CRT_SECURE_NO_WARNINGS;_HAS_EXCEPTIONS=0;DEBUG;_DEBUG;%(PreprocessorDefinitions) true - MultiThreadedDebug + MultiThreadedDebugDLL false true true @@ -247,6 +249,7 @@ true true true + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) diff --git a/Core/DolphinVM/LoadImage.cpp b/Core/DolphinVM/LoadImage.cpp index 642491fdab..aac2868803 100755 --- a/Core/DolphinVM/LoadImage.cpp +++ b/Core/DolphinVM/LoadImage.cpp @@ -12,7 +12,6 @@ #include "binstream.h" #include "zbinstream.h" #include "objmem.h" -#include "ObjMemPriv.inl" #include "interprt.h" #include "rc_vm.h" @@ -344,20 +343,8 @@ template HRESULT ObjectMemory::LoadObjects(ibinstream& i ST::Object* ObjectMemory::AllocObj(OTE * ote, size_t allocSize) { - ST::Object* pObj; - if (allocSize <= MaxSmallObjectSize) - { - // Allocate from one of the memory pools - pObj = static_cast(allocSmallChunk(allocSize)); - ote->m_flags.m_space = static_cast(Spaces::Pools); - } - else - { - // Normal space and other spaces allocated from heap (may not be too many) - pObj = static_cast(allocChunk(allocSize)); - ote->m_flags.m_space = static_cast(Spaces::Normal); - } - + ST::Object* pObj = static_cast(allocChunk(allocSize)); + ote->m_flags.m_space = static_cast(Spaces::Normal); ote->m_location = pObj; return pObj; } @@ -424,7 +411,7 @@ void ObjectMemory::FixupObject(OTE* ote, uintptr_t* oldLocation, const ImageHead // Look for the special image stamp object else if (classPointer == _Pointers.ClassContext) { - ASSERT(ote->heapSpace() == Spaces::Pools || ote->heapSpace() == Spaces::Normal); + ASSERT(ote->heapSpace() == Spaces::Normal); // Can't deallocate now - must leave for collection later - maybe could go in the Zct though. VERIFY(ote->decRefs()); diff --git a/Core/DolphinVM/ObjMemInit.cpp b/Core/DolphinVM/ObjMemInit.cpp index add1e9451f..55117f1f40 100755 --- a/Core/DolphinVM/ObjMemInit.cpp +++ b/Core/DolphinVM/ObjMemInit.cpp @@ -20,7 +20,6 @@ #include "ObjMem.h" -#include "ObjMemPriv.inl" #include "Interprt.h" #include "rc_vm.h" #include "VMExcept.h" @@ -49,13 +48,6 @@ static HRESULT getSystemInfo() return S_OK; } -void ObjectMemory::FixedSizePool::Initialize() -{ - m_pFreePages = NULL; - m_pAllocations = NULL; - m_nAllocations = 0; -} - HRESULT ObjectMemory::Initialize() { // Assembler will need to be modified if these are not the case @@ -70,8 +62,6 @@ HRESULT ObjectMemory::Initialize() ASSERT(Context::FixedSize == 2); ASSERT(BlockClosure::FixedSize == 5); ASSERT(sizeof(BlockCopyExtension) == sizeof(uint32_t)); - ASSERT(MinObjectSize >= sizeof(Oop)); - ASSERT(_ROUND2(MinObjectSize,sizeof(Oop)) == MinObjectSize); //ASSERT(sizeof(Object) == ObjectHeaderSize*sizeof(MWORD)); ASSERT(sizeof(VMPointers) == (192*sizeof(Oop)+ObjectByteSize)); // Check that the const objects segment is still exactly one page @@ -105,8 +95,6 @@ HRESULT ObjectMemory::Initialize() if (FAILED(hr)) return hr; - FixedSizePool::Initialize(); - m_nNextIdHash = 1 << 16 | 1; m_nOTSize = OTDefaultSize; m_nOTMax = OTDefaultMax; @@ -131,37 +119,11 @@ HRESULT ObjectMemory::Initialize() m_spaceOTEBits[static_cast(Spaces::Heap)].m_pointer = FALSE; m_spaceOTEBits[static_cast(Spaces::Floats)].m_pointer = FALSE; - //MaxSizeOfPoolObject = PoolObjectSizeLimit; - //NumPools = MaxPools; - - //CRegKey rk; - //if (OpenDolphinKey(rk, "") == ERROR_SUCCESS) - //{ - // rk.QueryDWORDValue("PoolThreshold", MaxSizeOfPoolObject); - // if (MaxSizeOfPoolObject > PoolObjectSizeLimit) - // MaxSizeOfPoolObject = PoolObjectSizeLimit; - // NumPools = MaxSizeOfPoolObject < MinObjectSize ? 0 : - // (MaxSizeOfPoolObject-MinObjectSize)/PoolGranularity + 1; - // ASSERT(NumPools >= 0 && NumPools <= MaxPools); - //} - - for (auto j=0;j(::HeapAlloc(m_hHeap, 0, chunkSize)); - #ifdef _DEBUG - memset(pObj, 0xCD, chunkSize); - #endif - return pObj; - #else - return malloc(chunkSize); - #endif -} - -extern "C" ST::Object emptyObj; - -inline POBJECT ObjectMemory::allocSmallChunk(size_t chunkSize) -{ -#ifdef MEMSTATS - ++m_nSmallAllocated; -#endif - - ASSERT(chunkSize <= MaxSmallObjectSize); - return chunkSize <= MaxSizeOfPoolObject - ? (chunkSize == 0 - ? &emptyObj - : // Use chunk pools, which are fast but can cause memory fragmentation - spacePoolForSize(chunkSize).allocate()) - : static_cast(__sbh_alloc_block(chunkSize)); -} - -inline void ObjectMemory::freeSmallChunk(POBJECT pBlock, size_t size) -{ -#ifdef MEMSTATS - ++m_nSmallFreed; -#endif - - ASSERT(size <= MaxSmallObjectSize); - if (size <= MaxSizeOfPoolObject) - { - if (pBlock != &emptyObj) - spacePoolForSize(size).deallocate(pBlock); - } - else - { - // Locate and dealloc SBH block - PHEADER pHeader = __sbh_find_block(pBlock); - ASSERT(pHeader != NULL); - __sbh_free_block(pHeader, pBlock); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Oop allocation - -inline OTE* __fastcall ObjectMemory::allocateOop(POBJECT pLocation) -{ - __assume(m_pFreePointerList != nullptr); - - // N.B. By not ref. counting class here, we make a useful saving of a redundant - // ref. counting operation in primitiveNew and primitiveNewWithArg - - OTE* ote = m_pFreePointerList; - - m_pFreePointerList = NextFree(ote); - - ASSERT(ote->isFree()); -#ifdef TRACKFREEOTEs - --m_nFreeOTEs; - assert(m_nFreeOTEs >= 0); - //assert(m_nFreeOTEs == CountFreeOTEs()); -#endif - - // Set OTE fields of the Oop - ote->m_location = pLocation; - - // Maintain the last used garbage collector mark to speed up collections - // Doing this will also reset the free bit and set the pointer bit - // so byte allocations will need to reset it - ote->m_flagsWord = *reinterpret_cast(&m_spaceOTEBits[static_cast(Spaces::Pools)]); - - return ote; -} - diff --git a/Core/DolphinVM/SBHEAP.C b/Core/DolphinVM/SBHEAP.C deleted file mode 100755 index 76878f3995..0000000000 --- a/Core/DolphinVM/SBHEAP.C +++ /dev/null @@ -1,1470 +0,0 @@ -// This is the Small Block heap from VC6 -// The reason for linking it in statically is to avoid the overhead -// of the critical section locks (Dolphin is not multi-threaded at this level) - -/*** -*sbheap.c - Small-block heap code -* -* Copyright (c) Microsoft Corporation. All rights reserved. -* -*Purpose: -* Core code for small-block heap. -* -*******************************************************************************/ - -#include "segdefs.h" -#pragma code_seg(MEM_SEG) - -#undef _CRTBLD -#include -#include -#include -#include "sbheap.h" - -#define _CRTBLD -#include "winheap.h" -#include -/* -#include -#include -*/ -#include -#include - -size_t __sbh_threshold; - -PHEADER __sbh_pHeaderList; // pointer to list start -PHEADER __sbh_pHeaderScan; // pointer to list rover -int __sbh_sizeHeaderList; // allocated size of list -int __sbh_cntHeaderList; // count of entries defined - -PHEADER __sbh_pHeaderDefer=NULL; -int __sbh_indGroupDefer; - -/************************ BEGIN BSM MODIFICATION ******************************/ -// BSM wants to use stdcall rather than cdecl because it is typically faster -#define __cdecl __stdcall -/************************ END BSM MODIFICATION ********************************/ - -/* Prototypes for user functions */ -size_t __cdecl _get_sbh_threshold(void); -int __cdecl _set_sbh_threshold(size_t); - -void DumpEntry(char *, int *); - -/*** -*size_t _get_sbh_threshold() - return small-block threshold -* -*Purpose: -* Return the current value of __sbh_threshold -* -*Entry: -* None. -* -*Exit: -* See above. -* -*Exceptions: -* -*******************************************************************************/ - -size_t __cdecl _get_sbh_threshold (void) -{ - /* Ensure already initialised */ - if(!_crtheap) - { - return 0; - } - return __sbh_threshold; -} - -/*** -*int _set_sbh_threshold(threshold) - set small-block heap threshold -* -*Purpose: -* Set the upper limit for the size of an allocation which will be -* supported from the small-block heap. -* -*Entry: -* size_t threshold - proposed new value for __sbh_theshold -* -*Exit: -* Returns 1 if successful. Returns 0 if threshold was invalid. -* -*Exceptions: -* Input parameters are validated. Refer to the validation section of the function. -* -*******************************************************************************/ - -int __cdecl _set_sbh_threshold (size_t threshold) -{ - if(!_crtheap) - { - return 0; - } - - // test against maximum value - if too large, return error - if (threshold > MAX_ALLOC_DATA_SIZE) - { - errno = EINVAL; - return 0; - } - __sbh_threshold = threshold; - return 1; -} - -/*** -*int __sbh_heap_init() - set small-block heap threshold -* -*Purpose: -* Allocate space for initial header list and init variables. -* -*Entry: -* None. -* -*Exit: -* Returns 1 if successful. Returns 0 if initialization failed. -* -*Exceptions: -* -*******************************************************************************/ -int __cdecl __sbh_heap_init (size_t threshold) -{ - if (!(__sbh_pHeaderList = HeapAlloc(_crtheap, 0, 16 * sizeof(HEADER)))) - return FALSE; - - __sbh_threshold = threshold; - __sbh_pHeaderScan = __sbh_pHeaderList; - __sbh_pHeaderDefer = NULL; - __sbh_cntHeaderList = 0; - __sbh_sizeHeaderList = 16; - - return TRUE; -} - -/*** -*PHEADER *__sbh_find_block(pvAlloc) - find block in small-block heap -* -*Purpose: -* Determine if the specified allocation block lies in the small-block -* heap and, if so, return the header to be used for the block. -* -*Entry: -* void * pvBlock - pointer to block to be freed -* -*Exit: -* If successful, a pointer to the header to use is returned. -* If unsuccessful, NULL is returned. -* -*Exceptions: -* -*******************************************************************************/ - -PHEADER __cdecl __sbh_find_block (void * pvAlloc) -{ - PHEADER pHeaderLast = __sbh_pHeaderList + __sbh_cntHeaderList; - PHEADER pHeader; - unsigned int offRegion; - - // scan through the header list to determine if entry - // is in the region heap data reserved address space - pHeader = __sbh_pHeaderList; - while (pHeader < pHeaderLast) - { - offRegion = (unsigned int)((uintptr_t)pvAlloc - (uintptr_t)pHeader->pHeapData); - if (offRegion < BYTES_PER_REGION) - return pHeader; - pHeader++; - } - return NULL; -} - -#ifdef _DEBUG - -/*** -*int __sbh_verify_block(pHeader, pvAlloc) - verify pointer in sbh -* -*Purpose: -* Test if pointer is valid within the heap header given. -* -*Entry: -* pHeader - pointer to HEADER where entry should be -* pvAlloc - pointer to test validity of -* -*Exit: -* Returns 1 if pointer is valid, else 0. -* -*Exceptions: -* -*******************************************************************************/ - -int __cdecl __sbh_verify_block (PHEADER pHeader, void * pvAlloc) -{ - unsigned int indGroup; - unsigned int offRegion; - - // calculate region offset to determine the group index - offRegion = (unsigned int)((uintptr_t)pvAlloc - (uintptr_t)pHeader->pHeapData); - indGroup = offRegion / BYTES_PER_GROUP; - - // return TRUE if: - // group is committed (bit in vector cleared) AND - // pointer is at paragraph boundary AND - // pointer is not at start of page - return (!(pHeader->bitvCommit & (0x80000000UL >> indGroup))) && - (!(offRegion & 0xf)) && - (offRegion & (BYTES_PER_PAGE - 1)); -} - -#endif /* _DEBUG */ - -/*** -*void __sbh_free_block(preg, ppage, pmap) - free block -* -*Purpose: -* Free the specified block from the small-block heap. -* -*Entry: -* pHeader - pointer to HEADER of region to free memory -* pvAlloc - pointer to memory to free -* -*Exit: -* No return value. -* -*Exceptions: -* -*******************************************************************************/ - -void __cdecl __sbh_free_block (PHEADER pHeader, void * pvAlloc) -{ - PREGION pRegion; - PGROUP pGroup; - PENTRY pHead; - PENTRY pEntry; - PENTRY pNext; - PENTRY pPrev; - void * pHeapDecommit; - int sizeEntry; - int sizeNext; - int sizePrev; - unsigned int indGroup; - unsigned int indEntry; - unsigned int indNext; - unsigned int indPrev; - unsigned int offRegion; - - // region is determined by the header - pRegion = pHeader->pRegion; - - // use the region offset to determine the group index - offRegion = (unsigned int)(((uintptr_t)pvAlloc - (uintptr_t)pHeader->pHeapData)); - indGroup = offRegion / BYTES_PER_GROUP; - pGroup = &pRegion->grpHeadList[indGroup]; - - // get size of entry - decrement value since entry is allocated - pEntry = (PENTRY)((char *)pvAlloc - sizeof(int)); - sizeEntry = pEntry->sizeFront - 1; - - // check if the entry is already free. note the size has already been - // decremented - if ( (sizeEntry & 1 ) != 0 ) - return; - - // point to next entry to get its size - pNext = (PENTRY)((char *)pEntry + sizeEntry); - sizeNext = pNext->sizeFront; - - // get size from end of previous entry - sizePrev = ((PENTRYEND)((char *)pEntry - sizeof(int)))->sizeBack; - - // test if next entry is free by an even size value - - if ((sizeNext & 1) == 0) - { - // free next entry - disconnect and add its size to sizeEntry - - // determine index of next entry - indNext = (sizeNext >> 4) - 1; - if (indNext > 63) - indNext = 63; - - // test entry is sole member of bucket (next == prev), - if (pNext->pEntryNext == pNext->pEntryPrev) - { - // clear bit in group vector, decrement region count - // if region count is now zero, clear bit in header - // entry vector - if (indNext < 32) - { - pRegion->bitvGroupHi[indGroup] &= ~(0x80000000L >> indNext); - if (--pRegion->cntRegionSize[indNext] == 0) - pHeader->bitvEntryHi &= ~(0x80000000L >> indNext); - } - else - { - pRegion->bitvGroupLo[indGroup] &= - ~(0x80000000L >> (indNext - 32)); - if (--pRegion->cntRegionSize[indNext] == 0) - pHeader->bitvEntryLo &= ~(0x80000000L >> (indNext - 32)); - } - } - - // unlink entry from list - pNext->pEntryPrev->pEntryNext = pNext->pEntryNext; - pNext->pEntryNext->pEntryPrev = pNext->pEntryPrev; - - // add next entry size to freed entry size - sizeEntry += sizeNext; - } - - // compute index of free entry (plus next entry if it was free) - indEntry = (sizeEntry >> 4) - 1; - if (indEntry > 63) - indEntry = 63; - - // test if previous entry is free by an even size value - if ((sizePrev & 1) == 0) - { - // free previous entry - add size to sizeEntry and - // disconnect if index changes - - // get pointer to previous entry - pPrev = (PENTRY)((char *)pEntry - sizePrev); - - // determine index of previous entry - indPrev = (sizePrev >> 4) - 1; - if (indPrev > 63) - indPrev = 63; - - // add previous entry size to sizeEntry and determine - // its new index - sizeEntry += sizePrev; - indEntry = (sizeEntry >> 4) - 1; - if (indEntry > 63) - indEntry = 63; - - // if index changed due to coalesing, reconnect to new size - if (indPrev != indEntry) - { - // disconnect entry from indPrev - // test entry is sole member of bucket (next == prev), - if (pPrev->pEntryNext == pPrev->pEntryPrev) - { - // clear bit in group vector, decrement region count - // if region count is now zero, clear bit in header - // entry vector - if (indPrev < 32) - { - pRegion->bitvGroupHi[indGroup] &= - ~(0x80000000L >> indPrev); - if (--pRegion->cntRegionSize[indPrev] == 0) - pHeader->bitvEntryHi &= ~(0x80000000L >> indPrev); - } - else - { - pRegion->bitvGroupLo[indGroup] &= - ~(0x80000000L >> (indPrev - 32)); - if (--pRegion->cntRegionSize[indPrev] == 0) - pHeader->bitvEntryLo &= - ~(0x80000000L >> (indPrev - 32)); - } - } - - // unlink entry from list - pPrev->pEntryPrev->pEntryNext = pPrev->pEntryNext; - pPrev->pEntryNext->pEntryPrev = pPrev->pEntryPrev; - } - // set pointer to connect it instead of the free entry - pEntry = pPrev; - } - - // test if previous entry was free with an index change or allocated - if (!((sizePrev & 1) == 0 && indPrev == indEntry)) - { - // connect pEntry entry to indEntry - // add entry to the start of the bucket list - pHead = (PENTRY)((char *)&pGroup->listHead[indEntry] - sizeof(int)); - pEntry->pEntryNext = pHead->pEntryNext; - pEntry->pEntryPrev = pHead; - pHead->pEntryNext = pEntry; - pEntry->pEntryNext->pEntryPrev = pEntry; - - // test entry is sole member of bucket (next == prev), - if (pEntry->pEntryNext == pEntry->pEntryPrev) - { - // if region count was zero, set bit in region vector - // set bit in header entry vector, increment region count - if (indEntry < 32) - { - if (pRegion->cntRegionSize[indEntry]++ == 0) - pHeader->bitvEntryHi |= 0x80000000L >> indEntry; - pRegion->bitvGroupHi[indGroup] |= 0x80000000L >> indEntry; - } - else - { - if (pRegion->cntRegionSize[indEntry]++ == 0) - pHeader->bitvEntryLo |= 0x80000000L >> (indEntry - 32); - pRegion->bitvGroupLo[indGroup] |= 0x80000000L >> - (indEntry - 32); - } - } - } - - // adjust the entry size front and back - pEntry->sizeFront = sizeEntry; - ((PENTRYEND)((char *)pEntry + sizeEntry - - sizeof(ENTRYEND)))->sizeBack = sizeEntry; - - // one less allocation in group - test if empty - if (--pGroup->cntEntries == 0) - { - // if a group has been deferred, free that group - if (__sbh_pHeaderDefer) - { - // if now zero, decommit the group data heap - pHeapDecommit = (void *)((char *)__sbh_pHeaderDefer->pHeapData + - __sbh_indGroupDefer * BYTES_PER_GROUP); - VirtualFree(pHeapDecommit, BYTES_PER_GROUP, MEM_DECOMMIT); - - // set bit in commit vector - __sbh_pHeaderDefer->bitvCommit |= - 0x80000000 >> __sbh_indGroupDefer; - - // clear entry vector for the group and header vector bit - // if needed - __sbh_pHeaderDefer->pRegion->bitvGroupLo[__sbh_indGroupDefer] = 0; - if (--__sbh_pHeaderDefer->pRegion->cntRegionSize[63] == 0) - __sbh_pHeaderDefer->bitvEntryLo &= ~0x00000001L; - - // if commit vector is the initial value, - // remove the region if it is not the last - if (__sbh_pHeaderDefer->bitvCommit == BITV_COMMIT_INIT) - { - // release the address space for heap data - VirtualFree(__sbh_pHeaderDefer->pHeapData, 0, MEM_RELEASE); - - // free the region memory area - HeapFree(_crtheap, 0, __sbh_pHeaderDefer->pRegion); - - // remove entry from header list by copying over - memmove((void *)__sbh_pHeaderDefer, - (void *)(__sbh_pHeaderDefer + 1), - (int)((intptr_t)(__sbh_pHeaderList + __sbh_cntHeaderList) - - (intptr_t)(__sbh_pHeaderDefer + 1))); - __sbh_cntHeaderList--; - - // if pHeader was after the one just removed, adjust it - if (pHeader > __sbh_pHeaderDefer) - pHeader--; - - // initialize scan pointer to start of list - __sbh_pHeaderScan = __sbh_pHeaderList; - } - } - - // defer the group just freed - __sbh_pHeaderDefer = pHeader; - __sbh_indGroupDefer = indGroup; - } -} - -/*** -*void * __sbh_alloc_block(intSize) - allocate a block -* -*Purpose: -* Allocate a block from the small-block heap, the specified number of -* bytes in size. -* -*Entry: -* intSize - size of the allocation request in bytes -* -*Exit: -* Returns a pointer to the newly allocated block, if successful. -* Returns NULL, if failure. -* -*Exceptions: -* -*******************************************************************************/ - -void * __cdecl __sbh_alloc_block (int intSize) -{ - PHEADER pHeaderLast = __sbh_pHeaderList + __sbh_cntHeaderList; - PHEADER pHeader; - PREGION pRegion; - PGROUP pGroup; - PENTRY pEntry; - PENTRY pHead; - BITVEC bitvEntryLo; - BITVEC bitvEntryHi; - BITVEC bitvTest; - int sizeEntry; - int indEntry; - int indGroupUse; - int sizeNewFree; - int indNewFree; - - // add 8 bytes entry overhead and round up to next para size - sizeEntry = (intSize + 2 * (int)sizeof(int) + (BYTES_PER_PARA - 1)) - & ~(BYTES_PER_PARA - 1); - - // determine index and mask from entry size - // Hi MSB: bit 0 size: 1 paragraph - // bit 1 2 paragraphs - // ... ... - // bit 30 31 paragraphs - // bit 31 32 paragraphs - // Lo MSB: bit 0 size: 33 paragraph - // bit 1 34 paragraphs - // ... ... - // bit 30 63 paragraphs - // bit 31 64+ paragraphs - indEntry = (sizeEntry >> 4) - 1; - if (indEntry < 32) - { - bitvEntryHi = 0xffffffffUL >> indEntry; - bitvEntryLo = 0xffffffffUL; - } - else - { - bitvEntryHi = 0; - bitvEntryLo = 0xffffffffUL >> (indEntry - 32); - } - - // scan header list from rover to end for region with a free - // entry with an adequate size - pHeader = __sbh_pHeaderScan; - while (pHeader < pHeaderLast) - { - if ((bitvEntryHi & pHeader->bitvEntryHi) | - (bitvEntryLo & pHeader->bitvEntryLo)) - break; - pHeader++; - } - - // if no entry, scan from list start up to the rover - if (pHeader == pHeaderLast) - { - pHeader = __sbh_pHeaderList; - while (pHeader < __sbh_pHeaderScan) - { - if ((bitvEntryHi & pHeader->bitvEntryHi) | - (bitvEntryLo & pHeader->bitvEntryLo)) - break; - pHeader++; - } - - // no free entry exists, scan list from rover to end - // for available groups to commit - if (pHeader == __sbh_pHeaderScan) - { - while (pHeader < pHeaderLast) - { - if (pHeader->bitvCommit) - break; - pHeader++; - } - - // if no available groups, scan from start to rover - if (pHeader == pHeaderLast) - { - pHeader = __sbh_pHeaderList; - while (pHeader < __sbh_pHeaderScan) - { - if (pHeader->bitvCommit) - break; - pHeader++; - } - - // if no available groups, create a new region - if (pHeader == __sbh_pHeaderScan) - if (!(pHeader = __sbh_alloc_new_region())) - return NULL; - } - - // commit a new group in region associated with pHeader - if ((pHeader->pRegion->indGroupUse = - __sbh_alloc_new_group(pHeader)) == -1) - return NULL; - } - } - __sbh_pHeaderScan = pHeader; - - pRegion = pHeader->pRegion; - indGroupUse = pRegion->indGroupUse; - - // determine the group to allocate from - if (indGroupUse == -1 || - !((bitvEntryHi & pRegion->bitvGroupHi[indGroupUse]) | - (bitvEntryLo & pRegion->bitvGroupLo[indGroupUse]))) - { - // preferred group could not allocate entry, so - // scan through all defined vectors - indGroupUse = 0; - while (!((bitvEntryHi & pRegion->bitvGroupHi[indGroupUse]) | - (bitvEntryLo & pRegion->bitvGroupLo[indGroupUse]))) - indGroupUse++; - } - pGroup = &pRegion->grpHeadList[indGroupUse]; - - // determine bucket index - indEntry = 0; - - // get high entry intersection - if zero, use the lower one - if (!(bitvTest = bitvEntryHi & pRegion->bitvGroupHi[indGroupUse])) - { - indEntry = 32; - bitvTest = bitvEntryLo & pRegion->bitvGroupLo[indGroupUse]; - } - while ((int)bitvTest >= 0) - { - bitvTest <<= 1; - indEntry++; - } - pEntry = pGroup->listHead[indEntry].pEntryNext; - - // compute size and bucket index of new free entry - - // for zero-sized entry, the index is -1 - sizeNewFree = pEntry->sizeFront - sizeEntry; - indNewFree = (sizeNewFree >> 4) - 1; - if (indNewFree > 63) - indNewFree = 63; - - // only modify entry pointers if bucket index changed - if (indNewFree != indEntry) - { - // test entry is sole member of bucket (next == prev), - if (pEntry->pEntryNext == pEntry->pEntryPrev) - { - // clear bit in group vector, decrement region count - // if region count is now zero, clear bit in region vector - if (indEntry < 32) - { - pRegion->bitvGroupHi[indGroupUse] &= - ~(0x80000000L >> indEntry); - if (--pRegion->cntRegionSize[indEntry] == 0) - pHeader->bitvEntryHi &= ~(0x80000000L >> indEntry); - } - else - { - pRegion->bitvGroupLo[indGroupUse] &= - ~(0x80000000L >> (indEntry - 32)); - if (--pRegion->cntRegionSize[indEntry] == 0) - pHeader->bitvEntryLo &= ~(0x80000000L >> (indEntry - 32)); - } - } - - // unlink entry from list - pEntry->pEntryPrev->pEntryNext = pEntry->pEntryNext; - pEntry->pEntryNext->pEntryPrev = pEntry->pEntryPrev; - - // if free entry size is still nonzero, reconnect it - if (sizeNewFree != 0) - { - // add entry to the start of the bucket list - pHead = (PENTRY)((char *)&pGroup->listHead[indNewFree] - - sizeof(int)); - pEntry->pEntryNext = pHead->pEntryNext; - pEntry->pEntryPrev = pHead; - pHead->pEntryNext = pEntry; - pEntry->pEntryNext->pEntryPrev = pEntry; - - // test entry is sole member of bucket (next == prev), - if (pEntry->pEntryNext == pEntry->pEntryPrev) - { - // if region count was zero, set bit in region vector - // set bit in group vector, increment region count - if (indNewFree < 32) - { - if (pRegion->cntRegionSize[indNewFree]++ == 0) - pHeader->bitvEntryHi |= 0x80000000L >> indNewFree; - pRegion->bitvGroupHi[indGroupUse] |= - 0x80000000L >> indNewFree; - } - else - { - if (pRegion->cntRegionSize[indNewFree]++ == 0) - pHeader->bitvEntryLo |= - 0x80000000L >> (indNewFree - 32); - pRegion->bitvGroupLo[indGroupUse] |= - 0x80000000L >> (indNewFree - 32); - } - } - } - } - - // change size of free entry (front and back) - if (sizeNewFree != 0) - { - pEntry->sizeFront = sizeNewFree; - ((PENTRYEND)((char *)pEntry + sizeNewFree - - sizeof(ENTRYEND)))->sizeBack = sizeNewFree; - } - - // mark the allocated entry - pEntry = (PENTRY)((char *)pEntry + sizeNewFree); - pEntry->sizeFront = sizeEntry + 1; - ((PENTRYEND)((char *)pEntry + sizeEntry - - sizeof(ENTRYEND)))->sizeBack = sizeEntry + 1; - - // one more allocation in group - test if group was empty - if (pGroup->cntEntries++ == 0) - { - // if allocating into deferred group, cancel deferral - if (pHeader == __sbh_pHeaderDefer && - indGroupUse == __sbh_indGroupDefer) - __sbh_pHeaderDefer = NULL; - } - - pRegion->indGroupUse = indGroupUse; - - return (void *)((char *)pEntry + sizeof(int)); -} - -/*** -*PHEADER __sbh_alloc_new_region() -* -*Purpose: -* Add a new HEADER structure in the header list. Allocate a new -* REGION structure and initialize. Reserve memory for future -* group commitments. -* -*Entry: -* None. -* -*Exit: -* Returns a pointer to newly created HEADER entry, if successful. -* Returns NULL, if failure. -* -*Exceptions: -* -*******************************************************************************/ - -PHEADER __cdecl __sbh_alloc_new_region (void) -{ - PHEADER pHeader; - - // create a new entry in the header list - - // if list if full, realloc to extend its size - if (__sbh_cntHeaderList == __sbh_sizeHeaderList) - { - if (!(pHeader = (PHEADER)HeapReAlloc(_crtheap, 0, __sbh_pHeaderList, - (__sbh_sizeHeaderList + 16) * sizeof(HEADER)))) - return NULL; - - // update pointer and counter values - __sbh_pHeaderList = pHeader; - __sbh_sizeHeaderList += 16; - } - - // point to new header in list - pHeader = __sbh_pHeaderList + __sbh_cntHeaderList; - - // allocate a new region associated with the new header - if (!(pHeader->pRegion = (PREGION)HeapAlloc(_crtheap, HEAP_ZERO_MEMORY, - sizeof(REGION)))) - return NULL; - - // reserve address space for heap data in the region - if ((pHeader->pHeapData = VirtualAlloc(0, BYTES_PER_REGION, - MEM_RESERVE, PAGE_READWRITE)) == NULL) - { - HeapFree(_crtheap, 0, pHeader->pRegion); - return NULL; - } - - // initialize alloc and commit group vectors - pHeader->bitvEntryHi = 0; - pHeader->bitvEntryLo = 0; - pHeader->bitvCommit = BITV_COMMIT_INIT; - - // complete entry by incrementing list count - __sbh_cntHeaderList++; - - // initialize index of group to try first (none defined yet) - pHeader->pRegion->indGroupUse = -1; - - return pHeader; -} - -/*** -*int __sbh_alloc_new_group(pHeader) -* -*Purpose: -* Initializes a GROUP structure within HEADER pointed by pHeader. -* Commits and initializes the memory in the memory reserved by the -* REGION. -* -*Entry: -* pHeader - pointer to HEADER from which the GROUP is defined. -* -*Exit: -* Returns an index to newly created GROUP, if successful. -* Returns -1, if failure. -* -*Exceptions: -* -*******************************************************************************/ - -int __cdecl __sbh_alloc_new_group (PHEADER pHeader) -{ - PREGION pRegion = pHeader->pRegion; - PGROUP pGroup; - PENTRY pEntry; - PENTRY pHead; - PENTRYEND pEntryEnd; - BITVEC bitvCommit; - int indCommit; - int index; - void * pHeapPage; - void * pHeapStartPage; - void * pHeapEndPage; - - // determine next group to use by first bit set in commit vector - bitvCommit = pHeader->bitvCommit; - indCommit = 0; - while ((int)bitvCommit >= 0) - { - bitvCommit <<= 1; - indCommit++; - } - - // allocate and initialize a new group - pGroup = &pRegion->grpHeadList[indCommit]; - - for (index = 0; index < 63; index++) - { - pEntry = (PENTRY)((char *)&pGroup->listHead[index] - sizeof(int)); - pEntry->pEntryNext = pEntry->pEntryPrev = pEntry; - } - - // commit heap memory for new group - pHeapStartPage = (void *)((char *)pHeader->pHeapData + - indCommit * BYTES_PER_GROUP); - if ((VirtualAlloc(pHeapStartPage, BYTES_PER_GROUP, MEM_COMMIT, - PAGE_READWRITE)) == NULL) - return -1; - - // initialize heap data with empty page entries - pHeapEndPage = (void *)((char *)pHeapStartPage + - (PAGES_PER_GROUP - 1) * BYTES_PER_PAGE); - - for (pHeapPage = pHeapStartPage; pHeapPage <= pHeapEndPage; - pHeapPage = (void *)((char *)pHeapPage + BYTES_PER_PAGE)) - { - // set sentinel values at start and end of the page - *(int *)((char *)pHeapPage + 8) = -1; - *(int *)((char *)pHeapPage + BYTES_PER_PAGE - 4) = -1; - - // set size and pointer info for one empty entry - pEntry = (PENTRY)((char *)pHeapPage + ENTRY_OFFSET); - pEntry->sizeFront = MAX_FREE_ENTRY_SIZE; - pEntry->pEntryNext = (PENTRY)((char *)pEntry + - BYTES_PER_PAGE); - pEntry->pEntryPrev = (PENTRY)((char *)pEntry - - BYTES_PER_PAGE); - pEntryEnd = (PENTRYEND)((char *)pEntry + MAX_FREE_ENTRY_SIZE - - sizeof(ENTRYEND)); - pEntryEnd->sizeBack = MAX_FREE_ENTRY_SIZE; - } - - // initialize group entry pointer for maximum size - // and set terminate list entries - pHead = (PENTRY)((char *)&pGroup->listHead[63] - sizeof(int)); - pEntry = pHead->pEntryNext = - (PENTRY)((char *)pHeapStartPage + ENTRY_OFFSET); - pEntry->pEntryPrev = pHead; - - pEntry = pHead->pEntryPrev = - (PENTRY)((char *)pHeapEndPage + ENTRY_OFFSET); - pEntry->pEntryNext = pHead; - - pRegion->bitvGroupHi[indCommit] = 0x00000000L; - pRegion->bitvGroupLo[indCommit] = 0x00000001L; - if (pRegion->cntRegionSize[63]++ == 0) - pHeader->bitvEntryLo |= 0x00000001L; - - // clear bit in commit vector - pHeader->bitvCommit &= ~(0x80000000L >> indCommit); - - return indCommit; -} - -/*** -*int __sbh_resize_block(pHeader, pvAlloc, intNew) - resize block -* -*Purpose: -* Resize the specified block from the small-block heap. -* The allocation block is not moved. -* -*Entry: -* pHeader - pointer to HEADER containing block -* pvAlloc - pointer to block to resize -* intNew - new size of block in bytes -* -*Exit: -* Returns 1, if successful. Otherwise, 0 is returned. -* -*Exceptions: -* -*******************************************************************************/ - -int __cdecl __sbh_resize_block (PHEADER pHeader, void * pvAlloc, int intNew) -{ - PREGION pRegion; - PGROUP pGroup; - PENTRY pHead; - PENTRY pEntry; - PENTRY pNext; - int sizeEntry; - int sizeNext; - int sizeNew; - unsigned int indGroup; - unsigned int indEntry; - unsigned int indNext; - unsigned int offRegion; - - // add 8 bytes entry overhead and round up to next para size - sizeNew = (intNew + 2 * (int)sizeof(int) + (BYTES_PER_PARA - 1)) - & ~(BYTES_PER_PARA - 1); - - // region is determined by the header - pRegion = pHeader->pRegion; - - // use the region offset to determine the group index - offRegion = (unsigned int)((uintptr_t)pvAlloc - (uintptr_t)pHeader->pHeapData); - indGroup = offRegion / BYTES_PER_GROUP; - pGroup = &pRegion->grpHeadList[indGroup]; - - // get size of entry - decrement value since entry is allocated - pEntry = (PENTRY)((char *)pvAlloc - sizeof(int)); - sizeEntry = pEntry->sizeFront - 1; - - // point to next entry to get its size - pNext = (PENTRY)((char *)pEntry + sizeEntry); - sizeNext = pNext->sizeFront; - - // test if new size is larger than the current one - if (sizeNew > sizeEntry) - { - // if next entry not free, or not large enough, fail - if ((sizeNext & 1) || (sizeNew > sizeEntry + sizeNext)) - return FALSE; - - // disconnect next entry - - // determine index of next entry - indNext = (sizeNext >> 4) - 1; - if (indNext > 63) - indNext = 63; - - // test entry is sole member of bucket (next == prev), - if (pNext->pEntryNext == pNext->pEntryPrev) - { - // clear bit in group vector, decrement region count - // if region count is now zero, clear bit in header - // entry vector - if (indNext < 32) - { - pRegion->bitvGroupHi[indGroup] &= ~(0x80000000L >> indNext); - if (--pRegion->cntRegionSize[indNext] == 0) - pHeader->bitvEntryHi &= ~(0x80000000L >> indNext); - } - else - { - pRegion->bitvGroupLo[indGroup] &= - ~(0x80000000L >> (indNext - 32)); - if (--pRegion->cntRegionSize[indNext] == 0) - pHeader->bitvEntryLo &= ~(0x80000000L >> (indNext - 32)); - } - } - - // unlink entry from list - pNext->pEntryPrev->pEntryNext = pNext->pEntryNext; - pNext->pEntryNext->pEntryPrev = pNext->pEntryPrev; - - // compute new size of the next entry, test if nonzero - if ((sizeNext = sizeEntry + sizeNext - sizeNew) > 0) - { - // compute start of next entry and connect it - pNext = (PENTRY)((char *)pEntry + sizeNew); - - // determine index of next entry - indNext = (sizeNext >> 4) - 1; - if (indNext > 63) - indNext = 63; - - // add next entry to the start of the bucket list - pHead = (PENTRY)((char *)&pGroup->listHead[indNext] - - sizeof(int)); - pNext->pEntryNext = pHead->pEntryNext; - pNext->pEntryPrev = pHead; - pHead->pEntryNext = pNext; - pNext->pEntryNext->pEntryPrev = pNext; - - // test entry is sole member of bucket (next == prev), - if (pNext->pEntryNext == pNext->pEntryPrev) - { - // if region count was zero, set bit in region vector - // set bit in header entry vector, increment region count - if (indNext < 32) - { - if (pRegion->cntRegionSize[indNext]++ == 0) - pHeader->bitvEntryHi |= 0x80000000L >> indNext; - pRegion->bitvGroupHi[indGroup] |= 0x80000000L >> indNext; - } - else - { - if (pRegion->cntRegionSize[indNext]++ == 0) - pHeader->bitvEntryLo |= 0x80000000L >> (indNext - 32); - pRegion->bitvGroupLo[indGroup] |= - 0x80000000L >> (indNext - 32); - } - } - - // adjust size fields of next entry - pNext->sizeFront = sizeNext; - ((PENTRYEND)((char *)pNext + sizeNext - - sizeof(ENTRYEND)))->sizeBack = sizeNext; - } - - // adjust pEntry to its new size (plus one since allocated) - pEntry->sizeFront = sizeNew + 1; - ((PENTRYEND)((char *)pEntry + sizeNew - - sizeof(ENTRYEND)))->sizeBack = sizeNew + 1; - } - - // not larger, test if smaller - else if (sizeNew < sizeEntry) - { - // adjust pEntry to new smaller size - pEntry->sizeFront = sizeNew + 1; - ((PENTRYEND)((char *)pEntry + sizeNew - - sizeof(ENTRYEND)))->sizeBack = sizeNew + 1; - - // set pEntry and sizeEntry to leftover space - pEntry = (PENTRY)((char *)pEntry + sizeNew); - sizeEntry -= sizeNew; - - // determine index of entry - indEntry = (sizeEntry >> 4) - 1; - if (indEntry > 63) - indEntry = 63; - - // test if next entry is free - if ((sizeNext & 1) == 0) - { - // if so, disconnect it - - // determine index of next entry - indNext = (sizeNext >> 4) - 1; - if (indNext > 63) - indNext = 63; - - // test entry is sole member of bucket (next == prev), - if (pNext->pEntryNext == pNext->pEntryPrev) - { - // clear bit in group vector, decrement region count - // if region count is now zero, clear bit in header - // entry vector - if (indNext < 32) - { - pRegion->bitvGroupHi[indGroup] &= - ~(0x80000000L >> indNext); - if (--pRegion->cntRegionSize[indNext] == 0) - pHeader->bitvEntryHi &= ~(0x80000000L >> indNext); - } - else - { - pRegion->bitvGroupLo[indGroup] &= - ~(0x80000000L >> (indNext - 32)); - if (--pRegion->cntRegionSize[indNext] == 0) - pHeader->bitvEntryLo &= - ~(0x80000000L >> (indNext - 32)); - } - } - - // unlink entry from list - pNext->pEntryPrev->pEntryNext = pNext->pEntryNext; - pNext->pEntryNext->pEntryPrev = pNext->pEntryPrev; - - // add next entry size to present - sizeEntry += sizeNext; - indEntry = (sizeEntry >> 4) - 1; - if (indEntry > 63) - indEntry = 63; - } - - // connect leftover space with any free next entry - - // add next entry to the start of the bucket list - pHead = (PENTRY)((char *)&pGroup->listHead[indEntry] - sizeof(int)); - pEntry->pEntryNext = pHead->pEntryNext; - pEntry->pEntryPrev = pHead; - pHead->pEntryNext = pEntry; - pEntry->pEntryNext->pEntryPrev = pEntry; - - // test entry is sole member of bucket (next == prev), - if (pEntry->pEntryNext == pEntry->pEntryPrev) - { - // if region count was zero, set bit in region vector - // set bit in header entry vector, increment region count - if (indEntry < 32) - { - if (pRegion->cntRegionSize[indEntry]++ == 0) - pHeader->bitvEntryHi |= 0x80000000L >> indEntry; - pRegion->bitvGroupHi[indGroup] |= 0x80000000L >> indEntry; - } - else - { - if (pRegion->cntRegionSize[indEntry]++ == 0) - pHeader->bitvEntryLo |= 0x80000000L >> (indEntry - 32); - pRegion->bitvGroupLo[indGroup] |= 0x80000000L >> - (indEntry - 32); - } - } - - // adjust size fields of entry - pEntry->sizeFront = sizeEntry; - ((PENTRYEND)((char *)pEntry + sizeEntry - - sizeof(ENTRYEND)))->sizeBack = sizeEntry; - } - - return TRUE; -} - -/*** -*int __sbh_heapmin() - minimize heap -* -*Purpose: -* Minimize the heap by freeing any deferred group. -* -*Entry: -* __sbh_pHeaderDefer - pointer to HEADER of deferred group -* __sbh_indGroupDefer - index of GROUP to defer -* -*Exit: -* None. -* -*Exceptions: -* -*******************************************************************************/ - -void __cdecl __sbh_heapmin (void) -{ - void * pHeapDecommit; - - // if a group has been deferred, free that group - if (__sbh_pHeaderDefer) - { - // if now zero, decommit the group data heap - pHeapDecommit = (void *)((char *)__sbh_pHeaderDefer->pHeapData + - __sbh_indGroupDefer * BYTES_PER_GROUP); - VirtualFree(pHeapDecommit, BYTES_PER_GROUP, MEM_DECOMMIT); - - // set bit in commit vector - __sbh_pHeaderDefer->bitvCommit |= 0x80000000 >> __sbh_indGroupDefer; - - // clear entry vector for the group and header vector bit - // if needed - __sbh_pHeaderDefer->pRegion->bitvGroupLo[__sbh_indGroupDefer] = 0; - if (--__sbh_pHeaderDefer->pRegion->cntRegionSize[63] == 0) - __sbh_pHeaderDefer->bitvEntryLo &= ~0x00000001L; - - // if commit vector is the initial value, - // remove the region if it is not the last - if (__sbh_pHeaderDefer->bitvCommit == BITV_COMMIT_INIT && - __sbh_cntHeaderList > 1) - { - // free the region memory area - HeapFree(_crtheap, 0, __sbh_pHeaderDefer->pRegion); - - // remove entry from header list by copying over - memmove((void *)__sbh_pHeaderDefer, (void *)(__sbh_pHeaderDefer + 1), - (int)((intptr_t)(__sbh_pHeaderList + __sbh_cntHeaderList) - - (intptr_t)(__sbh_pHeaderDefer + 1))); - __sbh_cntHeaderList--; - } - - // clear deferred condition - __sbh_pHeaderDefer = NULL; - } - -#ifdef _DEBUG - if (__sbh_heap_check() != 0) - _asm int 3; -#endif -} - -#ifdef _DEBUG - -/*** -*int __sbh_heap_check() - check small-block heap -* -*Purpose: -* Perform validity checks on the small-block heap. -* -*Entry: -* There are no arguments. -* -*Exit: -* Returns 0 if the small-block is okay. -* Returns < 0 if the small-block heap has an error. The exact value -* identifies where, in the source code below, the error was detected. -* -*Exceptions: -* -*******************************************************************************/ - -int __cdecl __sbh_heap_check (void) -{ - PHEADER pHeader; - PREGION pRegion; - PGROUP pGroup; - PENTRY pEntry; - PENTRY pNext; - PENTRY pEntryLast; - PENTRY pEntryHead; - PENTRY pEntryPage; - PENTRY pEntryPageLast; - int indHeader; - int indGroup; - int indPage; - int indEntry; - int indHead; - int sizeEntry; - int sizeTrue; - int cntAllocated; - int cntFree[64]; - int cntEntries; - void * pHeapGroup; - void * pHeapPage; - void * pPageStart; - BITVEC bitvCommit; - BITVEC bitvGroupHi; - BITVEC bitvGroupLo; - BITVEC bitvEntryHi; - BITVEC bitvEntryLo; - - // check validity of header list - if (IsBadWritePtr(__sbh_pHeaderList, - __sbh_cntHeaderList * sizeof(HEADER))) - return -1; - - // scan for all headers in list - pHeader = __sbh_pHeaderList; - for (indHeader = 0; indHeader < __sbh_cntHeaderList; indHeader++) - { - // define region and test if valid - pRegion = pHeader->pRegion; - if (IsBadWritePtr(pRegion, sizeof(REGION))) - return -2; - - // scan for all groups in region - pHeapGroup = pHeader->pHeapData; - pGroup = &pRegion->grpHeadList[0]; - bitvCommit = pHeader->bitvCommit; - bitvEntryHi = 0; - bitvEntryLo = 0; - for (indGroup = 0; indGroup < GROUPS_PER_REGION; indGroup++) - { - // initialize entry vector and entry counts for group - bitvGroupHi = 0; - bitvGroupLo = 0; - cntAllocated = 0; - for (indEntry = 0; indEntry < 64; indEntry++) - cntFree[indEntry] = 0; - - // test if group is committed - if ((int)bitvCommit >= 0) - { - // committed, ensure addresses are accessable - if (IsBadWritePtr(pHeapGroup, BYTES_PER_GROUP)) - return -4; - - // for each page in group, check validity of entries - pHeapPage = pHeapGroup; - for (indPage = 0; indPage < PAGES_PER_GROUP; indPage++) - { - // define pointers to first and past last entry - pEntry = (PENTRY)((char *)pHeapPage + ENTRY_OFFSET); - pEntryLast = (PENTRY)((char *)pEntry - + MAX_FREE_ENTRY_SIZE); - - // check front and back page sentinel values - if (*(int *)((char *)pEntry - sizeof(int)) != -1 || - *(int *)pEntryLast != -1) - return -5; - - // loop through each entry in page - do - { - // get entry size and test if allocated - sizeEntry = sizeTrue = pEntry->sizeFront; - if (sizeEntry & 1) - { - // allocated entry - set true size - sizeTrue--; - - // test against maximum allocated entry size - if (sizeTrue > MAX_ALLOC_ENTRY_SIZE) - return -6; - - // increment allocated count for group - cntAllocated++; - } - else - { - // free entry - determine index and increment - // count for list head checking - indEntry = (sizeTrue >> 4) - 1; - if (indEntry > 63) - indEntry = 63; - cntFree[indEntry]++; - } - - // check size validity - if (sizeTrue < 0x10 || sizeTrue & 0xf - || sizeTrue > MAX_FREE_ENTRY_SIZE) - return -7; - - // check if back entry size same as front - if (((PENTRYEND)((char *)pEntry + sizeTrue - - sizeof(int)))->sizeBack != sizeEntry) - return -8; - - // move to next entry in page - pEntry = (PENTRY)((char *)pEntry + sizeTrue); - } - while (pEntry < pEntryLast); - - // test if last entry did not overrun page end - if (pEntry != pEntryLast) - return -8; - - // point to next page in data heap - pHeapPage = (void *)((char *)pHeapPage + BYTES_PER_PAGE); - } - - // check if allocated entry count is correct - if (pGroup->cntEntries != cntAllocated) - return -9; - - // check validity of linked-lists of free entries - pEntryHead = (PENTRY)((char *)&pGroup->listHead[0] - - sizeof(int)); - for (indHead = 0; indHead < 64; indHead++) - { - // scan through list until head is reached or expected - // number of entries traversed - cntEntries = 0; - pEntry = pEntryHead; - while ((pNext = pEntry->pEntryNext) != pEntryHead && - cntEntries != cntFree[indHead]) - { - // test if next pointer is in group data area - if ((void *)pNext < pHeapGroup || (void *)pNext >= - (void *)((char *)pHeapGroup + BYTES_PER_GROUP)) - return -10; - - // determine page address of next entry - pPageStart = (void *)((uintptr_t)pNext & - ~(uintptr_t)(BYTES_PER_PAGE - 1)); - - // point to first entry and past last in the page - pEntryPage = (PENTRY)((char *)pPageStart + - ENTRY_OFFSET); - pEntryPageLast = (PENTRY)((char *)pEntryPage + - MAX_FREE_ENTRY_SIZE); - - // do scan from start of page - // no error checking since it was already scanned - while (pEntryPage != pEntryPageLast) - { - // if entry matches, exit loop - if (pEntryPage == pNext) - break; - - // point to next entry - pEntryPage = (PENTRY)((char *)pEntryPage + - (pEntryPage->sizeFront & ~1)); - } - - // if page end reached, pNext was not valid - if (pEntryPage == pEntryPageLast) - return -11; - - // entry valid, but check if entry index matches - // the header - indEntry = (pNext->sizeFront >> 4) - 1; - if (indEntry > 63) - indEntry = 63; - if (indEntry != indHead) - return -12; - - // check if previous pointer in pNext points - // back to pEntry - if (pNext->pEntryPrev != pEntry) - return -13; - - // update scan pointer and counter - pEntry = pNext; - cntEntries++; - } - - // if nonzero number of entries, set bit in group - // and region vectors - if (cntEntries) - { - if (indHead < 32) - { - bitvGroupHi |= 0x80000000L >> indHead; - bitvEntryHi |= 0x80000000L >> indHead; - } - else - { - bitvGroupLo |= 0x80000000L >> (indHead - 32); - bitvEntryLo |= 0x80000000L >> (indHead - 32); - } - } - - // check if list is exactly the expected size - if (pEntry->pEntryNext != pEntryHead || - cntEntries != cntFree[indHead]) - return -14; - - // check if previous pointer in header points to - // last entry processed - if (pEntryHead->pEntryPrev != pEntry) - return -15; - - // point to next linked-list header - note size - pEntryHead = (PENTRY)((char *)pEntryHead + - sizeof(LISTHEAD)); - } - } - - // test if group vector is valid - if (bitvGroupHi != pRegion->bitvGroupHi[indGroup] || - bitvGroupLo != pRegion->bitvGroupLo[indGroup]) - return -16; - - // adjust for next group in region - pHeapGroup = (void *)((char *)pHeapGroup + BYTES_PER_GROUP); - pGroup++; - bitvCommit <<= 1; - } - - // test if group vector is valid - if (bitvEntryHi != pHeader->bitvEntryHi || - bitvEntryLo != pHeader->bitvEntryLo) - return -17; - - // adjust for next header in list - pHeader++; - } - return 0; -} - -#endif \ No newline at end of file diff --git a/Core/DolphinVM/SaveImage.cpp b/Core/DolphinVM/SaveImage.cpp index 237591da56..4226d1c23c 100644 --- a/Core/DolphinVM/SaveImage.cpp +++ b/Core/DolphinVM/SaveImage.cpp @@ -15,7 +15,6 @@ #include "binstream.h" #include "zfbinstream.h" #include "objmem.h" -#include "ObjMemPriv.inl" #include "interprt.h" #include "rc_vm.h" diff --git a/Core/DolphinVM/ToGoStub/GuiToGo.vcxproj b/Core/DolphinVM/ToGoStub/GuiToGo.vcxproj index e7ef982dfa..d737593ae5 100644 --- a/Core/DolphinVM/ToGoStub/GuiToGo.vcxproj +++ b/Core/DolphinVM/ToGoStub/GuiToGo.vcxproj @@ -98,7 +98,7 @@ TO_GO;_CTYPE_DISABLE_MACROS;WIN32;_WINDOWS;WIN32_LEAN_AND_MEAN;WIN32_EXTRA_LEAN;STRICT;ZEXPORT=__stdcall;ZEXPORTVA=__cdecl;_HAS_EXCEPTIONS=0;NDEBUG;%(PreprocessorDefinitions) false - MultiThreaded + MultiThreadedDLL Use ist.h @@ -115,6 +115,7 @@ false UseLinkTimeCodeGeneration + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) @@ -139,7 +140,7 @@ true - MultiThreadedDebug + MultiThreadedDebugDLL true true true @@ -176,6 +177,7 @@ true true + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) @@ -201,7 +203,7 @@ true - MultiThreadedDebug + MultiThreadedDebugDLL true true true @@ -238,6 +240,7 @@ true true + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) diff --git a/Core/DolphinVM/ToGoStub/togo.def b/Core/DolphinVM/ToGoStub/togo.def index c85cbbefea..fae6af8d6c 100644 --- a/Core/DolphinVM/ToGoStub/togo.def +++ b/Core/DolphinVM/ToGoStub/togo.def @@ -31,63 +31,6 @@ AxWinTerm compress2 uncompress -; CRT functions imported by the image - - _chsize_s - _clearfp - _close - _control87 - _dup - _dup2 - _errno - _fdopen - _filelengthi64 - _fileno - _fseeki64 - _ftelli64 - _get_invalid_parameter_handler - _get_osfhandle - _isatty - _makepath_s - _open_osfhandle - _setmode - _splitpath_s - _statusfp - _wcserror_s - _wcsicmp - _wfsopen - atoi - fclose - feof - fflush - fgetc - fgets - fgetwc - fgetws - fputc - fputs - fputwc - fputws - fread_s - free - fwrite - memcmp - memcpy_s - rand - setlocale - srand - strcat_s - strcmp - strcspn - strlen - strncmp - strncpy_s - ungetc - ungetwc - wcslen - wcscspn - wcsncpy_s - ; VMLibrary _snprintf_s diff --git a/Core/DolphinVM/Utf16String.cpp b/Core/DolphinVM/Utf16String.cpp index 2917a4eaa7..56b25db326 100644 --- a/Core/DolphinVM/Utf16String.cpp +++ b/Core/DolphinVM/Utf16String.cpp @@ -14,8 +14,8 @@ void Utf16StringBuf::FromUtf8(const char8_t* psz8, size_t cch8) m_cwch = LengthOfUtf8(psz8, cch8); if (m_cwch >= _countof(m_wcsBuf)) { - m_pBuf = reinterpret_cast(malloc((m_cwch + 1) * sizeof(char16_t))); - // If malloc returns nullptr, then will fail below with benign AV + m_pBuf = new char16_t[m_cwch + 1]; + // If alloc returns nullptr, then will fail below with benign AV } char16_t* pEnd = ConvertUtf8_unsafe(psz8, cch8, m_pBuf); @@ -197,8 +197,8 @@ void Utf16StringBuf::FromAnsi(const char* psz, size_t cch) m_cwch = LengthOfAnsi(psz, cch); if (m_cwch >= _countof(m_wcsBuf)) { - m_pBuf = reinterpret_cast(malloc((m_cwch + 1) * sizeof(char16_t))); - // If malloc returns nullptr, then will fail below with benign AV + m_pBuf = new char16_t[m_cwch + 1]; + // If alloc returns nullptr, then will fail below with benign AV } char16_t* pEnd = ConvertAnsi_unsafe(psz, cch, m_pBuf); @@ -210,8 +210,8 @@ void Utf16StringBuf::FromAnsi(const char* psz, size_t cch, UINT codePage) { if (cch >= _countof(m_wcsBuf)) { - m_pBuf = reinterpret_cast(malloc((cch + 1) * sizeof(char16_t))); - // If malloc returns nullptr, then will fail below with benign AV + m_pBuf = new char16_t[cch + 1]; + // If alloc returns nullptr, then will fail below with benign AV } m_cwch = static_cast(::MultiByteToWideChar(codePage, 0, psz, cch, (LPWSTR)m_pBuf, cch)); diff --git a/Core/DolphinVM/Utf16StringBuf.h b/Core/DolphinVM/Utf16StringBuf.h index ad06e1c038..36384a6585 100644 --- a/Core/DolphinVM/Utf16StringBuf.h +++ b/Core/DolphinVM/Utf16StringBuf.h @@ -37,7 +37,8 @@ class Utf16StringBuf ~Utf16StringBuf() { - if (m_pBuf != m_wcsBuf) free(m_pBuf); + if (m_pBuf != m_wcsBuf) + delete m_pBuf; } public: diff --git a/Core/DolphinVM/Utf8String.cpp b/Core/DolphinVM/Utf8String.cpp index 758669e0d1..749b55c882 100644 --- a/Core/DolphinVM/Utf8String.cpp +++ b/Core/DolphinVM/Utf8String.cpp @@ -13,8 +13,8 @@ Utf8StringBuf::Utf8StringBuf(const char* __restrict psz, size_t cch) m_cch8 = LengthOfAnsi(psz, cch); if (m_cch8 >= _countof(m_ch8Buf)) { - m_pBuf = reinterpret_cast(malloc((m_cch8 + 1) * sizeof(char8_t))); - // If malloc returns nullptr, then will fail below with benign AV + m_pBuf = new char8_t[m_cch8 + 1]; + // If alloc returns nullptr, then will fail below with benign AV } *(ConvertAnsi_unsafe(psz, cch, m_pBuf, m_cch8)) = '\0'; @@ -104,8 +104,8 @@ Utf8StringBuf::Utf8StringBuf(const char16_t* __restrict pwch, size_t cwch) m_cch8 = LengthOfUtf16(pwch, cwch); if (m_cch8 >= _countof(m_ch8Buf)) { - m_pBuf = reinterpret_cast(malloc((m_cch8 + 1) * sizeof(char8_t))); - // If malloc returns nullptr, then will fail below with benign AV + m_pBuf = new char8_t[m_cch8 + 1]; + // If alloc returns nullptr, then will fail below with benign AV } *(ConvertUtf16_unsafe(pwch, cwch, m_pBuf, m_cch8)) = '\0'; diff --git a/Core/DolphinVM/Utf8StringBuf.h b/Core/DolphinVM/Utf8StringBuf.h index 71878a903d..80c12505ba 100644 --- a/Core/DolphinVM/Utf8StringBuf.h +++ b/Core/DolphinVM/Utf8StringBuf.h @@ -15,7 +15,8 @@ class Utf8StringBuf ~Utf8StringBuf() { - if (m_pBuf != m_ch8Buf) free(m_pBuf); + if (m_pBuf != m_ch8Buf) + delete m_pBuf; } operator const char8_t*() const { return m_pBuf; } diff --git a/Core/DolphinVM/VMLib/VMLib.vcxitems b/Core/DolphinVM/VMLib/VMLib.vcxitems index be5157d680..05fe645a60 100644 --- a/Core/DolphinVM/VMLib/VMLib.vcxitems +++ b/Core/DolphinVM/VMLib/VMLib.vcxitems @@ -60,9 +60,6 @@ $(SolutionDir)zlib;%(AdditionalIncludeDirectories) - - NotUsing - @@ -81,6 +78,17 @@ + + Cdecl + Cdecl + Cdecl + NotUsing + NotUsing + NotUsing + $(SolutionDir)mimalloc\include;$(SolutionDir);%(AdditionalIncludeDirectories) + $(SolutionDir)mimalloc\include;$(SolutionDir);%(AdditionalIncludeDirectories) + $(SolutionDir)mimalloc\include;$(SolutionDir);%(AdditionalIncludeDirectories) + @@ -108,7 +116,6 @@ - @@ -154,9 +161,6 @@ Document - - Document - diff --git a/Core/DolphinVM/VMLib/VMLib.vcxitems.filters b/Core/DolphinVM/VMLib/VMLib.vcxitems.filters index f1f19ea6af..29b08aefd7 100644 --- a/Core/DolphinVM/VMLib/VMLib.vcxitems.filters +++ b/Core/DolphinVM/VMLib/VMLib.vcxitems.filters @@ -85,9 +85,6 @@ ObjectMemory - - ObjectMemory - Interpreter @@ -164,6 +161,9 @@ Primitives + + ObjectMemory + @@ -258,9 +258,6 @@ Smalltalk Objects - - ObjectMemory - Interpreter @@ -348,9 +345,6 @@ Interpreter - - ObjectMemory - diff --git a/Core/DolphinVM/VMLib/heap.cpp b/Core/DolphinVM/VMLib/heap.cpp new file mode 100644 index 0000000000..24198e43c0 --- /dev/null +++ b/Core/DolphinVM/VMLib/heap.cpp @@ -0,0 +1,212 @@ +/////////////////////////////////////////////////////////////////////////////// +// Low-level memory chunk (not object) management routines +// +// These map directly onto a heap + +#include "Ist.h" +#include "objmem.h" + +#ifdef WIN32_HEAP +#define _CRTBLD +#include "winheap.h" +#undef _CRTBLD + +HANDLE ObjectMemory::m_hHeap; +extern "C" { HANDLE _crtheap; } +#else + +// Use mimalloc + +#include "mimalloc.h" +#include "mimalloc-new-delete.h" +#pragma comment(lib, "mimalloc-static.lib") + +static mi_heap_t* objectHeap; + +#endif + +#ifdef MEMSTATS +extern size_t m_nAllocated; +extern size_t m_nFreed; +#endif + +/////////////////////////////////////////////////////////////////////////////// + +void* ObjMemCall ObjectMemory::allocChunk(size_t chunkSize) +{ +#ifdef WIN32_HEAP + void* pChunk = ::HeapAlloc(m_hHeap, 0, chunkSize); +#else + void* pChunk = mi_heap_malloc(objectHeap, chunkSize); +#endif + +#ifdef _DEBUG + memset(pChunk, 0xCD, chunkSize); +#endif + + return pChunk; +} + +void ObjMemCall ObjectMemory::freeChunk(void* pChunk) +{ +#ifdef MEMSTATS + ++m_nFreed; +#endif + +#ifdef WIN32_HEAP + ::HeapFree(m_hHeap, 0, pChunk); +#else + mi_free(pChunk); +#endif +} + +void* ObjMemCall ObjectMemory::reallocChunk(void* pChunk, size_t newChunkSize) +{ +#ifdef WIN32_HEAP + return ::HeapReAlloc(m_hHeap, 0, pChunk, newChunkSize); +#else + return mi_heap_reallocf(objectHeap, pChunk, newChunkSize); +#endif +} + +// Compact any object memory heaps to minimize working set +void ObjectMemory::HeapCompact() +{ + // Minimize space occuppied by the heap +#ifdef WIN32_HEAP + ::HeapCompact(m_hHeap, 0); +#else + mi_heap_collect(objectHeap, true); +#endif + + _heapmin(); +} + + +static void heapError(int err, void* arg) +{ + ULONG_PTR args[1]; + args[0] = errno; + + switch (err) + { + case EFAULT: // Corrupted free list or meta - data was detected(only in debug and secure mode). + case EAGAIN: // Double free was detected(only in debug and secure mode). + ::RaiseException(static_cast(VMExceptions::CrtFault), EXCEPTION_NONCONTINUABLE, 1, (CONST ULONG_PTR*)args); + break; + case EOVERFLOW: // Too large a request, for example in mi_calloc(), the count and size parameters are too large. + case EINVAL: // Trying to free or re - allocate an invalid pointer. + ::RaiseException(static_cast(VMExceptions::CrtFault), 0, 1, (CONST ULONG_PTR*)args); + + case ENOMEM: // Not enough memory available to satisfy the request. + ::RaiseException(STATUS_NO_MEMORY, 0, 0, nullptr); + break; + } +} + + +void ObjectMemory::InitializeHeap() +{ +#ifdef WIN32_HEAP + if (!m_hHeap) + { + // Reinitialize the heaps each time through as gets deleted on terminate + m_hHeap = ::HeapCreate(HEAP_NO_SERIALIZE | HEAP_GENERATE_EXCEPTIONS, HEAPINITPAGES * dwPageSize, 0); + if (!m_hHeap) + ::RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, NULL); + _crtheap = m_hHeap; + } +#else + if (!objectHeap) + { + mi_register_error(heapError, nullptr); + objectHeap = mi_heap_new(); + if (!objectHeap) + ::RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, NULL); + + #ifdef DEBUG + { + mi_option_enable(mi_option_show_errors); + mi_option_enable(mi_option_show_stats); + mi_option_enable(mi_option_verbose); + } + #endif + } +#endif +} + +void ObjectMemory::UninitializeHeap() +{ +#ifdef WIN32_HEAP + // Leave heap around for use next time? + // ::HeapDestroy(m_hHeap); + // m_hHeap = 0; + // _crtheap = 0; +#else + mi_register_error(nullptr, nullptr); + mi_heap_destroy(objectHeap); + objectHeap = nullptr; +#endif +} + +#ifdef _DEBUG + +size_t ObjectMemory::chunkSize(void* pChunk) +{ +#ifdef WIN32_HEAP + return ::HeapSize(m_hHeap, 0, pChunk); +#else + return mi_usable_size(pChunk); +#endif +} + +void ObjectMemory::checkPools() +{ +#ifndef WIN32_HEAP + const size_t loopEnd = m_nOTSize; + for (size_t i = OTBase; i < loopEnd; i++) + { + OTE& ote = m_pOT[i]; + if (!ote.isFree()) + { + Spaces space = ote.heapSpace(); + if (space == Spaces::Normal) + { + HARDASSERT(mi_heap_check_owned(objectHeap, ote.m_location)); + } + } + } +#endif +} + +#endif + +#ifdef MEMSTATS +extern "C" void __cdecl dumpOutput(const char* msg, void* arg) +{ + TRACESTREAM << msg; +} + +void ObjectMemory::OTEPool::DumpStats() +{ + tracelock lock(TRACESTREAM); + TRACESTREAM << L"OTEPool(" << this << L"): total " << std::dec << m_nAllocated << ", free " << m_nFree << std::endl; +} + +void ObjectMemory::DumpStats(const wchar_t* stage) +{ + tracelock lock(TRACESTREAM); + + TRACESTREAM << std::endl << L"Object Memory Statistics " << stage << L":" << std::endl + << L"------------------------------" << std::endl; + +#ifdef WIN32_HEAP + static _CrtMemState CRTMemState; + _CrtMemCheckpoint(&CRTMemState); + _CrtMemDumpStatistics(&CRTMemState); +#else + mi_stats_print_out(dumpOutput, nullptr); +#endif +} + +#endif diff --git a/Core/DolphinVM/alloc.cpp b/Core/DolphinVM/alloc.cpp index adb0bfd9a4..554b5cb49b 100755 --- a/Core/DolphinVM/alloc.cpp +++ b/Core/DolphinVM/alloc.cpp @@ -13,7 +13,6 @@ #pragma code_seg(MEM_SEG) #include "ObjMem.h" -#include "ObjMemPriv.inl" #include "Interprt.h" #include "VirtualMemoryStats.h" @@ -23,33 +22,48 @@ #include "rc_vm.h" #endif -#ifdef MEMSTATS - extern size_t m_nLargeAllocated; - extern size_t m_nSmallAllocated; -#endif - // Smalltalk classes #include "STVirtualObject.h" #include "STByteArray.h" -// No auto-inlining in this module please -#pragma auto_inline(off) +/////////////////////////////////////////////////////////////////////////////// +// Oop allocation + +inline OTE* __fastcall ObjectMemory::allocateOop(POBJECT pLocation) +{ + __assume(m_pFreePointerList != nullptr); + + // N.B. By not ref. counting class here, we make a useful saving of a redundant + // ref. counting operation in primitiveNew and primitiveNewWithArg + + OTE* ote = m_pFreePointerList; + + m_pFreePointerList = NextFree(ote); + + ASSERT(ote->isFree()); +#ifdef TRACKFREEOTEs + --m_nFreeOTEs; + assert(m_nFreeOTEs >= 0); + //assert(m_nFreeOTEs == CountFreeOTEs()); +#endif + + // Set OTE fields of the Oop + ote->m_location = pLocation; + + // Maintain the last used garbage collector mark to speed up collections + // Doing this will also reset the free bit and set the pointer bit + // so byte allocations will need to reset it + ote->m_flagsWord = *reinterpret_cast(&m_spaceOTEBits[static_cast(Spaces::Normal)]); + + return ote; +} -ObjectMemory::FixedSizePool ObjectMemory::m_pools[NumPools]; -ObjectMemory::FixedSizePool::Link* ObjectMemory::FixedSizePool::m_pFreePages; -void** ObjectMemory::FixedSizePool::m_pAllocations; -size_t ObjectMemory::FixedSizePool::m_nAllocations; /////////////////////////////////////////////////////////////////////////////// // Public object allocation routines -// Rarely used, so don't inline it -POBJECT ObjectMemory::allocLargeObject(size_t objectSize, OTE*& ote) +POBJECT ObjectMemory::allocObject(size_t objectSize, OTE*& ote) { -#ifdef MEMSTATS - ++m_nLargeAllocated; -#endif - POBJECT pObj = static_cast(allocChunk(_ROUND2(objectSize, sizeof(Oop)))); // allocateOop expects crit section to be used @@ -59,30 +73,6 @@ POBJECT ObjectMemory::allocLargeObject(size_t objectSize, OTE*& ote) return pObj; } -inline POBJECT ObjectMemory::allocObject(size_t objectSize, OTE*& ote) -{ - // Callers are expected to round requests to Oop granularity - if (objectSize <= MaxSmallObjectSize) - { - // Smallblock heap already has space for object size at start of obj which includes - // heap overhead,etc, and is rounded to a paragraph size - // Why not alloc. four bytes less, overwrite this size with our object size, and then - // move back the object body pointer by four. On delete need to reapply the object - // size back into the object? - No wouldn't work because of the way heap accesses - // adjoining objects when freeing! - - POBJECT pObj = static_cast(allocSmallChunk(objectSize)); - ote = allocateOop(pObj); - ote->setSize(objectSize); - ASSERT(ote->heapSpace() == Spaces::Pools); - return pObj; - } - else - { - return allocLargeObject(objectSize, ote); - } -} - /////////////////////////////////////////////////////////////////////////////// // Object copying (mostly allocation) @@ -387,8 +377,7 @@ PointersOTE* __fastcall ObjectMemory::newUninitializedPointerObject(BehaviorOTE* size_t objectSize = SizeOfPointers(oops); OTE* ote; allocObject(objectSize, ote); - ASSERT((objectSize > MaxSizeOfPoolObject && ote->heapSpace() == Spaces::Normal) - || ote->heapSpace() == Spaces::Pools); + ASSERT(ote->heapSpace() == Spaces::Normal); // These are stored in the object itself ASSERT(ote->getSize() == objectSize); @@ -412,9 +401,7 @@ template BytesOTE* ObjectMemory::newByteObject(B ASSERT(!classPointer->m_location->m_instanceSpec.m_nullTerminated); VariantByteObject* newBytes = static_cast(allocObject(elementCount + SizeOfPointers(0), ote)); - ASSERT((elementCount > MaxSizeOfPoolObject && ote->heapSpace() == Spaces::Normal) - || ote->heapSpace() == Spaces::Pools); - + ASSERT(ote->heapSpace() == Spaces::Normal); ASSERT(ote->getSize() == elementCount + SizeOfPointers(0)); if (Initialized) @@ -455,8 +442,7 @@ template BytesOTE* ObjectMemory::newByteObject(B objectSize += NULLTERMSIZE; VariantByteObject* newBytes = static_cast(allocObject(objectSize + SizeOfPointers(0), ote)); - ASSERT((objectSize > MaxSizeOfPoolObject && ote->heapSpace() == Spaces::Normal) - || ote->heapSpace() == Spaces::Pools); + ASSERT(ote->heapSpace() == Spaces::Normal); ASSERT(ote->getSize() == objectSize + SizeOfPointers(0)); @@ -636,8 +622,7 @@ BytesOTE* __fastcall ObjectMemory::shallowCopy(BytesOTE* ote) OTE* copyPointer; // Allocate an uninitialized object ... VariantByteObject* pLocation = static_cast(allocObject(objectSize, copyPointer)); - ASSERT((objectSize > MaxSizeOfPoolObject && copyPointer->heapSpace() == Spaces::Normal) - || copyPointer->heapSpace() == Spaces::Pools); + ASSERT(copyPointer->heapSpace() == Spaces::Normal); ASSERT(copyPointer->getSize() == objectSize); // This set does not want to copy over the immutability bit - i.e. even if the original was immutable, the @@ -817,343 +802,3 @@ VirtualOTE* ObjectMemory::newVirtualObject(BehaviorOTE* classPointer, size_t ini return nullptr; } -/////////////////////////////////////////////////////////////////////////////// -// Low-level memory chunk (not object) management routines -// -void ObjectMemory::FixedSizePool::morePages() -{ - const size_t nPages = dwAllocationGranularity / dwPageSize; - UNREFERENCED_PARAMETER(nPages); - ASSERT(dwPageSize*nPages == dwAllocationGranularity); - - uint8_t* pStart = static_cast(::VirtualAlloc(NULL, dwAllocationGranularity, MEM_COMMIT, PAGE_READWRITE)); - if (pStart) - { -#ifdef _DEBUG - { - tracelock lock(TRACESTREAM); - TRACESTREAM << L"FixedSizePool: new pages @ " << LPVOID(pStart) << std::endl; - } -#endif - - // Put the allocation (64k) into the allocation list so we can free it later - { - m_nAllocations++; - m_pAllocations = static_cast(realloc(m_pAllocations, m_nAllocations * sizeof(void*))); - m_pAllocations[m_nAllocations - 1] = pStart; - } - - // We don't know whether the chunks are to contain zeros or nils, so we don't bother to init the space -#ifdef _DEBUG - memset(pStart, 0xCD, dwAllocationGranularity); -#endif - - uint8_t* pLast = pStart + dwAllocationGranularity - dwPageSize; - -#ifdef _DEBUG - // ASSERT that pLast is correct by causing a GPF if it isn't! - memset(reinterpret_cast(pLast), 0xCD, dwPageSize); -#endif - - for (uint8_t* p = pStart; p < pLast; p += dwPageSize) - reinterpret_cast(p)->next = reinterpret_cast(p + dwPageSize); - - reinterpret_cast(pLast)->next = 0; - m_pFreePages = reinterpret_cast(pStart); - -#ifdef _DEBUG - // m_nPages++; -#endif - } - else - { - ::RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, NULL); // Fatal - we must exit Dolphin - } -} - -inline uint8_t* ObjectMemory::FixedSizePool::allocatePage() -{ - if (!m_pFreePages) - { - morePages(); - ASSERT(m_pFreePages); - } - - Link* pPage = m_pFreePages; - m_pFreePages = pPage->next; - - return reinterpret_cast(pPage); -} - -// Allocate another page for a fixed size pool -void ObjectMemory::FixedSizePool::moreChunks() -{ - constexpr size_t nOverhead = 0;//12; - constexpr size_t nBlockSize = dwPageSize - nOverhead; - const size_t nChunks = nBlockSize / m_nChunkSize; - - uint8_t* pStart = allocatePage(); - - #ifdef _DEBUG - if (abs(Interpreter::executionTrace) > 0) - { - tracelock lock(TRACESTREAM); - TRACESTREAM<< L"FixedSizePool(" << this - << L" new page @ " << pStart - << L" (" << m_nPages<< L" pages of " - << nChunks <<" chunks of " - << m_nChunkSize <<" bytes, total waste " - << m_nPages*(nBlockSize-(nChunks*m_nChunkSize)) << L')' << std::endl; - } - memset(pStart, 0xCD, nBlockSize); - #else - // We don't know whether the chunks are to contain zeros or nils, so we don't bother to init the space - #endif - - uint8_t* pLast = &pStart[(nChunks-1) * m_nChunkSize]; - - #ifdef _DEBUG - // ASSERT that pLast is correct by causing a GPF if it isn't! - memset(static_cast(pLast), 0xCD, m_nChunkSize); - #endif - - const size_t chunkSize = m_nChunkSize; // Loop invariant - for (uint8_t* p = pStart; p < pLast; p += chunkSize) - reinterpret_cast(p)->next = reinterpret_cast(p + chunkSize); - - reinterpret_cast(pLast)->next = 0; - m_pFreeChunks = reinterpret_cast(pStart); - - #ifdef _DEBUG - m_nPages++; - m_pages = static_cast(realloc(m_pages, m_nPages*sizeof(void*))); - m_pages[m_nPages-1] = pStart; - #endif -} - -void ObjectMemory::FixedSizePool::setSize(size_t nChunkSize) -{ - m_nChunkSize = nChunkSize; - ASSERT(m_nChunkSize >= MinObjectSize); - // Must be on 4 byte boundaries - ASSERT(m_nChunkSize % MinObjectSize == 0); - // m_dwPageUsed = (dwPageSize / m_nChunkSize) * m_nChunkSize; -} - -inline ObjectMemory::FixedSizePool::FixedSizePool(size_t nChunkSize) : m_pFreeChunks(0) -#ifdef _DEBUG - , m_pages(0), m_nPages(0) -#endif -{ - setSize(nChunkSize); -} - -//#ifdef NDEBUG -// #pragma auto_inline(on) -//#endif - -inline POBJECT ObjectMemory::reallocChunk(POBJECT pChunk, size_t newChunkSize) -{ - #ifdef PRIVATE_HEAP - return static_cast(::HeapReAlloc(m_hHeap, 0, pChunk, newChunkSize)); - #else - void *oldPointer = pChunk; - void *newPointer = realloc(pChunk, newChunkSize); - _ASSERT(newPointer); - if (NULL == newPointer) - free(oldPointer); - return newPointer; - #endif -} - - -#ifdef MEMSTATS - void ObjectMemory::OTEPool::DumpStats() - { - tracelock lock(TRACESTREAM); - TRACESTREAM<< L"OTEPool(" << this<< L"): total " << std::dec << m_nAllocated <<", free " << m_nFree << std::endl; - } - - static _CrtMemState CRTMemState; - void ObjectMemory::DumpStats() - { - tracelock lock(TRACESTREAM); - - TRACESTREAM << std::endl<< L"Object Memory Statistics:" << std::endl - << L"------------------------------" << std::endl; - - CheckPoint(); - _CrtMemDumpStatistics(&CRTMemState); - -#ifdef _DEBUG - checkPools(); -#endif - - TRACESTREAM << std::endl << L"OTE Pools:" << std::endl - << L"------------------" << std::endl; - - // We need to empty the OTEPool free lists as these hold pre-allocated objects for certain special types - // These are marked as free in the OT to reserve them - Interpreter::FlushPools(); - - TRACESTREAM << std::endl << L"Pool Statistics:" << std::endl - << L"------------------" << std::endl << std::dec - << NumPools<< L" pools in the interval " - << m_pools[0].getSize()<< L" to: " - << m_pools[NumPools-1].getSize() - << std::endl << std::endl; - - size_t pageWaste=0; - size_t totalPages=0; - size_t totalFreeBytes=0; - size_t totalChunks=0; - size_t totalFreeChunks=0; - for (auto i=0;iisFree()) - { - totalObjects++; - switch (ote->heapSpace()) - { - case Spaces::Normal: - { - size_t size = ote->sizeOf(); - if (size <= MaxSmallObjectSize) - { - TRACESTREAM << L"Normal object of size " << size << " below threshold: " << ote << std::endl; - } - break; - } - case Spaces::Virtual: - break; - case Spaces::Heap: - break; - - case Spaces::Blocks: - case Spaces::Contexts: - case Spaces::Dwords: - case Spaces::Floats: - case Spaces::Pools: - { - size_t size = ote->sizeOf(); - if (size != 0 && size <= PoolObjectSizeLimit) - { - totalPoolObjects++; - size_t chunkSize = spacePoolForSize(size).getSize(); - objectWaste += chunkSize - size; - } - else - { - ASSERT(size <= MaxSmallObjectSize); - totalSmallHeapObjects++; - totalSmallHeapObjectsSize += size; - } - break; - } - } - } - } - - ASSERT((totalChunks - totalFreeChunks) == totalPoolObjects); - size_t wastePercentage = (totalChunks - totalFreeChunks) == 0 - ? 0 - : size_t(double(objectWaste)/ - double(totalPoolObjects)*100.0); - - TRACESTREAM<< L"===============================================" << std::endl; - TRACE(L"Total objects = %d\n" - "Total pool objs = %d\n" - "Total small objs = %d (%d bytes)\n" - "Total chunks = %d\n" - "Total Pages = %d\n" - "Total Allocs = %d\n" - "Total allocated = %d\n" - "Page Waste = %d bytes\n" - "Object Waste = %d bytes (avg 0.%d)\n" - "Total Waste = %d\n" - "Total free chks = %d\n" - "Total Free = %d bytes\n", - totalObjects, - totalPoolObjects, - totalSmallHeapObjects, totalSmallHeapObjectsSize, - totalChunks, - totalPages, - FixedSizePool::m_nAllocations, - totalPages*dwPageSize, - pageWaste, - objectWaste, wastePercentage, - pageWaste+objectWaste, - totalFreeChunks, - totalFreeBytes); - } - - void ObjectMemory::CheckPoint() - { - _CrtMemCheckpoint(&CRTMemState); - } - - size_t ObjectMemory::FixedSizePool::getFree() - { - Link* pChunk = m_pFreeChunks; - size_t tally = 0; - while (pChunk) - { - tally++; - pChunk = pChunk->next; - } - return tally; - } -#endif - -#if defined(_DEBUG) - - bool ObjectMemory::FixedSizePool::isMyChunk(void* pChunk) - { - const size_t loopEnd = m_nPages; - for (size_t i=0;i= pPage && static_cast(pChunk) <= (static_cast(pPage)+dwPageSize)) - return true; - } - return false; - } - - bool ObjectMemory::FixedSizePool::isValid() - { - Link* pChunk = m_pFreeChunks; - while (pChunk) - { - if (!isMyChunk(pChunk)) - return false; - pChunk = pChunk->next; - } - return true; - } - -#endif - diff --git a/Core/DolphinVM/dealloc.cpp b/Core/DolphinVM/dealloc.cpp index f9096e4f8a..dc33956581 100644 --- a/Core/DolphinVM/dealloc.cpp +++ b/Core/DolphinVM/dealloc.cpp @@ -12,15 +12,10 @@ #include "Ist.h" #include "ObjMem.h" #include "Interprt.h" -#include "ObjMemPriv.inl" // Smalltalk classes #include "STVirtualObject.h" -#ifdef MEMSTATS - extern size_t m_nLargeFreed; -#endif - #pragma code_seg(MEM_SEG) /////////////////////////////////////////////////////////////////////////////// @@ -43,24 +38,6 @@ inline void ObjectMemory::releasePointer(OTE* ote) //HARDASSERT(m_nFreeOTEs == CountFreeOTEs()); } -/////////////////////////////////////////////////////////////////////////////// -// Low-level memory chunk (not object) management routines -// -// These map directly onto C or Win32 heap - -void ObjectMemory::freeChunk(POBJECT pObj) -{ -#ifdef MEMSTATS - ++m_nLargeFreed; -#endif - - #ifdef PRIVATE_HEAP - ::HeapFree(m_hHeap, 0, pObj); - #else - free(pObj); - #endif -} - /////////////////////////////////////////////////////////////////////////////// // Prevent inline expansion of this routine in private count down and elsewhere //#pragma auto_inline(off) @@ -113,15 +90,6 @@ void ObjectMemory::deallocate(OTE* ote) Interpreter::m_otePools[static_cast(Interpreter::Pools::Floats)].deallocate(ote); break; - case Spaces::Pools: - { - size_t size = ote->sizeOf(); - HARDASSERT(size <= MaxSmallObjectSize); - freeSmallChunk(ote->m_location, size); - releasePointer(ote); - } - break; - default: ASSERT(false); __assume(false); @@ -148,9 +116,8 @@ void ObjectMemory::OTEPool::clear() ote->beAllocated(); - // All objects on the free list originated from pool space, so we need to - // send them back there - ote->m_flags.m_space = static_cast(Spaces::Pools); + // All objects on the free list originated from the heap, so we need to send them back there + ote->m_flags.m_space = static_cast(Spaces::Normal); ote->setSize(ote->isPointers() ? SizeOfPointers(m_size) : m_size); ObjectMemory::deallocate(ote); diff --git a/Core/DolphinVM/dll.vcxproj b/Core/DolphinVM/dll.vcxproj index f8f6c8c569..872d3ddf65 100644 --- a/Core/DolphinVM/dll.vcxproj +++ b/Core/DolphinVM/dll.vcxproj @@ -114,6 +114,7 @@ .\VM.def _DllMainCRTStartup%4012 + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) @@ -160,6 +161,7 @@ _DllMainCRTStartup%4012 MachineX86 true + $(SolutionDir)..\..\out\msvc-$(Platform)\Debug;%(AdditionalLibraryDirectories) @@ -214,6 +216,7 @@ _DllMainCRTStartup%4012 false false + $(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) diff --git a/Core/DolphinVM/ist.h b/Core/DolphinVM/ist.h index 2def05d0e7..3b7a760e85 100755 --- a/Core/DolphinVM/ist.h +++ b/Core/DolphinVM/ist.h @@ -56,7 +56,6 @@ #include #include #include -#include #include #pragma warning(disable:4711) // Function selected for automatic inline expansion diff --git a/Core/DolphinVM/objmem.cpp b/Core/DolphinVM/objmem.cpp index 4a8822669d..cdf58a6951 100644 --- a/Core/DolphinVM/objmem.cpp +++ b/Core/DolphinVM/objmem.cpp @@ -12,7 +12,6 @@ #pragma code_seg(MEM_SEG) #include "ObjMem.h" -#include "ObjMemPriv.inl" #include "Interprt.h" #include "rc_vm.h" #include "VMExcept.h" @@ -21,15 +20,9 @@ using namespace concurrency; - -HANDLE ObjectMemory::m_hHeap; -extern "C" { HANDLE _crtheap; } - #ifdef MEMSTATS - size_t m_nLargeAllocated = 0; - size_t m_nLargeFreed = 0; - size_t m_nSmallAllocated = 0; - size_t m_nSmallFreed = 0; + size_t m_nAllocated = 0; + size_t m_nFreed = 0; #endif #ifdef TRACKFREEOTEs @@ -508,23 +501,7 @@ ArrayOTE* __stdcall ObjectMemory::referencesTo(Oop referencedObjectPointer, bool *****************************************************************************/ -/////////////////////////////////////////////////////////////////////////////// -// Low-level memory chunk (not object) management routines -// -// These map directly onto C or Win32 heap - -#ifdef _DEBUG - size_t ObjectMemory::chunkSize(void* pChunk) - { - #ifdef PRIVATE_HEAP - return ::HeapSize(m_hHeap, 0, pChunk); - #else - return _msize(pChunk); - #endif - } -#endif - -/////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// // OT Allocation #pragma code_seg(GC_SEG) @@ -589,43 +566,11 @@ HRESULT ObjectMemory::allocateOT(size_t reserve, size_t commit) #pragma code_seg(GC_SEG) -// Compact any object memory heaps to minimize working set -void ObjectMemory::HeapCompact() -{ - // Minimize space occuppied by the heap - __sbh_heapmin(); - #ifdef PRIVATE_HEAP - ::HeapCompact(m_hHeap, 0); - #endif - - _heapmin(); -} - -#pragma code_seg(TERM_SEG) - -void ObjectMemory::FixedSizePool::Terminate() -{ - const size_t loopEnd = m_nAllocations; - for (size_t i=0;i MaxSizeOfPoolObject); - #else - bNeedsDealloc = ote.getSpace != Spaces::Pools; - #endif - - if (bNeedsDealloc) - { - ote.m_count = 0; // To avoid assertion - deallocate(&ote); - } + ote.m_count = 0; // To avoid assertion + deallocate(&ote); } } } - //for (auto j=0;jContextRecord->Esi, Interpreter::m_registers.m_stackPointer); #ifdef MEMSTATS - trace(L"Small Allocated %u, freed %u, large allocated %u, freed %u\n", - m_nSmallAllocated, m_nSmallFreed, m_nLargeAllocated, m_nLargeFreed); - m_nLargeAllocated = m_nLargeFreed = m_nSmallAllocated = m_nSmallFreed = 0; + trace(L"Objects allocated %u, freed %u\n", + m_nAllocated, m_nFreed); + m_nAllocated = m_nFreed = 0; #endif const size_t extraBytes = OTPagesAllocatedPerOverflow*dwPageSize; const size_t extraOTEs = extraBytes/sizeof(OTE); diff --git a/Core/DolphinVM/objmem.h b/Core/DolphinVM/objmem.h index 4287010838..bea0ed5d95 100644 --- a/Core/DolphinVM/objmem.h +++ b/Core/DolphinVM/objmem.h @@ -20,11 +20,10 @@ using namespace ST; -#define PRIVATE_HEAP -//#undef PRIVATE_HEAP +#define ObjMemCall __fastcall -// Dolphin Smallblock heap separate from C-runtime sbh -#include "sbheap.h" +//#define WIN32_HEAP +#undef WIN32_HEAP #if defined(_DEBUG) #define MEMSTATS @@ -63,9 +62,11 @@ class ObjectMemory // Public interface for use of Interpreter static HRESULT Initialize(); + static void __cdecl InitializeHeap(); static HRESULT InitializeImage(); static void InitializeMemoryManager(); static void Terminate(); + static void __cdecl UninitializeHeap(); // Object Pointer access static Oop fetchPointerOfObject(size_t fieldIndex, PointersOTE* ote); @@ -92,14 +93,6 @@ class ObjectMemory static ByteElementSize GetBytesElementSize(BytesOTE* ote); - // Use CRT Small block heap OR pool if size <= this threshold - static constexpr size_t MaxSmallObjectSize = 0x3f8; - static constexpr size_t NumPools = 5; - static constexpr size_t MinSizeHighBit = 3; - static constexpr size_t MinObjectSize = 1 << MinSizeHighBit; - static constexpr size_t PoolObjectSizeLimit = MinObjectSize << (NumPools - 1); - - static VirtualOTE* __fastcall newVirtualObject(BehaviorOTE* classPointer, size_t initialSize, size_t maxSize); static PointersOTE* __fastcall newPointerObject(BehaviorOTE* classPointer); static PointersOTE* __fastcall newPointerObject(BehaviorOTE* classPointer, size_t instanceSize); @@ -128,7 +121,7 @@ class ObjectMemory static size_t __fastcall OopsUsed(); static size_t GetOTSize(); static size_t compact(Oop* const sp); - static void HeapCompact(); + static void __cdecl HeapCompact(); // Used by Interpreter and Compiler to update any Oops they hold following a compact template static void compactOop(T*& ote) @@ -228,8 +221,7 @@ class ObjectMemory static void checkReferences(Oop* const sp); static void checkReferences(); static void addRefsFrom(OTE* ote); - static void checkPools(); - static void checkOtePools(); + static void __cdecl checkPools(); static void checkStackRefs(Oop* const sp); static bool isValidOop(Oop); #endif @@ -241,8 +233,7 @@ class ObjectMemory } #ifdef MEMSTATS - static void DumpStats(); - static void CheckPoint(); + static void __cdecl DumpStats(const wchar_t*); #endif static _PrimitiveFailureCode __stdcall SaveImageFile(const wchar_t* fileName, bool bBackup, int nCompressionLevel, size_t nMaxObjects); @@ -289,7 +280,7 @@ class ObjectMemory size_t m_nFree; size_t m_nAllocated; - void DumpStats(); + void __cdecl DumpStats(); void registerNew(OTE* newOTE, BehaviorOTE* classPointer); #endif @@ -410,56 +401,6 @@ class ObjectMemory #endif private: - /////////////////////////////////////////////////////////////////////////// - // Memory Pools - - __declspec(align(8)) class FixedSizePool - { - public: - FixedSizePool(size_t nChunkSize=MinObjectSize); - - POBJECT allocate(); - void deallocate(POBJECT pChunk); - - void setSize(size_t nChunkSize); - void terminate(); - - #ifdef _DEBUG - bool isMyChunk(void* pChunk); - bool isValid(); - #endif - - #ifdef MEMSTATS - size_t getPages() { return m_nPages; } - size_t getFree(); - void** m_pages; - size_t m_nPages; - #endif - - size_t getSize() { return m_nChunkSize; } - - private: - void moreChunks(); - static void morePages(); - static uint8_t* allocatePage(); - - public: - static void Initialize(); - static void Terminate(); - - public: - struct Link { Link* next; }; - - private: - - Link* m_pFreeChunks; - size_t m_nChunkSize; - - static Link* m_pFreePages; - static void** m_pAllocations; - public: - static size_t m_nAllocations; - }; static HRESULT __stdcall allocateOT(size_t reserve, size_t commit); @@ -470,20 +411,16 @@ class ObjectMemory public: static hash_t nextIdentityHash(); private: - // Memory allocators - these are very thin layers of C/Win32 heap - static void freeChunk(POBJECT pChunk); - static void freeSmallChunk(POBJECT pObj, size_t size); - static POBJECT reallocChunk(POBJECT pChunk, size_t newChunkSize); + // Low-level memory allocators - these are very thin layers over mimalloc or Win32 heap + static void* ObjMemCall allocChunk(size_t chunkSize); + static void ObjMemCall freeChunk(void* pChunk); + static void* ObjMemCall reallocChunk(void* pChunk, size_t newChunkSize); + #ifdef _DEBUG static size_t chunkSize(void* pChunk); #endif - static POBJECT allocSmallChunk(size_t chunkSize); - static POBJECT allocChunk(size_t chunkSize); static POBJECT allocObject(size_t objectSize, OTE*& ote); - static POBJECT allocLargeObject(size_t objectSize, OTE*& ote); - - static FixedSizePool& spacePoolForSize(size_t objectSize); static void decRefs(Oop); @@ -578,9 +515,6 @@ class ObjectMemory static OTE* m_pOT; // The Object Table itself private: static OTE* m_pFreePointerList; // Head of list of free Object Table Entries - -private: - static FixedSizePool m_pools[NumPools]; }; // Lower level object creation @@ -885,70 +819,6 @@ inline size_t ObjectMemory::lastStrongPointerOf(const OTE* ote) /////////////////////////////////////////////////////////////////////////////// -// Memory pool routines - -inline ObjectMemory::FixedSizePool& ObjectMemory::spacePoolForSize(size_t objectSize) -{ - HARDASSERT(objectSize != 0); - HARDASSERT(objectSize <= PoolObjectSizeLimit); - unsigned long nPool; - if (!_BitScanReverse(&nPool, (objectSize - 1) >> (MinSizeHighBit - 1))) - { - HARDASSERT(objectSize < MinObjectSize); - return m_pools[0]; - } - ASSUME(nPool < NumPools); - ObjectMemory::FixedSizePool& pool = m_pools[nPool]; - HARDASSERT(pool.getSize() >= objectSize); - HARDASSERT(nPool == 0 || (m_pools[nPool - 1].getSize() < objectSize)); - return pool; -} - -inline POBJECT ObjectMemory::FixedSizePool::allocate() -{ - if (!m_pFreeChunks) - { - moreChunks(); - ASSERT(m_pFreeChunks); - _ASSERTE(isValid()); - } - Link* pChunk = m_pFreeChunks; - m_pFreeChunks = pChunk->next; - - #if defined(_DEBUG) // && defined( // JGFoster - if (_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF) - HARDASSERT(isValid()); - memset(&pChunk->next, 0xCD, sizeof(pChunk->next)); - #endif - - return reinterpret_cast(pChunk); -} - -inline void ObjectMemory::FixedSizePool::deallocate(POBJECT p) -{ - #ifdef _DEBUG - HARDASSERT(isMyChunk(p)); - if (_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF) - { - HARDASSERT(isValid()); - } - memset(p, 0xCD, m_nChunkSize); - #endif - - Link* pChunk = reinterpret_cast(p); - pChunk->next = m_pFreeChunks; - m_pFreeChunks = pChunk; -} - -inline void ObjectMemory::FixedSizePool::terminate() -{ - #ifdef _DEBUG - free(m_pages); - m_pages = 0; - m_nPages = 0; - #endif - m_pFreeChunks = 0; -} inline size_t ObjectMemory::OTEPool::FreeCount() { @@ -1019,9 +889,6 @@ inline BytesOTE* ObjectMemory::OTEPool::newByteObject(BehaviorOTE* classPointer) #ifdef MEMSTATS registerNew(reinterpret_cast(ote), classPointer); #endif - - // It MUST be the case that all pooled objects can reside in pool space - ASSERT(ote->heapSpace() == Spaces::Pools); } ote->m_flags = m_spaceOTEBits[static_cast(m_space)]; @@ -1052,9 +919,6 @@ inline PointersOTE* ObjectMemory::OTEPool::newPointerObject(BehaviorOTE* classPo #ifdef MEMSTATS registerNew(reinterpret_cast(ote), classPointer); #endif - - // It MUST be the case that all pooled objects can reside in pool space - ASSERT(ote->heapSpace() == Spaces::Pools); } ote->m_flags = m_spaceOTEBits[static_cast(m_space)]; diff --git a/Core/DolphinVM/ote.h b/Core/DolphinVM/ote.h index 928744f1a3..34d656e169 100644 --- a/Core/DolphinVM/ote.h +++ b/Core/DolphinVM/ote.h @@ -35,13 +35,13 @@ typedef TOTE BehaviorOTE; typedef uint8_t count_t; typedef uint16_t hash_t; // Identity hash value, assigned on object creation -enum class Spaces { Normal, Virtual, Blocks, Contexts, Dwords, Heap, Floats, Pools }; +enum class Spaces { Normal, Virtual, Blocks, Contexts, Dwords, Heap, Floats }; typedef typename std::underlying_type::type space_t; union OTEFlags { // Object Creation - static constexpr space_t NumSpaces = static_cast(Spaces::Pools) + 1; + static constexpr space_t NumSpaces = static_cast(Spaces::Floats) + 1; struct { diff --git a/Core/DolphinVM/realloc.cpp b/Core/DolphinVM/realloc.cpp index 65dcbb243b..cdd2a2c945 100755 --- a/Core/DolphinVM/realloc.cpp +++ b/Core/DolphinVM/realloc.cpp @@ -13,39 +13,12 @@ #include "ObjMem.h" #include "interprt.h" -#include "ObjMemPriv.inl" // Smalltalk classes #include "STBehavior.h" // Need to look at class flags, and fixed fields #include "STVirtualObject.h" #include "STByteArray.h" -/////////////////////////////////////////////////////////////////////////////// -// Low-level memory chunk (not object) management routines -// -// These map directly onto C or Win32 heap - - -inline POBJECT ObjectMemory::reallocChunk(POBJECT pChunk, size_t newChunkSize) -{ - #if defined(_DEBUG) - if (__sbh_find_block(pChunk) != NULL) - // Hang on a minute, this block is from the SBH - ASSERT(FALSE); - else - { - for (auto i=0;i(pChunk))); - } - #endif - - #ifdef PRIVATE_HEAP - return static_cast(::HeapReAlloc(m_hHeap, 0, pChunk, newChunkSize)); - #else - return realloc(pChunk, newChunkSize); - #endif -} - /////////////////////////////////////////////////////////////////////////////// // Use with care. Neither initialises new space, or cleans up old pointers // which are sized away!! Although this is a public function, since sometimes @@ -71,7 +44,7 @@ template POBJECT ObjectMemory::basicResize(POTE ote, size_t byteS { // TRACE("Resizing normal object...\n"); pObject = ote->m_location; - pObject = reallocChunk(pObject, byteSize+Extra); + pObject = static_cast(reallocChunk(pObject, byteSize+Extra)); if (pObject) { @@ -86,33 +59,6 @@ template POBJECT ObjectMemory::basicResize(POTE ote, size_t byteS pObject = resizeVirtual(ote, byteSize+Extra); break; - case Spaces::Pools: - { - #if defined(_DEBUG) - if (abs(Interpreter::executionTrace) > 0) - checkPools(); - #endif - - // May be able to do some quicker resizing here if size is still in same pool? - if ((byteSize + Extra) <= MaxSmallObjectSize) - { - pObject = allocSmallChunk(byteSize + Extra); - } - else - { - pObject = allocChunk(byteSize + Extra); - ote->m_flags.m_space = static_cast(Spaces::Normal); - } - - POBJECT pOldObject = ote->m_location; - auto oldSize = ote->getSize(); - memcpy(pObject, pOldObject, min(oldSize, byteSize)); - freeSmallChunk(pOldObject, ote->sizeOf()); - ote->m_location = pObject; - ote->setSize(byteSize); - break; - } - default: // Not resizeable return nullptr; diff --git a/Core/DolphinVM/sbheap.h b/Core/DolphinVM/sbheap.h deleted file mode 100644 index 829e2edd3b..0000000000 --- a/Core/DolphinVM/sbheap.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#define __sbh_alloc_block __dsbh_alloc_block -#define __sbh_alloc_new_group __dsbh_alloc_new_group -#define __sbh_alloc_new_region __dsbh_alloc_new_region -#define __sbh_find_block __dsbh_find_block -//#define __sbh_verify_block __dsbh_verify_block -#define __sbh_free_block __dsbh_free_block -#define __sbh_heap_init __dsbh_heap_init -#define __sbh_heapmin __dsbh_heapmin -#define __sbh_resize_block __dsbh_resize_block -#define _get_sbh_threshold _get_dsbh_threshold -#define _set_sbh_threshold _set_dsbh_threshold - -#define _crtheap _dsbheap - -#define __sbh_threshold __dsbh_threshold -#define __sbh_pHeaderList __dsbh_pHeaderList -#define __sbh_pHeaderScan __dsbh_pHeaderScan -#define __sbh_sizeHeaderList __dsbh_sizeHeaderList -#define __sbh_cntHeaderList __dsbh_cntHeaderList -#define __sbh_pHeaderDefer __dsbh_pHeaderDefer -#define __sbh_indGroupDefer __dsbh_indGroupDefer diff --git a/Core/DolphinVM/zct.cpp b/Core/DolphinVM/zct.cpp index 081ded3407..92cf3089ce 100644 --- a/Core/DolphinVM/zct.cpp +++ b/Core/DolphinVM/zct.cpp @@ -13,7 +13,6 @@ #pragma code_seg(MEM_SEG) #include "ObjMem.h" -#include "ObjMemPriv.inl" #include "Interprt.h" #include "rc_vm.h" #include "RegKey.h" diff --git a/Core/Object Arts/Dolphin/Lagoon/Lagoon Tests.pax b/Core/Object Arts/Dolphin/Lagoon/Lagoon Tests.pax index d4dc062db9..7a3a6640c4 100644 --- a/Core/Object Arts/Dolphin/Lagoon/Lagoon Tests.pax +++ b/Core/Object Arts/Dolphin/Lagoon/Lagoon Tests.pax @@ -6,7 +6,6 @@ package paxVersion: 2.1; package setClassNames: #( - #{Tools.Tests.CRTLibraryImportTest} #{Tools.Tests.LagoonTests} #{Tools.Tests.PackageClosureTests} ). @@ -37,14 +36,6 @@ package! "Class Definitions"! -Core.Tests.DolphinTest - subclass: #'Tools.Tests.CRTLibraryImportTest' - instanceVariableNames: '' - classVariableNames: '' - imports: #() - classInstanceVariableNames: '' - classConstants: {}! - Core.Tests.DolphinTest subclass: #'Tools.Tests.LagoonTests' instanceVariableNames: '' diff --git a/Core/Object Arts/Dolphin/Lagoon/Tools.Tests.CRTLibraryImportTest.cls b/Core/Object Arts/Dolphin/Lagoon/Tools.Tests.CRTLibraryImportTest.cls deleted file mode 100644 index 54eb935e15..0000000000 --- a/Core/Object Arts/Dolphin/Lagoon/Tools.Tests.CRTLibraryImportTest.cls +++ /dev/null @@ -1,59 +0,0 @@ -"Filed out from Dolphin Smalltalk"! - -Core.Tests.DolphinTest - subclass: #'Tools.Tests.CRTLibraryImportTest' - instanceVariableNames: '' - classVariableNames: '' - imports: #() - classInstanceVariableNames: '' - classConstants: {}! - -Tools.Tests.CRTLibraryImportTest guid: (Core.GUID fromString: '{a3836ac0-e09a-4f44-b33f-3f87f52f2098}')! - -Tools.Tests.CRTLibraryImportTest comment: ''! - -!Tools.Tests.CRTLibraryImportTest categoriesForClass!SUnit! ! - -!Tools.Tests.CRTLibraryImportTest methodsFor! - -devOnlyCrtFunctions - ^((MethodCategory deprecatedMethods methodsInBehavior: OS.CRTLibrary) - select: [:each | each isExternalCall]) collect: [:each | each functionName]! - -stubNames - ^#('ConsoleToGo.exe' 'GUIToGo.exe' 'IPDolphinToGo.dll')! - -testStubCrtExports - "Ensure that .def files include proper CRTLibrary imports (#183)." - - | expected | - expected := self devOnlyCrtFunctions. - self stubNames do: - [:eachStubName | - | f l procs missing | - f := FileLocator installRelative localFileSpecFor: eachStubName. - l := External.DynamicLinkLibrary open: f. - - [| unexported | - procs := (OS.CRTLibrary selectMethods: [:each | each isExternalCall]) - collect: [:each | each functionName]. - missing := procs select: [:each | (l getProcAddress: each asAnsiString ifAbsent: []) isNil]. - unexported := missing difference: expected. - self assert: unexported isEmpty - description: - [| desc | - desc := String writeStream. - desc - nextPutAll: eachStubName; - nextPutAll: ' is missing exports for the required CRT functions '. - unexported asSortedCollection do: [:export | desc print: export] - separatedBy: [desc nextPutAll: ', ']. - desc contents]] - ensure: [l close]]! ! - -!Tools.Tests.CRTLibraryImportTest categoriesForMethods! -devOnlyCrtFunctions!constants!private! ! -stubNames!constants!private! ! -testStubCrtExports!public!unit tests! ! -! -