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: MethodIter.cpp |
6 | |
7 | // Iterate through jitted instances of a method. |
8 | //***************************************************************************** |
9 | |
10 | |
11 | #include "common.h" |
12 | #include "methoditer.h" |
13 | |
14 | |
15 | //--------------------------------------------------------------------------------------- |
16 | // |
17 | // Iterates next MethodDesc. Updates the holder only if the assembly differs from the previous one. |
18 | // Caller should not release (i.e. change) the holder explicitly between calls, otherwise collectible |
19 | // assembly might be without a reference and get deallocated (even the native part). |
20 | // |
21 | BOOL LoadedMethodDescIterator::Next( |
22 | CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder) |
23 | { |
24 | CONTRACTL |
25 | { |
26 | NOTHROW; |
27 | GC_NOTRIGGER; |
28 | MODE_PREEMPTIVE; |
29 | } |
30 | CONTRACTL_END |
31 | |
32 | if (!m_fFirstTime) |
33 | { |
34 | // This is the 2nd or more time we called Next(). |
35 | |
36 | // If the method + type is not generic, then nothing more to iterate. |
37 | if (!m_mainMD->HasClassOrMethodInstantiation()) |
38 | { |
39 | *pDomainAssemblyHolder = NULL; |
40 | return FALSE; |
41 | } |
42 | goto ADVANCE_METHOD; |
43 | } |
44 | |
45 | m_fFirstTime = FALSE; |
46 | |
47 | // This is the 1st time we've called Next(). must Initialize iterator |
48 | if (m_mainMD == NULL) |
49 | { |
50 | m_mainMD = m_module->LookupMethodDef(m_md); |
51 | } |
52 | |
53 | // note m_mainMD should be sufficiently restored to allow us to get |
54 | // at the method table, flags and token etc. |
55 | if (m_mainMD == NULL) |
56 | { |
57 | *pDomainAssemblyHolder = NULL; |
58 | return FALSE; |
59 | } |
60 | |
61 | // Needs to work w/ non-generic methods too. |
62 | if (!m_mainMD->HasClassOrMethodInstantiation()) |
63 | { |
64 | *pDomainAssemblyHolder = NULL; |
65 | return TRUE; |
66 | } |
67 | |
68 | m_assemIterator = m_pAppDomain->IterateAssembliesEx(m_assemIterationFlags); |
69 | |
70 | ADVANCE_ASSEMBLY: |
71 | if (!m_assemIterator.Next(pDomainAssemblyHolder)) |
72 | { |
73 | _ASSERTE(*pDomainAssemblyHolder == NULL); |
74 | return FALSE; |
75 | } |
76 | |
77 | #ifdef _DEBUG |
78 | dbg_m_pDomainAssembly = *pDomainAssemblyHolder; |
79 | #endif //_DEBUG |
80 | |
81 | m_moduleIterator = (*pDomainAssemblyHolder)->IterateModules(m_moduleIterationFlags); |
82 | |
83 | ADVANCE_MODULE: |
84 | if (!m_moduleIterator.Next()) |
85 | goto ADVANCE_ASSEMBLY; |
86 | |
87 | if (GetCurrentModule()->IsResource()) |
88 | goto ADVANCE_MODULE; |
89 | |
90 | if (m_mainMD->HasClassInstantiation()) |
91 | { |
92 | m_typeIterator.Reset(); |
93 | } |
94 | else |
95 | { |
96 | m_startedNonGenericType = FALSE; |
97 | } |
98 | |
99 | ADVANCE_TYPE: |
100 | if (m_mainMD->HasClassInstantiation()) |
101 | { |
102 | if (!GetCurrentModule()->GetAvailableParamTypes()->FindNext(&m_typeIterator, &m_typeIteratorEntry)) |
103 | goto ADVANCE_MODULE; |
104 | if (CORCOMPILE_IS_POINTER_TAGGED(m_typeIteratorEntry->GetTypeHandle().AsTAddr())) |
105 | goto ADVANCE_TYPE; |
106 | |
107 | //if (m_typeIteratorEntry->data != TypeHandle(m_mainMD->GetMethodTable())) |
108 | // goto ADVANCE_TYPE; |
109 | |
110 | // When looking up the AvailableParamTypes table we have to be really careful since |
111 | // the entries may be unrestored, and may have all sorts of encoded tokens in them. |
112 | // Similar logic occurs in the Lookup function for that table. We will clean this |
113 | // up in Whidbey Beta2. |
114 | TypeHandle th = m_typeIteratorEntry->GetTypeHandle(); |
115 | |
116 | if (th.IsEncodedFixup()) |
117 | goto ADVANCE_TYPE; |
118 | |
119 | if (th.IsTypeDesc()) |
120 | goto ADVANCE_TYPE; |
121 | |
122 | MethodTable *pMT = th.AsMethodTable(); |
123 | |
124 | if (!pMT->IsRestored()) |
125 | goto ADVANCE_TYPE; |
126 | |
127 | // Check the class token |
128 | if (pMT->GetTypeDefRid() != m_mainMD->GetMethodTable()->GetTypeDefRid()) |
129 | goto ADVANCE_TYPE; |
130 | |
131 | // Check the module is correct |
132 | if (pMT->GetModule() != m_module) |
133 | goto ADVANCE_TYPE; |
134 | } |
135 | else if (m_startedNonGenericType) |
136 | { |
137 | goto ADVANCE_MODULE; |
138 | } |
139 | else |
140 | { |
141 | m_startedNonGenericType = TRUE; |
142 | } |
143 | |
144 | if (m_mainMD->HasMethodInstantiation()) |
145 | { |
146 | m_methodIterator.Reset(); |
147 | } |
148 | else |
149 | { |
150 | m_startedNonGenericMethod = FALSE; |
151 | } |
152 | |
153 | ADVANCE_METHOD: |
154 | if (m_mainMD->HasMethodInstantiation()) |
155 | { |
156 | if (!GetCurrentModule()->GetInstMethodHashTable()->FindNext(&m_methodIterator, &m_methodIteratorEntry)) |
157 | goto ADVANCE_TYPE; |
158 | if (CORCOMPILE_IS_POINTER_TAGGED(dac_cast<TADDR>(m_methodIteratorEntry->GetMethod()))) |
159 | goto ADVANCE_METHOD; |
160 | if (!m_methodIteratorEntry->GetMethod()->IsRestored()) |
161 | goto ADVANCE_METHOD; |
162 | if (m_methodIteratorEntry->GetMethod()->GetModule() != m_module) |
163 | goto ADVANCE_METHOD; |
164 | if (m_methodIteratorEntry->GetMethod()->GetMemberDef() != m_md) |
165 | goto ADVANCE_METHOD; |
166 | } |
167 | else if (m_startedNonGenericMethod) |
168 | { |
169 | goto ADVANCE_TYPE; |
170 | } |
171 | else |
172 | { |
173 | m_startedNonGenericMethod = TRUE; |
174 | } |
175 | |
176 | // Note: We don't need to keep the assembly alive in DAC - see code:CollectibleAssemblyHolder#CAH_DAC |
177 | #ifndef DACCESS_COMPILE |
178 | _ASSERTE_MSG( |
179 | *pDomainAssemblyHolder == dbg_m_pDomainAssembly, |
180 | "Caller probably modified the assembly holder, which he shouldn't - see method comment." ); |
181 | #endif //DACCESS_COMPILE |
182 | |
183 | return TRUE; |
184 | } // LoadedMethodDescIterator::Next |
185 | |
186 | |
187 | Module * LoadedMethodDescIterator::GetCurrentModule() |
188 | { |
189 | CONTRACTL |
190 | { |
191 | NOTHROW; |
192 | GC_NOTRIGGER; |
193 | MODE_ANY; |
194 | } |
195 | CONTRACTL_END |
196 | |
197 | return m_moduleIterator.GetLoadedModule(); |
198 | } |
199 | |
200 | MethodDesc *LoadedMethodDescIterator::Current() |
201 | { |
202 | CONTRACTL |
203 | { |
204 | NOTHROW; |
205 | GC_NOTRIGGER; |
206 | PRECONDITION(CheckPointer(m_mainMD)); |
207 | } |
208 | CONTRACTL_END |
209 | |
210 | |
211 | if (m_mainMD->HasMethodInstantiation()) |
212 | { |
213 | _ASSERTE(m_methodIteratorEntry); |
214 | return m_methodIteratorEntry->GetMethod(); |
215 | } |
216 | |
217 | if (!m_mainMD->HasClassInstantiation()) |
218 | { |
219 | // No Method or Class instantiation,then it's not generic. |
220 | return m_mainMD; |
221 | } |
222 | |
223 | MethodTable *pMT = m_typeIteratorEntry->GetTypeHandle().GetMethodTable(); |
224 | PREFIX_ASSUME(pMT != NULL); |
225 | _ASSERTE(pMT); |
226 | |
227 | return pMT->GetMethodDescForSlot(m_mainMD->GetSlot()); |
228 | } |
229 | |
230 | // Initialize the iterator. It will cover generics + prejitted; |
231 | // but it is not EnC aware. |
232 | void |
233 | LoadedMethodDescIterator::Start( |
234 | AppDomain * pAppDomain, |
235 | Module *pModule, |
236 | mdMethodDef md, |
237 | AssemblyIterationFlags assemblyIterationFlags, |
238 | ModuleIterationOption moduleIterationFlags) |
239 | { |
240 | CONTRACTL |
241 | { |
242 | NOTHROW; |
243 | GC_NOTRIGGER; |
244 | PRECONDITION(CheckPointer(pModule)); |
245 | PRECONDITION(CheckPointer(pAppDomain, NULL_OK)); |
246 | } |
247 | CONTRACTL_END; |
248 | |
249 | m_assemIterationFlags = assemblyIterationFlags; |
250 | m_moduleIterationFlags = moduleIterationFlags; |
251 | m_mainMD = NULL; |
252 | m_module = pModule; |
253 | m_md = md; |
254 | m_pAppDomain = pAppDomain; |
255 | m_fFirstTime = TRUE; |
256 | |
257 | _ASSERTE(pAppDomain != NULL); |
258 | _ASSERTE(TypeFromToken(m_md) == mdtMethodDef); |
259 | } |
260 | |
261 | // This is special init for DAC only |
262 | // @TODO:: change it to dac compile only. |
263 | void |
264 | LoadedMethodDescIterator::Start( |
265 | AppDomain *pAppDomain, |
266 | Module *pModule, |
267 | mdMethodDef md, |
268 | MethodDesc *pMethodDesc) |
269 | { |
270 | Start(pAppDomain, pModule, md); |
271 | m_mainMD = pMethodDesc; |
272 | } |
273 | |
274 | LoadedMethodDescIterator::LoadedMethodDescIterator(void) |
275 | { |
276 | LIMITED_METHOD_CONTRACT; |
277 | m_mainMD = NULL; |
278 | m_module = NULL; |
279 | m_md = mdTokenNil; |
280 | m_pAppDomain = NULL; |
281 | } |
282 | |