summaryrefslogtreecommitdiff
path: root/src/inc/utilcode.h
diff options
context:
space:
mode:
authorJiyoung Yun <jy910.yun@samsung.com>2016-11-23 19:09:09 +0900
committerJiyoung Yun <jy910.yun@samsung.com>2016-11-23 19:09:09 +0900
commit4b4aad7217d3292650e77eec2cf4c198ea9c3b4b (patch)
tree98110734c91668dfdbb126fcc0e15ddbd93738ca /src/inc/utilcode.h
parentfa45f57ed55137c75ac870356a1b8f76c84b229c (diff)
downloadcoreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.gz
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.bz2
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.zip
Imported Upstream version 1.1.0upstream/1.1.0
Diffstat (limited to 'src/inc/utilcode.h')
-rw-r--r--src/inc/utilcode.h5753
1 files changed, 5753 insertions, 0 deletions
diff --git a/src/inc/utilcode.h b/src/inc/utilcode.h
new file mode 100644
index 0000000000..c519e8b872
--- /dev/null
+++ b/src/inc/utilcode.h
@@ -0,0 +1,5753 @@
+// 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.
+//*****************************************************************************
+// UtilCode.h
+//
+// Utility functions implemented in UtilCode.lib.
+//
+//*****************************************************************************
+
+#ifndef __UtilCode_h__
+#define __UtilCode_h__
+
+#include "crtwrap.h"
+#include "winwrap.h"
+#include <wchar.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ole2.h>
+#include <oleauto.h>
+#include <limits.h>
+#include "clrtypes.h"
+#include "safewrap.h"
+#include "volatile.h"
+#include <daccess.h>
+#include "clrhost.h"
+#include "debugmacros.h"
+#include "corhlprpriv.h"
+#include "winnls.h"
+#include "check.h"
+#include "safemath.h"
+#include "new.hpp"
+
+#ifdef PAL_STDCPP_COMPAT
+#include <type_traits>
+#else
+#include "clr_std/type_traits"
+#endif
+
+#include "contract.h"
+#include "entrypoints.h"
+
+#include "clrnt.h"
+
+// Values for the names of Watson
+const WCHAR kWatsonName1[] = W("drwatson");
+const WCHAR kWatsonName2[] = W("drwtsn32");
+
+#include "random.h"
+
+#define WINDOWS_KERNEL32_DLLNAME_A "kernel32"
+#define WINDOWS_KERNEL32_DLLNAME_W W("kernel32")
+
+#if defined(FEATURE_CORECLR)
+#define CoreLibName_W W("System.Private.CoreLib")
+#define CoreLibName_IL_W W("System.Private.CoreLib.dll")
+#define CoreLibName_NI_W W("System.Private.CoreLib.ni.dll")
+#define CoreLibName_TLB_W W("System.Private.CoreLib.tlb")
+#define CoreLibName_A "System.Private.CoreLib"
+#define CoreLibName_IL_A "System.Private.CoreLib.dll"
+#define CoreLibName_NI_A "System.Private.CoreLib.ni.dll"
+#define CoreLibName_TLB_A "System.Private.CoreLib.tlb"
+#define CoreLibNameLen 22
+#define CoreLibSatelliteName_A "System.Private.CoreLib.resources"
+#define CoreLibSatelliteNameLen 32
+#define LegacyCoreLibName_A "mscorlib"
+#else // !defined(FEATURE_CORECLR)
+#define CoreLibName_W W("mscorlib")
+#define CoreLibName_IL_W W("mscorlib.dll")
+#define CoreLibName_NI_W W("mscorlib.ni.dll")
+#define CoreLibName_TLB_W W("mscorlib.tlb")
+#define CoreLibName_A "mscorlib"
+#define CoreLibName_IL_A "mscorlib.dll"
+#define CoreLibName_NI_A "mscorlib.ni.dll"
+#define CoreLibName_TLB_A "mscorlib.tlb"
+#define CoreLibNameLen 8
+#define CoreLibSatelliteName_A "mscorlib.resources"
+#define CoreLibSatelliteNameLen 18
+#define LegacyCoreLibName_A "mscorlib"
+#endif // defined(FEATURE_CORECLR)
+
+class StringArrayList;
+
+#if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE)
+#define _DEBUG_IMPL 1
+#endif
+
+#ifdef _TARGET_ARM_
+
+// Under ARM we generate code only with Thumb encoding. In order to ensure we execute such code in the correct
+// mode we must ensure the low-order bit is set in any code address we'll call as a sub-routine. In C++ this
+// is handled automatically for us by the compiler. When generating and working with code generated
+// dynamically we have to be careful to set or mask-out this bit as appropriate.
+#ifndef THUMB_CODE
+#define THUMB_CODE 1
+#endif
+
+// Given a WORD extract the bitfield [lowbit, highbit] (i.e. BitExtract(0xffff, 15, 0) == 0xffff).
+inline WORD BitExtract(WORD wValue, DWORD highbit, DWORD lowbit)
+{
+ _ASSERTE((highbit < 16) && (lowbit < 16) && (highbit >= lowbit));
+ return (wValue >> lowbit) & ((1 << ((highbit - lowbit) + 1)) - 1);
+}
+
+// Determine whether an ARM Thumb mode instruction is 32-bit or 16-bit based on the first WORD of the
+// instruction.
+inline bool Is32BitInstruction(WORD opcode)
+{
+ return BitExtract(opcode, 15, 11) >= 0x1d;
+}
+
+template <typename ResultType, typename SourceType>
+inline ResultType DataPointerToThumbCode(SourceType pCode)
+{
+ return (ResultType)(((UINT_PTR)pCode) | THUMB_CODE);
+}
+
+template <typename ResultType, typename SourceType>
+inline ResultType ThumbCodeToDataPointer(SourceType pCode)
+{
+ return (ResultType)(((UINT_PTR)pCode) & ~THUMB_CODE);
+}
+
+#endif // _TARGET_ARM_
+
+// Convert from a PCODE to the corresponding PINSTR. On many architectures this will be the identity function;
+// on ARM, this will mask off the THUMB bit.
+inline TADDR PCODEToPINSTR(PCODE pc)
+{
+#ifdef _TARGET_ARM_
+ return ThumbCodeToDataPointer<TADDR,PCODE>(pc);
+#else
+ return dac_cast<PCODE>(pc);
+#endif
+}
+
+typedef LPCSTR LPCUTF8;
+typedef LPSTR LPUTF8;
+
+#include "nsutilpriv.h"
+
+#include "stdmacros.h"
+
+/*
+// This is for WinCE
+#ifdef VERIFY
+#undef VERIFY
+#endif
+
+#ifdef _ASSERTE
+#undef _ASSERTE
+#endif
+*/
+
+//********** Macros. **********************************************************
+#ifndef FORCEINLINE
+ #if _MSC_VER < 1200
+ #define FORCEINLINE inline
+ #else
+ #define FORCEINLINE __forceinline
+ #endif
+#endif
+
+#ifndef DEBUG_NOINLINE
+#if defined(_DEBUG)
+#define DEBUG_NOINLINE __declspec(noinline)
+#else
+#define DEBUG_NOINLINE
+#endif
+#endif
+
+#ifndef DBG_NOINLINE_X86__RET_INLINE
+#if defined(_DEBUG) && defined(_TARGET_X86_)
+// this exists to make scan work on x86.
+#define DBG_NOINLINE_X86__RET_INLINE __declspec(noinline)
+#else
+#define DBG_NOINLINE_X86__RET_INLINE FORCEINLINE
+#endif
+#endif
+
+#include <stddef.h> // for offsetof
+
+#ifndef NumItems
+// Number of elements in a fixed-size array
+#define NumItems(s) (sizeof(s) / sizeof(s[0]))
+#endif
+
+#ifndef StrLen
+// Number of characters in a string literal. Excludes terminating NULL.
+#define StrLen(str) (NumItems(str) - 1)
+#endif
+
+
+#define IS_DIGIT(ch) ((ch >= W('0')) && (ch <= W('9')))
+#define DIGIT_TO_INT(ch) (ch - W('0'))
+#define INT_TO_DIGIT(i) ((WCHAR)(W('0') + i))
+
+#define IS_HEXDIGIT(ch) (((ch >= W('a')) && (ch <= W('f'))) || \
+ ((ch >= W('A')) && (ch <= W('F'))))
+#define HEXDIGIT_TO_INT(ch) ((towlower(ch) - W('a')) + 10)
+#define INT_TO_HEXDIGIT(i) ((WCHAR)(W('a') + (i - 10)))
+
+
+// Helper will 4 byte align a value, rounding up.
+#define ALIGN4BYTE(val) (((val) + 3) & ~0x3)
+
+#ifdef _DEBUG
+#define DEBUGARG(x) , x
+#else
+#define DEBUGARG(x)
+#endif
+
+#ifndef sizeofmember
+// Returns the size of a class or struct member.
+#define sizeofmember(c,m) (sizeof(((c*)0)->m))
+#endif
+
+//=--------------------------------------------------------------------------=
+// Prefast helpers.
+//
+
+#include "safemath.h"
+
+
+//=--------------------------------------------------------------------------=
+// string helpers.
+
+//
+// given and ANSI String, copy it into a wide buffer.
+// be careful about scoping when using this macro!
+//
+// how to use the below two macros:
+//
+// ...
+// LPSTR pszA;
+// pszA = MyGetAnsiStringRoutine();
+// MAKE_WIDEPTR_FROMANSI(pwsz, pszA);
+// MyUseWideStringRoutine(pwsz);
+// ...
+//
+// similarily for MAKE_ANSIPTR_FROMWIDE. note that the first param does not
+// have to be declared, and no clean up must be done.
+//
+
+// We'll define an upper limit that allows multiplication by 4 (the max
+// bytes/char in UTF-8) but still remains positive, and allows some room for pad.
+// Under normal circumstances, we should never get anywhere near this limit.
+#define MAKE_MAX_LENGTH 0x1fffff00
+
+#ifndef MAKE_TOOLONGACTION
+#define MAKE_TOOLONGACTION ThrowHR(COR_E_OVERFLOW)
+#endif
+
+#ifndef MAKE_TRANSLATIONFAILED
+#define MAKE_TRANSLATIONFAILED ThrowWin32(ERROR_NO_UNICODE_TRANSLATION)
+#endif
+
+// This version throws on conversion errors (ie, no best fit character
+// mapping to characters that look similar, and no use of the default char
+// ('?') when printing out unrepresentable characters. Use this method for
+// most development in the EE, especially anything like metadata or class
+// names. See the BESTFIT version if you're printing out info to the console.
+#define MAKE_MULTIBYTE_FROMWIDE(ptrname, widestr, codepage) \
+ int __l##ptrname = (int)wcslen(widestr); \
+ if (__l##ptrname > MAKE_MAX_LENGTH) \
+ MAKE_TOOLONGACTION; \
+ __l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
+ CQuickBytes __CQuickBytes##ptrname; \
+ __CQuickBytes##ptrname.AllocThrows(__l##ptrname); \
+ BOOL __b##ptrname; \
+ DWORD __cBytes##ptrname = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, -1, (LPSTR)__CQuickBytes##ptrname.Ptr(), __l##ptrname, NULL, &__b##ptrname); \
+ if (__b##ptrname || (__cBytes##ptrname == 0 && (widestr[0] != W('\0')))) { \
+ MAKE_TRANSLATIONFAILED; \
+ } \
+ LPSTR ptrname = (LPSTR)__CQuickBytes##ptrname.Ptr()
+
+// This version does best fit character mapping and also allows the use
+// of the default char ('?') for any Unicode character that isn't
+// representable. This is reasonable for writing to the console, but
+// shouldn't be used for most string conversions.
+#define MAKE_MULTIBYTE_FROMWIDE_BESTFIT(ptrname, widestr, codepage) \
+ int __l##ptrname = (int)wcslen(widestr); \
+ if (__l##ptrname > MAKE_MAX_LENGTH) \
+ MAKE_TOOLONGACTION; \
+ __l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
+ CQuickBytes __CQuickBytes##ptrname; \
+ __CQuickBytes##ptrname.AllocThrows(__l##ptrname); \
+ DWORD __cBytes##ptrname = WszWideCharToMultiByte(codepage, 0, widestr, -1, (LPSTR)__CQuickBytes##ptrname.Ptr(), __l##ptrname, NULL, NULL); \
+ if (__cBytes##ptrname == 0 && __l##ptrname != 0) { \
+ MAKE_TRANSLATIONFAILED; \
+ } \
+ LPSTR ptrname = (LPSTR)__CQuickBytes##ptrname.Ptr()
+
+// Use for anything critical other than output to console, where weird
+// character mappings are unacceptable.
+#define MAKE_ANSIPTR_FROMWIDE(ptrname, widestr) MAKE_MULTIBYTE_FROMWIDE(ptrname, widestr, CP_ACP)
+
+// Use for output to the console.
+#define MAKE_ANSIPTR_FROMWIDE_BESTFIT(ptrname, widestr) MAKE_MULTIBYTE_FROMWIDE_BESTFIT(ptrname, widestr, CP_ACP)
+
+#define MAKE_WIDEPTR_FROMANSI(ptrname, ansistr) \
+ CQuickBytes __qb##ptrname; \
+ int __l##ptrname; \
+ __l##ptrname = WszMultiByteToWideChar(CP_ACP, 0, ansistr, -1, 0, 0); \
+ if (__l##ptrname > MAKE_MAX_LENGTH) \
+ MAKE_TOOLONGACTION; \
+ LPWSTR ptrname = (LPWSTR) __qb##ptrname.AllocThrows((__l##ptrname+1)*sizeof(WCHAR)); \
+ if (WszMultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, ansistr, -1, ptrname, __l##ptrname) == 0) { \
+ MAKE_TRANSLATIONFAILED; \
+ }
+
+#define MAKE_WIDEPTR_FROMANSI_NOTHROW(ptrname, ansistr) \
+ CQuickBytes __qb##ptrname; \
+ LPWSTR ptrname = 0; \
+ int __l##ptrname; \
+ __l##ptrname = WszMultiByteToWideChar(CP_ACP, 0, ansistr, -1, 0, 0); \
+ if (__l##ptrname <= MAKE_MAX_LENGTH) { \
+ ptrname = (LPWSTR) __qb##ptrname.AllocNoThrow((__l##ptrname+1)*sizeof(WCHAR)); \
+ if (ptrname) { \
+ if (WszMultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, ansistr, -1, ptrname, __l##ptrname) != 0) { \
+ ptrname[__l##ptrname] = 0; \
+ } else { \
+ ptrname = 0; \
+ } \
+ } \
+ }
+
+#define MAKE_UTF8PTR_FROMWIDE(ptrname, widestr) CQuickBytes _##ptrname; _##ptrname.ConvertUnicode_Utf8(widestr); LPSTR ptrname = (LPSTR) _##ptrname.Ptr();
+
+#define MAKE_UTF8PTR_FROMWIDE_NOTHROW(ptrname, widestr) \
+ CQuickBytes __qb##ptrname; \
+ int __l##ptrname = (int)wcslen(widestr); \
+ LPUTF8 ptrname = 0; \
+ if (__l##ptrname <= MAKE_MAX_LENGTH) { \
+ __l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
+ ptrname = (LPUTF8) __qb##ptrname.AllocNoThrow(__l##ptrname); \
+ } \
+ if (ptrname) { \
+ INT32 __lresult##ptrname=WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, ptrname, __l##ptrname-1, NULL, NULL); \
+ DWORD __dwCaptureLastError##ptrname = ::GetLastError(); \
+ if ((__lresult##ptrname==0) && (((LPCWSTR)widestr)[0] != W('\0'))) { \
+ if (__dwCaptureLastError##ptrname==ERROR_INSUFFICIENT_BUFFER) { \
+ INT32 __lsize##ptrname=WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, NULL, 0, NULL, NULL); \
+ ptrname = (LPSTR) __qb##ptrname .AllocNoThrow(__lsize##ptrname); \
+ if (ptrname) { \
+ if (WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, ptrname, __lsize##ptrname, NULL, NULL) != 0) { \
+ ptrname[__l##ptrname] = 0; \
+ } else { \
+ ptrname = 0; \
+ } \
+ } \
+ } \
+ else { \
+ ptrname = 0; \
+ } \
+ } \
+ } \
+
+#define MAKE_WIDEPTR_FROMUTF8N(ptrname, utf8str, n8chrs) \
+ CQuickBytes __qb##ptrname; \
+ int __l##ptrname; \
+ __l##ptrname = WszMultiByteToWideChar(CP_UTF8, 0, utf8str, n8chrs, 0, 0); \
+ if (__l##ptrname > MAKE_MAX_LENGTH) \
+ MAKE_TOOLONGACTION; \
+ LPWSTR ptrname = (LPWSTR) __qb##ptrname .AllocThrows((__l##ptrname+1)*sizeof(WCHAR)); \
+ if (0==WszMultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8str, n8chrs, ptrname, __l##ptrname)) { \
+ MAKE_TRANSLATIONFAILED; \
+ } \
+ ptrname[__l##ptrname] = 0;
+
+
+#define MAKE_WIDEPTR_FROMUTF8(ptrname, utf8str) CQuickBytes _##ptrname; _##ptrname.ConvertUtf8_Unicode(utf8str); LPCWSTR ptrname = (LPCWSTR) _##ptrname.Ptr();
+
+
+#define MAKE_WIDEPTR_FROMUTF8N_NOTHROW(ptrname, utf8str, n8chrs) \
+ CQuickBytes __qb##ptrname; \
+ int __l##ptrname; \
+ LPWSTR ptrname = 0; \
+ __l##ptrname = WszMultiByteToWideChar(CP_UTF8, 0, utf8str, n8chrs, 0, 0); \
+ if (__l##ptrname <= MAKE_MAX_LENGTH) { \
+ ptrname = (LPWSTR) __qb##ptrname.AllocNoThrow((__l##ptrname+1)*sizeof(WCHAR)); \
+ if (ptrname) { \
+ if (WszMultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8str, n8chrs, ptrname, __l##ptrname) != 0) { \
+ ptrname[__l##ptrname] = 0; \
+ } else { \
+ ptrname = 0; \
+ } \
+ } \
+ }
+
+#define MAKE_WIDEPTR_FROMUTF8_NOTHROW(ptrname, utf8str) MAKE_WIDEPTR_FROMUTF8N_NOTHROW(ptrname, utf8str, -1)
+
+// This method takes the number of characters
+#define MAKE_MULTIBYTE_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt, codepage) \
+ CQuickBytes __qb##ptrname; \
+ int __l##ptrname; \
+ __l##ptrname = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, _nCharacters, NULL, 0, NULL, NULL); \
+ if (__l##ptrname > MAKE_MAX_LENGTH) \
+ MAKE_TOOLONGACTION; \
+ ptrname = (LPUTF8) __qb##ptrname .AllocThrows(__l##ptrname+1); \
+ BOOL __b##ptrname; \
+ DWORD _pCnt = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, _nCharacters, ptrname, __l##ptrname, NULL, &__b##ptrname); \
+ if (__b##ptrname || (_pCnt == 0 && _nCharacters > 0)) { \
+ MAKE_TRANSLATIONFAILED; \
+ } \
+ ptrname[__l##ptrname] = 0;
+
+#define MAKE_MULTIBYTE_FROMWIDEN_BESTFIT(ptrname, widestr, _nCharacters, _pCnt, codepage) \
+ CQuickBytes __qb##ptrname; \
+ int __l##ptrname; \
+ __l##ptrname = WszWideCharToMultiByte(codepage, 0, widestr, _nCharacters, NULL, 0, NULL, NULL); \
+ if (__l##ptrname > MAKE_MAX_LENGTH) \
+ MAKE_TOOLONGACTION; \
+ ptrname = (LPUTF8) __qb##ptrname .AllocThrows(__l##ptrname+1); \
+ DWORD _pCnt = WszWideCharToMultiByte(codepage, 0, widestr, _nCharacters, ptrname, __l##ptrname, NULL, NULL); \
+ if (_pCnt == 0 && _nCharacters > 0) { \
+ MAKE_TRANSLATIONFAILED; \
+ } \
+ ptrname[__l##ptrname] = 0;
+
+#define MAKE_ANSIPTR_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt) \
+ MAKE_MULTIBYTE_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt, CP_ACP)
+
+
+inline
+LPWSTR DuplicateString(
+ LPCWSTR wszString,
+ size_t cchString)
+{
+ STATIC_CONTRACT_NOTHROW;
+
+ LPWSTR wszDup = NULL;
+ if (wszString != NULL)
+ {
+ wszDup = new (nothrow) WCHAR[cchString + 1];
+ if (wszDup != NULL)
+ {
+ wcscpy_s(wszDup, cchString + 1, wszString);
+ }
+ }
+ return wszDup;
+}
+
+inline
+LPWSTR DuplicateString(
+ LPCWSTR wszString)
+{
+ STATIC_CONTRACT_NOTHROW;
+
+ if (wszString != NULL)
+ {
+ return DuplicateString(wszString, wcslen(wszString));
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+void DECLSPEC_NORETURN ThrowOutOfMemory();
+
+inline
+LPWSTR DuplicateStringThrowing(
+ LPCWSTR wszString,
+ size_t cchString)
+{
+ STATIC_CONTRACT_THROWS;
+
+ if (wszString == NULL)
+ return NULL;
+
+ LPWSTR wszDup = DuplicateString(wszString, cchString);
+ if (wszDup == NULL)
+ ThrowOutOfMemory();
+
+ return wszDup;
+}
+
+inline
+LPWSTR DuplicateStringThrowing(
+ LPCWSTR wszString)
+{
+ STATIC_CONTRACT_THROWS;
+
+ if (wszString == NULL)
+ return NULL;
+
+ LPWSTR wszDup = DuplicateString(wszString);
+ if (wszDup == NULL)
+ ThrowOutOfMemory();
+
+ return wszDup;
+}
+
+
+//*****************************************************************************
+// Placement new is used to new and object at an exact location. The pointer
+// is simply returned to the caller without actually using the heap. The
+// advantage here is that you cause the ctor() code for the object to be run.
+// This is ideal for heaps of C++ objects that need to get init'd multiple times.
+// Example:
+// void *pMem = GetMemFromSomePlace();
+// Foo *p = new (pMem) Foo;
+// DoSomething(p);
+// p->~Foo();
+//*****************************************************************************
+#ifndef __PLACEMENT_NEW_INLINE
+#define __PLACEMENT_NEW_INLINE
+inline void *__cdecl operator new(size_t, void *_P)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return (_P);
+}
+#endif // __PLACEMENT_NEW_INLINE
+
+
+/********************************************************************************/
+/* portability helpers */
+#ifdef _WIN64
+#define IN_WIN64(x) x
+#define IN_WIN32(x)
+#else
+#define IN_WIN64(x)
+#define IN_WIN32(x) x
+#endif
+
+void * __cdecl
+operator new(size_t n);
+
+_Ret_bytecap_(n) void * __cdecl
+operator new[](size_t n);
+
+void __cdecl
+operator delete(void *p) NOEXCEPT;
+
+void __cdecl
+operator delete[](void *p) NOEXCEPT;
+
+#ifdef _DEBUG_IMPL
+HRESULT _OutOfMemory(LPCSTR szFile, int iLine);
+#define OutOfMemory() _OutOfMemory(__FILE__, __LINE__)
+#else
+inline HRESULT OutOfMemory()
+{
+ LIMITED_METHOD_CONTRACT;
+ return (E_OUTOFMEMORY);
+}
+#endif
+
+//*****************************************************************************
+// Handle accessing localizable resource strings
+//*****************************************************************************
+// NOTE: Should use locale names as much as possible. LCIDs don't support
+// custom cultures on Vista+.
+// TODO: This should always use the names
+#ifdef FEATURE_USE_LCID
+typedef LCID LocaleID;
+typedef LCID LocaleIDValue;
+#else
+typedef LPCWSTR LocaleID;
+typedef WCHAR LocaleIDValue[LOCALE_NAME_MAX_LENGTH];
+#endif
+
+// Notes about the culture callbacks:
+// - The language we're operating in can change at *runtime*!
+// - A process may operate in *multiple* languages.
+// (ex: Each thread may have it's own language)
+// - If we don't care what language we're in (or have no way of knowing),
+// then return a 0-length name and UICULTUREID_DONTCARE for the culture ID.
+// - GetCultureName() and the GetCultureId() must be in sync (refer to the
+// same language).
+// - We have two functions separate functions for better performance.
+// - The name is used to resolve a directory for MsCorRC.dll.
+// - The id is used as a key to map to a dll hinstance.
+
+// Callback to obtain both the culture name and the culture's parent culture name
+typedef HRESULT (*FPGETTHREADUICULTURENAMES)(__inout StringArrayList* pCultureNames);
+#ifdef FEATURE_USE_LCID
+// Callback to return the culture ID.
+const LCID UICULTUREID_DONTCARE = (LCID)-1;
+#else
+const LPCWSTR UICULTUREID_DONTCARE = NULL;
+#endif
+
+typedef int (*FPGETTHREADUICULTUREID)(LocaleIDValue*);
+
+HMODULE CLRLoadLibrary(LPCWSTR lpLibFileName);
+
+HMODULE CLRLoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
+
+BOOL CLRFreeLibrary(HMODULE hModule);
+
+// Prevent people from using LoadStringRC & LoadStringRCEx from inside the product since it
+// causes issues with having the wrong version picked up inside the shim.
+#define LoadStringRC __error("From inside the CLR, use UtilLoadStringRC; LoadStringRC is only meant to be exported.")
+#define LoadStringRCEx __error("From inside the CLR, use UtilLoadStringRCEx; LoadStringRC is only meant to be exported.")
+
+// Load a string using the resources for the current module.
+STDAPI UtilLoadStringRC(UINT iResouceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax, int bQuiet=FALSE);
+
+#if defined(ENABLE_DOWNLEVEL_FOR_NLS) || defined(FEATURE_USE_LCID)
+STDAPI UtilLoadStringRCEx(LCID lcid, UINT iResourceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax, int bQuiet, int *pcwchUsed);
+#endif
+
+// Specify callbacks so that UtilLoadStringRC can find out which language we're in.
+// If no callbacks specified (or both parameters are NULL), we default to the
+// resource dll in the root (which is probably english).
+void SetResourceCultureCallbacks(
+ FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
+ FPGETTHREADUICULTUREID fpGetThreadUICultureId
+);
+
+void GetResourceCultureCallbacks(
+ FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
+ FPGETTHREADUICULTUREID* fpGetThreadUICultureId
+);
+
+#if !defined(DACCESS_COMPILE)
+// Get the MUI ID, on downlevel platforms where MUI is not supported it
+// returns the default system ID.
+extern int GetMUILanguageID(LocaleIDValue* pResult);
+extern HRESULT GetMUILanguageNames(__inout StringArrayList* pCultureNames);
+
+#endif // !defined(DACCESS_COMPILE)
+
+//*****************************************************************************
+// Use this class by privately deriving from noncopyable to disallow copying of
+// your class.
+//*****************************************************************************
+class noncopyable
+{
+protected:
+ noncopyable()
+ {}
+ ~noncopyable()
+ {}
+
+private:
+ noncopyable(const noncopyable&);
+ const noncopyable& operator=(const noncopyable&);
+};
+
+//*****************************************************************************
+// Must associate each handle to an instance of a resource dll with the int
+// that it represents
+//*****************************************************************************
+typedef HINSTANCE HRESOURCEDLL;
+
+
+class CCulturedHInstance
+{
+ LocaleIDValue m_LangId;
+ HRESOURCEDLL m_hInst;
+ BOOL m_fMissing;
+
+public:
+ CCulturedHInstance()
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_hInst = NULL;
+ m_fMissing = FALSE;
+ }
+
+ BOOL HasID(LocaleID id)
+ {
+ _ASSERTE(m_hInst != NULL || m_fMissing);
+ if (id == UICULTUREID_DONTCARE)
+ return FALSE;
+
+#ifdef FEATURE_USE_LCID
+ return id == m_LangId;
+#else
+ return wcscmp(id, m_LangId) == 0;
+#endif
+ }
+
+ HRESOURCEDLL GetLibraryHandle()
+ {
+ return m_hInst;
+ }
+
+ BOOL IsSet()
+ {
+ return m_hInst != NULL;
+ }
+
+ BOOL IsMissing()
+ {
+ return m_fMissing;
+ }
+
+ void SetMissing(LocaleID id)
+ {
+ _ASSERTE(m_hInst == NULL);
+ SetId(id);
+ m_fMissing = TRUE;
+ }
+
+ void Set(LocaleID id, HRESOURCEDLL hInst)
+ {
+ _ASSERTE(m_hInst == NULL);
+ _ASSERTE(m_fMissing == FALSE);
+ SetId(id);
+ m_hInst = hInst;
+ }
+ private:
+ void SetId(LocaleID id)
+ {
+#ifdef FEATURE_USE_LCID
+ m_LangId = id;
+#else
+ if (id != UICULTUREID_DONTCARE)
+ {
+ wcsncpy_s(m_LangId, NumItems(m_LangId), id, NumItems(m_LangId));
+ m_LangId[NumItems(m_LangId)-1] = W('\0');
+ }
+ else
+ {
+ m_LangId[0] = W('\0');
+ }
+#endif
+ }
+ };
+
+#ifndef DACCESS_COMPILE
+void AddThreadPreferredUILanguages(StringArrayList* pArray);
+#endif
+//*****************************************************************************
+// CCompRC manages string Resource access for COM+. This includes loading
+// the MsCorRC.dll for resources as well allowing each thread to use a
+// a different localized version.
+//*****************************************************************************
+class CCompRC
+{
+public:
+
+ enum ResourceCategory
+ {
+ // must be present
+ Required,
+
+ // present in Desktop CLR and Core CLR + debug pack, an error
+ // If missing, get a generic error message instead
+ Error,
+
+ // present in Desktop CLR and Core CLR + debug pack, normal operation (e.g tracing)
+ // if missing, get a generic "resource not found" message instead
+ Debugging,
+
+ // present in Desktop CLR, optional for CoreCLR
+ DesktopCLR,
+
+ // might not be present, non essential
+ Optional
+ };
+
+ CCompRC()
+ {
+ // This constructor will be fired up on startup. Make sure it doesn't
+ // do anything besides zero-out out values.
+ m_bUseFallback = FALSE;
+
+ m_fpGetThreadUICultureId = NULL;
+ m_fpGetThreadUICultureNames = NULL;
+
+
+ m_pHash = NULL;
+ m_nHashSize = 0;
+ m_csMap = NULL;
+ m_pResourceFile = NULL;
+#ifdef FEATURE_PAL
+ m_pResourceDomain = NULL;
+#endif // FEATURE_PAL
+
+ }// CCompRC
+
+ HRESULT Init(LPCWSTR pResourceFile, BOOL bUseFallback = FALSE);
+ void Destroy();
+
+ BOOL ShouldUseFallback()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_bUseFallback;
+ };
+
+ static void SetIsMscoree() {s_bIsMscoree = TRUE;}
+
+ HRESULT LoadString(ResourceCategory eCategory, UINT iResourceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax , int *pcwchUsed=NULL);
+ HRESULT LoadString(ResourceCategory eCategory, LocaleID langId, UINT iResourceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax, int *pcwchUsed);
+
+ void SetResourceCultureCallbacks(
+ FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
+ FPGETTHREADUICULTUREID fpGetThreadUICultureId
+ );
+
+ void GetResourceCultureCallbacks(
+ FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
+ FPGETTHREADUICULTUREID* fpGetThreadUICultureId
+ );
+
+ HRESULT LoadMUILibrary(HRESOURCEDLL * pHInst);
+
+ // Get the default resource location (mscorrc.dll for desktop, mscorrc.debug.dll for CoreCLR)
+ static CCompRC* GetDefaultResourceDll();
+#ifdef FEATURE_CORECLR
+ // Get the generic messages dll (Silverlight only, mscorrc.dll)
+ static CCompRC* GetFallbackResourceDll();
+#endif
+ static void ShutdownDefaultResourceDll();
+ static void GetDefaultCallbacks(
+ FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
+ FPGETTHREADUICULTUREID* fpGetThreadUICultureId)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_DefaultResourceDll.GetResourceCultureCallbacks(
+ fpGetThreadUICultureNames,
+ fpGetThreadUICultureId);
+ }
+
+ static void SetDefaultCallbacks(
+ FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
+ FPGETTHREADUICULTUREID fpGetThreadUICultureId)
+ {
+ WRAPPER_NO_CONTRACT;
+ // Either both are NULL or neither are NULL
+ _ASSERTE((fpGetThreadUICultureNames != NULL) ==
+ (fpGetThreadUICultureId != NULL));
+
+ m_DefaultResourceDll.SetResourceCultureCallbacks(
+ fpGetThreadUICultureNames,
+ fpGetThreadUICultureId);
+
+#ifdef FEATURE_CORECLR
+ m_FallbackResourceDll.SetResourceCultureCallbacks(
+ fpGetThreadUICultureNames,
+ fpGetThreadUICultureId);
+
+#endif
+ }
+
+#ifdef USE_FORMATMESSAGE_WRAPPER
+
+DWORD
+PALAPI
+static
+FormatMessage(
+ IN DWORD dwFlags,
+ IN LPCVOID lpSource,
+ IN DWORD dwMessageId,
+ IN DWORD dwLanguageId,
+ OUT LPWSTR lpBuffer,
+ IN DWORD nSize,
+ IN va_list *Arguments);
+#endif // USE_FORMATMESSAGE_WRAPPER
+
+
+private:
+ HRESULT GetLibrary(LocaleID langId, HRESOURCEDLL* phInst);
+#ifndef DACCESS_COMPILE
+ HRESULT LoadLibraryHelper(HRESOURCEDLL *pHInst,
+ SString& rcPath);
+ HRESULT LoadLibraryThrows(HRESOURCEDLL * pHInst);
+ HRESULT LoadLibrary(HRESOURCEDLL * pHInst);
+ HRESULT LoadResourceFile(HRESOURCEDLL * pHInst, LPCWSTR lpFileName);
+#endif
+
+ // We do not have global constructors any more
+ static LONG m_dwDefaultInitialized;
+ static CCompRC m_DefaultResourceDll;
+ static LPCWSTR m_pDefaultResource;
+
+#ifdef FEATURE_CORECLR
+ // fallback resources if debug pack is not installed
+ static LONG m_dwFallbackInitialized;
+ static CCompRC m_FallbackResourceDll;
+ static LPCWSTR m_pFallbackResource;
+#endif
+
+ // We must map between a thread's int and a dll instance.
+ // Since we only expect 1 language almost all of the time, we'll special case
+ // that and then use a variable size map for everything else.
+ CCulturedHInstance m_Primary;
+ CCulturedHInstance * m_pHash;
+ int m_nHashSize;
+
+ CRITSEC_COOKIE m_csMap;
+
+ LPCWSTR m_pResourceFile;
+#ifdef FEATURE_PAL
+ // Resource domain is an ANSI string identifying a native resources file
+ static LPCSTR m_pDefaultResourceDomain;
+ static LPCSTR m_pFallbackResourceDomain;
+ LPCSTR m_pResourceDomain;
+#endif // FEATURE_PAL
+
+ // Main accessors for hash
+ HRESOURCEDLL LookupNode(LocaleID langId, BOOL &fMissing);
+ HRESULT AddMapNode(LocaleID langId, HRESOURCEDLL hInst, BOOL fMissing = FALSE);
+
+ FPGETTHREADUICULTUREID m_fpGetThreadUICultureId;
+ FPGETTHREADUICULTURENAMES m_fpGetThreadUICultureNames;
+
+ BOOL m_bUseFallback;
+ static BOOL s_bIsMscoree;
+};
+
+HRESULT UtilLoadResourceString(CCompRC::ResourceCategory eCategory, UINT iResouceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax);
+
+
+int UtilMessageBox(
+ HWND hWnd, // Handle to Owner Window
+ UINT uText, // Resource Identifier for Text message
+ UINT uCaption, // Resource Identifier for Caption
+ UINT uType, // Style of MessageBox
+ BOOL displayForNonInteractive, // Display even if the process is running non interactive
+ BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+ ...); // Additional Arguments
+
+int UtilMessageBoxNonLocalized(
+ HWND hWnd, // Handle to Owner Window
+ LPCWSTR lpText, // Resource Identifier for Text message
+ LPCWSTR lpTitle, // Resource Identifier for Caption
+ UINT uType, // Style of MessageBox
+ BOOL displayForNonInteractive, // Display even if the process is running non interactive
+ BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+ ...); // Additional Arguments
+
+int UtilMessageBoxVA(
+ HWND hWnd, // Handle to Owner Window
+ UINT uText, // Resource Identifier for Text message
+ UINT uCaption, // Resource Identifier for Caption
+ UINT uType, // Style of MessageBox
+ BOOL displayForNonInteractive, // Display even if the process is running non interactive
+ BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+ va_list args); // Additional Arguments
+
+int UtilMessageBoxNonLocalizedVA(
+ HWND hWnd, // Handle to Owner Window
+ LPCWSTR lpText, // Text message
+ LPCWSTR lpCaption, // Caption
+ UINT uType, // Style of MessageBox
+ BOOL displayForNonInteractive, // Display even if the process is running non interactive
+ BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+ BOOL * pInputFromUser, // To distinguish between user pressing abort vs. assuming abort.
+ va_list args); // Additional Arguments
+
+int UtilMessageBoxNonLocalizedVA(
+ HWND hWnd, // Handle to Owner Window
+ LPCWSTR lpText, // Text message
+ LPCWSTR lpCaption, // Caption
+ LPCWSTR lpDetails, // Details that may be shown in a collapsed extended area of the dialog (Vista or higher).
+ UINT uType, // Style of MessageBox
+ BOOL displayForNonInteractive, // Display even if the process is running non interactive
+ BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+ BOOL * pInputFromUser, // To distinguish between user pressing abort vs. assuming abort.
+ va_list args); // Additional Arguments
+
+int UtilMessageBoxCatastrophic(
+ UINT uText, // Text for MessageBox
+ UINT uTitle, // Title for MessageBox
+ UINT uType, // Style of MessageBox
+ BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+ ...);
+
+int UtilMessageBoxCatastrophicNonLocalized(
+ LPCWSTR lpText, // Text for MessageBox
+ LPCWSTR lpTitle, // Title for MessageBox
+ UINT uType, // Style of MessageBox
+ BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+ ...);
+
+int UtilMessageBoxCatastrophicVA(
+ UINT uText, // Text for MessageBox
+ UINT uTitle, // Title for MessageBox
+ UINT uType, // Style of MessageBox
+ BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+ va_list args); // Additional Arguments
+
+int UtilMessageBoxCatastrophicNonLocalizedVA(
+ LPCWSTR lpText, // Text for MessageBox
+ LPCWSTR lpTitle, // Title for MessageBox
+ UINT uType, // Style of MessageBox
+ BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
+ va_list args); // Additional Arguments
+
+
+// The HRESULT_FROM_WIN32 macro evaluates its arguments three times.
+// <TODO>TODO: All HRESULT_FROM_WIN32(GetLastError()) should be replaced by calls to
+// this helper function avoid code bloat</TODO>
+inline HRESULT HRESULT_FROM_GetLastError()
+{
+ WRAPPER_NO_CONTRACT;
+ DWORD dw = GetLastError();
+ // Make sure we return a failure
+ if (dw == ERROR_SUCCESS)
+ {
+ _ASSERTE(!"We were expecting to get an error code, but a success code is being returned. Check this code path for Everett!");
+ return E_FAIL;
+ }
+ else
+ return HRESULT_FROM_WIN32(dw);
+}
+
+inline HRESULT HRESULT_FROM_GetLastErrorNA()
+{
+ WRAPPER_NO_CONTRACT;
+ DWORD dw = GetLastError();
+ // Make sure we return a failure
+ if (dw == ERROR_SUCCESS)
+ return E_FAIL;
+ else
+ return HRESULT_FROM_WIN32(dw);
+}
+
+inline HRESULT BadError(HRESULT hr)
+{
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(!"Serious Error");
+ return (hr);
+}
+
+#define TESTANDRETURN(test, hrVal) \
+{ \
+ int ___test = (int)(test); \
+ if (! ___test) \
+ return hrVal; \
+}
+
+#define TESTANDRETURNPOINTER(pointer) \
+ TESTANDRETURN(pointer!=NULL, E_POINTER)
+
+#define TESTANDRETURNMEMORY(pointer) \
+ TESTANDRETURN(pointer!=NULL, E_OUTOFMEMORY)
+
+#define TESTANDRETURNHR(hr) \
+ TESTANDRETURN(SUCCEEDED(hr), hr)
+
+#define TESTANDRETURNARG(argtest) \
+ TESTANDRETURN(argtest, E_INVALIDARG)
+
+// Quick validity check for HANDLEs that are returned by Win32 APIs that
+// use INVALID_HANDLE_VALUE instead of NULL to indicate an error
+inline BOOL IsValidHandle(HANDLE h)
+{
+ LIMITED_METHOD_CONTRACT;
+ return ((h != NULL) && (h != INVALID_HANDLE_VALUE));
+}
+
+// Count the bits in a value in order iBits time.
+inline int CountBits(int iNum)
+{
+ LIMITED_METHOD_CONTRACT;
+ int iBits;
+ for (iBits=0; iNum; iBits++)
+ iNum = iNum & (iNum - 1);
+ return (iBits);
+}
+
+#include "bitposition.h"
+
+// Used to remove trailing zeros from Decimal types.
+// NOTE: Assumes hi32 bits are empty (used for conversions from Cy->Dec)
+inline HRESULT DecimalCanonicalize(DECIMAL* dec)
+{
+ WRAPPER_NO_CONTRACT;
+
+ // Clear the VARENUM field
+ (*(USHORT*)dec) = 0;
+
+ // Remove trailing zeros:
+ DECIMAL temp;
+ DECIMAL templast;
+ temp = templast = *dec;
+
+ // Ensure the hi 32 bits are empty (should be if we came from a currency)
+ if ((DECIMAL_HI32(temp) != 0) || (DECIMAL_SCALE(temp) > 4))
+ return DISP_E_OVERFLOW;
+
+ // Return immediately if dec represents a zero.
+ if (DECIMAL_LO32(temp) == 0 && DECIMAL_MID32(temp) == 0)
+ return S_OK;
+
+ // Compare to the original to see if we've
+ // lost non-zero digits (and make sure we don't overflow the scale BYTE)
+
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:6219) // "Suppress PREFast warning about Implicit cast between semantically different integer types"
+#endif
+ while ((DECIMAL_SCALE(temp) <= 4) && (VARCMP_EQ == VarDecCmp(dec, &temp)))
+ {
+
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+ templast = temp;
+
+ // Remove the last digit and normalize. Ignore temp.Hi32
+ // as Currency values will have a max of 64 bits of data.
+ DECIMAL_SCALE(temp)--;
+ UINT64 temp64 = (((UINT64) DECIMAL_MID32(temp)) << 32) + DECIMAL_LO32(temp);
+ temp64 /= 10;
+
+ DECIMAL_MID32(temp) = (ULONG)(temp64 >> 32);
+ DECIMAL_LO32(temp) = (ULONG)temp64;
+ }
+ *dec = templast;
+
+ return S_OK;
+}
+
+//*****************************************************************************
+//
+// Paths functions. Use these instead of the CRT.
+//
+//*****************************************************************************
+// secure version! Specify the size of the each buffer in count of elements
+void SplitPath(register const WCHAR *path,
+ __inout_z __inout_ecount_opt(driveSizeInWords) WCHAR *drive, int driveSizeInWords,
+ __inout_z __inout_ecount_opt(dirSizeInWords) WCHAR *dir, int dirSizeInWords,
+ __inout_z __inout_ecount_opt(fnameSizeInWords) WCHAR *fname, size_t fnameSizeInWords,
+ __inout_z __inout_ecount_opt(extSizeInWords) WCHAR *ext, size_t extSizeInWords);
+
+//*******************************************************************************
+// A much more sensible version that just points to each section of the string.
+//*******************************************************************************
+void SplitPathInterior(
+ __in LPCWSTR wszPath,
+ __out_opt LPCWSTR *pwszDrive, __out_opt size_t *pcchDrive,
+ __out_opt LPCWSTR *pwszDir, __out_opt size_t *pcchDir,
+ __out_opt LPCWSTR *pwszFileName, __out_opt size_t *pcchFileName,
+ __out_opt LPCWSTR *pwszExt, __out_opt size_t *pcchExt);
+
+#ifndef FEATURE_CORECLR
+void MakePath(__out_ecount (MAX_LONGPATH) register WCHAR *path,
+ __in LPCWSTR drive,
+ __in LPCWSTR dir,
+ __in LPCWSTR fname,
+ __in LPCWSTR ext);
+#endif
+
+void MakePath(__out CQuickWSTR &path,
+ __in LPCWSTR drive,
+ __in LPCWSTR dir,
+ __in LPCWSTR fname,
+ __in LPCWSTR ext);
+
+WCHAR * FullPath(__out_ecount (maxlen) WCHAR *UserBuf, const WCHAR *path, size_t maxlen);
+
+//*****************************************************************************
+//
+// SString version of the path functions.
+//
+//*****************************************************************************
+void SplitPath(__in SString const &path,
+ __inout_opt SString *drive,
+ __inout_opt SString *dir,
+ __inout_opt SString *fname,
+ __inout_opt SString *ext);
+
+#if !defined(NO_CLRCONFIG)
+
+//*****************************************************************************
+//
+// **** REGUTIL - Static helper functions for reading/writing to Windows registry.
+//
+//*****************************************************************************
+
+
+class REGUTIL
+{
+public:
+//*****************************************************************************
+
+ enum CORConfigLevel
+ {
+ COR_CONFIG_ENV = 0x01,
+ COR_CONFIG_USER = 0x02,
+ COR_CONFIG_MACHINE = 0x04,
+ COR_CONFIG_FUSION = 0x08,
+
+ COR_CONFIG_REGISTRY = (COR_CONFIG_USER|COR_CONFIG_MACHINE|COR_CONFIG_FUSION),
+ COR_CONFIG_ALL = (COR_CONFIG_ENV|COR_CONFIG_USER|COR_CONFIG_MACHINE),
+ };
+
+ //
+ // NOTE: The following function is deprecated; use the CLRConfig class instead.
+ // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
+ //
+ static DWORD GetConfigDWORD_DontUse_(
+ LPCWSTR name,
+ DWORD defValue,
+ CORConfigLevel level = COR_CONFIG_ALL,
+ BOOL fPrependCOMPLUS = TRUE);
+
+ //
+ // NOTE: The following function is deprecated; use the CLRConfig class instead.
+ // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
+ //
+ static HRESULT GetConfigDWORD_DontUse_(
+ LPCWSTR name,
+ DWORD defValue,
+ __out DWORD * result,
+ CORConfigLevel level = COR_CONFIG_ALL,
+ BOOL fPrependCOMPLUS = TRUE);
+
+ static ULONGLONG GetConfigULONGLONG_DontUse_(
+ LPCWSTR name,
+ ULONGLONG defValue,
+ CORConfigLevel level = COR_CONFIG_ALL,
+ BOOL fPrependCOMPLUS = TRUE);
+
+ //
+ // NOTE: The following function is deprecated; use the CLRConfig class instead.
+ // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
+ //
+ static DWORD GetConfigFlag_DontUse_(
+ LPCWSTR name,
+ DWORD bitToSet,
+ BOOL defValue = FALSE);
+
+ //
+ // NOTE: The following function is deprecated; use the CLRConfig class instead.
+ // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
+ //
+ static LPWSTR GetConfigString_DontUse_(
+ LPCWSTR name,
+ BOOL fPrependCOMPLUS = TRUE,
+ CORConfigLevel level = COR_CONFIG_ALL,
+ BOOL fUsePerfCache = TRUE);
+
+ static void FreeConfigString(__in __in_z LPWSTR name);
+
+#ifdef FEATURE_CORECLR
+private:
+#endif //FEATURE_CORECLR
+ static LPWSTR EnvGetString(LPCWSTR name, BOOL fPrependCOMPLUS);
+#ifdef FEATURE_CORECLR
+public:
+#endif //FEATURE_CORECLR
+
+ static BOOL UseRegistry();
+
+private:
+//*****************************************************************************
+// Get either a DWORD or ULONGLONG. Always puts the result in a ULONGLONG that
+// you can safely cast to a DWORD if fGetDWORD is TRUE.
+//*****************************************************************************
+ static HRESULT GetConfigInteger(
+ LPCWSTR name,
+ ULONGLONG defValue,
+ __out ULONGLONG * result,
+ BOOL fGetDWORD = TRUE,
+ CORConfigLevel level = COR_CONFIG_ALL,
+ BOOL fPrependCOMPLUS = TRUE);
+public:
+
+#ifndef FEATURE_CORECLR
+ static void AllowRegistryUse(BOOL fAllowUse);
+
+
+//*****************************************************************************
+// Open's the given key and returns the value desired. If the key or value is
+// not found, then the default is returned.
+//*****************************************************************************
+ static long GetLong( // Return value from registry or default.
+ LPCTSTR szName, // Name of value to get.
+ long iDefault, // Default value to return if not found.
+ LPCTSTR szKey=NULL, // Name of key, NULL==default.
+ HKEY hKey=HKEY_LOCAL_MACHINE);// What key to work on.
+
+//*****************************************************************************
+// Open's the given key and returns the value desired. If the key or value is
+// not found, then the default is returned.
+//*****************************************************************************
+ static long SetLong( // Return value from registry or default.
+ LPCTSTR szName, // Name of value to get.
+ long iValue, // Value to set.
+ LPCTSTR szKey=NULL, // Name of key, NULL==default.
+ HKEY hKey=HKEY_LOCAL_MACHINE);// What key to work on.
+
+//*****************************************************************************
+// Open's the given key and returns the value desired. If the key or value is
+// not found, then it's created
+//*****************************************************************************
+ static long SetOrCreateLong( // Return value from registry or default.
+ LPCTSTR szName, // Name of value to get.
+ long iValue, // Value to set.
+ LPCTSTR szKey=NULL, // Name of key, NULL==default.
+ HKEY hKey=HKEY_LOCAL_MACHINE);// What key to work on.
+
+
+
+//*****************************************************************************
+// Set an entry in the registry of the form:
+// HKEY_CLASSES_ROOT\szKey\szSubkey = szValue. If szSubkey or szValue are
+// NULL, omit them from the above expression.
+//*****************************************************************************
+ static BOOL SetKeyAndValue( // TRUE or FALSE.
+ LPCTSTR szKey, // Name of the reg key to set.
+ LPCTSTR szSubkey, // Optional subkey of szKey.
+ LPCTSTR szValue); // Optional value for szKey\szSubkey.
+
+//*****************************************************************************
+// Delete an entry in the registry of the form:
+// HKEY_CLASSES_ROOT\szKey\szSubkey.
+//*****************************************************************************
+ static LONG DeleteKey( // TRUE or FALSE.
+ LPCTSTR szKey, // Name of the reg key to set.
+ LPCTSTR szSubkey); // Subkey of szKey.
+
+//*****************************************************************************
+// Open the key, create a new keyword and value pair under it.
+//*****************************************************************************
+ static BOOL SetRegValue( // Return status.
+ LPCTSTR szKeyName, // Name of full key.
+ LPCTSTR szKeyword, // Name of keyword.
+ LPCTSTR szValue); // Value of keyword.
+
+//*****************************************************************************
+// Does standard registration of a CoClass with a progid.
+//*****************************************************************************
+ static HRESULT RegisterCOMClass( // Return code.
+ REFCLSID rclsid, // Class ID.
+ LPCTSTR szDesc, // Description of the class.
+ LPCTSTR szProgIDPrefix, // Prefix for progid.
+ int iVersion, // Version # for progid.
+ LPCTSTR szClassProgID, // Class progid.
+ LPCTSTR szThreadingModel, // What threading model to use.
+ LPCTSTR szModule, // Path to class.
+ HINSTANCE hInst, // Handle to module being registered
+ LPCTSTR szAssemblyName, // Optional assembly name
+ LPCTSTR szVersion, // Optional Runtime Version (directry containing runtime)
+ BOOL fExternal, // flag - External to mscoree.
+ BOOL fRelativePath); // flag - Relative path in szModule
+
+//*****************************************************************************
+// Unregister the basic information in the system registry for a given object
+// class.
+//*****************************************************************************
+ static HRESULT UnregisterCOMClass( // Return code.
+ REFCLSID rclsid, // Class ID we are registering.
+ LPCTSTR szProgIDPrefix, // Prefix for progid.
+ int iVersion, // Version # for progid.
+ LPCTSTR szClassProgID, // Class progid.
+ BOOL fExternal); // flag - External to mscoree.
+
+//*****************************************************************************
+// Does standard registration of a CoClass with a progid.
+// NOTE: This is the non-side-by-side execution version.
+//*****************************************************************************
+ static HRESULT RegisterCOMClass( // Return code.
+ REFCLSID rclsid, // Class ID.
+ LPCTSTR szDesc, // Description of the class.
+ LPCTSTR szProgIDPrefix, // Prefix for progid.
+ int iVersion, // Version # for progid.
+ LPCTSTR szClassProgID, // Class progid.
+ LPCTSTR szThreadingModel, // What threading model to use.
+ LPCTSTR szModule, // Path to class.
+ BOOL bInprocServer = true); // Whether we register the server as inproc or local
+
+//*****************************************************************************
+// Unregister the basic information in the system registry for a given object
+// class.
+// NOTE: This is the non-side-by-side execution version.
+//*****************************************************************************
+ static HRESULT UnregisterCOMClass( // Return code.
+ REFCLSID rclsid, // Class ID we are registering.
+ LPCTSTR szProgIDPrefix, // Prefix for progid.
+ int iVersion, // Version # for progid.
+ LPCTSTR szClassProgID); // Class progid.
+
+//*****************************************************************************
+// Register a type library.
+//*****************************************************************************
+ static HRESULT RegisterTypeLib( // Return code.
+ REFGUID rtlbid, // TypeLib ID we are registering.
+ int iVersion, // Typelib version.
+ LPCTSTR szDesc, // TypeLib description.
+ LPCTSTR szModule); // Path to the typelib.
+
+//*****************************************************************************
+// Remove the registry keys for a type library.
+//*****************************************************************************
+ static HRESULT UnregisterTypeLib( // Return code.
+ REFGUID rtlbid, // TypeLib ID we are registering.
+ int iVersion); // Typelib version.
+
+#endif //#ifndef FEATURE_CORECLR
+
+//*****************************************************************************
+// (Optional) Initialize the config registry cache
+// (see ConfigCacheValueNameSeenPerhaps, below.)
+//*****************************************************************************
+ static void InitOptionalConfigCache();
+
+private:
+
+#ifndef FEATURE_CORECLR
+
+//*****************************************************************************
+// Register the basics for a in proc server.
+//*****************************************************************************
+ static HRESULT RegisterClassBase( // Return code.
+ REFCLSID rclsid, // Class ID we are registering.
+ LPCTSTR szDesc, // Class description.
+ LPCTSTR szProgID, // Class prog ID.
+ LPCTSTR szIndepProgID, // Class version independant prog ID.
+ __out_ecount (cchOutCLSID) LPTSTR szOutCLSID, // CLSID formatted in character form.
+ DWORD cchOutCLSID); // Out CLS ID buffer size in characters
+
+
+//*****************************************************************************
+// Delete the basic settings for an inproc server.
+//*****************************************************************************
+ static HRESULT UnregisterClassBase( // Return code.
+ REFCLSID rclsid, // Class ID we are registering.
+ LPCTSTR szProgID, // Class prog ID.
+ LPCTSTR szIndepProgID, // Class version independant prog ID.
+ __out_ecount (cchOutCLSID) LPTSTR szOutCLSID, // Return formatted class ID here.
+ DWORD cchOutCLSID); // Out CLS ID buffer size in characters
+
+#endif //#ifndef FEATURE_CORECLR
+
+//*****************************************************************************
+// Return TRUE if the registry value name might have been seen in the registry
+// at startup;
+// return FALSE if the value was definitely not seen at startup.
+//
+// Perf Optimization for VSWhidbey:113373.
+//*****************************************************************************
+ static BOOL RegCacheValueNameSeenPerhaps(
+ LPCWSTR name);
+//*****************************************************************************
+// Return TRUE if the environment variable name might have been seen at startup;
+// return FALSE if the value was definitely not seen at startup.
+//*****************************************************************************
+ static BOOL EnvCacheValueNameSeenPerhaps(
+ LPCWSTR name);
+
+ static BOOL s_fUseRegCache; // Enable registry cache; if FALSE, CCVNSP
+ // always returns TRUE.
+ static BOOL s_fUseEnvCache; // Enable env cache.
+
+ static BOOL s_fUseRegistry; // Allow lookups in the registry
+
+ // Open the .NetFramework keys once and cache the handles
+ static HKEY s_hMachineFrameworkKey;
+ static HKEY s_hUserFrameworkKey;
+};
+
+// need this here because CLRConfig depends on REGUTIL, and ConfigStringHolder depends on CLRConfig
+#include "clrconfig.h"
+
+//-----------------------------------------------------------------------------
+// Wrapper for configuration strings.
+// This serves as a holder to call FreeConfigString.
+class ConfigStringHolder
+{
+public:
+ ConfigStringHolder() { m_wszString = NULL; }
+ ~ConfigStringHolder()
+ {
+ Clear();
+ }
+
+ //
+ // NOTE: The following function is deprecated; use the CLRConfig class instead.
+ // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
+ //
+ void Init_DontUse_(LPCWSTR wszName)
+ {
+ Clear();
+ m_wszString = REGUTIL::GetConfigString_DontUse_(wszName);
+ }
+
+ // Free resources.
+ void Clear()
+ {
+ if (m_wszString != NULL)
+ {
+ REGUTIL::FreeConfigString(m_wszString);
+ m_wszString = NULL;
+ }
+ }
+
+ // Get the string value. NULL if not set.
+ LPCWSTR Value()
+ {
+ return m_wszString;
+ }
+
+private:
+ LPWSTR m_wszString;
+};
+
+#endif // defined(NO_CLRCONFIG)
+
+#include "ostype.h"
+
+#define CLRGetTickCount64() GetTickCount64()
+
+//
+// Use this function to initialize the s_CodeAllocHint
+// during startup. base is runtime .dll base address,
+// size is runtime .dll virtual size.
+//
+void InitCodeAllocHint(SIZE_T base, SIZE_T size, int randomPageOffset);
+
+
+//
+// Use this function to reset the s_CodeAllocHint
+// after unloading an AppDomain
+//
+void ResetCodeAllocHint();
+
+//
+// Returns TRUE if p is located in near clr.dll that allows us
+// to use rel32 IP-relative addressing modes.
+//
+BOOL IsPreferredExecutableRange(void * p);
+
+//
+// Allocate free memory that will be used for executable code
+// Handles the special requirements that we have on 64-bit platforms
+// where we want the executable memory to be located near mscorwks
+//
+BYTE * ClrVirtualAllocExecutable(SIZE_T dwSize,
+ DWORD flAllocationType,
+ DWORD flProtect);
+
+//
+// Allocate free memory within the range [pMinAddr..pMaxAddr] using
+// ClrVirtualQuery to find free memory and ClrVirtualAlloc to allocate it.
+//
+BYTE * ClrVirtualAllocWithinRange(const BYTE *pMinAddr,
+ const BYTE *pMaxAddr,
+ SIZE_T dwSize,
+ DWORD flAllocationType,
+ DWORD flProtect);
+
+//
+// Allocate free memory with specific alignment
+//
+LPVOID ClrVirtualAllocAligned(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect, SIZE_T alignment);
+
+//******************************************************************************
+// Returns the number of processors that a process has been configured to run on
+//******************************************************************************
+class NumaNodeInfo
+{
+private:
+ static BOOL m_enableGCNumaAware;
+ static BOOL InitNumaNodeInfoAPI();
+
+public:
+ static BOOL CanEnableGCNumaAware();
+ static void InitNumaNodeInfo();
+
+#if !defined(FEATURE_REDHAWK)&& !defined(FEATURE_PAL)
+private: // apis types
+
+ //GetNumaHighestNodeNumber()
+ typedef BOOL
+ (WINAPI *PGNHNN)(PULONG);
+ //VirtualAllocExNuma()
+ typedef LPVOID
+ (WINAPI *PVAExN)(HANDLE,LPVOID,SIZE_T,DWORD,DWORD,DWORD);
+
+ // api pfns and members
+ static PGNHNN m_pGetNumaHighestNodeNumber;
+ static PVAExN m_pVirtualAllocExNuma;
+
+public: // functions
+
+ static LPVOID VirtualAllocExNuma(HANDLE hProc, LPVOID lpAddr, SIZE_T size,
+ DWORD allocType, DWORD prot, DWORD node);
+
+private:
+ //GetNumaProcessorNodeEx()
+ typedef BOOL
+ (WINAPI *PGNPNEx)(PPROCESSOR_NUMBER, PUSHORT);
+ static PGNPNEx m_pGetNumaProcessorNodeEx;
+
+public:
+ static BOOL GetNumaProcessorNodeEx(PPROCESSOR_NUMBER proc_no, PUSHORT node_no);
+#endif
+};
+
+struct CPU_Group_Info
+{
+ WORD nr_active; // at most 64
+ WORD reserved[1];
+ WORD begin;
+ WORD end;
+ DWORD_PTR active_mask;
+ DWORD groupWeight;
+ DWORD activeThreadWeight;
+};
+
+class CPUGroupInfo
+{
+private:
+ static LONG m_initialization;
+ static WORD m_nGroups;
+ static WORD m_nProcessors;
+ static BOOL m_enableGCCPUGroups;
+ static BOOL m_threadUseAllCpuGroups;
+ static WORD m_initialGroup;
+ static CPU_Group_Info *m_CPUGroupInfoArray;
+
+ static BOOL InitCPUGroupInfoAPI();
+ static BOOL InitCPUGroupInfoArray();
+ static BOOL InitCPUGroupInfoRange();
+ static void InitCPUGroupInfo();
+ static BOOL IsInitialized();
+
+public:
+ static void EnsureInitialized();
+ static BOOL CanEnableGCCPUGroups();
+ static BOOL CanEnableThreadUseAllCpuGroups();
+ static WORD GetNumActiveProcessors();
+ static void GetGroupForProcessor(WORD processor_number,
+ WORD *group_number, WORD *group_processor_number);
+ static DWORD CalculateCurrentProcessorNumber();
+ //static void PopulateCPUUsageArray(void * infoBuffer, ULONG infoSize);
+
+#if !defined(FEATURE_REDHAWK) && !defined(FEATURE_PAL)
+private:
+ //GetLogicalProcessorInforomationEx()
+ typedef BOOL
+ (WINAPI *PGLPIEx)(DWORD, SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *, PDWORD);
+ //SetThreadGroupAffinity()
+ typedef BOOL
+ (WINAPI *PSTGA)(HANDLE, GROUP_AFFINITY *, GROUP_AFFINITY *);
+ //GetThreadGroupAffinity()
+ typedef BOOL
+ (WINAPI *PGTGA)(HANDLE, GROUP_AFFINITY *);
+ //GetCurrentProcessorNumberEx()
+ typedef void
+ (WINAPI *PGCPNEx)(PROCESSOR_NUMBER *);
+ //GetSystemTimes()
+ typedef BOOL
+ (WINAPI *PGST)(FILETIME *, FILETIME *, FILETIME *);
+ //NtQuerySystemInformationEx()
+ //typedef int
+ //(WINAPI *PNTQSIEx)(SYSTEM_INFORMATION_CLASS, PULONG, ULONG, PVOID, ULONG, PULONG);
+ static PGLPIEx m_pGetLogicalProcessorInformationEx;
+ static PSTGA m_pSetThreadGroupAffinity;
+ static PGTGA m_pGetThreadGroupAffinity;
+ static PGCPNEx m_pGetCurrentProcessorNumberEx;
+ static PGST m_pGetSystemTimes;
+ //static PNTQSIEx m_pNtQuerySystemInformationEx;
+
+public:
+ static BOOL GetLogicalProcessorInformationEx(DWORD relationship,
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *slpiex, PDWORD count);
+ static BOOL SetThreadGroupAffinity(HANDLE h,
+ GROUP_AFFINITY *groupAffinity, GROUP_AFFINITY *previousGroupAffinity);
+ static BOOL GetThreadGroupAffinity(HANDLE h, GROUP_AFFINITY *groupAffinity);
+ static BOOL GetSystemTimes(FILETIME *idleTime, FILETIME *kernelTime, FILETIME *userTime);
+ static void ChooseCPUGroupAffinity(GROUP_AFFINITY *gf);
+ static void ClearCPUGroupAffinity(GROUP_AFFINITY *gf);
+#endif
+};
+
+int GetCurrentProcessCpuCount();
+DWORD_PTR GetCurrentProcessCpuMask();
+
+//*****************************************************************************
+// Return != 0 if the bit at the specified index in the array is on and 0 if
+// it is off.
+//*****************************************************************************
+inline int GetBit(PTR_BYTE pcBits,int iBit)
+{
+ LIMITED_METHOD_CONTRACT;
+ return (pcBits[iBit>>3] & (1 << (iBit & 0x7)));
+}
+
+#ifdef DACCESS_COMPILE
+inline int GetBit(BYTE const * pcBits,int iBit)
+{
+ WRAPPER_NO_CONTRACT;
+ return GetBit(dac_cast<PTR_BYTE>(pcBits), iBit);
+}
+#endif
+
+//*****************************************************************************
+// Set the state of the bit at the specified index based on the value of bOn.
+//*****************************************************************************
+inline void SetBit(PTR_BYTE pcBits,int iBit,int bOn)
+{
+ LIMITED_METHOD_CONTRACT;
+ if (bOn)
+ pcBits[iBit>>3] |= (1 << (iBit & 0x7));
+ else
+ pcBits[iBit>>3] &= ~(1 << (iBit & 0x7));
+}
+
+#ifdef DACCESS_COMPILE
+inline void SetBit(BYTE * pcBits,int iBit,int bOn)
+{
+ WRAPPER_NO_CONTRACT;
+ SetBit(dac_cast<PTR_BYTE>(pcBits), iBit, bOn);
+}
+#endif
+
+template<typename T>
+class SimpleListNode
+{
+public:
+ SimpleListNode<T>(const T& _t)
+ {
+ data = _t;
+ next = 0;
+ }
+
+ T data;
+ SimpleListNode<T>* next;
+};
+
+template<typename T>
+class SimpleList
+{
+public:
+ typedef SimpleListNode<T> NodeType;
+
+ SimpleList<T>()
+ {
+ head = NULL;
+ }
+
+ void LinkHead(NodeType* pNode)
+ {
+ pNode->next = head;
+ head = pNode;
+ }
+
+ NodeType* UnlinkHead()
+ {
+ NodeType* ret = head;
+
+ if (head)
+ {
+ head = head->next;
+ }
+ return ret;
+ }
+
+ NodeType* Head()
+ {
+ return head;
+ }
+
+protected:
+
+ NodeType* head;
+};
+
+
+template < typename T, typename U >
+struct Pair
+{
+public:
+ typedef Pair< T, U > this_type;
+ typedef T first_type;
+ typedef U second_type;
+
+ Pair()
+ {}
+
+ Pair( T const & t, U const & u )
+ : m_first( t )
+ , m_second( u )
+ { SUPPORTS_DAC; }
+
+ Pair( this_type const & obj )
+ : m_first( obj.m_first )
+ , m_second( obj.m_second )
+ {}
+
+ this_type & operator=( this_type const & obj )
+ {
+ m_first = obj.m_first;
+ m_second = obj.m_second;
+ return *this;
+ }
+
+ T & First()
+ {
+ return m_first;
+ }
+
+ T const & First() const
+ {
+ return m_first;
+ }
+
+ U & Second()
+ {
+ return m_second;
+ }
+
+ U const & Second() const
+ {
+ return m_second;
+ }
+
+ bool operator==(const Pair& rhs) const
+ {
+ return ((this->First() == rhs.First()) &&
+ (this->Second() == rhs.Second()));
+ }
+
+ bool operator!=(const Pair& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+private:
+ first_type m_first;
+ second_type m_second;
+};
+
+
+template < typename T, typename U >
+Pair< T, U > MakePair( T const & t, U const & u )
+{
+ SUPPORTS_DAC;
+ return Pair< T, U >( t, u );
+}
+
+
+//*****************************************************************************
+// This class implements a dynamic array of structures for which the order of
+// the elements is unimportant. This means that any item placed in the list
+// may be swapped to any other location in the list at any time. If the order
+// of the items you place in the array is important, then use the CStructArray
+// class.
+//*****************************************************************************
+
+template <class T,
+ int iGrowInc,
+ class ALLOCATOR>
+class CUnorderedArrayWithAllocator
+{
+ int m_iCount; // # of elements used in the list.
+ int m_iSize; // # of elements allocated in the list.
+public:
+#ifndef DACCESS_COMPILE
+ T *m_pTable; // Pointer to the list of elements.
+#else
+ TADDR m_pTable; // Pointer to the list of elements.
+#endif
+
+public:
+
+#ifndef DACCESS_COMPILE
+
+ CUnorderedArrayWithAllocator() :
+ m_iCount(0),
+ m_iSize(0),
+ m_pTable(NULL)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+ ~CUnorderedArrayWithAllocator()
+ {
+ LIMITED_METHOD_CONTRACT;
+ // Free the chunk of memory.
+ if (m_pTable != NULL)
+ ALLOCATOR::Free(this, m_pTable);
+ }
+
+ void Clear()
+ {
+ WRAPPER_NO_CONTRACT;
+ m_iCount = 0;
+ if (m_iSize > iGrowInc)
+ {
+ T* tmp = ALLOCATOR::AllocNoThrow(this, iGrowInc);
+ if (tmp) {
+ ALLOCATOR::Free(this, m_pTable);
+ m_pTable = tmp;
+ m_iSize = iGrowInc;
+ }
+ }
+ }
+
+ void Clear(int iFirst, int iCount)
+ {
+ WRAPPER_NO_CONTRACT;
+ int iSize;
+
+ if (iFirst + iCount < m_iCount)
+ memmove(&m_pTable[iFirst], &m_pTable[iFirst + iCount], sizeof(T) * (m_iCount - (iFirst + iCount)));
+
+ m_iCount -= iCount;
+
+ iSize = ((m_iCount / iGrowInc) * iGrowInc) + ((m_iCount % iGrowInc != 0) ? iGrowInc : 0);
+ if (m_iSize > iGrowInc && iSize < m_iSize)
+ {
+ T *tmp = ALLOCATOR::AllocNoThrow(this, iSize);
+ if (tmp) {
+ memcpy (tmp, m_pTable, iSize * sizeof(T));
+ delete [] m_pTable;
+ m_pTable = tmp;
+ m_iSize = iSize;
+ }
+ }
+ _ASSERTE(m_iCount <= m_iSize);
+ }
+
+ T *Table()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_pTable);
+ }
+
+ T *Append()
+ {
+ CONTRACTL {
+ NOTHROW;
+ } CONTRACTL_END;
+
+ // The array should grow, if we can't fit one more element into the array.
+ if (m_iSize <= m_iCount && GrowNoThrow() == NULL)
+ return (NULL);
+ return (&m_pTable[m_iCount++]);
+ }
+
+ T *AppendThrowing()
+ {
+ CONTRACTL {
+ THROWS;
+ } CONTRACTL_END;
+
+ // The array should grow, if we can't fit one more element into the array.
+ if (m_iSize <= m_iCount)
+ Grow();
+ return (&m_pTable[m_iCount++]);
+ }
+
+ void Delete(const T &Entry)
+ {
+ LIMITED_METHOD_CONTRACT;
+ --m_iCount;
+ for (int i=0; i <= m_iCount; ++i)
+ if (m_pTable[i] == Entry)
+ {
+ m_pTable[i] = m_pTable[m_iCount];
+ return;
+ }
+
+ // Just in case we didn't find it.
+ ++m_iCount;
+ }
+
+ void DeleteByIndex(int i)
+ {
+ LIMITED_METHOD_CONTRACT;
+ --m_iCount;
+ m_pTable[i] = m_pTable[m_iCount];
+ }
+
+ void Swap(int i,int j)
+ {
+ LIMITED_METHOD_CONTRACT;
+ T tmp;
+
+ if (i == j)
+ return;
+ tmp = m_pTable[i];
+ m_pTable[i] = m_pTable[j];
+ m_pTable[j] = tmp;
+ }
+
+#else
+
+ TADDR Table()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ return (m_pTable);
+ }
+
+ void EnumMemoryRegions(void)
+ {
+ SUPPORTS_DAC;
+ DacEnumMemoryRegion(m_pTable, m_iCount * sizeof(T));
+ }
+
+#endif // #ifndef DACCESS_COMPILE
+
+ USHORT Count()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ _ASSERTE(FitsIn<USHORT>(m_iCount));
+ return static_cast<USHORT>(m_iCount);
+ }
+
+private:
+ T *Grow();
+ T *GrowNoThrow();
+};
+
+
+#ifndef DACCESS_COMPILE
+
+//*****************************************************************************
+// Increase the size of the array.
+//*****************************************************************************
+template <class T,
+ int iGrowInc,
+ class ALLOCATOR>
+T *CUnorderedArrayWithAllocator<T,iGrowInc,ALLOCATOR>::GrowNoThrow() // NULL if can't grow.
+{
+ WRAPPER_NO_CONTRACT;
+ T *pTemp;
+
+ // try to allocate memory for reallocation.
+ if ((pTemp = ALLOCATOR::AllocNoThrow(this, m_iSize+iGrowInc)) == NULL)
+ return (NULL);
+ memcpy (pTemp, m_pTable, m_iSize*sizeof(T));
+ ALLOCATOR::Free(this, m_pTable);
+ m_pTable = pTemp;
+ m_iSize += iGrowInc;
+ _ASSERTE(m_iSize > 0);
+ return (pTemp);
+}
+
+template <class T,
+ int iGrowInc,
+ class ALLOCATOR>
+T *CUnorderedArrayWithAllocator<T,iGrowInc,ALLOCATOR>::Grow() // exception if can't grow.
+{
+ WRAPPER_NO_CONTRACT;
+ T *pTemp;
+
+ // try to allocate memory for reallocation.
+ pTemp = ALLOCATOR::AllocThrowing(this, m_iSize+iGrowInc);
+ memcpy (pTemp, m_pTable, m_iSize*sizeof(T));
+ ALLOCATOR::Free(this, m_pTable);
+ m_pTable = pTemp;
+ m_iSize += iGrowInc;
+ _ASSERTE(m_iSize > 0);
+ return (pTemp);
+}
+
+#endif // #ifndef DACCESS_COMPILE
+
+
+template <class T>
+class CUnorderedArray__Allocator
+{
+public:
+
+ static T *AllocThrowing (void*, int nElements)
+ {
+ return new T[nElements];
+ }
+
+ static T *AllocNoThrow (void*, int nElements)
+ {
+ return new (nothrow) T[nElements];
+ }
+
+ static void Free (void*, T *pTable)
+ {
+ delete [] pTable;
+ }
+};
+
+
+template <class T,int iGrowInc>
+class CUnorderedArray : public CUnorderedArrayWithAllocator<T, iGrowInc, CUnorderedArray__Allocator<T> >
+{
+public:
+
+ CUnorderedArray ()
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+};
+
+
+//Used by the debugger. Included here in hopes somebody else might, too
+typedef CUnorderedArray<SIZE_T, 17> SIZE_T_UNORDERED_ARRAY;
+
+
+//*****************************************************************************
+// This class implements a dynamic array of structures for which the insert
+// order is important. Inserts will slide all elements after the location
+// down, deletes slide all values over the deleted item. If the order of the
+// items in the array is unimportant to you, then CUnorderedArray may provide
+// the same feature set at lower cost.
+//*****************************************************************************
+class CStructArray
+{
+ BYTE *m_pList; // Pointer to the list of elements.
+ int m_iCount; // # of elements used in the list.
+ int m_iSize; // # of elements allocated in the list.
+ int m_iGrowInc; // Growth increment.
+ short m_iElemSize; // Size of an array element.
+ bool m_bFree; // true if data is automatically maintained.
+
+public:
+ CStructArray(short iElemSize, short iGrowInc = 1) :
+ m_pList(NULL),
+ m_iCount(0),
+ m_iSize(0),
+ m_iGrowInc(iGrowInc),
+ m_iElemSize(iElemSize),
+ m_bFree(true)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+ ~CStructArray()
+ {
+ WRAPPER_NO_CONTRACT;
+ Clear();
+ }
+
+ void *Insert(int iIndex);
+ void *InsertThrowing(int iIndex);
+ void *Append();
+ void *AppendThrowing();
+ int AllocateBlock(int iCount);
+ void AllocateBlockThrowing(int iCount);
+ void Delete(int iIndex);
+ void *Ptr()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_pList);
+ }
+ void *Get(int iIndex)
+ {
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(iIndex < m_iCount);
+ return ((void *) ((size_t) Ptr() + (iIndex * m_iElemSize)));
+ }
+ int Size()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_iCount * m_iElemSize);
+ }
+ int Count()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_iCount);
+ }
+ void Clear();
+ void ClearCount()
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_iCount = 0;
+ }
+
+ void InitOnMem(short iElemSize, void *pList, int iCount, int iSize, int iGrowInc=1)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_iElemSize = iElemSize;
+ m_iGrowInc = (short) iGrowInc;
+ m_pList = (BYTE*)pList;
+ m_iCount = iCount;
+ m_iSize = iSize;
+ m_bFree = false;
+ }
+
+private:
+ void Grow(int iCount);
+};
+
+
+//*****************************************************************************
+// This template simplifies access to a CStructArray by removing void * and
+// adding some operator overloads.
+//*****************************************************************************
+template <class T>
+class CDynArray : public CStructArray
+{
+public:
+ CDynArray(short iGrowInc=16) :
+ CStructArray(sizeof(T), iGrowInc)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ T *Insert(int iIndex)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ((T *)CStructArray::Insert((int)iIndex));
+ }
+
+ T *InsertThrowing(int iIndex)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ((T *)CStructArray::InsertThrowing((int)iIndex));
+ }
+
+ T *Append()
+ {
+ WRAPPER_NO_CONTRACT;
+ return ((T *)CStructArray::Append());
+ }
+
+ T *AppendThrowing()
+ {
+ WRAPPER_NO_CONTRACT;
+ return ((T *)CStructArray::AppendThrowing());
+ }
+
+ T *Ptr()
+ {
+ WRAPPER_NO_CONTRACT;
+ return ((T *)CStructArray::Ptr());
+ }
+
+ T *Get(int iIndex)
+ {
+ WRAPPER_NO_CONTRACT;
+ return (Ptr() + iIndex);
+ }
+ T &operator[](int iIndex)
+ {
+ WRAPPER_NO_CONTRACT;
+ return (*(Ptr() + iIndex));
+ }
+ int ItemIndex(T *p)
+ {
+ WRAPPER_NO_CONTRACT;
+ return (((int)(LONG_PTR)p - (int)(LONG_PTR)Ptr()) / sizeof(T));
+ }
+ void Move(int iFrom, int iTo)
+ {
+ WRAPPER_NO_CONTRACT;
+ T tmp;
+
+ _ASSERTE(iFrom >= 0 && iFrom < Count() &&
+ iTo >= 0 && iTo < Count());
+
+ tmp = *(Ptr() + iFrom);
+ if (iTo > iFrom)
+ memmove(Ptr() + iFrom, Ptr() + iFrom + 1, (iTo - iFrom) * sizeof(T));
+ else
+ memmove(Ptr() + iTo + 1, Ptr() + iTo, (iFrom - iTo) * sizeof(T));
+ *(Ptr() + iTo) = tmp;
+ }
+};
+
+// Some common arrays.
+typedef CDynArray<int> INTARRAY;
+typedef CDynArray<short> SHORTARRAY;
+typedef CDynArray<int> LONGARRAY;
+typedef CDynArray<USHORT> USHORTARRAY;
+typedef CDynArray<ULONG> ULONGARRAY;
+typedef CDynArray<BYTE> BYTEARRAY;
+typedef CDynArray<mdToken> TOKENARRAY;
+
+template <class T> class CStackArray : public CStructArray
+{
+public:
+ CStackArray(short iGrowInc=4) :
+ CStructArray(sizeof(T), iGrowInc),
+ m_curPos(0)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ void Push(T p)
+ {
+ WRAPPER_NO_CONTRACT;
+ // We should only inc m_curPos after we grow the array.
+ T *pT = (T *)CStructArray::InsertThrowing(m_curPos);
+ m_curPos ++;
+ *pT = p;
+ }
+
+ T * Pop()
+ {
+ WRAPPER_NO_CONTRACT;
+ T * retPtr;
+
+ _ASSERTE(m_curPos > 0);
+
+ retPtr = (T *)CStructArray::Get(m_curPos-1);
+ CStructArray::Delete(m_curPos--);
+
+ return (retPtr);
+ }
+
+ int Count()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return(m_curPos);
+ }
+
+private:
+ int m_curPos;
+};
+
+
+//*****************************************************************************
+// This template manages a list of free entries by their 0 based offset. By
+// making it a template, you can use whatever size free chain will match your
+// maximum count of items. -1 is reserved.
+//*****************************************************************************
+template <class T> class TFreeList
+{
+public:
+ void Init(
+ T *rgList,
+ int iCount)
+ {
+ LIMITED_METHOD_CONTRACT;
+ // Save off values.
+ m_rgList = rgList;
+ m_iCount = iCount;
+ m_iNext = 0;
+
+ // Init free list.
+ int i;
+ for (i=0; i<iCount - 1; i++)
+ m_rgList[i] = i + 1;
+ m_rgList[i] = (T) -1;
+ }
+
+ T GetFreeEntry() // Index of free item, or -1.
+ {
+ LIMITED_METHOD_CONTRACT;
+ T iNext;
+
+ if (m_iNext == (T) -1)
+ return (-1);
+
+ iNext = m_iNext;
+ m_iNext = m_rgList[m_iNext];
+ return (iNext);
+ }
+
+ void DelFreeEntry(T iEntry)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(iEntry < m_iCount);
+ m_rgList[iEntry] = m_iNext;
+ m_iNext = iEntry;
+ }
+
+ // This function can only be used when it is guaranteed that the free
+ // array is contigous, for example, right after creation to quickly
+ // get a range of items from the heap.
+ void ReserveRange(int iCount)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(iCount < m_iCount);
+ _ASSERTE(m_iNext == 0);
+ m_iNext = iCount;
+ }
+
+private:
+ T *m_rgList; // List of free info.
+ int m_iCount; // How many entries to manage.
+ T m_iNext; // Next item to get.
+};
+
+
+//*****************************************************************************
+//*****************************************************************************
+template <class T> class CQuickSort
+{
+protected:
+ T *m_pBase; // Base of array to sort.
+private:
+ SSIZE_T m_iCount; // How many items in array.
+ SSIZE_T m_iElemSize; // Size of one element.
+public:
+ CQuickSort(
+ T *pBase, // Address of first element.
+ SSIZE_T iCount) : // How many there are.
+ m_pBase(pBase),
+ m_iCount(iCount),
+ m_iElemSize(sizeof(T))
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ }
+
+//*****************************************************************************
+// Call to sort the array.
+//*****************************************************************************
+ inline void Sort()
+ {
+ WRAPPER_NO_CONTRACT;
+ SortRange(0, m_iCount - 1);
+ }
+
+protected:
+//*****************************************************************************
+// Override this function to do the comparison.
+//*****************************************************************************
+ virtual FORCEINLINE int Compare( // -1, 0, or 1
+ T *psFirst, // First item to compare.
+ T *psSecond) // Second item to compare.
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return (memcmp(psFirst, psSecond, sizeof(T)));
+// return (::Compare(*psFirst, *psSecond));
+ }
+
+ virtual FORCEINLINE void Swap(
+ SSIZE_T iFirst,
+ SSIZE_T iSecond)
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ if (iFirst == iSecond) return;
+ T sTemp( m_pBase[iFirst] );
+ m_pBase[iFirst] = m_pBase[iSecond];
+ m_pBase[iSecond] = sTemp;
+ }
+
+private:
+ inline void SortRange(
+ SSIZE_T iLeft,
+ SSIZE_T iRight)
+ {
+ WRAPPER_NO_CONTRACT;
+ SSIZE_T iLast;
+ SSIZE_T i; // loop variable.
+
+ for (;;)
+ {
+ // if less than two elements you're done.
+ if (iLeft >= iRight)
+ return;
+
+ // ASSERT that we now have valid indicies. This is statically provable
+ // since this private function is only called with valid indicies,
+ // and iLeft and iRight only converge towards eachother. However,
+ // PreFast can't detect this because it doesn't know about our callers.
+ COMPILER_ASSUME(iLeft >= 0 && iLeft < m_iCount);
+ COMPILER_ASSUME(iRight >= 0 && iRight < m_iCount);
+
+ // The mid-element is the pivot, move it to the left.
+ Swap(iLeft, (iLeft + iRight) / 2);
+ iLast = iLeft;
+
+ // move everything that is smaller than the pivot to the left.
+ for (i = iLeft + 1; i <= iRight; i++)
+ {
+ if (Compare(&m_pBase[i], &m_pBase[iLeft]) < 0)
+ {
+ Swap(i, ++iLast);
+ }
+ }
+
+ // Put the pivot to the point where it is in between smaller and larger elements.
+ Swap(iLeft, iLast);
+
+ // Sort each partition.
+ SSIZE_T iLeftLast = iLast - 1;
+ SSIZE_T iRightFirst = iLast + 1;
+ if (iLeftLast - iLeft < iRight - iRightFirst)
+ { // Left partition is smaller, sort it recursively
+ SortRange(iLeft, iLeftLast);
+ // Tail call to sort the right (bigger) partition
+ iLeft = iRightFirst;
+ //iRight = iRight;
+ continue;
+ }
+ else
+ { // Right partition is smaller, sort it recursively
+ SortRange(iRightFirst, iRight);
+ // Tail call to sort the left (bigger) partition
+ //iLeft = iLeft;
+ iRight = iLeftLast;
+ continue;
+ }
+ }
+ }
+};
+
+//*****************************************************************************
+// Faster and simpler version of the binary search below.
+//*****************************************************************************
+template <class T>
+const T * BinarySearch(const T * pBase, int iCount, const T & find)
+{
+ WRAPPER_NO_CONTRACT;
+
+ int iFirst = 0;
+ int iLast = iCount - 1;
+
+ // It is faster to use linear search once we get down to a small number of elements.
+ while (iLast - iFirst > 10)
+ {
+ int iMid = (iLast + iFirst) / 2;
+
+ if (find < pBase[iMid])
+ iLast = iMid - 1;
+ else
+ iFirst = iMid;
+ }
+
+ for (int i = iFirst; i <= iLast; i++)
+ {
+ if (find == pBase[i])
+ return &pBase[i];
+
+ if (find < pBase[i])
+ break;
+ }
+
+ return NULL;
+}
+
+//*****************************************************************************
+// This template encapsulates a binary search algorithm on the given type
+// of data.
+//*****************************************************************************
+template <class T> class CBinarySearch
+{
+private:
+ const T *m_pBase; // Base of array to sort.
+ int m_iCount; // How many items in array.
+
+public:
+ CBinarySearch(
+ const T *pBase, // Address of first element.
+ int iCount) : // Value to find.
+ m_pBase(pBase),
+ m_iCount(iCount)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+//*****************************************************************************
+// Searches for the item passed to ctor.
+//*****************************************************************************
+ const T *Find( // Pointer to found item in array.
+ const T *psFind, // The key to find.
+ int *piInsert = NULL) // Index to insert at.
+ {
+ WRAPPER_NO_CONTRACT;
+ int iMid, iFirst, iLast; // Loop control.
+ int iCmp; // Comparison.
+
+ iFirst = 0;
+ iLast = m_iCount - 1;
+ while (iFirst <= iLast)
+ {
+ iMid = (iLast + iFirst) / 2;
+ iCmp = Compare(psFind, &m_pBase[iMid]);
+ if (iCmp == 0)
+ {
+ if (piInsert != NULL)
+ *piInsert = iMid;
+ return (&m_pBase[iMid]);
+ }
+ else if (iCmp < 0)
+ iLast = iMid - 1;
+ else
+ iFirst = iMid + 1;
+ }
+ if (piInsert != NULL)
+ *piInsert = iFirst;
+ return (NULL);
+ }
+
+//*****************************************************************************
+// Override this function to do the comparison if a comparison operator is
+// not valid for your data type (such as a struct).
+//*****************************************************************************
+ virtual int Compare( // -1, 0, or 1
+ const T *psFirst, // Key you are looking for.
+ const T *psSecond) // Item to compare to.
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (memcmp(psFirst, psSecond, sizeof(T)));
+// return (::Compare(*psFirst, *psSecond));
+ }
+};
+
+//*****************************************************************************
+// The information that the hash table implementation stores at the beginning
+// of every record that can be but in the hash table.
+//*****************************************************************************
+typedef DPTR(struct HASHENTRY) PTR_HASHENTRY;
+struct HASHENTRY
+{
+ ULONG iPrev; // Previous bucket in the chain.
+ ULONG iNext; // Next bucket in the chain.
+};
+
+typedef DPTR(struct FREEHASHENTRY) PTR_FREEHASHENTRY;
+struct FREEHASHENTRY : HASHENTRY
+{
+ ULONG iFree;
+};
+
+//*****************************************************************************
+// Used by the FindFirst/FindNextEntry functions. These api's allow you to
+// do a sequential scan of all entries.
+//*****************************************************************************
+struct HASHFIND
+{
+ ULONG iBucket; // The next bucket to look in.
+ ULONG iNext;
+};
+
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+// This is a class that implements a chain and bucket hash table.
+//
+// The data is actually supplied as an array of structures by the user of this class.
+// This allows the buckets to use small indices to point to the chain, instead of pointers.
+//
+// Each entry in the array contains a HASHENTRY structure immediately
+// followed by the key used to hash the structure.
+//
+// The HASHENTRY part of every structure is used to implement the chain of
+// entries in a single bucket.
+//
+// This implementation does not support rehashing the buckets if the table grows
+// to big.
+// @TODO: Fix this by adding an abstract function Hash() which must be implemented
+// by all clients.
+//
+//*****************************************************************************
+class CHashTable
+{
+ friend class DebuggerRCThread; //RCthread actually needs access to
+ //fields of derrived class DebuggerPatchTable
+
+protected:
+ TADDR m_pcEntries; // Pointer to the array of structs.
+ ULONG m_iEntrySize; // Size of the structs.
+
+ ULONG m_iBuckets; // # of chains we are hashing into.
+ PTR_ULONG m_piBuckets; // Ptr to the array of bucket chains.
+
+ INDEBUG(unsigned m_maxSearch;) // For evaluating perf characteristics
+
+ HASHENTRY *EntryPtr(ULONG iEntry)
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return (PTR_HASHENTRY(m_pcEntries + (iEntry * m_iEntrySize)));
+ }
+
+ ULONG ItemIndex(HASHENTRY *p)
+ {
+ SUPPORTS_DAC;
+ LIMITED_METHOD_CONTRACT;
+ return (ULONG)((dac_cast<TADDR>(p) - m_pcEntries) / m_iEntrySize);
+ }
+
+
+public:
+
+ CHashTable(
+ ULONG iBuckets) : // # of chains we are hashing into.
+ m_pcEntries((TADDR)NULL),
+ m_iBuckets(iBuckets)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_piBuckets = NULL;
+
+ INDEBUG(m_maxSearch = 0;)
+ }
+
+ CHashTable() : // # of chains we are hashing into.
+ m_pcEntries((TADDR)NULL),
+ m_iBuckets(5)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_piBuckets = NULL;
+
+ INDEBUG(m_maxSearch = 0;)
+ }
+
+#ifndef DACCESS_COMPILE
+
+ ~CHashTable()
+ {
+ LIMITED_METHOD_CONTRACT;
+ if (m_piBuckets != NULL)
+ {
+ delete [] m_piBuckets;
+ m_piBuckets = NULL;
+ }
+ }
+
+//*****************************************************************************
+// This is the second part of construction where we do all of the work that
+// can fail. We also take the array of structs here because the calling class
+// presumably needs to allocate it in its NewInit.
+//*****************************************************************************
+ HRESULT NewInit( // Return status.
+ BYTE *pcEntries, // Array of structs we are managing.
+ ULONG iEntrySize); // Size of the entries.
+
+//*****************************************************************************
+// This can be called to change the pointer to the table that the hash table
+// is managing. You might call this if (for example) you realloc the size
+// of the table and its pointer is different.
+//*****************************************************************************
+ void SetTable(
+ BYTE *pcEntries) // Array of structs we are managing.
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pcEntries = (TADDR)pcEntries;
+ }
+
+//*****************************************************************************
+// Clear the hash table as if there were nothing in it.
+//*****************************************************************************
+ void Clear()
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(m_piBuckets != NULL);
+ memset(m_piBuckets, 0xff, m_iBuckets * sizeof(ULONG));
+ }
+
+//*****************************************************************************
+// Add the struct at the specified index in m_pcEntries to the hash chains.
+//*****************************************************************************
+ BYTE *Add( // New entry.
+ ULONG iHash, // Hash value of entry to add.
+ ULONG iIndex); // Index of struct in m_pcEntries.
+
+//*****************************************************************************
+// Delete the struct at the specified index in m_pcEntries from the hash chains.
+//*****************************************************************************
+ void Delete(
+ ULONG iHash, // Hash value of entry to delete.
+ ULONG iIndex); // Index of struct in m_pcEntries.
+
+ void Delete(
+ ULONG iHash, // Hash value of entry to delete.
+ HASHENTRY *psEntry); // The struct to delete.
+
+//*****************************************************************************
+// The item at the specified index has been moved, update the previous and
+// next item.
+//*****************************************************************************
+ void Move(
+ ULONG iHash, // Hash value for the item.
+ ULONG iNew); // New location.
+
+#endif // #ifndef DACCESS_COMPILE
+
+//*****************************************************************************
+// Return a boolean indicating whether or not this hash table has been inited.
+//*****************************************************************************
+ int IsInited()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_piBuckets != NULL);
+ }
+
+//*****************************************************************************
+// Search the hash table for an entry with the specified key value.
+//*****************************************************************************
+ BYTE *Find( // Index of struct in m_pcEntries.
+ ULONG iHash, // Hash value of the item.
+ SIZE_T key); // The key to match.
+
+//*****************************************************************************
+// Search the hash table for the next entry with the specified key value.
+//*****************************************************************************
+ ULONG FindNext( // Index of struct in m_pcEntries.
+ SIZE_T key, // The key to match.
+ ULONG iIndex); // Index of previous match.
+
+//*****************************************************************************
+// Returns the first entry in the first hash bucket and inits the search
+// struct. Use the FindNextEntry function to continue walking the list. The
+// return order is not gauranteed.
+//*****************************************************************************
+ BYTE *FindFirstEntry( // First entry found, or 0.
+ HASHFIND *psSrch) // Search object.
+ {
+ WRAPPER_NO_CONTRACT;
+ if (m_piBuckets == 0)
+ return (0);
+ psSrch->iBucket = 1;
+ psSrch->iNext = m_piBuckets[0];
+ return (FindNextEntry(psSrch));
+ }
+
+//*****************************************************************************
+// Returns the next entry in the list.
+//*****************************************************************************
+ BYTE *FindNextEntry( // The next entry, or0 for end of list.
+ HASHFIND *psSrch); // Search object.
+
+#ifdef DACCESS_COMPILE
+ void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
+ ULONG numEntries);
+#endif
+
+protected:
+ virtual BOOL Cmp(SIZE_T key1, const HASHENTRY * pc2) = 0;
+};
+
+
+class CNewData
+{
+public:
+ static BYTE *Alloc(int iSize, int iMaxSize)
+ {
+ WRAPPER_NO_CONTRACT;
+ return (new BYTE[iSize]);
+ }
+ static void Free(BYTE *pPtr, int iSize)
+ {
+ LIMITED_METHOD_CONTRACT;
+ delete [] pPtr;
+ }
+ static BYTE *Grow(BYTE *&pPtr, int iCurSize)
+ {
+ WRAPPER_NO_CONTRACT;
+ BYTE *p;
+ S_SIZE_T newSize = S_SIZE_T(iCurSize) + S_SIZE_T(GrowSize(iCurSize));
+ //check for overflow
+ if(newSize.IsOverflow())
+ p = NULL;
+ else
+ p = new (nothrow) BYTE[newSize.Value()];
+ if (p == 0) return (0);
+ memcpy (p, pPtr, iCurSize);
+ delete [] pPtr;
+ pPtr = p;
+ return pPtr;
+ }
+ static void Clean(BYTE * pData, int iSize)
+ {
+ }
+ static int RoundSize(int iSize)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (iSize);
+ }
+ static int GrowSize(int iCurSize)
+ {
+ LIMITED_METHOD_CONTRACT;
+ int newSize = (3 * iCurSize) / 2;
+ return (newSize < 256) ? 256 : newSize;
+ }
+};
+
+class CNewDataNoThrow
+{
+public:
+ static BYTE *Alloc(int iSize, int iMaxSize)
+ {
+ WRAPPER_NO_CONTRACT;
+ return (new (nothrow) BYTE[iSize]);
+ }
+ static void Free(BYTE *pPtr, int iSize)
+ {
+ LIMITED_METHOD_CONTRACT;
+ delete [] pPtr;
+ }
+ static BYTE *Grow(BYTE *&pPtr, int iCurSize)
+ {
+ WRAPPER_NO_CONTRACT;
+ BYTE *p;
+ S_SIZE_T newSize = S_SIZE_T(iCurSize) + S_SIZE_T(GrowSize(iCurSize));
+ //check for overflow
+ if(newSize.IsOverflow())
+ p = NULL;
+ else
+ p = new (nothrow) BYTE[newSize.Value()];
+ if (p == 0) return (0);
+ memcpy (p, pPtr, iCurSize);
+ delete [] pPtr;
+ pPtr = p;
+ return pPtr;
+ }
+ static void Clean(BYTE * pData, int iSize)
+ {
+ }
+ static int RoundSize(int iSize)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (iSize);
+ }
+ static int GrowSize(int iCurSize)
+ {
+ LIMITED_METHOD_CONTRACT;
+ int newSize = (3 * iCurSize) / 2;
+ return (newSize < 256) ? 256 : newSize;
+ }
+};
+
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+// CHashTable expects the data to be in a single array - this is provided by
+// CHashTableAndData.
+// The array is allocated using the MemMgr type. CNewData and
+// CNewDataNoThrow can be used for this.
+//*****************************************************************************
+template <class MemMgr>
+class CHashTableAndData : public CHashTable
+{
+public:
+ ULONG m_iFree; // Index into m_pcEntries[] of next available slot
+ ULONG m_iEntries; // size of m_pcEntries[]
+
+public:
+
+ CHashTableAndData() :
+ CHashTable()
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ CHashTableAndData(
+ ULONG iBuckets) : // # of chains we are hashing into.
+ CHashTable(iBuckets)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+#ifndef DACCESS_COMPILE
+
+ ~CHashTableAndData()
+ {
+ WRAPPER_NO_CONTRACT;
+ if (m_pcEntries != NULL)
+ MemMgr::Free((BYTE*)m_pcEntries, MemMgr::RoundSize(m_iEntries * m_iEntrySize));
+ }
+
+//*****************************************************************************
+// This is the second part of construction where we do all of the work that
+// can fail. We also take the array of structs here because the calling class
+// presumably needs to allocate it in its NewInit.
+//*****************************************************************************
+ HRESULT NewInit( // Return status.
+ ULONG iEntries, // # of entries.
+ ULONG iEntrySize, // Size of the entries.
+ int iMaxSize); // Max size of data.
+
+//*****************************************************************************
+// Clear the hash table as if there were nothing in it.
+//*****************************************************************************
+ void Clear()
+ {
+ WRAPPER_NO_CONTRACT;
+ m_iFree = 0;
+ InitFreeChain(0, m_iEntries);
+ CHashTable::Clear();
+ }
+
+//*****************************************************************************
+// Grabs a slot for the new entry to be added.
+// The caller should fill in the non-HASHENTRY part of the returned slot
+//*****************************************************************************
+ BYTE *Add(
+ ULONG iHash) // Hash value of entry to add.
+ {
+ WRAPPER_NO_CONTRACT;
+ FREEHASHENTRY *psEntry;
+
+ // Make the table bigger if necessary.
+ if (m_iFree == UINT32_MAX && !Grow())
+ return (NULL);
+
+ // Add the first entry from the free list to the hash chain.
+ psEntry = (FREEHASHENTRY *) CHashTable::Add(iHash, m_iFree);
+ m_iFree = psEntry->iFree;
+
+ // If we're recycling memory, give our memory-allocator a chance to re-init it.
+
+ // Each entry is prefixed with a header - we don't want to trash that.
+ SIZE_T cbHeader = sizeof(FREEHASHENTRY);
+ MemMgr::Clean((BYTE*) psEntry + cbHeader, (int) (m_iEntrySize - cbHeader));
+
+ return ((BYTE *) psEntry);
+ }
+
+//*****************************************************************************
+// Delete the struct at the specified index in m_pcEntries from the hash chains.
+//*****************************************************************************
+ void Delete(
+ ULONG iHash, // Hash value of entry to delete.
+ ULONG iIndex) // Index of struct in m_pcEntries.
+ {
+ WRAPPER_NO_CONTRACT;
+ CHashTable::Delete(iHash, iIndex);
+ ((FREEHASHENTRY *) EntryPtr(iIndex))->iFree = m_iFree;
+ m_iFree = iIndex;
+ }
+
+ void Delete(
+ ULONG iHash, // Hash value of entry to delete.
+ HASHENTRY *psEntry) // The struct to delete.
+ {
+ WRAPPER_NO_CONTRACT;
+ CHashTable::Delete(iHash, psEntry);
+ ((FREEHASHENTRY *) psEntry)->iFree = m_iFree;
+ m_iFree = ItemIndex(psEntry);
+ }
+
+#endif // #ifndef DACCESS_COMPILE
+
+ // This is a sad legacy workaround. The debugger's patch table (implemented as this
+ // class) is shared across process. We publish the runtime offsets of
+ // some key fields. Since those fields are private, we have to provide
+ // accessors here. So if you're not using these functions, don't start.
+ // We can hopefully remove them.
+ // Note that we can't just make RCThread a friend of this class (we tried
+ // originally) because the inheritence chain has a private modifier,
+ // so DebuggerPatchTable::m_pcEntries is illegal.
+ static SIZE_T helper_GetOffsetOfEntries()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return offsetof(CHashTableAndData, m_pcEntries);
+ }
+
+ static SIZE_T helper_GetOffsetOfCount()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return offsetof(CHashTableAndData, m_iEntries);
+ }
+
+#ifdef DACCESS_COMPILE
+ void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+ {
+ SUPPORTS_DAC;
+ CHashTable::EnumMemoryRegions(flags, m_iEntries);
+ }
+#endif
+
+private:
+ void InitFreeChain(ULONG iStart,ULONG iEnd);
+ int Grow();
+};
+
+#ifndef DACCESS_COMPILE
+
+//*****************************************************************************
+// This is the second part of construction where we do all of the work that
+// can fail. We also take the array of structs here because the calling class
+// presumably needs to allocate it in its NewInit.
+//*****************************************************************************
+template<class MemMgr>
+HRESULT CHashTableAndData<MemMgr>::NewInit(// Return status.
+ ULONG iEntries, // # of entries.
+ ULONG iEntrySize, // Size of the entries.
+ int iMaxSize) // Max size of data.
+{
+ WRAPPER_NO_CONTRACT;
+ BYTE *pcEntries;
+ HRESULT hr;
+
+
+ // note that this function can throw because it depends on the <M>::Alloc
+
+ // Allocate the memory for the entries.
+ if ((pcEntries = MemMgr::Alloc(MemMgr::RoundSize(iEntries * iEntrySize),
+ MemMgr::RoundSize(iMaxSize))) == 0)
+ return (E_OUTOFMEMORY);
+ m_iEntries = iEntries;
+
+ // Init the base table.
+ if (FAILED(hr = CHashTable::NewInit(pcEntries, iEntrySize)))
+ MemMgr::Free(pcEntries, MemMgr::RoundSize(iEntries * iEntrySize));
+ else
+ {
+ // Init the free chain.
+ m_iFree = 0;
+ InitFreeChain(0, iEntries);
+ }
+ return (hr);
+}
+
+//*****************************************************************************
+// Initialize a range of records such that they are linked together to be put
+// on the free chain.
+//*****************************************************************************
+template<class MemMgr>
+void CHashTableAndData<MemMgr>::InitFreeChain(
+ ULONG iStart, // Index to start initializing.
+ ULONG iEnd) // Index to stop initializing
+{
+ LIMITED_METHOD_CONTRACT;
+ BYTE* pcPtr;
+ _ASSERTE(iEnd > iStart);
+
+ pcPtr = (BYTE*)m_pcEntries + iStart * m_iEntrySize;
+ for (++iStart; iStart < iEnd; ++iStart)
+ {
+ ((FREEHASHENTRY *) pcPtr)->iFree = iStart;
+ pcPtr += m_iEntrySize;
+ }
+ ((FREEHASHENTRY *) pcPtr)->iFree = UINT32_MAX;
+}
+
+//*****************************************************************************
+// Attempt to increase the amount of space available for the record heap.
+//*****************************************************************************
+template<class MemMgr>
+int CHashTableAndData<MemMgr>::Grow() // 1 if successful, 0 if not.
+{
+ WRAPPER_NO_CONTRACT;
+ int iCurSize; // Current size in bytes.
+ int iEntries; // New # of entries.
+
+ _ASSERTE(m_pcEntries != NULL);
+ _ASSERTE(m_iFree == UINT32_MAX);
+
+ // Compute the current size and new # of entries.
+ S_UINT32 iTotEntrySize = S_UINT32(m_iEntries) * S_UINT32(m_iEntrySize);
+ if( iTotEntrySize.IsOverflow() )
+ {
+ _ASSERTE( !"CHashTableAndData overflow!" );
+ return (0);
+ }
+ iCurSize = MemMgr::RoundSize( iTotEntrySize.Value() );
+ iEntries = (iCurSize + MemMgr::GrowSize(iCurSize)) / m_iEntrySize;
+
+ if ( (iEntries < 0) || ((ULONG)iEntries <= m_iEntries) )
+ {
+ _ASSERTE( !"CHashTableAndData overflow!" );
+ return (0);
+ }
+
+ // Try to expand the array.
+ if (MemMgr::Grow(*(BYTE**)&m_pcEntries, iCurSize) == 0)
+ return (0);
+
+ // Init the newly allocated space.
+ InitFreeChain(m_iEntries, iEntries);
+ m_iFree = m_iEntries;
+ m_iEntries = iEntries;
+ return (1);
+}
+
+#endif // #ifndef DACCESS_COMPILE
+
+//*****************************************************************************
+//*****************************************************************************
+
+inline COUNT_T HashCOUNT_T(COUNT_T currentHash, COUNT_T data)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+ return ((currentHash << 5) + currentHash) ^ data;
+}
+
+inline COUNT_T HashPtr(COUNT_T currentHash, PTR_VOID ptr)
+{
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+ return HashCOUNT_T(currentHash, COUNT_T(SIZE_T(dac_cast<TADDR>(ptr))));
+}
+
+inline DWORD HashThreeToOne(DWORD a, DWORD b, DWORD c)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ /*
+ lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+ These are functions for producing 32-bit hashes for hash table lookup.
+ hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+ are externally useful functions. Routines to test the hash are included
+ if SELF_TEST is defined. You can use this free for any purpose. It's in
+ the public domain. It has no warranty.
+ */
+
+ #define rot32(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+ c ^= b; c -= rot32(b,14);
+ a ^= c; a -= rot32(c,11);
+ b ^= a; b -= rot32(a,25);
+ c ^= b; c -= rot32(b,16);
+ a ^= c; a -= rot32(c,4);
+ b ^= a; b -= rot32(a,14);
+ c ^= b; c -= rot32(b,24);
+
+ return c;
+}
+
+inline ULONG HashBytes(BYTE const *pbData, size_t iSize)
+{
+ LIMITED_METHOD_CONTRACT;
+ ULONG hash = 5381;
+
+ BYTE const *pbDataEnd = pbData + iSize;
+
+ for (/**/ ; pbData < pbDataEnd; pbData++)
+ {
+ hash = ((hash << 5) + hash) ^ *pbData;
+ }
+ return hash;
+}
+
+// Helper function for hashing a string char by char.
+inline ULONG HashStringA(LPCSTR szStr)
+{
+ LIMITED_METHOD_CONTRACT;
+ ULONG hash = 5381;
+ int c;
+
+ while ((c = *szStr) != 0)
+ {
+ hash = ((hash << 5) + hash) ^ c;
+ ++szStr;
+ }
+ return hash;
+}
+
+inline ULONG HashString(LPCWSTR szStr)
+{
+ LIMITED_METHOD_CONTRACT;
+ ULONG hash = 5381;
+ int c;
+
+ while ((c = *szStr) != 0)
+ {
+ hash = ((hash << 5) + hash) ^ c;
+ ++szStr;
+ }
+ return hash;
+}
+
+inline ULONG HashStringN(LPCWSTR szStr, SIZE_T cchStr)
+{
+ LIMITED_METHOD_CONTRACT;
+ ULONG hash = 5381;
+
+ // hash the string two characters at a time
+ ULONG *ptr = (ULONG *)szStr;
+
+ // we assume that szStr is null-terminated
+ _ASSERTE(cchStr <= wcslen(szStr));
+ SIZE_T cDwordCount = (cchStr + 1) / 2;
+
+ for (SIZE_T i = 0; i < cDwordCount; i++)
+ {
+ hash = ((hash << 5) + hash) ^ ptr[i];
+ }
+
+ return hash;
+}
+
+// Case-insensitive string hash function.
+inline ULONG HashiStringA(LPCSTR szStr)
+{
+ LIMITED_METHOD_CONTRACT;
+ ULONG hash = 5381;
+ while (*szStr != 0)
+ {
+ hash = ((hash << 5) + hash) ^ toupper(*szStr);
+ szStr++;
+ }
+ return hash;
+}
+
+// Case-insensitive string hash function.
+inline ULONG HashiString(LPCWSTR szStr)
+{
+ LIMITED_METHOD_CONTRACT;
+ ULONG hash = 5381;
+ while (*szStr != 0)
+ {
+ hash = ((hash << 5) + hash) ^ towupper(*szStr);
+ szStr++;
+ }
+ return hash;
+}
+
+// Case-insensitive string hash function.
+inline ULONG HashiStringN(LPCWSTR szStr, DWORD count)
+{
+ LIMITED_METHOD_CONTRACT;
+ ULONG hash = 5381;
+ while (*szStr != 0 && count--)
+ {
+ hash = ((hash << 5) + hash) ^ towupper(*szStr);
+ szStr++;
+ }
+ return hash;
+}
+
+// Case-insensitive string hash function when all of the
+// characters in the string are known to be below 0x80.
+// Knowing this is much more efficient than calling
+// towupper above.
+inline ULONG HashiStringKnownLower80(LPCWSTR szStr) {
+ LIMITED_METHOD_CONTRACT;
+ ULONG hash = 5381;
+ int c;
+ int mask = ~0x20;
+ while ((c = *szStr)!=0) {
+ //If we have a lowercase character, ANDing off 0x20
+ //(mask) will make it an uppercase character.
+ if (c>='a' && c<='z') {
+ c&=mask;
+ }
+ hash = ((hash << 5) + hash) ^ c;
+ ++szStr;
+ }
+ return hash;
+}
+
+inline ULONG HashiStringNKnownLower80(LPCWSTR szStr, DWORD count) {
+ LIMITED_METHOD_CONTRACT;
+ ULONG hash = 5381;
+ int c;
+ int mask = ~0x20;
+ while ((c = *szStr) !=0 && count--) {
+ //If we have a lowercase character, ANDing off 0x20
+ //(mask) will make it an uppercase character.
+ if (c>='a' && c<='z') {
+ c&=mask;
+ }
+ hash = ((hash << 5) + hash) ^ c;
+ ++szStr;
+ }
+ return hash;
+}
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+// This class implements a closed hashing table. Values are hashed to a bucket,
+// and if that bucket is full already, then the value is placed in the next
+// free bucket starting after the desired target (with wrap around). If the
+// table becomes 75% full, it is grown and rehashed to reduce lookups. This
+// class is best used in a reltively small lookup table where hashing is
+// not going to cause many collisions. By not having the collision chain
+// logic, a lot of memory is saved.
+//
+// The user of the template is required to supply several methods which decide
+// how each element can be marked as free, deleted, or used. It would have
+// been possible to write this with more internal logic, but that would require
+// either (a) more overhead to add status on top of elements, or (b) hard
+// coded types like one for strings, one for ints, etc... This gives you the
+// flexibility of adding logic to your type.
+//*****************************************************************************
+class CClosedHashBase
+{
+ BYTE *EntryPtr(int iEntry)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_rgData + (iEntry * m_iEntrySize));
+ }
+
+ BYTE *EntryPtr(int iEntry, BYTE *rgData)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (rgData + (iEntry * m_iEntrySize));
+ }
+
+public:
+ enum ELEMENTSTATUS
+ {
+ FREE, // Item is not in use right now.
+ DELETED, // Item is deleted.
+ USED // Item is in use.
+ };
+
+ CClosedHashBase(
+ int iBuckets, // How many buckets should we start with.
+ int iEntrySize, // Size of an entry.
+ bool bPerfect) : // true if bucket size will hash with no collisions.
+ m_bPerfect(bPerfect),
+ m_iBuckets(iBuckets),
+ m_iEntrySize(iEntrySize),
+ m_iCount(0),
+ m_iCollisions(0),
+ m_rgData(0)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_iSize = iBuckets + 7;
+ }
+
+ ~CClosedHashBase()
+ {
+ WRAPPER_NO_CONTRACT;
+ Clear();
+ }
+
+ virtual void Clear()
+ {
+ LIMITED_METHOD_CONTRACT;
+ delete [] m_rgData;
+ m_iCount = 0;
+ m_iCollisions = 0;
+ m_rgData = 0;
+ }
+
+//*****************************************************************************
+// Accessors for getting at the underlying data. Be careful to use Count()
+// only when you want the number of buckets actually used.
+//*****************************************************************************
+
+ int Count()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_iCount);
+ }
+
+ int Collisions()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_iCollisions);
+ }
+
+ int Buckets()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_iBuckets);
+ }
+
+ void SetBuckets(int iBuckets, bool bPerfect=false)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(m_rgData == 0);
+ m_iBuckets = iBuckets;
+ m_iSize = m_iBuckets + 7;
+ m_bPerfect = bPerfect;
+ }
+
+ BYTE *Data()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_rgData);
+ }
+
+//*****************************************************************************
+// Add a new item to hash table given the key value. If this new entry
+// exceeds maximum size, then the table will grow and be re-hashed, which
+// may cause a memory error.
+//*****************************************************************************
+ BYTE *Add( // New item to fill out on success.
+ void *pData) // The value to hash on.
+ {
+ WRAPPER_NO_CONTRACT;
+ // If we haven't allocated any memory, or it is too small, fix it.
+ if (!m_rgData || ((m_iCount + 1) > (m_iSize * 3 / 4) && !m_bPerfect))
+ {
+ if (!ReHash())
+ return (0);
+ }
+
+ return (DoAdd(pData, m_rgData, m_iBuckets, m_iSize, m_iCollisions, m_iCount));
+ }
+
+//*****************************************************************************
+// Delete the given value. This will simply mark the entry as deleted (in
+// order to keep the collision chain intact). There is an optimization that
+// consecutive deleted entries leading up to a free entry are themselves freed
+// to reduce collisions later on.
+//*****************************************************************************
+ void Delete(
+ void *pData); // Key value to delete.
+
+
+//*****************************************************************************
+// Callback function passed to DeleteLoop.
+//*****************************************************************************
+ typedef BOOL (* DELETELOOPFUNC)( // Delete current item?
+ BYTE *pEntry, // Bucket entry to evaluate
+ void *pCustomizer); // User-defined value
+
+//*****************************************************************************
+// Iterates over all active values, passing each one to pDeleteLoopFunc.
+// If pDeleteLoopFunc returns TRUE, the entry is deleted. This is safer
+// and faster than using FindNext() and Delete().
+//*****************************************************************************
+ void DeleteLoop(
+ DELETELOOPFUNC pDeleteLoopFunc, // Decides whether to delete item
+ void *pCustomizer); // Extra value passed to deletefunc.
+
+
+//*****************************************************************************
+// Lookup a key value and return a pointer to the element if found.
+//*****************************************************************************
+ BYTE *Find( // The item if found, 0 if not.
+ void *pData); // The key to lookup.
+
+//*****************************************************************************
+// Look for an item in the table. If it isn't found, then create a new one and
+// return that.
+//*****************************************************************************
+ BYTE *FindOrAdd( // The item if found, 0 if not.
+ void *pData, // The key to lookup.
+ bool &bNew); // true if created.
+
+//*****************************************************************************
+// The following functions are used to traverse each used entry. This code
+// will skip over deleted and free entries freeing the caller up from such
+// logic.
+//*****************************************************************************
+ BYTE *GetFirst() // The first entry, 0 if none.
+ {
+ WRAPPER_NO_CONTRACT;
+ int i; // Loop control.
+
+ // If we've never allocated the table there can't be any to get.
+ if (m_rgData == 0)
+ return (0);
+
+ // Find the first one.
+ for (i=0; i<m_iSize; i++)
+ {
+ if (Status(EntryPtr(i)) != FREE && Status(EntryPtr(i)) != DELETED)
+ return (EntryPtr(i));
+ }
+ return (0);
+ }
+
+ BYTE *GetNext(BYTE *Prev) // The next entry, 0 if done.
+ {
+ WRAPPER_NO_CONTRACT;
+ int i; // Loop control.
+
+ for (i = (int)(((size_t) Prev - (size_t) &m_rgData[0]) / m_iEntrySize) + 1; i<m_iSize; i++)
+ {
+ if (Status(EntryPtr(i)) != FREE && Status(EntryPtr(i)) != DELETED)
+ return (EntryPtr(i));
+ }
+ return (0);
+ }
+
+private:
+//*****************************************************************************
+// Hash is called with a pointer to an element in the table. You must override
+// this method and provide a hash algorithm for your element type.
+//*****************************************************************************
+ virtual unsigned int Hash( // The key value.
+ void const *pData)=0; // Raw data to hash.
+
+//*****************************************************************************
+// Compare is used in the typical memcmp way, 0 is eqaulity, -1/1 indicate
+// direction of miscompare. In this system everything is always equal or not.
+//*****************************************************************************
+ virtual unsigned int Compare( // 0, -1, or 1.
+ void const *pData, // Raw key data on lookup.
+ BYTE *pElement)=0; // The element to compare data against.
+
+//*****************************************************************************
+// Return true if the element is free to be used.
+//*****************************************************************************
+ virtual ELEMENTSTATUS Status( // The status of the entry.
+ BYTE *pElement)=0; // The element to check.
+
+//*****************************************************************************
+// Sets the status of the given element.
+//*****************************************************************************
+ virtual void SetStatus(
+ BYTE *pElement, // The element to set status for.
+ ELEMENTSTATUS eStatus)=0; // New status.
+
+//*****************************************************************************
+// Returns the internal key value for an element.
+//*****************************************************************************
+ virtual void *GetKey( // The data to hash on.
+ BYTE *pElement)=0; // The element to return data ptr for.
+
+//*****************************************************************************
+// This helper actually does the add for you.
+//*****************************************************************************
+ BYTE *DoAdd(void *pData, BYTE *rgData, int &iBuckets, int iSize,
+ int &iCollisions, int &iCount);
+
+//*****************************************************************************
+// This function is called either to init the table in the first place, or
+// to rehash the table if we ran out of room.
+//*****************************************************************************
+ bool ReHash(); // true if successful.
+
+//*****************************************************************************
+// Walk each item in the table and mark it free.
+//*****************************************************************************
+ void InitFree(BYTE *ptr, int iSize)
+ {
+ WRAPPER_NO_CONTRACT;
+ int i;
+ for (i=0; i<iSize; i++, ptr += m_iEntrySize)
+ SetStatus(ptr, FREE);
+ }
+
+private:
+ bool m_bPerfect; // true if the table size guarantees
+ // no collisions.
+ int m_iBuckets; // How many buckets do we have.
+ int m_iEntrySize; // Size of an entry.
+ int m_iSize; // How many elements can we have.
+ int m_iCount; // How many items cannot be used (NON free, i.e. USED+DELETED).
+ int m_iCollisions; // How many have we had.
+ BYTE *m_rgData; // Data element list.
+};
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+template <class T> class CClosedHash : public CClosedHashBase
+{
+public:
+ CClosedHash(
+ int iBuckets, // How many buckets should we start with.
+ bool bPerfect=false) : // true if bucket size will hash with no collisions.
+ CClosedHashBase(iBuckets, sizeof(T), bPerfect)
+ {
+ WRAPPER_NO_CONTRACT;
+ }
+
+ T &operator[](int iIndex)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ((T &) *(Data() + (iIndex * sizeof(T))));
+ }
+
+
+//*****************************************************************************
+// Add a new item to hash table given the key value. If this new entry
+// exceeds maximum size, then the table will grow and be re-hashed, which
+// may cause a memory error.
+//*****************************************************************************
+ T *Add( // New item to fill out on success.
+ void *pData) // The value to hash on.
+ {
+ WRAPPER_NO_CONTRACT;
+ return ((T *) CClosedHashBase::Add(pData));
+ }
+
+//*****************************************************************************
+// Lookup a key value and return a pointer to the element if found.
+//*****************************************************************************
+ T *Find( // The item if found, 0 if not.
+ void *pData) // The key to lookup.
+ {
+ WRAPPER_NO_CONTRACT;
+ return ((T *) CClosedHashBase::Find(pData));
+ }
+
+//*****************************************************************************
+// Look for an item in the table. If it isn't found, then create a new one and
+// return that.
+//*****************************************************************************
+ T *FindOrAdd( // The item if found, 0 if not.
+ void *pData, // The key to lookup.
+ bool &bNew) // true if created.
+ {
+ WRAPPER_NO_CONTRACT;
+ return ((T *) CClosedHashBase::FindOrAdd(pData, bNew));
+ }
+
+
+//*****************************************************************************
+// The following functions are used to traverse each used entry. This code
+// will skip over deleted and free entries freeing the caller up from such
+// logic.
+//*****************************************************************************
+ T *GetFirst() // The first entry, 0 if none.
+ {
+ WRAPPER_NO_CONTRACT;
+ return ((T *) CClosedHashBase::GetFirst());
+ }
+
+ T *GetNext(T *Prev) // The next entry, 0 if done.
+ {
+ WRAPPER_NO_CONTRACT;
+ return ((T *) CClosedHashBase::GetNext((BYTE *) Prev));
+ }
+};
+
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+// Closed hash with typed parameters. The derived class is the second
+// parameter to the template. The derived class must implement:
+// unsigned long Hash(const T *pData);
+// unsigned long Compare(const T *p1, T *p2);
+// ELEMENTSTATUS Status(T *pEntry);
+// void SetStatus(T *pEntry, ELEMENTSTATUS s);
+// void* GetKey(T *pEntry);
+//*****************************************************************************
+template<class T, class H>class CClosedHashEx : public CClosedHash<T>
+{
+public:
+ CClosedHashEx(
+ int iBuckets, // How many buckets should we start with.
+ bool bPerfect=false) : // true if bucket size will hash with no collisions.
+ CClosedHash<T> (iBuckets, bPerfect)
+ {
+ WRAPPER_NO_CONTRACT;
+ }
+
+ unsigned int Hash(const void *pData)
+ {
+ WRAPPER_NO_CONTRACT;
+ return static_cast<H*>(this)->Hash((const T*)pData);
+ }
+
+ unsigned int Compare(const void *p1, BYTE *p2)
+ {
+ WRAPPER_NO_CONTRACT;
+ return static_cast<H*>(this)->Compare((const T*)p1, (T*)p2);
+ }
+
+ typename CClosedHash<T>::ELEMENTSTATUS Status(BYTE *p)
+ {
+ WRAPPER_NO_CONTRACT;
+ return static_cast<H*>(this)->Status((T*)p);
+ }
+
+ void SetStatus(BYTE *p, typename CClosedHash<T>::ELEMENTSTATUS s)
+ {
+ WRAPPER_NO_CONTRACT;
+ static_cast<H*>(this)->SetStatus((T*)p, s);
+ }
+
+ void* GetKey(BYTE *p)
+ {
+ WRAPPER_NO_CONTRACT;
+ return static_cast<H*>(this)->GetKey((T*)p);
+ }
+};
+
+
+//*****************************************************************************
+// IMPORTANT: This data structure is deprecated, please do not add any new uses.
+// The hashtable implementation that should be used instead is code:SHash.
+// If code:SHash does not work for you, talk to mailto:clrdeag.
+//*****************************************************************************
+// This template is another form of a closed hash table. It handles collisions
+// through a linked chain. To use it, derive your hashed item from HASHLINK
+// and implement the virtual functions required. 1.5 * ibuckets will be
+// allocated, with the extra .5 used for collisions. If you add to the point
+// where no free nodes are available, the entire table is grown to make room.
+// The advantage to this system is that collisions are always directly known,
+// there either is one or there isn't.
+//*****************************************************************************
+struct HASHLINK
+{
+ ULONG iNext; // Offset for next entry.
+};
+
+template <class T> class CChainedHash
+{
+ friend class VerifyLayoutsMD;
+public:
+ CChainedHash(int iBuckets=32) :
+ m_rgData(0),
+ m_iBuckets(iBuckets),
+ m_iCount(0),
+ m_iMaxChain(0),
+ m_iFree(0)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_iSize = iBuckets + (iBuckets / 2);
+ }
+
+ ~CChainedHash()
+ {
+ LIMITED_METHOD_CONTRACT;
+ if (m_rgData)
+ delete [] m_rgData;
+ }
+
+ void SetBuckets(int iBuckets)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(m_rgData == 0);
+ // if iBuckets==0, then we'll allocate a zero size array and AV on dereference.
+ _ASSERTE(iBuckets > 0);
+ m_iBuckets = iBuckets;
+ m_iSize = iBuckets + (iBuckets / 2);
+ }
+
+ T *Add(void const *pData)
+ {
+ WRAPPER_NO_CONTRACT;
+ ULONG iHash;
+ int iBucket;
+ T *pItem;
+
+ // Build the list if required.
+ if (m_rgData == 0 || m_iFree == 0xffffffff)
+ {
+ if (!ReHash())
+ return (0);
+ }
+
+ // Hash the item and pick a bucket.
+ iHash = Hash(pData);
+ iBucket = iHash % m_iBuckets;
+
+ // Use the bucket if it is free.
+ if (InUse(&m_rgData[iBucket]) == false)
+ {
+ pItem = &m_rgData[iBucket];
+ pItem->iNext = 0xffffffff;
+ }
+ // Else take one off of the free list for use.
+ else
+ {
+ ULONG iEntry;
+
+ // Pull an item from the free list.
+ iEntry = m_iFree;
+ pItem = &m_rgData[m_iFree];
+ m_iFree = pItem->iNext;
+
+ // Link the new node in after the bucket.
+ pItem->iNext = m_rgData[iBucket].iNext;
+ m_rgData[iBucket].iNext = iEntry;
+ }
+ ++m_iCount;
+ return (pItem);
+ }
+
+ T *Find(void const *pData, bool bAddIfNew=false)
+ {
+ WRAPPER_NO_CONTRACT;
+ ULONG iHash;
+ int iBucket;
+ T *pItem;
+
+ // Check states for lookup.
+ if (m_rgData == 0)
+ {
+ // If we won't be adding, then we are through.
+ if (bAddIfNew == false)
+ return (0);
+
+ // Otherwise, create the table.
+ if (!ReHash())
+ return (0);
+ }
+
+ // Hash the item and pick a bucket.
+ iHash = Hash(pData);
+ iBucket = iHash % m_iBuckets;
+
+ // If it isn't in use, then there it wasn't found.
+ if (!InUse(&m_rgData[iBucket]))
+ {
+ if (bAddIfNew == false)
+ pItem = 0;
+ else
+ {
+ pItem = &m_rgData[iBucket];
+ pItem->iNext = 0xffffffff;
+ ++m_iCount;
+ }
+ }
+ // Scan the list for the one we want.
+ else
+ {
+ ULONG iChain = 0;
+ for (pItem=(T *) &m_rgData[iBucket]; pItem; pItem=GetNext(pItem))
+ {
+ if (Cmp(pData, pItem) == 0)
+ break;
+ ++iChain;
+ }
+
+ if (!pItem && bAddIfNew)
+ {
+ ULONG iEntry;
+
+ // Record maximum chain length.
+ if (iChain > m_iMaxChain)
+ m_iMaxChain = iChain;
+
+ // Now need more room.
+ if (m_iFree == 0xffffffff)
+ {
+ if (!ReHash())
+ return (0);
+ }
+
+ // Pull an item from the free list.
+ iEntry = m_iFree;
+ pItem = &m_rgData[m_iFree];
+ m_iFree = pItem->iNext;
+
+ // Link the new node in after the bucket.
+ pItem->iNext = m_rgData[iBucket].iNext;
+ m_rgData[iBucket].iNext = iEntry;
+ ++m_iCount;
+ }
+ }
+ return (pItem);
+ }
+
+ int Count()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_iCount);
+ }
+
+ int Buckets()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_iBuckets);
+ }
+
+ ULONG MaxChainLength()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_iMaxChain);
+ }
+
+ virtual void Clear()
+ {
+ LIMITED_METHOD_CONTRACT;
+ // Free up the memory.
+ if (m_rgData)
+ {
+ delete [] m_rgData;
+ m_rgData = 0;
+ }
+
+ m_rgData = 0;
+ m_iFree = 0;
+ m_iCount = 0;
+ m_iMaxChain = 0;
+ }
+
+ virtual bool InUse(T *pItem)=0;
+ virtual void SetFree(T *pItem)=0;
+ virtual ULONG Hash(void const *pData)=0;
+ virtual int Cmp(void const *pData, void *pItem)=0;
+private:
+ inline T *GetNext(T *pItem)
+ {
+ LIMITED_METHOD_CONTRACT;
+ if (pItem->iNext != 0xffffffff)
+ return ((T *) &m_rgData[pItem->iNext]);
+ return (0);
+ }
+
+ bool ReHash()
+ {
+ WRAPPER_NO_CONTRACT;
+ T *rgTemp;
+ int iNewSize;
+
+ // If this is a first time allocation, then just malloc it.
+ if (!m_rgData)
+ {
+ if ((m_rgData = new (nothrow) T[m_iSize]) == 0)
+ return (false);
+
+ int i;
+ for (i=0; i<m_iSize; i++)
+ SetFree(&m_rgData[i]);
+
+ m_iFree = m_iBuckets;
+ for (i=m_iBuckets; i<m_iSize; i++)
+ ((T *) &m_rgData[i])->iNext = i + 1;
+ ((T *) &m_rgData[m_iSize - 1])->iNext = 0xffffffff;
+ return (true);
+ }
+
+ // Otherwise we need more room on the free chain, so allocate some.
+ iNewSize = m_iSize + (m_iSize / 2);
+
+ // Allocate/realloc memory.
+ if ((rgTemp = new (nothrow) T[iNewSize]) == 0)
+ return (false);
+
+ memcpy (rgTemp,m_rgData,m_iSize*sizeof(T));
+ delete [] m_rgData;
+
+ // Init new entries, save the new free chain, and reset internals.
+ m_iFree = m_iSize;
+ for (int i=m_iFree; i<iNewSize; i++)
+ {
+ SetFree(&rgTemp[i]);
+ ((T *) &rgTemp[i])->iNext = i + 1;
+ }
+ ((T *) &rgTemp[iNewSize - 1])->iNext = 0xffffffff;
+
+ m_rgData = rgTemp;
+ m_iSize = iNewSize;
+ return (true);
+ }
+
+private:
+ T *m_rgData; // Data to store items in.
+ int m_iBuckets; // How many buckets we want.
+ int m_iSize; // How many are allocated.
+ int m_iCount; // How many are we using.
+ ULONG m_iMaxChain; // Max chain length.
+ ULONG m_iFree; // Free chain.
+};
+
+
+//*****************************************************************************
+//
+//********** String helper functions.
+//
+//*****************************************************************************
+
+//*****************************************************************************
+// Checks if string length exceeds the specified limit
+//*****************************************************************************
+inline BOOL IsStrLongerThan(__in __in_z char* pstr, unsigned N)
+{
+ LIMITED_METHOD_CONTRACT;
+ unsigned i = 0;
+ if(pstr)
+ {
+ for(i=0; (i < N)&&(pstr[i]); i++);
+ }
+ return (i >= N);
+}
+
+
+//*****************************************************************************
+// Class to parse a list of simple assembly names and then find a match
+//*****************************************************************************
+
+class AssemblyNamesList
+{
+ struct AssemblyName
+ {
+ LPUTF8 m_assemblyName;
+ AssemblyName *m_next; // Next name
+ };
+
+ AssemblyName *m_pNames; // List of names
+
+public:
+
+ bool IsInList(LPCUTF8 assemblyName);
+
+ bool IsEmpty()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pNames == 0;
+ }
+
+ AssemblyNamesList(__in LPWSTR list);
+ ~AssemblyNamesList();
+};
+
+//*****************************************************************************
+// Class to parse a list of method names and then find a match
+//*****************************************************************************
+
+struct CORINFO_SIG_INFO;
+
+class MethodNamesListBase
+{
+ struct MethodName
+ {
+ LPUTF8 methodName; // NULL means wildcard
+ LPUTF8 className; // NULL means wildcard
+ int numArgs; // number of args for the method, -1 is wildcard
+ MethodName *next; // Next name
+ };
+
+ MethodName *pNames; // List of names
+
+ bool IsInList(LPCUTF8 methodName, LPCUTF8 className, int numArgs);
+
+public:
+ void Init()
+ {
+ LIMITED_METHOD_CONTRACT;
+ pNames = 0;
+ }
+
+ void Init(__in __in_z LPWSTR list)
+ {
+ WRAPPER_NO_CONTRACT;
+ pNames = 0;
+ Insert(list);
+ }
+
+ void Destroy();
+
+ void Insert(__in __in_z LPWSTR list);
+
+ bool IsInList(LPCUTF8 methodName, LPCUTF8 className, PCCOR_SIGNATURE sig = NULL);
+ bool IsInList(LPCUTF8 methodName, LPCUTF8 className, CORINFO_SIG_INFO* pSigInfo);
+ bool IsEmpty()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return pNames == 0;
+ }
+};
+
+class MethodNamesList : public MethodNamesListBase
+{
+public:
+ MethodNamesList()
+ {
+ WRAPPER_NO_CONTRACT;
+ Init();
+ }
+
+ MethodNamesList(__in LPWSTR list)
+ {
+ WRAPPER_NO_CONTRACT;
+ Init(list);
+ }
+
+ ~MethodNamesList()
+ {
+ WRAPPER_NO_CONTRACT;
+ Destroy();
+ }
+};
+
+#if !defined(NO_CLRCONFIG)
+
+/**************************************************************************/
+/* simple wrappers around the REGUTIL and MethodNameList routines that make
+ the lookup lazy */
+
+/* to be used as static variable - no constructor/destructor, assumes zero
+ initialized memory */
+
+class ConfigDWORD
+{
+public:
+ //
+ // NOTE: The following function is deprecated; use the CLRConfig class instead.
+ // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
+ //
+ inline DWORD val_DontUse_(__in __in_z LPCWSTR keyName, DWORD defaultVal=0)
+ {
+ WRAPPER_NO_CONTRACT;
+ // make sure that the memory was zero initialized
+ _ASSERTE(m_inited == 0 || m_inited == 1);
+
+ if (!m_inited) init_DontUse_(keyName, defaultVal);
+ return m_value;
+ }
+ inline DWORD val(const CLRConfig::ConfigDWORDInfo & info)
+ {
+ WRAPPER_NO_CONTRACT;
+ // make sure that the memory was zero initialized
+ _ASSERTE(m_inited == 0 || m_inited == 1);
+
+ if (!m_inited) init(info);
+ return m_value;
+ }
+
+private:
+ void init_DontUse_(__in __in_z LPCWSTR keyName, DWORD defaultVal=0);
+ void init(const CLRConfig::ConfigDWORDInfo & info);
+
+private:
+ DWORD m_value;
+ BYTE m_inited;
+};
+
+/**************************************************************************/
+class ConfigString
+{
+public:
+ inline LPWSTR val(const CLRConfig::ConfigStringInfo & info)
+ {
+ WRAPPER_NO_CONTRACT;
+ // make sure that the memory was zero initialized
+ _ASSERTE(m_inited == 0 || m_inited == 1);
+
+ if (!m_inited) init(info);
+ return m_value;
+ }
+
+ bool isInitialized()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ // make sure that the memory was zero initialized
+ _ASSERTE(m_inited == 0 || m_inited == 1);
+
+ return m_inited == 1;
+ }
+
+private:
+ void init(const CLRConfig::ConfigStringInfo & info);
+
+private:
+ LPWSTR m_value;
+ BYTE m_inited;
+};
+
+/**************************************************************************/
+class ConfigMethodSet
+{
+public:
+ bool isEmpty()
+ {
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(m_inited == 1);
+ return m_list.IsEmpty();
+ }
+
+ bool contains(LPCUTF8 methodName, LPCUTF8 className, PCCOR_SIGNATURE sig = NULL);
+ bool contains(LPCUTF8 methodName, LPCUTF8 className, CORINFO_SIG_INFO* pSigInfo);
+
+ inline void ensureInit(const CLRConfig::ConfigStringInfo & info)
+ {
+ WRAPPER_NO_CONTRACT;
+ // make sure that the memory was zero initialized
+ _ASSERTE(m_inited == 0 || m_inited == 1);
+
+ if (!m_inited) init(info);
+ }
+
+private:
+ void init(const CLRConfig::ConfigStringInfo & info);
+
+private:
+ MethodNamesListBase m_list;
+
+ BYTE m_inited;
+};
+
+#endif // !defined(NO_CLRCONFIG)
+
+//*****************************************************************************
+// Convert a pointer to a string into a GUID.
+//*****************************************************************************
+HRESULT LPCSTRToGuid( // Return status.
+ LPCSTR szGuid, // String to convert.
+ GUID *psGuid); // Buffer for converted GUID.
+
+//*****************************************************************************
+// Convert a GUID into a pointer to a string
+//*****************************************************************************
+int GuidToLPWSTR( // Return status.
+ GUID Guid, // [IN] The GUID to convert.
+ __out_ecount (cchGuid) LPWSTR szGuid, // [OUT] String into which the GUID is stored
+ DWORD cchGuid); // [IN] Size in wide chars of szGuid
+
+//*****************************************************************************
+// Parse a Wide char string into a GUID
+//*****************************************************************************
+BOOL LPWSTRToGuid(
+ GUID * Guid, // [OUT] The GUID to fill in
+ __in_ecount(cchGuid) LPCWSTR szGuid, // [IN] String to parse
+ DWORD cchGuid); // [IN] Count in wchars in string
+
+typedef VPTR(class RangeList) PTR_RangeList;
+
+class RangeList
+{
+ public:
+ VPTR_BASE_CONCRETE_VTABLE_CLASS(RangeList)
+
+#ifndef DACCESS_COMPILE
+ RangeList();
+ ~RangeList();
+#else
+ RangeList()
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+#endif
+
+ // Wrappers to make the virtual calls DAC-safe.
+ BOOL AddRange(const BYTE *start, const BYTE *end, void *id)
+ {
+ return this->AddRangeWorker(start, end, id);
+ }
+
+ void RemoveRanges(void *id, const BYTE *start = NULL, const BYTE *end = NULL)
+ {
+ return this->RemoveRangesWorker(id, start, end);
+ }
+
+ BOOL IsInRange(TADDR address, TADDR *pID = NULL)
+ {
+ SUPPORTS_DAC;
+
+ return this->IsInRangeWorker(address, pID);
+ }
+
+#ifndef DACCESS_COMPILE
+
+ // You can overload these two for synchronization (as LockedRangeList does)
+ virtual BOOL AddRangeWorker(const BYTE *start, const BYTE *end, void *id);
+ // If both "start" and "end" are NULL, then this method deletes all ranges with
+ // the given id (i.e. the original behaviour). Otherwise, it ignores the given
+ // id and deletes all ranges falling in the region [start, end).
+ virtual void RemoveRangesWorker(void *id, const BYTE *start = NULL, const BYTE *end = NULL);
+#else
+ virtual BOOL AddRangeWorker(const BYTE *start, const BYTE *end, void *id)
+ {
+ return TRUE;
+ }
+ virtual void RemoveRangesWorker(void *id, const BYTE *start = NULL, const BYTE *end = NULL) { }
+#endif // !DACCESS_COMPILE
+
+ virtual BOOL IsInRangeWorker(TADDR address, TADDR *pID = NULL);
+
+#ifdef DACCESS_COMPILE
+ void EnumMemoryRegions(enum CLRDataEnumMemoryFlags flags);
+#endif
+
+ enum
+ {
+ RANGE_COUNT = 10
+ };
+
+
+ private:
+ struct Range
+ {
+ TADDR start;
+ TADDR end;
+ TADDR id;
+ };
+
+ struct RangeListBlock
+ {
+ Range ranges[RANGE_COUNT];
+ DPTR(RangeListBlock) next;
+
+#ifdef DACCESS_COMPILE
+ void EnumMemoryRegions(enum CLRDataEnumMemoryFlags flags);
+#endif
+
+ };
+
+ void InitBlock(RangeListBlock *block);
+
+ RangeListBlock m_starterBlock;
+ DPTR(RangeListBlock) m_firstEmptyBlock;
+ TADDR m_firstEmptyRange;
+};
+
+
+//
+// A private function to do the equavilent of a CoCreateInstance in
+// cases where we can't make the real call. Use this when, for
+// instance, you need to create a symbol reader in the Runtime but
+// we're not CoInitialized. Obviously, this is only good for COM
+// objects for which CoCreateInstance is just a glorified
+// find-and-load-me operation.
+//
+
+HRESULT FakeCoCreateInstanceEx(REFCLSID rclsid,
+ LPCWSTR wszDllPath,
+ REFIID riid,
+ void ** ppv,
+ HMODULE * phmodDll);
+
+// Provided for backward compatibility and for code that doesn't need the HMODULE of the
+// DLL that was loaded to create the COM object. See comment at implementation of
+// code:FakeCoCreateInstanceEx for more details.
+inline HRESULT FakeCoCreateInstance(REFCLSID rclsid,
+ REFIID riid,
+ void ** ppv)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ }
+ CONTRACTL_END;
+
+ return FakeCoCreateInstanceEx(rclsid, NULL, riid, ppv, NULL);
+};
+
+HRESULT FakeCoCallDllGetClassObject(REFCLSID rclsid,
+ LPCWSTR wszDllPath,
+ REFIID riid,
+ void ** ppv,
+ HMODULE * phmodDll);
+
+//*****************************************************************************
+// Gets the directory based on the location of the module. This routine
+// is called at COR setup time. Set is called during EEStartup and by the
+// MetaData dispenser.
+//*****************************************************************************
+HRESULT GetInternalSystemDirectory(__out_ecount_part_opt(*pdwLength,*pdwLength) LPWSTR buffer, __inout DWORD* pdwLength);
+LPCWSTR GetInternalSystemDirectory(__out_opt DWORD * pdwLength = NULL);
+
+//*****************************************************************************
+// This function validates the given Method/Field/Standalone signature. (util.cpp)
+//*****************************************************************************
+struct IMDInternalImport;
+HRESULT validateTokenSig(
+ mdToken tk, // [IN] Token whose signature needs to be validated.
+ PCCOR_SIGNATURE pbSig, // [IN] Signature.
+ ULONG cbSig, // [IN] Size in bytes of the signature.
+ DWORD dwFlags, // [IN] Method flags.
+ IMDInternalImport* pImport); // [IN] Internal MD Import interface ptr
+
+//*****************************************************************************
+// Determine the version number of the runtime that was used to build the
+// specified image. The pMetadata pointer passed in is the pointer to the
+// metadata contained in the image.
+//*****************************************************************************
+HRESULT GetImageRuntimeVersionString(PVOID pMetaData, LPCSTR* pString);
+void AdjustImageRuntimeVersion (SString* pVersion);
+
+//*****************************************************************************
+// The registry keys and values that contain the information regarding
+// the default registered unmanaged debugger.
+//*****************************************************************************
+SELECTANY const WCHAR kDebugApplicationsPoliciesKey[] = W("SOFTWARE\\Policies\\Microsoft\\Windows\\Windows Error Reporting\\DebugApplications");
+SELECTANY const WCHAR kDebugApplicationsKey[] = W("SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\DebugApplications");
+
+SELECTANY const WCHAR kUnmanagedDebuggerKey[] = W("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug");
+SELECTANY const WCHAR kUnmanagedDebuggerValue[] = W("Debugger");
+SELECTANY const WCHAR kUnmanagedDebuggerAutoValue[] = W("Auto");
+SELECTANY const WCHAR kUnmanagedDebuggerAutoExclusionListKey[] = W("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList");
+
+BOOL GetRegistryLongValue(HKEY hKeyParent, // Parent key.
+ LPCWSTR szKey, // Key name to look at.
+ LPCWSTR szName, // Name of value to get.
+ long *pValue, // Put value here, if found.
+ BOOL fReadNonVirtualizedKey); // Whether to read 64-bit hive on WOW64
+
+HRESULT GetCurrentModuleFileName(SString& pBuffer);
+
+//*****************************************************************************
+// Retrieve information regarding what registered default debugger
+//*****************************************************************************
+void GetDebuggerSettingInfo(SString &debuggerKeyValue, BOOL *pfAuto);
+HRESULT GetDebuggerSettingInfoWorker(__out_ecount_part_opt(*pcchDebuggerString, *pcchDebuggerString) LPWSTR wszDebuggerString, DWORD * pcchDebuggerString, BOOL * pfAuto);
+
+void TrimWhiteSpace(__inout_ecount(*pcch) LPCWSTR *pwsz, __inout LPDWORD pcch);
+
+
+//*****************************************************************************
+// Convert a UTF8 string to Unicode, into a CQuickArray<WCHAR>.
+//*****************************************************************************
+HRESULT Utf2Quick(
+ LPCUTF8 pStr, // The string to convert.
+ CQuickArray<WCHAR> &rStr, // The QuickArray<WCHAR> to convert it into.
+ int iCurLen); // Inital characters in the array to leave (default 0).
+
+//*****************************************************************************
+// Extract the movl 64-bit unsigned immediate from an IA64 bundle
+// (Format X2)
+//*****************************************************************************
+UINT64 GetIA64Imm64(UINT64 * pBundle);
+UINT64 GetIA64Imm64(UINT64 qword0, UINT64 qword1);
+
+//*****************************************************************************
+// Deposit the movl 64-bit unsigned immediate into an IA64 bundle
+// (Format X2)
+//*****************************************************************************
+void PutIA64Imm64(UINT64 * pBundle, UINT64 imm64);
+
+//*****************************************************************************
+// Extract the IP-Relative signed 25-bit immediate from an IA64 bundle
+// (Formats B1, B2 or B3)
+// Note that due to branch target alignment requirements
+// the lowest four bits in the result will always be zero.
+//*****************************************************************************
+INT32 GetIA64Rel25(UINT64 * pBundle, UINT32 slot);
+INT32 GetIA64Rel25(UINT64 qword0, UINT64 qword1, UINT32 slot);
+
+//*****************************************************************************
+// Deposit the IP-Relative signed 25-bit immediate into an IA64 bundle
+// (Formats B1, B2 or B3)
+// Note that due to branch target alignment requirements
+// the lowest four bits are required to be zero.
+//*****************************************************************************
+void PutIA64Rel25(UINT64 * pBundle, UINT32 slot, INT32 imm25);
+
+//*****************************************************************************
+// Extract the IP-Relative signed 64-bit immediate from an IA64 bundle
+// (Formats X3 or X4)
+//*****************************************************************************
+INT64 GetIA64Rel64(UINT64 * pBundle);
+INT64 GetIA64Rel64(UINT64 qword0, UINT64 qword1);
+
+//*****************************************************************************
+// Deposit the IP-Relative signed 64-bit immediate into a IA64 bundle
+// (Formats X3 or X4)
+//*****************************************************************************
+void PutIA64Rel64(UINT64 * pBundle, INT64 imm64);
+
+//*****************************************************************************
+// Extract the 32-bit immediate from movw/movt Thumb2 sequence
+//*****************************************************************************
+UINT32 GetThumb2Mov32(UINT16 * p);
+
+//*****************************************************************************
+// Deposit the 32-bit immediate into movw/movt Thumb2 sequence
+//*****************************************************************************
+void PutThumb2Mov32(UINT16 * p, UINT32 imm32);
+
+//*****************************************************************************
+// Extract the 24-bit rel offset from bl instruction
+//*****************************************************************************
+INT32 GetThumb2BlRel24(UINT16 * p);
+
+//*****************************************************************************
+// Extract the 24-bit rel offset from bl instruction
+//*****************************************************************************
+void PutThumb2BlRel24(UINT16 * p, INT32 imm24);
+
+//*****************************************************************************
+// Extract the PC-Relative offset from a b or bl instruction
+//*****************************************************************************
+INT32 GetArm64Rel28(UINT32 * pCode);
+
+//*****************************************************************************
+// Extract the PC-Relative page address from an adrp instruction
+//*****************************************************************************
+INT32 GetArm64Rel21(UINT32 * pCode);
+
+//*****************************************************************************
+// Extract the page offset from an add instruction
+//*****************************************************************************
+INT32 GetArm64Rel12(UINT32 * pCode);
+
+//*****************************************************************************
+// Deposit the PC-Relative offset 'imm28' into a b or bl instruction
+//*****************************************************************************
+void PutArm64Rel28(UINT32 * pCode, INT32 imm28);
+
+//*****************************************************************************
+// Deposit the PC-Relative page address 'imm21' into an adrp instruction
+//*****************************************************************************
+void PutArm64Rel21(UINT32 * pCode, INT32 imm21);
+
+//*****************************************************************************
+// Deposit the page offset 'imm12' into an add instruction
+//*****************************************************************************
+void PutArm64Rel12(UINT32 * pCode, INT32 imm12);
+
+//*****************************************************************************
+// Returns whether the offset fits into bl instruction
+//*****************************************************************************
+inline bool FitsInThumb2BlRel24(INT32 imm24)
+{
+ return ((imm24 << 7) >> 7) == imm24;
+}
+
+//*****************************************************************************
+// Returns whether the offset fits into an Arm64 b or bl instruction
+//*****************************************************************************
+inline bool FitsInRel28(INT32 val32)
+{
+ return (val32 >= -0x08000000) && (val32 < 0x08000000);
+}
+
+//*****************************************************************************
+// Returns whether the offset fits into an Arm64 adrp instruction
+//*****************************************************************************
+inline bool FitsInRel21(INT32 val32)
+{
+ return (val32 >= 0) && (val32 <= 0x001FFFFF);
+}
+
+//*****************************************************************************
+// Returns whether the offset fits into an Arm64 add instruction
+//*****************************************************************************
+inline bool FitsInRel12(INT32 val32)
+{
+ return (val32 >= 0) && (val32 <= 0x00000FFF);
+}
+
+//*****************************************************************************
+// Returns whether the offset fits into an Arm64 b or bl instruction
+//*****************************************************************************
+inline bool FitsInRel28(INT64 val64)
+{
+ return (val64 >= -0x08000000LL) && (val64 < 0x08000000LL);
+}
+
+//*****************************************************************************
+// Splits a command line into argc/argv lists, using the VC7 parsing rules.
+// This functions interface mimics the CommandLineToArgvW api.
+// If function fails, returns NULL.
+// If function suceeds, call delete [] on return pointer when done.
+//*****************************************************************************
+LPWSTR *SegmentCommandLine(LPCWSTR lpCmdLine, DWORD *pNumArgs);
+
+//
+// TEB access can be dangerous when using fibers because a fiber may
+// run on multiple threads. If the TEB pointer is retrieved and saved
+// and then a fiber is moved to a different thread, when it accesses
+// the saved TEB pointer, it will be looking at the TEB state for a
+// different fiber.
+//
+// These accessors serve the purpose of retrieving information from the
+// TEB in a manner that ensures that the current fiber will not switch
+// threads while the access is occuring.
+//
+class ClrTeb
+{
+public:
+#if defined(FEATURE_PAL)
+
+ // returns pointer that uniquely identifies the fiber
+ static void* GetFiberPtrId()
+ {
+ LIMITED_METHOD_CONTRACT;
+ // not fiber for FEATURE_PAL - use the regular thread ID
+ return (void *)(size_t)GetCurrentThreadId();
+ }
+
+ static void* InvalidFiberPtrId()
+ {
+ return NULL;
+ }
+
+ static void* GetStackBase()
+ {
+ return PAL_GetStackBase();
+ }
+
+ static void* GetStackLimit()
+ {
+ return PAL_GetStackLimit();
+ }
+
+#else // !FEATURE_PAL
+
+ // returns pointer that uniquely identifies the fiber
+ static void* GetFiberPtrId()
+ {
+ LIMITED_METHOD_CONTRACT;
+ // stackbase is the unique fiber identifier
+ return NtCurrentTeb()->NtTib.StackBase;
+ }
+
+ static void* GetStackBase()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return NtCurrentTeb()->NtTib.StackBase;
+ }
+
+ static void* GetStackLimit()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return NtCurrentTeb()->NtTib.StackLimit;
+ }
+
+ // Please don't start to use this method unless you absolutely have to.
+ // The reason why this is added is for WIN64 to support LEGACY PE-style TLS
+ // variables. On X86 it is supported by the JIT compilers themselves. On
+ // WIN64 we build more logic into the JIT helper for accessing fields.
+ static void* GetLegacyThreadLocalStoragePointer()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return NtCurrentTeb()->ThreadLocalStoragePointer;
+ }
+
+ static void* GetOleReservedPtr()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return NtCurrentTeb()->ReservedForOle;
+ }
+
+ static void* GetProcessEnvironmentBlock()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return NtCurrentTeb()->ProcessEnvironmentBlock;
+ }
+
+#ifndef FEATURE_CORECLR
+ static void* GetFiberDataPtr()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return ClrTeb::IsCurrentThreadAFiber()? GetCurrentFiber() : NULL;
+ }
+
+ static BOOL IsCurrentThreadAFiber()
+ {
+ return IsThreadAFiber();
+ }
+#endif
+
+ static void* InvalidFiberPtrId()
+ {
+ return (void*) 1;
+ }
+#endif // !FEATURE_PAL
+};
+
+#if !defined(DACCESS_COMPILE)
+
+// check if current thread is a GC thread (concurrent or server)
+inline BOOL IsGCSpecialThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+ STATIC_CONTRACT_CANNOT_TAKE_LOCK;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_GC);
+}
+
+// check if current thread is a Gate thread
+inline BOOL IsGateSpecialThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Gate);
+}
+
+// check if current thread is a Timer thread
+inline BOOL IsTimerSpecialThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Timer);
+}
+
+// check if current thread is a debugger helper thread
+inline BOOL IsDbgHelperSpecialThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_DbgHelper);
+}
+
+// check if current thread is a debugger helper thread
+inline BOOL IsETWRundownSpecialThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_ETWRundownThread);
+}
+
+// check if current thread is a generic instantiation lookup compare thread
+inline BOOL IsGenericInstantiationLookupCompareThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_GenericInstantiationCompare);
+}
+
+// check if current thread is a thread which is performing shutdown
+inline BOOL IsShutdownSpecialThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Shutdown);
+}
+
+inline BOOL IsThreadPoolIOCompletionSpecialThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Threadpool_IOCompletion);
+}
+
+inline BOOL IsThreadPoolWorkerSpecialThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Threadpool_Worker);
+}
+
+inline BOOL IsWaitSpecialThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Wait);
+}
+
+// check if current thread is a thread which is performing shutdown
+inline BOOL IsSuspendEEThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_DynamicSuspendEE);
+}
+
+inline BOOL IsFinalizerThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Finalizer);
+}
+
+inline BOOL IsADUnloadHelperThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_ADUnloadHelper);
+}
+
+inline BOOL IsShutdownHelperThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_ShutdownHelper);
+}
+
+inline BOOL IsProfilerAttachThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_ProfAPI_Attach);
+}
+
+// set specical type for current thread
+inline void ClrFlsSetThreadType (TlsThreadTypeFlag flag)
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+ STATIC_CONTRACT_SO_TOLERANT;
+
+ ClrFlsSetValue (TlsIdx_ThreadType, (LPVOID)(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) |flag));
+}
+
+// clear specical type for current thread
+inline void ClrFlsClearThreadType (TlsThreadTypeFlag flag)
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+ ClrFlsSetValue (TlsIdx_ThreadType, (LPVOID)(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ~flag));
+}
+
+#endif //!DACCESS_COMPILE
+
+#ifdef DACCESS_COMPILE
+#define SET_THREAD_TYPE_STACKWALKER(pThread)
+#define CLEAR_THREAD_TYPE_STACKWALKER()
+#else // DACCESS_COMPILE
+#define SET_THREAD_TYPE_STACKWALKER(pThread) ClrFlsSetValue(TlsIdx_StackWalkerWalkingThread, pThread)
+#define CLEAR_THREAD_TYPE_STACKWALKER() ClrFlsSetValue(TlsIdx_StackWalkerWalkingThread, NULL)
+#endif // DACCESS_COMPILE
+
+inline BOOL IsStackWalkerThread()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+ STATIC_CONTRACT_CANNOT_TAKE_LOCK;
+
+#if defined(DACCESS_COMPILE)
+ return FALSE;
+#else
+ return ClrFlsGetValue (TlsIdx_StackWalkerWalkingThread) != NULL;
+#endif
+}
+
+inline BOOL IsGCThread ()
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+ STATIC_CONTRACT_SUPPORTS_DAC;
+ STATIC_CONTRACT_SO_TOLERANT;
+
+#if !defined(DACCESS_COMPILE)
+ return IsGCSpecialThread () || IsSuspendEEThread ();
+#else
+ return FALSE;
+#endif
+}
+
+class ClrFlsThreadTypeSwitch
+{
+public:
+ ClrFlsThreadTypeSwitch (TlsThreadTypeFlag flag)
+ {
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+#ifndef DACCESS_COMPILE
+ m_flag = flag;
+ m_fPreviouslySet = (((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & flag);
+
+ // In debug builds, remember the full group of flags that were set at the time
+ // the constructor was called. This will be used in ASSERTs in the destructor
+ INDEBUG(m_nPreviousFlagGroup = (size_t)ClrFlsGetValue (TlsIdx_ThreadType));
+
+ if (!m_fPreviouslySet)
+ {
+ ClrFlsSetThreadType(flag);
+ }
+#endif // DACCESS_COMPILE
+ }
+
+ ~ClrFlsThreadTypeSwitch ()
+ {
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+#ifndef DACCESS_COMPILE
+ // This holder should only be used to set (and thus restore) ONE thread type flag
+ // at a time. If more than that one flag was modified since this holder was
+ // instantiated, then this holder still restores only the flag it knows about. To
+ // prevent confusion, assert if some other flag was modified, so the user doesn't
+ // expect the holder to restore the entire original set of flags.
+ //
+ // The expression below says that the only difference between the previous flag
+ // group and the current flag group should be m_flag (or no difference at all, if
+ // m_flag's state didn't actually change).
+ _ASSERTE(((m_nPreviousFlagGroup ^ (size_t) ClrFlsGetValue(TlsIdx_ThreadType)) | (size_t) m_flag) == (size_t) m_flag);
+
+ if (m_fPreviouslySet)
+ {
+ ClrFlsSetThreadType(m_flag);
+ }
+ else
+ {
+ ClrFlsClearThreadType(m_flag);
+ }
+#endif // DACCESS_COMPILE
+ }
+
+private:
+ TlsThreadTypeFlag m_flag;
+ BOOL m_fPreviouslySet;
+ INDEBUG(size_t m_nPreviousFlagGroup);
+};
+
+class ClrFlsValueSwitch
+{
+public:
+ ClrFlsValueSwitch (PredefinedTlsSlots slot, PVOID value)
+ {
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+#ifndef DACCESS_COMPILE
+ m_slot = slot;
+ m_PreviousValue = ClrFlsGetValue(slot);
+ ClrFlsSetValue(slot, value);
+#endif // DACCESS_COMPILE
+ }
+
+ ~ClrFlsValueSwitch ()
+ {
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_MODE_ANY;
+
+#ifndef DACCESS_COMPILE
+ ClrFlsSetValue(m_slot, m_PreviousValue);
+#endif // DACCESS_COMPILE
+ }
+
+private:
+ PVOID m_PreviousValue;
+ PredefinedTlsSlots m_slot;
+};
+
+//*********************************************************************************
+
+// When we're hosted, operations called by the host (such as Thread::YieldTask)
+// may not cause calls back into the host, as the host needs not be reentrant.
+// Use the following holder for code in which calls into the host are forbidden.
+// (If a call into the host is attempted nevertheless, an assert will fire.)
+
+class ForbidCallsIntoHostOnThisThread
+{
+private:
+ static Volatile<PVOID> s_pvOwningFiber;
+
+ FORCEINLINE static BOOL Enter(BOOL)
+ {
+ WRAPPER_NO_CONTRACT;
+ return InterlockedCompareExchangePointer(
+ &s_pvOwningFiber, ClrTeb::GetFiberPtrId(), NULL) == NULL;
+ }
+
+ FORCEINLINE static void Leave(BOOL)
+ {
+ LIMITED_METHOD_CONTRACT;
+ s_pvOwningFiber = NULL;
+ }
+
+public:
+ typedef ConditionalStateHolder<BOOL, ForbidCallsIntoHostOnThisThread::Enter, ForbidCallsIntoHostOnThisThread::Leave> Holder;
+
+ FORCEINLINE static BOOL CanThisThreadCallIntoHost()
+ {
+ WRAPPER_NO_CONTRACT;
+ return s_pvOwningFiber != ClrTeb::GetFiberPtrId();
+ }
+};
+
+typedef ForbidCallsIntoHostOnThisThread::Holder ForbidCallsIntoHostOnThisThreadHolder;
+
+FORCEINLINE BOOL CanThisThreadCallIntoHost()
+{
+ WRAPPER_NO_CONTRACT;
+ return ForbidCallsIntoHostOnThisThread::CanThisThreadCallIntoHost();
+}
+
+//*********************************************************************************
+
+#include "contract.inl"
+
+namespace util
+{
+ // compare adapters
+ //
+
+ template < typename T >
+ struct less
+ {
+ bool operator()( T const & first, T const & second ) const
+ {
+ return first < second;
+ }
+ };
+
+ template < typename T >
+ struct greater
+ {
+ bool operator()( T const & first, T const & second ) const
+ {
+ return first > second;
+ }
+ };
+
+
+ // sort adapters
+ //
+
+ template< typename Iter, typename Pred >
+ void sort( Iter begin, Iter end, Pred pred );
+
+ template< typename T, typename Pred >
+ void sort( T * begin, T * end, Pred pred )
+ {
+ struct sort_helper : CQuickSort< T >
+ {
+ sort_helper( T * begin, T * end, Pred pred )
+ : CQuickSort< T >( begin, end - begin )
+ , m_pred( pred )
+ {}
+
+ virtual int Compare( T * first, T * second )
+ {
+ return m_pred( *first, *second ) ? -1
+ : ( m_pred( *second, *first ) ? 1 : 0 );
+ }
+
+ Pred m_pred;
+ };
+
+ sort_helper sort_obj( begin, end, pred );
+ sort_obj.Sort();
+ }
+
+
+ template < typename Iter >
+ void sort( Iter begin, Iter end );
+
+ template < typename T >
+ void sort( T * begin, T * end )
+ {
+ util::sort( begin, end, util::less< T >() );
+ }
+
+
+ // binary search adapters
+ //
+
+ template < typename Iter, typename T, typename Pred >
+ Iter lower_bound( Iter begin, Iter end, T const & val, Pred pred );
+
+ template < typename T, typename Pred >
+ T * lower_bound( T * begin, T * end, T const & val, Pred pred )
+ {
+ for (; begin != end; )
+ {
+ T * mid = begin + ( end - begin ) / 2;
+ if ( pred( *mid, val ) )
+ begin = ++mid;
+ else
+ end = mid;
+ }
+
+ return begin;
+ }
+
+
+ template < typename Iter, typename T >
+ Iter lower_bound( Iter begin, Iter end, T const & val );
+
+ template < typename T >
+ T * lower_bound( T * begin, T * end, T const & val )
+ {
+ return util::lower_bound( begin, end, val, util::less< T >() );
+ }
+}
+
+
+/* ------------------------------------------------------------------------ *
+ * Overloaded operators for the executable heap
+ * ------------------------------------------------------------------------ */
+
+#ifndef FEATURE_PAL
+
+struct CExecutable { int x; };
+extern const CExecutable executable;
+
+void * __cdecl operator new(size_t n, const CExecutable&);
+void * __cdecl operator new[](size_t n, const CExecutable&);
+void * __cdecl operator new(size_t n, const CExecutable&, const NoThrow&);
+void * __cdecl operator new[](size_t n, const CExecutable&, const NoThrow&);
+
+
+//
+// Executable heap delete to match the executable heap new above.
+//
+template<class T> void DeleteExecutable(T *p)
+{
+ if (p != NULL)
+ {
+ p->T::~T();
+
+ ClrHeapFree(ClrGetProcessExecutableHeap(), 0, p);
+ }
+}
+
+#endif // FEATURE_PAL
+
+INDEBUG(BOOL DbgIsExecutable(LPVOID lpMem, SIZE_T length);)
+
+class HighCharHelper {
+public:
+ static inline BOOL IsHighChar(int c) {
+ return (BOOL)HighCharTable[c];
+ }
+
+private:
+ static const BYTE HighCharTable[];
+};
+
+
+BOOL ThreadWillCreateGuardPage(SIZE_T sizeReservedStack, SIZE_T sizeCommitedStack);
+
+FORCEINLINE void HolderSysFreeString(BSTR str) { CONTRACT_VIOLATION(ThrowsViolation); SysFreeString(str); }
+
+typedef Wrapper<BSTR, DoNothing, HolderSysFreeString> BSTRHolder;
+
+BOOL FileExists(LPCWSTR filename);
+
+#ifndef FEATURE_CORECLR
+class FileLockHolder
+{
+public:
+ FileLockHolder();
+ ~FileLockHolder();
+
+ virtual void Acquire(LPCWSTR lockName, HANDLE hInterrupt = 0, BOOL* pInterrupted = NULL);
+ HRESULT AcquireNoThrow(LPCWSTR lockName, HANDLE hInterrupt = 0, BOOL* pInterrupted = NULL);
+
+ static BOOL IsTaken(LPCWSTR lockName);
+ void Release();
+private:
+ HANDLE _hLock;
+};
+#endif // FEATURE_CORECLR
+
+// a class for general x.x version info
+class MajorMinorVersionInfo
+{
+protected:
+ WORD version[2];
+ BOOL bInitialized;
+public:
+ //cctors
+ MajorMinorVersionInfo()
+ {
+ LIMITED_METHOD_CONTRACT;
+ bInitialized = FALSE;
+ ZeroMemory(version,sizeof(version));
+ };
+
+ MajorMinorVersionInfo(WORD wMajor, WORD wMinor)
+ {
+ WRAPPER_NO_CONTRACT;
+ Init(wMajor,wMinor);
+ };
+
+ // getters
+ BOOL IsInitialized() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return bInitialized;
+ };
+
+ WORD Major() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return version[0];
+ };
+
+ WORD Minor() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return version[1];
+ };
+
+ // setters
+ void Init(WORD wMajor, WORD wMinor)
+ {
+ LIMITED_METHOD_CONTRACT;
+ version[0]=wMajor;
+ version[1]=wMinor;
+ bInitialized=TRUE;
+ };
+};
+
+// CLR runtime version info in Major/Minor form
+class RUNTIMEVERSIONINFO : public MajorMinorVersionInfo
+{
+ static RUNTIMEVERSIONINFO notDefined;
+public:
+ // cctors
+ RUNTIMEVERSIONINFO() {};
+
+ RUNTIMEVERSIONINFO(WORD wMajor, WORD wMinor) :
+ MajorMinorVersionInfo(wMajor,wMinor){};
+
+ // CLR version specific helpers
+ BOOL IsPreWhidbey() const
+ {
+ WRAPPER_NO_CONTRACT;
+ return (Major() == 1) && (Minor() <= 1);
+ }
+
+ static const RUNTIMEVERSIONINFO& NotApplicable()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return notDefined;
+ }
+};
+
+
+// HMODULE_TGT represents a handle to a module in the target process. In non-DAC builds this is identical
+// to HMODULE (HINSTANCE), which is the base address of the module. In DAC builds this must be a target address,
+// and so is represented by TADDR.
+
+#ifdef DACCESS_COMPILE
+typedef TADDR HMODULE_TGT;
+#else
+typedef HMODULE HMODULE_TGT;
+#endif
+
+BOOL IsIPInModule(HMODULE_TGT hModule, PCODE ip);
+
+//----------------------------------------------------------------------------------------
+// The runtime invokes InitUtilcode() in its dllmain and passes along all of the critical
+// callback pointers. For the desktop CLR, all DLLs loaded by the runtime must also call
+// InitUtilcode with the same callbacks as the runtime used. To achieve this, the runtime
+// calls a special initialization routine exposed by the loaded module with the callbacks,
+// which in turn calls InitUtilcode.
+//
+// This structure collects all of the critical callback info passed in InitUtilcode().
+// Note that one of them is GetCLRFunction() which is itself a gofer for many other
+// callbacks. If a callback fetch be safely deferred until we have TLS and stack probe
+// functionality running, it should be added to that function rather than this structure.
+// Things like IEE are here because that callback has to be set up before GetCLRFunction()
+// can be safely called.
+//----------------------------------------------------------------------------------------
+struct CoreClrCallbacks
+{
+ typedef IExecutionEngine* (__stdcall * pfnIEE_t)();
+ typedef HRESULT (__stdcall * pfnGetCORSystemDirectory_t)(SString& pbuffer);
+ typedef void* (__stdcall * pfnGetCLRFunction_t)(LPCSTR functionName);
+
+ HINSTANCE m_hmodCoreCLR;
+ pfnIEE_t m_pfnIEE;
+ pfnGetCORSystemDirectory_t m_pfnGetCORSystemDirectory;
+ pfnGetCLRFunction_t m_pfnGetCLRFunction;
+};
+
+#if defined(FEATURE_CORECLR) || !defined(SELF_NO_HOST) || defined(DACCESS_COMPILE)
+
+// For DAC, we include this functionality only when EH SxS is enabled.
+
+//----------------------------------------------------------------------------------------
+// CoreCLR must invoke this before CRT initialization to ensure utilcode has all the callback
+// pointers it needs.
+//----------------------------------------------------------------------------------------
+VOID InitUtilcode(const CoreClrCallbacks &cccallbacks);
+CoreClrCallbacks const & GetClrCallbacks();
+
+//----------------------------------------------------------------------------------------
+// Stuff below is for utilcode.lib eyes only.
+//----------------------------------------------------------------------------------------
+
+// Stores callback pointers provided by InitUtilcode().
+extern CoreClrCallbacks g_CoreClrCallbacks;
+
+// Throws up a helpful dialog if InitUtilcode() wasn't called.
+#ifdef _DEBUG
+void OnUninitializedCoreClrCallbacks();
+#define VALIDATECORECLRCALLBACKS() if (g_CoreClrCallbacks.m_hmodCoreCLR == NULL) OnUninitializedCoreClrCallbacks()
+#else //_DEBUG
+#define VALIDATECORECLRCALLBACKS()
+#endif //_DEBUG
+
+#endif // defined(FEATURE_CORECLR) || !defined(SELF_NO_HOST) || defined(DACCESS_COMPILE)
+
+#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+
+// Corrupting Exception limited support for outside the VM folder
+BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO = TRUE);
+
+#endif // FEATURE_CORRUPTING_EXCEPTIONS
+
+
+BOOL IsV2RuntimeLoaded(void);
+
+namespace UtilCode
+{
+ // These are type-safe versions of Interlocked[Compare]Exchange
+ // They avoid invoking struct cast operations via reinterpreting
+ // the struct's address as a LONG* or LONGLONG* and dereferencing it.
+ //
+ // If we had a global ::operator & (unary), we would love to use that
+ // to ensure we were not also accidentally getting a structs's provided
+ // operator &. TODO: probe with a static_assert?
+
+ template <typename T, int SIZE = sizeof(T)>
+ struct InterlockedCompareExchangeHelper;
+
+ template <typename T>
+ struct InterlockedCompareExchangeHelper<T, sizeof(LONG)>
+ {
+ static inline T InterlockedExchange(
+ T volatile * target,
+ T value)
+ {
+ static_assert_no_msg(sizeof(T) == sizeof(LONG));
+ LONG res = ::InterlockedExchange(
+ reinterpret_cast<LONG volatile *>(target),
+ *reinterpret_cast<LONG *>(/*::operator*/&(value)));
+ return *reinterpret_cast<T*>(&res);
+ }
+
+ static inline T InterlockedCompareExchange(
+ T volatile * destination,
+ T exchange,
+ T comparand)
+ {
+ static_assert_no_msg(sizeof(T) == sizeof(LONG));
+ LONG res = ::InterlockedCompareExchange(
+ reinterpret_cast<LONG volatile *>(destination),
+ *reinterpret_cast<LONG*>(/*::operator*/&(exchange)),
+ *reinterpret_cast<LONG*>(/*::operator*/&(comparand)));
+ return *reinterpret_cast<T*>(&res);
+ }
+ };
+
+ template <typename T>
+ struct InterlockedCompareExchangeHelper<T, sizeof(LONGLONG)>
+ {
+ static inline T InterlockedExchange(
+ T volatile * target,
+ T value)
+ {
+ static_assert_no_msg(sizeof(T) == sizeof(LONGLONG));
+ LONGLONG res = ::InterlockedExchange64(
+ reinterpret_cast<LONGLONG volatile *>(target),
+ *reinterpret_cast<LONGLONG *>(/*::operator*/&(value)));
+ return *reinterpret_cast<T*>(&res);
+ }
+
+ static inline T InterlockedCompareExchange(
+ T volatile * destination,
+ T exchange,
+ T comparand)
+ {
+ static_assert_no_msg(sizeof(T) == sizeof(LONGLONG));
+ LONGLONG res = ::InterlockedCompareExchange64(
+ reinterpret_cast<LONGLONG volatile *>(destination),
+ *reinterpret_cast<LONGLONG*>(/*::operator*/&(exchange)),
+ *reinterpret_cast<LONGLONG*>(/*::operator*/&(comparand)));
+ return *reinterpret_cast<T*>(&res);
+ }
+ };
+}
+
+template <typename T>
+inline T InterlockedExchangeT(
+ T volatile * target,
+ T value)
+{
+ return ::UtilCode::InterlockedCompareExchangeHelper<T>::InterlockedExchange(
+ target, value);
+}
+
+template <typename T>
+inline T InterlockedCompareExchangeT(
+ T volatile * destination,
+ T exchange,
+ T comparand)
+{
+ return ::UtilCode::InterlockedCompareExchangeHelper<T>::InterlockedCompareExchange(
+ destination, exchange, comparand);
+}
+
+// Pointer variants for Interlocked[Compare]ExchangePointer
+// If the underlying type is a const type, we have to remove its constness
+// since Interlocked[Compare]ExchangePointer doesn't take const void * arguments.
+template <typename T>
+inline T* InterlockedExchangeT(
+ T* volatile * target,
+ T* value)
+{
+ //STATIC_ASSERT(value == 0);
+ typedef typename std::remove_const<T>::type * non_const_ptr_t;
+ return reinterpret_cast<T*>(InterlockedExchangePointer(
+ reinterpret_cast<PVOID volatile *>(const_cast<non_const_ptr_t volatile *>(target)),
+ reinterpret_cast<PVOID>(const_cast<non_const_ptr_t>(value))));
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangeT(
+ T* volatile * destination,
+ T* exchange,
+ T* comparand)
+{
+ //STATIC_ASSERT(exchange == 0);
+ typedef typename std::remove_const<T>::type * non_const_ptr_t;
+ return reinterpret_cast<T*>(InterlockedCompareExchangePointer(
+ reinterpret_cast<PVOID volatile *>(const_cast<non_const_ptr_t volatile *>(destination)),
+ reinterpret_cast<PVOID>(const_cast<non_const_ptr_t>(exchange)),
+ reinterpret_cast<PVOID>(const_cast<non_const_ptr_t>(comparand))));
+}
+
+// NULL pointer variants of the above to avoid having to cast NULL
+// to the appropriate pointer type.
+template <typename T>
+inline T* InterlockedExchangeT(
+ T* volatile * target,
+ int value) // When NULL is provided as argument.
+{
+ //STATIC_ASSERT(value == 0);
+ return InterlockedExchangeT(target, reinterpret_cast<T*>(value));
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangeT(
+ T* volatile * destination,
+ int exchange, // When NULL is provided as argument.
+ T* comparand)
+{
+ //STATIC_ASSERT(exchange == 0);
+ return InterlockedCompareExchangeT(destination, reinterpret_cast<T*>(exchange), comparand);
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangeT(
+ T* volatile * destination,
+ T* exchange,
+ int comparand) // When NULL is provided as argument.
+{
+ //STATIC_ASSERT(comparand == 0);
+ return InterlockedCompareExchangeT(destination, exchange, reinterpret_cast<T*>(comparand));
+}
+
+// NULL pointer variants of the above to avoid having to cast NULL
+// to the appropriate pointer type.
+template <typename T>
+inline T* InterlockedExchangeT(
+ T* volatile * target,
+ std::nullptr_t value) // When nullptr is provided as argument.
+{
+ //STATIC_ASSERT(value == 0);
+ return InterlockedExchangeT(target, reinterpret_cast<T*>(value));
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangeT(
+ T* volatile * destination,
+ std::nullptr_t exchange, // When nullptr is provided as argument.
+ T* comparand)
+{
+ //STATIC_ASSERT(exchange == 0);
+ return InterlockedCompareExchangeT(destination, reinterpret_cast<T*>(exchange), comparand);
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangeT(
+ T* volatile * destination,
+ T* exchange,
+ std::nullptr_t comparand) // When nullptr is provided as argument.
+{
+ //STATIC_ASSERT(comparand == 0);
+ return InterlockedCompareExchangeT(destination, exchange, reinterpret_cast<T*>(comparand));
+}
+
+#undef InterlockedExchangePointer
+#define InterlockedExchangePointer Use_InterlockedExchangeT
+#undef InterlockedCompareExchangePointer
+#define InterlockedCompareExchangePointer Use_InterlockedCompareExchangeT
+
+// Returns the directory for HMODULE. So, if HMODULE was for "C:\Dir1\Dir2\Filename.DLL",
+// then this would return "C:\Dir1\Dir2\" (note the trailing backslash).
+HRESULT GetHModuleDirectory(HMODULE hMod, SString& wszPath);
+HRESULT CopySystemDirectory(const SString& pPathString, SString& pbuffer);
+
+HMODULE LoadLocalizedResourceDLLForSDK(_In_z_ LPCWSTR wzResourceDllName, _In_opt_z_ LPCWSTR modulePath=NULL, bool trySelf=true);
+// This is a slight variation that can be used for anything else
+typedef void* (__cdecl *LocalizedFileHandler)(LPCWSTR);
+void* FindLocalizedFile(_In_z_ LPCWSTR wzResourceDllName, LocalizedFileHandler lfh, _In_opt_z_ LPCWSTR modulePath=NULL);
+
+BOOL IsClrHostedLegacyComObject(REFCLSID rclsid);
+
+
+#if !defined(FEATURE_CORECLR) && !defined(CROSSGEN_COMPILE)
+
+// No utilcode code should use the global LoadLibraryShim anymore. UtilCode::LoadLibraryShim will do
+// the right thing based on whether the hosted or non-hosted utilcode is linked to. Using the global
+// LoadLibraryShim will result in a deprecated use warning.
+
+#ifdef SELF_NO_HOST
+#define LEGACY_ACTIVATION_SHIM_LOAD_LIBRARY WszLoadLibrary
+#include "legacyactivationshim.h"
+#include "mscoreepriv.h"
+
+namespace UtilCode
+{
+ inline HRESULT LoadLibraryShim(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll)
+ {
+ return LegacyActivationShim::LoadLibraryShim(szDllName, szVersion, pvReserved, phModDll);
+ }
+};
+#else // SELF_NO_HOST
+namespace UtilCode
+{
+ // Hosted environment
+ HRESULT LoadLibraryShim(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll);
+};
+#endif // SELF_NO_HOST
+
+#endif // !FEATURE_CORECLR && !CROSSGEN_COMPILE
+
+
+// Helper to support termination due to heap corruption
+// It's not supported on Win2K, so we have to manually delay load it
+void EnableTerminationOnHeapCorruption();
+
+
+#if !defined(FEATURE_CORECLR)
+// On success, sets pwszProcessExePath (required) to full path to process EXE.
+HRESULT GetProcessExePath(LPCWSTR *pwszProcessExePath);
+#endif
+
+namespace Clr { namespace Util
+{
+ // This api returns a pointer to a null-terminated string that contains the local appdata directory
+ // or it returns NULL in the case that the directory could not be found. The return value from this function
+ // is not actually checked for existence.
+ HRESULT GetLocalAppDataDirectory(LPCWSTR *ppwzLocalAppDataDirectory);
+ HRESULT SetLocalAppDataDirectory(LPCWSTR pwzLocalAppDataDirectory);
+
+namespace Reg
+{
+ HRESULT ReadStringValue(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, SString & ssValue);
+ __success(return == S_OK)
+ HRESULT ReadStringValue(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, __deref_out __deref_out_z LPWSTR* pwszValue);
+}
+
+#ifdef FEATURE_COMINTEROP
+namespace Com
+{
+ HRESULT FindServerUsingCLSID(REFCLSID rclsid, SString & ssServerName);
+ HRESULT FindServerUsingCLSID(REFCLSID rclsid, __deref_out __deref_out_z LPWSTR* pwszServerName);
+ HRESULT FindInprocServer32UsingCLSID(REFCLSID rclsid, SString & ssInprocServer32Name);
+ HRESULT FindInprocServer32UsingCLSID(REFCLSID rclsid, __deref_out __deref_out_z LPWSTR* pwszInprocServer32Name);
+ BOOL IsMscoreeInprocServer32(const SString & ssInprocServer32Name);
+ BOOL CLSIDHasMscoreeAsInprocServer32(REFCLSID rclsid);
+}
+#endif // FEATURE_COMINTEROP
+
+namespace Win32
+{
+ static const WCHAR LONG_FILENAME_PREFIX_W[] = W("\\\\?\\");
+ static const CHAR LONG_FILENAME_PREFIX_A[] = "\\\\?\\";
+
+ void GetModuleFileName(
+ HMODULE hModule,
+ SString & ssFileName,
+ bool fAllowLongFileNames = false);
+
+ __success(return == S_OK)
+ HRESULT GetModuleFileName(
+ HMODULE hModule,
+ __deref_out_z LPWSTR * pwszFileName,
+ bool fAllowLongFileNames = false);
+
+ void GetFullPathName(
+ SString const & ssFileName,
+ SString & ssPathName,
+ DWORD * pdwFilePartIdx,
+ bool fAllowLongFileNames = false);
+}
+
+}}
+
+#if defined(FEATURE_APPX) && !defined(DACCESS_COMPILE)
+ // Forward declaration of AppX::IsAppXProcess
+ namespace AppX { bool IsAppXProcess(); }
+
+ // LOAD_WITH_ALTERED_SEARCH_PATH is unsupported in AppX processes.
+ inline DWORD GetLoadWithAlteredSearchPathFlag()
+ {
+ WRAPPER_NO_CONTRACT;
+ return AppX::IsAppXProcess() ? 0 : LOAD_WITH_ALTERED_SEARCH_PATH;
+ }
+#else // FEATURE_APPX && !DACCESS_COMPILE
+ // LOAD_WITH_ALTERED_SEARCH_PATH can be used unconditionally.
+ inline DWORD GetLoadWithAlteredSearchPathFlag()
+ {
+ LIMITED_METHOD_CONTRACT;
+ #ifdef LOAD_WITH_ALTERED_SEARCH_PATH
+ return LOAD_WITH_ALTERED_SEARCH_PATH;
+ #else
+ return 0;
+ #endif
+ }
+#endif // FEATURE_APPX && !DACCESS_COMPILE
+
+// clr::SafeAddRef and clr::SafeRelease helpers.
+namespace clr
+{
+ //=================================================================================================================
+ template <typename ItfT>
+ static inline
+ typename std::enable_if< std::is_pointer<ItfT>::value, ItfT >::type
+ SafeAddRef(ItfT pItf)
+ {
+ STATIC_CONTRACT_LIMITED_METHOD;
+ if (pItf != nullptr)
+ {
+ pItf->AddRef();
+ }
+ return pItf;
+ }
+
+ //=================================================================================================================
+ template <typename ItfT>
+ typename std::enable_if< std::is_pointer<ItfT>::value && std::is_reference<ItfT>::value, ULONG >::type
+ SafeRelease(ItfT pItf)
+ {
+ STATIC_CONTRACT_LIMITED_METHOD;
+ ULONG res = 0;
+ if (pItf != nullptr)
+ {
+ res = pItf->Release();
+ pItf = nullptr;
+ }
+ return res;
+ }
+
+ //=================================================================================================================
+ template <typename ItfT>
+ typename std::enable_if< std::is_pointer<ItfT>::value && !std::is_reference<ItfT>::value, ULONG >::type
+ SafeRelease(ItfT pItf)
+ {
+ STATIC_CONTRACT_LIMITED_METHOD;
+ ULONG res = 0;
+ if (pItf != nullptr)
+ {
+ res = pItf->Release();
+ }
+ return res;
+ }
+}
+
+// clr::SafeDelete
+namespace clr
+{
+ //=================================================================================================================
+ template <typename PtrT>
+ static inline
+ typename std::enable_if< std::is_pointer<PtrT>::value, PtrT >::type
+ SafeDelete(PtrT & ptr)
+ {
+ STATIC_CONTRACT_LIMITED_METHOD;
+ if (ptr != nullptr)
+ {
+ delete ptr;
+ ptr = nullptr;
+ }
+ }
+}
+
+// ======================================================================================
+// Spinning support (used by VM and by MetaData via file:..\Utilcode\UTSem.cpp)
+
+struct SpinConstants
+{
+ DWORD dwInitialDuration;
+ DWORD dwMaximumDuration;
+ DWORD dwBackoffFactor;
+ DWORD dwRepetitions;
+};
+
+extern SpinConstants g_SpinConstants;
+
+// ======================================================================================
+
+#endif // __UtilCode_h__