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//
21BOOL 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
70ADVANCE_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
83ADVANCE_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
99ADVANCE_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
153ADVANCE_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
187Module * 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
200MethodDesc *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.
232void
233LoadedMethodDescIterator::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.
263void
264LoadedMethodDescIterator::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
274LoadedMethodDescIterator::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