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//
24class PendingTypeLoadEntry
25{
26 friend class ClassLoader; // workaround really need to beef up the API below
27
28public:
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
221class PendingTypeLoadTable
222{
223protected:
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
234public:
235
236#ifdef _DEBUG
237 DWORD m_dwDebugMemory;
238#endif
239
240 static PendingTypeLoadTable *Create(LoaderHeap *pHeap, DWORD dwNumBuckets, AllocMemTracker *pamTracker);
241
242private:
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
250public:
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
260private:
261 TableEntry* FindItem(TypeKey *pKey);
262};
263
264
265#endif // _H_PENDINGLOAD
266