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 | // pendingload.h |
6 | // |
7 | |
8 | // |
9 | |
10 | #ifndef _H_PENDINGLOAD |
11 | #define _H_PENDINGLOAD |
12 | |
13 | #include "crst.h" |
14 | #include "class.h" |
15 | #include "typekey.h" |
16 | #include "typehash.h" |
17 | #include "vars.hpp" |
18 | #include "shash.h" |
19 | #include "typestring.h" |
20 | |
21 | // |
22 | // A temporary structure used when loading and resolving classes |
23 | // |
24 | class PendingTypeLoadEntry |
25 | { |
26 | friend class ClassLoader; // workaround really need to beef up the API below |
27 | |
28 | public: |
29 | PendingTypeLoadEntry(TypeKey typeKey, TypeHandle typeHnd) |
30 | : m_Crst( |
31 | CrstPendingTypeLoadEntry, |
32 | CrstFlags(CRST_HOST_BREAKABLE|CRST_UNSAFE_SAMELEVEL) |
33 | ), |
34 | m_typeKey(typeKey) |
35 | |
36 | { |
37 | WRAPPER_NO_CONTRACT; |
38 | |
39 | m_typeHandle = typeHnd; |
40 | m_dwWaitCount = 1; |
41 | m_hrResult = S_OK; |
42 | m_pException = NULL; |
43 | #ifdef _DEBUG |
44 | if (LoggingOn(LF_CLASSLOADER, LL_INFO10000)) |
45 | { |
46 | SString name; |
47 | TypeString::AppendTypeKeyDebug(name, &m_typeKey); |
48 | LOG((LF_CLASSLOADER, LL_INFO10000, "PHASEDLOAD: Creating loading entry for type %S\n" , name.GetUnicode())); |
49 | } |
50 | #endif |
51 | |
52 | m_fLockAcquired = TRUE; |
53 | |
54 | //--------------------------------------------------------------------------- |
55 | // The PendingTypeLoadEntry() lock has a higher level than UnresolvedClassLock. |
56 | // But whenever we create one, we have to acquire it while holding the UnresolvedClassLock. |
57 | // This is safe since we're the ones that created the lock and are guaranteed to acquire |
58 | // it without blocking. But to prevent the crstlevel system from asserting, we |
59 | // must acquire using a special method. |
60 | //--------------------------------------------------------------------------- |
61 | m_Crst.Enter(INDEBUG(Crst::CRST_NO_LEVEL_CHECK)); |
62 | } |
63 | |
64 | ~PendingTypeLoadEntry() |
65 | { |
66 | LIMITED_METHOD_CONTRACT; |
67 | |
68 | if (m_fLockAcquired) |
69 | m_Crst.Leave(); |
70 | |
71 | if (m_pException && !m_pException->IsPreallocatedException()) { |
72 | delete m_pException; |
73 | } |
74 | } |
75 | |
76 | #ifdef _DEBUG |
77 | BOOL HasLock() |
78 | { |
79 | LIMITED_METHOD_CONTRACT; |
80 | return m_Crst.OwnedByCurrentThread(); |
81 | } |
82 | #endif |
83 | |
84 | #ifndef DACCESS_COMPILE |
85 | VOID DECLSPEC_NORETURN ThrowException() |
86 | { |
87 | CONTRACTL |
88 | { |
89 | THROWS; |
90 | GC_TRIGGERS; |
91 | INJECT_FAULT(COMPlusThrowOM();); |
92 | } |
93 | CONTRACTL_END; |
94 | |
95 | if (m_pException) |
96 | PAL_CPP_THROW(Exception *, m_pException->Clone()); |
97 | |
98 | _ASSERTE(FAILED(m_hrResult)); |
99 | |
100 | if (m_hrResult == COR_E_TYPELOAD) |
101 | { |
102 | TypeKey typeKey = GetTypeKey(); |
103 | ClassLoader::ThrowTypeLoadException(&typeKey, |
104 | IDS_CLASSLOAD_GENERAL); |
105 | |
106 | } |
107 | else |
108 | EX_THROW(EEMessageException, (m_hrResult)); |
109 | } |
110 | |
111 | void SetException(Exception *pException) |
112 | { |
113 | CONTRACTL |
114 | { |
115 | NOTHROW; |
116 | PRECONDITION(HasLock()); |
117 | PRECONDITION(m_pException == NULL); |
118 | PRECONDITION(m_dwWaitCount > 0); |
119 | } |
120 | CONTRACTL_END; |
121 | |
122 | m_typeHandle = TypeHandle(); |
123 | m_hrResult = COR_E_TYPELOAD; |
124 | |
125 | // we don't care if this fails |
126 | // we already know the HRESULT so if we can't store |
127 | // the details - so be it |
128 | EX_TRY |
129 | { |
130 | FAULT_NOT_FATAL(); |
131 | m_pException = pException->Clone(); |
132 | } |
133 | EX_CATCH |
134 | { |
135 | m_pException=NULL; |
136 | } |
137 | EX_END_CATCH(SwallowAllExceptions); |
138 | } |
139 | |
140 | void SetResult(TypeHandle typeHnd) |
141 | { |
142 | CONTRACTL |
143 | { |
144 | NOTHROW; |
145 | PRECONDITION(HasLock()); |
146 | PRECONDITION(m_pException == NULL); |
147 | PRECONDITION(m_dwWaitCount > 0); |
148 | } |
149 | CONTRACTL_END; |
150 | |
151 | m_typeHandle = typeHnd; |
152 | } |
153 | |
154 | void UnblockWaiters() |
155 | { |
156 | CONTRACTL |
157 | { |
158 | NOTHROW; |
159 | PRECONDITION(HasLock()); |
160 | PRECONDITION(m_dwWaitCount > 0); |
161 | } |
162 | CONTRACTL_END; |
163 | |
164 | _ASSERTE(m_fLockAcquired); |
165 | m_Crst.Leave(); |
166 | m_fLockAcquired = FALSE; |
167 | } |
168 | #endif //DACCESS_COMPILE |
169 | |
170 | TypeKey GetTypeKey() |
171 | { |
172 | LIMITED_METHOD_CONTRACT; |
173 | return m_typeKey; |
174 | } |
175 | |
176 | void AddRef() |
177 | { |
178 | LIMITED_METHOD_CONTRACT; |
179 | InterlockedIncrement(&m_dwWaitCount); |
180 | } |
181 | |
182 | void Release() |
183 | { |
184 | LIMITED_METHOD_CONTRACT; |
185 | if (InterlockedDecrement(&m_dwWaitCount) == 0) |
186 | delete this; |
187 | } |
188 | |
189 | BOOL HasWaiters() |
190 | { |
191 | LIMITED_METHOD_CONTRACT; |
192 | return m_dwWaitCount > 1; |
193 | } |
194 | |
195 | private: |
196 | Crst m_Crst; |
197 | |
198 | public: |
199 | // Result of loading; this is first created in the CREATE stage of class loading |
200 | TypeHandle m_typeHandle; |
201 | |
202 | private: |
203 | // Type that we're loading |
204 | TypeKey m_typeKey; |
205 | |
206 | // Number of threads waiting for this type |
207 | LONG m_dwWaitCount; |
208 | |
209 | // Error result, propagated to all threads loading this class |
210 | HRESULT m_hrResult; |
211 | |
212 | // Exception object to throw |
213 | Exception *m_pException; |
214 | |
215 | // m_Crst was acquired |
216 | BOOL m_fLockAcquired; |
217 | }; |
218 | |
219 | // Hash table used to hold pending type loads |
220 | // @todo : use shash.h when it supports LoaderHeap/Alloc\MemTracker |
221 | class PendingTypeLoadTable |
222 | { |
223 | protected: |
224 | struct TableEntry |
225 | { |
226 | TableEntry* pNext; |
227 | DWORD dwHashValue; |
228 | PendingTypeLoadEntry* pData; |
229 | }; |
230 | |
231 | TableEntry **m_pBuckets; // Pointer to first entry for each bucket |
232 | DWORD m_dwNumBuckets; |
233 | |
234 | public: |
235 | |
236 | #ifdef _DEBUG |
237 | DWORD m_dwDebugMemory; |
238 | #endif |
239 | |
240 | static PendingTypeLoadTable *Create(LoaderHeap *pHeap, DWORD dwNumBuckets, AllocMemTracker *pamTracker); |
241 | |
242 | private: |
243 | // These functions don't actually exist - declared private to prevent bypassing PendingTypeLoadTable::Create |
244 | void * operator new(size_t size); |
245 | void operator delete(void *p); |
246 | |
247 | PendingTypeLoadTable(); |
248 | ~PendingTypeLoadTable(); |
249 | |
250 | public: |
251 | BOOL InsertValue(PendingTypeLoadEntry* pEntry); |
252 | BOOL DeleteValue(TypeKey *pKey); |
253 | PendingTypeLoadEntry* GetValue(TypeKey *pKey); |
254 | TableEntry* AllocNewEntry(); |
255 | void FreeEntry(TableEntry* pEntry); |
256 | #ifdef _DEBUG |
257 | void Dump(); |
258 | #endif |
259 | |
260 | private: |
261 | TableEntry* FindItem(TypeKey *pKey); |
262 | }; |
263 | |
264 | |
265 | #endif // _H_PENDINGLOAD |
266 | |