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: pendingload.cpp
6//
7
8//
9
10#include "common.h"
11#include "excep.h"
12#include "pendingload.h"
13
14#ifndef DACCESS_COMPILE
15
16
17// ============================================================================
18// Pending type load hash table methods
19// ============================================================================
20/*static */ PendingTypeLoadTable* PendingTypeLoadTable::Create(LoaderHeap *pHeap,
21 DWORD dwNumBuckets,
22 AllocMemTracker *pamTracker)
23{
24 CONTRACTL
25 {
26 STANDARD_VM_CHECK;
27 PRECONDITION(CheckPointer(pHeap));
28 }
29 CONTRACTL_END;
30
31 size_t size = sizeof(PendingTypeLoadTable);
32 BYTE * pMem;
33 PendingTypeLoadTable * pThis;
34
35 _ASSERT( dwNumBuckets >= 0 );
36 S_SIZE_T allocSize = S_SIZE_T( dwNumBuckets )
37 * S_SIZE_T( sizeof(PendingTypeLoadTable::TableEntry*) )
38 + S_SIZE_T( size );
39 if( allocSize.IsOverflow() )
40 {
41 ThrowHR(E_INVALIDARG);
42 }
43 pMem = (BYTE *) pamTracker->Track(pHeap->AllocMem( allocSize ));
44
45 pThis = (PendingTypeLoadTable *) pMem;
46
47#ifdef _DEBUG
48 pThis->m_dwDebugMemory = (DWORD)(size + dwNumBuckets*sizeof(PendingTypeLoadTable::TableEntry*));
49#endif
50
51 pThis->m_dwNumBuckets = dwNumBuckets;
52 pThis->m_pBuckets = (PendingTypeLoadTable::TableEntry**) (pMem + size);
53
54 // Don't need to memset() since this was ClrVirtualAlloc()'d memory
55 // memset(pThis->m_pBuckets, 0, dwNumBuckets*sizeof(PendingTypeLoadTable::TableEntry*));
56
57 return pThis;
58}
59
60
61
62PendingTypeLoadTable::TableEntry *PendingTypeLoadTable::AllocNewEntry()
63{
64 CONTRACTL
65 {
66 NOTHROW;
67 GC_NOTRIGGER;
68 MODE_ANY;
69 INJECT_FAULT( return NULL; );
70 }
71 CONTRACTL_END
72
73#ifdef _DEBUG
74 m_dwDebugMemory += (DWORD) (sizeof(PendingTypeLoadTable::TableEntry));
75#endif
76
77 return (PendingTypeLoadTable::TableEntry *) new (nothrow) BYTE[sizeof(PendingTypeLoadTable::TableEntry)];
78}
79
80
81void PendingTypeLoadTable::FreeEntry(PendingTypeLoadTable::TableEntry * pEntry)
82{
83 CONTRACTL
84 {
85 NOTHROW;
86 GC_NOTRIGGER;
87 MODE_ANY;
88 }
89 CONTRACTL_END
90
91 // keep in sync with the allocator used in AllocNewEntry
92 delete[] ((BYTE*)pEntry);
93
94#ifdef _DEBUG
95 m_dwDebugMemory -= (DWORD) (sizeof(PendingTypeLoadTable::TableEntry));
96#endif
97}
98
99
100//
101// Does not handle duplicates!
102//
103BOOL PendingTypeLoadTable::InsertValue(PendingTypeLoadEntry *pData)
104{
105 CONTRACTL
106 {
107 NOTHROW;
108 GC_NOTRIGGER;
109 MODE_ANY;
110 INJECT_FAULT( return FALSE; );
111 PRECONDITION(CheckPointer(pData));
112 PRECONDITION(FindItem(&pData->GetTypeKey()) == NULL);
113 }
114 CONTRACTL_END
115
116 _ASSERTE(m_dwNumBuckets != 0);
117
118 DWORD dwHash = pData->GetTypeKey().ComputeHash();
119 DWORD dwBucket = dwHash % m_dwNumBuckets;
120 PendingTypeLoadTable::TableEntry * pNewEntry = AllocNewEntry();
121 if (pNewEntry == NULL)
122 return FALSE;
123
124 // Insert at head of bucket
125 pNewEntry->pNext = m_pBuckets[dwBucket];
126 pNewEntry->pData = pData;
127 pNewEntry->dwHashValue = dwHash;
128
129 m_pBuckets[dwBucket] = pNewEntry;
130
131 return TRUE;
132}
133
134
135BOOL PendingTypeLoadTable::DeleteValue(TypeKey *pKey)
136{
137 CONTRACTL
138 {
139 NOTHROW;
140 GC_NOTRIGGER;
141 MODE_ANY;
142 FORBID_FAULT;
143 PRECONDITION(CheckPointer(pKey));
144 }
145 CONTRACTL_END
146
147 _ASSERTE(m_dwNumBuckets != 0);
148
149 DWORD dwHash = pKey->ComputeHash();
150 DWORD dwBucket = dwHash % m_dwNumBuckets;
151 PendingTypeLoadTable::TableEntry * pSearch;
152 PendingTypeLoadTable::TableEntry **ppPrev = &m_pBuckets[dwBucket];
153
154 for (pSearch = m_pBuckets[dwBucket]; pSearch; pSearch = pSearch->pNext)
155 {
156 TypeKey entryTypeKey = pSearch->pData->GetTypeKey();
157 if (pSearch->dwHashValue == dwHash && TypeKey::Equals(pKey, &entryTypeKey))
158 {
159 *ppPrev = pSearch->pNext;
160 FreeEntry(pSearch);
161 return TRUE;
162 }
163
164 ppPrev = &pSearch->pNext;
165 }
166
167 return FALSE;
168}
169
170
171PendingTypeLoadTable::TableEntry *PendingTypeLoadTable::FindItem(TypeKey *pKey)
172{
173 CONTRACTL
174 {
175 NOTHROW;
176 GC_NOTRIGGER;
177 MODE_ANY;
178 FORBID_FAULT;
179 PRECONDITION(CheckPointer(pKey));
180 }
181 CONTRACTL_END
182
183 _ASSERTE(m_dwNumBuckets != 0);
184
185
186 DWORD dwHash = pKey->ComputeHash();
187 DWORD dwBucket = dwHash % m_dwNumBuckets;
188 PendingTypeLoadTable::TableEntry * pSearch;
189
190 for (pSearch = m_pBuckets[dwBucket]; pSearch; pSearch = pSearch->pNext)
191 {
192 TypeKey entryTypeKey = pSearch->pData->GetTypeKey();
193 if (pSearch->dwHashValue == dwHash && TypeKey::Equals(pKey, &entryTypeKey))
194 {
195 return pSearch;
196 }
197 }
198
199 return NULL;
200}
201
202
203#ifdef _DEBUG
204void PendingTypeLoadTable::Dump()
205{
206 CONTRACTL
207 {
208 THROWS;
209 GC_TRIGGERS;
210 MODE_ANY;
211 }
212 CONTRACTL_END
213
214 LOG((LF_CLASSLOADER, LL_INFO10000, "PHASEDLOAD: table contains:\n"));
215 for (DWORD i = 0; i < m_dwNumBuckets; i++)
216 {
217 for (TableEntry *pSearch = m_pBuckets[i]; pSearch; pSearch = pSearch->pNext)
218 {
219 SString name;
220 TypeKey entryTypeKey = pSearch->pData->GetTypeKey();
221 TypeString::AppendTypeKeyDebug(name, &entryTypeKey);
222 LOG((LF_CLASSLOADER, LL_INFO10000, " Entry %S with handle %p at level %s\n", name.GetUnicode(), pSearch->pData->m_typeHandle.AsPtr(),
223 pSearch->pData->m_typeHandle.IsNull() ? "not-applicable" : classLoadLevelName[pSearch->pData->m_typeHandle.GetLoadLevel()]));
224 }
225 }
226}
227#endif
228
229PendingTypeLoadEntry* PendingTypeLoadTable::GetValue(TypeKey *pKey)
230{
231 CONTRACTL
232 {
233 NOTHROW;
234 GC_NOTRIGGER;
235 MODE_ANY;
236 FORBID_FAULT;
237 PRECONDITION(CheckPointer(pKey));
238 }
239 CONTRACTL_END
240
241 PendingTypeLoadTable::TableEntry *pItem = FindItem(pKey);
242
243 if (pItem != NULL)
244 {
245 return pItem->pData;
246 }
247 else
248 {
249 return NULL;
250 }
251}
252
253#endif // #ifndef DACCESS_COMPILE
254
255