| 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 |  |