diff options
author | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
---|---|---|
committer | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
commit | ef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch) | |
tree | dee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/md/hotdata | |
download | coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2 coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip |
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/md/hotdata')
31 files changed, 1608 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..8ce023f575 --- /dev/null +++ b/src/md/hotdata/CMakeLists.txt @@ -0,0 +1,20 @@ + +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) +if(WIN32) + add_subdirectory(full-staticcrt) +endif(WIN32)
\ No newline at end of file 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/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..9f37472641 --- /dev/null +++ b/src/md/hotdata/dac/CMakeLists.txt @@ -0,0 +1,4 @@ + +include(${CLR_DIR}/dac.cmake) + +add_library(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..c27a959ec6 --- /dev/null +++ b/src/md/hotdata/export.h @@ -0,0 +1,26 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..48194d7392 --- /dev/null +++ b/src/md/hotdata/external.cpp @@ -0,0 +1,14 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..64836e5080 --- /dev/null +++ b/src/md/hotdata/external.h @@ -0,0 +1,21 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..dd7488f768 --- /dev/null +++ b/src/md/hotdata/full-staticcrt/CMakeLists.txt @@ -0,0 +1,2 @@ +add_definitions(-D_CRTIMP=) # static link of crt +add_library(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..688dfbee9a --- /dev/null +++ b/src/md/hotdata/full/CMakeLists.txt @@ -0,0 +1 @@ +add_library(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..88591374af --- /dev/null +++ b/src/md/hotdata/heapindex.h @@ -0,0 +1,69 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..d61ff11683 --- /dev/null +++ b/src/md/hotdata/hotdataformat.h @@ -0,0 +1,156 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..4830a42d38 --- /dev/null +++ b/src/md/hotdata/hotheap.cpp @@ -0,0 +1,186 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..cc59c8a175 --- /dev/null +++ b/src/md/hotdata/hotheap.h @@ -0,0 +1,68 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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, + __in 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..7d408c4c25 --- /dev/null +++ b/src/md/hotdata/hotheapsdirectoryiterator.cpp @@ -0,0 +1,111 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..ee9d97220b --- /dev/null +++ b/src/md/hotdata/hotheapsdirectoryiterator.h @@ -0,0 +1,72 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..00d4285b68 --- /dev/null +++ b/src/md/hotdata/hotheapwriter.cpp @@ -0,0 +1,306 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..fe0739a9aa --- /dev/null +++ b/src/md/hotdata/hotheapwriter.h @@ -0,0 +1,85 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..4cdb3f709a --- /dev/null +++ b/src/md/hotdata/hotmetadata.cpp @@ -0,0 +1,86 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..dc8330a18c --- /dev/null +++ b/src/md/hotdata/hotmetadata.h @@ -0,0 +1,44 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..a110445d24 --- /dev/null +++ b/src/md/hotdata/hottable.cpp @@ -0,0 +1,139 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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..226ab0e178 --- /dev/null +++ b/src/md/hotdata/hottable.h @@ -0,0 +1,58 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license 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 |