From 1d5e50a24cf06590f6abe18105ca2c1e39aa4fc7 Mon Sep 17 00:00:00 2001 From: Bruce Forstall Date: Sun, 22 Mar 2020 16:50:37 -0700 Subject: [PATCH] Speed up SuperPMI `mcs -removeDup` Create a "Hash" class that encapsulates the MD5 hashing that is used to determine if two MCs are equivalent. Primarily, this allows caching the Windows Crypto provider, which it is very slow to acquire. In addition, make some changes to avoid unnecessary memory allocations and other unnecessary work. The result is that `mcs -removeDup` is about 4x faster. Much of the remaining cost is that we read, deserialize the MC, then reserialize the MC (if unique), and finally destroy the in-memory MC. There is a lot of memory allocation/deallocation in this process that could possibly be avoided or improved for this scenario. --- .../src/ToolBox/superpmi/mcs/CMakeLists.txt | 1 + .../ToolBox/superpmi/mcs/verbremovedup.cpp | 16 +- .../ToolBox/superpmi/superpmi-shared/hash.cpp | 197 ++++++++++++++++++ .../ToolBox/superpmi/superpmi-shared/hash.h | 47 +++++ .../superpmi-shared/methodcontext.cpp | 115 ++++------ .../superpmi/superpmi-shared/methodcontext.h | 11 +- .../superpmi-shim-collector/CMakeLists.txt | 1 + .../superpmi-shim-counter/CMakeLists.txt | 1 + .../superpmi-shim-simple/CMakeLists.txt | 1 + .../ToolBox/superpmi/superpmi/CMakeLists.txt | 1 + 10 files changed, 300 insertions(+), 91 deletions(-) create mode 100644 src/coreclr/src/ToolBox/superpmi/superpmi-shared/hash.cpp create mode 100644 src/coreclr/src/ToolBox/superpmi/superpmi-shared/hash.h diff --git a/src/coreclr/src/ToolBox/superpmi/mcs/CMakeLists.txt b/src/coreclr/src/ToolBox/superpmi/mcs/CMakeLists.txt index b20ab76c77ec1f..4b83b7dda7d728 100644 --- a/src/coreclr/src/ToolBox/superpmi/mcs/CMakeLists.txt +++ b/src/coreclr/src/ToolBox/superpmi/mcs/CMakeLists.txt @@ -31,6 +31,7 @@ set(MCS_SOURCES ../superpmi-shared/callutils.cpp ../superpmi-shared/compileresult.cpp ../superpmi-shared/errorhandling.cpp + ../superpmi-shared/hash.cpp ../superpmi-shared/logging.cpp ../superpmi-shared/mclist.cpp ../superpmi-shared/methodcontext.cpp diff --git a/src/coreclr/src/ToolBox/superpmi/mcs/verbremovedup.cpp b/src/coreclr/src/ToolBox/superpmi/mcs/verbremovedup.cpp index 10a4e6c21f6007..b76621f9583592 100644 --- a/src/coreclr/src/ToolBox/superpmi/mcs/verbremovedup.cpp +++ b/src/coreclr/src/ToolBox/superpmi/mcs/verbremovedup.cpp @@ -25,8 +25,10 @@ bool unique(MethodContext* mc) unsigned newFlags = 0; mc->repCompileMethod(&newInfo, &newFlags); - char* md5Buff = new char[MD5_HASH_BUFFER_SIZE]; - mc->dumpMethodMD5HashToBuffer(md5Buff, MD5_HASH_BUFFER_SIZE, /* ignoreMethodName */ true); + // Assume that there are lots of duplicates, so don't allocate a new buffer for the MD5 hash data + // until we know we're going to add it to the map. + char md5Buff[MD5_HASH_BUFFER_SIZE]; + mc->dumpMethodMD5HashToBuffer(md5Buff, MD5_HASH_BUFFER_SIZE, /* ignoreMethodName */ true, &newInfo, newFlags); if (inFile->GetIndex(newInfo.ILCodeSize) == -1) inFile->Add(newInfo.ILCodeSize, new DenseLightWeightMap()); @@ -36,15 +38,15 @@ bool unique(MethodContext* mc) for (int i = 0; i < (int)ourRank->GetCount(); i++) { char* md5Buff2 = ourRank->Get(i); - if (strncmp(md5Buff, md5Buff2, MD5_HASH_BUFFER_SIZE) == 0) { - delete[] md5Buff; return false; } } - ourRank->Append(md5Buff); + char* newmd5Buff = new char[MD5_HASH_BUFFER_SIZE]; + memcpy(newmd5Buff, md5Buff, MD5_HASH_BUFFER_SIZE); + ourRank->Append(newmd5Buff); return true; } @@ -130,6 +132,8 @@ int verbRemoveDup::DoWork(const char* nameOfInput, const char* nameOfOutput, boo } } + LogInfo("Loaded %d, Saved %d", mci.MethodContextNumber(), savedCount); + // We're leaking 'inFile' or 'inFileLegacy', but the process is going away, so it shouldn't matter. if (CloseHandle(hFileOut) == 0) @@ -138,8 +142,6 @@ int verbRemoveDup::DoWork(const char* nameOfInput, const char* nameOfOutput, boo return -1; } - LogInfo("Loaded %d, Saved %d", mci.MethodContextNumber(), savedCount); - if (!mci.Destroy()) return -1; diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/hash.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/hash.cpp new file mode 100644 index 00000000000000..1312e5aa5ddf61 --- /dev/null +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/hash.cpp @@ -0,0 +1,197 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// hash.cpp - Class for hashing a text stream using MD5 hashing +// +// Note that on Windows, acquiring the Crypto hash provider is expensive, so +// only do that once and cache it. +//---------------------------------------------------------- + +#include "standardpch.h" +#include "runtimedetails.h" +#include "errorhandling.h" +#include "md5.h" +#include "hash.h" + +Hash::Hash() +#ifndef TARGET_UNIX + : m_Initialized(false) + , m_hCryptProv(NULL) +#endif // !TARGET_UNIX +{ +} + +Hash::~Hash() +{ + Destroy(); // Ignoring return code. +} + +// static +bool Hash::Initialize() +{ +#ifdef TARGET_UNIX + + // No initialization necessary. + +#else // !TARGET_UNIX + + if (m_Initialized) + { + LogError("Hash class has already been initialized"); + return false; + } + + // Get handle to the crypto provider + if (!CryptAcquireContextA(&m_hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + goto OnError; + + m_Initialized = true; + return true; + +OnError: + LogError("Failed to create a hash using the Crypto API (Error 0x%X)", GetLastError()); + + if (m_hCryptProv != NULL) + CryptReleaseContext(m_hCryptProv, 0); + + m_Initialized = false; + return false; + +#endif // !TARGET_UNIX +} + +// static +bool Hash::Destroy() +{ +#ifdef TARGET_UNIX + + // No destruction necessary. + +#else // !TARGET_UNIX + + // Should probably check Crypt() function return codes. + if (m_hCryptProv != NULL) + { + CryptReleaseContext(m_hCryptProv, 0); + m_hCryptProv = NULL; + } + + m_Initialized = false; + return true; + +#endif // !TARGET_UNIX +} + +// Hash::WriteHashValueAsText - Take a binary hash value in the array of bytes pointed to by +// 'pHash' (size in bytes 'cbHash'), and write an ASCII hexadecimal representation of it in the buffer +// 'hashTextBuffer' (size in bytes 'hashTextBufferLen'). +// +// Returns true on success, false on failure (only if the arguments are bad). +bool Hash::WriteHashValueAsText(const BYTE* pHash, size_t cbHash, char* hashTextBuffer, size_t hashTextBufferLen) +{ + // This could be: + // + // for (DWORD i = 0; i < MD5_HASH_BYTE_SIZE; i++) + // { + // sprintf_s(hash + i * 2, hashLen - i * 2, "%02X", bHash[i]); + // } + // + // But this function is hot, and sprintf_s is too slow. This is a specialized function to speed it up. + + if (hashTextBufferLen < 2 * cbHash + 1) // 2 characters for each byte, plus null terminator + { + LogError("WriteHashValueAsText doesn't have enough space to write the output"); + return false; + } + + static const char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + char* pCur = hashTextBuffer; + for (size_t i = 0; i < cbHash; i++) + { + unsigned digit = pHash[i]; + unsigned lowNibble = digit & 0xF; + unsigned highNibble = digit >> 4; + *pCur++ = hexDigits[highNibble]; + *pCur++ = hexDigits[lowNibble]; + } + *pCur++ = '\0'; + return true; +} + +// Hash::HashBuffer - Compute an MD5 hash of the data pointed to by 'pBuffer', of 'bufLen' bytes, +// writing the hexadecimal ASCII text representation of the hash to the buffer pointed to by 'hash', +// of 'hashLen' bytes in size, which must be at least MD5_HASH_BUFFER_SIZE bytes. +// +// Returns the number of bytes written, or -1 on error. +int Hash::HashBuffer(BYTE* pBuffer, size_t bufLen, char* hash, size_t hashLen) +{ +#ifdef TARGET_UNIX + + MD5HASHDATA md5_hashdata; + MD5 md5_hasher; + + if (hashLen < MD5_HASH_BUFFER_SIZE) + return -1; + + md5_hasher.Hash(pBuffer, (ULONG)bufLen, &md5_hashdata); + + DWORD md5_hashdata_size = sizeof(md5_hashdata.rgb) / sizeof(BYTE); + Assert(md5_hashdata_size == MD5_HASH_BYTE_SIZE); + + if (!WriteHashValueAsText(md5_hashdata.rgb, md5_hashdata_size, hash, hashLen)) + return -1; + + return MD5_HASH_BUFFER_SIZE; // if we had success we wrote MD5_HASH_BUFFER_SIZE bytes to the buffer + +#else // !TARGET_UNIX + + if (!m_Initialized) + { + LogError("Hash class not initialized"); + return -1; + } + + HCRYPTHASH hCryptHash; + BYTE bHash[MD5_HASH_BYTE_SIZE]; + DWORD cbHash = MD5_HASH_BYTE_SIZE; + + if (hashLen < MD5_HASH_BUFFER_SIZE) + return -1; + + if (!CryptCreateHash(m_hCryptProv, CALG_MD5, 0, 0, &hCryptHash)) + goto OnError; + + if (!CryptHashData(hCryptHash, pBuffer, (DWORD)bufLen, 0)) + goto OnError; + + if (!CryptGetHashParam(hCryptHash, HP_HASHVAL, bHash, &cbHash, 0)) + goto OnError; + + if (cbHash != MD5_HASH_BYTE_SIZE) + goto OnError; + + if (!WriteHashValueAsText(bHash, cbHash, hash, hashLen)) + return -1; + + // Clean up. + CryptDestroyHash(hCryptHash); + hCryptHash = NULL; + + return MD5_HASH_BUFFER_SIZE; // if we had success we wrote MD5_HASH_BUFFER_SIZE bytes to the buffer + +OnError: + LogError("Failed to create a hash using the Crypto API (Error 0x%X)", GetLastError()); + + if (hCryptHash != NULL) + { + CryptDestroyHash(hCryptHash); + hCryptHash = NULL; + } + + return -1; + +#endif // !TARGET_UNIX +} diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/hash.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/hash.h new file mode 100644 index 00000000000000..8db50cdcaa8d9c --- /dev/null +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/hash.h @@ -0,0 +1,47 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// hash.h - Class for hashing a text stream using MD5 hashing +//---------------------------------------------------------- +#ifndef _hash +#define _hash + +#define MD5_HASH_BYTE_SIZE 16 // MD5 is 128-bit, so we need 16 bytes to store it +#define MD5_HASH_BUFFER_SIZE 33 // MD5 is 128-bit, so we need 32 chars + 1 char to store null-terminator + +class Hash +{ +public: + + Hash(); + ~Hash(); + + bool Initialize(); + bool Destroy(); + + bool IsInitialized() + { +#ifdef TARGET_UNIX + return true; // No initialization necessary. +#else // TARGET_UNIX + return m_Initialized; +#endif // !TARGET_UNIX + + } + + int HashBuffer(BYTE* pBuffer, size_t bufLen, char* hash, size_t hashLen); + +private: + + bool WriteHashValueAsText(const BYTE* pHash, size_t cbHash, char* hashTextBuffer, size_t hashTextBufferLen); + +#ifndef TARGET_UNIX + bool m_Initialized; + HCRYPTPROV m_hCryptProv; +#endif // !TARGET_UNIX +}; + +#endif diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp index c4a9f4745cd13c..8eb53dcca7e7e7 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp @@ -9,7 +9,6 @@ //---------------------------------------------------------- #include "standardpch.h" -#include "md5.h" #include "methodcontext.h" #include "compileresult.h" #include "lightweightmap.h" @@ -36,6 +35,9 @@ #define DEBUG_REP(x) #endif +// static variable initialization +Hash MethodContext::m_hash; + MethodContext::MethodContext() { methodSize = 0; @@ -288,7 +290,7 @@ void MethodContext::MethodInitHelper(unsigned char* buff2, unsigned int totalLen { mcPackets packetType = (mcPackets)buff2[buffIndex++]; memcpy(&localsize, &buff2[buffIndex], sizeof(unsigned int)); - buffIndex += 4; + buffIndex += sizeof(unsigned int); switch (packetType) { @@ -6195,44 +6197,56 @@ const WCHAR* MethodContext::repGetStringConfigValue(const WCHAR* name) return value; } -int MethodContext::dumpMethodIdentityInfoToBuffer(char* buff, int len, bool ignoreMethodName /* = false */) +int MethodContext::dumpMethodIdentityInfoToBuffer(char* buff, int len, bool ignoreMethodName /* = false */, CORINFO_METHOD_INFO* optInfo /* = nullptr */, unsigned optFlags /* = 0 */) { - char* obuff = buff; - if (len < METHOD_IDENTITY_INFO_SIZE) return -1; // Obtain the Method Info structure for this method - CORINFO_METHOD_INFO info; - unsigned flags = 0; + CORINFO_METHOD_INFO info; + CORINFO_METHOD_INFO* pInfo = nullptr; + unsigned flags = 0; + + if (optInfo != nullptr) + { + // Use the info we've already retrieved from repCompileMethod(). + pInfo = optInfo; + flags = optFlags; + } + else + { + repCompileMethod(&info, &flags); + pInfo = &info; + } - repCompileMethod(&info, &flags); + char* obuff = buff; // Add the Method Signature - int t = sprintf_s(buff, len, "%s -- ", CallUtils::GetMethodFullName(this, info.ftn, info.args, ignoreMethodName)); + int t = sprintf_s(buff, len, "%s -- ", CallUtils::GetMethodFullName(this, pInfo->ftn, pInfo->args, ignoreMethodName)); buff += t; len -= t; // Add Calling convention information, CorInfoOptions and CorInfoRegionKind - t = sprintf_s(buff, len, "CallingConvention: %d, CorInfoOptions: %d, CorInfoRegionKind: %d ", info.args.callConv, - info.options, info.regionKind); + t = sprintf_s(buff, len, "CallingConvention: %d, CorInfoOptions: %d, CorInfoRegionKind: %d ", pInfo->args.callConv, + pInfo->options, pInfo->regionKind); buff += t; len -= t; // Hash the IL Code for this method and append it to the ID info char ilHash[MD5_HASH_BUFFER_SIZE]; - dumpMD5HashToBuffer(info.ILCode, info.ILCodeSize, ilHash, MD5_HASH_BUFFER_SIZE); + dumpMD5HashToBuffer(pInfo->ILCode, pInfo->ILCodeSize, ilHash, MD5_HASH_BUFFER_SIZE); t = sprintf_s(buff, len, "ILCode Hash: %s", ilHash); buff += t; len -= t; return (int)(buff - obuff); } -int MethodContext::dumpMethodMD5HashToBuffer(char* buff, int len, bool ignoreMethodName /* = false */) + +int MethodContext::dumpMethodMD5HashToBuffer(char* buff, int len, bool ignoreMethodName /* = false */, CORINFO_METHOD_INFO* optInfo /* = nullptr */, unsigned optFlags /* = 0 */) { char bufferIdentityInfo[METHOD_IDENTITY_INFO_SIZE]; - int cbLen = dumpMethodIdentityInfoToBuffer(bufferIdentityInfo, METHOD_IDENTITY_INFO_SIZE, ignoreMethodName); + int cbLen = dumpMethodIdentityInfoToBuffer(bufferIdentityInfo, METHOD_IDENTITY_INFO_SIZE, ignoreMethodName, optInfo, optFlags); if (cbLen < 0) return cbLen; @@ -6244,74 +6258,17 @@ int MethodContext::dumpMethodMD5HashToBuffer(char* buff, int len, bool ignoreMet int MethodContext::dumpMD5HashToBuffer(BYTE* pBuffer, int bufLen, char* hash, int hashLen) { -#ifdef TARGET_UNIX - - MD5HASHDATA md5_hashdata; - MD5 md5_hasher; - - if (hashLen < MD5_HASH_BUFFER_SIZE) - return -1; - - md5_hasher.Hash(pBuffer, (ULONG)bufLen, &md5_hashdata); - - DWORD md5_hashdata_size = sizeof(md5_hashdata.rgb) / sizeof(BYTE); - Assert(md5_hashdata_size == MD5_HASH_BYTE_SIZE); - - for (DWORD i = 0; i < md5_hashdata_size; i++) - { - sprintf_s(hash + i * 2, hashLen - i * 2, "%02X", md5_hashdata.rgb[i]); - } - - return MD5_HASH_BUFFER_SIZE; // if we had success we wrote MD5_HASH_BUFFER_SIZE bytes to the buffer - -#else // !TARGET_UNIX - - HCRYPTPROV hProv = NULL; // CryptoProvider - HCRYPTHASH hHash = NULL; - BYTE bHash[MD5_HASH_BYTE_SIZE]; - DWORD cbHash = MD5_HASH_BYTE_SIZE; - - if (hashLen < MD5_HASH_BUFFER_SIZE) - return -1; - - // Get handle to the crypto provider - if (!CryptAcquireContextA(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) - goto OnError; - - if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) - goto OnError; - - if (!CryptHashData(hHash, pBuffer, bufLen, 0)) - goto OnError; - - if (!CryptGetHashParam(hHash, HP_HASHVAL, bHash, &cbHash, 0)) - goto OnError; - - if (cbHash != MD5_HASH_BYTE_SIZE) - goto OnError; - - for (DWORD i = 0; i < MD5_HASH_BYTE_SIZE; i++) + // Lazy initialize the MD5 hasher. + if (!m_hash.IsInitialized()) { - sprintf_s(hash + i * 2, hashLen - i * 2, "%02X", bHash[i]); + if (!m_hash.Initialize()) + { + AssertMsg(false, "Failed to initialize the MD5 hasher"); + return -1; + } } - if (hHash != NULL) - CryptDestroyHash(hHash); - if (hProv != NULL) - CryptReleaseContext(hProv, 0); - - return MD5_HASH_BUFFER_SIZE; // if we had success we wrote MD5_HASH_BUFFER_SIZE bytes to the buffer - -OnError: - AssertMsg(false, "Failed to create a hash using the Crypto API (Error %X)", GetLastError()); - - if (hHash != NULL) - CryptDestroyHash(hHash); - if (hProv != NULL) - CryptReleaseContext(hProv, 0); - return -1; - -#endif // !TARGET_UNIX + return m_hash.HashBuffer(pBuffer, bufLen, hash, hashLen); } MethodContext::Environment MethodContext::cloneEnvironment() diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h index 5e2454d60affee..35e12b485ee674 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h @@ -14,12 +14,10 @@ #include "compileresult.h" #include "lightweightmap.h" #include "errorhandling.h" +#include "hash.h" #define METHOD_IDENTITY_INFO_SIZE 0x10000 // We assume that the METHOD_IDENTITY_INFO_SIZE will not exceed 64KB -#define MD5_HASH_BYTE_SIZE 16 // MD5 is 128-bit, so we need 16 bytes to store it -#define MD5_HASH_BUFFER_SIZE 33 // MD5 is 128-bit, so we need 32 chars + 1 char to store null-terminator - class MethodContext { public: @@ -583,8 +581,8 @@ class MethodContext static int dumpStatTitleToBuffer(char* buff, int len); int methodSize; - int dumpMethodIdentityInfoToBuffer(char* buff, int len, bool ignoreMethodName = false); - int dumpMethodMD5HashToBuffer(char* buff, int len, bool ignoreMethodName = false); + int dumpMethodIdentityInfoToBuffer(char* buff, int len, bool ignoreMethodName = false, CORINFO_METHOD_INFO* optInfo = nullptr, unsigned optFlags = 0); + int dumpMethodMD5HashToBuffer(char* buff, int len, bool ignoreMethodName = false, CORINFO_METHOD_INFO* optInfo = nullptr, unsigned optFlags = 0); void recGlobalContext(const MethodContext& other); @@ -1315,6 +1313,9 @@ class MethodContext #define LWM(map, key, value) LightWeightMap* map; #define DENSELWM(map, value) DenseLightWeightMap* map; #include "lwmlist.h" + + // MD5 hasher + static Hash m_hash; }; // ********************* Please keep this up-to-date to ease adding more *************** diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/CMakeLists.txt b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/CMakeLists.txt index f67eedda48b694..5c7310f4e91e81 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/CMakeLists.txt +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/CMakeLists.txt @@ -22,6 +22,7 @@ set(SUPERPMI_SHIM_COLLECTOR_SOURCES ../superpmi-shared/callutils.cpp ../superpmi-shared/compileresult.cpp ../superpmi-shared/errorhandling.cpp + ../superpmi-shared/hash.cpp ../superpmi-shared/logging.cpp ../superpmi-shared/mclist.cpp ../superpmi-shared/methodcontext.cpp diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/CMakeLists.txt b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/CMakeLists.txt index 65ed573279f93a..d3d9a527867787 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/CMakeLists.txt +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/CMakeLists.txt @@ -23,6 +23,7 @@ set(SUPERPMI_SHIM_COUNTER_SOURCES ../superpmi-shared/callutils.cpp ../superpmi-shared/compileresult.cpp ../superpmi-shared/errorhandling.cpp + ../superpmi-shared/hash.cpp ../superpmi-shared/logging.cpp ../superpmi-shared/mclist.cpp ../superpmi-shared/methodcontext.cpp diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/CMakeLists.txt b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/CMakeLists.txt index aaa41d43760171..cb4caded38d0dd 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/CMakeLists.txt +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/CMakeLists.txt @@ -22,6 +22,7 @@ set(SUPERPMI_SHIM_SIMPLE_SOURCES ../superpmi-shared/callutils.cpp ../superpmi-shared/compileresult.cpp ../superpmi-shared/errorhandling.cpp + ../superpmi-shared/hash.cpp ../superpmi-shared/logging.cpp ../superpmi-shared/mclist.cpp ../superpmi-shared/methodcontext.cpp diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi/CMakeLists.txt b/src/coreclr/src/ToolBox/superpmi/superpmi/CMakeLists.txt index 86992d950c06de..adc3cde6a17882 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi/CMakeLists.txt +++ b/src/coreclr/src/ToolBox/superpmi/superpmi/CMakeLists.txt @@ -29,6 +29,7 @@ set(SUPERPMI_SOURCES ../superpmi-shared/callutils.cpp ../superpmi-shared/compileresult.cpp ../superpmi-shared/errorhandling.cpp + ../superpmi-shared/hash.cpp ../superpmi-shared/logging.cpp ../superpmi-shared/mclist.cpp ../superpmi-shared/methodcontext.cpp