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 | |
63 | class 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). |
80 | inline 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. |
88 | inline bool Is32BitInstruction(WORD opcode) |
89 | { |
90 | return BitExtract(opcode, 15, 11) >= 0x1d; |
91 | } |
92 | |
93 | template <typename ResultType, typename SourceType> |
94 | inline ResultType DataPointerToThumbCode(SourceType pCode) |
95 | { |
96 | return (ResultType)(((UINT_PTR)pCode) | THUMB_CODE); |
97 | } |
98 | |
99 | template <typename ResultType, typename SourceType> |
100 | inline 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. |
109 | inline 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. |
120 | inline 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 | |
129 | typedef LPCSTR LPCUTF8; |
130 | typedef 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 | |
406 | inline |
407 | LPWSTR 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 | |
425 | inline |
426 | LPWSTR 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 | |
441 | void DECLSPEC_NORETURN ThrowOutOfMemory(); |
442 | |
443 | inline |
444 | LPWSTR 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 | |
460 | inline |
461 | LPWSTR 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 |
490 | inline 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 | |
517 | void * __cdecl |
518 | operator new(size_t n); |
519 | |
520 | _Ret_bytecap_(n) void * __cdecl |
521 | operator new[](size_t n); |
522 | |
523 | void __cdecl |
524 | operator delete(void *p) NOEXCEPT; |
525 | |
526 | void __cdecl |
527 | operator delete[](void *p) NOEXCEPT; |
528 | |
529 | #ifdef _DEBUG_IMPL |
530 | HRESULT _OutOfMemory(LPCSTR szFile, int iLine); |
531 | #define OutOfMemory() _OutOfMemory(__FILE__, __LINE__) |
532 | #else |
533 | inline 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 |
547 | typedef LCID LocaleID; |
548 | typedef LCID LocaleIDValue; |
549 | #else |
550 | typedef LPCWSTR LocaleID; |
551 | typedef 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 |
567 | typedef HRESULT (*FPGETTHREADUICULTURENAMES)(__inout StringArrayList* pCultureNames); |
568 | #ifdef FEATURE_USE_LCID |
569 | // Callback to return the culture ID. |
570 | const LCID UICULTUREID_DONTCARE = (LCID)-1; |
571 | #else |
572 | const LPCWSTR UICULTUREID_DONTCARE = NULL; |
573 | #endif |
574 | |
575 | typedef int (*FPGETTHREADUICULTUREID)(LocaleIDValue*); |
576 | |
577 | HMODULE CLRLoadLibrary(LPCWSTR lpLibFileName); |
578 | |
579 | HMODULE CLRLoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); |
580 | |
581 | BOOL 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. |
589 | STDAPI UtilLoadStringRC(UINT iResouceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax, int bQuiet=FALSE); |
590 | |
591 | #ifdef FEATURE_USE_LCID |
592 | STDAPI 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). |
598 | void SetResourceCultureCallbacks( |
599 | FPGETTHREADUICULTURENAMES fpGetThreadUICultureNames, |
600 | FPGETTHREADUICULTUREID fpGetThreadUICultureId |
601 | ); |
602 | |
603 | void 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. |
611 | extern int GetMUILanguageID(LocaleIDValue* pResult); |
612 | extern 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 | //***************************************************************************** |
620 | class noncopyable |
621 | { |
622 | protected: |
623 | noncopyable() |
624 | {} |
625 | ~noncopyable() |
626 | {} |
627 | |
628 | private: |
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 | //***************************************************************************** |
637 | typedef HINSTANCE HRESOURCEDLL; |
638 | |
639 | |
640 | class CCulturedHInstance |
641 | { |
642 | LocaleIDValue m_LangId; |
643 | HRESOURCEDLL m_hInst; |
644 | BOOL m_fMissing; |
645 | |
646 | public: |
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 |
716 | void 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 | //***************************************************************************** |
723 | class CCompRC |
724 | { |
725 | public: |
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 | |
829 | DWORD |
830 | PALAPI |
831 | static |
832 | FormatMessage( |
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 | |
843 | private: |
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 | |
891 | HRESULT UtilLoadResourceString(CCompRC::ResourceCategory eCategory, UINT iResouceID, __out_ecount (iMax) LPWSTR szBuffer, int iMax); |
892 | |
893 | |
894 | int 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 | |
903 | int 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 | |
912 | int 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 | |
921 | int 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 | |
931 | int 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 | |
942 | int 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 | |
949 | int 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 | |
956 | int 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 | |
963 | int 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> |
974 | inline 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 | |
988 | inline 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 | |
999 | inline 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 |
1027 | inline 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. |
1034 | inline 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. |
1046 | inline 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 |
1083 | void 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 | //******************************************************************************* |
1092 | void 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 | |
1100 | void MakePath(__out CQuickWSTR &path, |
1101 | __in LPCWSTR drive, |
1102 | __in LPCWSTR dir, |
1103 | __in LPCWSTR fname, |
1104 | __in LPCWSTR ext); |
1105 | |
1106 | WCHAR * FullPath(__out_ecount (maxlen) WCHAR *UserBuf, const WCHAR *path, size_t maxlen); |
1107 | |
1108 | //***************************************************************************** |
1109 | // |
1110 | // SString version of the path functions. |
1111 | // |
1112 | //***************************************************************************** |
1113 | void 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 | |
1128 | class REGUTIL |
1129 | { |
1130 | public: |
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 | |
1192 | private: |
1193 | static LPWSTR EnvGetString(LPCWSTR name, BOOL fPrependCOMPLUS); |
1194 | public: |
1195 | |
1196 | static BOOL UseRegistry(); |
1197 | |
1198 | private: |
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); |
1210 | public: |
1211 | |
1212 | |
1213 | //***************************************************************************** |
1214 | // (Optional) Initialize the config registry cache |
1215 | // (see ConfigCacheValueNameSeenPerhaps, below.) |
1216 | //***************************************************************************** |
1217 | static void InitOptionalConfigCache(); |
1218 | |
1219 | private: |
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. |
1255 | class ConfigStringHolder |
1256 | { |
1257 | public: |
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 | |
1290 | private: |
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 | // |
1305 | void 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 | // |
1312 | void 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 | // |
1318 | BOOL 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 | // |
1325 | BYTE * 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 | // |
1333 | BYTE * 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 | // |
1342 | LPVOID 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 | //****************************************************************************** |
1347 | class NumaNodeInfo |
1348 | { |
1349 | private: |
1350 | static BOOL m_enableGCNumaAware; |
1351 | static BOOL InitNumaNodeInfoAPI(); |
1352 | |
1353 | public: |
1354 | static BOOL CanEnableGCNumaAware(); |
1355 | static void InitNumaNodeInfo(); |
1356 | |
1357 | #if !defined(FEATURE_REDHAWK) |
1358 | private: // 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 | |
1371 | public: // functions |
1372 | |
1373 | static LPVOID VirtualAllocExNuma(HANDLE hProc, LPVOID lpAddr, SIZE_T size, |
1374 | DWORD allocType, DWORD prot, DWORD node); |
1375 | |
1376 | private: |
1377 | //GetNumaProcessorNodeEx() |
1378 | typedef BOOL |
1379 | (WINAPI *PGNPNEx)(PPROCESSOR_NUMBER, PUSHORT); |
1380 | static PGNPNEx m_pGetNumaProcessorNodeEx; |
1381 | |
1382 | public: |
1383 | static BOOL GetNumaProcessorNodeEx(PPROCESSOR_NUMBER proc_no, PUSHORT node_no); |
1384 | #endif |
1385 | }; |
1386 | |
1387 | struct 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 | |
1398 | class CPUGroupInfo |
1399 | { |
1400 | private: |
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 | |
1416 | public: |
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) |
1427 | private: |
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 | |
1453 | public: |
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 | |
1464 | public: |
1465 | static bool HadSingleProcessorAtStartup() |
1466 | { |
1467 | LIMITED_METHOD_CONTRACT; |
1468 | return s_hadSingleProcessorAtStartup; |
1469 | } |
1470 | }; |
1471 | |
1472 | int GetCurrentProcessCpuCount(); |
1473 | DWORD_PTR GetCurrentProcessCpuMask(); |
1474 | |
1475 | uint32_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 | //***************************************************************************** |
1482 | inline 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 |
1489 | inline 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 | //***************************************************************************** |
1499 | inline 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 |
1509 | inline 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 | |
1516 | template<typename T> |
1517 | class SimpleListNode |
1518 | { |
1519 | public: |
1520 | SimpleListNode<T>(const T& _t) |
1521 | { |
1522 | data = _t; |
1523 | next = 0; |
1524 | } |
1525 | |
1526 | T data; |
1527 | SimpleListNode<T>* next; |
1528 | }; |
1529 | |
1530 | template<typename T> |
1531 | class SimpleList |
1532 | { |
1533 | public: |
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 | |
1563 | protected: |
1564 | |
1565 | NodeType* head; |
1566 | }; |
1567 | |
1568 | |
1569 | template < typename T, typename U > |
1570 | struct Pair |
1571 | { |
1572 | public: |
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 | |
1628 | private: |
1629 | first_type m_first; |
1630 | second_type m_second; |
1631 | }; |
1632 | |
1633 | |
1634 | template < typename T, typename U > |
1635 | Pair< 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 | |
1650 | template <class T, |
1651 | int iGrowInc, |
1652 | class ALLOCATOR> |
1653 | class CUnorderedArrayWithAllocator |
1654 | { |
1655 | int m_iCount; // # of elements used in the list. |
1656 | int m_iSize; // # of elements allocated in the list. |
1657 | public: |
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 | |
1664 | public: |
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 | |
1811 | private: |
1812 | T *Grow(); |
1813 | T *GrowNoThrow(); |
1814 | }; |
1815 | |
1816 | |
1817 | #ifndef DACCESS_COMPILE |
1818 | |
1819 | //***************************************************************************** |
1820 | // Increase the size of the array. |
1821 | //***************************************************************************** |
1822 | template <class T, |
1823 | int iGrowInc, |
1824 | class ALLOCATOR> |
1825 | T *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 | |
1841 | template <class T, |
1842 | int iGrowInc, |
1843 | class ALLOCATOR> |
1844 | T *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 | |
1862 | template <class T> |
1863 | class CUnorderedArray__Allocator |
1864 | { |
1865 | public: |
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 | |
1884 | template <class T,int iGrowInc> |
1885 | class CUnorderedArray : public CUnorderedArrayWithAllocator<T, iGrowInc, CUnorderedArray__Allocator<T> > |
1886 | { |
1887 | public: |
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 |
1897 | typedef 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 | //***************************************************************************** |
1907 | class 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 | |
1916 | public: |
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 | |
1979 | private: |
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 | //***************************************************************************** |
1988 | template <class T> |
1989 | class CDynArray : public CStructArray |
1990 | { |
1991 | public: |
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. |
2061 | typedef CDynArray<int> INTARRAY; |
2062 | typedef CDynArray<short> SHORTARRAY; |
2063 | typedef CDynArray<int> LONGARRAY; |
2064 | typedef CDynArray<USHORT> USHORTARRAY; |
2065 | typedef CDynArray<ULONG> ULONGARRAY; |
2066 | typedef CDynArray<BYTE> BYTEARRAY; |
2067 | typedef CDynArray<mdToken> TOKENARRAY; |
2068 | |
2069 | template <class T> class CStackArray : public CStructArray |
2070 | { |
2071 | public: |
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 | |
2107 | private: |
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 | //***************************************************************************** |
2117 | template <class T> class TFreeList |
2118 | { |
2119 | public: |
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 | |
2169 | private: |
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 | //***************************************************************************** |
2178 | template <class T> class CQuickSort |
2179 | { |
2180 | protected: |
2181 | T *m_pBase; // Base of array to sort. |
2182 | private: |
2183 | SSIZE_T m_iCount; // How many items in array. |
2184 | SSIZE_T m_iElemSize; // Size of one element. |
2185 | public: |
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 | |
2205 | protected: |
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 | |
2229 | private: |
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 | //***************************************************************************** |
2293 | template <class T> |
2294 | const 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 | //***************************************************************************** |
2328 | template <class T> class CBinarySearch |
2329 | { |
2330 | private: |
2331 | const T *m_pBase; // Base of array to sort. |
2332 | int m_iCount; // How many items in array. |
2333 | |
2334 | public: |
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 | //***************************************************************************** |
2395 | typedef DPTR(struct HASHENTRY) PTR_HASHENTRY; |
2396 | struct HASHENTRY |
2397 | { |
2398 | ULONG iPrev; // Previous bucket in the chain. |
2399 | ULONG iNext; // Next bucket in the chain. |
2400 | }; |
2401 | |
2402 | typedef DPTR(struct FREEHASHENTRY) PTR_FREEHASHENTRY; |
2403 | struct 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 | //***************************************************************************** |
2412 | struct 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 | //***************************************************************************** |
2441 | class CHashTable |
2442 | { |
2443 | friend class DebuggerRCThread; //RCthread actually needs access to |
2444 | //fields of derrived class DebuggerPatchTable |
2445 | |
2446 | protected: |
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 | |
2469 | public: |
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 | |
2615 | protected: |
2616 | virtual BOOL Cmp(SIZE_T key1, const HASHENTRY * pc2) = 0; |
2617 | }; |
2618 | |
2619 | |
2620 | class CNewData |
2621 | { |
2622 | public: |
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 | |
2665 | class CNewDataNoThrow |
2666 | { |
2667 | public: |
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 | //***************************************************************************** |
2721 | template <class MemMgr> |
2722 | class CHashTableAndData : public CHashTable |
2723 | { |
2724 | public: |
2725 | ULONG m_iFree; // Index into m_pcEntries[] of next available slot |
2726 | ULONG m_iEntries; // size of m_pcEntries[] |
2727 | |
2728 | public: |
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 = 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 | |
2853 | private: |
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 | //***************************************************************************** |
2865 | template<class MemMgr> |
2866 | HRESULT 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 | //***************************************************************************** |
2900 | template<class MemMgr> |
2901 | void 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 | //***************************************************************************** |
2921 | template<class MemMgr> |
2922 | int 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 | |
2963 | inline COUNT_T HashCOUNT_T(COUNT_T currentHash, COUNT_T data) |
2964 | { |
2965 | LIMITED_METHOD_DAC_CONTRACT; |
2966 | return ((currentHash << 5) + currentHash) ^ data; |
2967 | } |
2968 | |
2969 | inline 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 | |
2976 | inline 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 | |
3002 | inline 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. |
3017 | inline 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 | |
3031 | inline 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 | |
3045 | inline 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. |
3066 | inline 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. |
3079 | inline 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. |
3092 | inline 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. |
3108 | inline 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 | |
3125 | inline 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 | //***************************************************************************** |
3162 | class 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 | |
3176 | public: |
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 | |
3348 | private: |
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 | |
3406 | private: |
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 | //***************************************************************************** |
3422 | template <class T> class CClosedHash : public CClosedHashBase |
3423 | { |
3424 | public: |
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 | //***************************************************************************** |
3507 | template<class T, class H>class CClosedHashEx : public CClosedHash<T> |
3508 | { |
3509 | public: |
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 | //***************************************************************************** |
3563 | struct HASHLINK |
3564 | { |
3565 | ULONG iNext; // Offset for next entry. |
3566 | }; |
3567 | |
3568 | template <class T> class CChainedHash |
3569 | { |
3570 | friend class VerifyLayoutsMD; |
3571 | public: |
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; |
3755 | private: |
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 | |
3811 | private: |
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 | //***************************************************************************** |
3830 | inline 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 | |
3846 | class 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 | |
3856 | public: |
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 | |
3874 | struct CORINFO_SIG_INFO; |
3875 | |
3876 | class 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 | |
3890 | public: |
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 | |
3917 | class MethodNamesList : public MethodNamesListBase |
3918 | { |
3919 | public: |
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 | |
3948 | class ConfigDWORD |
3949 | { |
3950 | public: |
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 | |
3974 | private: |
3975 | void init_DontUse_(__in __in_z LPCWSTR keyName, DWORD defaultVal=0); |
3976 | void init(const CLRConfig::ConfigDWORDInfo & info); |
3977 | |
3978 | private: |
3979 | DWORD m_value; |
3980 | BYTE m_inited; |
3981 | }; |
3982 | |
3983 | /**************************************************************************/ |
3984 | class ConfigString |
3985 | { |
3986 | public: |
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 | |
4007 | private: |
4008 | void init(const CLRConfig::ConfigStringInfo & info); |
4009 | |
4010 | private: |
4011 | LPWSTR m_value; |
4012 | BYTE m_inited; |
4013 | }; |
4014 | |
4015 | /**************************************************************************/ |
4016 | class ConfigMethodSet |
4017 | { |
4018 | public: |
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 | |
4038 | private: |
4039 | void init(const CLRConfig::ConfigStringInfo & info); |
4040 | |
4041 | private: |
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 | //***************************************************************************** |
4052 | HRESULT 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 | //***************************************************************************** |
4059 | int 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 | //***************************************************************************** |
4067 | BOOL 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 | |
4072 | typedef VPTR(class RangeList) PTR_RangeList; |
4073 | |
4074 | class 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 | |
4171 | HRESULT 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. |
4180 | inline 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 | |
4193 | HRESULT 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 | //***************************************************************************** |
4204 | HRESULT GetInternalSystemDirectory(__out_ecount_part_opt(*pdwLength,*pdwLength) LPWSTR buffer, __inout DWORD* pdwLength); |
4205 | LPCWSTR GetInternalSystemDirectory(__out_opt DWORD * pdwLength = NULL); |
4206 | |
4207 | //***************************************************************************** |
4208 | // This function validates the given Method/Field/Standalone signature. (util.cpp) |
4209 | //***************************************************************************** |
4210 | struct IMDInternalImport; |
4211 | HRESULT 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 | //***************************************************************************** |
4223 | HRESULT 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 | //***************************************************************************** |
4229 | SELECTANY const WCHAR kDebugApplicationsPoliciesKey[] = W("SOFTWARE\\Policies\\Microsoft\\Windows\\Windows Error Reporting\\DebugApplications" ); |
4230 | SELECTANY const WCHAR kDebugApplicationsKey[] = W("SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\DebugApplications" ); |
4231 | |
4232 | SELECTANY const WCHAR kUnmanagedDebuggerKey[] = W("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" ); |
4233 | SELECTANY const WCHAR kUnmanagedDebuggerValue[] = W("Debugger" ); |
4234 | SELECTANY const WCHAR kUnmanagedDebuggerAutoValue[] = W("Auto" ); |
4235 | SELECTANY const WCHAR kUnmanagedDebuggerAutoExclusionListKey[] = W("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList" ); |
4236 | |
4237 | BOOL 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 | |
4243 | HRESULT GetCurrentModuleFileName(SString& pBuffer); |
4244 | |
4245 | //***************************************************************************** |
4246 | // Retrieve information regarding what registered default debugger |
4247 | //***************************************************************************** |
4248 | void GetDebuggerSettingInfo(SString &debuggerKeyValue, BOOL *pfAuto); |
4249 | HRESULT GetDebuggerSettingInfoWorker(__out_ecount_part_opt(*pcchDebuggerString, *pcchDebuggerString) LPWSTR wszDebuggerString, DWORD * pcchDebuggerString, BOOL * pfAuto); |
4250 | |
4251 | void TrimWhiteSpace(__inout_ecount(*pcch) LPCWSTR *pwsz, __inout LPDWORD pcch); |
4252 | |
4253 | |
4254 | //***************************************************************************** |
4255 | // Convert a UTF8 string to Unicode, into a CQuickArray<WCHAR>. |
4256 | //***************************************************************************** |
4257 | HRESULT 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 | //***************************************************************************** |
4266 | UINT64 GetIA64Imm64(UINT64 * pBundle); |
4267 | UINT64 GetIA64Imm64(UINT64 qword0, UINT64 qword1); |
4268 | |
4269 | //***************************************************************************** |
4270 | // Deposit the movl 64-bit unsigned immediate into an IA64 bundle |
4271 | // (Format X2) |
4272 | //***************************************************************************** |
4273 | void 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 | //***************************************************************************** |
4281 | INT32 GetIA64Rel25(UINT64 * pBundle, UINT32 slot); |
4282 | INT32 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 | //***************************************************************************** |
4290 | void 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 | //***************************************************************************** |
4296 | INT64 GetIA64Rel64(UINT64 * pBundle); |
4297 | INT64 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 | //***************************************************************************** |
4303 | void PutIA64Rel64(UINT64 * pBundle, INT64 imm64); |
4304 | |
4305 | //***************************************************************************** |
4306 | // Extract the 32-bit immediate from movw/movt Thumb2 sequence |
4307 | //***************************************************************************** |
4308 | UINT32 GetThumb2Mov32(UINT16 * p); |
4309 | |
4310 | //***************************************************************************** |
4311 | // Deposit the 32-bit immediate into movw/movt Thumb2 sequence |
4312 | //***************************************************************************** |
4313 | void PutThumb2Mov32(UINT16 * p, UINT32 imm32); |
4314 | |
4315 | //***************************************************************************** |
4316 | // Extract the 24-bit rel offset from bl instruction |
4317 | //***************************************************************************** |
4318 | INT32 GetThumb2BlRel24(UINT16 * p); |
4319 | |
4320 | //***************************************************************************** |
4321 | // Extract the 24-bit rel offset from bl instruction |
4322 | //***************************************************************************** |
4323 | void PutThumb2BlRel24(UINT16 * p, INT32 imm24); |
4324 | |
4325 | //***************************************************************************** |
4326 | // Extract the PC-Relative offset from a b or bl instruction |
4327 | //***************************************************************************** |
4328 | INT32 GetArm64Rel28(UINT32 * pCode); |
4329 | |
4330 | //***************************************************************************** |
4331 | // Extract the PC-Relative page address from an adrp instruction |
4332 | //***************************************************************************** |
4333 | INT32 GetArm64Rel21(UINT32 * pCode); |
4334 | |
4335 | //***************************************************************************** |
4336 | // Extract the page offset from an add instruction |
4337 | //***************************************************************************** |
4338 | INT32 GetArm64Rel12(UINT32 * pCode); |
4339 | |
4340 | //***************************************************************************** |
4341 | // Deposit the PC-Relative offset 'imm28' into a b or bl instruction |
4342 | //***************************************************************************** |
4343 | void PutArm64Rel28(UINT32 * pCode, INT32 imm28); |
4344 | |
4345 | //***************************************************************************** |
4346 | // Deposit the PC-Relative page address 'imm21' into an adrp instruction |
4347 | //***************************************************************************** |
4348 | void PutArm64Rel21(UINT32 * pCode, INT32 imm21); |
4349 | |
4350 | //***************************************************************************** |
4351 | // Deposit the page offset 'imm12' into an add instruction |
4352 | //***************************************************************************** |
4353 | void PutArm64Rel12(UINT32 * pCode, INT32 imm12); |
4354 | |
4355 | //***************************************************************************** |
4356 | // Returns whether the offset fits into bl instruction |
4357 | //***************************************************************************** |
4358 | inline 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 | //***************************************************************************** |
4366 | inline 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 | //***************************************************************************** |
4374 | inline 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 | //***************************************************************************** |
4382 | inline 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 | //***************************************************************************** |
4390 | inline 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 | //***************************************************************************** |
4401 | LPWSTR *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 | // |
4414 | class ClrTeb |
4415 | { |
4416 | public: |
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) |
4497 | inline 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 |
4508 | inline 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 |
4518 | inline 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 |
4528 | inline 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 |
4538 | inline 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 |
4548 | inline 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 |
4558 | inline 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 | |
4567 | inline 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 | |
4576 | inline 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 | |
4585 | inline 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 |
4595 | inline 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 | |
4604 | inline 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 | |
4613 | inline 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 | |
4622 | inline 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 |
4632 | inline 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 |
4643 | inline 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 | |
4662 | HRESULT SetThreadName(HANDLE hThread, PCWSTR lpThreadDescription); |
4663 | |
4664 | inline 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 | |
4678 | inline 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 | |
4693 | class ClrFlsThreadTypeSwitch |
4694 | { |
4695 | public: |
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 | |
4746 | private: |
4747 | TlsThreadTypeFlag m_flag; |
4748 | BOOL m_fPreviouslySet; |
4749 | INDEBUG(size_t m_nPreviousFlagGroup); |
4750 | }; |
4751 | |
4752 | class ClrFlsValueSwitch |
4753 | { |
4754 | public: |
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 | |
4779 | private: |
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 | |
4791 | class ForbidCallsIntoHostOnThisThread |
4792 | { |
4793 | private: |
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 | |
4809 | public: |
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 | |
4819 | typedef ForbidCallsIntoHostOnThisThread::Holder ForbidCallsIntoHostOnThisThreadHolder; |
4820 | |
4821 | FORCEINLINE BOOL CanThisThreadCallIntoHost() |
4822 | { |
4823 | WRAPPER_NO_CONTRACT; |
4824 | return ForbidCallsIntoHostOnThisThread::CanThisThreadCallIntoHost(); |
4825 | } |
4826 | |
4827 | //********************************************************************************* |
4828 | |
4829 | #include "contract.inl" |
4830 | |
4831 | namespace 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 | |
4934 | struct CExecutable { int x; }; |
4935 | extern const CExecutable executable; |
4936 | |
4937 | void * __cdecl operator new(size_t n, const CExecutable&); |
4938 | void * __cdecl operator new[](size_t n, const CExecutable&); |
4939 | void * __cdecl operator new(size_t n, const CExecutable&, const NoThrow&); |
4940 | void * __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 | // |
4946 | template<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 | |
4958 | INDEBUG(BOOL DbgIsExecutable(LPVOID lpMem, SIZE_T length);) |
4959 | |
4960 | BOOL NoGuiOnAssert(); |
4961 | #ifdef _DEBUG |
4962 | VOID TerminateOnAssert(); |
4963 | #endif // _DEBUG |
4964 | |
4965 | class HighCharHelper { |
4966 | public: |
4967 | static inline BOOL IsHighChar(int c) { |
4968 | return (BOOL)HighCharTable[c]; |
4969 | } |
4970 | |
4971 | private: |
4972 | static const BYTE HighCharTable[]; |
4973 | }; |
4974 | |
4975 | |
4976 | BOOL ThreadWillCreateGuardPage(SIZE_T sizeReservedStack, SIZE_T sizeCommitedStack); |
4977 | |
4978 | FORCEINLINE void HolderSysFreeString(BSTR str) { CONTRACT_VIOLATION(ThrowsViolation); SysFreeString(str); } |
4979 | |
4980 | typedef 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 |
4987 | typedef TADDR HMODULE_TGT; |
4988 | #else |
4989 | typedef HMODULE HMODULE_TGT; |
4990 | #endif |
4991 | |
4992 | BOOL 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 | //---------------------------------------------------------------------------------------- |
5008 | struct 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 | //---------------------------------------------------------------------------------------- |
5027 | VOID InitUtilcode(const CoreClrCallbacks &cccallbacks); |
5028 | CoreClrCallbacks const & GetClrCallbacks(); |
5029 | |
5030 | //---------------------------------------------------------------------------------------- |
5031 | // Stuff below is for utilcode.lib eyes only. |
5032 | //---------------------------------------------------------------------------------------- |
5033 | |
5034 | // Stores callback pointers provided by InitUtilcode(). |
5035 | extern CoreClrCallbacks g_CoreClrCallbacks; |
5036 | |
5037 | // Throws up a helpful dialog if InitUtilcode() wasn't called. |
5038 | #ifdef _DEBUG |
5039 | void 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 |
5049 | BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO = TRUE); |
5050 | |
5051 | #endif // FEATURE_CORRUPTING_EXCEPTIONS |
5052 | |
5053 | namespace 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 | |
5123 | template <typename T> |
5124 | inline T InterlockedExchangeT( |
5125 | T volatile * target, |
5126 | T value) |
5127 | { |
5128 | return ::UtilCode::InterlockedCompareExchangeHelper<T>::InterlockedExchange( |
5129 | target, value); |
5130 | } |
5131 | |
5132 | template <typename T> |
5133 | inline 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. |
5145 | template <typename T> |
5146 | inline 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 | |
5157 | template <typename T> |
5158 | inline 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. |
5173 | template <typename T> |
5174 | inline 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 | |
5182 | template <typename T> |
5183 | inline 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 | |
5192 | template <typename T> |
5193 | inline 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. |
5204 | template <typename T> |
5205 | inline 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 | |
5213 | template <typename T> |
5214 | inline 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 | |
5223 | template <typename T> |
5224 | inline 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). |
5240 | HRESULT GetHModuleDirectory(HMODULE hMod, SString& wszPath); |
5241 | HRESULT CopySystemDirectory(const SString& pPathString, SString& pbuffer); |
5242 | |
5243 | HMODULE 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 |
5245 | typedef void* (__cdecl *LocalizedFileHandler)(LPCWSTR); |
5246 | void* FindLocalizedFile(_In_z_ LPCWSTR wzResourceDllName, LocalizedFileHandler lfh, _In_opt_z_ LPCWSTR modulePath=NULL); |
5247 | |
5248 | BOOL 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 |
5255 | void EnableTerminationOnHeapCorruption(); |
5256 | |
5257 | |
5258 | |
5259 | namespace 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 | |
5267 | namespace 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 |
5275 | namespace 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 | |
5286 | namespace 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. |
5335 | namespace 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 |
5382 | namespace 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 | |
5402 | struct SpinConstants |
5403 | { |
5404 | DWORD dwInitialDuration; |
5405 | DWORD dwMaximumDuration; |
5406 | DWORD dwBackoffFactor; |
5407 | DWORD dwRepetitions; |
5408 | DWORD dwMonitorSpinCount; |
5409 | }; |
5410 | |
5411 | extern SpinConstants g_SpinConstants; |
5412 | |
5413 | // ====================================================================================== |
5414 | |
5415 | void* GetCLRFunction(LPCSTR FunctionName); |
5416 | |
5417 | #endif // __UtilCode_h__ |
5418 | |