summaryrefslogtreecommitdiff
path: root/src/md/hotdata
diff options
context:
space:
mode:
Diffstat (limited to 'src/md/hotdata')
-rw-r--r--src/md/hotdata/.gitmirror1
-rw-r--r--src/md/hotdata/CMakeLists.txt21
-rw-r--r--src/md/hotdata/HotData.settings.targets28
-rw-r--r--src/md/hotdata/crossgen/.gitmirror1
-rw-r--r--src/md/hotdata/crossgen/CMakeLists.txt5
-rw-r--r--src/md/hotdata/crossgen/MDHotData_crossgen.nativeproj18
-rw-r--r--src/md/hotdata/dac/.gitmirror1
-rw-r--r--src/md/hotdata/dac/CMakeLists.txt6
-rw-r--r--src/md/hotdata/dac/dirs.proj19
-rw-r--r--src/md/hotdata/dirs.proj21
-rw-r--r--src/md/hotdata/export.h25
-rw-r--r--src/md/hotdata/external.cpp13
-rw-r--r--src/md/hotdata/external.h20
-rw-r--r--src/md/hotdata/full-staticcrt/.gitmirror1
-rw-r--r--src/md/hotdata/full-staticcrt/CMakeLists.txt4
-rw-r--r--src/md/hotdata/full-staticcrt/MDHotData-staticcrt.props11
-rw-r--r--src/md/hotdata/full-staticcrt/dirs.proj19
-rw-r--r--src/md/hotdata/full/.gitmirror1
-rw-r--r--src/md/hotdata/full/CMakeLists.txt3
-rw-r--r--src/md/hotdata/full/MDHotData.nativeproj19
-rw-r--r--src/md/hotdata/heapindex.h68
-rw-r--r--src/md/hotdata/hotdataformat.h155
-rw-r--r--src/md/hotdata/hotheap.cpp185
-rw-r--r--src/md/hotdata/hotheap.h67
-rw-r--r--src/md/hotdata/hotheapsdirectoryiterator.cpp110
-rw-r--r--src/md/hotdata/hotheapsdirectoryiterator.h71
-rw-r--r--src/md/hotdata/hotheapwriter.cpp305
-rw-r--r--src/md/hotdata/hotheapwriter.h84
-rw-r--r--src/md/hotdata/hotmetadata.cpp85
-rw-r--r--src/md/hotdata/hotmetadata.h43
-rw-r--r--src/md/hotdata/hottable.cpp138
-rw-r--r--src/md/hotdata/hottable.h57
32 files changed, 1605 insertions, 0 deletions
diff --git a/src/md/hotdata/.gitmirror b/src/md/hotdata/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/md/hotdata/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/md/hotdata/CMakeLists.txt b/src/md/hotdata/CMakeLists.txt
new file mode 100644
index 0000000000..199edaa40e
--- /dev/null
+++ b/src/md/hotdata/CMakeLists.txt
@@ -0,0 +1,21 @@
+
+set(MDHOTDATA_SOURCES
+ hotmetadata.cpp
+ hottable.cpp
+ hotheapsdirectoryiterator.cpp
+ hotheap.cpp
+ hotheapwriter.cpp
+)
+
+convert_to_absolute_path(MDHOTDATA_SOURCES ${MDHOTDATA_SOURCES})
+
+if(CLR_CMAKE_PLATFORM_UNIX)
+ add_compile_options(-fPIC)
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+add_subdirectory(dac)
+add_subdirectory(full)
+add_subdirectory(crossgen)
+if(WIN32)
+ add_subdirectory(full-staticcrt)
+endif(WIN32)
diff --git a/src/md/hotdata/HotData.settings.targets b/src/md/hotdata/HotData.settings.targets
new file mode 100644
index 0000000000..c8bde7d372
--- /dev/null
+++ b/src/md/hotdata/HotData.settings.targets
@@ -0,0 +1,28 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--*****************************************************-->
+ <!--This MSBuild project file was automatically generated-->
+ <!--from the original SOURCES/DIRS file by the KBC tool.-->
+ <!--*****************************************************-->
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <!--OK to delete NO_NTDLL for devdiv builds.-->
+ <MDHotDataSrcDirectory>$(ClrSrcDirectory)\MD\HotData\</MDHotDataSrcDirectory>
+ <CDefines>$(CDefines);UNICODE;_UNICODE</CDefines>
+ <OutputPath>$(ClrLibDest)</OutputPath>
+ <TargetType>LIBRARY</TargetType>
+ <PCHHeader>external.h</PCHHeader>
+ <EnableCxxPCHHeaders>true</EnableCxxPCHHeaders>
+ <!--PCH: Both precompiled header and cpp are on the same ..\ path this is likely to be wrong.-->
+ <PCHCompile>$(MDHotDataSrcDirectory)\external.cpp</PCHCompile>
+ </PropertyGroup>
+ <!--Leaf Project Items-->
+ <ItemGroup>
+ <CppCompile Include="$(MDHotDataSrcDirectory)\HotMetaData.cpp" />
+ <CppCompile Include="$(MDHotDataSrcDirectory)\HotTable.cpp" />
+ <CppCompile Include="$(MDHotDataSrcDirectory)\HotHeapsDirectoryIterator.cpp" />
+ <CppCompile Include="$(MDHotDataSrcDirectory)\HotHeap.cpp" />
+ <CppCompile Include="$(MDHotDataSrcDirectory)\HotHeapWriter.cpp" />
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/md/hotdata/crossgen/.gitmirror b/src/md/hotdata/crossgen/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/md/hotdata/crossgen/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/md/hotdata/crossgen/CMakeLists.txt b/src/md/hotdata/crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..7d7738c5c1
--- /dev/null
+++ b/src/md/hotdata/crossgen/CMakeLists.txt
@@ -0,0 +1,5 @@
+include(${CLR_DIR}/crossgen.cmake)
+include(../../md_wks.cmake)
+
+add_precompiled_header(external.h ../external.cpp MDHOTDATA_SOURCES)
+add_library_clr(mdhotdata_crossgen ${MDHOTDATA_SOURCES})
diff --git a/src/md/hotdata/crossgen/MDHotData_crossgen.nativeproj b/src/md/hotdata/crossgen/MDHotData_crossgen.nativeproj
new file mode 100644
index 0000000000..1e6087e594
--- /dev/null
+++ b/src/md/hotdata/crossgen/MDHotData_crossgen.nativeproj
@@ -0,0 +1,18 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <!--*****************************************************-->
+ <!--This MSBuild project file was automatically generated-->
+ <!--from the original SOURCES/DIRS file by the KBC tool.-->
+ <!--*****************************************************-->
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <OutputName>mdhotdata_crossgen</OutputName>
+ </PropertyGroup>
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\xplat\SetCrossGen.props" />
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\HotData\HotData.settings.targets" />
+
+ <!--Leaf Project Items-->
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>
diff --git a/src/md/hotdata/dac/.gitmirror b/src/md/hotdata/dac/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/md/hotdata/dac/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/md/hotdata/dac/CMakeLists.txt b/src/md/hotdata/dac/CMakeLists.txt
new file mode 100644
index 0000000000..99a3f1d00d
--- /dev/null
+++ b/src/md/hotdata/dac/CMakeLists.txt
@@ -0,0 +1,6 @@
+
+include(${CLR_DIR}/dac.cmake)
+
+add_precompiled_header(external.h ../external.cpp MDHOTDATA_SOURCES)
+
+add_library_clr(mdhotdata_dac ${MDHOTDATA_SOURCES})
diff --git a/src/md/hotdata/dac/dirs.proj b/src/md/hotdata/dac/dirs.proj
new file mode 100644
index 0000000000..730c0c89d6
--- /dev/null
+++ b/src/md/hotdata/dac/dirs.proj
@@ -0,0 +1,19 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Include="HostLocal\mdhotdata_dac.nativeproj" />
+ </ItemGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/md/hotdata/dirs.proj b/src/md/hotdata/dirs.proj
new file mode 100644
index 0000000000..1ad2cf969f
--- /dev/null
+++ b/src/md/hotdata/dirs.proj
@@ -0,0 +1,21 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Include="full\mdhotdata.nativeproj" />
+ <ProjectFile Include="full-staticcrt\dirs.proj" />
+ <ProjectFile Include="dac\dirs.proj" />
+ </ItemGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/md/hotdata/export.h b/src/md/hotdata/export.h
new file mode 100644
index 0000000000..a0a9305626
--- /dev/null
+++ b/src/md/hotdata/export.h
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: export.h
+//
+
+//
+// Popular types defined in MetaData\HotData directory.
+// It's supposed to be included from other (MetaData) subcomponents, not from this directory.
+//
+// ======================================================================================
+
+#pragma once
+
+#include "hotmetadata.h"
+
+#include "hottable.h"
+
+#include "hotheapsdirectoryiterator.h"
+#include "hotheap.h"
+
+#include "heapindex.h"
+
+#include "hotheapwriter.h"
diff --git a/src/md/hotdata/external.cpp b/src/md/hotdata/external.cpp
new file mode 100644
index 0000000000..26ec26d9a4
--- /dev/null
+++ b/src/md/hotdata/external.cpp
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: external.cpp
+//
+
+//
+// Precompiled headers.
+//
+// ======================================================================================
+
+#include "external.h"
diff --git a/src/md/hotdata/external.h b/src/md/hotdata/external.h
new file mode 100644
index 0000000000..eb14b17167
--- /dev/null
+++ b/src/md/hotdata/external.h
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: external.h
+//
+
+//
+// External types used in MetaData\HotData subcomponent classes.
+// This file is used for precompiled headers, so it has to be included at the beginning of every .cpp in
+// this directory.
+//
+// ======================================================================================
+
+#pragma once
+
+#include "../external.h"
+#include "../export.h"
+
+#include "../databuffer.h"
diff --git a/src/md/hotdata/full-staticcrt/.gitmirror b/src/md/hotdata/full-staticcrt/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/md/hotdata/full-staticcrt/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/md/hotdata/full-staticcrt/CMakeLists.txt b/src/md/hotdata/full-staticcrt/CMakeLists.txt
new file mode 100644
index 0000000000..8570c4a6f6
--- /dev/null
+++ b/src/md/hotdata/full-staticcrt/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_definitions(-D_CRTIMP=) # static link of crt
+
+add_precompiled_header(external.h ../external.cpp MDHOTDATA_SOURCES)
+add_library_clr(mdhotdata-staticcrt ${MDHOTDATA_SOURCES})
diff --git a/src/md/hotdata/full-staticcrt/MDHotData-staticcrt.props b/src/md/hotdata/full-staticcrt/MDHotData-staticcrt.props
new file mode 100644
index 0000000000..a9ac42bf5f
--- /dev/null
+++ b/src/md/hotdata/full-staticcrt/MDHotData-staticcrt.props
@@ -0,0 +1,11 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\HotData\HotData.settings.targets" />
+
+ <PropertyGroup>
+ <LinkNoLibraries>true</LinkNoLibraries>
+ <LinkUseCMT>true</LinkUseCMT>
+ <UseMsvcrt>false</UseMsvcrt>
+ </PropertyGroup>
+
+</Project>
diff --git a/src/md/hotdata/full-staticcrt/dirs.proj b/src/md/hotdata/full-staticcrt/dirs.proj
new file mode 100644
index 0000000000..cf4651a468
--- /dev/null
+++ b/src/md/hotdata/full-staticcrt/dirs.proj
@@ -0,0 +1,19 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Condition="'$(FeatureDbiDebugging)'=='true'" Include="HostLocal\mdhotdata-staticcrt.nativeproj" />
+ </ItemGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/md/hotdata/full/.gitmirror b/src/md/hotdata/full/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/md/hotdata/full/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/md/hotdata/full/CMakeLists.txt b/src/md/hotdata/full/CMakeLists.txt
new file mode 100644
index 0000000000..26fc6a0721
--- /dev/null
+++ b/src/md/hotdata/full/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_precompiled_header(external.h ../external.cpp MDHOTDATA_SOURCES)
+
+add_library_clr(mdhotdata_full ${MDHOTDATA_SOURCES})
diff --git a/src/md/hotdata/full/MDHotData.nativeproj b/src/md/hotdata/full/MDHotData.nativeproj
new file mode 100644
index 0000000000..b85a064343
--- /dev/null
+++ b/src/md/hotdata/full/MDHotData.nativeproj
@@ -0,0 +1,19 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <!--*****************************************************-->
+ <!--This MSBuild project file was automatically generated-->
+ <!--from the original SOURCES/DIRS file by the KBC tool.-->
+ <!--*****************************************************-->
+ <!--Leaf project Properties-->
+ <!--Leaf project Properties-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\MD\HotData\HotData.settings.targets" />
+
+ <PropertyGroup>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <OutputName>MDHotData</OutputName>
+ </PropertyGroup>
+
+ <!--Leaf Project Items-->
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>
diff --git a/src/md/hotdata/heapindex.h b/src/md/hotdata/heapindex.h
new file mode 100644
index 0000000000..5d63f97063
--- /dev/null
+++ b/src/md/hotdata/heapindex.h
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotHeapWriter.h
+//
+
+//
+// Class code:HeapIndex represents type of MetaData heap (#String, #GUID, #Blob, or #US).
+//
+// ======================================================================================
+
+#pragma once
+
+namespace MetaData
+{
+
+// --------------------------------------------------------------------------------------
+//
+// This class represents type of MetaData heap (#String, #GUID, #Blob, or #US).
+//
+class HeapIndex
+{
+private:
+ UINT32 m_Index;
+public:
+ enum
+ {
+ StringHeapIndex = 0,
+ GuidHeapIndex = 1,
+ BlobHeapIndex = 2,
+ UserStringHeapIndex = 3,
+
+ CountHeapIndex,
+ InvalidHeapIndex
+ };
+ HeapIndex()
+ {
+ m_Index = InvalidHeapIndex;
+ }
+ HeapIndex(UINT32 index)
+ {
+ _ASSERTE(IsValid(index));
+ m_Index = index;
+ }
+ void Set(UINT32 index)
+ {
+ _ASSERTE(IsValid(index));
+ m_Index = index;
+ }
+ void SetInvalid()
+ {
+ m_Index = InvalidHeapIndex;
+ }
+ BOOL IsValid() const
+ {
+ return m_Index < CountHeapIndex;
+ }
+ static BOOL IsValid(UINT32 index)
+ {
+ return index < CountHeapIndex;
+ }
+ UINT32 Get() const
+ { return m_Index; }
+
+}; // class HeapIndex
+
+}; // namespace MetaData
diff --git a/src/md/hotdata/hotdataformat.h b/src/md/hotdata/hotdataformat.h
new file mode 100644
index 0000000000..0823010611
--- /dev/null
+++ b/src/md/hotdata/hotdataformat.h
@@ -0,0 +1,155 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotDataFormat.h
+//
+
+//
+// Format of the hot data stored in the hot stream. The format consists of several structures:
+// * code:MetaData::HotMetaDataHeader, which contains reference to:
+// * code:MetaData::HotTablesDirectory, which contains array of references to:
+// * code:HotTableHeader
+// * code:MetaData::HotHeapsDirectory, which contains array of code:MetaData::HotHeapsDirectoryEntry,
+// each containig:
+// * index of the heap code:HeapIndex and a reference to:
+// * code:MetaData::HotHeapHeader, which contains reference to:
+// * index table, which contains sorted array of represented hot indexes in the heap
+// * value offsets table, which contains offsets of values for corresponding hot indexes in
+// previous table
+// * value heap, which contains the values (copied out) from the original cold heap
+//
+// ======================================================================================
+
+#pragma once
+
+#include "external.h"
+
+// To avoid weird .h cycles, we have to include stgpool.h to get include of metamodelpub.h
+#include <stgpool.h>
+#include <metamodelpub.h>
+
+namespace MetaData
+{
+
+// #HotMetaData
+// To help with startup time, we create a section of metadata that is only that meta-data that was touched
+// durring IBC profiling. Given an offset into a pool this checks if we have any hot data associated with
+// it. If we do we return a poitner to it, otherwse we return NULL.
+
+#include <pshpack1.h>
+
+// --------------------------------------------------------------------------------------
+//
+// Top level hot data header.
+// Ends at the end of MetaData hot stream (i.e. starts at offset end-8).
+//
+struct HotMetaDataHeader
+{
+ // Negative offset relative to the beginning of this structure.
+ // Points to the END (!!!) of code:HotTablesDirectory structure.
+ UINT32 m_nTablesDirectoryEnd_NegativeOffset;
+ // Negative offset relative to the beginning of this structure.
+ // Points to the (start of) code:HotHeapsDirectory structure.
+ UINT32 m_nHeapsDirectoryStart_NegativeOffset;
+
+}; // struct HotMetaDataHeader
+
+// --------------------------------------------------------------------------------------
+//
+// This is the starting structure for hot data of tables.
+// It's referenced (via reference to the end) from
+// code:HotMetaDataHeader::m_nTablesDirectoryEnd_NegativeOffset.
+//
+struct HotTablesDirectory
+{
+ // Magic number (code:#const_nMagic) for format verification.
+ UINT32 m_nMagic;
+ // Array of signed offsets (should have negative or 0 value) relative to the beginning of this structute
+ // for each MetaData table.
+ // Points to the (start of) code:HotTableHeader structure.
+ INT32 m_rgTableHeader_SignedOffset[TBL_COUNT];
+
+ //#const_nMagic
+ // Magic value "HOMD" in code:m_nMagic field.
+ static const UINT32 const_nMagic = 0x484f4e44;
+
+}; // struct HotTablesDirectory
+
+// --------------------------------------------------------------------------------------
+//
+// Describes hot data in a table.
+// Entry referenced (via reference to the start) from code:HotTablesDirectory::m_rgTableHeader_SignedOffset.
+//
+struct HotTableHeader
+{
+ UINT32 m_cTableRecordCount;
+ // Can be 0 or sizeof(struct HotTableHeader)
+ UINT32 m_nFirstLevelTable_PositiveOffset;
+ // Can be 0
+ UINT32 m_nSecondLevelTable_PositiveOffset;
+ UINT32 m_offsIndexMappingTable;
+ UINT32 m_offsHotData;
+ UINT16 m_shiftCount;
+
+}; // struct HotTableHeader
+
+// --------------------------------------------------------------------------------------
+//
+// This is the starting structure for hot data of heaps (string, blob, guid and user string heap).
+// The directory is an array of code:HotHeapsDirectoryEntry structures.
+// It's referenced from code:HotMetaDataHeader::m_nHeapsDirectoryStart_NegativeOffset.
+//
+struct HotHeapsDirectory
+{
+ //code:HotHeapsDirectoryEntry m_rgEntries[*];
+
+}; // struct HotHeapsDirectory
+
+// --------------------------------------------------------------------------------------
+//
+// Describes one heap and its hot data.
+// Entry in the hot heaps directory (code:HotHeapsDirectory).
+//
+struct HotHeapsDirectoryEntry
+{
+ // Index of the represented heap code:HeapIndex.
+ UINT32 m_nHeapIndex;
+ // Negative offset relative to the beginning of this structure.
+ // Points to the (start of) code:HotHeapHeader structure.
+ UINT32 m_nHeapHeaderStart_NegativeOffset;
+
+}; // struct HotHeapsDirectoryEntry
+
+// --------------------------------------------------------------------------------------
+//
+// Describes hot data in a heap.
+// It's referenced from code:HotHeapsDirectoryEntry::m_nHeapHeaderStart_NegativeOffset.
+//
+struct HotHeapHeader
+{
+ // Negative offset relative to the beginning of this structure.
+ // Points to a (start of) table of indexes (UINT32). This table is sorted, so binary search can be
+ // performed. If an index is cached in hot data of this heap, then the index is present in this table
+ // of indexes.
+ UINT32 m_nIndexTableStart_NegativeOffset;
+ // Negative offset relative to the beginning of this structure.
+ // Points to a (start of) table of value offsets (UINT32). This table contains value for each iteam in
+ // previous table of indexes. When an index is found in the previous table, then the value offset is
+ // stored in this table at the same index.
+ // The value offset is positive (!!!) offset relative to the start of heap values (see next member -
+ // code:m_nValueHeapStart_NegativeOffset)
+ UINT32 m_nValueOffsetTableStart_NegativeOffset;
+ // Negative offset relative to the beginning of this structure.
+ // Points to a (start of) values in the hot heap. This heap contains copies of values from the "normal"
+ // (cold) heap. The values in this heap have therefore the same encoding as the values in corresponding
+ // normal/cold heap.
+ // Offsets into this heap are stored in value offset table (code:m_nValueOffsetTableStart_NegativeOffset)
+ // as positive (!!!) offsets relative to the start of this hot value heap.
+ UINT32 m_nValueHeapStart_NegativeOffset;
+
+}; // struct HotHeapHeader
+
+#include <poppack.h>
+
+}; // namespace MetaData
diff --git a/src/md/hotdata/hotheap.cpp b/src/md/hotdata/hotheap.cpp
new file mode 100644
index 0000000000..ac53d23aff
--- /dev/null
+++ b/src/md/hotdata/hotheap.cpp
@@ -0,0 +1,185 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotHeap.cpp
+//
+
+//
+// Class code:MetaData::HotHeap represents a hot heap in MetaData hot stream.
+//
+// ======================================================================================
+
+#include "external.h"
+
+#include "hotheap.h"
+#include "hotdataformat.h"
+#include <utilcode.h>
+
+namespace MetaData
+{
+
+// --------------------------------------------------------------------------------------
+//
+// Initializes hot heap from its header and data.
+// Provides limited debug-only validation of the structure.
+//
+__checkReturn
+HRESULT
+HotHeap::Initialize(
+ struct HotHeapHeader *pHotHeapHeader,
+ DataBuffer hotHeapData)
+{
+ _ASSERTE(hotHeapData.GetDataPointerBehind() == reinterpret_cast<BYTE *>(pHotHeapHeader));
+
+ UINT32 nMaximumNegativeOffset = hotHeapData.GetSize();
+ if (pHotHeapHeader->m_nIndexTableStart_NegativeOffset > nMaximumNegativeOffset)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - invalid index table offset.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ if ((pHotHeapHeader->m_nIndexTableStart_NegativeOffset % 4) != 0)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - index table offset is not aligned.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ if (pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset > nMaximumNegativeOffset)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - invalid value offset table offset.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ if ((pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset % 4) != 0)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - value offset table offset is not aligned.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ // Index table has to be behind value offset table
+ if (pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset < pHotHeapHeader->m_nIndexTableStart_NegativeOffset)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - value offset table doesn't start before index table.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ if (pHotHeapHeader->m_nValueHeapStart_NegativeOffset > nMaximumNegativeOffset)
+ {
+ m_pHotHeapHeader = NULL;
+ Debug_ReportError("Invalid hot heap header format - invalid value heap offset.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ m_pHotHeapHeader = pHotHeapHeader;
+ return S_OK;
+} // HotHeap::Initialize
+
+#ifdef _DEBUG_METADATA
+// --------------------------------------------------------------------------------------
+//
+// Validates hot heap structure (extension of code:Initialize checks).
+//
+__checkReturn
+HRESULT
+HotHeap::Debug_Validate()
+{
+ // Additional verification, more strict checks than in code:Initialize
+ S_UINT32 nValueOffsetTableStart =
+ S_UINT32(2) *
+ S_UINT32(m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset);
+ if (nValueOffsetTableStart.IsOverflow() ||
+ (nValueOffsetTableStart.Value() != m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset))
+ {
+ Debug_ReportError("Invalid hot heap header format.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ if (m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset <= m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset)
+ {
+ Debug_ReportError("Invalid hot heap header format.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+
+ // Already validated against underflow in code:Initialize
+ BYTE *pIndexTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset;
+ UINT32 *rgIndexTable = reinterpret_cast<UINT32 *>(pIndexTableStart);
+ // Already validated against underflow in code:Initialize
+ BYTE *pValueOffsetTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset;
+ UINT32 *rgValueOffsetTable = reinterpret_cast<UINT32 *>(pValueOffsetTableStart);
+ // Already validated against underflow in code:Initialize
+ BYTE *pValueHeapStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset;
+ DataBuffer valueHeap(
+ pValueHeapStart,
+ m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset - m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset);
+
+ // Already validated for % 4 == 0 in code:Initialize
+ UINT32 cIndexTableCount = m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset / 4;
+ UINT32 nPreviousValue = 0;
+ for (UINT32 nIndex = 0; nIndex < cIndexTableCount; nIndex++)
+ {
+ if (nPreviousValue >= rgIndexTable[nIndex])
+ {
+ Debug_ReportError("Invalid hot heap header format.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ UINT32 nValueOffset = rgValueOffsetTable[nIndex];
+ if (nValueOffset >= valueHeap.GetSize())
+ {
+ Debug_ReportError("Invalid hot heap header format.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ // TODO: Verify item (depends if it is string, blob, guid or user string)
+ }
+ return S_OK;
+} // HotHeap::Debug_Validate
+#endif //_DEBUG_METADATA
+
+// --------------------------------------------------------------------------------------
+//
+// Gets stored data at index.
+// Returns S_FALSE if data index is not stored in hot heap.
+//
+__checkReturn
+HRESULT
+HotHeap::GetData(
+ UINT32 nDataIndex,
+ __in DataBlob *pData)
+{
+ // Already validated against underflow in code:Initialize
+ BYTE *pIndexTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset;
+ // Already validated against underflow in code:Initialize
+ BYTE *pValueOffsetTableStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueOffsetTableStart_NegativeOffset;
+ // Already validated against underflow in code:Initialize
+ BYTE *pValueHeapStart = reinterpret_cast<BYTE *>(m_pHotHeapHeader) - m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset;
+
+ const UINT32 *pnFoundDataIndex = BinarySearch<UINT32>(
+ reinterpret_cast<UINT32 *>(pIndexTableStart),
+ m_pHotHeapHeader->m_nIndexTableStart_NegativeOffset / sizeof(UINT32),
+ nDataIndex);
+
+ if (pnFoundDataIndex == NULL)
+ { // Index is not stored in hot data
+ return S_FALSE;
+ }
+ _ASSERTE(((UINT32 *)pIndexTableStart <= pnFoundDataIndex) &&
+ (pnFoundDataIndex + 1 <= (UINT32 *)m_pHotHeapHeader));
+
+ // Index of found data index in the index table (note: it is not offset, but really index)
+ UINT32 nIndexOfFoundDataIndex = (UINT32)(pnFoundDataIndex - (UINT32 *)pIndexTableStart);
+
+ // Value offset contains positive offset to the ValueHeap start
+ // Already validated against overflow in code:Initialize
+ UINT32 nValueOffset_PositiveOffset = reinterpret_cast<UINT32 *>(pValueOffsetTableStart)[nIndexOfFoundDataIndex];
+ if (nValueOffset_PositiveOffset >= m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset)
+ {
+ pData->Clear();
+ Debug_ReportError("Invalid hot data format - value offset reaches behind the hot heap data.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ pData->Init(
+ pValueHeapStart + nValueOffset_PositiveOffset,
+ m_pHotHeapHeader->m_nValueHeapStart_NegativeOffset - nValueOffset_PositiveOffset);
+
+ return S_OK;
+} // HotHeap::GetData
+
+}; // namespace MetaData
diff --git a/src/md/hotdata/hotheap.h b/src/md/hotdata/hotheap.h
new file mode 100644
index 0000000000..bad1ed2d0d
--- /dev/null
+++ b/src/md/hotdata/hotheap.h
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotHeap.h
+//
+
+//
+// Class code:MetaData::HotHeap represents a hot heap in MetaData hot stream.
+//
+// ======================================================================================
+
+#pragma once
+
+#include "external.h"
+
+namespace MetaData
+{
+
+// Forward declarations
+struct HotHeapHeader;
+
+// --------------------------------------------------------------------------------------
+//
+// This class represents a hot heap in MetaData hot stream.
+//
+class HotHeap
+{
+ friend class VerifyLayoutsMD;
+private:
+ struct HotHeapHeader *m_pHotHeapHeader;
+
+private:
+ friend class HotHeapsDirectoryIterator;
+
+ // Initializes hot heap from its header and data.
+ __checkReturn
+ HRESULT Initialize(struct HotHeapHeader *pHotHeapHeader, DataBuffer hotHeapData);
+
+public:
+ HotHeap()
+ { m_pHotHeapHeader = NULL; }
+ HotHeap(const HotHeap &source)
+ { m_pHotHeapHeader = source.m_pHotHeapHeader; }
+
+ void Clear()
+ { m_pHotHeapHeader = NULL; }
+
+ // Gets stored data at index.
+ // Returns S_FALSE if data index is not stored in hot heap.
+ __checkReturn
+ HRESULT GetData(
+ UINT32 nDataIndex,
+ __out DataBlob *pData);
+
+ inline BOOL IsEmpty() const
+ { return m_pHotHeapHeader == NULL; }
+
+#ifdef _DEBUG_METADATA
+ // Validates hot heap structure (extension of code:Initialize checks).
+ __checkReturn
+ HRESULT Debug_Validate();
+#endif //_DEBUG_METADATA
+
+}; // class HotHeap
+
+}; // namespace MetaData
diff --git a/src/md/hotdata/hotheapsdirectoryiterator.cpp b/src/md/hotdata/hotheapsdirectoryiterator.cpp
new file mode 100644
index 0000000000..e0cdb1ca8e
--- /dev/null
+++ b/src/md/hotdata/hotheapsdirectoryiterator.cpp
@@ -0,0 +1,110 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotHeapsDirectoryIterator.h
+//
+
+//
+// Class code:MetaData::HotHeapsDirectoryIterator represents an iterator through hot heaps directory
+// (code:HotHeapsDirectory).
+//
+// ======================================================================================
+
+#include "external.h"
+
+#include "hotheapsdirectoryiterator.h"
+#include "hotdataformat.h"
+
+namespace MetaData
+{
+
+// --------------------------------------------------------------------------------------
+//
+// Creates empty iterator.
+//
+HotHeapsDirectoryIterator::HotHeapsDirectoryIterator()
+{
+ m_RemainingHeapsDirectoryData.Clear();
+ m_HotHeapsData.Clear();
+} // HotHeapsDirectoryIterator::HotHeapsDirectoryIterator
+
+// --------------------------------------------------------------------------------------
+//
+// Initialize iteration on heaps directory (hotHeapsDirectoryData) with heap hot data (hotHeapsData).
+// The caller guarantees that the heap hot data end where heaps directory beggins.
+//
+void
+HotHeapsDirectoryIterator::Initialize(
+ DataBuffer hotHeapsDirectoryData,
+ DataBuffer hotHeapsData)
+{
+ _ASSERTE(hotHeapsData.GetDataPointerBehind() == hotHeapsDirectoryData.GetDataPointer());
+ m_RemainingHeapsDirectoryData = hotHeapsDirectoryData;
+ m_HotHeapsData = hotHeapsData;
+} // HotHeapsDirectoryIterator::Initialize
+
+// --------------------------------------------------------------------------------------
+//
+// Gets next hot heap (*pHotHeap, of index *pHotHeapIndex) from the heaps directory.
+// Returns S_OK and fills *pHotHeap and *pHotHeapIndex with the next code:HotHeap information.
+// Returns S_FALSE, if the last hot heap was already returned. Clears *pHotHeap and *pHotHeapIndex in this
+// case.
+// Returns error code if the format is invalid. Clears *pHotHeap and *pHotHeapIndex in this case.
+//
+__checkReturn
+HRESULT
+HotHeapsDirectoryIterator::GetNext(
+ HotHeap *pHotHeap,
+ HeapIndex *pHotHeapIndex)
+{
+ HRESULT hr;
+ DataBuffer hotHeapHeaderData;
+ DataBuffer hotHeapData;
+
+ struct HotHeapsDirectoryEntry *pEntry;
+ if (!m_RemainingHeapsDirectoryData.GetData<struct HotHeapsDirectoryEntry>(
+ &pEntry))
+ {
+ hr = S_FALSE;
+ goto ErrExit;
+ }
+
+ if (!HeapIndex::IsValid(pEntry->m_nHeapIndex))
+ {
+ Debug_ReportError("Invalid hot heaps directory format - invalid heap index.");
+ IfFailGo(METADATA_E_INVALID_FORMAT);
+ }
+ pHotHeapIndex->Set(pEntry->m_nHeapIndex);
+
+ hotHeapHeaderData = m_HotHeapsData;
+ if (!hotHeapHeaderData.SkipToExactSize(pEntry->m_nHeapHeaderStart_NegativeOffset))
+ {
+ Debug_ReportError("Invalid hot heaps directory format - heap header offset reaches in front of of hot heaps data.");
+ IfFailGo(METADATA_E_INVALID_FORMAT);
+ }
+
+ struct HotHeapHeader *pHeader;
+ if (!hotHeapHeaderData.PeekData<struct HotHeapHeader>(&pHeader))
+ {
+ Debug_ReportError("Invalid hot heaps directory format - heap header reaches behind hot heaps data.");
+ IfFailGo(METADATA_E_INVALID_FORMAT);
+ }
+
+ hotHeapData = m_HotHeapsData;
+ if (!hotHeapData.TruncateBySize(pEntry->m_nHeapHeaderStart_NegativeOffset))
+ {
+ Debug_ReportInternalError("There's a bug because previous call to SkipToExactSize succeeded.");
+ IfFailGo(METADATA_E_INVALID_FORMAT);
+ }
+
+ IfFailGo(pHotHeap->Initialize(pHeader, hotHeapData));
+ _ASSERTE(hr == S_OK);
+ return hr;
+ErrExit:
+ pHotHeap->Clear();
+ pHotHeapIndex->SetInvalid();
+ return hr;
+} // HotHeapsDirectoryIterator::GetNext
+
+}; // namespace MetaData
diff --git a/src/md/hotdata/hotheapsdirectoryiterator.h b/src/md/hotdata/hotheapsdirectoryiterator.h
new file mode 100644
index 0000000000..fc5acb9a53
--- /dev/null
+++ b/src/md/hotdata/hotheapsdirectoryiterator.h
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotHeapsDirectoryIterator.h
+//
+
+//
+// Class code:MetaData::HotHeapsDirectoryIterator represents an iterator through hot heaps directory
+// (code:HotHeapsDirectory).
+//
+// ======================================================================================
+
+#pragma once
+
+#include "external.h"
+#include "heapindex.h"
+#include "hotheap.h"
+
+namespace MetaData
+{
+
+// --------------------------------------------------------------------------------------
+//
+// This class represents an iterator through hot heaps directory (code:HotHeapsDirectory), i.e. through an
+// array of code:HotHeapsDirectoryEntry.
+//
+class HotHeapsDirectoryIterator
+{
+private:
+ //
+ // Private data
+ //
+
+ // Remaining data from the heaps directory. On each iteration this will be shrinked (the
+ // code:HotHeapsDirectoryEntry will be skipped).
+ DataBuffer m_RemainingHeapsDirectoryData;
+ // Data for the hot heaps. It has to end exactly where heaps directory starts.
+ DataBuffer m_HotHeapsData;
+
+private:
+ //
+ // Operations with restricted access
+ //
+
+ // code:HotMetaData is the only class allowed to create this iteration.
+ friend class HotMetaData;
+
+ // Initialize iteration on heaps directory (hotHeapsDirectoryData) with heap hot data (hotHeapsData).
+ // The caller guarantees that the heap hot data end where heaps directory beggins.
+ void Initialize(
+ DataBuffer hotHeapsDirectoryData,
+ DataBuffer hotHeapsData);
+
+public:
+ //
+ // Operations
+ //
+
+ // Creates empty iterator.
+ HotHeapsDirectoryIterator();
+
+ // S_OK, S_FALSE, error code (clears the HotHeap if not S_OK)
+ __checkReturn
+ HRESULT GetNext(
+ HotHeap *pHotHeap,
+ HeapIndex *pHotHeapIndex);
+
+}; // class HotHeapsDirectoryIterator
+
+}; // namespace MetaData
diff --git a/src/md/hotdata/hotheapwriter.cpp b/src/md/hotdata/hotheapwriter.cpp
new file mode 100644
index 0000000000..7f4edf4cff
--- /dev/null
+++ b/src/md/hotdata/hotheapwriter.cpp
@@ -0,0 +1,305 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotHeapWriter.cpp
+//
+
+//
+// Class code:HotHeapWriter represents a writer of hot heap into MetaData hot stream (collected by IBC).
+//
+// ======================================================================================
+
+#include "external.h"
+
+#include "hotheapwriter.h"
+#include "../heaps/export.h"
+
+#include <stgpool.h>
+#include <metamodelpub.h>
+#include <utilcode.h>
+#include "../inc/streamutil.h"
+
+#include "hotdataformat.h"
+
+#ifdef FEATURE_PREJIT
+// Cannot be included without FEATURE_PREJIT:
+#include <corcompile.h>
+#endif //FEATURE_PREJIT
+
+namespace MetaData
+{
+
+// --------------------------------------------------------------------------------------
+//
+// Creates writer for #String heap.
+//
+HotHeapWriter::HotHeapWriter(
+ const StringHeapRW *pStringHeap)
+{
+ m_HeapIndex = HeapIndex::StringHeapIndex;
+ m_pStringHeap = pStringHeap;
+} // HotHeapWriter::HotHeapWriter
+
+// --------------------------------------------------------------------------------------
+//
+// Creates writer for #Blob or #US heap (if fUserStringHeap is TRUE).
+//
+HotHeapWriter::HotHeapWriter(
+ const BlobHeapRW *pBlobHeap,
+ BOOL fUserStringHeap)
+{
+ m_HeapIndex = fUserStringHeap ? HeapIndex::UserStringHeapIndex : HeapIndex::BlobHeapIndex;
+ m_pBlobHeap = pBlobHeap;
+} // HotHeapWriter::HotHeapWriter
+
+// --------------------------------------------------------------------------------------
+//
+// Creates writer for #GUID heap.
+//
+HotHeapWriter::HotHeapWriter(
+ const GuidHeapRW *pGuidHeap)
+{
+ m_HeapIndex = HeapIndex::GuidHeapIndex;
+ m_pGuidHeap = pGuidHeap;
+} // HotHeapWriter::HotHeapWriter
+
+// --------------------------------------------------------------------------------------
+//
+// Destroys the writer of hot heap.
+//
+void
+HotHeapWriter::Delete()
+{
+} // HotHeapWriter::Delete
+
+typedef struct _RidOffsetPair
+{
+ ULONG rid;
+ ULONG offset;
+ // compare function for qsort
+ static int __cdecl Compare(void const *_x, void const *_y);
+} RidOffsetPair;
+
+// static
+int __cdecl
+RidOffsetPair::Compare(void const *_x, void const *_y)
+{
+ RidOffsetPair const *x = reinterpret_cast<RidOffsetPair const *>(_x);
+ RidOffsetPair const *y = reinterpret_cast<RidOffsetPair const *>(_y);
+
+ return x->rid - y->rid;
+}
+
+// --------------------------------------------------------------------------------------
+//
+// Stores hot data reported by IBC in profile data (code:CorProfileData) to a stream.
+// Aligns output stream to 4-bytes.
+//
+__checkReturn
+HRESULT
+HotHeapWriter::SaveToStream(
+ IStream *pStream,
+ CorProfileData *pProfileData,
+ UINT32 *pnSavedSize) const
+{
+ _ASSERTE(pStream != NULL);
+ _ASSERTE(pProfileData != NULL);
+ _ASSERTE(pnSavedSize != NULL);
+
+#ifdef FEATURE_PREJIT
+ HRESULT hr = S_OK;
+ UINT32 nOffset = 0;
+ UINT32 nValueHeapStart_PositiveOffset;
+ UINT32 nValueOffsetTableStart_PositiveOffset;
+ UINT32 nIndexTableStart_PositiveOffset;
+
+ // data
+ //
+
+ // number of hot tokens
+ UINT32 nHotItemsCount = pProfileData->GetHotTokens(
+ GetTableIndex(),
+ 1 << ProfilingFlags_MetaData,
+ 1 << ProfilingFlags_MetaData,
+ NULL,
+ 0);
+ CONSISTENCY_CHECK(nHotItemsCount != 0);
+
+ NewArrayHolder<UINT32> hotItemArr = new (nothrow) UINT32[nHotItemsCount];
+ IfNullRet(hotItemArr);
+
+ // get hot tokens
+ static_assert_no_msg(sizeof(UINT32) == sizeof(mdToken));
+ pProfileData->GetHotTokens(
+ GetTableIndex(),
+ 1 << ProfilingFlags_MetaData,
+ 1 << ProfilingFlags_MetaData,
+ reinterpret_cast<mdToken *>(&hotItemArr[0]),
+ nHotItemsCount);
+
+ // convert tokens to rids
+ for (UINT32 i = 0; i < nHotItemsCount; i++)
+ {
+ hotItemArr[i] = RidFromToken(hotItemArr[i]);
+ }
+
+ NewArrayHolder<RidOffsetPair> offsetMapping = new (nothrow) RidOffsetPair[nHotItemsCount];
+ IfNullRet(offsetMapping);
+
+ // write data
+ nValueHeapStart_PositiveOffset = nOffset;
+
+ // note that we write hot items in the order they appear in pProfileData->GetHotTokens
+ // this is so that we preserve the ordering optimizations done by IbcMerge
+ for (UINT32 i = 0; i < nHotItemsCount; i++)
+ {
+ DataBlob data;
+ IfFailRet(GetData(
+ hotItemArr[i],
+ &data));
+
+ // keep track of the offset at which each hot item is written
+ offsetMapping[i].rid = hotItemArr[i];
+ offsetMapping[i].offset = nOffset;
+
+ IfFailRet(StreamUtil::WriteToStream(
+ pStream,
+ data.GetDataPointer(),
+ data.GetSize(),
+ &nOffset));
+ }
+
+ IfFailRet(StreamUtil::AlignDWORD(pStream, &nOffset));
+
+ // sort by rid so that a hot rid can be looked up by binary search
+ qsort(offsetMapping, nHotItemsCount, sizeof(RidOffsetPair), RidOffsetPair::Compare);
+
+ // initialize table of offsets to data
+ NewArrayHolder<UINT32> dataIndices = new (nothrow) UINT32[nHotItemsCount];
+ IfNullRet(dataIndices);
+
+ // fill in the hotItemArr (now sorted by rid) and dataIndices array with each offset
+ for (UINT32 i = 0; i < nHotItemsCount; i++)
+ {
+ hotItemArr[i] = offsetMapping[i].rid;
+ dataIndices[i] = offsetMapping[i].offset;
+ }
+
+ // table of offsets to data
+ //
+
+ nValueOffsetTableStart_PositiveOffset = nOffset;
+ IfFailRet(StreamUtil::WriteToStream(pStream, &dataIndices[0], sizeof(UINT32) * nHotItemsCount, &nOffset));
+
+ // rid table (sorted)
+ //
+
+ nIndexTableStart_PositiveOffset = nOffset;
+
+ IfFailRet(StreamUtil::WriteToStream(pStream, &hotItemArr[0], nHotItemsCount * sizeof(UINT32), &nOffset));
+ IfFailRet(StreamUtil::AlignDWORD(pStream, &nOffset));
+
+ {
+ // hot pool header
+ struct HotHeapHeader header;
+
+ // fix offsets
+ header.m_nIndexTableStart_NegativeOffset = nOffset - nIndexTableStart_PositiveOffset;
+ header.m_nValueOffsetTableStart_NegativeOffset = nOffset - nValueOffsetTableStart_PositiveOffset;
+ header.m_nValueHeapStart_NegativeOffset = nOffset - nValueHeapStart_PositiveOffset;
+
+ // write header
+ IfFailRet(StreamUtil::WriteToStream(pStream, &header, sizeof(header), &nOffset));
+ }
+
+ *pnSavedSize = nOffset;
+
+#endif //FEATURE_PREJIT
+
+ return S_OK;
+} // HotHeapWriter::PersistHotToStream
+
+// --------------------------------------------------------------------------------------
+//
+// Returns index of the heap as table index used by IBC (code:CorProfileData).
+//
+UINT32
+HotHeapWriter::GetTableIndex() const
+{
+ return TBL_COUNT + m_HeapIndex.Get();
+} // HotHeapWriter::GetTableIndex
+
+// --------------------------------------------------------------------------------------
+//
+// Returns heap data at index (nIndex).
+//
+__checkReturn
+HRESULT
+HotHeapWriter::GetData(
+ UINT32 nIndex,
+ DataBlob *pData) const
+{
+ HRESULT hr;
+
+ switch (m_HeapIndex.Get())
+ {
+ case HeapIndex::StringHeapIndex:
+ {
+ LPCSTR szString;
+ IfFailGo(m_pStringHeap->GetString(
+ nIndex,
+ &szString));
+ _ASSERTE(hr == S_OK);
+
+ // This should not overflow, because we checked it before, but it doesn't hurt
+ S_UINT32 cbStringSize = S_UINT32(strlen(szString)) + S_UINT32(1);
+ if (cbStringSize.IsOverflow())
+ {
+ Debug_ReportInternalError("There's a bug in the string heap consistency - string is too long.");
+ IfFailGo(METADATA_E_INTERNAL_ERROR);
+ }
+
+ pData->Init((BYTE *)szString, cbStringSize.Value());
+ return S_OK;
+ }
+ case HeapIndex::GuidHeapIndex:
+ {
+ // The nIndex is in fact 0-based offset into GUID heap (0, 16, 32, ...), convert it to 1-based element index (1, 2, 3, ...) for GetGuid method
+ if ((nIndex % sizeof(GUID)) != 0)
+ {
+ Debug_ReportInternalError("There's a bug in the caller/IBC - this should be GUID offset aligned to 16-B.");
+ IfFailGo(METADATA_E_INTERNAL_ERROR);
+ }
+ nIndex = (nIndex / sizeof(GUID)) + 1;
+
+ GUID UNALIGNED *pGuid;
+ IfFailGo(const_cast<GuidHeapRW *>(m_pGuidHeap)->GetGuid(
+ nIndex,
+ &pGuid));
+ _ASSERTE(hr == S_OK);
+ pData->Init((BYTE *)pGuid, sizeof(GUID));
+ return S_OK;
+ }
+ case HeapIndex::BlobHeapIndex:
+ case HeapIndex::UserStringHeapIndex:
+ {
+ IfFailGo(const_cast<BlobHeapRW *>(m_pBlobHeap)->GetBlobWithSizePrefix(
+ nIndex,
+ pData));
+ _ASSERTE(hr == S_OK);
+
+ return S_OK;
+ }
+ default:
+ Debug_ReportInternalError("There's a bug in the caller - this is wrong heap index.");
+ IfFailGo(METADATA_E_INTERNAL_ERROR);
+ }
+ return S_OK;
+
+ErrExit:
+ pData->Clear();
+ return hr;
+} // HotHeapWriter::GetData
+
+}; // namespace MetaData
diff --git a/src/md/hotdata/hotheapwriter.h b/src/md/hotdata/hotheapwriter.h
new file mode 100644
index 0000000000..c62b50277a
--- /dev/null
+++ b/src/md/hotdata/hotheapwriter.h
@@ -0,0 +1,84 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotHeapWriter.h
+//
+
+//
+// Class code:HotHeapWriter represents a writer of hot heap into MetaData hot stream (collected by IBC).
+//
+// ======================================================================================
+
+#pragma once
+
+#include "external.h"
+#include "heapindex.h"
+
+// Forward declarations
+class CorProfileData;
+struct IStream;
+
+namespace MetaData
+{
+
+// Forward declarations
+class StringHeapRW;
+class BlobHeapRW;
+class GuidHeapRW;
+
+// --------------------------------------------------------------------------------------
+//
+// This class represents a writer of hot heap into MetaData hot stream (collected by IBC).
+//
+class HotHeapWriter
+{
+private:
+ // Index of the represented heap (type of the heap).
+ HeapIndex m_HeapIndex;
+ union
+ {
+ const StringHeapRW *m_pStringHeap;
+ // Both #Blob and #US heaps are represented as code:BlobHeapRW.
+ const BlobHeapRW *m_pBlobHeap;
+ const GuidHeapRW *m_pGuidHeap;
+ };
+
+public:
+ // Creates writer for #String heap.
+ HotHeapWriter(const StringHeapRW *pStringHeap);
+ // Creates writer for #Blob or #US heap (if fUserStringHeap is TRUE).
+ HotHeapWriter(
+ const BlobHeapRW *pBlobHeap,
+ BOOL fUserStringHeap);
+ // Creates writer for #GUID heap.
+ HotHeapWriter(const GuidHeapRW *pGuidHeap);
+
+ // Destroys the writer of hot heap.
+ void Delete();
+
+ // Stores hot data reported by IBC in profile data (code:CorProfileData) to a stream.
+ // Aligns output stream to 4-bytes.
+ __checkReturn
+ HRESULT SaveToStream(
+ IStream *pStream,
+ CorProfileData *pProfileData,
+ UINT32 *pnSavedSize) const;
+
+ // Returns index of the heap as table index used by IBC (code:CorProfileData).
+ UINT32 GetTableIndex() const;
+
+private:
+ //
+ // Helpers
+ //
+
+ // Returns heap data at index (nIndex).
+ __checkReturn
+ HRESULT GetData(
+ UINT32 nIndex,
+ DataBlob *pData) const;
+
+}; // class HotHeapWriter
+
+}; // namespace MetaData
diff --git a/src/md/hotdata/hotmetadata.cpp b/src/md/hotdata/hotmetadata.cpp
new file mode 100644
index 0000000000..2810eecd15
--- /dev/null
+++ b/src/md/hotdata/hotmetadata.cpp
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotMetaData.cpp
+//
+
+//
+// Class code:MetaData::HotMetaData represents a reader of hot data in MetaData hot stream.
+//
+// ======================================================================================
+
+#include "external.h"
+
+#include "hotmetadata.h"
+#include "hotdataformat.h"
+#include "hotheapsdirectoryiterator.h"
+
+namespace MetaData
+{
+
+// --------------------------------------------------------------------------------------
+//
+// Class code:MetaData::HotMetaData represents a reader of hot data in MetaData hot stream.
+//
+__checkReturn
+HRESULT
+HotMetaData::Initialize(
+ DataBuffer data)
+{
+ m_Data = data;
+
+ return S_OK;
+} // HotMetaData::Initialize
+
+// --------------------------------------------------------------------------------------
+//
+// Returns iterator of stored hot heaps (code:HotHeap).
+//
+__checkReturn
+HRESULT
+HotMetaData::GetHeapsDirectoryIterator(
+ HotHeapsDirectoryIterator *pHeapsDirectoryIterator)
+{
+ if (m_Data.GetSize() < sizeof(struct HotMetaDataHeader))
+ {
+ Debug_ReportError("Invalid hot MetaData format - header doesn't fit into the hot data.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+
+ struct HotMetaDataHeader *pHeader;
+ if (!m_Data.PeekDataAt<struct HotMetaDataHeader>(
+ m_Data.GetSize() - sizeof(struct HotMetaDataHeader),
+ &pHeader))
+ {
+ Debug_ReportInternalError("There's a bug, because previous size check succeeded.");
+ return METADATA_E_INTERNAL_ERROR;
+ }
+ // Get rid of the read header
+ DataBuffer heapsData = m_Data;
+ if (!heapsData.TruncateBySize(sizeof(struct HotMetaDataHeader)))
+ {
+ Debug_ReportInternalError("There's a bug, because previous size check succeeded.");
+ return METADATA_E_INTERNAL_ERROR;
+ }
+ DataBuffer heapsDirectoryData = heapsData;
+ if (!heapsDirectoryData.SkipToExactSize(pHeader->m_nHeapsDirectoryStart_NegativeOffset))
+ {
+ Debug_ReportError("Invalid hot MetaData format - heaps directory offset reaches in front of hot data.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+ if (!heapsData.TruncateBySize(pHeader->m_nHeapsDirectoryStart_NegativeOffset))
+ {
+ Debug_ReportInternalError("There's a bug, because previous call to SkipToExactSize succeeded.");
+ return METADATA_E_INVALID_FORMAT;
+ }
+
+ pHeapsDirectoryIterator->Initialize(
+ heapsDirectoryData,
+ heapsData);
+
+ return S_OK;
+} // HotMetaData::GetHeapsDirectoryIterator
+
+}; // namespace MetaData
diff --git a/src/md/hotdata/hotmetadata.h b/src/md/hotdata/hotmetadata.h
new file mode 100644
index 0000000000..cba75fe46a
--- /dev/null
+++ b/src/md/hotdata/hotmetadata.h
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotMetaData.h
+//
+
+//
+// Class code:MetaData::HotMetaData represents a reader of hot data in MetaData hot stream.
+//
+// ======================================================================================
+
+#pragma once
+
+#include "external.h"
+
+namespace MetaData
+{
+
+// Forward declaration
+class HotHeapsDirectoryIterator;
+
+// --------------------------------------------------------------------------------------
+//
+// This class represents a reader of hot data in MetaData hot stream.
+//
+class HotMetaData
+{
+private:
+ DataBuffer m_Data;
+
+public:
+ // Creates reader for MetaData hot stream of format file:HotDataFormat.h.
+ __checkReturn
+ HRESULT Initialize(DataBuffer data);
+
+ // Returns iterator of stored hot heaps (code:HotHeap).
+ __checkReturn
+ HRESULT GetHeapsDirectoryIterator(HotHeapsDirectoryIterator *pHeapsDirectoryIterator);
+
+}; // class HotMetaData
+
+}; // namespace MetaData
diff --git a/src/md/hotdata/hottable.cpp b/src/md/hotdata/hottable.cpp
new file mode 100644
index 0000000000..51efe1bf94
--- /dev/null
+++ b/src/md/hotdata/hottable.cpp
@@ -0,0 +1,138 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotTable.cpp
+//
+
+//
+// Class code:MetaData::HotTable stores hot table records cache, a cache of often-accessed
+// table records stored only in NGEN images.
+// The cache is created using IBC logging.
+//
+// ======================================================================================
+
+#include "external.h"
+
+#include "hottable.h"
+#include "hotdataformat.h"
+
+#include <metamodelpub.h>
+
+namespace MetaData
+{
+
+// --------------------------------------------------------------------------------------
+//
+// Returns S_OK if index (nIndex) is present in the hot table record cache and returns its value from
+// cache (*ppRecord).
+// Returns S_FALSE if offset is not in the hot table record cache, DOES NOT initialize *ppRecord in this
+// case!
+// Returns error code otherwise (and sets *pRecord to NULL).
+//
+
+//static
+__checkReturn
+HRESULT
+HotTable::GetData(
+ UINT32 nRowIndex,
+ __deref_out_opt BYTE **ppRecord,
+ UINT32 cbRecordSize,
+ struct HotTableHeader *pHotTableHeader)
+{
+ BYTE *pHotTableHeaderData = (BYTE *)pHotTableHeader;
+
+ if (pHotTableHeader->m_nFirstLevelTable_PositiveOffset != 0)
+ { // Has first level table
+ // fetch the first level table
+ WORD *pFirstLevelTable = (WORD *)(pHotTableHeaderData + pHotTableHeader->m_nFirstLevelTable_PositiveOffset);
+
+ // find the high order bits of the rid
+ BYTE bRid = (BYTE)(nRowIndex >> pHotTableHeader->m_shiftCount);
+
+ // use the low order bits of the rid to index into
+ // the first level table.
+ UINT32 nMask = (1 << pHotTableHeader->m_shiftCount) - 1;
+ int i = pFirstLevelTable[nRowIndex & nMask];
+ int end = pFirstLevelTable[(nRowIndex & nMask) + 1];
+
+ // the generation logic should make sure either all tables are present
+ // or all absent.
+ _ASSERTE(pHotTableHeader->m_nSecondLevelTable_PositiveOffset != 0);
+ _ASSERTE(pHotTableHeader->m_offsIndexMappingTable != 0);
+
+ // fetch second level and index mapping tables
+ BYTE *pSecondLevelTable = pHotTableHeaderData + pHotTableHeader->m_nSecondLevelTable_PositiveOffset;
+ WORD *pIndexMappingTable = (WORD *)(pHotTableHeaderData + pHotTableHeader->m_offsIndexMappingTable);
+
+ // look for the high order bits of the rid in the second level table.
+ // search is linear, but should be short on average.
+ for ( ; i < end; i++)
+ {
+ if (pSecondLevelTable[i] == bRid)
+ {
+ // we have found the hot rid we are looking for
+
+ // now consult the index mapping table to find where the hot data is stored
+ int index = pIndexMappingTable[i];
+
+ *ppRecord = pHotTableHeaderData + pHotTableHeader->m_offsHotData + (index * cbRecordSize);
+ return S_OK;
+ }
+ }
+ // Not found in hot data
+ return S_FALSE;
+ }
+ // no first level table - this implies the whole table is replicated
+ // in the hot section. simply multiply and fetch the right record.
+ // hot indices are 0-based, rids are 1-base, so need to subtract 1 from rid.
+
+ *ppRecord = pHotTableHeaderData + pHotTableHeader->m_offsHotData + ((nRowIndex - 1) * cbRecordSize);
+ return S_OK;
+} // HotTable::GetData
+
+// static
+void
+HotTable::CheckTables(struct HotTablesDirectory *pHotTablesDirectory)
+{
+#ifdef _DEBUG
+ _ASSERTE(pHotTablesDirectory->m_nMagic == HotTablesDirectory::const_nMagic);
+
+ for (UINT32 nTableIndex = 0; nTableIndex < TBL_COUNT; nTableIndex++)
+ {
+ if (pHotTablesDirectory->m_rgTableHeader_SignedOffset[nTableIndex] != 0)
+ {
+ struct HotTableHeader *pHotTableHeader = GetTableHeader(pHotTablesDirectory, nTableIndex);
+
+ _ASSERTE((pHotTableHeader->m_cTableRecordCount > 0) && (pHotTableHeader->m_cTableRecordCount <= USHRT_MAX));
+ if (pHotTableHeader->m_nFirstLevelTable_PositiveOffset == 0)
+ {
+ _ASSERTE(pHotTableHeader->m_nSecondLevelTable_PositiveOffset == 0);
+ _ASSERTE(pHotTableHeader->m_offsIndexMappingTable == 0);
+ _ASSERTE(pHotTableHeader->m_offsHotData == Align4(sizeof(struct HotTableHeader)));
+ }
+ else
+ {
+ UINT32 nFirstLevelTableOffset = sizeof(struct HotTableHeader);
+ _ASSERTE(pHotTableHeader->m_nFirstLevelTable_PositiveOffset == nFirstLevelTableOffset);
+ UINT32 cbFirstLevelTableSize = sizeof(WORD) * ((1 << pHotTableHeader->m_shiftCount) + 1);
+
+ _ASSERTE(pHotTableHeader->m_nSecondLevelTable_PositiveOffset != 0);
+ UINT32 nSecondLevelTableOffset = nFirstLevelTableOffset + cbFirstLevelTableSize;
+ _ASSERTE(pHotTableHeader->m_nSecondLevelTable_PositiveOffset == nSecondLevelTableOffset);
+ UINT32 cbSecondLevelTableSize = sizeof(BYTE) * pHotTableHeader->m_cTableRecordCount;
+
+ _ASSERTE(pHotTableHeader->m_offsIndexMappingTable != 0);
+ UINT32 nIndexMappingTableOffset = nSecondLevelTableOffset + cbSecondLevelTableSize;
+ _ASSERTE(pHotTableHeader->m_offsIndexMappingTable == nIndexMappingTableOffset);
+ UINT32 cbIndexMappingTableSize = sizeof(WORD) * pHotTableHeader->m_cTableRecordCount;
+
+ UINT32 nHotDataOffset = nIndexMappingTableOffset + cbIndexMappingTableSize;
+ _ASSERTE(pHotTableHeader->m_offsHotData == Align4(nHotDataOffset));
+ }
+ }
+ }
+#endif //_DEBUG
+} // HotTable::CheckTables
+
+}; // namespace MetaData
diff --git a/src/md/hotdata/hottable.h b/src/md/hotdata/hottable.h
new file mode 100644
index 0000000000..361638e3f5
--- /dev/null
+++ b/src/md/hotdata/hottable.h
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: HotTable.h
+//
+
+//
+// Class code:MetaData::HotTable stores hot table records cache, a cache of often-accessed
+// table records stored only in NGEN images.
+// The cache is created using IBC logging.
+//
+// ======================================================================================
+
+#pragma once
+
+#include "external.h"
+
+#include "hotdataformat.h"
+
+namespace MetaData
+{
+
+// --------------------------------------------------------------------------------------
+//
+// This class stores hot table records cache, a cache of often-accessed table records stored only in NGEN
+// images.
+// The cache is created using IBC logging.
+//
+class HotTable
+{
+public:
+ __checkReturn
+ static HRESULT GetData(
+ UINT32 nRowIndex,
+ __deref_out_opt BYTE **ppRecord,
+ UINT32 cbRecordSize,
+ struct HotTableHeader *pHotTableHeader);
+
+ inline static struct HotTableHeader *GetTableHeader(
+ struct HotTablesDirectory *pHotTablesDirectory,
+ UINT32 nTableIndex)
+ {
+ _ASSERTE(pHotTablesDirectory != NULL);
+
+ INT32 nTableOffset = pHotTablesDirectory->m_rgTableHeader_SignedOffset[nTableIndex];
+ _ASSERTE(nTableOffset != 0);
+
+ BYTE *pHotTableHeaderData = ((BYTE *)pHotTablesDirectory) + nTableOffset;
+ return (struct HotTableHeader *)pHotTableHeaderData;
+ }
+
+ static void CheckTables(struct HotTablesDirectory *pHotTablesDirectory);
+
+}; // class HotTable
+
+}; // namespace MetaData