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 | // File: eehash.cpp |
6 | // |
7 | |
8 | // |
9 | |
10 | |
11 | #include "common.h" |
12 | #include "excep.h" |
13 | #include "eehash.h" |
14 | #include "stringliteralmap.h" |
15 | #include "clsload.hpp" |
16 | #include "typectxt.h" |
17 | #include "genericdict.h" |
18 | |
19 | // ============================================================================ |
20 | // UTF8 string hash table helper. |
21 | // ============================================================================ |
22 | EEHashEntry_t * EEUtf8HashTableHelper::AllocateEntry(LPCUTF8 pKey, BOOL bDeepCopy, void *pHeap) |
23 | { |
24 | CONTRACTL |
25 | { |
26 | NOTHROW; |
27 | GC_NOTRIGGER; |
28 | INJECT_FAULT(return NULL;); |
29 | } |
30 | CONTRACTL_END |
31 | |
32 | EEHashEntry_t *pEntry; |
33 | |
34 | if (bDeepCopy) |
35 | { |
36 | DWORD StringLen = (DWORD)strlen(pKey); |
37 | DWORD BufLen = 0; |
38 | // Review conversion of size_t to DWORD. |
39 | #ifdef _MSC_VER |
40 | #pragma warning(push) |
41 | #pragma warning(disable:4267) |
42 | #endif |
43 | if (!ClrSafeInt<DWORD>::addition(StringLen, SIZEOF_EEHASH_ENTRY + sizeof(LPUTF8) + 1, BufLen)) |
44 | #ifdef _MSC_VER |
45 | #pragma warning(pop) |
46 | #endif |
47 | return NULL; |
48 | pEntry = (EEHashEntry_t *) new (nothrow) BYTE[BufLen]; |
49 | if (!pEntry) |
50 | return NULL; |
51 | |
52 | memcpy(pEntry->Key + sizeof(LPUTF8), pKey, StringLen + 1); |
53 | *((LPUTF8*)pEntry->Key) = (LPUTF8)(pEntry->Key + sizeof(LPUTF8)); |
54 | } |
55 | else |
56 | { |
57 | pEntry = (EEHashEntry_t *) new (nothrow)BYTE[SIZEOF_EEHASH_ENTRY + sizeof(LPUTF8)]; |
58 | if (pEntry) |
59 | *((LPCUTF8*)pEntry->Key) = pKey; |
60 | } |
61 | |
62 | return pEntry; |
63 | } |
64 | |
65 | |
66 | void EEUtf8HashTableHelper::DeleteEntry(EEHashEntry_t *pEntry, void *pHeap) |
67 | { |
68 | CONTRACTL |
69 | { |
70 | NOTHROW; |
71 | GC_NOTRIGGER; |
72 | FORBID_FAULT; |
73 | } |
74 | CONTRACTL_END |
75 | |
76 | delete [] (BYTE*)pEntry; |
77 | } |
78 | |
79 | |
80 | BOOL EEUtf8HashTableHelper::CompareKeys(EEHashEntry_t *pEntry, LPCUTF8 pKey) |
81 | { |
82 | LIMITED_METHOD_DAC_CONTRACT; |
83 | |
84 | LPCUTF8 pEntryKey = *((LPCUTF8*)pEntry->Key); |
85 | return (strcmp(pEntryKey, pKey) == 0) ? TRUE : FALSE; |
86 | } |
87 | |
88 | |
89 | DWORD EEUtf8HashTableHelper::Hash(LPCUTF8 pKey) |
90 | { |
91 | LIMITED_METHOD_DAC_CONTRACT; |
92 | |
93 | DWORD dwHash = 0; |
94 | |
95 | while (*pKey != 0) |
96 | { |
97 | dwHash = (dwHash << 5) + (dwHash >> 5) + (*pKey); |
98 | pKey++; |
99 | } |
100 | |
101 | return dwHash; |
102 | } |
103 | |
104 | |
105 | LPCUTF8 EEUtf8HashTableHelper::GetKey(EEHashEntry_t *pEntry) |
106 | { |
107 | LIMITED_METHOD_CONTRACT; |
108 | |
109 | return *((LPCUTF8*)pEntry->Key); |
110 | } |
111 | |
112 | #ifndef DACCESS_COMPILE |
113 | |
114 | // ============================================================================ |
115 | // Unicode string hash table helper. |
116 | // ============================================================================ |
117 | EEHashEntry_t * EEUnicodeHashTableHelper::AllocateEntry(EEStringData *pKey, BOOL bDeepCopy, void *pHeap) |
118 | { |
119 | CONTRACTL |
120 | { |
121 | NOTHROW; |
122 | GC_NOTRIGGER; |
123 | INJECT_FAULT(return NULL;); |
124 | } |
125 | CONTRACTL_END |
126 | |
127 | EEHashEntry_t *pEntry; |
128 | |
129 | if (bDeepCopy) |
130 | { |
131 | pEntry = (EEHashEntry_t *) new (nothrow) BYTE[SIZEOF_EEHASH_ENTRY + sizeof(EEStringData) + ((pKey->GetCharCount() + 1) * sizeof(WCHAR))]; |
132 | if (pEntry) { |
133 | EEStringData *pEntryKey = (EEStringData *)(&pEntry->Key); |
134 | pEntryKey->SetIsOnlyLowChars (pKey->GetIsOnlyLowChars()); |
135 | pEntryKey->SetCharCount (pKey->GetCharCount()); |
136 | pEntryKey->SetStringBuffer ((LPWSTR) ((LPBYTE)pEntry->Key + sizeof(EEStringData))); |
137 | memcpy((LPWSTR)pEntryKey->GetStringBuffer(), pKey->GetStringBuffer(), pKey->GetCharCount() * sizeof(WCHAR)); |
138 | } |
139 | } |
140 | else |
141 | { |
142 | pEntry = (EEHashEntry_t *) new (nothrow) BYTE[SIZEOF_EEHASH_ENTRY + sizeof(EEStringData)]; |
143 | if (pEntry) { |
144 | EEStringData *pEntryKey = (EEStringData *) pEntry->Key; |
145 | pEntryKey->SetIsOnlyLowChars (pKey->GetIsOnlyLowChars()); |
146 | pEntryKey->SetCharCount (pKey->GetCharCount()); |
147 | pEntryKey->SetStringBuffer (pKey->GetStringBuffer()); |
148 | } |
149 | } |
150 | |
151 | return pEntry; |
152 | } |
153 | |
154 | |
155 | void EEUnicodeHashTableHelper::DeleteEntry(EEHashEntry_t *pEntry, void *pHeap) |
156 | { |
157 | LIMITED_METHOD_CONTRACT; |
158 | |
159 | delete [] (BYTE*)pEntry; |
160 | } |
161 | |
162 | |
163 | BOOL EEUnicodeHashTableHelper::CompareKeys(EEHashEntry_t *pEntry, EEStringData *pKey) |
164 | { |
165 | LIMITED_METHOD_CONTRACT; |
166 | |
167 | EEStringData *pEntryKey = (EEStringData*) pEntry->Key; |
168 | |
169 | // Same buffer, same string. |
170 | if (pEntryKey->GetStringBuffer() == pKey->GetStringBuffer()) |
171 | return TRUE; |
172 | |
173 | // Length not the same, never a match. |
174 | if (pEntryKey->GetCharCount() != pKey->GetCharCount()) |
175 | return FALSE; |
176 | |
177 | // Compare the entire thing. |
178 | // We'll deliberately ignore the bOnlyLowChars field since this derived from the characters |
179 | return !memcmp(pEntryKey->GetStringBuffer(), pKey->GetStringBuffer(), pEntryKey->GetCharCount() * sizeof(WCHAR)); |
180 | } |
181 | |
182 | |
183 | DWORD EEUnicodeHashTableHelper::Hash(EEStringData *pKey) |
184 | { |
185 | LIMITED_METHOD_CONTRACT; |
186 | |
187 | return (HashBytes((const BYTE *) pKey->GetStringBuffer(), pKey->GetCharCount()*sizeof(WCHAR))); |
188 | } |
189 | |
190 | |
191 | EEStringData *EEUnicodeHashTableHelper::GetKey(EEHashEntry_t *pEntry) |
192 | { |
193 | LIMITED_METHOD_CONTRACT; |
194 | |
195 | return (EEStringData*)pEntry->Key; |
196 | } |
197 | |
198 | void EEUnicodeHashTableHelper::ReplaceKey(EEHashEntry_t *pEntry, EEStringData *pNewKey) |
199 | { |
200 | LIMITED_METHOD_CONTRACT; |
201 | |
202 | ((EEStringData*)pEntry->Key)->SetStringBuffer (pNewKey->GetStringBuffer()); |
203 | ((EEStringData*)pEntry->Key)->SetCharCount (pNewKey->GetCharCount()); |
204 | ((EEStringData*)pEntry->Key)->SetIsOnlyLowChars (pNewKey->GetIsOnlyLowChars()); |
205 | } |
206 | |
207 | // ============================================================================ |
208 | // Unicode stringliteral hash table helper. |
209 | // ============================================================================ |
210 | EEHashEntry_t * EEUnicodeStringLiteralHashTableHelper::AllocateEntry(EEStringData *pKey, BOOL bDeepCopy, void *pHeap) |
211 | { |
212 | CONTRACTL |
213 | { |
214 | NOTHROW; |
215 | GC_NOTRIGGER; |
216 | INJECT_FAULT(return NULL;); |
217 | } |
218 | CONTRACTL_END |
219 | |
220 | // We assert here because we expect that the heap is not null for EEUnicodeStringLiteralHash table. |
221 | // If someone finds more uses of this kind of hashtable then remove this asserte. |
222 | // Also note that in case of heap being null we go ahead and use new /delete which is EXPENSIVE |
223 | // But for production code this might be ok if the memory is fragmented then thers a better chance |
224 | // of getting smaller allocations than full pages. |
225 | _ASSERTE (pHeap); |
226 | |
227 | if (pHeap) |
228 | return (EEHashEntry_t *) ((MemoryPool*)pHeap)->AllocateElementNoThrow (); |
229 | else |
230 | return (EEHashEntry_t *) new (nothrow) BYTE[SIZEOF_EEHASH_ENTRY]; |
231 | } |
232 | |
233 | |
234 | void EEUnicodeStringLiteralHashTableHelper::DeleteEntry(EEHashEntry_t *pEntry, void *pHeap) |
235 | { |
236 | CONTRACTL |
237 | { |
238 | NOTHROW; |
239 | GC_NOTRIGGER; |
240 | FORBID_FAULT; |
241 | } |
242 | CONTRACTL_END |
243 | |
244 | // We assert here because we expect that the heap is not null for EEUnicodeStringLiteralHash table. |
245 | // If someone finds more uses of this kind of hashtable then remove this asserte. |
246 | // Also note that in case of heap being null we go ahead and use new /delete which is EXPENSIVE |
247 | // But for production code this might be ok if the memory is fragmented then thers a better chance |
248 | // of getting smaller allocations than full pages. |
249 | _ASSERTE (pHeap); |
250 | |
251 | if (pHeap) |
252 | ((MemoryPool*)pHeap)->FreeElement(pEntry); |
253 | else |
254 | delete [] (BYTE*)pEntry; |
255 | } |
256 | |
257 | |
258 | BOOL EEUnicodeStringLiteralHashTableHelper::CompareKeys(EEHashEntry_t *pEntry, EEStringData *pKey) |
259 | { |
260 | CONTRACTL |
261 | { |
262 | NOTHROW; |
263 | GC_NOTRIGGER; |
264 | FORBID_FAULT; |
265 | } |
266 | CONTRACTL_END |
267 | |
268 | GCX_COOP(); |
269 | |
270 | StringLiteralEntry *pHashData = (StringLiteralEntry *)pEntry->Data; |
271 | |
272 | EEStringData pEntryKey; |
273 | pHashData->GetStringData(&pEntryKey); |
274 | |
275 | // Length not the same, never a match. |
276 | if (pEntryKey.GetCharCount() != pKey->GetCharCount()) |
277 | return FALSE; |
278 | |
279 | // Compare the entire thing. |
280 | // We'll deliberately ignore the bOnlyLowChars field since this derived from the characters |
281 | return (!memcmp(pEntryKey.GetStringBuffer(), pKey->GetStringBuffer(), pEntryKey.GetCharCount() * sizeof(WCHAR))); |
282 | } |
283 | |
284 | |
285 | DWORD EEUnicodeStringLiteralHashTableHelper::Hash(EEStringData *pKey) |
286 | { |
287 | LIMITED_METHOD_CONTRACT; |
288 | |
289 | return (HashBytes((const BYTE *) pKey->GetStringBuffer(), pKey->GetCharCount() * sizeof(WCHAR))); |
290 | } |
291 | |
292 | |
293 | // ============================================================================ |
294 | // Instantiation hash table helper. |
295 | // ============================================================================ |
296 | |
297 | EEHashEntry_t *EEInstantiationHashTableHelper::AllocateEntry(const SigTypeContext *pKey, BOOL bDeepCopy, AllocationHeap pHeap) |
298 | { |
299 | CONTRACTL |
300 | { |
301 | NOTHROW; |
302 | GC_NOTRIGGER; |
303 | } |
304 | CONTRACTL_END |
305 | |
306 | EEHashEntry_t *pEntry = (EEHashEntry_t *) new (nothrow) BYTE[SIZEOF_EEHASH_ENTRY + sizeof(SigTypeContext)]; |
307 | if (!pEntry) |
308 | return NULL; |
309 | *((SigTypeContext*)pEntry->Key) = *pKey; |
310 | |
311 | return pEntry; |
312 | } |
313 | |
314 | void EEInstantiationHashTableHelper::DeleteEntry(EEHashEntry_t *pEntry, AllocationHeap pHeap) |
315 | { |
316 | LIMITED_METHOD_CONTRACT; |
317 | |
318 | delete [] (BYTE*)pEntry; |
319 | } |
320 | |
321 | BOOL EEInstantiationHashTableHelper::CompareKeys(EEHashEntry_t *pEntry, const SigTypeContext *pKey) |
322 | { |
323 | LIMITED_METHOD_CONTRACT; |
324 | |
325 | SigTypeContext *pThis = (SigTypeContext*)&pEntry->Key; |
326 | return SigTypeContext::Equal(pThis, pKey); |
327 | } |
328 | |
329 | DWORD EEInstantiationHashTableHelper::Hash(const SigTypeContext *pKey) |
330 | { |
331 | LIMITED_METHOD_CONTRACT; |
332 | |
333 | DWORD dwHash = 5381; |
334 | DWORD i; |
335 | |
336 | for (i = 0; i < pKey->m_classInst.GetNumArgs(); i++) |
337 | dwHash = ((dwHash << 5) + dwHash) ^ (unsigned int)(SIZE_T)pKey->m_classInst[i].AsPtr(); |
338 | |
339 | for (i = 0; i < pKey->m_methodInst.GetNumArgs(); i++) |
340 | dwHash = ((dwHash << 5) + dwHash) ^ (unsigned int)(SIZE_T)pKey->m_methodInst[i].AsPtr(); |
341 | |
342 | return dwHash; |
343 | } |
344 | |
345 | const SigTypeContext *EEInstantiationHashTableHelper::GetKey(EEHashEntry_t *pEntry) |
346 | { |
347 | LIMITED_METHOD_CONTRACT; |
348 | |
349 | return (const SigTypeContext*)&pEntry->Key; |
350 | } |
351 | |
352 | |
353 | |
354 | // ============================================================================ |
355 | // ComComponentInfo hash table helper. |
356 | // ============================================================================ |
357 | |
358 | EEHashEntry_t *EEClassFactoryInfoHashTableHelper::AllocateEntry(ClassFactoryInfo *pKey, BOOL bDeepCopy, void *pHeap) |
359 | { |
360 | CONTRACTL |
361 | { |
362 | NOTHROW; |
363 | GC_NOTRIGGER; |
364 | INJECT_FAULT(return NULL;); |
365 | } |
366 | CONTRACTL_END |
367 | |
368 | EEHashEntry_t *pEntry; |
369 | S_SIZE_T cbStringLen = S_SIZE_T(0); |
370 | |
371 | _ASSERTE(bDeepCopy && "Non deep copy is not supported by the EEComCompInfoHashTableHelper" ); |
372 | |
373 | if (pKey->m_strServerName) |
374 | cbStringLen = (S_SIZE_T(wcslen(pKey->m_strServerName)) + S_SIZE_T(1)) * S_SIZE_T(sizeof(WCHAR)); |
375 | |
376 | S_SIZE_T cbEntry = S_SIZE_T(SIZEOF_EEHASH_ENTRY + sizeof(ClassFactoryInfo)) + cbStringLen; |
377 | |
378 | if (cbEntry.IsOverflow()) |
379 | return NULL; |
380 | |
381 | _ASSERTE(!cbStringLen.IsOverflow()); |
382 | |
383 | pEntry = (EEHashEntry_t *) new (nothrow) BYTE[cbEntry.Value()]; |
384 | if (pEntry) { |
385 | memcpy(pEntry->Key + sizeof(ClassFactoryInfo), pKey->m_strServerName, cbStringLen.Value()); |
386 | ((ClassFactoryInfo*)pEntry->Key)->m_strServerName = pKey->m_strServerName ? (WCHAR*)(pEntry->Key + sizeof(ClassFactoryInfo)) : NULL; |
387 | ((ClassFactoryInfo*)pEntry->Key)->m_clsid = pKey->m_clsid; |
388 | } |
389 | |
390 | return pEntry; |
391 | } |
392 | |
393 | void EEClassFactoryInfoHashTableHelper::DeleteEntry(EEHashEntry_t *pEntry, void *pHeap) |
394 | { |
395 | LIMITED_METHOD_CONTRACT; |
396 | |
397 | delete [] (BYTE*) pEntry; |
398 | } |
399 | |
400 | BOOL EEClassFactoryInfoHashTableHelper::CompareKeys(EEHashEntry_t *pEntry, ClassFactoryInfo *pKey) |
401 | { |
402 | LIMITED_METHOD_CONTRACT; |
403 | |
404 | // First check the GUIDs. |
405 | if (((ClassFactoryInfo*)pEntry->Key)->m_clsid != pKey->m_clsid) |
406 | return FALSE; |
407 | |
408 | // Next do a trivial comparition on the server name pointer values. |
409 | if (((ClassFactoryInfo*)pEntry->Key)->m_strServerName == pKey->m_strServerName) |
410 | return TRUE; |
411 | |
412 | // If the pointers are not equal then if one is NULL then the server names are different. |
413 | if (!((ClassFactoryInfo*)pEntry->Key)->m_strServerName || !pKey->m_strServerName) |
414 | return FALSE; |
415 | |
416 | // Finally do a string comparition of the server names. |
417 | return wcscmp(((ClassFactoryInfo*)pEntry->Key)->m_strServerName, pKey->m_strServerName) == 0; |
418 | } |
419 | |
420 | DWORD EEClassFactoryInfoHashTableHelper::Hash(ClassFactoryInfo *pKey) |
421 | { |
422 | LIMITED_METHOD_CONTRACT; |
423 | |
424 | DWORD dwHash = 0; |
425 | BYTE *pGuidData = (BYTE*)&pKey->m_clsid; |
426 | |
427 | for (unsigned int i = 0; i < sizeof(GUID); i++) |
428 | { |
429 | dwHash = (dwHash << 5) + (dwHash >> 5) + (*pGuidData); |
430 | pGuidData++; |
431 | } |
432 | |
433 | if (pKey->m_strServerName) |
434 | { |
435 | WCHAR *pSrvNameData = pKey->m_strServerName; |
436 | |
437 | while (*pSrvNameData != 0) |
438 | { |
439 | dwHash = (dwHash << 5) + (dwHash >> 5) + (*pSrvNameData); |
440 | pSrvNameData++; |
441 | } |
442 | } |
443 | |
444 | return dwHash; |
445 | } |
446 | |
447 | ClassFactoryInfo *EEClassFactoryInfoHashTableHelper::GetKey(EEHashEntry_t *pEntry) |
448 | { |
449 | LIMITED_METHOD_CONTRACT; |
450 | |
451 | return (ClassFactoryInfo*)pEntry->Key; |
452 | } |
453 | #endif // !DACCESS_COMPILE |
454 | |