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// ============================================================================
22EEHashEntry_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
66void 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
80BOOL 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
89DWORD 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
105LPCUTF8 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// ============================================================================
117EEHashEntry_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
155void EEUnicodeHashTableHelper::DeleteEntry(EEHashEntry_t *pEntry, void *pHeap)
156{
157 LIMITED_METHOD_CONTRACT;
158
159 delete [] (BYTE*)pEntry;
160}
161
162
163BOOL 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
183DWORD EEUnicodeHashTableHelper::Hash(EEStringData *pKey)
184{
185 LIMITED_METHOD_CONTRACT;
186
187 return (HashBytes((const BYTE *) pKey->GetStringBuffer(), pKey->GetCharCount()*sizeof(WCHAR)));
188}
189
190
191EEStringData *EEUnicodeHashTableHelper::GetKey(EEHashEntry_t *pEntry)
192{
193 LIMITED_METHOD_CONTRACT;
194
195 return (EEStringData*)pEntry->Key;
196}
197
198void 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// ============================================================================
210EEHashEntry_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
234void 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
258BOOL 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
285DWORD 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
297EEHashEntry_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
314void EEInstantiationHashTableHelper::DeleteEntry(EEHashEntry_t *pEntry, AllocationHeap pHeap)
315{
316 LIMITED_METHOD_CONTRACT;
317
318 delete [] (BYTE*)pEntry;
319}
320
321BOOL 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
329DWORD 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
345const 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
358EEHashEntry_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
393void EEClassFactoryInfoHashTableHelper::DeleteEntry(EEHashEntry_t *pEntry, void *pHeap)
394{
395 LIMITED_METHOD_CONTRACT;
396
397 delete [] (BYTE*) pEntry;
398}
399
400BOOL 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
420DWORD 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
447ClassFactoryInfo *EEClassFactoryInfoHashTableHelper::GetKey(EEHashEntry_t *pEntry)
448{
449 LIMITED_METHOD_CONTRACT;
450
451 return (ClassFactoryInfo*)pEntry->Key;
452}
453#endif // !DACCESS_COMPILE
454