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