diff options
Diffstat (limited to 'src/vm/util.hpp')
-rw-r--r-- | src/vm/util.hpp | 1382 |
1 files changed, 1382 insertions, 0 deletions
diff --git a/src/vm/util.hpp b/src/vm/util.hpp new file mode 100644 index 0000000000..d81eedb0df --- /dev/null +++ b/src/vm/util.hpp @@ -0,0 +1,1382 @@ +// 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. +// +// util.hpp +// + +// +// Miscellaneous useful functions +// + +#ifndef _H_UTIL +#define _H_UTIL + +#define MAX_UINT32_HEX_CHAR_LEN 8 // max number of chars representing an unsigned int32, not including terminating null char. +#define MAX_INT32_DECIMAL_CHAR_LEN 11 // max number of chars representing an int32, including sign, not including terminating null char. + +#include "utilcode.h" +#include "metadata.h" +#include "holderinst.h" +#include "clrdata.h" +#include "xclrdata.h" +#include "posterror.h" +#include "clr_std/type_traits" + + +// Prevent the use of UtilMessageBox and WszMessageBox from inside the EE. +#undef UtilMessageBoxCatastrophic +#undef UtilMessageBoxCatastrophicNonLocalized +#undef UtilMessageBoxCatastrophic +#undef UtilMessageBoxCatastrophicNonLocalizedVA +#undef UtilMessageBox +#undef UtilMessageBoxNonLocalized +#undef UtilMessageBoxVA +#undef UtilMessageBoxNonLocalizedVA +#undef WszMessageBox +#define UtilMessageBoxCatastrophic __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE") +#define UtilMessageBoxCatastrophicNonLocalized __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE") +#define UtilMessageBoxCatastrophicVA __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE") +#define UtilMessageBoxCatastrophicNonLocalizedVA __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE") +#define UtilMessageBox __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE") +#define UtilMessageBoxNonLocalized __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE") +#define UtilMessageBoxVA __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE") +#define UtilMessageBoxNonLocalizedVA __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE") +#define WszMessageBox __error("Use one of the EEMessageBox APIs (defined in eemessagebox.h) from inside the EE") + +//======================================================================== +// More convenient names for integer types of a guaranteed size. +//======================================================================== + +typedef __int8 I1; +typedef ArrayDPTR(I1) PTR_I1; +typedef unsigned __int8 U1; +typedef __int16 I2; +typedef unsigned __int16 U2; +typedef __int32 I4; +typedef unsigned __int32 U4; +typedef __int64 I8; +typedef unsigned __int64 U8; +typedef float R4; +typedef double R8; + +// +// Forward the FastInterlock methods to the matching Win32 APIs. They are implemented +// using compiler intrinsics so they are as fast as they can possibly be. +// + +// +// these don't have corresponding compiler intrinsics +// + +#ifdef FEATURE_SINGLE_THREADED +#define FastInterlockIncrement(a) (++(*a)) +#define FastInterlockDecrement(a) (--(*a)) +#define FastInterlockOr(a, b) (*a |= (DWORD)b) +#define FastInterlockAnd(a, b) (*a &= (DWORD)b) +#define FastInterlockIncrementLong(a) (++(*a)) +#define FastInterlockDecrementLong(a) (--(*a)) +#define FastInterlockOrLong(a, b) (*a |= (UINT64)b) +#define FastInterlockAndLong(a, b) (*a &= (UINT64)b) +#define FastInterlockCompareExchange InterlockedCompareExchange +#define FastInterlockCompareExchangePointer InterlockedCompareExchangeT + +#else + +// +// these DO have corresponding compiler intrinsics +// +#define FastInterlockIncrement InterlockedIncrement +#define FastInterlockDecrement InterlockedDecrement +#define FastInterlockExchange InterlockedExchange +#define FastInterlockCompareExchange InterlockedCompareExchange +#define FastInterlockExchangeAdd InterlockedExchangeAdd +#define FastInterlockExchangeLong InterlockedExchange64 +#define FastInterlockCompareExchangeLong InterlockedCompareExchange64 +#define FastInterlockExchangeAddLong InterlockedExchangeAdd64 + +// +// Forward FastInterlock[Compare]ExchangePointer to the +// Utilcode Interlocked[Compare]ExchangeT. +// +#define FastInterlockExchangePointer InterlockedExchangeT +#define FastInterlockCompareExchangePointer InterlockedCompareExchangeT + +FORCEINLINE void FastInterlockOr(DWORD RAW_KEYWORD(volatile) *p, const int msk) +{ + LIMITED_METHOD_CONTRACT; + + InterlockedOr((LONG *)p, msk); +} + +FORCEINLINE void FastInterlockAnd(DWORD RAW_KEYWORD(volatile) *p, const int msk) +{ + LIMITED_METHOD_CONTRACT; + + InterlockedAnd((LONG *)p, msk); +} + +#endif + +#ifndef FEATURE_PAL +// Copied from malloc.h: don't want to bring in the whole header file. +void * __cdecl _alloca(size_t); +#endif // !FEATURE_PAL + +#ifdef _PREFAST_ +// Suppress prefast warning #6255: alloca indicates failure by raising a stack overflow exception +#pragma warning(disable:6255) +#endif // _PREFAST_ + +// Function to parse apart a command line and return the +// arguments just like argv and argc +LPWSTR* CommandLineToArgvW(__in LPWSTR lpCmdLine, DWORD *pNumArgs); +#define ISWWHITE(x) ((x)==W(' ') || (x)==W('\t') || (x)==W('\n') || (x)==W('\r') ) + +BOOL inline FitsInI1(__int64 val) +{ + LIMITED_METHOD_DAC_CONTRACT; + return val == (__int64)(__int8)val; +} + +BOOL inline FitsInI2(__int64 val) +{ + LIMITED_METHOD_CONTRACT; + return val == (__int64)(__int16)val; +} + +BOOL inline FitsInI4(__int64 val) +{ + LIMITED_METHOD_DAC_CONTRACT; + return val == (__int64)(__int32)val; +} + +BOOL inline FitsInU1(unsigned __int64 val) +{ + LIMITED_METHOD_CONTRACT; + return val == (unsigned __int64)(unsigned __int8)val; +} + +BOOL inline FitsInU2(unsigned __int64 val) +{ + LIMITED_METHOD_CONTRACT; + return val == (unsigned __int64)(unsigned __int16)val; +} + +BOOL inline FitsInU4(unsigned __int64 val) +{ + LIMITED_METHOD_DAC_CONTRACT; + return val == (unsigned __int64)(unsigned __int32)val; +} + +// returns FALSE if overflows 15 bits: otherwise, (*pa) is incremented by b +BOOL inline SafeAddUINT15(UINT16 *pa, ULONG b) +{ + LIMITED_METHOD_CONTRACT; + + UINT16 a = *pa; + // first check if overflows 16 bits + if ( ((UINT16)b) != b ) + { + return FALSE; + } + // now make sure that doesn't overflow 15 bits + if (((ULONG)a + b) > 0x00007FFF) + { + return FALSE; + } + (*pa) += (UINT16)b; + return TRUE; +} + + +// returns FALSE if overflows 16 bits: otherwise, (*pa) is incremented by b +BOOL inline SafeAddUINT16(UINT16 *pa, ULONG b) +{ + UINT16 a = *pa; + if ( ((UINT16)b) != b ) + { + return FALSE; + } + // now make sure that doesn't overflow 16 bits + if (((ULONG)a + b) > 0x0000FFFF) + { + return FALSE; + } + (*pa) += (UINT16)b; + return TRUE; +} + + +// returns FALSE if overflow: otherwise, (*pa) is incremented by b +BOOL inline SafeAddUINT32(UINT32 *pa, UINT32 b) +{ + LIMITED_METHOD_CONTRACT; + + UINT32 a = *pa; + if ( ((UINT32)(a + b)) < a) + { + return FALSE; + } + (*pa) += b; + return TRUE; +} + +// returns FALSE if overflow: otherwise, (*pa) is incremented by b +BOOL inline SafeAddULONG(ULONG *pa, ULONG b) +{ + LIMITED_METHOD_CONTRACT; + + ULONG a = *pa; + if ( ((ULONG)(a + b)) < a) + { + return FALSE; + } + (*pa) += b; + return TRUE; +} + +// returns FALSE if overflow: otherwise, (*pa) is multiplied by b +BOOL inline SafeMulSIZE_T(SIZE_T *pa, SIZE_T b) +{ + LIMITED_METHOD_CONTRACT; + +#ifdef _DEBUG_IMPL + { + //Make sure SIZE_T is unsigned + SIZE_T m = ((SIZE_T)(-1)); + SIZE_T z = 0; + _ASSERTE(m > z); + } +#endif + + + SIZE_T a = *pa; + const SIZE_T m = ((SIZE_T)(-1)); + if ( (m / b) < a ) + { + return FALSE; + } + (*pa) *= b; + return TRUE; +} + + + +//************************************************************************ +// CQuickHeap +// +// A fast non-multithread-safe heap for short term use. +// Destroying the heap frees all blocks allocated from the heap. +// Blocks cannot be freed individually. +// +// The heap uses COM+ exceptions to report errors. +// +// The heap does not use any internal synchronization so it is not +// multithreadsafe. +//************************************************************************ +class CQuickHeap +{ + public: + CQuickHeap(); + ~CQuickHeap(); + + //--------------------------------------------------------------- + // Allocates a block of "sz" bytes. If there's not enough + // memory, throws an OutOfMemoryError. + //--------------------------------------------------------------- + LPVOID Alloc(UINT sz); + + + private: + enum { +#ifdef _DEBUG + kBlockSize = 24 +#else + kBlockSize = 1024 +#endif + }; + + // The QuickHeap allocates QuickBlock's as needed and chains + // them in a single-linked list. Most QuickBlocks have a size + // of kBlockSize bytes (not counting m_next), and individual + // allocation requests are suballocated from them. + // Allocation requests of greater than kBlockSize are satisfied + // by allocating a special big QuickBlock of the right size. + struct QuickBlock + { + QuickBlock *m_next; + BYTE m_bytes[1]; + }; + + + // Linked list of QuickBlock's. + QuickBlock *m_pFirstQuickBlock; + + // Offset to next available byte in m_pFirstQuickBlock. + LPBYTE m_pNextFree; + + // Linked list of big QuickBlock's + QuickBlock *m_pFirstBigQuickBlock; + +}; + +//====================================================================== +// String Helpers +// +// +// +ULONG StringHashValueW(__in LPWSTR wzString); +ULONG StringHashValueA(LPCSTR szString); + +void PrintToStdOutA(const char *pszString); +void PrintToStdOutW(const WCHAR *pwzString); +void PrintToStdErrA(const char *pszString); +void PrintToStdErrW(const WCHAR *pwzString); +void NPrintToStdOutA(const char *pszString, size_t nbytes); +void NPrintToStdOutW(const WCHAR *pwzString, size_t nchars); +void NPrintToStdErrA(const char *pszString, size_t nbytes); +void NPrintToStdErrW(const WCHAR *pwzString, size_t nchars); + + +//===================================================================== +// Function for formatted text output to the debugger +// +// +void __cdecl VMDebugOutputA(__in LPSTR format, ...); +void __cdecl VMDebugOutputW(__in LPWSTR format, ...); + +//===================================================================== +// VM-safe wrapper for PostError. +// +HRESULT VMPostError( // Returned error. + HRESULT hrRpt, // Reported error. + ...); // Error arguments. + +//===================================================================== +// Displays the messaage box or logs the message, corresponding to the last COM+ error occurred +void VMDumpCOMErrors(HRESULT hrErr); +HRESULT LoadMscorsn(); + +#include "nativevaraccessors.h" + +#ifndef FEATURE_PAL + +HRESULT WszSHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, size_t cchPath, __out_ecount(MAX_LONGPATH) LPWSTR pszwPath); +HRESULT WszShellExecute(HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd); + +#ifndef DACCESS_COMPILE +#include "shellapi.h" +HRESULT WszShellExecuteEx(LPSHELLEXECUTEINFO lpExecInfo); +#endif // #ifndef DACCESS_COMPILE + +#endif // !FEATURE_PAL + +BOOL GetUserDir(__out_ecount(bufferCount) WCHAR * buffer, size_t bufferCount, BOOL fRoaming); +BOOL GetInternetCacheDir(__out_ecount(bufferCount) WCHAR * buffer, size_t bufferCount ); + +HRESULT GetUserSidString (HANDLE hToken, __deref_out LPWSTR *wszSid); +BOOL IsUserProfileLoaded(); + +//====================================================================== +// Stack friendly registry helpers +// +LONG UtilRegEnumKey(HKEY hKey, // handle to key to query + DWORD dwIndex, // index of subkey to query + CQuickWSTR* lpName);// buffer for subkey name + +LONG UtilRegQueryStringValueEx(HKEY hKey, // handle to key to query + LPCWSTR lpValueName, // address of name of value to query + LPDWORD lpReserved, // reserved + LPDWORD lpType, // address of buffer for value type + CQuickWSTR* lpData);// data buffer + +//====================================================================== +// Event logging + +BOOL ReportEventCLR ( + IN WORD wType, // Event type - warning, error, success, etc + IN WORD wCategory, // Event category + IN DWORD dwEventID, // Event identifier (defined in shimr\msg.mc) + IN PSID lpUserSid, // user's security identifier + IN SString * message // message to log + ); + +// -------------------------------------------------------------------------------- +// GCX macros +// +// These are the normal way to change or assert the GC mode of a thread. They handle +// the required stack discipline in mode switches with an autodestructor which +// automatically triggers on leaving the current scope. +// +// Usage: +// GCX_COOP(); Switch to cooperative mode, assume thread is setup +// GCX_PREEMP(); Switch to preemptive mode, NOP if no thread setup +// GCX_COOP_THREAD_EXISTS(Thread*); Fast switch to cooperative mode, must pass non-null Thread +// GCX_PREEMP_THREAD_EXISTS(Thread*); Fast switch to preemptive mode, must pass non-null Thread +// +// (There is an intentional asymmetry between GCX_COOP and GCX_PREEMP. GCX_COOP +// asserts if you call it without having a Thread setup. GCX_PREEMP becomes a NOP. +// This is because all unmanaged threads are effectively preemp.) +// +// (There is actually one more case here - an "EE worker thread" such as the debugger +// thread or GC thread, which we don't want to call SetupThread() on, but which is +// effectively in cooperative mode due to explicit cooperation with the collector. +// This case is not handled by these macros; the current working assumption is that +// such threads never use them. But at some point we may have to consider +// this case if there is utility code which is called from those threads.) +// +// GCX_MAYBE_*(BOOL); Same as above, but only do the switch if BOOL is TRUE. +// +// GCX_ASSERT_*(); Same as above, but assert mode rather than switch to mode. +// Note that assert is applied during backout as well. +// No overhead in a free build. +// +// GCX_FORBID(); Add "ForbidGC" semantics to a cooperative mode situation. +// Asserts that the thread will not trigger a GC or +// reach a GC-safe point, or call anything that might +// do one of these things. +// +// GCX_NOTRIGGER(); "ForbidGC" without the automatic assertion for coop mode. +// +// -------------------------------------------------------------------------------- + +template<BOOL COOPERATIVE> +class AutoCleanupGCAssert; + +template<BOOL COOPERATIVE> +class GCAssert; + + +typedef AutoCleanupGCAssert<TRUE> AutoCleanupGCAssertCoop; +typedef AutoCleanupGCAssert<FALSE> AutoCleanupGCAssertPreemp; + +typedef GCAssert<TRUE> GCAssertCoop; +typedef GCAssert<FALSE> GCAssertPreemp; + +#if !defined(CROSSGEN_COMPILE) && !defined(DACCESS_COMPILE) + +#ifdef ENABLE_CONTRACTS_IMPL +#define GCX_COOP() GCCoop __gcHolder("GCX_COOP", __FUNCTION__, __FILE__, __LINE__) +#define GCX_COOP_NO_DTOR() GCCoopNoDtor __gcHolder; __gcHolder.Enter(TRUE, "GCX_COOP_NO_DTOR", __FUNCTION__, __FILE__, __LINE__) +#define GCX_COOP_NO_DTOR_END() __gcHolder.Leave(); +#else +#define GCX_COOP() GCCoop __gcHolder +#define GCX_COOP_NO_DTOR() GCCoopNoDtor __gcHolder; __gcHolder.Enter(TRUE) +#define GCX_COOP_NO_DTOR_END() __gcHolder.Leave(); +#endif + +#ifdef ENABLE_CONTRACTS_IMPL +#define GCX_PREEMP() GCPreemp __gcHolder("GCX_PREEMP", __FUNCTION__, __FILE__, __LINE__) +#define GCX_PREEMP_NO_DTOR() GCPreempNoDtor __gcHolder; __gcHolder.Enter(TRUE, "GCX_PREEMP_NO_DTOR", __FUNCTION__, __FILE__, __LINE__) +#define GCX_PREEMP_NO_DTOR_HAVE_THREAD(curThreadNullOk) GCPreempNoDtor __gcHolder; __gcHolder.Enter(curThreadNullOk, TRUE, "GCX_PREEMP_NO_DTOR_HAVE_THREAD", __FUNCTION__, __FILE__, __LINE__) +#define GCX_PREEMP_NO_DTOR_END() __gcHolder.Leave(); +#else +#define GCX_PREEMP() GCPreemp __gcHolder +#define GCX_PREEMP_NO_DTOR_HAVE_THREAD(curThreadNullOk) GCPreempNoDtor __gcHolder; __gcHolder.Enter(curThreadNullOk, TRUE) +#define GCX_PREEMP_NO_DTOR() GCPreempNoDtor __gcHolder; __gcHolder.Enter(TRUE) +#define GCX_PREEMP_NO_DTOR_END() __gcHolder.Leave() +#endif + +#ifdef ENABLE_CONTRACTS_IMPL +#define GCX_COOP_THREAD_EXISTS(curThread) GCCoopThreadExists __gcHolder((curThread), "GCX_COOP_THREAD_EXISTS", __FUNCTION__, __FILE__, __LINE__) +#else +#define GCX_COOP_THREAD_EXISTS(curThread) GCCoopThreadExists __gcHolder((curThread)) +#endif + +#ifdef ENABLE_CONTRACTS_IMPL +#define GCX_PREEMP_THREAD_EXISTS(curThread) GCPreempThreadExists __gcHolder((curThread), "GCX_PREEMP_THREAD_EXISTS", __FUNCTION__, __FILE__, __LINE__) +#else +#define GCX_PREEMP_THREAD_EXISTS(curThread) GCPreempThreadExists __gcHolder((curThread)) +#endif + +#ifdef ENABLE_CONTRACTS_IMPL +#define GCX_MAYBE_COOP(_cond) GCCoop __gcHolder(_cond, "GCX_MAYBE_COOP", __FUNCTION__, __FILE__, __LINE__) +#define GCX_MAYBE_COOP_NO_DTOR(_cond) GCCoopNoDtor __gcHolder; __gcHolder.Enter(_cond, "GCX_MAYBE_COOP_NO_DTOR", __FUNCTION__, __FILE__, __LINE__) +#define GCX_MAYBE_COOP_NO_DTOR_END() __gcHolder.Leave(); +#else +#define GCX_MAYBE_COOP(_cond) GCCoop __gcHolder(_cond) +#define GCX_MAYBE_COOP_NO_DTOR(_cond) GCCoopNoDtor __gcHolder; __gcHolder.Enter(_cond) +#define GCX_MAYBE_COOP_NO_DTOR_END() __gcHolder.Leave(); +#endif + +#ifdef ENABLE_CONTRACTS_IMPL +#define GCX_MAYBE_PREEMP(_cond) GCPreemp __gcHolder(_cond, "GCX_MAYBE_PREEMP", __FUNCTION__, __FILE__, __LINE__) +#define GCX_MAYBE_PREEMP_NO_DTOR(_cond) GCPreempNoDtor __gcHolder; __gcHolder.Enter(_cond, "GCX_MAYBE_PREEMP_NO_DTOR", __FUNCTION__, __FILE__, __LINE__) +#define GCX_MAYBE_PREEMP_NO_DTOR_END() __gcHolder.Leave(); +#else +#define GCX_MAYBE_PREEMP(_cond) GCPreemp __gcHolder(_cond) +#define GCX_MAYBE_PREEMP_NO_DTOR(_cond) GCPreempNoDtor __gcHolder; __gcHolder.Enter(_cond) +#define GCX_MAYBE_PREEMP_NO_DTOR_END() __gcHolder.Leave() +#endif + +#ifdef ENABLE_CONTRACTS_IMPL +#define GCX_MAYBE_COOP_THREAD_EXISTS(curThread, _cond) GCCoopThreadExists __gcHolder((curThread), (_cond), "GCX_MAYBE_COOP_THREAD_EXISTS", __FUNCTION__, __FILE__, __LINE__) +#else +#define GCX_MAYBE_COOP_THREAD_EXISTS(curThread, _cond) GCCoopThreadExists __gcHolder((curThread), (_cond)) +#endif + +#ifdef ENABLE_CONTRACTS_IMPL +#define GCX_MAYBE_PREEMP_THREAD_EXISTS(curThread, _cond) GCPreempThreadExists __gcHolder((curThread), (_cond), "GCX_MAYBE_PREEMP_THREAD_EXISTS", __FUNCTION__, __FILE__, __LINE__) +#else +#define GCX_MAYBE_PREEMP_THREAD_EXISTS(curThread, _cond) GCPreempThreadExists __gcHolder((curThread), (_cond)) +#endif + +// This has a potential race with the GC thread. It is currently +// used for a few cases where (a) we potentially haven't started up the EE yet, or +// (b) we are on a "special thread". +#ifdef ENABLE_CONTRACTS_IMPL +#define GCX_COOP_NO_THREAD_BROKEN() GCCoopHackNoThread __gcHolder("GCX_COOP_NO_THREAD_BROKEN", __FUNCTION__, __FILE__, __LINE__) +#else +#define GCX_COOP_NO_THREAD_BROKEN() GCCoopHackNoThread __gcHolder +#endif + + +#ifdef ENABLE_CONTRACTS_IMPL +#define GCX_MAYBE_COOP_NO_THREAD_BROKEN(_cond) GCCoopHackNoThread __gcHolder(_cond, "GCX_MAYBE_COOP_NO_THREAD_BROKEN", __FUNCTION__, __FILE__, __LINE__) +#else +#define GCX_MAYBE_COOP_NO_THREAD_BROKEN(_cond) GCCoopHackNoThread __gcHolder(_cond) +#endif + +#else // !defined(CROSSGEN_COMPILE) && !defined(DACCESS_COMPILE) + +#define GCX_COOP() +#define GCX_COOP_NO_DTOR() +#define GCX_COOP_NO_DTOR_END() + +#define GCX_PREEMP() +#define GCX_PREEMP_NO_DTOR() +#define GCX_PREEMP_NO_DTOR_HAVE_THREAD(curThreadNullOk) +#define GCX_PREEMP_NO_DTOR_END() + +#define GCX_MAYBE_PREEMP(_cond) + +#define GCX_COOP_NO_THREAD_BROKEN() +#define GCX_MAYBE_COOP_NO_THREAD_BROKEN(_cond) + +#define GCX_PREEMP_THREAD_EXISTS(curThread) +#define GCX_COOP_THREAD_EXISTS(curThread) + +#define GCX_POP() + +#endif // !defined(CROSSGEN_COMPILE) && !defined(DACCESS_COMPILE) + +#if defined(_DEBUG_IMPL) && !defined(CROSSGEN_COMPILE) + +#define GCX_ASSERT_PREEMP() ::AutoCleanupGCAssertPreemp __gcHolder +#define GCX_ASSERT_COOP() ::AutoCleanupGCAssertCoop __gcHolder + +#define BEGIN_GCX_ASSERT_COOP \ + { \ + GCAssertCoop __gcHolder; \ + __gcHolder.BeginGCAssert() + +#define END_GCX_ASSERT_COOP \ + __gcHolder.EndGCAssert(); \ + } + +#define BEGIN_GCX_ASSERT_PREEMP \ + { \ + GCAssertPreemp __gcHolder; \ + __gcHolder.BeginGCAssert() + +#define END_GCX_ASSERT_PREEMP \ + __gcHolder.EndGCAssert(); \ + } + + +#else + +#define GCX_ASSERT_PREEMP() +#define GCX_ASSERT_COOP() + +#define BEGIN_GCX_ASSERT_COOP \ + { +#define END_GCX_ASSERT_COOP \ + } +#define BEGIN_GCX_ASSERT_PREEMP \ + { +#define END_GCX_ASSERT_PREEMP \ + } + +#endif + +#ifdef ENABLE_CONTRACTS_IMPL + +#define GCX_FORBID() ::GCForbid __gcForbidHolder(__FUNCTION__, __FILE__, __LINE__) +#define GCX_NOTRIGGER() ::GCNoTrigger __gcNoTriggerHolder(__FUNCTION__, __FILE__, __LINE__) + +#define GCX_MAYBE_FORBID(fConditional) ::GCForbid __gcForbidHolder(fConditional, __FUNCTION__, __FILE__, __LINE__) +#define GCX_MAYBE_NOTRIGGER(fConditional) ::GCNoTrigger __gcNoTriggerHolder(fConditional, __FUNCTION__, __FILE__, __LINE__) + +#else + + +#define GCX_FORBID() +#define GCX_NOTRIGGER() + +#define GCX_MAYBE_FORBID(fConditional) +#define GCX_MAYBE_NOTRIGGER(fConditional) + +#endif + +typedef BOOL (*FnLockOwner)(LPVOID); +struct LockOwner +{ + LPVOID lock; + FnLockOwner lockOwnerFunc; +}; + +// this is the standard lockowner for things that require a lock owner but which really don't +// need any validation due to their simple/safe semantics +// the classic example of this is a hash table that is initialized and then never grows +extern LockOwner g_lockTrustMeIAmThreadSafe; + +// The OS ThreadId is not a stable ID for a thread we a host uses fiber instead of Thread. +// For each managed Thread, we have a stable and unique id in Thread object. For other threads, +// e.g. Server GC or Concurrent GC thread, debugger helper thread, we do not have a Thread object, +// and we use OS ThreadId to identify them since they are not managed by a host. +class EEThreadId +{ +private: + void *m_FiberPtrId; +public: +#ifdef _DEBUG + EEThreadId() + : m_FiberPtrId(NULL) + { + LIMITED_METHOD_CONTRACT; + } +#endif + + void SetToCurrentThread() + { + WRAPPER_NO_CONTRACT; + + m_FiberPtrId = ClrTeb::GetFiberPtrId(); + } + + bool IsCurrentThread() const + { + WRAPPER_NO_CONTRACT; + + return (m_FiberPtrId == ClrTeb::GetFiberPtrId()); + } + + +#ifdef _DEBUG + bool IsUnknown() const + { + LIMITED_METHOD_CONTRACT; + return m_FiberPtrId == NULL; + } +#endif + void Clear() + { + LIMITED_METHOD_CONTRACT; + m_FiberPtrId = NULL; + } +}; + +#ifdef FEATURE_INCLUDE_ALL_INTERFACES +#define CLRMEMORYHOSTED 0x1 +#define CLRTASKHOSTED 0x2 +#define CLRSYNCHOSTED 0x4 +#define CLRTHREADPOOLHOSTED 0x8 +#define CLRIOCOMPLETIONHOSTED 0x10 +#define CLRASSEMBLYHOSTED 0x20 +#define CLRGCHOSTED 0x40 +#define CLRSECURITYHOSTED 0x80 +#endif +#define CLRHOSTED 0x80000000 + +GVAL_DECL(DWORD, g_fHostConfig); + + +inline BOOL CLRHosted() +{ + LIMITED_METHOD_CONTRACT; + + return g_fHostConfig; +} + +#ifdef FEATURE_INCLUDE_ALL_INTERFACES +inline BOOL CLRMemoryHosted() +{ + LIMITED_METHOD_CONTRACT; + + return g_fHostConfig&CLRMEMORYHOSTED; +} + +inline BOOL CLRTaskHosted() +{ + // !!! Can not use contract here. + // !!! This function is called by Thread::DetachThread after we free TLS memory. + // !!! Contract will recreate TLS memory. + LIMITED_METHOD_DAC_CONTRACT; + + return g_fHostConfig&CLRTASKHOSTED; +} + +inline BOOL CLRSyncHosted() +{ + LIMITED_METHOD_CONTRACT; + + return g_fHostConfig&CLRSYNCHOSTED; +} +inline BOOL CLRThreadpoolHosted() +{ + LIMITED_METHOD_CONTRACT; + + return g_fHostConfig&CLRTHREADPOOLHOSTED; +} +inline BOOL CLRIoCompletionHosted() +{ + LIMITED_METHOD_CONTRACT; + + return g_fHostConfig&CLRIOCOMPLETIONHOSTED; +} +inline BOOL CLRAssemblyHosted() +{ + return g_fHostConfig&CLRASSEMBLYHOSTED; +} + +inline BOOL CLRGCHosted() +{ + LIMITED_METHOD_CONTRACT; + + return g_fHostConfig&CLRGCHOSTED; +} + +inline BOOL CLRSecurityHosted() +{ + LIMITED_METHOD_CONTRACT; + + return g_fHostConfig&CLRSECURITYHOSTED; +} +#else // FEATURE_INCLUDE_ALL_INTERFACES +inline BOOL CLRMemoryHosted() +{ + LIMITED_METHOD_CONTRACT; + return FALSE; +} + +inline BOOL CLRTaskHosted() +{ + LIMITED_METHOD_DAC_CONTRACT; + return FALSE; +} + +inline BOOL CLRSyncHosted() +{ + LIMITED_METHOD_CONTRACT; + return FALSE; +} + +inline BOOL CLRThreadpoolHosted() +{ + LIMITED_METHOD_CONTRACT; + return FALSE; +} + +inline BOOL CLRIoCompletionHosted() +{ + LIMITED_METHOD_CONTRACT; + return FALSE; +} + +inline BOOL CLRAssemblyHosted() +{ + LIMITED_METHOD_CONTRACT; + return FALSE; +} + +inline BOOL CLRGCHosted() +{ + LIMITED_METHOD_CONTRACT; + return FALSE; +} + +inline BOOL CLRSecurityHosted() +{ + LIMITED_METHOD_CONTRACT; + return FALSE; +} +#endif // FEATURE_INCLUDE_ALL_INTERFACES + +#ifndef FEATURE_PAL +HMODULE CLRGetModuleHandle(LPCWSTR lpModuleFileName); + +// Equivalent to CLRGetModuleHandle(NULL) but doesn't have the INJECT_FAULT contract associated +// with CLRGetModuleHandle. +HMODULE CLRGetCurrentModuleHandle(); + +HMODULE CLRLoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); +#endif // !FEATURE_PAL + +HMODULE CLRLoadLibrary(LPCWSTR lpLibFileName); + +BOOL CLRFreeLibrary(HMODULE hModule); +VOID CLRFreeLibraryAndExitThread(HMODULE hModule, DWORD dwExitCode); + +LPVOID +CLRMapViewOfFileEx( + IN HANDLE hFileMappingObject, + IN DWORD dwDesiredAccess, + IN DWORD dwFileOffsetHigh, + IN DWORD dwFileOffsetLow, + IN SIZE_T dwNumberOfBytesToMap, + IN LPVOID lpBaseAddress + ); + +LPVOID +CLRMapViewOfFile( + IN HANDLE hFileMappingObject, + IN DWORD dwDesiredAccess, + IN DWORD dwFileOffsetHigh, + IN DWORD dwFileOffsetLow, + IN SIZE_T dwNumberOfBytesToMap + ); + + +BOOL +CLRUnmapViewOfFile( + IN LPVOID lpBaseAddress + ); + +BOOL CompareFiles(HANDLE hFile1,HANDLE hFile2); + + +#ifndef DACCESS_COMPILE +FORCEINLINE void VoidCLRUnmapViewOfFile(void *ptr) { CLRUnmapViewOfFile(ptr); } +typedef Wrapper<void *, DoNothing, VoidCLRUnmapViewOfFile> CLRMapViewHolder; +#else +typedef Wrapper<void *, DoNothing, DoNothing> CLRMapViewHolder; +#endif + +void GetProcessMemoryLoad(LPMEMORYSTATUSEX pMSEX); + +void ProcessEventForHost(EClrEvent event, void *data); +void ProcessSOEventForHost(EXCEPTION_POINTERS *pExceptionInfo, BOOL fInSoTolerant); +BOOL IsHostRegisteredForEvent(EClrEvent event); + +#define SetupThreadForComCall(OOMRetVal) \ + MAKE_CURRENT_THREAD_AVAILABLE_EX(GetThreadNULLOk()); \ + if (CURRENT_THREAD == NULL) \ + { \ + CURRENT_THREAD = SetupThreadNoThrow(); \ + if (CURRENT_THREAD == NULL) \ + return OOMRetVal; \ + } \ + + +#define InternalSetupForComCall(CannotEnterRetVal, OOMRetVal, SORetVal, CheckCanRunManagedCode) \ +SetupThreadForComCall(OOMRetVal); \ +if (CheckCanRunManagedCode && !CanRunManagedCode()) \ + return CannotEnterRetVal; \ +SO_INTOLERANT_CODE_NOTHROW(CURRENT_THREAD, return SORetVal) \ + +#define ComCallHostNotificationHR() \ +ReverseEnterRuntimeHolderNoThrow REHolder; \ +if (CLRTaskHosted()) \ +{ \ + HRESULT hr = REHolder.AcquireNoThrow(); \ + if (FAILED(hr)) \ + { \ + return hr; \ + } \ +} + +#define SetupForComCallHRNoHostNotif() InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, true) +#define SetupForComCallHRNoHostNotifNoCheckCanRunManagedCode() InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, false) +#define SetupForComCallDWORDNoHostNotif() InternalSetupForComCall(-1, -1, -1, true) + +#define SetupForComCallHR() \ +InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, true) \ +ComCallHostNotificationHR() + +#define SetupForComCallHRNoCheckCanRunManagedCode() \ +InternalSetupForComCall(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, false) \ +ComCallHostNotificationHR() + +#ifdef FEATURE_CORRUPTING_EXCEPTIONS + +// Since Corrupting exceptions can escape COM interop boundaries, +// these macros will be used to setup the initial SO-Intolerant transition. +#define InternalSetupForComCallWithEscapingCorruptingExceptions(CannotEnterRetVal, OOMRetVal, SORetVal, CheckCanRunManagedCode) \ +if (CheckCanRunManagedCode && !CanRunManagedCode()) \ + return CannotEnterRetVal; \ +SetupThreadForComCall(OOMRetVal); \ +BEGIN_SO_INTOLERANT_CODE_NOTHROW(CURRENT_THREAD, SORetVal) \ + +#define BeginSetupForComCallHRWithEscapingCorruptingExceptions() \ +HRESULT __hr = S_OK; \ +InternalSetupForComCallWithEscapingCorruptingExceptions(HOST_E_CLRNOTAVAILABLE, E_OUTOFMEMORY, COR_E_STACKOVERFLOW, true) \ +ReverseEnterRuntimeHolderNoThrow REHolder; \ +if (CLRTaskHosted()) \ +{ \ + __hr = REHolder.AcquireNoThrow(); \ +} \ + \ +if (SUCCEEDED(__hr)) \ +{ \ + +#define EndSetupForComCallHRWithEscapingCorruptingExceptions() \ +} \ +END_SO_INTOLERANT_CODE; \ + \ +if (FAILED(__hr)) \ +{ \ + return __hr; \ +} \ + +#endif // FEATURE_CORRUPTING_EXCEPTIONS + +#define SetupForComCallDWORD() \ +InternalSetupForComCall(-1, -1, -1, true) \ +ReverseEnterRuntimeHolderNoThrow REHolder; \ +if (CLRTaskHosted()) \ +{ \ + if (FAILED(REHolder.AcquireNoThrow())) \ + { \ + return -1; \ + } \ +} + +// Special version of SetupForComCallDWORD that doesn't call +// CanRunManagedCode() to avoid firing LoaderLock MDA +#define SetupForComCallDWORDNoCheckCanRunManagedCode() \ +InternalSetupForComCall(-1, -1, -1, false) \ +ReverseEnterRuntimeHolderNoThrow REHolder; \ +if (CLRTaskHosted()) \ +{ \ + if (FAILED(REHolder.AcquireNoThrow())) \ + { \ + return -1; \ + } \ +} + +#include "unsafe.h" + +inline void UnsafeTlsFreeForHolder(DWORD* addr) +{ + WRAPPER_NO_CONTRACT; + + if (addr && *addr != TLS_OUT_OF_INDEXES) { + UnsafeTlsFree(*addr); + *addr = TLS_OUT_OF_INDEXES; + } +} + +// A holder to make sure tls slot is released and memory for allocated one is set to TLS_OUT_OF_INDEXES +typedef Holder<DWORD*, DoNothing<DWORD*>, UnsafeTlsFreeForHolder> TlsHolder; + +// A holder for HMODULE. +FORCEINLINE void VoidFreeLibrary(HMODULE h) { WRAPPER_NO_CONTRACT; CLRFreeLibrary(h); } + +typedef Wrapper<HMODULE, DoNothing<HMODULE>, VoidFreeLibrary, NULL> ModuleHandleHolder; + +#ifndef FEATURE_PAL + +// A holder for memory blocks allocated by Windows. This holder (and any OS APIs you call +// that allocate objects on your behalf) should not be used when the CLR is memory-hosted. + +FORCEINLINE void VoidFreeWinAllocatedBlock(LPVOID pv) +{ + LIMITED_METHOD_CONTRACT; + + _ASSERTE(!CLRMemoryHosted()); + +#pragma push_macro("GetProcessHeap") +#pragma push_macro("HeapFree") +#undef GetProcessHeap +#undef HeapFree + // 0: no special flags + ::HeapFree(::GetProcessHeap(), 0, pv); +#pragma pop_macro("HeapFree") +#pragma pop_macro("GetProcessHeap") +} + +typedef Wrapper<LPVOID, DoNothing<LPVOID>, VoidFreeWinAllocatedBlock, NULL> WinAllocatedBlockHolder; + +#endif // !FEATURE_PAL + +// For debugging, we can track arbitrary Can't-Stop regions. +// In V1.0, this was on the Thread object, but we need to track this for threads w/o a Thread object. +FORCEINLINE void IncCantStopCount() +{ + ClrFlsIncrementValue(TlsIdx_CantStopCount, 1); +} + +FORCEINLINE void DecCantStopCount() +{ + ClrFlsIncrementValue(TlsIdx_CantStopCount, -1); +} + +typedef StateHolder<IncCantStopCount, DecCantStopCount> CantStopHolder; + +#ifdef _DEBUG +// For debug-only, this can be used w/ a holder to ensure that we're keeping our CS count balanced. +// We should never use this w/ control flow. +inline int GetCantStopCount() +{ + return (int) (size_t) ClrFlsGetValue(TlsIdx_CantStopCount); +} + +// At places where we know we're calling out to native code, we can assert that we're NOT in a CS region. +// This is _debug only since we only use it for asserts; not for real code-flow control in a retail build. +inline bool IsInCantStopRegion() +{ + return (GetCantStopCount() > 0); +} +#endif // _DEBUG + + +// PAL does not support per-thread locales. The holder is no-op for FEATURE_PALs +class ThreadLocaleHolder +{ +#ifndef FEATURE_PAL +public: + + ThreadLocaleHolder() + { + m_locale = GetThreadLocale(); + } + + ~ThreadLocaleHolder(); + +private: + LCID m_locale; +#endif // !FEATURE_PAL +}; + + + +BOOL IsValidMethodCodeNotification(USHORT Notification); + +typedef DPTR(struct JITNotification) PTR_JITNotification; +struct JITNotification +{ + USHORT state; // values from CLRDataMethodCodeNotification + TADDR clrModule; + mdToken methodToken; + + JITNotification() { SetFree(); } + BOOL IsFree() { return state == CLRDATA_METHNOTIFY_NONE; } + void SetFree() { state = CLRDATA_METHNOTIFY_NONE; clrModule = NULL; methodToken = 0; } + void SetState(TADDR moduleIn, mdToken tokenIn, USHORT NType) + { + _ASSERTE(IsValidMethodCodeNotification(NType)); + clrModule = moduleIn; + methodToken = tokenIn; + state = NType; + } +}; + +// The maximum number of TADDR sized arguments that the SOS exception notification can use +#define MAX_CLR_NOTIFICATION_ARGS 3 +GARY_DECL(size_t, g_clrNotificationArguments, MAX_CLR_NOTIFICATION_ARGS); +extern void InitializeClrNotifications(); + +GPTR_DECL(JITNotification, g_pNotificationTable); +GVAL_DECL(ULONG32, g_dacNotificationFlags); + +#if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE) + +inline void +InitializeJITNotificationTable() +{ + g_pNotificationTable = new (nothrow) JITNotification[1001]; +} + +#endif // FEATURE_PAL && !DACCESS_COMPILE + +class JITNotifications +{ +public: + JITNotifications(JITNotification *jitTable); + BOOL SetNotification(TADDR clrModule, mdToken token, USHORT NType); + USHORT Requested(TADDR clrModule, mdToken token); + + // if clrModule is NULL, all active notifications are changed to NType + BOOL SetAllNotifications(TADDR clrModule,USHORT NType,BOOL *changedOut); + inline BOOL IsActive() { LIMITED_METHOD_CONTRACT; return m_jitTable!=NULL; } + + UINT GetTableSize(); +#ifdef DACCESS_COMPILE + static JITNotification *InitializeNotificationTable(UINT TableSize); + // Updates target table from host copy + BOOL UpdateOutOfProcTable(); +#endif + +private: + UINT GetLength(); + void IncrementLength(); + void DecrementLength(); + + BOOL FindItem(TADDR clrModule, mdToken token, UINT *indexOut); + + JITNotification *m_jitTable; +}; + +typedef DPTR(struct GcNotification) PTR_GcNotification; + +inline +BOOL IsValidGcNotification(GcEvt_t evType) +{ return (evType < GC_EVENT_TYPE_MAX); } + +#define CLRDATA_GC_NONE 0 + +struct GcNotification +{ + GcEvtArgs ev; + + GcNotification() { SetFree(); } + BOOL IsFree() { return ev.typ == CLRDATA_GC_NONE; } + void SetFree() { memset(this, 0, sizeof(*this)); ev.typ = (GcEvt_t) CLRDATA_GC_NONE; } + void Set(GcEvtArgs ev_) + { + _ASSERTE(IsValidGcNotification(ev_.typ)); + ev = ev_; + } + BOOL IsMatch(GcEvtArgs ev_) + { + LIMITED_METHOD_CONTRACT; + if (ev.typ != ev_.typ) + { + return FALSE; + } + switch (ev.typ) + { + case GC_MARK_END: + if (ev_.condemnedGeneration == 0 || + (ev.condemnedGeneration & ev_.condemnedGeneration) != 0) + { + return TRUE; + } + break; + default: + break; + } + + return FALSE; + } +}; + +GPTR_DECL(GcNotification, g_pGcNotificationTable); + +class GcNotifications +{ +public: + GcNotifications(GcNotification *gcTable); + BOOL SetNotification(GcEvtArgs ev); + GcEvtArgs* GetNotification(GcEvtArgs ev) + { + LIMITED_METHOD_CONTRACT; + UINT idx; + if (FindItem(ev, &idx)) + { + return &m_gcTable[idx].ev; + } + else + { + return NULL; + } + } + + // if clrModule is NULL, all active notifications are changed to NType + inline BOOL IsActive() + { return m_gcTable != NULL; } + + UINT GetTableSize() + { return Size(); } + +#ifdef DACCESS_COMPILE + static GcNotification *InitializeNotificationTable(UINT TableSize); + // Updates target table from host copy + BOOL UpdateOutOfProcTable(); +#endif + +private: + UINT& Length() + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(IsActive()); + UINT *pLen = (UINT *) &(m_gcTable[-1].ev.typ); + return *pLen; + } + UINT& Size() + { + _ASSERTE(IsActive()); + UINT *pLen = (UINT *) &(m_gcTable[-1].ev.typ); + return *(pLen+1); + } + void IncrementLength() + { ++Length(); } + void DecrementLength() + { --Length(); } + + BOOL FindItem(GcEvtArgs ev, UINT *indexOut); + + GcNotification *m_gcTable; +}; + + +class MethodDesc; +class Module; + +class DACNotify +{ +public: + // types + enum { + MODULE_LOAD_NOTIFICATION=1, + MODULE_UNLOAD_NOTIFICATION=2, + JIT_NOTIFICATION=3, + JIT_DISCARD_NOTIFICATION=4, + EXCEPTION_NOTIFICATION=5, + GC_NOTIFICATION= 6, + CATCH_ENTER_NOTIFICATION = 7, + }; + + // called from the runtime + static void DoJITNotification(MethodDesc *MethodDescPtr); + static void DoJITDiscardNotification(MethodDesc *MethodDescPtr); + static void DoModuleLoadNotification(Module *Module); + static void DoModuleUnloadNotification(Module *Module); + static void DoExceptionNotification(class Thread* ThreadPtr); + static void DoGCNotification(const GcEvtArgs& evtargs); + static void DoExceptionCatcherEnterNotification(MethodDesc *MethodDescPtr, DWORD nativeOffset); + + // called from the DAC + static int GetType(TADDR Args[]); + static BOOL ParseJITNotification(TADDR Args[], TADDR& MethodDescPtr); + static BOOL ParseJITDiscardNotification(TADDR Args[], TADDR& MethodDescPtr); + static BOOL ParseModuleLoadNotification(TADDR Args[], TADDR& ModulePtr); + static BOOL ParseModuleUnloadNotification(TADDR Args[], TADDR& ModulePtr); + static BOOL ParseExceptionNotification(TADDR Args[], TADDR& ThreadPtr); + static BOOL ParseGCNotification(TADDR Args[], GcEvtArgs& evtargs); + static BOOL ParseExceptionCatcherEnterNotification(TADDR Args[], TADDR& MethodDescPtr, DWORD& nativeOffset); +}; + +void DACNotifyCompilationFinished(MethodDesc *pMethodDesc); + +#ifdef _DEBUG +#ifndef FEATURE_PAL +// NOTE: Windows Vista RTM SDK defines CaptureStackBackTrace as RtlCaptureStackBackTrace (in winbase.h) +// Renamed CaptureStackBackTrace to UtilCaptureBackTrace in order to avoid conflicts with the Windows definition +USHORT UtilCaptureStackBackTrace( + ULONG FramesToSkip, + ULONG FramesToCapture, + PVOID * BackTrace, + OUT PULONG BackTraceHash); +#endif // !FEATURE_PAL +#endif //_DEBUG + + +// These wrap the SString:L:CompareCaseInsenstive function in a way that makes it +// easy to fix code that uses _stricmp. _stricmp should be avoided as it uses the current +// C-runtime locale rather than the invariance culture. +// +// Note that unlike the real _stricmp, these functions unavoidably have a throws/gc_triggers/inject_fault +// contract. So if need a case-insensitive comparison in a place where you can't tolerate this contract, +// you've got a problem. +int __cdecl stricmpUTF8(const char* szStr1, const char* szStr2); + +#ifdef _DEBUG +class DisableDelayLoadCheckForOleaut32 +{ +public: + DisableDelayLoadCheckForOleaut32(); + ~DisableDelayLoadCheckForOleaut32(); +}; +#endif + +extern LONG g_OLEAUT32_Loaded; + +#ifndef FEATURE_CORECLR +#define ENSURE_OLEAUT32_LOADED() \ +{ \ + /* Should only be used in FCALL */ \ + _ASSERTE (__me != 0); \ + if (g_OLEAUT32_Loaded == 0) \ + { \ + /* CLRLoadLibrary/CLRFreeLibrary claim they trigger, but this */ \ + /* isn't really true in this case because we're loading oleaut32 */ \ + /* which we know doesn't contain any managed code in its DLLMain */ \ + CONTRACT_VIOLATION(GCViolation|SOToleranceViolation); \ + HMODULE hMod = CLRLoadLibrary(W("oleaut32")); \ + if (hMod == NULL) \ + { \ + __FCThrow(__me, kOutOfMemoryException, 0, 0, 0, 0); \ + } \ + else \ + { \ + if (FastInterlockExchange(&g_OLEAUT32_Loaded, 1) == 1) \ + { \ + CLRFreeLibrary(hMod); \ + } \ + } \ + } \ +} \ +INDEBUG(DisableDelayLoadCheckForOleaut32 _disableOleaut32Check); +#else // !FEATURE_CORECLR +#define ENSURE_OLEAUT32_LOADED() +#endif // !FEATURE_CORECLR + +BOOL DbgIsExecutable(LPVOID lpMem, SIZE_T length); + +#ifndef DACCESS_COMPILE +// returns if ARM was already enabled or not. +BOOL EnableARM(); +#endif // !DACCESS_COMPILE + +int GetRandomInt(int maxVal); + +class InternalCasingHelper { + + private: + // Convert szIn to lower case in the Invariant locale. + // TODO: NLS Arrowhead -Called by the two ToLowers) + static INT32 InvariantToLowerHelper(__out_bcount_opt(cMaxBytes) LPUTF8 szOut, int cMaxBytes, __in_z LPCUTF8 szIn, BOOL fAllowThrow); + + public: + // + // Native helper functions to do correct casing operations in + // runtime native code. + // + + // Convert szIn to lower case in the Invariant locale. (WARNING: May throw.) + static INT32 InvariantToLower(__out_bcount_opt(cMaxBytes) LPUTF8 szOut, int cMaxBytes, __in_z LPCUTF8 szIn); + + // Convert szIn to lower case in the Invariant locale. (WARNING: This version + // won't throw but it will use stack space as an intermediary (so don't + // use for ridiculously long strings.) + static INT32 InvariantToLowerNoThrow(__out_bcount_opt(cMaxBytes) LPUTF8 szOut, int cMaxBytes, __in_z LPCUTF8 szIn); +}; + +// +// +// COMCHARACTER +// +// +class COMCharacter { +public: + //These are here for support from native code. They are never called from our managed classes. + static BOOL nativeIsWhiteSpace(WCHAR c); + static BOOL nativeIsDigit(WCHAR c); +}; + +#ifdef _DEBUG +#define FORCEINLINE_NONDEBUG +#else +#define FORCEINLINE_NONDEBUG FORCEINLINE +#endif + +#ifndef FEATURE_PAL +// Extract the file version from an executable. +HRESULT GetFileVersion(LPCWSTR wszFilePath, ULARGE_INTEGER* pFileVersion); +#endif // !FEATURE_PAL + +#endif /* _H_UTIL */ + |