1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//*****************************************************************************
5// UtilCode.h
6//
7// Utility functions implemented in UtilCode.lib.
8//
9//*****************************************************************************
10
11#ifndef __UtilCode_h__
12#define __UtilCode_h__
13
14#include "crtwrap.h"
15#include "winwrap.h"
16#include <wchar.h>
17#include <stdio.h>
18#include <malloc.h>
19#include <ole2.h>
20#include <oleauto.h>
21#include <limits.h>
22#include "clrtypes.h"
23#include "safewrap.h"
24#include "volatile.h"
25#include <daccess.h>
26#include "clrhost.h"
27#include "debugmacros.h"
28#include "corhlprpriv.h"
29#include "winnls.h"
30#include "check.h"
31#include "safemath.h"
32#include "new.hpp"
33
34#ifdef PAL_STDCPP_COMPAT
35#include <type_traits>
36#else
37#include "clr_std/type_traits"
38#endif
39
40#include "contract.h"
41#include "entrypoints.h"
42
43#include "clrnt.h"
44
45#include "random.h"
46
47#define WINDOWS_KERNEL32_DLLNAME_A "kernel32"
48#define WINDOWS_KERNEL32_DLLNAME_W W("kernel32")
49
50#define CoreLibName_W W("System.Private.CoreLib")
51#define CoreLibName_IL_W W("System.Private.CoreLib.dll")
52#define CoreLibName_NI_W W("System.Private.CoreLib.ni.dll")
53#define CoreLibName_TLB_W W("System.Private.CoreLib.tlb")
54#define CoreLibName_A "System.Private.CoreLib"
55#define CoreLibName_IL_A "System.Private.CoreLib.dll"
56#define CoreLibName_NI_A "System.Private.CoreLib.ni.dll"
57#define CoreLibName_TLB_A "System.Private.CoreLib.tlb"
58#define CoreLibNameLen 22
59#define CoreLibSatelliteName_A "System.Private.CoreLib.resources"
60#define CoreLibSatelliteNameLen 32
61#define LegacyCoreLibName_A "mscorlib"
62
63class StringArrayList;
64
65#if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE)
66#define _DEBUG_IMPL 1
67#endif
68
69#ifdef _TARGET_ARM_
70
71// Under ARM we generate code only with Thumb encoding. In order to ensure we execute such code in the correct
72// mode we must ensure the low-order bit is set in any code address we'll call as a sub-routine. In C++ this
73// is handled automatically for us by the compiler. When generating and working with code generated
74// dynamically we have to be careful to set or mask-out this bit as appropriate.
75#ifndef THUMB_CODE
76#define THUMB_CODE 1
77#endif
78
79// Given a WORD extract the bitfield [lowbit, highbit] (i.e. BitExtract(0xffff, 15, 0) == 0xffff).
80inline WORD BitExtract(WORD wValue, DWORD highbit, DWORD lowbit)
81{
82 _ASSERTE((highbit < 16) && (lowbit < 16) && (highbit >= lowbit));
83 return (wValue >> lowbit) & ((1 << ((highbit - lowbit) + 1)) - 1);
84}
85
86// Determine whether an ARM Thumb mode instruction is 32-bit or 16-bit based on the first WORD of the
87// instruction.
88inline bool Is32BitInstruction(WORD opcode)
89{
90 return BitExtract(opcode, 15, 11) >= 0x1d;
91}
92
93template <typename ResultType, typename SourceType>
94inline ResultType DataPointerToThumbCode(SourceType pCode)
95{
96 return (ResultType)(((UINT_PTR)pCode) | THUMB_CODE);
97}
98
99template <typename ResultType, typename SourceType>
100inline ResultType ThumbCodeToDataPointer(SourceType pCode)
101{
102 return (ResultType)(((UINT_PTR)pCode) & ~THUMB_CODE);
103}
104
105#endif // _TARGET_ARM_
106
107// Convert from a PCODE to the corresponding PINSTR. On many architectures this will be the identity function;
108// on ARM, this will mask off the THUMB bit.
109inline TADDR PCODEToPINSTR(PCODE pc)
110{
111#ifdef _TARGET_ARM_
112 return ThumbCodeToDataPointer<TADDR,PCODE>(pc);
113#else
114 return dac_cast<PCODE>(pc);
115#endif
116}
117
118// Convert from a PINSTR to the corresponding PCODE. On many architectures this will be the identity function;
119// on ARM, this will raise the THUMB bit.
120inline PCODE PINSTRToPCODE(TADDR addr)
121{
122#ifdef _TARGET_ARM_
123 return DataPointerToThumbCode<PCODE,TADDR>(addr);
124#else
125 return dac_cast<PCODE>(addr);
126#endif
127}
128
129typedef LPCSTR LPCUTF8;
130typedef LPSTR LPUTF8;
131
132#include "nsutilpriv.h"
133
134#include "stdmacros.h"
135
136//********** Macros. **********************************************************
137#ifndef FORCEINLINE
138 #if _MSC_VER < 1200
139 #define FORCEINLINE inline
140 #else
141 #define FORCEINLINE __forceinline
142 #endif
143#endif
144
145#ifndef DEBUG_NOINLINE
146#if defined(_DEBUG)
147#define DEBUG_NOINLINE __declspec(noinline)
148#else
149#define DEBUG_NOINLINE
150#endif
151#endif
152
153#ifndef DBG_NOINLINE_X86__RET_INLINE
154#if defined(_DEBUG) && defined(_TARGET_X86_)
155// this exists to make scan work on x86.
156#define DBG_NOINLINE_X86__RET_INLINE __declspec(noinline)
157#else
158#define DBG_NOINLINE_X86__RET_INLINE FORCEINLINE
159#endif
160#endif
161
162#include <stddef.h> // for offsetof
163
164#ifndef NumItems
165// Number of elements in a fixed-size array
166#define NumItems(s) (sizeof(s) / sizeof(s[0]))
167#endif
168
169#ifndef StrLen
170// Number of characters in a string literal. Excludes terminating NULL.
171#define StrLen(str) (NumItems(str) - 1)
172#endif
173
174
175#define IS_DIGIT(ch) ((ch >= W('0')) && (ch <= W('9')))
176#define DIGIT_TO_INT(ch) (ch - W('0'))
177#define INT_TO_DIGIT(i) ((WCHAR)(W('0') + i))
178
179#define IS_HEXDIGIT(ch) (((ch >= W('a')) && (ch <= W('f'))) || \
180 ((ch >= W('A')) && (ch <= W('F'))))
181#define HEXDIGIT_TO_INT(ch) ((towlower(ch) - W('a')) + 10)
182#define INT_TO_HEXDIGIT(i) ((WCHAR)(W('a') + (i - 10)))
183
184
185// Helper will 4 byte align a value, rounding up.
186#define ALIGN4BYTE(val) (((val) + 3) & ~0x3)
187
188#ifdef _DEBUG
189#define DEBUGARG(x) , x
190#else
191#define DEBUGARG(x)
192#endif
193
194#ifndef sizeofmember
195// Returns the size of a class or struct member.
196#define sizeofmember(c,m) (sizeof(((c*)0)->m))
197#endif
198
199//=--------------------------------------------------------------------------=
200// Prefast helpers.
201//
202
203#include "safemath.h"
204
205
206//=--------------------------------------------------------------------------=
207// string helpers.
208
209//
210// given and ANSI String, copy it into a wide buffer.
211// be careful about scoping when using this macro!
212//
213// how to use the below two macros:
214//
215// ...
216// LPSTR pszA;
217// pszA = MyGetAnsiStringRoutine();
218// MAKE_WIDEPTR_FROMANSI(pwsz, pszA);
219// MyUseWideStringRoutine(pwsz);
220// ...
221//
222// similarily for MAKE_ANSIPTR_FROMWIDE. note that the first param does not
223// have to be declared, and no clean up must be done.
224//
225
226// We'll define an upper limit that allows multiplication by 4 (the max
227// bytes/char in UTF-8) but still remains positive, and allows some room for pad.
228// Under normal circumstances, we should never get anywhere near this limit.
229#define MAKE_MAX_LENGTH 0x1fffff00
230
231#ifndef MAKE_TOOLONGACTION
232#define MAKE_TOOLONGACTION ThrowHR(COR_E_OVERFLOW)
233#endif
234
235#ifndef MAKE_TRANSLATIONFAILED
236#define MAKE_TRANSLATIONFAILED ThrowWin32(ERROR_NO_UNICODE_TRANSLATION)
237#endif
238
239// This version throws on conversion errors (ie, no best fit character
240// mapping to characters that look similar, and no use of the default char
241// ('?') when printing out unrepresentable characters. Use this method for
242// most development in the EE, especially anything like metadata or class
243// names. See the BESTFIT version if you're printing out info to the console.
244#define MAKE_MULTIBYTE_FROMWIDE(ptrname, widestr, codepage) \
245 int __l##ptrname = (int)wcslen(widestr); \
246 if (__l##ptrname > MAKE_MAX_LENGTH) \
247 MAKE_TOOLONGACTION; \
248 __l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
249 CQuickBytes __CQuickBytes##ptrname; \
250 __CQuickBytes##ptrname.AllocThrows(__l##ptrname); \
251 BOOL __b##ptrname; \
252 DWORD __cBytes##ptrname = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, -1, (LPSTR)__CQuickBytes##ptrname.Ptr(), __l##ptrname, NULL, &__b##ptrname); \
253 if (__b##ptrname || (__cBytes##ptrname == 0 && (widestr[0] != W('\0')))) { \
254 MAKE_TRANSLATIONFAILED; \
255 } \
256 LPSTR ptrname = (LPSTR)__CQuickBytes##ptrname.Ptr()
257
258// This version does best fit character mapping and also allows the use
259// of the default char ('?') for any Unicode character that isn't
260// representable. This is reasonable for writing to the console, but
261// shouldn't be used for most string conversions.
262#define MAKE_MULTIBYTE_FROMWIDE_BESTFIT(ptrname, widestr, codepage) \
263 int __l##ptrname = (int)wcslen(widestr); \
264 if (__l##ptrname > MAKE_MAX_LENGTH) \
265 MAKE_TOOLONGACTION; \
266 __l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
267 CQuickBytes __CQuickBytes##ptrname; \
268 __CQuickBytes##ptrname.AllocThrows(__l##ptrname); \
269 DWORD __cBytes##ptrname = WszWideCharToMultiByte(codepage, 0, widestr, -1, (LPSTR)__CQuickBytes##ptrname.Ptr(), __l##ptrname, NULL, NULL); \
270 if (__cBytes##ptrname == 0 && __l##ptrname != 0) { \
271 MAKE_TRANSLATIONFAILED; \
272 } \
273 LPSTR ptrname = (LPSTR)__CQuickBytes##ptrname.Ptr()
274
275// Use for anything critical other than output to console, where weird
276// character mappings are unacceptable.
277#define MAKE_ANSIPTR_FROMWIDE(ptrname, widestr) MAKE_MULTIBYTE_FROMWIDE(ptrname, widestr, CP_ACP)
278
279// Use for output to the console.
280#define MAKE_ANSIPTR_FROMWIDE_BESTFIT(ptrname, widestr) MAKE_MULTIBYTE_FROMWIDE_BESTFIT(ptrname, widestr, CP_ACP)
281
282#define MAKE_WIDEPTR_FROMANSI(ptrname, ansistr) \
283 CQuickBytes __qb##ptrname; \
284 int __l##ptrname; \
285 __l##ptrname = WszMultiByteToWideChar(CP_ACP, 0, ansistr, -1, 0, 0); \
286 if (__l##ptrname > MAKE_MAX_LENGTH) \
287 MAKE_TOOLONGACTION; \
288 LPWSTR ptrname = (LPWSTR) __qb##ptrname.AllocThrows((__l##ptrname+1)*sizeof(WCHAR)); \
289 if (WszMultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, ansistr, -1, ptrname, __l##ptrname) == 0) { \
290 MAKE_TRANSLATIONFAILED; \
291 }
292
293#define MAKE_WIDEPTR_FROMANSI_NOTHROW(ptrname, ansistr) \
294 CQuickBytes __qb##ptrname; \
295 LPWSTR ptrname = 0; \
296 int __l##ptrname; \
297 __l##ptrname = WszMultiByteToWideChar(CP_ACP, 0, ansistr, -1, 0, 0); \
298 if (__l##ptrname <= MAKE_MAX_LENGTH) { \
299 ptrname = (LPWSTR) __qb##ptrname.AllocNoThrow((__l##ptrname+1)*sizeof(WCHAR)); \
300 if (ptrname) { \
301 if (WszMultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, ansistr, -1, ptrname, __l##ptrname) != 0) { \
302 ptrname[__l##ptrname] = 0; \
303 } else { \
304 ptrname = 0; \
305 } \
306 } \
307 }
308
309#define MAKE_UTF8PTR_FROMWIDE(ptrname, widestr) CQuickBytes _##ptrname; _##ptrname.ConvertUnicode_Utf8(widestr); LPSTR ptrname = (LPSTR) _##ptrname.Ptr();
310
311#define MAKE_UTF8PTR_FROMWIDE_NOTHROW(ptrname, widestr) \
312 CQuickBytes __qb##ptrname; \
313 int __l##ptrname = (int)wcslen(widestr); \
314 LPUTF8 ptrname = 0; \
315 if (__l##ptrname <= MAKE_MAX_LENGTH) { \
316 __l##ptrname = (int)((__l##ptrname + 1) * 2 * sizeof(char)); \
317 ptrname = (LPUTF8) __qb##ptrname.AllocNoThrow(__l##ptrname); \
318 } \
319 if (ptrname) { \
320 INT32 __lresult##ptrname=WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, ptrname, __l##ptrname-1, NULL, NULL); \
321 DWORD __dwCaptureLastError##ptrname = ::GetLastError(); \
322 if ((__lresult##ptrname==0) && (((LPCWSTR)widestr)[0] != W('\0'))) { \
323 if (__dwCaptureLastError##ptrname==ERROR_INSUFFICIENT_BUFFER) { \
324 INT32 __lsize##ptrname=WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, NULL, 0, NULL, NULL); \
325 ptrname = (LPSTR) __qb##ptrname .AllocNoThrow(__lsize##ptrname); \
326 if (ptrname) { \
327 if (WszWideCharToMultiByte(CP_UTF8, 0, widestr, -1, ptrname, __lsize##ptrname, NULL, NULL) != 0) { \
328 ptrname[__l##ptrname] = 0; \
329 } else { \
330 ptrname = 0; \
331 } \
332 } \
333 } \
334 else { \
335 ptrname = 0; \
336 } \
337 } \
338 } \
339
340#define MAKE_WIDEPTR_FROMUTF8N(ptrname, utf8str, n8chrs) \
341 CQuickBytes __qb##ptrname; \
342 int __l##ptrname; \
343 __l##ptrname = WszMultiByteToWideChar(CP_UTF8, 0, utf8str, n8chrs, 0, 0); \
344 if (__l##ptrname > MAKE_MAX_LENGTH) \
345 MAKE_TOOLONGACTION; \
346 LPWSTR ptrname = (LPWSTR) __qb##ptrname .AllocThrows((__l##ptrname+1)*sizeof(WCHAR)); \
347 if (0==WszMultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8str, n8chrs, ptrname, __l##ptrname)) { \
348 MAKE_TRANSLATIONFAILED; \
349 } \
350 ptrname[__l##ptrname] = 0;
351
352
353#define MAKE_WIDEPTR_FROMUTF8(ptrname, utf8str) CQuickBytes _##ptrname; _##ptrname.ConvertUtf8_Unicode(utf8str); LPCWSTR ptrname = (LPCWSTR) _##ptrname.Ptr();
354
355
356#define MAKE_WIDEPTR_FROMUTF8N_NOTHROW(ptrname, utf8str, n8chrs) \
357 CQuickBytes __qb##ptrname; \
358 int __l##ptrname; \
359 LPWSTR ptrname = 0; \
360 __l##ptrname = WszMultiByteToWideChar(CP_UTF8, 0, utf8str, n8chrs, 0, 0); \
361 if (__l##ptrname <= MAKE_MAX_LENGTH) { \
362 ptrname = (LPWSTR) __qb##ptrname.AllocNoThrow((__l##ptrname+1)*sizeof(WCHAR)); \
363 if (ptrname) { \
364 if (WszMultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8str, n8chrs, ptrname, __l##ptrname) != 0) { \
365 ptrname[__l##ptrname] = 0; \
366 } else { \
367 ptrname = 0; \
368 } \
369 } \
370 }
371
372#define MAKE_WIDEPTR_FROMUTF8_NOTHROW(ptrname, utf8str) MAKE_WIDEPTR_FROMUTF8N_NOTHROW(ptrname, utf8str, -1)
373
374// This method takes the number of characters
375#define MAKE_MULTIBYTE_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt, codepage) \
376 CQuickBytes __qb##ptrname; \
377 int __l##ptrname; \
378 __l##ptrname = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, _nCharacters, NULL, 0, NULL, NULL); \
379 if (__l##ptrname > MAKE_MAX_LENGTH) \
380 MAKE_TOOLONGACTION; \
381 ptrname = (LPUTF8) __qb##ptrname .AllocThrows(__l##ptrname+1); \
382 BOOL __b##ptrname; \
383 DWORD _pCnt = WszWideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, widestr, _nCharacters, ptrname, __l##ptrname, NULL, &__b##ptrname); \
384 if (__b##ptrname || (_pCnt == 0 && _nCharacters > 0)) { \
385 MAKE_TRANSLATIONFAILED; \
386 } \
387 ptrname[__l##ptrname] = 0;
388
389#define MAKE_MULTIBYTE_FROMWIDEN_BESTFIT(ptrname, widestr, _nCharacters, _pCnt, codepage) \
390 CQuickBytes __qb##ptrname; \
391 int __l##ptrname; \
392 __l##ptrname = WszWideCharToMultiByte(codepage, 0, widestr, _nCharacters, NULL, 0, NULL, NULL); \
393 if (__l##ptrname > MAKE_MAX_LENGTH) \
394 MAKE_TOOLONGACTION; \
395 ptrname = (LPUTF8) __qb##ptrname .AllocThrows(__l##ptrname+1); \
396 DWORD _pCnt = WszWideCharToMultiByte(codepage, 0, widestr, _nCharacters, ptrname, __l##ptrname, NULL, NULL); \
397 if (_pCnt == 0 && _nCharacters > 0) { \
398 MAKE_TRANSLATIONFAILED; \
399 } \
400 ptrname[__l##ptrname] = 0;
401
402#define MAKE_ANSIPTR_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt) \
403 MAKE_MULTIBYTE_FROMWIDEN(ptrname, widestr, _nCharacters, _pCnt, CP_ACP)
404
405
406inline
407LPWSTR DuplicateString(
408 LPCWSTR wszString,
409 size_t cchString)
410{
411 STATIC_CONTRACT_NOTHROW;
412
413 LPWSTR wszDup = NULL;
414 if (wszString != NULL)
415 {
416 wszDup = new (nothrow) WCHAR[cchString + 1];
417 if (wszDup != NULL)
418 {
419 wcscpy_s(wszDup, cchString + 1, wszString);
420 }
421 }
422 return wszDup;
423}
424
425inline
426LPWSTR DuplicateString(
427 LPCWSTR wszString)
428{
429 STATIC_CONTRACT_NOTHROW;
430
431 if (wszString != NULL)
432 {
433 return DuplicateString(wszString, wcslen(wszString));
434 }
435 else
436 {
437 return NULL;
438 }
439}
440
441void DECLSPEC_NORETURN ThrowOutOfMemory();
442
443inline
444LPWSTR DuplicateStringThrowing(
445 LPCWSTR wszString,
446 size_t cchString)
447{
448 STATIC_CONTRACT_THROWS;
449
450 if (wszString == NULL)
451 return NULL;
452
453 LPWSTR wszDup = DuplicateString(wszString, cchString);
454 if (wszDup == NULL)
455 ThrowOutOfMemory();
456
457 return wszDup;
458}
459
460inline
461LPWSTR DuplicateStringThrowing(
462 LPCWSTR wszString)
463{
464 STATIC_CONTRACT_THROWS;
465
466 if (wszString == NULL)
467 return NULL;
468
469 LPWSTR wszDup = DuplicateString(wszString);
470 if (wszDup == NULL)
471 ThrowOutOfMemory();
472
473 return wszDup;
474}
475
476
477//*****************************************************************************
478// Placement new is used to new and object at an exact location. The pointer
479// is simply returned to the caller without actually using the heap. The
480// advantage here is that you cause the ctor() code for the object to be run.
481// This is ideal for heaps of C++ objects that need to get init'd multiple times.
482// Example:
483// void *pMem = GetMemFromSomePlace();
484// Foo *p = new (pMem) Foo;
485// DoSomething(p);
486// p->~Foo();
487//*****************************************************************************
488#ifndef __PLACEMENT_NEW_INLINE
489#define __PLACEMENT_NEW_INLINE
490inline void *__cdecl operator new(size_t, void *_P)
491{
492 LIMITED_METHOD_DAC_CONTRACT;
493
494 return (_P);
495}
496#endif // __PLACEMENT_NEW_INLINE
497
498
499/********************************************************************************/
500/* portability helpers */
501#ifdef _WIN64
502#define IN_WIN64(x) x
503#define IN_WIN32(x)
504#else
505#define IN_WIN64(x)
506#define IN_WIN32(x) x
507#endif
508
509#ifdef _TARGET_64BIT_
510#define IN_TARGET_64BIT(x) x
511#define IN_TARGET_32BIT(x)
512#else
513#define IN_TARGET_64BIT(x)
514#define IN_TARGET_32BIT(x) x
515#endif
516
517void * __cdecl
518operator new(size_t n);
519
520_Ret_bytecap_(n) void * __cdecl
521operator new[](size_t n);
522
523void __cdecl
524operator delete(void *p) NOEXCEPT;
525
526void __cdecl
527operator delete[](void *p) NOEXCEPT;
528
529#ifdef _DEBUG_IMPL
530HRESULT _OutOfMemory(LPCSTR szFile, int iLine);
531#define OutOfMemory() _OutOfMemory(__FILE__, __LINE__)
532#else
533inline HRESULT OutOfMemory()
534{
535 LIMITED_METHOD_CONTRACT;
536 return (E_OUTOFMEMORY);
537}
538#endif
539
540//*****************************************************************************
541// Handle accessing localizable resource strings
542//*****************************************************************************
543// NOTE: Should use locale names as much as possible. LCIDs don't support
544// custom cultures on Vista+.
545// TODO: This should always use the names
546#ifdef FEATURE_USE_LCID
547typedef LCID LocaleID;
548typedef LCID LocaleIDValue;
549#else
550typedef LPCWSTR LocaleID;
551typedef WCHAR LocaleIDValue[LOCALE_NAME_MAX_LENGTH];
552#endif
553
554// Notes about the culture callbacks:
555// - The language we're operating in can change at *runtime*!
556// - A process may operate in *multiple* languages.
557// (ex: Each thread may have it's own language)
558// - If we don't care what language we're in (or have no way of knowing),
559// then return a 0-length name and UICULTUREID_DONTCARE for the culture ID.
560// - GetCultureName() and the GetCultureId() must be in sync (refer to the
561// same language).
562// - We have two functions separate functions for better performance.
563// - The name is used to resolve a directory for MsCorRC.dll.
564// - The id is used as a key to map to a dll hinstance.
565
566// Callback to obtain both the culture name and the culture's parent culture name
567typedef HRESULT (*FPGETTHREADUICULTURENAMES)(__inout StringArrayList* pCultureNames);
568#ifdef FEATURE_USE_LCID
569// Callback to return the culture ID.
570const LCID UICULTUREID_DONTCARE = (LCID)-1;
571#else
572const LPCWSTR UICULTUREID_DONTCARE = NULL;
573#endif
574
575typedef int (*FPGETTHREADUICULTUREID)(LocaleIDValue*);
576
577HMODULE CLRLoadLibrary(LPCWSTR lpLibFileName);
578
579HMODULE CLRLoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
580
581BOOL CLRFreeLibrary(HMODULE hModule);
582
583// Prevent people from using LoadStringRC & LoadStringRCEx from inside the product since it
584// causes issues with having the wrong version picked up inside the shim.
585#define LoadStringRC __error("From inside the CLR, use UtilLoadStringRC; LoadStringRC is only meant to be exported.")
586#define LoadStringRCEx __error("From inside the CLR, use UtilLoadStringRCEx; LoadStringRC is only meant to be exported.")
587
588// Load a string using the resources for the current module.
589STDAPI UtilLoadStringRC(UINT iResouceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax, int bQuiet=FALSE);
590
591#ifdef FEATURE_USE_LCID
592STDAPI UtilLoadStringRCEx(LCID lcid, UINT iResourceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax, int bQuiet, int *pcwchUsed);
593#endif
594
595// Specify callbacks so that UtilLoadStringRC can find out which language we're in.
596// If no callbacks specified (or both parameters are NULL), we default to the
597// resource dll in the root (which is probably english).
598void SetResourceCultureCallbacks(
599 FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
600 FPGETTHREADUICULTUREID fpGetThreadUICultureId
601);
602
603void GetResourceCultureCallbacks(
604 FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
605 FPGETTHREADUICULTUREID* fpGetThreadUICultureId
606);
607
608#if !defined(DACCESS_COMPILE)
609// Get the MUI ID, on downlevel platforms where MUI is not supported it
610// returns the default system ID.
611extern int GetMUILanguageID(LocaleIDValue* pResult);
612extern HRESULT GetMUILanguageNames(__inout StringArrayList* pCultureNames);
613
614#endif // !defined(DACCESS_COMPILE)
615
616//*****************************************************************************
617// Use this class by privately deriving from noncopyable to disallow copying of
618// your class.
619//*****************************************************************************
620class noncopyable
621{
622protected:
623 noncopyable()
624 {}
625 ~noncopyable()
626 {}
627
628private:
629 noncopyable(const noncopyable&);
630 const noncopyable& operator=(const noncopyable&);
631};
632
633//*****************************************************************************
634// Must associate each handle to an instance of a resource dll with the int
635// that it represents
636//*****************************************************************************
637typedef HINSTANCE HRESOURCEDLL;
638
639
640class CCulturedHInstance
641{
642 LocaleIDValue m_LangId;
643 HRESOURCEDLL m_hInst;
644 BOOL m_fMissing;
645
646public:
647 CCulturedHInstance()
648 {
649 LIMITED_METHOD_CONTRACT;
650 m_hInst = NULL;
651 m_fMissing = FALSE;
652 }
653
654 BOOL HasID(LocaleID id)
655 {
656 _ASSERTE(m_hInst != NULL || m_fMissing);
657 if (id == UICULTUREID_DONTCARE)
658 return FALSE;
659
660#ifdef FEATURE_USE_LCID
661 return id == m_LangId;
662#else
663 return wcscmp(id, m_LangId) == 0;
664#endif
665 }
666
667 HRESOURCEDLL GetLibraryHandle()
668 {
669 return m_hInst;
670 }
671
672 BOOL IsSet()
673 {
674 return m_hInst != NULL;
675 }
676
677 BOOL IsMissing()
678 {
679 return m_fMissing;
680 }
681
682 void SetMissing(LocaleID id)
683 {
684 _ASSERTE(m_hInst == NULL);
685 SetId(id);
686 m_fMissing = TRUE;
687 }
688
689 void Set(LocaleID id, HRESOURCEDLL hInst)
690 {
691 _ASSERTE(m_hInst == NULL);
692 _ASSERTE(m_fMissing == FALSE);
693 SetId(id);
694 m_hInst = hInst;
695 }
696 private:
697 void SetId(LocaleID id)
698 {
699#ifdef FEATURE_USE_LCID
700 m_LangId = id;
701#else
702 if (id != UICULTUREID_DONTCARE)
703 {
704 wcsncpy_s(m_LangId, NumItems(m_LangId), id, NumItems(m_LangId));
705 m_LangId[NumItems(m_LangId)-1] = W('\0');
706 }
707 else
708 {
709 m_LangId[0] = W('\0');
710 }
711#endif
712 }
713 };
714
715#ifndef DACCESS_COMPILE
716void AddThreadPreferredUILanguages(StringArrayList* pArray);
717#endif
718//*****************************************************************************
719// CCompRC manages string Resource access for COM+. This includes loading
720// the MsCorRC.dll for resources as well allowing each thread to use a
721// a different localized version.
722//*****************************************************************************
723class CCompRC
724{
725public:
726
727 enum ResourceCategory
728 {
729 // must be present
730 Required,
731
732 // present in Desktop CLR and Core CLR + debug pack, an error
733 // If missing, get a generic error message instead
734 Error,
735
736 // present in Desktop CLR and Core CLR + debug pack, normal operation (e.g tracing)
737 // if missing, get a generic "resource not found" message instead
738 Debugging,
739
740 // present in Desktop CLR, optional for CoreCLR
741 DesktopCLR,
742
743 // might not be present, non essential
744 Optional
745 };
746
747 CCompRC()
748 {
749 // This constructor will be fired up on startup. Make sure it doesn't
750 // do anything besides zero-out out values.
751 m_bUseFallback = FALSE;
752
753 m_fpGetThreadUICultureId = NULL;
754 m_fpGetThreadUICultureNames = NULL;
755
756
757 m_pHash = NULL;
758 m_nHashSize = 0;
759 m_csMap = NULL;
760 m_pResourceFile = NULL;
761#ifdef FEATURE_PAL
762 m_pResourceDomain = NULL;
763#endif // FEATURE_PAL
764
765 }// CCompRC
766
767 HRESULT Init(LPCWSTR pResourceFile, BOOL bUseFallback = FALSE);
768 void Destroy();
769
770 BOOL ShouldUseFallback()
771 {
772 LIMITED_METHOD_CONTRACT;
773 return m_bUseFallback;
774 };
775
776 static void SetIsMscoree() {s_bIsMscoree = TRUE;}
777
778 HRESULT LoadString(ResourceCategory eCategory, UINT iResourceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax , int *pcwchUsed=NULL);
779 HRESULT LoadString(ResourceCategory eCategory, LocaleID langId, UINT iResourceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax, int *pcwchUsed);
780
781 void SetResourceCultureCallbacks(
782 FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
783 FPGETTHREADUICULTUREID fpGetThreadUICultureId
784 );
785
786 void GetResourceCultureCallbacks(
787 FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
788 FPGETTHREADUICULTUREID* fpGetThreadUICultureId
789 );
790
791 HRESULT LoadMUILibrary(HRESOURCEDLL * pHInst);
792
793 // Get the default resource location (mscorrc.dll for desktop, mscorrc.debug.dll for CoreCLR)
794 static CCompRC* GetDefaultResourceDll();
795 // Get the generic messages dll (Silverlight only, mscorrc.dll)
796 static CCompRC* GetFallbackResourceDll();
797 static void ShutdownDefaultResourceDll();
798 static void GetDefaultCallbacks(
799 FPGETTHREADUICULTURENAMES* fpGetThreadUICultureNames,
800 FPGETTHREADUICULTUREID* fpGetThreadUICultureId)
801 {
802 WRAPPER_NO_CONTRACT;
803 m_DefaultResourceDll.GetResourceCultureCallbacks(
804 fpGetThreadUICultureNames,
805 fpGetThreadUICultureId);
806 }
807
808 static void SetDefaultCallbacks(
809 FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames,
810 FPGETTHREADUICULTUREID fpGetThreadUICultureId)
811 {
812 WRAPPER_NO_CONTRACT;
813 // Either both are NULL or neither are NULL
814 _ASSERTE((fpGetThreadUICultureNames != NULL) ==
815 (fpGetThreadUICultureId != NULL));
816
817 m_DefaultResourceDll.SetResourceCultureCallbacks(
818 fpGetThreadUICultureNames,
819 fpGetThreadUICultureId);
820
821 m_FallbackResourceDll.SetResourceCultureCallbacks(
822 fpGetThreadUICultureNames,
823 fpGetThreadUICultureId);
824
825 }
826
827#ifdef USE_FORMATMESSAGE_WRAPPER
828
829DWORD
830PALAPI
831static
832FormatMessage(
833 IN DWORD dwFlags,
834 IN LPCVOID lpSource,
835 IN DWORD dwMessageId,
836 IN DWORD dwLanguageId,
837 OUT LPWSTR lpBuffer,
838 IN DWORD nSize,
839 IN va_list *Arguments);
840#endif // USE_FORMATMESSAGE_WRAPPER
841
842
843private:
844 HRESULT GetLibrary(LocaleID langId, HRESOURCEDLL* phInst);
845#ifndef DACCESS_COMPILE
846 HRESULT LoadLibraryHelper(HRESOURCEDLL *pHInst,
847 SString& rcPath);
848 HRESULT LoadLibraryThrows(HRESOURCEDLL * pHInst);
849 HRESULT LoadLibrary(HRESOURCEDLL * pHInst);
850 HRESULT LoadResourceFile(HRESOURCEDLL * pHInst, LPCWSTR lpFileName);
851#endif
852
853 // We do not have global constructors any more
854 static LONG m_dwDefaultInitialized;
855 static CCompRC m_DefaultResourceDll;
856 static LPCWSTR m_pDefaultResource;
857
858 // fallback resources if debug pack is not installed
859 static LONG m_dwFallbackInitialized;
860 static CCompRC m_FallbackResourceDll;
861 static LPCWSTR m_pFallbackResource;
862
863 // We must map between a thread's int and a dll instance.
864 // Since we only expect 1 language almost all of the time, we'll special case
865 // that and then use a variable size map for everything else.
866 CCulturedHInstance m_Primary;
867 CCulturedHInstance * m_pHash;
868 int m_nHashSize;
869
870 CRITSEC_COOKIE m_csMap;
871
872 LPCWSTR m_pResourceFile;
873#ifdef FEATURE_PAL
874 // Resource domain is an ANSI string identifying a native resources file
875 static LPCSTR m_pDefaultResourceDomain;
876 static LPCSTR m_pFallbackResourceDomain;
877 LPCSTR m_pResourceDomain;
878#endif // FEATURE_PAL
879
880 // Main accessors for hash
881 HRESOURCEDLL LookupNode(LocaleID langId, BOOL &fMissing);
882 HRESULT AddMapNode(LocaleID langId, HRESOURCEDLL hInst, BOOL fMissing = FALSE);
883
884 FPGETTHREADUICULTUREID m_fpGetThreadUICultureId;
885 FPGETTHREADUICULTURENAMES m_fpGetThreadUICultureNames;
886
887 BOOL m_bUseFallback;
888 static BOOL s_bIsMscoree;
889};
890
891HRESULT UtilLoadResourceString(CCompRC::ResourceCategory eCategory, UINT iResouceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax);
892
893
894int UtilMessageBox(
895 HWND hWnd, // Handle to Owner Window
896 UINT uText, // Resource Identifier for Text message
897 UINT uCaption, // Resource Identifier for Caption
898 UINT uType, // Style of MessageBox
899 BOOL displayForNonInteractive, // Display even if the process is running non interactive
900 BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
901 ...); // Additional Arguments
902
903int UtilMessageBoxNonLocalized(
904 HWND hWnd, // Handle to Owner Window
905 LPCWSTR lpText, // Resource Identifier for Text message
906 LPCWSTR lpTitle, // Resource Identifier for Caption
907 UINT uType, // Style of MessageBox
908 BOOL displayForNonInteractive, // Display even if the process is running non interactive
909 BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
910 ...); // Additional Arguments
911
912int UtilMessageBoxVA(
913 HWND hWnd, // Handle to Owner Window
914 UINT uText, // Resource Identifier for Text message
915 UINT uCaption, // Resource Identifier for Caption
916 UINT uType, // Style of MessageBox
917 BOOL displayForNonInteractive, // Display even if the process is running non interactive
918 BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
919 va_list args); // Additional Arguments
920
921int UtilMessageBoxNonLocalizedVA(
922 HWND hWnd, // Handle to Owner Window
923 LPCWSTR lpText, // Text message
924 LPCWSTR lpCaption, // Caption
925 UINT uType, // Style of MessageBox
926 BOOL displayForNonInteractive, // Display even if the process is running non interactive
927 BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
928 BOOL * pInputFromUser, // To distinguish between user pressing abort vs. assuming abort.
929 va_list args); // Additional Arguments
930
931int UtilMessageBoxNonLocalizedVA(
932 HWND hWnd, // Handle to Owner Window
933 LPCWSTR lpText, // Text message
934 LPCWSTR lpCaption, // Caption
935 LPCWSTR lpDetails, // Details that may be shown in a collapsed extended area of the dialog (Vista or higher).
936 UINT uType, // Style of MessageBox
937 BOOL displayForNonInteractive, // Display even if the process is running non interactive
938 BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
939 BOOL * pInputFromUser, // To distinguish between user pressing abort vs. assuming abort.
940 va_list args); // Additional Arguments
941
942int UtilMessageBoxCatastrophic(
943 UINT uText, // Text for MessageBox
944 UINT uTitle, // Title for MessageBox
945 UINT uType, // Style of MessageBox
946 BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
947 ...);
948
949int UtilMessageBoxCatastrophicNonLocalized(
950 LPCWSTR lpText, // Text for MessageBox
951 LPCWSTR lpTitle, // Title for MessageBox
952 UINT uType, // Style of MessageBox
953 BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
954 ...);
955
956int UtilMessageBoxCatastrophicVA(
957 UINT uText, // Text for MessageBox
958 UINT uTitle, // Title for MessageBox
959 UINT uType, // Style of MessageBox
960 BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
961 va_list args); // Additional Arguments
962
963int UtilMessageBoxCatastrophicNonLocalizedVA(
964 LPCWSTR lpText, // Text for MessageBox
965 LPCWSTR lpTitle, // Title for MessageBox
966 UINT uType, // Style of MessageBox
967 BOOL ShowFileNameInTitle, // Flag to show FileName in Caption
968 va_list args); // Additional Arguments
969
970
971// The HRESULT_FROM_WIN32 macro evaluates its arguments three times.
972// <TODO>TODO: All HRESULT_FROM_WIN32(GetLastError()) should be replaced by calls to
973// this helper function avoid code bloat</TODO>
974inline HRESULT HRESULT_FROM_GetLastError()
975{
976 WRAPPER_NO_CONTRACT;
977 DWORD dw = GetLastError();
978 // Make sure we return a failure
979 if (dw == ERROR_SUCCESS)
980 {
981 _ASSERTE(!"We were expecting to get an error code, but a success code is being returned. Check this code path for Everett!");
982 return E_FAIL;
983 }
984 else
985 return HRESULT_FROM_WIN32(dw);
986}
987
988inline HRESULT HRESULT_FROM_GetLastErrorNA()
989{
990 WRAPPER_NO_CONTRACT;
991 DWORD dw = GetLastError();
992 // Make sure we return a failure
993 if (dw == ERROR_SUCCESS)
994 return E_FAIL;
995 else
996 return HRESULT_FROM_WIN32(dw);
997}
998
999inline HRESULT BadError(HRESULT hr)
1000{
1001 LIMITED_METHOD_CONTRACT;
1002 _ASSERTE(!"Serious Error");
1003 return (hr);
1004}
1005
1006#define TESTANDRETURN(test, hrVal) \
1007{ \
1008 int ___test = (int)(test); \
1009 if (! ___test) \
1010 return hrVal; \
1011}
1012
1013#define TESTANDRETURNPOINTER(pointer) \
1014 TESTANDRETURN(pointer!=NULL, E_POINTER)
1015
1016#define TESTANDRETURNMEMORY(pointer) \
1017 TESTANDRETURN(pointer!=NULL, E_OUTOFMEMORY)
1018
1019#define TESTANDRETURNHR(hr) \
1020 TESTANDRETURN(SUCCEEDED(hr), hr)
1021
1022#define TESTANDRETURNARG(argtest) \
1023 TESTANDRETURN(argtest, E_INVALIDARG)
1024
1025// Quick validity check for HANDLEs that are returned by Win32 APIs that
1026// use INVALID_HANDLE_VALUE instead of NULL to indicate an error
1027inline BOOL IsValidHandle(HANDLE h)
1028{
1029 LIMITED_METHOD_CONTRACT;
1030 return ((h != NULL) && (h != INVALID_HANDLE_VALUE));
1031}
1032
1033// Count the bits in a value in order iBits time.
1034inline int CountBits(int iNum)
1035{
1036 LIMITED_METHOD_CONTRACT;
1037 int iBits;
1038 for (iBits=0; iNum; iBits++)
1039 iNum = iNum & (iNum - 1);
1040 return (iBits);
1041}
1042
1043#include "bitposition.h"
1044
1045// Convert the currency to a decimal and canonicalize.
1046inline void VarDecFromCyCanonicalize(CY cyIn, DECIMAL* dec)
1047{
1048 WRAPPER_NO_CONTRACT;
1049
1050 (*(ULONG*)dec) = 0;
1051 DECIMAL_HI32(*dec) = 0;
1052 if (cyIn.int64 == 0) // For compatibility, a currency of 0 emits the Decimal "0.0000" (scale set to 4).
1053 {
1054 DECIMAL_SCALE(*dec) = 4;
1055 DECIMAL_LO32(*dec) = 0;
1056 DECIMAL_MID32(*dec) = 0;
1057 return;
1058 }
1059
1060 if (cyIn.int64 < 0) {
1061 DECIMAL_SIGN(*dec) = DECIMAL_NEG;
1062 cyIn.int64 = -cyIn.int64;
1063 }
1064
1065 BYTE scale = 4;
1066 ULONGLONG absoluteCy = (ULONGLONG)cyIn.int64;
1067 while (scale != 0 && ((absoluteCy % 10) == 0))
1068 {
1069 scale--;
1070 absoluteCy /= 10;
1071 }
1072 DECIMAL_SCALE(*dec) = scale;
1073 DECIMAL_LO32(*dec) = (ULONG)absoluteCy;
1074 DECIMAL_MID32(*dec) = (ULONG)(absoluteCy >> 32);
1075}
1076
1077//*****************************************************************************
1078//
1079// Paths functions. Use these instead of the CRT.
1080//
1081//*****************************************************************************
1082// secure version! Specify the size of the each buffer in count of elements
1083void SplitPath(const WCHAR *path,
1084 __inout_z __inout_ecount_opt(driveSizeInWords) WCHAR *drive, int driveSizeInWords,
1085 __inout_z __inout_ecount_opt(dirSizeInWords) WCHAR *dir, int dirSizeInWords,
1086 __inout_z __inout_ecount_opt(fnameSizeInWords) WCHAR *fname, size_t fnameSizeInWords,
1087 __inout_z __inout_ecount_opt(extSizeInWords) WCHAR *ext, size_t extSizeInWords);
1088
1089//*******************************************************************************
1090// A much more sensible version that just points to each section of the string.
1091//*******************************************************************************
1092void SplitPathInterior(
1093 __in LPCWSTR wszPath,
1094 __out_opt LPCWSTR *pwszDrive, __out_opt size_t *pcchDrive,
1095 __out_opt LPCWSTR *pwszDir, __out_opt size_t *pcchDir,
1096 __out_opt LPCWSTR *pwszFileName, __out_opt size_t *pcchFileName,
1097 __out_opt LPCWSTR *pwszExt, __out_opt size_t *pcchExt);
1098
1099
1100void MakePath(__out CQuickWSTR &path,
1101 __in LPCWSTR drive,
1102 __in LPCWSTR dir,
1103 __in LPCWSTR fname,
1104 __in LPCWSTR ext);
1105
1106WCHAR * FullPath(__out_ecount (maxlen) WCHAR *UserBuf, const WCHAR *path, size_t maxlen);
1107
1108//*****************************************************************************
1109//
1110// SString version of the path functions.
1111//
1112//*****************************************************************************
1113void SplitPath(__in SString const &path,
1114 __inout_opt SString *drive,
1115 __inout_opt SString *dir,
1116 __inout_opt SString *fname,
1117 __inout_opt SString *ext);
1118
1119#if !defined(NO_CLRCONFIG)
1120
1121//*****************************************************************************
1122//
1123// **** REGUTIL - Static helper functions for reading/writing to Windows registry.
1124//
1125//*****************************************************************************
1126
1127
1128class REGUTIL
1129{
1130public:
1131//*****************************************************************************
1132
1133 enum CORConfigLevel
1134 {
1135 COR_CONFIG_ENV = 0x01,
1136 COR_CONFIG_USER = 0x02,
1137 COR_CONFIG_MACHINE = 0x04,
1138 COR_CONFIG_FUSION = 0x08,
1139
1140 COR_CONFIG_REGISTRY = (COR_CONFIG_USER|COR_CONFIG_MACHINE|COR_CONFIG_FUSION),
1141 COR_CONFIG_ALL = (COR_CONFIG_ENV|COR_CONFIG_USER|COR_CONFIG_MACHINE),
1142 };
1143
1144 //
1145 // NOTE: The following function is deprecated; use the CLRConfig class instead.
1146 // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
1147 //
1148 static DWORD GetConfigDWORD_DontUse_(
1149 LPCWSTR name,
1150 DWORD defValue,
1151 CORConfigLevel level = COR_CONFIG_ALL,
1152 BOOL fPrependCOMPLUS = TRUE);
1153
1154 //
1155 // NOTE: The following function is deprecated; use the CLRConfig class instead.
1156 // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
1157 //
1158 static HRESULT GetConfigDWORD_DontUse_(
1159 LPCWSTR name,
1160 DWORD defValue,
1161 __out DWORD * result,
1162 CORConfigLevel level = COR_CONFIG_ALL,
1163 BOOL fPrependCOMPLUS = TRUE);
1164
1165 static ULONGLONG GetConfigULONGLONG_DontUse_(
1166 LPCWSTR name,
1167 ULONGLONG defValue,
1168 CORConfigLevel level = COR_CONFIG_ALL,
1169 BOOL fPrependCOMPLUS = TRUE);
1170
1171 //
1172 // NOTE: The following function is deprecated; use the CLRConfig class instead.
1173 // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
1174 //
1175 static DWORD GetConfigFlag_DontUse_(
1176 LPCWSTR name,
1177 DWORD bitToSet,
1178 BOOL defValue = FALSE);
1179
1180 //
1181 // NOTE: The following function is deprecated; use the CLRConfig class instead.
1182 // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
1183 //
1184 static LPWSTR GetConfigString_DontUse_(
1185 LPCWSTR name,
1186 BOOL fPrependCOMPLUS = TRUE,
1187 CORConfigLevel level = COR_CONFIG_ALL,
1188 BOOL fUsePerfCache = TRUE);
1189
1190 static void FreeConfigString(__in __in_z LPWSTR name);
1191
1192private:
1193 static LPWSTR EnvGetString(LPCWSTR name, BOOL fPrependCOMPLUS);
1194public:
1195
1196 static BOOL UseRegistry();
1197
1198private:
1199//*****************************************************************************
1200// Get either a DWORD or ULONGLONG. Always puts the result in a ULONGLONG that
1201// you can safely cast to a DWORD if fGetDWORD is TRUE.
1202//*****************************************************************************
1203 static HRESULT GetConfigInteger(
1204 LPCWSTR name,
1205 ULONGLONG defValue,
1206 __out ULONGLONG * result,
1207 BOOL fGetDWORD = TRUE,
1208 CORConfigLevel level = COR_CONFIG_ALL,
1209 BOOL fPrependCOMPLUS = TRUE);
1210public:
1211
1212
1213//*****************************************************************************
1214// (Optional) Initialize the config registry cache
1215// (see ConfigCacheValueNameSeenPerhaps, below.)
1216//*****************************************************************************
1217 static void InitOptionalConfigCache();
1218
1219private:
1220
1221
1222//*****************************************************************************
1223// Return TRUE if the registry value name might have been seen in the registry
1224// at startup;
1225// return FALSE if the value was definitely not seen at startup.
1226//
1227// Perf Optimization for VSWhidbey:113373.
1228//*****************************************************************************
1229 static BOOL RegCacheValueNameSeenPerhaps(
1230 LPCWSTR name);
1231//*****************************************************************************
1232// Return TRUE if the environment variable name might have been seen at startup;
1233// return FALSE if the value was definitely not seen at startup.
1234//*****************************************************************************
1235 static BOOL EnvCacheValueNameSeenPerhaps(
1236 LPCWSTR name);
1237
1238 static BOOL s_fUseRegCache; // Enable registry cache; if FALSE, CCVNSP
1239 // always returns TRUE.
1240 static BOOL s_fUseEnvCache; // Enable env cache.
1241
1242 static BOOL s_fUseRegistry; // Allow lookups in the registry
1243
1244 // Open the .NetFramework keys once and cache the handles
1245 static HKEY s_hMachineFrameworkKey;
1246 static HKEY s_hUserFrameworkKey;
1247};
1248
1249// need this here because CLRConfig depends on REGUTIL, and ConfigStringHolder depends on CLRConfig
1250#include "clrconfig.h"
1251
1252//-----------------------------------------------------------------------------
1253// Wrapper for configuration strings.
1254// This serves as a holder to call FreeConfigString.
1255class ConfigStringHolder
1256{
1257public:
1258 ConfigStringHolder() { m_wszString = NULL; }
1259 ~ConfigStringHolder()
1260 {
1261 Clear();
1262 }
1263
1264 //
1265 // NOTE: The following function is deprecated; use the CLRConfig class instead.
1266 // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
1267 //
1268 void Init_DontUse_(LPCWSTR wszName)
1269 {
1270 Clear();
1271 m_wszString = REGUTIL::GetConfigString_DontUse_(wszName);
1272 }
1273
1274 // Free resources.
1275 void Clear()
1276 {
1277 if (m_wszString != NULL)
1278 {
1279 REGUTIL::FreeConfigString(m_wszString);
1280 m_wszString = NULL;
1281 }
1282 }
1283
1284 // Get the string value. NULL if not set.
1285 LPCWSTR Value()
1286 {
1287 return m_wszString;
1288 }
1289
1290private:
1291 LPWSTR m_wszString;
1292};
1293
1294#endif // defined(NO_CLRCONFIG)
1295
1296#include "ostype.h"
1297
1298#define CLRGetTickCount64() GetTickCount64()
1299
1300//
1301// Use this function to initialize the s_CodeAllocHint
1302// during startup. base is runtime .dll base address,
1303// size is runtime .dll virtual size.
1304//
1305void InitCodeAllocHint(SIZE_T base, SIZE_T size, int randomPageOffset);
1306
1307
1308//
1309// Use this function to reset the s_CodeAllocHint
1310// after unloading an AppDomain
1311//
1312void ResetCodeAllocHint();
1313
1314//
1315// Returns TRUE if p is located in near clr.dll that allows us
1316// to use rel32 IP-relative addressing modes.
1317//
1318BOOL IsPreferredExecutableRange(void * p);
1319
1320//
1321// Allocate free memory that will be used for executable code
1322// Handles the special requirements that we have on 64-bit platforms
1323// where we want the executable memory to be located near mscorwks
1324//
1325BYTE * ClrVirtualAllocExecutable(SIZE_T dwSize,
1326 DWORD flAllocationType,
1327 DWORD flProtect);
1328
1329//
1330// Allocate free memory within the range [pMinAddr..pMaxAddr] using
1331// ClrVirtualQuery to find free memory and ClrVirtualAlloc to allocate it.
1332//
1333BYTE * ClrVirtualAllocWithinRange(const BYTE *pMinAddr,
1334 const BYTE *pMaxAddr,
1335 SIZE_T dwSize,
1336 DWORD flAllocationType,
1337 DWORD flProtect);
1338
1339//
1340// Allocate free memory with specific alignment
1341//
1342LPVOID ClrVirtualAllocAligned(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect, SIZE_T alignment);
1343
1344//******************************************************************************
1345// Returns the number of processors that a process has been configured to run on
1346//******************************************************************************
1347class NumaNodeInfo
1348{
1349private:
1350 static BOOL m_enableGCNumaAware;
1351 static BOOL InitNumaNodeInfoAPI();
1352
1353public:
1354 static BOOL CanEnableGCNumaAware();
1355 static void InitNumaNodeInfo();
1356
1357#if !defined(FEATURE_REDHAWK)
1358private: // apis types
1359
1360 //GetNumaHighestNodeNumber()
1361 typedef BOOL
1362 (WINAPI *PGNHNN)(PULONG);
1363 //VirtualAllocExNuma()
1364 typedef LPVOID
1365 (WINAPI *PVAExN)(HANDLE,LPVOID,SIZE_T,DWORD,DWORD,DWORD);
1366
1367 // api pfns and members
1368 static PGNHNN m_pGetNumaHighestNodeNumber;
1369 static PVAExN m_pVirtualAllocExNuma;
1370
1371public: // functions
1372
1373 static LPVOID VirtualAllocExNuma(HANDLE hProc, LPVOID lpAddr, SIZE_T size,
1374 DWORD allocType, DWORD prot, DWORD node);
1375
1376private:
1377 //GetNumaProcessorNodeEx()
1378 typedef BOOL
1379 (WINAPI *PGNPNEx)(PPROCESSOR_NUMBER, PUSHORT);
1380 static PGNPNEx m_pGetNumaProcessorNodeEx;
1381
1382public:
1383 static BOOL GetNumaProcessorNodeEx(PPROCESSOR_NUMBER proc_no, PUSHORT node_no);
1384#endif
1385};
1386
1387struct CPU_Group_Info
1388{
1389 WORD nr_active; // at most 64
1390 WORD reserved[1];
1391 WORD begin;
1392 WORD end;
1393 DWORD_PTR active_mask;
1394 DWORD groupWeight;
1395 DWORD activeThreadWeight;
1396};
1397
1398class CPUGroupInfo
1399{
1400private:
1401 static LONG m_initialization;
1402 static WORD m_nGroups;
1403 static WORD m_nProcessors;
1404 static BOOL m_enableGCCPUGroups;
1405 static BOOL m_threadUseAllCpuGroups;
1406 static WORD m_initialGroup;
1407 static CPU_Group_Info *m_CPUGroupInfoArray;
1408 static bool s_hadSingleProcessorAtStartup;
1409
1410 static BOOL InitCPUGroupInfoAPI();
1411 static BOOL InitCPUGroupInfoArray();
1412 static BOOL InitCPUGroupInfoRange();
1413 static void InitCPUGroupInfo();
1414 static BOOL IsInitialized();
1415
1416public:
1417 static void EnsureInitialized();
1418 static BOOL CanEnableGCCPUGroups();
1419 static BOOL CanEnableThreadUseAllCpuGroups();
1420 static WORD GetNumActiveProcessors();
1421 static void GetGroupForProcessor(WORD processor_number,
1422 WORD *group_number, WORD *group_processor_number);
1423 static DWORD CalculateCurrentProcessorNumber();
1424 //static void PopulateCPUUsageArray(void * infoBuffer, ULONG infoSize);
1425
1426#if !defined(FEATURE_REDHAWK)
1427private:
1428 //GetLogicalProcessorInforomationEx()
1429 typedef BOOL
1430 (WINAPI *PGLPIEx)(DWORD, SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *, PDWORD);
1431 //SetThreadGroupAffinity()
1432 typedef BOOL
1433 (WINAPI *PSTGA)(HANDLE, GROUP_AFFINITY *, GROUP_AFFINITY *);
1434 //GetThreadGroupAffinity()
1435 typedef BOOL
1436 (WINAPI *PGTGA)(HANDLE, GROUP_AFFINITY *);
1437 //GetCurrentProcessorNumberEx()
1438 typedef void
1439 (WINAPI *PGCPNEx)(PROCESSOR_NUMBER *);
1440 //GetSystemTimes()
1441 typedef BOOL
1442 (WINAPI *PGST)(FILETIME *, FILETIME *, FILETIME *);
1443 //NtQuerySystemInformationEx()
1444 //typedef int
1445 //(WINAPI *PNTQSIEx)(SYSTEM_INFORMATION_CLASS, PULONG, ULONG, PVOID, ULONG, PULONG);
1446 static PGLPIEx m_pGetLogicalProcessorInformationEx;
1447 static PSTGA m_pSetThreadGroupAffinity;
1448 static PGTGA m_pGetThreadGroupAffinity;
1449 static PGCPNEx m_pGetCurrentProcessorNumberEx;
1450 static PGST m_pGetSystemTimes;
1451 //static PNTQSIEx m_pNtQuerySystemInformationEx;
1452
1453public:
1454 static BOOL GetLogicalProcessorInformationEx(DWORD relationship,
1455 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *slpiex, PDWORD count);
1456 static BOOL SetThreadGroupAffinity(HANDLE h,
1457 GROUP_AFFINITY *groupAffinity, GROUP_AFFINITY *previousGroupAffinity);
1458 static BOOL GetThreadGroupAffinity(HANDLE h, GROUP_AFFINITY *groupAffinity);
1459 static BOOL GetSystemTimes(FILETIME *idleTime, FILETIME *kernelTime, FILETIME *userTime);
1460 static void ChooseCPUGroupAffinity(GROUP_AFFINITY *gf);
1461 static void ClearCPUGroupAffinity(GROUP_AFFINITY *gf);
1462#endif
1463
1464public:
1465 static bool HadSingleProcessorAtStartup()
1466 {
1467 LIMITED_METHOD_CONTRACT;
1468 return s_hadSingleProcessorAtStartup;
1469 }
1470};
1471
1472int GetCurrentProcessCpuCount();
1473DWORD_PTR GetCurrentProcessCpuMask();
1474
1475uint32_t GetOsPageSize();
1476
1477
1478//*****************************************************************************
1479// Return != 0 if the bit at the specified index in the array is on and 0 if
1480// it is off.
1481//*****************************************************************************
1482inline int GetBit(PTR_BYTE pcBits,int iBit)
1483{
1484 LIMITED_METHOD_CONTRACT;
1485 return (pcBits[iBit>>3] & (1 << (iBit & 0x7)));
1486}
1487
1488#ifdef DACCESS_COMPILE
1489inline int GetBit(BYTE const * pcBits,int iBit)
1490{
1491 WRAPPER_NO_CONTRACT;
1492 return GetBit(dac_cast<PTR_BYTE>(pcBits), iBit);
1493}
1494#endif
1495
1496//*****************************************************************************
1497// Set the state of the bit at the specified index based on the value of bOn.
1498//*****************************************************************************
1499inline void SetBit(PTR_BYTE pcBits,int iBit,int bOn)
1500{
1501 LIMITED_METHOD_CONTRACT;
1502 if (bOn)
1503 pcBits[iBit>>3] |= (1 << (iBit & 0x7));
1504 else
1505 pcBits[iBit>>3] &= ~(1 << (iBit & 0x7));
1506}
1507
1508#ifdef DACCESS_COMPILE
1509inline void SetBit(BYTE * pcBits,int iBit,int bOn)
1510{
1511 WRAPPER_NO_CONTRACT;
1512 SetBit(dac_cast<PTR_BYTE>(pcBits), iBit, bOn);
1513}
1514#endif
1515
1516template<typename T>
1517class SimpleListNode
1518{
1519public:
1520 SimpleListNode<T>(const T& _t)
1521 {
1522 data = _t;
1523 next = 0;
1524 }
1525
1526 T data;
1527 SimpleListNode<T>* next;
1528};
1529
1530template<typename T>
1531class SimpleList
1532{
1533public:
1534 typedef SimpleListNode<T> NodeType;
1535
1536 SimpleList<T>()
1537 {
1538 head = NULL;
1539 }
1540
1541 void LinkHead(NodeType* pNode)
1542 {
1543 pNode->next = head;
1544 head = pNode;
1545 }
1546
1547 NodeType* UnlinkHead()
1548 {
1549 NodeType* ret = head;
1550
1551 if (head)
1552 {
1553 head = head->next;
1554 }
1555 return ret;
1556 }
1557
1558 NodeType* Head()
1559 {
1560 return head;
1561 }
1562
1563protected:
1564
1565 NodeType* head;
1566};
1567
1568
1569template < typename T, typename U >
1570struct Pair
1571{
1572public:
1573 typedef Pair< T, U > this_type;
1574 typedef T first_type;
1575 typedef U second_type;
1576
1577 Pair()
1578 {}
1579
1580 Pair( T const & t, U const & u )
1581 : m_first( t )
1582 , m_second( u )
1583 { SUPPORTS_DAC; }
1584
1585 Pair( this_type const & obj )
1586 : m_first( obj.m_first )
1587 , m_second( obj.m_second )
1588 {}
1589
1590 this_type & operator=( this_type const & obj )
1591 {
1592 m_first = obj.m_first;
1593 m_second = obj.m_second;
1594 return *this;
1595 }
1596
1597 T & First()
1598 {
1599 return m_first;
1600 }
1601
1602 T const & First() const
1603 {
1604 return m_first;
1605 }
1606
1607 U & Second()
1608 {
1609 return m_second;
1610 }
1611
1612 U const & Second() const
1613 {
1614 return m_second;
1615 }
1616
1617 bool operator==(const Pair& rhs) const
1618 {
1619 return ((this->First() == rhs.First()) &&
1620 (this->Second() == rhs.Second()));
1621 }
1622
1623 bool operator!=(const Pair& rhs) const
1624 {
1625 return !(*this == rhs);
1626 }
1627
1628private:
1629 first_type m_first;
1630 second_type m_second;
1631};
1632
1633
1634template < typename T, typename U >
1635Pair< T, U > MakePair( T const & t, U const & u )
1636{
1637 SUPPORTS_DAC;
1638 return Pair< T, U >( t, u );
1639}
1640
1641
1642//*****************************************************************************
1643// This class implements a dynamic array of structures for which the order of
1644// the elements is unimportant. This means that any item placed in the list
1645// may be swapped to any other location in the list at any time. If the order
1646// of the items you place in the array is important, then use the CStructArray
1647// class.
1648//*****************************************************************************
1649
1650template <class T,
1651 int iGrowInc,
1652 class ALLOCATOR>
1653class CUnorderedArrayWithAllocator
1654{
1655 int m_iCount; // # of elements used in the list.
1656 int m_iSize; // # of elements allocated in the list.
1657public:
1658#ifndef DACCESS_COMPILE
1659 T *m_pTable; // Pointer to the list of elements.
1660#else
1661 TADDR m_pTable; // Pointer to the list of elements.
1662#endif
1663
1664public:
1665
1666#ifndef DACCESS_COMPILE
1667
1668 CUnorderedArrayWithAllocator() :
1669 m_iCount(0),
1670 m_iSize(0),
1671 m_pTable(NULL)
1672 {
1673 LIMITED_METHOD_CONTRACT;
1674 }
1675 ~CUnorderedArrayWithAllocator()
1676 {
1677 LIMITED_METHOD_CONTRACT;
1678 // Free the chunk of memory.
1679 if (m_pTable != NULL)
1680 ALLOCATOR::Free(this, m_pTable);
1681 }
1682
1683 void Clear()
1684 {
1685 WRAPPER_NO_CONTRACT;
1686 m_iCount = 0;
1687 if (m_iSize > iGrowInc)
1688 {
1689 T* tmp = ALLOCATOR::AllocNoThrow(this, iGrowInc);
1690 if (tmp) {
1691 ALLOCATOR::Free(this, m_pTable);
1692 m_pTable = tmp;
1693 m_iSize = iGrowInc;
1694 }
1695 }
1696 }
1697
1698 void Clear(int iFirst, int iCount)
1699 {
1700 WRAPPER_NO_CONTRACT;
1701 int iSize;
1702
1703 if (iFirst + iCount < m_iCount)
1704 memmove(&m_pTable[iFirst], &m_pTable[iFirst + iCount], sizeof(T) * (m_iCount - (iFirst + iCount)));
1705
1706 m_iCount -= iCount;
1707
1708 iSize = ((m_iCount / iGrowInc) * iGrowInc) + ((m_iCount % iGrowInc != 0) ? iGrowInc : 0);
1709 if (m_iSize > iGrowInc && iSize < m_iSize)
1710 {
1711 T *tmp = ALLOCATOR::AllocNoThrow(this, iSize);
1712 if (tmp) {
1713 memcpy (tmp, m_pTable, iSize * sizeof(T));
1714 delete [] m_pTable;
1715 m_pTable = tmp;
1716 m_iSize = iSize;
1717 }
1718 }
1719 _ASSERTE(m_iCount <= m_iSize);
1720 }
1721
1722 T *Table()
1723 {
1724 LIMITED_METHOD_CONTRACT;
1725 return (m_pTable);
1726 }
1727
1728 T *Append()
1729 {
1730 CONTRACTL {
1731 NOTHROW;
1732 } CONTRACTL_END;
1733
1734 // The array should grow, if we can't fit one more element into the array.
1735 if (m_iSize <= m_iCount && GrowNoThrow() == NULL)
1736 return (NULL);
1737 return (&m_pTable[m_iCount++]);
1738 }
1739
1740 T *AppendThrowing()
1741 {
1742 CONTRACTL {
1743 THROWS;
1744 } CONTRACTL_END;
1745
1746 // The array should grow, if we can't fit one more element into the array.
1747 if (m_iSize <= m_iCount)
1748 Grow();
1749 return (&m_pTable[m_iCount++]);
1750 }
1751
1752 void Delete(const T &Entry)
1753 {
1754 LIMITED_METHOD_CONTRACT;
1755 --m_iCount;
1756 for (int i=0; i <= m_iCount; ++i)
1757 if (m_pTable[i] == Entry)
1758 {
1759 m_pTable[i] = m_pTable[m_iCount];
1760 return;
1761 }
1762
1763 // Just in case we didn't find it.
1764 ++m_iCount;
1765 }
1766
1767 void DeleteByIndex(int i)
1768 {
1769 LIMITED_METHOD_CONTRACT;
1770 --m_iCount;
1771 m_pTable[i] = m_pTable[m_iCount];
1772 }
1773
1774 void Swap(int i,int j)
1775 {
1776 LIMITED_METHOD_CONTRACT;
1777 T tmp;
1778
1779 if (i == j)
1780 return;
1781 tmp = m_pTable[i];
1782 m_pTable[i] = m_pTable[j];
1783 m_pTable[j] = tmp;
1784 }
1785
1786#else
1787
1788 TADDR Table()
1789 {
1790 LIMITED_METHOD_CONTRACT;
1791 SUPPORTS_DAC;
1792 return (m_pTable);
1793 }
1794
1795 void EnumMemoryRegions(void)
1796 {
1797 SUPPORTS_DAC;
1798 DacEnumMemoryRegion(m_pTable, m_iCount * sizeof(T));
1799 }
1800
1801#endif // #ifndef DACCESS_COMPILE
1802
1803 USHORT Count()
1804 {
1805 LIMITED_METHOD_CONTRACT;
1806 SUPPORTS_DAC;
1807 _ASSERTE(FitsIn<USHORT>(m_iCount));
1808 return static_cast<USHORT>(m_iCount);
1809 }
1810
1811private:
1812 T *Grow();
1813 T *GrowNoThrow();
1814};
1815
1816
1817#ifndef DACCESS_COMPILE
1818
1819//*****************************************************************************
1820// Increase the size of the array.
1821//*****************************************************************************
1822template <class T,
1823 int iGrowInc,
1824 class ALLOCATOR>
1825T *CUnorderedArrayWithAllocator<T,iGrowInc,ALLOCATOR>::GrowNoThrow() // NULL if can't grow.
1826{
1827 WRAPPER_NO_CONTRACT;
1828 T *pTemp;
1829
1830 // try to allocate memory for reallocation.
1831 if ((pTemp = ALLOCATOR::AllocNoThrow(this, m_iSize+iGrowInc)) == NULL)
1832 return (NULL);
1833 memcpy (pTemp, m_pTable, m_iSize*sizeof(T));
1834 ALLOCATOR::Free(this, m_pTable);
1835 m_pTable = pTemp;
1836 m_iSize += iGrowInc;
1837 _ASSERTE(m_iSize > 0);
1838 return (pTemp);
1839}
1840
1841template <class T,
1842 int iGrowInc,
1843 class ALLOCATOR>
1844T *CUnorderedArrayWithAllocator<T,iGrowInc,ALLOCATOR>::Grow() // exception if can't grow.
1845{
1846 WRAPPER_NO_CONTRACT;
1847 T *pTemp;
1848
1849 // try to allocate memory for reallocation.
1850 pTemp = ALLOCATOR::AllocThrowing(this, m_iSize+iGrowInc);
1851 memcpy (pTemp, m_pTable, m_iSize*sizeof(T));
1852 ALLOCATOR::Free(this, m_pTable);
1853 m_pTable = pTemp;
1854 m_iSize += iGrowInc;
1855 _ASSERTE(m_iSize > 0);
1856 return (pTemp);
1857}
1858
1859#endif // #ifndef DACCESS_COMPILE
1860
1861
1862template <class T>
1863class CUnorderedArray__Allocator
1864{
1865public:
1866
1867 static T *AllocThrowing (void*, int nElements)
1868 {
1869 return new T[nElements];
1870 }
1871
1872 static T *AllocNoThrow (void*, int nElements)
1873 {
1874 return new (nothrow) T[nElements];
1875 }
1876
1877 static void Free (void*, T *pTable)
1878 {
1879 delete [] pTable;
1880 }
1881};
1882
1883
1884template <class T,int iGrowInc>
1885class CUnorderedArray : public CUnorderedArrayWithAllocator<T, iGrowInc, CUnorderedArray__Allocator<T> >
1886{
1887public:
1888
1889 CUnorderedArray ()
1890 {
1891 LIMITED_METHOD_CONTRACT;
1892 }
1893};
1894
1895
1896//Used by the debugger. Included here in hopes somebody else might, too
1897typedef CUnorderedArray<SIZE_T, 17> SIZE_T_UNORDERED_ARRAY;
1898
1899
1900//*****************************************************************************
1901// This class implements a dynamic array of structures for which the insert
1902// order is important. Inserts will slide all elements after the location
1903// down, deletes slide all values over the deleted item. If the order of the
1904// items in the array is unimportant to you, then CUnorderedArray may provide
1905// the same feature set at lower cost.
1906//*****************************************************************************
1907class CStructArray
1908{
1909 BYTE *m_pList; // Pointer to the list of elements.
1910 int m_iCount; // # of elements used in the list.
1911 int m_iSize; // # of elements allocated in the list.
1912 int m_iGrowInc; // Growth increment.
1913 short m_iElemSize; // Size of an array element.
1914 bool m_bFree; // true if data is automatically maintained.
1915
1916public:
1917 CStructArray(short iElemSize, short iGrowInc = 1) :
1918 m_pList(NULL),
1919 m_iCount(0),
1920 m_iSize(0),
1921 m_iGrowInc(iGrowInc),
1922 m_iElemSize(iElemSize),
1923 m_bFree(true)
1924 {
1925 LIMITED_METHOD_CONTRACT;
1926 }
1927 ~CStructArray()
1928 {
1929 WRAPPER_NO_CONTRACT;
1930 Clear();
1931 }
1932
1933 void *Insert(int iIndex);
1934 void *InsertThrowing(int iIndex);
1935 void *Append();
1936 void *AppendThrowing();
1937 int AllocateBlock(int iCount);
1938 void AllocateBlockThrowing(int iCount);
1939 void Delete(int iIndex);
1940 void *Ptr()
1941 {
1942 LIMITED_METHOD_CONTRACT;
1943 return (m_pList);
1944 }
1945 void *Get(int iIndex)
1946 {
1947 WRAPPER_NO_CONTRACT;
1948 _ASSERTE(iIndex < m_iCount);
1949 return ((void *) ((size_t) Ptr() + (iIndex * m_iElemSize)));
1950 }
1951 int Size()
1952 {
1953 LIMITED_METHOD_CONTRACT;
1954 return (m_iCount * m_iElemSize);
1955 }
1956 int Count()
1957 {
1958 LIMITED_METHOD_CONTRACT;
1959 return (m_iCount);
1960 }
1961 void Clear();
1962 void ClearCount()
1963 {
1964 LIMITED_METHOD_CONTRACT;
1965 m_iCount = 0;
1966 }
1967
1968 void InitOnMem(short iElemSize, void *pList, int iCount, int iSize, int iGrowInc=1)
1969 {
1970 LIMITED_METHOD_CONTRACT;
1971 m_iElemSize = iElemSize;
1972 m_iGrowInc = (short) iGrowInc;
1973 m_pList = (BYTE*)pList;
1974 m_iCount = iCount;
1975 m_iSize = iSize;
1976 m_bFree = false;
1977 }
1978
1979private:
1980 void Grow(int iCount);
1981};
1982
1983
1984//*****************************************************************************
1985// This template simplifies access to a CStructArray by removing void * and
1986// adding some operator overloads.
1987//*****************************************************************************
1988template <class T>
1989class CDynArray : public CStructArray
1990{
1991public:
1992 CDynArray(short iGrowInc=16) :
1993 CStructArray(sizeof(T), iGrowInc)
1994 {
1995 LIMITED_METHOD_CONTRACT;
1996 }
1997
1998 T *Insert(int iIndex)
1999 {
2000 WRAPPER_NO_CONTRACT;
2001 return ((T *)CStructArray::Insert((int)iIndex));
2002 }
2003
2004 T *InsertThrowing(int iIndex)
2005 {
2006 WRAPPER_NO_CONTRACT;
2007 return ((T *)CStructArray::InsertThrowing((int)iIndex));
2008 }
2009
2010 T *Append()
2011 {
2012 WRAPPER_NO_CONTRACT;
2013 return ((T *)CStructArray::Append());
2014 }
2015
2016 T *AppendThrowing()
2017 {
2018 WRAPPER_NO_CONTRACT;
2019 return ((T *)CStructArray::AppendThrowing());
2020 }
2021
2022 T *Ptr()
2023 {
2024 WRAPPER_NO_CONTRACT;
2025 return ((T *)CStructArray::Ptr());
2026 }
2027
2028 T *Get(int iIndex)
2029 {
2030 WRAPPER_NO_CONTRACT;
2031 return (Ptr() + iIndex);
2032 }
2033 T &operator[](int iIndex)
2034 {
2035 WRAPPER_NO_CONTRACT;
2036 return (*(Ptr() + iIndex));
2037 }
2038 int ItemIndex(T *p)
2039 {
2040 WRAPPER_NO_CONTRACT;
2041 return (((int)(LONG_PTR)p - (int)(LONG_PTR)Ptr()) / sizeof(T));
2042 }
2043 void Move(int iFrom, int iTo)
2044 {
2045 WRAPPER_NO_CONTRACT;
2046 T tmp;
2047
2048 _ASSERTE(iFrom >= 0 && iFrom < Count() &&
2049 iTo >= 0 && iTo < Count());
2050
2051 tmp = *(Ptr() + iFrom);
2052 if (iTo > iFrom)
2053 memmove(Ptr() + iFrom, Ptr() + iFrom + 1, (iTo - iFrom) * sizeof(T));
2054 else
2055 memmove(Ptr() + iTo + 1, Ptr() + iTo, (iFrom - iTo) * sizeof(T));
2056 *(Ptr() + iTo) = tmp;
2057 }
2058};
2059
2060// Some common arrays.
2061typedef CDynArray<int> INTARRAY;
2062typedef CDynArray<short> SHORTARRAY;
2063typedef CDynArray<int> LONGARRAY;
2064typedef CDynArray<USHORT> USHORTARRAY;
2065typedef CDynArray<ULONG> ULONGARRAY;
2066typedef CDynArray<BYTE> BYTEARRAY;
2067typedef CDynArray<mdToken> TOKENARRAY;
2068
2069template <class T> class CStackArray : public CStructArray
2070{
2071public:
2072 CStackArray(short iGrowInc=4) :
2073 CStructArray(sizeof(T), iGrowInc),
2074 m_curPos(0)
2075 {
2076 LIMITED_METHOD_CONTRACT;
2077 }
2078
2079 void Push(T p)
2080 {
2081 WRAPPER_NO_CONTRACT;
2082 // We should only inc m_curPos after we grow the array.
2083 T *pT = (T *)CStructArray::InsertThrowing(m_curPos);
2084 m_curPos ++;
2085 *pT = p;
2086 }
2087
2088 T * Pop()
2089 {
2090 WRAPPER_NO_CONTRACT;
2091 T * retPtr;
2092
2093 _ASSERTE(m_curPos > 0);
2094
2095 retPtr = (T *)CStructArray::Get(m_curPos-1);
2096 CStructArray::Delete(m_curPos--);
2097
2098 return (retPtr);
2099 }
2100
2101 int Count()
2102 {
2103 LIMITED_METHOD_CONTRACT;
2104 return(m_curPos);
2105 }
2106
2107private:
2108 int m_curPos;
2109};
2110
2111
2112//*****************************************************************************
2113// This template manages a list of free entries by their 0 based offset. By
2114// making it a template, you can use whatever size free chain will match your
2115// maximum count of items. -1 is reserved.
2116//*****************************************************************************
2117template <class T> class TFreeList
2118{
2119public:
2120 void Init(
2121 T *rgList,
2122 int iCount)
2123 {
2124 LIMITED_METHOD_CONTRACT;
2125 // Save off values.
2126 m_rgList = rgList;
2127 m_iCount = iCount;
2128 m_iNext = 0;
2129
2130 // Init free list.
2131 int i;
2132 for (i=0; i<iCount - 1; i++)
2133 m_rgList[i] = i + 1;
2134 m_rgList[i] = (T) -1;
2135 }
2136
2137 T GetFreeEntry() // Index of free item, or -1.
2138 {
2139 LIMITED_METHOD_CONTRACT;
2140 T iNext;
2141
2142 if (m_iNext == (T) -1)
2143 return (-1);
2144
2145 iNext = m_iNext;
2146 m_iNext = m_rgList[m_iNext];
2147 return (iNext);
2148 }
2149
2150 void DelFreeEntry(T iEntry)
2151 {
2152 LIMITED_METHOD_CONTRACT;
2153 _ASSERTE(iEntry < m_iCount);
2154 m_rgList[iEntry] = m_iNext;
2155 m_iNext = iEntry;
2156 }
2157
2158 // This function can only be used when it is guaranteed that the free
2159 // array is contigous, for example, right after creation to quickly
2160 // get a range of items from the heap.
2161 void ReserveRange(int iCount)
2162 {
2163 LIMITED_METHOD_CONTRACT;
2164 _ASSERTE(iCount < m_iCount);
2165 _ASSERTE(m_iNext == 0);
2166 m_iNext = iCount;
2167 }
2168
2169private:
2170 T *m_rgList; // List of free info.
2171 int m_iCount; // How many entries to manage.
2172 T m_iNext; // Next item to get.
2173};
2174
2175
2176//*****************************************************************************
2177//*****************************************************************************
2178template <class T> class CQuickSort
2179{
2180protected:
2181 T *m_pBase; // Base of array to sort.
2182private:
2183 SSIZE_T m_iCount; // How many items in array.
2184 SSIZE_T m_iElemSize; // Size of one element.
2185public:
2186 CQuickSort(
2187 T *pBase, // Address of first element.
2188 SSIZE_T iCount) : // How many there are.
2189 m_pBase(pBase),
2190 m_iCount(iCount),
2191 m_iElemSize(sizeof(T))
2192 {
2193 LIMITED_METHOD_DAC_CONTRACT;
2194 }
2195
2196//*****************************************************************************
2197// Call to sort the array.
2198//*****************************************************************************
2199 inline void Sort()
2200 {
2201 WRAPPER_NO_CONTRACT;
2202 SortRange(0, m_iCount - 1);
2203 }
2204
2205protected:
2206//*****************************************************************************
2207// Override this function to do the comparison.
2208//*****************************************************************************
2209 virtual FORCEINLINE int Compare( // -1, 0, or 1
2210 T *psFirst, // First item to compare.
2211 T *psSecond) // Second item to compare.
2212 {
2213 LIMITED_METHOD_DAC_CONTRACT;
2214 return (memcmp(psFirst, psSecond, sizeof(T)));
2215// return (::Compare(*psFirst, *psSecond));
2216 }
2217
2218 virtual FORCEINLINE void Swap(
2219 SSIZE_T iFirst,
2220 SSIZE_T iSecond)
2221 {
2222 LIMITED_METHOD_DAC_CONTRACT;
2223 if (iFirst == iSecond) return;
2224 T sTemp( m_pBase[iFirst] );
2225 m_pBase[iFirst] = m_pBase[iSecond];
2226 m_pBase[iSecond] = sTemp;
2227 }
2228
2229private:
2230 inline void SortRange(
2231 SSIZE_T iLeft,
2232 SSIZE_T iRight)
2233 {
2234 WRAPPER_NO_CONTRACT;
2235 SSIZE_T iLast;
2236 SSIZE_T i; // loop variable.
2237
2238 for (;;)
2239 {
2240 // if less than two elements you're done.
2241 if (iLeft >= iRight)
2242 return;
2243
2244 // ASSERT that we now have valid indicies. This is statically provable
2245 // since this private function is only called with valid indicies,
2246 // and iLeft and iRight only converge towards eachother. However,
2247 // PreFast can't detect this because it doesn't know about our callers.
2248 COMPILER_ASSUME(iLeft >= 0 && iLeft < m_iCount);
2249 COMPILER_ASSUME(iRight >= 0 && iRight < m_iCount);
2250
2251 // The mid-element is the pivot, move it to the left.
2252 Swap(iLeft, (iLeft + iRight) / 2);
2253 iLast = iLeft;
2254
2255 // move everything that is smaller than the pivot to the left.
2256 for (i = iLeft + 1; i <= iRight; i++)
2257 {
2258 if (Compare(&m_pBase[i], &m_pBase[iLeft]) < 0)
2259 {
2260 Swap(i, ++iLast);
2261 }
2262 }
2263
2264 // Put the pivot to the point where it is in between smaller and larger elements.
2265 Swap(iLeft, iLast);
2266
2267 // Sort each partition.
2268 SSIZE_T iLeftLast = iLast - 1;
2269 SSIZE_T iRightFirst = iLast + 1;
2270 if (iLeftLast - iLeft < iRight - iRightFirst)
2271 { // Left partition is smaller, sort it recursively
2272 SortRange(iLeft, iLeftLast);
2273 // Tail call to sort the right (bigger) partition
2274 iLeft = iRightFirst;
2275 //iRight = iRight;
2276 continue;
2277 }
2278 else
2279 { // Right partition is smaller, sort it recursively
2280 SortRange(iRightFirst, iRight);
2281 // Tail call to sort the left (bigger) partition
2282 //iLeft = iLeft;
2283 iRight = iLeftLast;
2284 continue;
2285 }
2286 }
2287 }
2288};
2289
2290//*****************************************************************************
2291// Faster and simpler version of the binary search below.
2292//*****************************************************************************
2293template <class T>
2294const T * BinarySearch(const T * pBase, int iCount, const T & find)
2295{
2296 WRAPPER_NO_CONTRACT;
2297
2298 int iFirst = 0;
2299 int iLast = iCount - 1;
2300
2301 // It is faster to use linear search once we get down to a small number of elements.
2302 while (iLast - iFirst > 10)
2303 {
2304 int iMid = (iLast + iFirst) / 2;
2305
2306 if (find < pBase[iMid])
2307 iLast = iMid - 1;
2308 else
2309 iFirst = iMid;
2310 }
2311
2312 for (int i = iFirst; i <= iLast; i++)
2313 {
2314 if (find == pBase[i])
2315 return &pBase[i];
2316
2317 if (find < pBase[i])
2318 break;
2319 }
2320
2321 return NULL;
2322}
2323
2324//*****************************************************************************
2325// This template encapsulates a binary search algorithm on the given type
2326// of data.
2327//*****************************************************************************
2328template <class T> class CBinarySearch
2329{
2330private:
2331 const T *m_pBase; // Base of array to sort.
2332 int m_iCount; // How many items in array.
2333
2334public:
2335 CBinarySearch(
2336 const T *pBase, // Address of first element.
2337 int iCount) : // Value to find.
2338 m_pBase(pBase),
2339 m_iCount(iCount)
2340 {
2341 LIMITED_METHOD_CONTRACT;
2342 }
2343
2344//*****************************************************************************
2345// Searches for the item passed to ctor.
2346//*****************************************************************************
2347 const T *Find( // Pointer to found item in array.
2348 const T *psFind, // The key to find.
2349 int *piInsert = NULL) // Index to insert at.
2350 {
2351 WRAPPER_NO_CONTRACT;
2352 int iMid, iFirst, iLast; // Loop control.
2353 int iCmp; // Comparison.
2354
2355 iFirst = 0;
2356 iLast = m_iCount - 1;
2357 while (iFirst <= iLast)
2358 {
2359 iMid = (iLast + iFirst) / 2;
2360 iCmp = Compare(psFind, &m_pBase[iMid]);
2361 if (iCmp == 0)
2362 {
2363 if (piInsert != NULL)
2364 *piInsert = iMid;
2365 return (&m_pBase[iMid]);
2366 }
2367 else if (iCmp < 0)
2368 iLast = iMid - 1;
2369 else
2370 iFirst = iMid + 1;
2371 }
2372 if (piInsert != NULL)
2373 *piInsert = iFirst;
2374 return (NULL);
2375 }
2376
2377//*****************************************************************************
2378// Override this function to do the comparison if a comparison operator is
2379// not valid for your data type (such as a struct).
2380//*****************************************************************************
2381 virtual int Compare( // -1, 0, or 1
2382 const T *psFirst, // Key you are looking for.
2383 const T *psSecond) // Item to compare to.
2384 {
2385 LIMITED_METHOD_CONTRACT;
2386 return (memcmp(psFirst, psSecond, sizeof(T)));
2387// return (::Compare(*psFirst, *psSecond));
2388 }
2389};
2390
2391//*****************************************************************************
2392// The information that the hash table implementation stores at the beginning
2393// of every record that can be but in the hash table.
2394//*****************************************************************************
2395typedef DPTR(struct HASHENTRY) PTR_HASHENTRY;
2396struct HASHENTRY
2397{
2398 ULONG iPrev; // Previous bucket in the chain.
2399 ULONG iNext; // Next bucket in the chain.
2400};
2401
2402typedef DPTR(struct FREEHASHENTRY) PTR_FREEHASHENTRY;
2403struct FREEHASHENTRY : HASHENTRY
2404{
2405 ULONG iFree;
2406};
2407
2408//*****************************************************************************
2409// Used by the FindFirst/FindNextEntry functions. These api's allow you to
2410// do a sequential scan of all entries.
2411//*****************************************************************************
2412struct HASHFIND
2413{
2414 ULONG iBucket; // The next bucket to look in.
2415 ULONG iNext;
2416};
2417
2418
2419//*****************************************************************************
2420// IMPORTANT: This data structure is deprecated, please do not add any new uses.
2421// The hashtable implementation that should be used instead is code:SHash.
2422// If code:SHash does not work for you, talk to mailto:clrdeag.
2423//*****************************************************************************
2424// This is a class that implements a chain and bucket hash table.
2425//
2426// The data is actually supplied as an array of structures by the user of this class.
2427// This allows the buckets to use small indices to point to the chain, instead of pointers.
2428//
2429// Each entry in the array contains a HASHENTRY structure immediately
2430// followed by the key used to hash the structure.
2431//
2432// The HASHENTRY part of every structure is used to implement the chain of
2433// entries in a single bucket.
2434//
2435// This implementation does not support rehashing the buckets if the table grows
2436// to big.
2437// @TODO: Fix this by adding an abstract function Hash() which must be implemented
2438// by all clients.
2439//
2440//*****************************************************************************
2441class CHashTable
2442{
2443 friend class DebuggerRCThread; //RCthread actually needs access to
2444 //fields of derrived class DebuggerPatchTable
2445
2446protected:
2447 TADDR m_pcEntries; // Pointer to the array of structs.
2448 ULONG m_iEntrySize; // Size of the structs.
2449
2450 ULONG m_iBuckets; // # of chains we are hashing into.
2451 PTR_ULONG m_piBuckets; // Ptr to the array of bucket chains.
2452
2453 INDEBUG(unsigned m_maxSearch;) // For evaluating perf characteristics
2454
2455 HASHENTRY *EntryPtr(ULONG iEntry)
2456 {
2457 LIMITED_METHOD_DAC_CONTRACT;
2458 return (PTR_HASHENTRY(m_pcEntries + (iEntry * m_iEntrySize)));
2459 }
2460
2461 ULONG ItemIndex(HASHENTRY *p)
2462 {
2463 SUPPORTS_DAC;
2464 LIMITED_METHOD_CONTRACT;
2465 return (ULONG)((dac_cast<TADDR>(p) - m_pcEntries) / m_iEntrySize);
2466 }
2467
2468
2469public:
2470
2471 CHashTable(
2472 ULONG iBuckets) : // # of chains we are hashing into.
2473 m_pcEntries((TADDR)NULL),
2474 m_iBuckets(iBuckets)
2475 {
2476 LIMITED_METHOD_CONTRACT;
2477
2478 m_piBuckets = NULL;
2479
2480 INDEBUG(m_maxSearch = 0;)
2481 }
2482
2483 CHashTable() : // # of chains we are hashing into.
2484 m_pcEntries((TADDR)NULL),
2485 m_iBuckets(5)
2486 {
2487 LIMITED_METHOD_CONTRACT;
2488
2489 m_piBuckets = NULL;
2490
2491 INDEBUG(m_maxSearch = 0;)
2492 }
2493
2494#ifndef DACCESS_COMPILE
2495
2496 ~CHashTable()
2497 {
2498 LIMITED_METHOD_CONTRACT;
2499 if (m_piBuckets != NULL)
2500 {
2501 delete [] m_piBuckets;
2502 m_piBuckets = NULL;
2503 }
2504 }
2505
2506//*****************************************************************************
2507// This is the second part of construction where we do all of the work that
2508// can fail. We also take the array of structs here because the calling class
2509// presumably needs to allocate it in its NewInit.
2510//*****************************************************************************
2511 HRESULT NewInit( // Return status.
2512 BYTE *pcEntries, // Array of structs we are managing.
2513 ULONG iEntrySize); // Size of the entries.
2514
2515//*****************************************************************************
2516// This can be called to change the pointer to the table that the hash table
2517// is managing. You might call this if (for example) you realloc the size
2518// of the table and its pointer is different.
2519//*****************************************************************************
2520 void SetTable(
2521 BYTE *pcEntries) // Array of structs we are managing.
2522 {
2523 LIMITED_METHOD_CONTRACT;
2524 m_pcEntries = (TADDR)pcEntries;
2525 }
2526
2527//*****************************************************************************
2528// Clear the hash table as if there were nothing in it.
2529//*****************************************************************************
2530 void Clear()
2531 {
2532 LIMITED_METHOD_CONTRACT;
2533 _ASSERTE(m_piBuckets != NULL);
2534 memset(m_piBuckets, 0xff, m_iBuckets * sizeof(ULONG));
2535 }
2536
2537//*****************************************************************************
2538// Add the struct at the specified index in m_pcEntries to the hash chains.
2539//*****************************************************************************
2540 BYTE *Add( // New entry.
2541 ULONG iHash, // Hash value of entry to add.
2542 ULONG iIndex); // Index of struct in m_pcEntries.
2543
2544//*****************************************************************************
2545// Delete the struct at the specified index in m_pcEntries from the hash chains.
2546//*****************************************************************************
2547 void Delete(
2548 ULONG iHash, // Hash value of entry to delete.
2549 ULONG iIndex); // Index of struct in m_pcEntries.
2550
2551 void Delete(
2552 ULONG iHash, // Hash value of entry to delete.
2553 HASHENTRY *psEntry); // The struct to delete.
2554
2555//*****************************************************************************
2556// The item at the specified index has been moved, update the previous and
2557// next item.
2558//*****************************************************************************
2559 void Move(
2560 ULONG iHash, // Hash value for the item.
2561 ULONG iNew); // New location.
2562
2563#endif // #ifndef DACCESS_COMPILE
2564
2565//*****************************************************************************
2566// Return a boolean indicating whether or not this hash table has been inited.
2567//*****************************************************************************
2568 int IsInited()
2569 {
2570 LIMITED_METHOD_CONTRACT;
2571 return (m_piBuckets != NULL);
2572 }
2573
2574//*****************************************************************************
2575// Search the hash table for an entry with the specified key value.
2576//*****************************************************************************
2577 BYTE *Find( // Index of struct in m_pcEntries.
2578 ULONG iHash, // Hash value of the item.
2579 SIZE_T key); // The key to match.
2580
2581//*****************************************************************************
2582// Search the hash table for the next entry with the specified key value.
2583//*****************************************************************************
2584 ULONG FindNext( // Index of struct in m_pcEntries.
2585 SIZE_T key, // The key to match.
2586 ULONG iIndex); // Index of previous match.
2587
2588//*****************************************************************************
2589// Returns the first entry in the first hash bucket and inits the search
2590// struct. Use the FindNextEntry function to continue walking the list. The
2591// return order is not gauranteed.
2592//*****************************************************************************
2593 BYTE *FindFirstEntry( // First entry found, or 0.
2594 HASHFIND *psSrch) // Search object.
2595 {
2596 WRAPPER_NO_CONTRACT;
2597 if (m_piBuckets == 0)
2598 return (0);
2599 psSrch->iBucket = 1;
2600 psSrch->iNext = m_piBuckets[0];
2601 return (FindNextEntry(psSrch));
2602 }
2603
2604//*****************************************************************************
2605// Returns the next entry in the list.
2606//*****************************************************************************
2607 BYTE *FindNextEntry( // The next entry, or0 for end of list.
2608 HASHFIND *psSrch); // Search object.
2609
2610#ifdef DACCESS_COMPILE
2611 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
2612 ULONG numEntries);
2613#endif
2614
2615protected:
2616 virtual BOOL Cmp(SIZE_T key1, const HASHENTRY * pc2) = 0;
2617};
2618
2619
2620class CNewData
2621{
2622public:
2623 static BYTE *Alloc(int iSize, int iMaxSize)
2624 {
2625 WRAPPER_NO_CONTRACT;
2626 return (new BYTE[iSize]);
2627 }
2628 static void Free(BYTE *pPtr, int iSize)
2629 {
2630 LIMITED_METHOD_CONTRACT;
2631 delete [] pPtr;
2632 }
2633 static BYTE *Grow(BYTE *&pPtr, int iCurSize)
2634 {
2635 WRAPPER_NO_CONTRACT;
2636 BYTE *p;
2637 S_SIZE_T newSize = S_SIZE_T(iCurSize) + S_SIZE_T(GrowSize(iCurSize));
2638 //check for overflow
2639 if(newSize.IsOverflow())
2640 p = NULL;
2641 else
2642 p = new (nothrow) BYTE[newSize.Value()];
2643 if (p == 0) return (0);
2644 memcpy (p, pPtr, iCurSize);
2645 delete [] pPtr;
2646 pPtr = p;
2647 return pPtr;
2648 }
2649 static void Clean(BYTE * pData, int iSize)
2650 {
2651 }
2652 static int RoundSize(int iSize)
2653 {
2654 LIMITED_METHOD_CONTRACT;
2655 return (iSize);
2656 }
2657 static int GrowSize(int iCurSize)
2658 {
2659 LIMITED_METHOD_CONTRACT;
2660 int newSize = (3 * iCurSize) / 2;
2661 return (newSize < 256) ? 256 : newSize;
2662 }
2663};
2664
2665class CNewDataNoThrow
2666{
2667public:
2668 static BYTE *Alloc(int iSize, int iMaxSize)
2669 {
2670 WRAPPER_NO_CONTRACT;
2671 return (new (nothrow) BYTE[iSize]);
2672 }
2673 static void Free(BYTE *pPtr, int iSize)
2674 {
2675 LIMITED_METHOD_CONTRACT;
2676 delete [] pPtr;
2677 }
2678 static BYTE *Grow(BYTE *&pPtr, int iCurSize)
2679 {
2680 WRAPPER_NO_CONTRACT;
2681 BYTE *p;
2682 S_SIZE_T newSize = S_SIZE_T(iCurSize) + S_SIZE_T(GrowSize(iCurSize));
2683 //check for overflow
2684 if(newSize.IsOverflow())
2685 p = NULL;
2686 else
2687 p = new (nothrow) BYTE[newSize.Value()];
2688 if (p == 0) return (0);
2689 memcpy (p, pPtr, iCurSize);
2690 delete [] pPtr;
2691 pPtr = p;
2692 return pPtr;
2693 }
2694 static void Clean(BYTE * pData, int iSize)
2695 {
2696 }
2697 static int RoundSize(int iSize)
2698 {
2699 LIMITED_METHOD_CONTRACT;
2700 return (iSize);
2701 }
2702 static int GrowSize(int iCurSize)
2703 {
2704 LIMITED_METHOD_CONTRACT;
2705 int newSize = (3 * iCurSize) / 2;
2706 return (newSize < 256) ? 256 : newSize;
2707 }
2708};
2709
2710
2711//*****************************************************************************
2712// IMPORTANT: This data structure is deprecated, please do not add any new uses.
2713// The hashtable implementation that should be used instead is code:SHash.
2714// If code:SHash does not work for you, talk to mailto:clrdeag.
2715//*****************************************************************************
2716// CHashTable expects the data to be in a single array - this is provided by
2717// CHashTableAndData.
2718// The array is allocated using the MemMgr type. CNewData and
2719// CNewDataNoThrow can be used for this.
2720//*****************************************************************************
2721template <class MemMgr>
2722class CHashTableAndData : public CHashTable
2723{
2724public:
2725 ULONG m_iFree; // Index into m_pcEntries[] of next available slot
2726 ULONG m_iEntries; // size of m_pcEntries[]
2727
2728public:
2729
2730 CHashTableAndData() :
2731 CHashTable()
2732 {
2733 LIMITED_METHOD_CONTRACT;
2734 }
2735
2736 CHashTableAndData(
2737 ULONG iBuckets) : // # of chains we are hashing into.
2738 CHashTable(iBuckets)
2739 {
2740 LIMITED_METHOD_CONTRACT;
2741 }
2742
2743#ifndef DACCESS_COMPILE
2744
2745 ~CHashTableAndData()
2746 {
2747 WRAPPER_NO_CONTRACT;
2748 if (m_pcEntries != NULL)
2749 MemMgr::Free((BYTE*)m_pcEntries, MemMgr::RoundSize(m_iEntries * m_iEntrySize));
2750 }
2751
2752//*****************************************************************************
2753// This is the second part of construction where we do all of the work that
2754// can fail. We also take the array of structs here because the calling class
2755// presumably needs to allocate it in its NewInit.
2756//*****************************************************************************
2757 HRESULT NewInit( // Return status.
2758 ULONG iEntries, // # of entries.
2759 ULONG iEntrySize, // Size of the entries.
2760 int iMaxSize); // Max size of data.
2761
2762//*****************************************************************************
2763// Clear the hash table as if there were nothing in it.
2764//*****************************************************************************
2765 void Clear()
2766 {
2767 WRAPPER_NO_CONTRACT;
2768 m_iFree = 0;
2769 InitFreeChain(0, m_iEntries);
2770 CHashTable::Clear();
2771 }
2772
2773//*****************************************************************************
2774// Grabs a slot for the new entry to be added.
2775// The caller should fill in the non-HASHENTRY part of the returned slot
2776//*****************************************************************************
2777 BYTE *Add(
2778 ULONG iHash) // Hash value of entry to add.
2779 {
2780 WRAPPER_NO_CONTRACT;
2781 FREEHASHENTRY *psEntry;
2782
2783 // Make the table bigger if necessary.
2784 if (m_iFree == UINT32_MAX && !Grow())
2785 return (NULL);
2786
2787 // Add the first entry from the free list to the hash chain.
2788 psEntry = (FREEHASHENTRY *) CHashTable::Add(iHash, m_iFree);
2789 m_iFree = psEntry->iFree;
2790
2791 // If we're recycling memory, give our memory-allocator a chance to re-init it.
2792
2793 // Each entry is prefixed with a header - we don't want to trash that.
2794 SIZE_T cbHeader = sizeof(FREEHASHENTRY);
2795 MemMgr::Clean((BYTE*) psEntry + cbHeader, (int) (m_iEntrySize - cbHeader));
2796
2797 return ((BYTE *) psEntry);
2798 }
2799
2800//*****************************************************************************
2801// Delete the struct at the specified index in m_pcEntries from the hash chains.
2802//*****************************************************************************
2803 void Delete(
2804 ULONG iHash, // Hash value of entry to delete.
2805 ULONG iIndex) // Index of struct in m_pcEntries.
2806 {
2807 WRAPPER_NO_CONTRACT;
2808 CHashTable::Delete(iHash, iIndex);
2809 ((FREEHASHENTRY *) EntryPtr(iIndex))->iFree = m_iFree;
2810 m_iFree = iIndex;
2811 }
2812
2813 void Delete(
2814 ULONG iHash, // Hash value of entry to delete.
2815 HASHENTRY *psEntry) // The struct to delete.
2816 {
2817 WRAPPER_NO_CONTRACT;
2818 CHashTable::Delete(iHash, psEntry);
2819 ((FREEHASHENTRY *) psEntry)->iFree = m_iFree;
2820 m_iFree = ItemIndex(psEntry);
2821 }
2822
2823#endif // #ifndef DACCESS_COMPILE
2824
2825 // This is a sad legacy workaround. The debugger's patch table (implemented as this
2826 // class) is shared across process. We publish the runtime offsets of
2827 // some key fields. Since those fields are private, we have to provide
2828 // accessors here. So if you're not using these functions, don't start.
2829 // We can hopefully remove them.
2830 // Note that we can't just make RCThread a friend of this class (we tried
2831 // originally) because the inheritence chain has a private modifier,
2832 // so DebuggerPatchTable::m_pcEntries is illegal.
2833 static SIZE_T helper_GetOffsetOfEntries()
2834 {
2835 LIMITED_METHOD_CONTRACT;
2836 return offsetof(CHashTableAndData, m_pcEntries);
2837 }
2838
2839 static SIZE_T helper_GetOffsetOfCount()
2840 {
2841 LIMITED_METHOD_CONTRACT;
2842 return offsetof(CHashTableAndData, m_iEntries);
2843 }
2844
2845#ifdef DACCESS_COMPILE
2846 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2847 {
2848 SUPPORTS_DAC;
2849 CHashTable::EnumMemoryRegions(flags, m_iEntries);
2850 }
2851#endif
2852
2853private:
2854 void InitFreeChain(ULONG iStart,ULONG iEnd);
2855 int Grow();
2856};
2857
2858#ifndef DACCESS_COMPILE
2859
2860//*****************************************************************************
2861// This is the second part of construction where we do all of the work that
2862// can fail. We also take the array of structs here because the calling class
2863// presumably needs to allocate it in its NewInit.
2864//*****************************************************************************
2865template<class MemMgr>
2866HRESULT CHashTableAndData<MemMgr>::NewInit(// Return status.
2867 ULONG iEntries, // # of entries.
2868 ULONG iEntrySize, // Size of the entries.
2869 int iMaxSize) // Max size of data.
2870{
2871 WRAPPER_NO_CONTRACT;
2872 BYTE *pcEntries;
2873 HRESULT hr;
2874
2875
2876 // note that this function can throw because it depends on the <M>::Alloc
2877
2878 // Allocate the memory for the entries.
2879 if ((pcEntries = MemMgr::Alloc(MemMgr::RoundSize(iEntries * iEntrySize),
2880 MemMgr::RoundSize(iMaxSize))) == 0)
2881 return (E_OUTOFMEMORY);
2882 m_iEntries = iEntries;
2883
2884 // Init the base table.
2885 if (FAILED(hr = CHashTable::NewInit(pcEntries, iEntrySize)))
2886 MemMgr::Free(pcEntries, MemMgr::RoundSize(iEntries * iEntrySize));
2887 else
2888 {
2889 // Init the free chain.
2890 m_iFree = 0;
2891 InitFreeChain(0, iEntries);
2892 }
2893 return (hr);
2894}
2895
2896//*****************************************************************************
2897// Initialize a range of records such that they are linked together to be put
2898// on the free chain.
2899//*****************************************************************************
2900template<class MemMgr>
2901void CHashTableAndData<MemMgr>::InitFreeChain(
2902 ULONG iStart, // Index to start initializing.
2903 ULONG iEnd) // Index to stop initializing
2904{
2905 LIMITED_METHOD_CONTRACT;
2906 BYTE* pcPtr;
2907 _ASSERTE(iEnd > iStart);
2908
2909 pcPtr = (BYTE*)m_pcEntries + iStart * m_iEntrySize;
2910 for (++iStart; iStart < iEnd; ++iStart)
2911 {
2912 ((FREEHASHENTRY *) pcPtr)->iFree = iStart;
2913 pcPtr += m_iEntrySize;
2914 }
2915 ((FREEHASHENTRY *) pcPtr)->iFree = UINT32_MAX;
2916}
2917
2918//*****************************************************************************
2919// Attempt to increase the amount of space available for the record heap.
2920//*****************************************************************************
2921template<class MemMgr>
2922int CHashTableAndData<MemMgr>::Grow() // 1 if successful, 0 if not.
2923{
2924 WRAPPER_NO_CONTRACT;
2925 int iCurSize; // Current size in bytes.
2926 int iEntries; // New # of entries.
2927
2928 _ASSERTE(m_pcEntries != NULL);
2929 _ASSERTE(m_iFree == UINT32_MAX);
2930
2931 // Compute the current size and new # of entries.
2932 S_UINT32 iTotEntrySize = S_UINT32(m_iEntries) * S_UINT32(m_iEntrySize);
2933 if( iTotEntrySize.IsOverflow() )
2934 {
2935 _ASSERTE( !"CHashTableAndData overflow!" );
2936 return (0);
2937 }
2938 iCurSize = MemMgr::RoundSize( iTotEntrySize.Value() );
2939 iEntries = (iCurSize + MemMgr::GrowSize(iCurSize)) / m_iEntrySize;
2940
2941 if ( (iEntries < 0) || ((ULONG)iEntries <= m_iEntries) )
2942 {
2943 _ASSERTE( !"CHashTableAndData overflow!" );
2944 return (0);
2945 }
2946
2947 // Try to expand the array.
2948 if (MemMgr::Grow(*(BYTE**)&m_pcEntries, iCurSize) == 0)
2949 return (0);
2950
2951 // Init the newly allocated space.
2952 InitFreeChain(m_iEntries, iEntries);
2953 m_iFree = m_iEntries;
2954 m_iEntries = iEntries;
2955 return (1);
2956}
2957
2958#endif // #ifndef DACCESS_COMPILE
2959
2960//*****************************************************************************
2961//*****************************************************************************
2962
2963inline COUNT_T HashCOUNT_T(COUNT_T currentHash, COUNT_T data)
2964{
2965 LIMITED_METHOD_DAC_CONTRACT;
2966 return ((currentHash << 5) + currentHash) ^ data;
2967}
2968
2969inline COUNT_T HashPtr(COUNT_T currentHash, PTR_VOID ptr)
2970{
2971 WRAPPER_NO_CONTRACT;
2972 SUPPORTS_DAC;
2973 return HashCOUNT_T(currentHash, COUNT_T(SIZE_T(dac_cast<TADDR>(ptr))));
2974}
2975
2976inline DWORD HashThreeToOne(DWORD a, DWORD b, DWORD c)
2977{
2978 LIMITED_METHOD_DAC_CONTRACT;
2979
2980 /*
2981 lookup3.c, by Bob Jenkins, May 2006, Public Domain.
2982
2983 These are functions for producing 32-bit hashes for hash table lookup.
2984 hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
2985 are externally useful functions. Routines to test the hash are included
2986 if SELF_TEST is defined. You can use this free for any purpose. It's in
2987 the public domain. It has no warranty.
2988 */
2989
2990 #define rot32(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
2991 c ^= b; c -= rot32(b,14);
2992 a ^= c; a -= rot32(c,11);
2993 b ^= a; b -= rot32(a,25);
2994 c ^= b; c -= rot32(b,16);
2995 a ^= c; a -= rot32(c,4);
2996 b ^= a; b -= rot32(a,14);
2997 c ^= b; c -= rot32(b,24);
2998
2999 return c;
3000}
3001
3002inline ULONG HashBytes(BYTE const *pbData, size_t iSize)
3003{
3004 LIMITED_METHOD_CONTRACT;
3005 ULONG hash = 5381;
3006
3007 BYTE const *pbDataEnd = pbData + iSize;
3008
3009 for (/**/ ; pbData < pbDataEnd; pbData++)
3010 {
3011 hash = ((hash << 5) + hash) ^ *pbData;
3012 }
3013 return hash;
3014}
3015
3016// Helper function for hashing a string char by char.
3017inline ULONG HashStringA(LPCSTR szStr)
3018{
3019 LIMITED_METHOD_CONTRACT;
3020 ULONG hash = 5381;
3021 int c;
3022
3023 while ((c = *szStr) != 0)
3024 {
3025 hash = ((hash << 5) + hash) ^ c;
3026 ++szStr;
3027 }
3028 return hash;
3029}
3030
3031inline ULONG HashString(LPCWSTR szStr)
3032{
3033 LIMITED_METHOD_CONTRACT;
3034 ULONG hash = 5381;
3035 int c;
3036
3037 while ((c = *szStr) != 0)
3038 {
3039 hash = ((hash << 5) + hash) ^ c;
3040 ++szStr;
3041 }
3042 return hash;
3043}
3044
3045inline ULONG HashStringN(LPCWSTR szStr, SIZE_T cchStr)
3046{
3047 LIMITED_METHOD_CONTRACT;
3048 ULONG hash = 5381;
3049
3050 // hash the string two characters at a time
3051 ULONG *ptr = (ULONG *)szStr;
3052
3053 // we assume that szStr is null-terminated
3054 _ASSERTE(cchStr <= wcslen(szStr));
3055 SIZE_T cDwordCount = (cchStr + 1) / 2;
3056
3057 for (SIZE_T i = 0; i < cDwordCount; i++)
3058 {
3059 hash = ((hash << 5) + hash) ^ ptr[i];
3060 }
3061
3062 return hash;
3063}
3064
3065// Case-insensitive string hash function.
3066inline ULONG HashiStringA(LPCSTR szStr)
3067{
3068 LIMITED_METHOD_CONTRACT;
3069 ULONG hash = 5381;
3070 while (*szStr != 0)
3071 {
3072 hash = ((hash << 5) + hash) ^ toupper(*szStr);
3073 szStr++;
3074 }
3075 return hash;
3076}
3077
3078// Case-insensitive string hash function.
3079inline ULONG HashiString(LPCWSTR szStr)
3080{
3081 LIMITED_METHOD_CONTRACT;
3082 ULONG hash = 5381;
3083 while (*szStr != 0)
3084 {
3085 hash = ((hash << 5) + hash) ^ towupper(*szStr);
3086 szStr++;
3087 }
3088 return hash;
3089}
3090
3091// Case-insensitive string hash function.
3092inline ULONG HashiStringN(LPCWSTR szStr, DWORD count)
3093{
3094 LIMITED_METHOD_CONTRACT;
3095 ULONG hash = 5381;
3096 while (*szStr != 0 && count--)
3097 {
3098 hash = ((hash << 5) + hash) ^ towupper(*szStr);
3099 szStr++;
3100 }
3101 return hash;
3102}
3103
3104// Case-insensitive string hash function when all of the
3105// characters in the string are known to be below 0x80.
3106// Knowing this is much more efficient than calling
3107// towupper above.
3108inline ULONG HashiStringKnownLower80(LPCWSTR szStr) {
3109 LIMITED_METHOD_CONTRACT;
3110 ULONG hash = 5381;
3111 int c;
3112 int mask = ~0x20;
3113 while ((c = *szStr)!=0) {
3114 //If we have a lowercase character, ANDing off 0x20
3115 //(mask) will make it an uppercase character.
3116 if (c>='a' && c<='z') {
3117 c&=mask;
3118 }
3119 hash = ((hash << 5) + hash) ^ c;
3120 ++szStr;
3121 }
3122 return hash;
3123}
3124
3125inline ULONG HashiStringNKnownLower80(LPCWSTR szStr, DWORD count) {
3126 LIMITED_METHOD_CONTRACT;
3127 ULONG hash = 5381;
3128 int c;
3129 int mask = ~0x20;
3130 while ((c = *szStr) !=0 && count--) {
3131 //If we have a lowercase character, ANDing off 0x20
3132 //(mask) will make it an uppercase character.
3133 if (c>='a' && c<='z') {
3134 c&=mask;
3135 }
3136 hash = ((hash << 5) + hash) ^ c;
3137 ++szStr;
3138 }
3139 return hash;
3140}
3141
3142//*****************************************************************************
3143// IMPORTANT: This data structure is deprecated, please do not add any new uses.
3144// The hashtable implementation that should be used instead is code:SHash.
3145// If code:SHash does not work for you, talk to mailto:clrdeag.
3146//*****************************************************************************
3147// This class implements a closed hashing table. Values are hashed to a bucket,
3148// and if that bucket is full already, then the value is placed in the next
3149// free bucket starting after the desired target (with wrap around). If the
3150// table becomes 75% full, it is grown and rehashed to reduce lookups. This
3151// class is best used in a reltively small lookup table where hashing is
3152// not going to cause many collisions. By not having the collision chain
3153// logic, a lot of memory is saved.
3154//
3155// The user of the template is required to supply several methods which decide
3156// how each element can be marked as free, deleted, or used. It would have
3157// been possible to write this with more internal logic, but that would require
3158// either (a) more overhead to add status on top of elements, or (b) hard
3159// coded types like one for strings, one for ints, etc... This gives you the
3160// flexibility of adding logic to your type.
3161//*****************************************************************************
3162class CClosedHashBase
3163{
3164 BYTE *EntryPtr(int iEntry)
3165 {
3166 LIMITED_METHOD_CONTRACT;
3167 return (m_rgData + (iEntry * m_iEntrySize));
3168 }
3169
3170 BYTE *EntryPtr(int iEntry, BYTE *rgData)
3171 {
3172 LIMITED_METHOD_CONTRACT;
3173 return (rgData + (iEntry * m_iEntrySize));
3174 }
3175
3176public:
3177 enum ELEMENTSTATUS
3178 {
3179 FREE, // Item is not in use right now.
3180 DELETED, // Item is deleted.
3181 USED // Item is in use.
3182 };
3183
3184 CClosedHashBase(
3185 int iBuckets, // How many buckets should we start with.
3186 int iEntrySize, // Size of an entry.
3187 bool bPerfect) : // true if bucket size will hash with no collisions.
3188 m_bPerfect(bPerfect),
3189 m_iBuckets(iBuckets),
3190 m_iEntrySize(iEntrySize),
3191 m_iCount(0),
3192 m_iCollisions(0),
3193 m_rgData(0)
3194 {
3195 LIMITED_METHOD_CONTRACT;
3196 m_iSize = iBuckets + 7;
3197 }
3198
3199 virtual ~CClosedHashBase()
3200 {
3201 WRAPPER_NO_CONTRACT;
3202 Clear();
3203 }
3204
3205 virtual void Clear()
3206 {
3207 LIMITED_METHOD_CONTRACT;
3208 delete [] m_rgData;
3209 m_iCount = 0;
3210 m_iCollisions = 0;
3211 m_rgData = 0;
3212 }
3213
3214//*****************************************************************************
3215// Accessors for getting at the underlying data. Be careful to use Count()
3216// only when you want the number of buckets actually used.
3217//*****************************************************************************
3218
3219 int Count()
3220 {
3221 LIMITED_METHOD_CONTRACT;
3222 return (m_iCount);
3223 }
3224
3225 int Collisions()
3226 {
3227 LIMITED_METHOD_CONTRACT;
3228 return (m_iCollisions);
3229 }
3230
3231 int Buckets()
3232 {
3233 LIMITED_METHOD_CONTRACT;
3234 return (m_iBuckets);
3235 }
3236
3237 void SetBuckets(int iBuckets, bool bPerfect=false)
3238 {
3239 LIMITED_METHOD_CONTRACT;
3240 _ASSERTE(m_rgData == 0);
3241 m_iBuckets = iBuckets;
3242 m_iSize = m_iBuckets + 7;
3243 m_bPerfect = bPerfect;
3244 }
3245
3246 BYTE *Data()
3247 {
3248 LIMITED_METHOD_CONTRACT;
3249 return (m_rgData);
3250 }
3251
3252//*****************************************************************************
3253// Add a new item to hash table given the key value. If this new entry
3254// exceeds maximum size, then the table will grow and be re-hashed, which
3255// may cause a memory error.
3256//*****************************************************************************
3257 BYTE *Add( // New item to fill out on success.
3258 void *pData) // The value to hash on.
3259 {
3260 WRAPPER_NO_CONTRACT;
3261 // If we haven't allocated any memory, or it is too small, fix it.
3262 if (!m_rgData || ((m_iCount + 1) > (m_iSize * 3 / 4) && !m_bPerfect))
3263 {
3264 if (!ReHash())
3265 return (0);
3266 }
3267
3268 return (DoAdd(pData, m_rgData, m_iBuckets, m_iSize, m_iCollisions, m_iCount));
3269 }
3270
3271//*****************************************************************************
3272// Delete the given value. This will simply mark the entry as deleted (in
3273// order to keep the collision chain intact). There is an optimization that
3274// consecutive deleted entries leading up to a free entry are themselves freed
3275// to reduce collisions later on.
3276//*****************************************************************************
3277 void Delete(
3278 void *pData); // Key value to delete.
3279
3280
3281//*****************************************************************************
3282// Callback function passed to DeleteLoop.
3283//*****************************************************************************
3284 typedef BOOL (* DELETELOOPFUNC)( // Delete current item?
3285 BYTE *pEntry, // Bucket entry to evaluate
3286 void *pCustomizer); // User-defined value
3287
3288//*****************************************************************************
3289// Iterates over all active values, passing each one to pDeleteLoopFunc.
3290// If pDeleteLoopFunc returns TRUE, the entry is deleted. This is safer
3291// and faster than using FindNext() and Delete().
3292//*****************************************************************************
3293 void DeleteLoop(
3294 DELETELOOPFUNC pDeleteLoopFunc, // Decides whether to delete item
3295 void *pCustomizer); // Extra value passed to deletefunc.
3296
3297
3298//*****************************************************************************
3299// Lookup a key value and return a pointer to the element if found.
3300//*****************************************************************************
3301 BYTE *Find( // The item if found, 0 if not.
3302 void *pData); // The key to lookup.
3303
3304//*****************************************************************************
3305// Look for an item in the table. If it isn't found, then create a new one and
3306// return that.
3307//*****************************************************************************
3308 BYTE *FindOrAdd( // The item if found, 0 if not.
3309 void *pData, // The key to lookup.
3310 bool &bNew); // true if created.
3311
3312//*****************************************************************************
3313// The following functions are used to traverse each used entry. This code
3314// will skip over deleted and free entries freeing the caller up from such
3315// logic.
3316//*****************************************************************************
3317 BYTE *GetFirst() // The first entry, 0 if none.
3318 {
3319 WRAPPER_NO_CONTRACT;
3320 int i; // Loop control.
3321
3322 // If we've never allocated the table there can't be any to get.
3323 if (m_rgData == 0)
3324 return (0);
3325
3326 // Find the first one.
3327 for (i=0; i<m_iSize; i++)
3328 {
3329 if (Status(EntryPtr(i)) != FREE && Status(EntryPtr(i)) != DELETED)
3330 return (EntryPtr(i));
3331 }
3332 return (0);
3333 }
3334
3335 BYTE *GetNext(BYTE *Prev) // The next entry, 0 if done.
3336 {
3337 WRAPPER_NO_CONTRACT;
3338 int i; // Loop control.
3339
3340 for (i = (int)(((size_t) Prev - (size_t) &m_rgData[0]) / m_iEntrySize) + 1; i<m_iSize; i++)
3341 {
3342 if (Status(EntryPtr(i)) != FREE && Status(EntryPtr(i)) != DELETED)
3343 return (EntryPtr(i));
3344 }
3345 return (0);
3346 }
3347
3348private:
3349//*****************************************************************************
3350// Hash is called with a pointer to an element in the table. You must override
3351// this method and provide a hash algorithm for your element type.
3352//*****************************************************************************
3353 virtual unsigned int Hash( // The key value.
3354 void const *pData)=0; // Raw data to hash.
3355
3356//*****************************************************************************
3357// Compare is used in the typical memcmp way, 0 is eqaulity, -1/1 indicate
3358// direction of miscompare. In this system everything is always equal or not.
3359//*****************************************************************************
3360 virtual unsigned int Compare( // 0, -1, or 1.
3361 void const *pData, // Raw key data on lookup.
3362 BYTE *pElement)=0; // The element to compare data against.
3363
3364//*****************************************************************************
3365// Return true if the element is free to be used.
3366//*****************************************************************************
3367 virtual ELEMENTSTATUS Status( // The status of the entry.
3368 BYTE *pElement)=0; // The element to check.
3369
3370//*****************************************************************************
3371// Sets the status of the given element.
3372//*****************************************************************************
3373 virtual void SetStatus(
3374 BYTE *pElement, // The element to set status for.
3375 ELEMENTSTATUS eStatus)=0; // New status.
3376
3377//*****************************************************************************
3378// Returns the internal key value for an element.
3379//*****************************************************************************
3380 virtual void *GetKey( // The data to hash on.
3381 BYTE *pElement)=0; // The element to return data ptr for.
3382
3383//*****************************************************************************
3384// This helper actually does the add for you.
3385//*****************************************************************************
3386 BYTE *DoAdd(void *pData, BYTE *rgData, int &iBuckets, int iSize,
3387 int &iCollisions, int &iCount);
3388
3389//*****************************************************************************
3390// This function is called either to init the table in the first place, or
3391// to rehash the table if we ran out of room.
3392//*****************************************************************************
3393 bool ReHash(); // true if successful.
3394
3395//*****************************************************************************
3396// Walk each item in the table and mark it free.
3397//*****************************************************************************
3398 void InitFree(BYTE *ptr, int iSize)
3399 {
3400 WRAPPER_NO_CONTRACT;
3401 int i;
3402 for (i=0; i<iSize; i++, ptr += m_iEntrySize)
3403 SetStatus(ptr, FREE);
3404 }
3405
3406private:
3407 bool m_bPerfect; // true if the table size guarantees
3408 // no collisions.
3409 int m_iBuckets; // How many buckets do we have.
3410 int m_iEntrySize; // Size of an entry.
3411 int m_iSize; // How many elements can we have.
3412 int m_iCount; // How many items cannot be used (NON free, i.e. USED+DELETED).
3413 int m_iCollisions; // How many have we had.
3414 BYTE *m_rgData; // Data element list.
3415};
3416
3417//*****************************************************************************
3418// IMPORTANT: This data structure is deprecated, please do not add any new uses.
3419// The hashtable implementation that should be used instead is code:SHash.
3420// If code:SHash does not work for you, talk to mailto:clrdeag.
3421//*****************************************************************************
3422template <class T> class CClosedHash : public CClosedHashBase
3423{
3424public:
3425 CClosedHash(
3426 int iBuckets, // How many buckets should we start with.
3427 bool bPerfect=false) : // true if bucket size will hash with no collisions.
3428 CClosedHashBase(iBuckets, sizeof(T), bPerfect)
3429 {
3430 WRAPPER_NO_CONTRACT;
3431 }
3432
3433 T &operator[](int iIndex)
3434 {
3435 WRAPPER_NO_CONTRACT;
3436 return ((T &) *(Data() + (iIndex * sizeof(T))));
3437 }
3438
3439
3440//*****************************************************************************
3441// Add a new item to hash table given the key value. If this new entry
3442// exceeds maximum size, then the table will grow and be re-hashed, which
3443// may cause a memory error.
3444//*****************************************************************************
3445 T *Add( // New item to fill out on success.
3446 void *pData) // The value to hash on.
3447 {
3448 WRAPPER_NO_CONTRACT;
3449 return ((T *) CClosedHashBase::Add(pData));
3450 }
3451
3452//*****************************************************************************
3453// Lookup a key value and return a pointer to the element if found.
3454//*****************************************************************************
3455 T *Find( // The item if found, 0 if not.
3456 void *pData) // The key to lookup.
3457 {
3458 WRAPPER_NO_CONTRACT;
3459 return ((T *) CClosedHashBase::Find(pData));
3460 }
3461
3462//*****************************************************************************
3463// Look for an item in the table. If it isn't found, then create a new one and
3464// return that.
3465//*****************************************************************************
3466 T *FindOrAdd( // The item if found, 0 if not.
3467 void *pData, // The key to lookup.
3468 bool &bNew) // true if created.
3469 {
3470 WRAPPER_NO_CONTRACT;
3471 return ((T *) CClosedHashBase::FindOrAdd(pData, bNew));
3472 }
3473
3474
3475//*****************************************************************************
3476// The following functions are used to traverse each used entry. This code
3477// will skip over deleted and free entries freeing the caller up from such
3478// logic.
3479//*****************************************************************************
3480 T *GetFirst() // The first entry, 0 if none.
3481 {
3482 WRAPPER_NO_CONTRACT;
3483 return ((T *) CClosedHashBase::GetFirst());
3484 }
3485
3486 T *GetNext(T *Prev) // The next entry, 0 if done.
3487 {
3488 WRAPPER_NO_CONTRACT;
3489 return ((T *) CClosedHashBase::GetNext((BYTE *) Prev));
3490 }
3491};
3492
3493
3494//*****************************************************************************
3495// IMPORTANT: This data structure is deprecated, please do not add any new uses.
3496// The hashtable implementation that should be used instead is code:SHash.
3497// If code:SHash does not work for you, talk to mailto:clrdeag.
3498//*****************************************************************************
3499// Closed hash with typed parameters. The derived class is the second
3500// parameter to the template. The derived class must implement:
3501// unsigned long Hash(const T *pData);
3502// unsigned long Compare(const T *p1, T *p2);
3503// ELEMENTSTATUS Status(T *pEntry);
3504// void SetStatus(T *pEntry, ELEMENTSTATUS s);
3505// void* GetKey(T *pEntry);
3506//*****************************************************************************
3507template<class T, class H>class CClosedHashEx : public CClosedHash<T>
3508{
3509public:
3510 CClosedHashEx(
3511 int iBuckets, // How many buckets should we start with.
3512 bool bPerfect=false) : // true if bucket size will hash with no collisions.
3513 CClosedHash<T> (iBuckets, bPerfect)
3514 {
3515 WRAPPER_NO_CONTRACT;
3516 }
3517
3518 unsigned int Hash(const void *pData)
3519 {
3520 WRAPPER_NO_CONTRACT;
3521 return static_cast<H*>(this)->Hash((const T*)pData);
3522 }
3523
3524 unsigned int Compare(const void *p1, BYTE *p2)
3525 {
3526 WRAPPER_NO_CONTRACT;
3527 return static_cast<H*>(this)->Compare((const T*)p1, (T*)p2);
3528 }
3529
3530 typename CClosedHash<T>::ELEMENTSTATUS Status(BYTE *p)
3531 {
3532 WRAPPER_NO_CONTRACT;
3533 return static_cast<H*>(this)->Status((T*)p);
3534 }
3535
3536 void SetStatus(BYTE *p, typename CClosedHash<T>::ELEMENTSTATUS s)
3537 {
3538 WRAPPER_NO_CONTRACT;
3539 static_cast<H*>(this)->SetStatus((T*)p, s);
3540 }
3541
3542 void* GetKey(BYTE *p)
3543 {
3544 WRAPPER_NO_CONTRACT;
3545 return static_cast<H*>(this)->GetKey((T*)p);
3546 }
3547};
3548
3549
3550//*****************************************************************************
3551// IMPORTANT: This data structure is deprecated, please do not add any new uses.
3552// The hashtable implementation that should be used instead is code:SHash.
3553// If code:SHash does not work for you, talk to mailto:clrdeag.
3554//*****************************************************************************
3555// This template is another form of a closed hash table. It handles collisions
3556// through a linked chain. To use it, derive your hashed item from HASHLINK
3557// and implement the virtual functions required. 1.5 * ibuckets will be
3558// allocated, with the extra .5 used for collisions. If you add to the point
3559// where no free nodes are available, the entire table is grown to make room.
3560// The advantage to this system is that collisions are always directly known,
3561// there either is one or there isn't.
3562//*****************************************************************************
3563struct HASHLINK
3564{
3565 ULONG iNext; // Offset for next entry.
3566};
3567
3568template <class T> class CChainedHash
3569{
3570 friend class VerifyLayoutsMD;
3571public:
3572 CChainedHash(int iBuckets=32) :
3573 m_rgData(0),
3574 m_iBuckets(iBuckets),
3575 m_iCount(0),
3576 m_iMaxChain(0),
3577 m_iFree(0)
3578 {
3579 LIMITED_METHOD_CONTRACT;
3580 m_iSize = iBuckets + (iBuckets / 2);
3581 }
3582
3583 ~CChainedHash()
3584 {
3585 LIMITED_METHOD_CONTRACT;
3586 if (m_rgData)
3587 delete [] m_rgData;
3588 }
3589
3590 void SetBuckets(int iBuckets)
3591 {
3592 LIMITED_METHOD_CONTRACT;
3593 _ASSERTE(m_rgData == 0);
3594 // if iBuckets==0, then we'll allocate a zero size array and AV on dereference.
3595 _ASSERTE(iBuckets > 0);
3596 m_iBuckets = iBuckets;
3597 m_iSize = iBuckets + (iBuckets / 2);
3598 }
3599
3600 T *Add(void const *pData)
3601 {
3602 WRAPPER_NO_CONTRACT;
3603 ULONG iHash;
3604 int iBucket;
3605 T *pItem;
3606
3607 // Build the list if required.
3608 if (m_rgData == 0 || m_iFree == 0xffffffff)
3609 {
3610 if (!ReHash())
3611 return (0);
3612 }
3613
3614 // Hash the item and pick a bucket.
3615 iHash = Hash(pData);
3616 iBucket = iHash % m_iBuckets;
3617
3618 // Use the bucket if it is free.
3619 if (InUse(&m_rgData[iBucket]) == false)
3620 {
3621 pItem = &m_rgData[iBucket];
3622 pItem->iNext = 0xffffffff;
3623 }
3624 // Else take one off of the free list for use.
3625 else
3626 {
3627 ULONG iEntry;
3628
3629 // Pull an item from the free list.
3630 iEntry = m_iFree;
3631 pItem = &m_rgData[m_iFree];
3632 m_iFree = pItem->iNext;
3633
3634 // Link the new node in after the bucket.
3635 pItem->iNext = m_rgData[iBucket].iNext;
3636 m_rgData[iBucket].iNext = iEntry;
3637 }
3638 ++m_iCount;
3639 return (pItem);
3640 }
3641
3642 T *Find(void const *pData, bool bAddIfNew=false)
3643 {
3644 WRAPPER_NO_CONTRACT;
3645 ULONG iHash;
3646 int iBucket;
3647 T *pItem;
3648
3649 // Check states for lookup.
3650 if (m_rgData == 0)
3651 {
3652 // If we won't be adding, then we are through.
3653 if (bAddIfNew == false)
3654 return (0);
3655
3656 // Otherwise, create the table.
3657 if (!ReHash())
3658 return (0);
3659 }
3660
3661 // Hash the item and pick a bucket.
3662 iHash = Hash(pData);
3663 iBucket = iHash % m_iBuckets;
3664
3665 // If it isn't in use, then there it wasn't found.
3666 if (!InUse(&m_rgData[iBucket]))
3667 {
3668 if (bAddIfNew == false)
3669 pItem = 0;
3670 else
3671 {
3672 pItem = &m_rgData[iBucket];
3673 pItem->iNext = 0xffffffff;
3674 ++m_iCount;
3675 }
3676 }
3677 // Scan the list for the one we want.
3678 else
3679 {
3680 ULONG iChain = 0;
3681 for (pItem=(T *) &m_rgData[iBucket]; pItem; pItem=GetNext(pItem))
3682 {
3683 if (Cmp(pData, pItem) == 0)
3684 break;
3685 ++iChain;
3686 }
3687
3688 if (!pItem && bAddIfNew)
3689 {
3690 ULONG iEntry;
3691
3692 // Record maximum chain length.
3693 if (iChain > m_iMaxChain)
3694 m_iMaxChain = iChain;
3695
3696 // Now need more room.
3697 if (m_iFree == 0xffffffff)
3698 {
3699 if (!ReHash())
3700 return (0);
3701 }
3702
3703 // Pull an item from the free list.
3704 iEntry = m_iFree;
3705 pItem = &m_rgData[m_iFree];
3706 m_iFree = pItem->iNext;
3707
3708 // Link the new node in after the bucket.
3709 pItem->iNext = m_rgData[iBucket].iNext;
3710 m_rgData[iBucket].iNext = iEntry;
3711 ++m_iCount;
3712 }
3713 }
3714 return (pItem);
3715 }
3716
3717 int Count()
3718 {
3719 LIMITED_METHOD_CONTRACT;
3720 return (m_iCount);
3721 }
3722
3723 int Buckets()
3724 {
3725 LIMITED_METHOD_CONTRACT;
3726 return (m_iBuckets);
3727 }
3728
3729 ULONG MaxChainLength()
3730 {
3731 LIMITED_METHOD_CONTRACT;
3732 return (m_iMaxChain);
3733 }
3734
3735 virtual void Clear()
3736 {
3737 LIMITED_METHOD_CONTRACT;
3738 // Free up the memory.
3739 if (m_rgData)
3740 {
3741 delete [] m_rgData;
3742 m_rgData = 0;
3743 }
3744
3745 m_rgData = 0;
3746 m_iFree = 0;
3747 m_iCount = 0;
3748 m_iMaxChain = 0;
3749 }
3750
3751 virtual bool InUse(T *pItem)=0;
3752 virtual void SetFree(T *pItem)=0;
3753 virtual ULONG Hash(void const *pData)=0;
3754 virtual int Cmp(void const *pData, void *pItem)=0;
3755private:
3756 inline T *GetNext(T *pItem)
3757 {
3758 LIMITED_METHOD_CONTRACT;
3759 if (pItem->iNext != 0xffffffff)
3760 return ((T *) &m_rgData[pItem->iNext]);
3761 return (0);
3762 }
3763
3764 bool ReHash()
3765 {
3766 WRAPPER_NO_CONTRACT;
3767 T *rgTemp;
3768 int iNewSize;
3769
3770 // If this is a first time allocation, then just malloc it.
3771 if (!m_rgData)
3772 {
3773 if ((m_rgData = new (nothrow) T[m_iSize]) == 0)
3774 return (false);
3775
3776 int i;
3777 for (i=0; i<m_iSize; i++)
3778 SetFree(&m_rgData[i]);
3779
3780 m_iFree = m_iBuckets;
3781 for (i=m_iBuckets; i<m_iSize; i++)
3782 ((T *) &m_rgData[i])->iNext = i + 1;
3783 ((T *) &m_rgData[m_iSize - 1])->iNext = 0xffffffff;
3784 return (true);
3785 }
3786
3787 // Otherwise we need more room on the free chain, so allocate some.
3788 iNewSize = m_iSize + (m_iSize / 2);
3789
3790 // Allocate/realloc memory.
3791 if ((rgTemp = new (nothrow) T[iNewSize]) == 0)
3792 return (false);
3793
3794 memcpy (rgTemp,m_rgData,m_iSize*sizeof(T));
3795 delete [] m_rgData;
3796
3797 // Init new entries, save the new free chain, and reset internals.
3798 m_iFree = m_iSize;
3799 for (int i=m_iFree; i<iNewSize; i++)
3800 {
3801 SetFree(&rgTemp[i]);
3802 ((T *) &rgTemp[i])->iNext = i + 1;
3803 }
3804 ((T *) &rgTemp[iNewSize - 1])->iNext = 0xffffffff;
3805
3806 m_rgData = rgTemp;
3807 m_iSize = iNewSize;
3808 return (true);
3809 }
3810
3811private:
3812 T *m_rgData; // Data to store items in.
3813 int m_iBuckets; // How many buckets we want.
3814 int m_iSize; // How many are allocated.
3815 int m_iCount; // How many are we using.
3816 ULONG m_iMaxChain; // Max chain length.
3817 ULONG m_iFree; // Free chain.
3818};
3819
3820
3821//*****************************************************************************
3822//
3823//********** String helper functions.
3824//
3825//*****************************************************************************
3826
3827//*****************************************************************************
3828// Checks if string length exceeds the specified limit
3829//*****************************************************************************
3830inline BOOL IsStrLongerThan(__in __in_z char* pstr, unsigned N)
3831{
3832 LIMITED_METHOD_CONTRACT;
3833 unsigned i = 0;
3834 if(pstr)
3835 {
3836 for(i=0; (i < N)&&(pstr[i]); i++);
3837 }
3838 return (i >= N);
3839}
3840
3841
3842//*****************************************************************************
3843// Class to parse a list of simple assembly names and then find a match
3844//*****************************************************************************
3845
3846class AssemblyNamesList
3847{
3848 struct AssemblyName
3849 {
3850 LPUTF8 m_assemblyName;
3851 AssemblyName *m_next; // Next name
3852 };
3853
3854 AssemblyName *m_pNames; // List of names
3855
3856public:
3857
3858 bool IsInList(LPCUTF8 assemblyName);
3859
3860 bool IsEmpty()
3861 {
3862 LIMITED_METHOD_CONTRACT;
3863 return m_pNames == 0;
3864 }
3865
3866 AssemblyNamesList(__in LPWSTR list);
3867 ~AssemblyNamesList();
3868};
3869
3870//*****************************************************************************
3871// Class to parse a list of method names and then find a match
3872//*****************************************************************************
3873
3874struct CORINFO_SIG_INFO;
3875
3876class MethodNamesListBase
3877{
3878 struct MethodName
3879 {
3880 LPUTF8 methodName; // NULL means wildcard
3881 LPUTF8 className; // NULL means wildcard
3882 int numArgs; // number of args for the method, -1 is wildcard
3883 MethodName *next; // Next name
3884 };
3885
3886 MethodName *pNames; // List of names
3887
3888 bool IsInList(LPCUTF8 methodName, LPCUTF8 className, int numArgs);
3889
3890public:
3891 void Init()
3892 {
3893 LIMITED_METHOD_CONTRACT;
3894 pNames = 0;
3895 }
3896
3897 void Init(__in __in_z LPWSTR list)
3898 {
3899 WRAPPER_NO_CONTRACT;
3900 pNames = 0;
3901 Insert(list);
3902 }
3903
3904 void Destroy();
3905
3906 void Insert(__in __in_z LPWSTR list);
3907
3908 bool IsInList(LPCUTF8 methodName, LPCUTF8 className, PCCOR_SIGNATURE sig = NULL);
3909 bool IsInList(LPCUTF8 methodName, LPCUTF8 className, CORINFO_SIG_INFO* pSigInfo);
3910 bool IsEmpty()
3911 {
3912 LIMITED_METHOD_CONTRACT;
3913 return pNames == 0;
3914 }
3915};
3916
3917class MethodNamesList : public MethodNamesListBase
3918{
3919public:
3920 MethodNamesList()
3921 {
3922 WRAPPER_NO_CONTRACT;
3923 Init();
3924 }
3925
3926 MethodNamesList(__in LPWSTR list)
3927 {
3928 WRAPPER_NO_CONTRACT;
3929 Init(list);
3930 }
3931
3932 ~MethodNamesList()
3933 {
3934 WRAPPER_NO_CONTRACT;
3935 Destroy();
3936 }
3937};
3938
3939#if !defined(NO_CLRCONFIG)
3940
3941/**************************************************************************/
3942/* simple wrappers around the REGUTIL and MethodNameList routines that make
3943 the lookup lazy */
3944
3945/* to be used as static variable - no constructor/destructor, assumes zero
3946 initialized memory */
3947
3948class ConfigDWORD
3949{
3950public:
3951 //
3952 // NOTE: The following function is deprecated; use the CLRConfig class instead.
3953 // To access a configuration value through CLRConfig, add an entry in file:../inc/CLRConfigValues.h.
3954 //
3955 inline DWORD val_DontUse_(__in __in_z LPCWSTR keyName, DWORD defaultVal=0)
3956 {
3957 WRAPPER_NO_CONTRACT;
3958 // make sure that the memory was zero initialized
3959 _ASSERTE(m_inited == 0 || m_inited == 1);
3960
3961 if (!m_inited) init_DontUse_(keyName, defaultVal);
3962 return m_value;
3963 }
3964 inline DWORD val(const CLRConfig::ConfigDWORDInfo & info)
3965 {
3966 WRAPPER_NO_CONTRACT;
3967 // make sure that the memory was zero initialized
3968 _ASSERTE(m_inited == 0 || m_inited == 1);
3969
3970 if (!m_inited) init(info);
3971 return m_value;
3972 }
3973
3974private:
3975 void init_DontUse_(__in __in_z LPCWSTR keyName, DWORD defaultVal=0);
3976 void init(const CLRConfig::ConfigDWORDInfo & info);
3977
3978private:
3979 DWORD m_value;
3980 BYTE m_inited;
3981};
3982
3983/**************************************************************************/
3984class ConfigString
3985{
3986public:
3987 inline LPWSTR val(const CLRConfig::ConfigStringInfo & info)
3988 {
3989 WRAPPER_NO_CONTRACT;
3990 // make sure that the memory was zero initialized
3991 _ASSERTE(m_inited == 0 || m_inited == 1);
3992
3993 if (!m_inited) init(info);
3994 return m_value;
3995 }
3996
3997 bool isInitialized()
3998 {
3999 WRAPPER_NO_CONTRACT;
4000
4001 // make sure that the memory was zero initialized
4002 _ASSERTE(m_inited == 0 || m_inited == 1);
4003
4004 return m_inited == 1;
4005 }
4006
4007private:
4008 void init(const CLRConfig::ConfigStringInfo & info);
4009
4010private:
4011 LPWSTR m_value;
4012 BYTE m_inited;
4013};
4014
4015/**************************************************************************/
4016class ConfigMethodSet
4017{
4018public:
4019 bool isEmpty()
4020 {
4021 WRAPPER_NO_CONTRACT;
4022 _ASSERTE(m_inited == 1);
4023 return m_list.IsEmpty();
4024 }
4025
4026 bool contains(LPCUTF8 methodName, LPCUTF8 className, PCCOR_SIGNATURE sig = NULL);
4027 bool contains(LPCUTF8 methodName, LPCUTF8 className, CORINFO_SIG_INFO* pSigInfo);
4028
4029 inline void ensureInit(const CLRConfig::ConfigStringInfo & info)
4030 {
4031 WRAPPER_NO_CONTRACT;
4032 // make sure that the memory was zero initialized
4033 _ASSERTE(m_inited == 0 || m_inited == 1);
4034
4035 if (!m_inited) init(info);
4036 }
4037
4038private:
4039 void init(const CLRConfig::ConfigStringInfo & info);
4040
4041private:
4042 MethodNamesListBase m_list;
4043
4044 BYTE m_inited;
4045};
4046
4047#endif // !defined(NO_CLRCONFIG)
4048
4049//*****************************************************************************
4050// Convert a pointer to a string into a GUID.
4051//*****************************************************************************
4052HRESULT LPCSTRToGuid( // Return status.
4053 LPCSTR szGuid, // String to convert.
4054 GUID *psGuid); // Buffer for converted GUID.
4055
4056//*****************************************************************************
4057// Convert a GUID into a pointer to a string
4058//*****************************************************************************
4059int GuidToLPWSTR( // Return status.
4060 GUID Guid, // [IN] The GUID to convert.
4061 __out_ecount (cchGuid) LPWSTR szGuid, // [OUT] String into which the GUID is stored
4062 DWORD cchGuid); // [IN] Size in wide chars of szGuid
4063
4064//*****************************************************************************
4065// Parse a Wide char string into a GUID
4066//*****************************************************************************
4067BOOL LPWSTRToGuid(
4068 GUID * Guid, // [OUT] The GUID to fill in
4069 __in_ecount(cchGuid) LPCWSTR szGuid, // [IN] String to parse
4070 DWORD cchGuid); // [IN] Count in wchars in string
4071
4072typedef VPTR(class RangeList) PTR_RangeList;
4073
4074class RangeList
4075{
4076 public:
4077 VPTR_BASE_CONCRETE_VTABLE_CLASS(RangeList)
4078
4079#ifndef DACCESS_COMPILE
4080 RangeList();
4081 ~RangeList();
4082#else
4083 RangeList()
4084 {
4085 LIMITED_METHOD_CONTRACT;
4086 }
4087#endif
4088
4089 // Wrappers to make the virtual calls DAC-safe.
4090 BOOL AddRange(const BYTE *start, const BYTE *end, void *id)
4091 {
4092 return this->AddRangeWorker(start, end, id);
4093 }
4094
4095 void RemoveRanges(void *id, const BYTE *start = NULL, const BYTE *end = NULL)
4096 {
4097 return this->RemoveRangesWorker(id, start, end);
4098 }
4099
4100 BOOL IsInRange(TADDR address, TADDR *pID = NULL)
4101 {
4102 SUPPORTS_DAC;
4103
4104 return this->IsInRangeWorker(address, pID);
4105 }
4106
4107#ifndef DACCESS_COMPILE
4108
4109 // You can overload these two for synchronization (as LockedRangeList does)
4110 virtual BOOL AddRangeWorker(const BYTE *start, const BYTE *end, void *id);
4111 // If both "start" and "end" are NULL, then this method deletes all ranges with
4112 // the given id (i.e. the original behaviour). Otherwise, it ignores the given
4113 // id and deletes all ranges falling in the region [start, end).
4114 virtual void RemoveRangesWorker(void *id, const BYTE *start = NULL, const BYTE *end = NULL);
4115#else
4116 virtual BOOL AddRangeWorker(const BYTE *start, const BYTE *end, void *id)
4117 {
4118 return TRUE;
4119 }
4120 virtual void RemoveRangesWorker(void *id, const BYTE *start = NULL, const BYTE *end = NULL) { }
4121#endif // !DACCESS_COMPILE
4122
4123 virtual BOOL IsInRangeWorker(TADDR address, TADDR *pID = NULL);
4124
4125#ifdef DACCESS_COMPILE
4126 void EnumMemoryRegions(enum CLRDataEnumMemoryFlags flags);
4127#endif
4128
4129 enum
4130 {
4131 RANGE_COUNT = 10
4132 };
4133
4134
4135 private:
4136 struct Range
4137 {
4138 TADDR start;
4139 TADDR end;
4140 TADDR id;
4141 };
4142
4143 struct RangeListBlock
4144 {
4145 Range ranges[RANGE_COUNT];
4146 DPTR(RangeListBlock) next;
4147
4148#ifdef DACCESS_COMPILE
4149 void EnumMemoryRegions(enum CLRDataEnumMemoryFlags flags);
4150#endif
4151
4152 };
4153
4154 void InitBlock(RangeListBlock *block);
4155
4156 RangeListBlock m_starterBlock;
4157 DPTR(RangeListBlock) m_firstEmptyBlock;
4158 TADDR m_firstEmptyRange;
4159};
4160
4161
4162//
4163// A private function to do the equavilent of a CoCreateInstance in
4164// cases where we can't make the real call. Use this when, for
4165// instance, you need to create a symbol reader in the Runtime but
4166// we're not CoInitialized. Obviously, this is only good for COM
4167// objects for which CoCreateInstance is just a glorified
4168// find-and-load-me operation.
4169//
4170
4171HRESULT FakeCoCreateInstanceEx(REFCLSID rclsid,
4172 LPCWSTR wszDllPath,
4173 REFIID riid,
4174 void ** ppv,
4175 HMODULE * phmodDll);
4176
4177// Provided for backward compatibility and for code that doesn't need the HMODULE of the
4178// DLL that was loaded to create the COM object. See comment at implementation of
4179// code:FakeCoCreateInstanceEx for more details.
4180inline HRESULT FakeCoCreateInstance(REFCLSID rclsid,
4181 REFIID riid,
4182 void ** ppv)
4183{
4184 CONTRACTL
4185 {
4186 NOTHROW;
4187 }
4188 CONTRACTL_END;
4189
4190 return FakeCoCreateInstanceEx(rclsid, NULL, riid, ppv, NULL);
4191};
4192
4193HRESULT FakeCoCallDllGetClassObject(REFCLSID rclsid,
4194 LPCWSTR wszDllPath,
4195 REFIID riid,
4196 void ** ppv,
4197 HMODULE * phmodDll);
4198
4199//*****************************************************************************
4200// Gets the directory based on the location of the module. This routine
4201// is called at COR setup time. Set is called during EEStartup and by the
4202// MetaData dispenser.
4203//*****************************************************************************
4204HRESULT GetInternalSystemDirectory(__out_ecount_part_opt(*pdwLength,*pdwLength) LPWSTR buffer, __inout DWORD* pdwLength);
4205LPCWSTR GetInternalSystemDirectory(__out_opt DWORD * pdwLength = NULL);
4206
4207//*****************************************************************************
4208// This function validates the given Method/Field/Standalone signature. (util.cpp)
4209//*****************************************************************************
4210struct IMDInternalImport;
4211HRESULT validateTokenSig(
4212 mdToken tk, // [IN] Token whose signature needs to be validated.
4213 PCCOR_SIGNATURE pbSig, // [IN] Signature.
4214 ULONG cbSig, // [IN] Size in bytes of the signature.
4215 DWORD dwFlags, // [IN] Method flags.
4216 IMDInternalImport* pImport); // [IN] Internal MD Import interface ptr
4217
4218//*****************************************************************************
4219// Determine the version number of the runtime that was used to build the
4220// specified image. The pMetadata pointer passed in is the pointer to the
4221// metadata contained in the image.
4222//*****************************************************************************
4223HRESULT GetImageRuntimeVersionString(PVOID pMetaData, LPCSTR* pString);
4224
4225//*****************************************************************************
4226// The registry keys and values that contain the information regarding
4227// the default registered unmanaged debugger.
4228//*****************************************************************************
4229SELECTANY const WCHAR kDebugApplicationsPoliciesKey[] = W("SOFTWARE\\Policies\\Microsoft\\Windows\\Windows Error Reporting\\DebugApplications");
4230SELECTANY const WCHAR kDebugApplicationsKey[] = W("SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\DebugApplications");
4231
4232SELECTANY const WCHAR kUnmanagedDebuggerKey[] = W("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug");
4233SELECTANY const WCHAR kUnmanagedDebuggerValue[] = W("Debugger");
4234SELECTANY const WCHAR kUnmanagedDebuggerAutoValue[] = W("Auto");
4235SELECTANY const WCHAR kUnmanagedDebuggerAutoExclusionListKey[] = W("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList");
4236
4237BOOL GetRegistryLongValue(HKEY hKeyParent, // Parent key.
4238 LPCWSTR szKey, // Key name to look at.
4239 LPCWSTR szName, // Name of value to get.
4240 long *pValue, // Put value here, if found.
4241 BOOL fReadNonVirtualizedKey); // Whether to read 64-bit hive on WOW64
4242
4243HRESULT GetCurrentModuleFileName(SString& pBuffer);
4244
4245//*****************************************************************************
4246// Retrieve information regarding what registered default debugger
4247//*****************************************************************************
4248void GetDebuggerSettingInfo(SString &debuggerKeyValue, BOOL *pfAuto);
4249HRESULT GetDebuggerSettingInfoWorker(__out_ecount_part_opt(*pcchDebuggerString, *pcchDebuggerString) LPWSTR wszDebuggerString, DWORD * pcchDebuggerString, BOOL * pfAuto);
4250
4251void TrimWhiteSpace(__inout_ecount(*pcch) LPCWSTR *pwsz, __inout LPDWORD pcch);
4252
4253
4254//*****************************************************************************
4255// Convert a UTF8 string to Unicode, into a CQuickArray<WCHAR>.
4256//*****************************************************************************
4257HRESULT Utf2Quick(
4258 LPCUTF8 pStr, // The string to convert.
4259 CQuickArray<WCHAR> &rStr, // The QuickArray<WCHAR> to convert it into.
4260 int iCurLen); // Inital characters in the array to leave (default 0).
4261
4262//*****************************************************************************
4263// Extract the movl 64-bit unsigned immediate from an IA64 bundle
4264// (Format X2)
4265//*****************************************************************************
4266UINT64 GetIA64Imm64(UINT64 * pBundle);
4267UINT64 GetIA64Imm64(UINT64 qword0, UINT64 qword1);
4268
4269//*****************************************************************************
4270// Deposit the movl 64-bit unsigned immediate into an IA64 bundle
4271// (Format X2)
4272//*****************************************************************************
4273void PutIA64Imm64(UINT64 * pBundle, UINT64 imm64);
4274
4275//*****************************************************************************
4276// Extract the IP-Relative signed 25-bit immediate from an IA64 bundle
4277// (Formats B1, B2 or B3)
4278// Note that due to branch target alignment requirements
4279// the lowest four bits in the result will always be zero.
4280//*****************************************************************************
4281INT32 GetIA64Rel25(UINT64 * pBundle, UINT32 slot);
4282INT32 GetIA64Rel25(UINT64 qword0, UINT64 qword1, UINT32 slot);
4283
4284//*****************************************************************************
4285// Deposit the IP-Relative signed 25-bit immediate into an IA64 bundle
4286// (Formats B1, B2 or B3)
4287// Note that due to branch target alignment requirements
4288// the lowest four bits are required to be zero.
4289//*****************************************************************************
4290void PutIA64Rel25(UINT64 * pBundle, UINT32 slot, INT32 imm25);
4291
4292//*****************************************************************************
4293// Extract the IP-Relative signed 64-bit immediate from an IA64 bundle
4294// (Formats X3 or X4)
4295//*****************************************************************************
4296INT64 GetIA64Rel64(UINT64 * pBundle);
4297INT64 GetIA64Rel64(UINT64 qword0, UINT64 qword1);
4298
4299//*****************************************************************************
4300// Deposit the IP-Relative signed 64-bit immediate into a IA64 bundle
4301// (Formats X3 or X4)
4302//*****************************************************************************
4303void PutIA64Rel64(UINT64 * pBundle, INT64 imm64);
4304
4305//*****************************************************************************
4306// Extract the 32-bit immediate from movw/movt Thumb2 sequence
4307//*****************************************************************************
4308UINT32 GetThumb2Mov32(UINT16 * p);
4309
4310//*****************************************************************************
4311// Deposit the 32-bit immediate into movw/movt Thumb2 sequence
4312//*****************************************************************************
4313void PutThumb2Mov32(UINT16 * p, UINT32 imm32);
4314
4315//*****************************************************************************
4316// Extract the 24-bit rel offset from bl instruction
4317//*****************************************************************************
4318INT32 GetThumb2BlRel24(UINT16 * p);
4319
4320//*****************************************************************************
4321// Extract the 24-bit rel offset from bl instruction
4322//*****************************************************************************
4323void PutThumb2BlRel24(UINT16 * p, INT32 imm24);
4324
4325//*****************************************************************************
4326// Extract the PC-Relative offset from a b or bl instruction
4327//*****************************************************************************
4328INT32 GetArm64Rel28(UINT32 * pCode);
4329
4330//*****************************************************************************
4331// Extract the PC-Relative page address from an adrp instruction
4332//*****************************************************************************
4333INT32 GetArm64Rel21(UINT32 * pCode);
4334
4335//*****************************************************************************
4336// Extract the page offset from an add instruction
4337//*****************************************************************************
4338INT32 GetArm64Rel12(UINT32 * pCode);
4339
4340//*****************************************************************************
4341// Deposit the PC-Relative offset 'imm28' into a b or bl instruction
4342//*****************************************************************************
4343void PutArm64Rel28(UINT32 * pCode, INT32 imm28);
4344
4345//*****************************************************************************
4346// Deposit the PC-Relative page address 'imm21' into an adrp instruction
4347//*****************************************************************************
4348void PutArm64Rel21(UINT32 * pCode, INT32 imm21);
4349
4350//*****************************************************************************
4351// Deposit the page offset 'imm12' into an add instruction
4352//*****************************************************************************
4353void PutArm64Rel12(UINT32 * pCode, INT32 imm12);
4354
4355//*****************************************************************************
4356// Returns whether the offset fits into bl instruction
4357//*****************************************************************************
4358inline bool FitsInThumb2BlRel24(INT32 imm24)
4359{
4360 return ((imm24 << 7) >> 7) == imm24;
4361}
4362
4363//*****************************************************************************
4364// Returns whether the offset fits into an Arm64 b or bl instruction
4365//*****************************************************************************
4366inline bool FitsInRel28(INT32 val32)
4367{
4368 return (val32 >= -0x08000000) && (val32 < 0x08000000);
4369}
4370
4371//*****************************************************************************
4372// Returns whether the offset fits into an Arm64 adrp instruction
4373//*****************************************************************************
4374inline bool FitsInRel21(INT32 val32)
4375{
4376 return (val32 >= 0) && (val32 <= 0x001FFFFF);
4377}
4378
4379//*****************************************************************************
4380// Returns whether the offset fits into an Arm64 add instruction
4381//*****************************************************************************
4382inline bool FitsInRel12(INT32 val32)
4383{
4384 return (val32 >= 0) && (val32 <= 0x00000FFF);
4385}
4386
4387//*****************************************************************************
4388// Returns whether the offset fits into an Arm64 b or bl instruction
4389//*****************************************************************************
4390inline bool FitsInRel28(INT64 val64)
4391{
4392 return (val64 >= -0x08000000LL) && (val64 < 0x08000000LL);
4393}
4394
4395//*****************************************************************************
4396// Splits a command line into argc/argv lists, using the VC7 parsing rules.
4397// This functions interface mimics the CommandLineToArgvW api.
4398// If function fails, returns NULL.
4399// If function suceeds, call delete [] on return pointer when done.
4400//*****************************************************************************
4401LPWSTR *SegmentCommandLine(LPCWSTR lpCmdLine, DWORD *pNumArgs);
4402
4403//
4404// TEB access can be dangerous when using fibers because a fiber may
4405// run on multiple threads. If the TEB pointer is retrieved and saved
4406// and then a fiber is moved to a different thread, when it accesses
4407// the saved TEB pointer, it will be looking at the TEB state for a
4408// different fiber.
4409//
4410// These accessors serve the purpose of retrieving information from the
4411// TEB in a manner that ensures that the current fiber will not switch
4412// threads while the access is occuring.
4413//
4414class ClrTeb
4415{
4416public:
4417#if defined(FEATURE_PAL)
4418
4419 // returns pointer that uniquely identifies the fiber
4420 static void* GetFiberPtrId()
4421 {
4422 LIMITED_METHOD_CONTRACT;
4423 // not fiber for FEATURE_PAL - use the regular thread ID
4424 return (void *)(size_t)GetCurrentThreadId();
4425 }
4426
4427 static void* InvalidFiberPtrId()
4428 {
4429 return NULL;
4430 }
4431
4432 static void* GetStackBase()
4433 {
4434 return PAL_GetStackBase();
4435 }
4436
4437 static void* GetStackLimit()
4438 {
4439 return PAL_GetStackLimit();
4440 }
4441
4442#else // !FEATURE_PAL
4443
4444 // returns pointer that uniquely identifies the fiber
4445 static void* GetFiberPtrId()
4446 {
4447 LIMITED_METHOD_CONTRACT;
4448 // stackbase is the unique fiber identifier
4449 return NtCurrentTeb()->NtTib.StackBase;
4450 }
4451
4452 static void* GetStackBase()
4453 {
4454 LIMITED_METHOD_CONTRACT;
4455 return NtCurrentTeb()->NtTib.StackBase;
4456 }
4457
4458 static void* GetStackLimit()
4459 {
4460 LIMITED_METHOD_CONTRACT;
4461 return NtCurrentTeb()->NtTib.StackLimit;
4462 }
4463
4464 // Please don't start to use this method unless you absolutely have to.
4465 // The reason why this is added is for WIN64 to support LEGACY PE-style TLS
4466 // variables. On X86 it is supported by the JIT compilers themselves. On
4467 // WIN64 we build more logic into the JIT helper for accessing fields.
4468 static void* GetLegacyThreadLocalStoragePointer()
4469 {
4470 LIMITED_METHOD_CONTRACT;
4471 return NtCurrentTeb()->ThreadLocalStoragePointer;
4472 }
4473
4474 static void* GetOleReservedPtr()
4475 {
4476 LIMITED_METHOD_CONTRACT;
4477 return NtCurrentTeb()->ReservedForOle;
4478 }
4479
4480 static void* GetProcessEnvironmentBlock()
4481 {
4482 LIMITED_METHOD_CONTRACT;
4483 return NtCurrentTeb()->ProcessEnvironmentBlock;
4484 }
4485
4486
4487 static void* InvalidFiberPtrId()
4488 {
4489 return (void*) 1;
4490 }
4491#endif // !FEATURE_PAL
4492};
4493
4494#if !defined(DACCESS_COMPILE)
4495
4496// check if current thread is a GC thread (concurrent or server)
4497inline BOOL IsGCSpecialThread ()
4498{
4499 STATIC_CONTRACT_NOTHROW;
4500 STATIC_CONTRACT_GC_NOTRIGGER;
4501 STATIC_CONTRACT_MODE_ANY;
4502 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
4503
4504 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_GC);
4505}
4506
4507// check if current thread is a Gate thread
4508inline BOOL IsGateSpecialThread ()
4509{
4510 STATIC_CONTRACT_NOTHROW;
4511 STATIC_CONTRACT_GC_NOTRIGGER;
4512 STATIC_CONTRACT_MODE_ANY;
4513
4514 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Gate);
4515}
4516
4517// check if current thread is a Timer thread
4518inline BOOL IsTimerSpecialThread ()
4519{
4520 STATIC_CONTRACT_NOTHROW;
4521 STATIC_CONTRACT_GC_NOTRIGGER;
4522 STATIC_CONTRACT_MODE_ANY;
4523
4524 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Timer);
4525}
4526
4527// check if current thread is a debugger helper thread
4528inline BOOL IsDbgHelperSpecialThread ()
4529{
4530 STATIC_CONTRACT_NOTHROW;
4531 STATIC_CONTRACT_GC_NOTRIGGER;
4532 STATIC_CONTRACT_MODE_ANY;
4533
4534 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_DbgHelper);
4535}
4536
4537// check if current thread is a debugger helper thread
4538inline BOOL IsETWRundownSpecialThread ()
4539{
4540 STATIC_CONTRACT_NOTHROW;
4541 STATIC_CONTRACT_GC_NOTRIGGER;
4542 STATIC_CONTRACT_MODE_ANY;
4543
4544 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_ETWRundownThread);
4545}
4546
4547// check if current thread is a generic instantiation lookup compare thread
4548inline BOOL IsGenericInstantiationLookupCompareThread ()
4549{
4550 STATIC_CONTRACT_NOTHROW;
4551 STATIC_CONTRACT_GC_NOTRIGGER;
4552 STATIC_CONTRACT_MODE_ANY;
4553
4554 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_GenericInstantiationCompare);
4555}
4556
4557// check if current thread is a thread which is performing shutdown
4558inline BOOL IsShutdownSpecialThread ()
4559{
4560 STATIC_CONTRACT_NOTHROW;
4561 STATIC_CONTRACT_GC_NOTRIGGER;
4562 STATIC_CONTRACT_MODE_ANY;
4563
4564 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Shutdown);
4565}
4566
4567inline BOOL IsThreadPoolIOCompletionSpecialThread ()
4568{
4569 STATIC_CONTRACT_NOTHROW;
4570 STATIC_CONTRACT_GC_NOTRIGGER;
4571 STATIC_CONTRACT_MODE_ANY;
4572
4573 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Threadpool_IOCompletion);
4574}
4575
4576inline BOOL IsThreadPoolWorkerSpecialThread ()
4577{
4578 STATIC_CONTRACT_NOTHROW;
4579 STATIC_CONTRACT_GC_NOTRIGGER;
4580 STATIC_CONTRACT_MODE_ANY;
4581
4582 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Threadpool_Worker);
4583}
4584
4585inline BOOL IsWaitSpecialThread ()
4586{
4587 STATIC_CONTRACT_NOTHROW;
4588 STATIC_CONTRACT_GC_NOTRIGGER;
4589 STATIC_CONTRACT_MODE_ANY;
4590
4591 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Wait);
4592}
4593
4594// check if current thread is a thread which is performing shutdown
4595inline BOOL IsSuspendEEThread ()
4596{
4597 STATIC_CONTRACT_NOTHROW;
4598 STATIC_CONTRACT_GC_NOTRIGGER;
4599 STATIC_CONTRACT_MODE_ANY;
4600
4601 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_DynamicSuspendEE);
4602}
4603
4604inline BOOL IsFinalizerThread ()
4605{
4606 STATIC_CONTRACT_NOTHROW;
4607 STATIC_CONTRACT_GC_NOTRIGGER;
4608 STATIC_CONTRACT_MODE_ANY;
4609
4610 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_Finalizer);
4611}
4612
4613inline BOOL IsShutdownHelperThread ()
4614{
4615 STATIC_CONTRACT_NOTHROW;
4616 STATIC_CONTRACT_GC_NOTRIGGER;
4617 STATIC_CONTRACT_MODE_ANY;
4618
4619 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_ShutdownHelper);
4620}
4621
4622inline BOOL IsProfilerAttachThread ()
4623{
4624 STATIC_CONTRACT_NOTHROW;
4625 STATIC_CONTRACT_GC_NOTRIGGER;
4626 STATIC_CONTRACT_MODE_ANY;
4627
4628 return !!(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ThreadType_ProfAPI_Attach);
4629}
4630
4631// set specical type for current thread
4632inline void ClrFlsSetThreadType (TlsThreadTypeFlag flag)
4633{
4634 STATIC_CONTRACT_NOTHROW;
4635 STATIC_CONTRACT_GC_NOTRIGGER;
4636 STATIC_CONTRACT_MODE_ANY;
4637 STATIC_CONTRACT_SO_TOLERANT;
4638
4639 ClrFlsSetValue (TlsIdx_ThreadType, (LPVOID)(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) |flag));
4640}
4641
4642// clear specical type for current thread
4643inline void ClrFlsClearThreadType (TlsThreadTypeFlag flag)
4644{
4645 STATIC_CONTRACT_NOTHROW;
4646 STATIC_CONTRACT_GC_NOTRIGGER;
4647 STATIC_CONTRACT_MODE_ANY;
4648
4649 ClrFlsSetValue (TlsIdx_ThreadType, (LPVOID)(((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & ~flag));
4650}
4651
4652#endif //!DACCESS_COMPILE
4653
4654#ifdef DACCESS_COMPILE
4655#define SET_THREAD_TYPE_STACKWALKER(pThread)
4656#define CLEAR_THREAD_TYPE_STACKWALKER()
4657#else // DACCESS_COMPILE
4658#define SET_THREAD_TYPE_STACKWALKER(pThread) ClrFlsSetValue(TlsIdx_StackWalkerWalkingThread, pThread)
4659#define CLEAR_THREAD_TYPE_STACKWALKER() ClrFlsSetValue(TlsIdx_StackWalkerWalkingThread, NULL)
4660#endif // DACCESS_COMPILE
4661
4662HRESULT SetThreadName(HANDLE hThread, PCWSTR lpThreadDescription);
4663
4664inline BOOL IsStackWalkerThread()
4665{
4666 STATIC_CONTRACT_NOTHROW;
4667 STATIC_CONTRACT_GC_NOTRIGGER;
4668 STATIC_CONTRACT_MODE_ANY;
4669 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
4670
4671#if defined(DACCESS_COMPILE)
4672 return FALSE;
4673#else
4674 return ClrFlsGetValue (TlsIdx_StackWalkerWalkingThread) != NULL;
4675#endif
4676}
4677
4678inline BOOL IsGCThread ()
4679{
4680 STATIC_CONTRACT_NOTHROW;
4681 STATIC_CONTRACT_GC_NOTRIGGER;
4682 STATIC_CONTRACT_MODE_ANY;
4683 STATIC_CONTRACT_SUPPORTS_DAC;
4684 STATIC_CONTRACT_SO_TOLERANT;
4685
4686#if !defined(DACCESS_COMPILE)
4687 return IsGCSpecialThread () || IsSuspendEEThread ();
4688#else
4689 return FALSE;
4690#endif
4691}
4692
4693class ClrFlsThreadTypeSwitch
4694{
4695public:
4696 ClrFlsThreadTypeSwitch (TlsThreadTypeFlag flag)
4697 {
4698 STATIC_CONTRACT_NOTHROW;
4699 STATIC_CONTRACT_GC_NOTRIGGER;
4700 STATIC_CONTRACT_MODE_ANY;
4701
4702#ifndef DACCESS_COMPILE
4703 m_flag = flag;
4704 m_fPreviouslySet = (((size_t)ClrFlsGetValue (TlsIdx_ThreadType)) & flag);
4705
4706 // In debug builds, remember the full group of flags that were set at the time
4707 // the constructor was called. This will be used in ASSERTs in the destructor
4708 INDEBUG(m_nPreviousFlagGroup = (size_t)ClrFlsGetValue (TlsIdx_ThreadType));
4709
4710 if (!m_fPreviouslySet)
4711 {
4712 ClrFlsSetThreadType(flag);
4713 }
4714#endif // DACCESS_COMPILE
4715 }
4716
4717 ~ClrFlsThreadTypeSwitch ()
4718 {
4719 STATIC_CONTRACT_NOTHROW;
4720 STATIC_CONTRACT_GC_NOTRIGGER;
4721 STATIC_CONTRACT_MODE_ANY;
4722
4723#ifndef DACCESS_COMPILE
4724 // This holder should only be used to set (and thus restore) ONE thread type flag
4725 // at a time. If more than that one flag was modified since this holder was
4726 // instantiated, then this holder still restores only the flag it knows about. To
4727 // prevent confusion, assert if some other flag was modified, so the user doesn't
4728 // expect the holder to restore the entire original set of flags.
4729 //
4730 // The expression below says that the only difference between the previous flag
4731 // group and the current flag group should be m_flag (or no difference at all, if
4732 // m_flag's state didn't actually change).
4733 _ASSERTE(((m_nPreviousFlagGroup ^ (size_t) ClrFlsGetValue(TlsIdx_ThreadType)) | (size_t) m_flag) == (size_t) m_flag);
4734
4735 if (m_fPreviouslySet)
4736 {
4737 ClrFlsSetThreadType(m_flag);
4738 }
4739 else
4740 {
4741 ClrFlsClearThreadType(m_flag);
4742 }
4743#endif // DACCESS_COMPILE
4744 }
4745
4746private:
4747 TlsThreadTypeFlag m_flag;
4748 BOOL m_fPreviouslySet;
4749 INDEBUG(size_t m_nPreviousFlagGroup);
4750};
4751
4752class ClrFlsValueSwitch
4753{
4754public:
4755 ClrFlsValueSwitch (PredefinedTlsSlots slot, PVOID value)
4756 {
4757 STATIC_CONTRACT_NOTHROW;
4758 STATIC_CONTRACT_GC_NOTRIGGER;
4759 STATIC_CONTRACT_MODE_ANY;
4760
4761#ifndef DACCESS_COMPILE
4762 m_slot = slot;
4763 m_PreviousValue = ClrFlsGetValue(slot);
4764 ClrFlsSetValue(slot, value);
4765#endif // DACCESS_COMPILE
4766 }
4767
4768 ~ClrFlsValueSwitch ()
4769 {
4770 STATIC_CONTRACT_NOTHROW;
4771 STATIC_CONTRACT_GC_NOTRIGGER;
4772 STATIC_CONTRACT_MODE_ANY;
4773
4774#ifndef DACCESS_COMPILE
4775 ClrFlsSetValue(m_slot, m_PreviousValue);
4776#endif // DACCESS_COMPILE
4777 }
4778
4779private:
4780 PVOID m_PreviousValue;
4781 PredefinedTlsSlots m_slot;
4782};
4783
4784//*********************************************************************************
4785
4786// When we're hosted, operations called by the host (such as Thread::YieldTask)
4787// may not cause calls back into the host, as the host needs not be reentrant.
4788// Use the following holder for code in which calls into the host are forbidden.
4789// (If a call into the host is attempted nevertheless, an assert will fire.)
4790
4791class ForbidCallsIntoHostOnThisThread
4792{
4793private:
4794 static Volatile<PVOID> s_pvOwningFiber;
4795
4796 FORCEINLINE static BOOL Enter(BOOL)
4797 {
4798 WRAPPER_NO_CONTRACT;
4799 return InterlockedCompareExchangePointer(
4800 &s_pvOwningFiber, ClrTeb::GetFiberPtrId(), NULL) == NULL;
4801 }
4802
4803 FORCEINLINE static void Leave(BOOL)
4804 {
4805 LIMITED_METHOD_CONTRACT;
4806 s_pvOwningFiber = NULL;
4807 }
4808
4809public:
4810 typedef ConditionalStateHolder<BOOL, ForbidCallsIntoHostOnThisThread::Enter, ForbidCallsIntoHostOnThisThread::Leave> Holder;
4811
4812 FORCEINLINE static BOOL CanThisThreadCallIntoHost()
4813 {
4814 WRAPPER_NO_CONTRACT;
4815 return s_pvOwningFiber != ClrTeb::GetFiberPtrId();
4816 }
4817};
4818
4819typedef ForbidCallsIntoHostOnThisThread::Holder ForbidCallsIntoHostOnThisThreadHolder;
4820
4821FORCEINLINE BOOL CanThisThreadCallIntoHost()
4822{
4823 WRAPPER_NO_CONTRACT;
4824 return ForbidCallsIntoHostOnThisThread::CanThisThreadCallIntoHost();
4825}
4826
4827//*********************************************************************************
4828
4829#include "contract.inl"
4830
4831namespace util
4832{
4833 // compare adapters
4834 //
4835
4836 template < typename T >
4837 struct less
4838 {
4839 bool operator()( T const & first, T const & second ) const
4840 {
4841 return first < second;
4842 }
4843 };
4844
4845 template < typename T >
4846 struct greater
4847 {
4848 bool operator()( T const & first, T const & second ) const
4849 {
4850 return first > second;
4851 }
4852 };
4853
4854
4855 // sort adapters
4856 //
4857
4858 template< typename Iter, typename Pred >
4859 void sort( Iter begin, Iter end, Pred pred );
4860
4861 template< typename T, typename Pred >
4862 void sort( T * begin, T * end, Pred pred )
4863 {
4864 struct sort_helper : CQuickSort< T >
4865 {
4866 sort_helper( T * begin, T * end, Pred pred )
4867 : CQuickSort< T >( begin, end - begin )
4868 , m_pred( pred )
4869 {}
4870
4871 virtual int Compare( T * first, T * second )
4872 {
4873 return m_pred( *first, *second ) ? -1
4874 : ( m_pred( *second, *first ) ? 1 : 0 );
4875 }
4876
4877 Pred m_pred;
4878 };
4879
4880 sort_helper sort_obj( begin, end, pred );
4881 sort_obj.Sort();
4882 }
4883
4884
4885 template < typename Iter >
4886 void sort( Iter begin, Iter end );
4887
4888 template < typename T >
4889 void sort( T * begin, T * end )
4890 {
4891 util::sort( begin, end, util::less< T >() );
4892 }
4893
4894
4895 // binary search adapters
4896 //
4897
4898 template < typename Iter, typename T, typename Pred >
4899 Iter lower_bound( Iter begin, Iter end, T const & val, Pred pred );
4900
4901 template < typename T, typename Pred >
4902 T * lower_bound( T * begin, T * end, T const & val, Pred pred )
4903 {
4904 for (; begin != end; )
4905 {
4906 T * mid = begin + ( end - begin ) / 2;
4907 if ( pred( *mid, val ) )
4908 begin = ++mid;
4909 else
4910 end = mid;
4911 }
4912
4913 return begin;
4914 }
4915
4916
4917 template < typename Iter, typename T >
4918 Iter lower_bound( Iter begin, Iter end, T const & val );
4919
4920 template < typename T >
4921 T * lower_bound( T * begin, T * end, T const & val )
4922 {
4923 return util::lower_bound( begin, end, val, util::less< T >() );
4924 }
4925}
4926
4927
4928/* ------------------------------------------------------------------------ *
4929 * Overloaded operators for the executable heap
4930 * ------------------------------------------------------------------------ */
4931
4932#ifndef FEATURE_PAL
4933
4934struct CExecutable { int x; };
4935extern const CExecutable executable;
4936
4937void * __cdecl operator new(size_t n, const CExecutable&);
4938void * __cdecl operator new[](size_t n, const CExecutable&);
4939void * __cdecl operator new(size_t n, const CExecutable&, const NoThrow&);
4940void * __cdecl operator new[](size_t n, const CExecutable&, const NoThrow&);
4941
4942
4943//
4944// Executable heap delete to match the executable heap new above.
4945//
4946template<class T> void DeleteExecutable(T *p)
4947{
4948 if (p != NULL)
4949 {
4950 p->T::~T();
4951
4952 ClrHeapFree(ClrGetProcessExecutableHeap(), 0, p);
4953 }
4954}
4955
4956#endif // FEATURE_PAL
4957
4958INDEBUG(BOOL DbgIsExecutable(LPVOID lpMem, SIZE_T length);)
4959
4960BOOL NoGuiOnAssert();
4961#ifdef _DEBUG
4962VOID TerminateOnAssert();
4963#endif // _DEBUG
4964
4965class HighCharHelper {
4966public:
4967 static inline BOOL IsHighChar(int c) {
4968 return (BOOL)HighCharTable[c];
4969 }
4970
4971private:
4972 static const BYTE HighCharTable[];
4973};
4974
4975
4976BOOL ThreadWillCreateGuardPage(SIZE_T sizeReservedStack, SIZE_T sizeCommitedStack);
4977
4978FORCEINLINE void HolderSysFreeString(BSTR str) { CONTRACT_VIOLATION(ThrowsViolation); SysFreeString(str); }
4979
4980typedef Wrapper<BSTR, DoNothing, HolderSysFreeString> BSTRHolder;
4981
4982// HMODULE_TGT represents a handle to a module in the target process. In non-DAC builds this is identical
4983// to HMODULE (HINSTANCE), which is the base address of the module. In DAC builds this must be a target address,
4984// and so is represented by TADDR.
4985
4986#ifdef DACCESS_COMPILE
4987typedef TADDR HMODULE_TGT;
4988#else
4989typedef HMODULE HMODULE_TGT;
4990#endif
4991
4992BOOL IsIPInModule(HMODULE_TGT hModule, PCODE ip);
4993
4994//----------------------------------------------------------------------------------------
4995// The runtime invokes InitUtilcode() in its dllmain and passes along all of the critical
4996// callback pointers. For the desktop CLR, all DLLs loaded by the runtime must also call
4997// InitUtilcode with the same callbacks as the runtime used. To achieve this, the runtime
4998// calls a special initialization routine exposed by the loaded module with the callbacks,
4999// which in turn calls InitUtilcode.
5000//
5001// This structure collects all of the critical callback info passed in InitUtilcode().
5002// Note that one of them is GetCLRFunction() which is itself a gofer for many other
5003// callbacks. If a callback fetch be safely deferred until we have TLS and stack probe
5004// functionality running, it should be added to that function rather than this structure.
5005// Things like IEE are here because that callback has to be set up before GetCLRFunction()
5006// can be safely called.
5007//----------------------------------------------------------------------------------------
5008struct CoreClrCallbacks
5009{
5010 typedef IExecutionEngine* (* pfnIEE_t)();
5011 typedef HRESULT (* pfnGetCORSystemDirectory_t)(SString& pbuffer);
5012 typedef void* (* pfnGetCLRFunction_t)(LPCSTR functionName);
5013
5014 HINSTANCE m_hmodCoreCLR;
5015 pfnIEE_t m_pfnIEE;
5016 pfnGetCORSystemDirectory_t m_pfnGetCORSystemDirectory;
5017 pfnGetCLRFunction_t m_pfnGetCLRFunction;
5018};
5019
5020
5021// For DAC, we include this functionality only when EH SxS is enabled.
5022
5023//----------------------------------------------------------------------------------------
5024// CoreCLR must invoke this before CRT initialization to ensure utilcode has all the callback
5025// pointers it needs.
5026//----------------------------------------------------------------------------------------
5027VOID InitUtilcode(const CoreClrCallbacks &cccallbacks);
5028CoreClrCallbacks const & GetClrCallbacks();
5029
5030//----------------------------------------------------------------------------------------
5031// Stuff below is for utilcode.lib eyes only.
5032//----------------------------------------------------------------------------------------
5033
5034// Stores callback pointers provided by InitUtilcode().
5035extern CoreClrCallbacks g_CoreClrCallbacks;
5036
5037// Throws up a helpful dialog if InitUtilcode() wasn't called.
5038#ifdef _DEBUG
5039void OnUninitializedCoreClrCallbacks();
5040#define VALIDATECORECLRCALLBACKS() if (g_CoreClrCallbacks.m_hmodCoreCLR == NULL) OnUninitializedCoreClrCallbacks()
5041#else //_DEBUG
5042#define VALIDATECORECLRCALLBACKS()
5043#endif //_DEBUG
5044
5045
5046#ifdef FEATURE_CORRUPTING_EXCEPTIONS
5047
5048// Corrupting Exception limited support for outside the VM folder
5049BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO = TRUE);
5050
5051#endif // FEATURE_CORRUPTING_EXCEPTIONS
5052
5053namespace UtilCode
5054{
5055 // These are type-safe versions of Interlocked[Compare]Exchange
5056 // They avoid invoking struct cast operations via reinterpreting
5057 // the struct's address as a LONG* or LONGLONG* and dereferencing it.
5058 //
5059 // If we had a global ::operator & (unary), we would love to use that
5060 // to ensure we were not also accidentally getting a structs's provided
5061 // operator &. TODO: probe with a static_assert?
5062
5063 template <typename T, int SIZE = sizeof(T)>
5064 struct InterlockedCompareExchangeHelper;
5065
5066 template <typename T>
5067 struct InterlockedCompareExchangeHelper<T, sizeof(LONG)>
5068 {
5069 static inline T InterlockedExchange(
5070 T volatile * target,
5071 T value)
5072 {
5073 static_assert_no_msg(sizeof(T) == sizeof(LONG));
5074 LONG res = ::InterlockedExchange(
5075 reinterpret_cast<LONG volatile *>(target),
5076 *reinterpret_cast<LONG *>(/*::operator*/&(value)));
5077 return *reinterpret_cast<T*>(&res);
5078 }
5079
5080 static inline T InterlockedCompareExchange(
5081 T volatile * destination,
5082 T exchange,
5083 T comparand)
5084 {
5085 static_assert_no_msg(sizeof(T) == sizeof(LONG));
5086 LONG res = ::InterlockedCompareExchange(
5087 reinterpret_cast<LONG volatile *>(destination),
5088 *reinterpret_cast<LONG*>(/*::operator*/&(exchange)),
5089 *reinterpret_cast<LONG*>(/*::operator*/&(comparand)));
5090 return *reinterpret_cast<T*>(&res);
5091 }
5092 };
5093
5094 template <typename T>
5095 struct InterlockedCompareExchangeHelper<T, sizeof(LONGLONG)>
5096 {
5097 static inline T InterlockedExchange(
5098 T volatile * target,
5099 T value)
5100 {
5101 static_assert_no_msg(sizeof(T) == sizeof(LONGLONG));
5102 LONGLONG res = ::InterlockedExchange64(
5103 reinterpret_cast<LONGLONG volatile *>(target),
5104 *reinterpret_cast<LONGLONG *>(/*::operator*/&(value)));
5105 return *reinterpret_cast<T*>(&res);
5106 }
5107
5108 static inline T InterlockedCompareExchange(
5109 T volatile * destination,
5110 T exchange,
5111 T comparand)
5112 {
5113 static_assert_no_msg(sizeof(T) == sizeof(LONGLONG));
5114 LONGLONG res = ::InterlockedCompareExchange64(
5115 reinterpret_cast<LONGLONG volatile *>(destination),
5116 *reinterpret_cast<LONGLONG*>(/*::operator*/&(exchange)),
5117 *reinterpret_cast<LONGLONG*>(/*::operator*/&(comparand)));
5118 return *reinterpret_cast<T*>(&res);
5119 }
5120 };
5121}
5122
5123template <typename T>
5124inline T InterlockedExchangeT(
5125 T volatile * target,
5126 T value)
5127{
5128 return ::UtilCode::InterlockedCompareExchangeHelper<T>::InterlockedExchange(
5129 target, value);
5130}
5131
5132template <typename T>
5133inline T InterlockedCompareExchangeT(
5134 T volatile * destination,
5135 T exchange,
5136 T comparand)
5137{
5138 return ::UtilCode::InterlockedCompareExchangeHelper<T>::InterlockedCompareExchange(
5139 destination, exchange, comparand);
5140}
5141
5142// Pointer variants for Interlocked[Compare]ExchangePointer
5143// If the underlying type is a const type, we have to remove its constness
5144// since Interlocked[Compare]ExchangePointer doesn't take const void * arguments.
5145template <typename T>
5146inline T* InterlockedExchangeT(
5147 T* volatile * target,
5148 T* value)
5149{
5150 //STATIC_ASSERT(value == 0);
5151 typedef typename std::remove_const<T>::type * non_const_ptr_t;
5152 return reinterpret_cast<T*>(InterlockedExchangePointer(
5153 reinterpret_cast<PVOID volatile *>(const_cast<non_const_ptr_t volatile *>(target)),
5154 reinterpret_cast<PVOID>(const_cast<non_const_ptr_t>(value))));
5155}
5156
5157template <typename T>
5158inline T* InterlockedCompareExchangeT(
5159 T* volatile * destination,
5160 T* exchange,
5161 T* comparand)
5162{
5163 //STATIC_ASSERT(exchange == 0);
5164 typedef typename std::remove_const<T>::type * non_const_ptr_t;
5165 return reinterpret_cast<T*>(InterlockedCompareExchangePointer(
5166 reinterpret_cast<PVOID volatile *>(const_cast<non_const_ptr_t volatile *>(destination)),
5167 reinterpret_cast<PVOID>(const_cast<non_const_ptr_t>(exchange)),
5168 reinterpret_cast<PVOID>(const_cast<non_const_ptr_t>(comparand))));
5169}
5170
5171// NULL pointer variants of the above to avoid having to cast NULL
5172// to the appropriate pointer type.
5173template <typename T>
5174inline T* InterlockedExchangeT(
5175 T* volatile * target,
5176 int value) // When NULL is provided as argument.
5177{
5178 //STATIC_ASSERT(value == 0);
5179 return InterlockedExchangeT(target, reinterpret_cast<T*>(value));
5180}
5181
5182template <typename T>
5183inline T* InterlockedCompareExchangeT(
5184 T* volatile * destination,
5185 int exchange, // When NULL is provided as argument.
5186 T* comparand)
5187{
5188 //STATIC_ASSERT(exchange == 0);
5189 return InterlockedCompareExchangeT(destination, reinterpret_cast<T*>(exchange), comparand);
5190}
5191
5192template <typename T>
5193inline T* InterlockedCompareExchangeT(
5194 T* volatile * destination,
5195 T* exchange,
5196 int comparand) // When NULL is provided as argument.
5197{
5198 //STATIC_ASSERT(comparand == 0);
5199 return InterlockedCompareExchangeT(destination, exchange, reinterpret_cast<T*>(comparand));
5200}
5201
5202// NULL pointer variants of the above to avoid having to cast NULL
5203// to the appropriate pointer type.
5204template <typename T>
5205inline T* InterlockedExchangeT(
5206 T* volatile * target,
5207 std::nullptr_t value) // When nullptr is provided as argument.
5208{
5209 //STATIC_ASSERT(value == 0);
5210 return InterlockedExchangeT(target, static_cast<T*>(value));
5211}
5212
5213template <typename T>
5214inline T* InterlockedCompareExchangeT(
5215 T* volatile * destination,
5216 std::nullptr_t exchange, // When nullptr is provided as argument.
5217 T* comparand)
5218{
5219 //STATIC_ASSERT(exchange == 0);
5220 return InterlockedCompareExchangeT(destination, static_cast<T*>(exchange), comparand);
5221}
5222
5223template <typename T>
5224inline T* InterlockedCompareExchangeT(
5225 T* volatile * destination,
5226 T* exchange,
5227 std::nullptr_t comparand) // When nullptr is provided as argument.
5228{
5229 //STATIC_ASSERT(comparand == 0);
5230 return InterlockedCompareExchangeT(destination, exchange, static_cast<T*>(comparand));
5231}
5232
5233#undef InterlockedExchangePointer
5234#define InterlockedExchangePointer Use_InterlockedExchangeT
5235#undef InterlockedCompareExchangePointer
5236#define InterlockedCompareExchangePointer Use_InterlockedCompareExchangeT
5237
5238// Returns the directory for HMODULE. So, if HMODULE was for "C:\Dir1\Dir2\Filename.DLL",
5239// then this would return "C:\Dir1\Dir2\" (note the trailing backslash).
5240HRESULT GetHModuleDirectory(HMODULE hMod, SString& wszPath);
5241HRESULT CopySystemDirectory(const SString& pPathString, SString& pbuffer);
5242
5243HMODULE LoadLocalizedResourceDLLForSDK(_In_z_ LPCWSTR wzResourceDllName, _In_opt_z_ LPCWSTR modulePath=NULL, bool trySelf=true);
5244// This is a slight variation that can be used for anything else
5245typedef void* (__cdecl *LocalizedFileHandler)(LPCWSTR);
5246void* FindLocalizedFile(_In_z_ LPCWSTR wzResourceDllName, LocalizedFileHandler lfh, _In_opt_z_ LPCWSTR modulePath=NULL);
5247
5248BOOL IsClrHostedLegacyComObject(REFCLSID rclsid);
5249
5250
5251
5252
5253// Helper to support termination due to heap corruption
5254// It's not supported on Win2K, so we have to manually delay load it
5255void EnableTerminationOnHeapCorruption();
5256
5257
5258
5259namespace Clr { namespace Util
5260{
5261 // This api returns a pointer to a null-terminated string that contains the local appdata directory
5262 // or it returns NULL in the case that the directory could not be found. The return value from this function
5263 // is not actually checked for existence.
5264 HRESULT GetLocalAppDataDirectory(LPCWSTR *ppwzLocalAppDataDirectory);
5265 HRESULT SetLocalAppDataDirectory(LPCWSTR pwzLocalAppDataDirectory);
5266
5267namespace Reg
5268{
5269 HRESULT ReadStringValue(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, SString & ssValue);
5270 __success(return == S_OK)
5271 HRESULT ReadStringValue(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, __deref_out __deref_out_z LPWSTR* pwszValue);
5272}
5273
5274#ifdef FEATURE_COMINTEROP
5275namespace Com
5276{
5277 HRESULT FindServerUsingCLSID(REFCLSID rclsid, SString & ssServerName);
5278 HRESULT FindServerUsingCLSID(REFCLSID rclsid, __deref_out __deref_out_z LPWSTR* pwszServerName);
5279 HRESULT FindInprocServer32UsingCLSID(REFCLSID rclsid, SString & ssInprocServer32Name);
5280 HRESULT FindInprocServer32UsingCLSID(REFCLSID rclsid, __deref_out __deref_out_z LPWSTR* pwszInprocServer32Name);
5281 BOOL IsMscoreeInprocServer32(const SString & ssInprocServer32Name);
5282 BOOL CLSIDHasMscoreeAsInprocServer32(REFCLSID rclsid);
5283}
5284#endif // FEATURE_COMINTEROP
5285
5286namespace Win32
5287{
5288 static const WCHAR LONG_FILENAME_PREFIX_W[] = W("\\\\?\\");
5289 static const CHAR LONG_FILENAME_PREFIX_A[] = "\\\\?\\";
5290
5291 void GetModuleFileName(
5292 HMODULE hModule,
5293 SString & ssFileName,
5294 bool fAllowLongFileNames = false);
5295
5296 __success(return == S_OK)
5297 HRESULT GetModuleFileName(
5298 HMODULE hModule,
5299 __deref_out_z LPWSTR * pwszFileName,
5300 bool fAllowLongFileNames = false);
5301
5302 void GetFullPathName(
5303 SString const & ssFileName,
5304 SString & ssPathName,
5305 DWORD * pdwFilePartIdx,
5306 bool fAllowLongFileNames = false);
5307}
5308
5309}}
5310
5311#if defined(FEATURE_APPX) && !defined(DACCESS_COMPILE)
5312 // Forward declaration of AppX::IsAppXProcess
5313 namespace AppX { bool IsAppXProcess(); }
5314
5315 // LOAD_WITH_ALTERED_SEARCH_PATH is unsupported in AppX processes.
5316 inline DWORD GetLoadWithAlteredSearchPathFlag()
5317 {
5318 WRAPPER_NO_CONTRACT;
5319 return AppX::IsAppXProcess() ? 0 : LOAD_WITH_ALTERED_SEARCH_PATH;
5320 }
5321#else // FEATURE_APPX && !DACCESS_COMPILE
5322 // LOAD_WITH_ALTERED_SEARCH_PATH can be used unconditionally.
5323 inline DWORD GetLoadWithAlteredSearchPathFlag()
5324 {
5325 LIMITED_METHOD_CONTRACT;
5326 #ifdef LOAD_WITH_ALTERED_SEARCH_PATH
5327 return LOAD_WITH_ALTERED_SEARCH_PATH;
5328 #else
5329 return 0;
5330 #endif
5331 }
5332#endif // FEATURE_APPX && !DACCESS_COMPILE
5333
5334// clr::SafeAddRef and clr::SafeRelease helpers.
5335namespace clr
5336{
5337 //=================================================================================================================
5338 template <typename ItfT>
5339 static inline
5340 typename std::enable_if< std::is_pointer<ItfT>::value, ItfT >::type
5341 SafeAddRef(ItfT pItf)
5342 {
5343 STATIC_CONTRACT_LIMITED_METHOD;
5344 if (pItf != nullptr)
5345 {
5346 pItf->AddRef();
5347 }
5348 return pItf;
5349 }
5350
5351 //=================================================================================================================
5352 template <typename ItfT>
5353 typename std::enable_if< std::is_pointer<ItfT>::value && std::is_reference<ItfT>::value, ULONG >::type
5354 SafeRelease(ItfT pItf)
5355 {
5356 STATIC_CONTRACT_LIMITED_METHOD;
5357 ULONG res = 0;
5358 if (pItf != nullptr)
5359 {
5360 res = pItf->Release();
5361 pItf = nullptr;
5362 }
5363 return res;
5364 }
5365
5366 //=================================================================================================================
5367 template <typename ItfT>
5368 typename std::enable_if< std::is_pointer<ItfT>::value && !std::is_reference<ItfT>::value, ULONG >::type
5369 SafeRelease(ItfT pItf)
5370 {
5371 STATIC_CONTRACT_LIMITED_METHOD;
5372 ULONG res = 0;
5373 if (pItf != nullptr)
5374 {
5375 res = pItf->Release();
5376 }
5377 return res;
5378 }
5379}
5380
5381// clr::SafeDelete
5382namespace clr
5383{
5384 //=================================================================================================================
5385 template <typename PtrT>
5386 static inline
5387 typename std::enable_if< std::is_pointer<PtrT>::value, PtrT >::type
5388 SafeDelete(PtrT & ptr)
5389 {
5390 STATIC_CONTRACT_LIMITED_METHOD;
5391 if (ptr != nullptr)
5392 {
5393 delete ptr;
5394 ptr = nullptr;
5395 }
5396 }
5397}
5398
5399// ======================================================================================
5400// Spinning support (used by VM and by MetaData via file:..\Utilcode\UTSem.cpp)
5401
5402struct SpinConstants
5403{
5404 DWORD dwInitialDuration;
5405 DWORD dwMaximumDuration;
5406 DWORD dwBackoffFactor;
5407 DWORD dwRepetitions;
5408 DWORD dwMonitorSpinCount;
5409};
5410
5411extern SpinConstants g_SpinConstants;
5412
5413// ======================================================================================
5414
5415void* GetCLRFunction(LPCSTR FunctionName);
5416
5417#endif // __UtilCode_h__
5418