diff options
Diffstat (limited to 'src/vm/methoditer.cpp')
-rw-r--r-- | src/vm/methoditer.cpp | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/src/vm/methoditer.cpp b/src/vm/methoditer.cpp new file mode 100644 index 0000000000..103bfafe06 --- /dev/null +++ b/src/vm/methoditer.cpp @@ -0,0 +1,370 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// File: MethodIter.cpp + +// Iterate through jitted instances of a method. +//***************************************************************************** + + +#include "common.h" +#include "methoditer.h" + + +//--------------------------------------------------------------------------------------- +// +// Iterates next MethodDesc. Updates the holder only if the assembly differs from the previous one. +// Caller should not release (i.e. change) the holder explicitly between calls, otherwise collectible +// assembly might be without a reference and get deallocated (even the native part). +// +BOOL LoadedMethodDescIterator::Next( + CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } + CONTRACTL_END + + if (!m_fFirstTime) + { + // This is the 2nd or more time we called Next(). + + // If the method + type is not generic, then nothing more to iterate. + if (!m_mainMD->HasClassOrMethodInstantiation()) + { + *pDomainAssemblyHolder = NULL; + return FALSE; + } + goto ADVANCE_METHOD; + } + + m_fFirstTime = FALSE; + + // This is the 1st time we've called Next(). must Initialize iterator + if (m_mainMD == NULL) + { + m_mainMD = m_module->LookupMethodDef(m_md); + } + + // note m_mainMD should be sufficiently restored to allow us to get + // at the method table, flags and token etc. + if (m_mainMD == NULL) + { + *pDomainAssemblyHolder = NULL; + return FALSE; + } + + // Needs to work w/ non-generic methods too. + // NOTE: this behavior seems odd. We appear to return the non-generic method even if + // that method doesn't reside in the set of assemblies defined by m_assemblyIterationMode. + // Presumably all the callers expect or at least cope with this so I'm just commenting without + // changing anything right now. + if (!m_mainMD->HasClassOrMethodInstantiation()) + { + *pDomainAssemblyHolder = NULL; + return TRUE; + } + + if (m_assemblyIterationMode == kModeSharedDomainAssemblies) + { + // Nothing to do... m_sharedAssemblyIterator is initialized on construction + } + else + { + m_assemIterator = m_pAppDomain->IterateAssembliesEx(m_assemIterationFlags); + } + +ADVANCE_ASSEMBLY: + if (m_assemblyIterationMode == kModeSharedDomainAssemblies) + { + if (!m_sharedAssemblyIterator.Next()) + return FALSE; + + m_sharedModuleIterator = m_sharedAssemblyIterator.GetAssembly()->IterateModules(); + } + else + { + if (!m_assemIterator.Next(pDomainAssemblyHolder)) + { + _ASSERTE(*pDomainAssemblyHolder == NULL); + return FALSE; + } + + if (m_assemblyIterationMode == kModeUnsharedADAssemblies) + { + // We're supposed to ignore shared assemblies, so check for them now + if ((*pDomainAssemblyHolder)->GetAssembly()->IsDomainNeutral()) + { + goto ADVANCE_ASSEMBLY; + } + } + +#ifdef _DEBUG + dbg_m_pDomainAssembly = *pDomainAssemblyHolder; +#endif //_DEBUG + + m_moduleIterator = (*pDomainAssemblyHolder)->IterateModules(m_moduleIterationFlags); + } + + +ADVANCE_MODULE: + if (m_assemblyIterationMode == kModeSharedDomainAssemblies) + { + if (!NextSharedModule()) + goto ADVANCE_ASSEMBLY; + } + else + { + if (!m_moduleIterator.Next()) + goto ADVANCE_ASSEMBLY; + } + + if (GetCurrentModule()->IsResource()) + goto ADVANCE_MODULE; + + if (m_mainMD->HasClassInstantiation()) + { + m_typeIterator.Reset(); + } + else + { + m_startedNonGenericType = FALSE; + } + +ADVANCE_TYPE: + if (m_mainMD->HasClassInstantiation()) + { + if (!GetCurrentModule()->GetAvailableParamTypes()->FindNext(&m_typeIterator, &m_typeIteratorEntry)) + goto ADVANCE_MODULE; + if (CORCOMPILE_IS_POINTER_TAGGED(m_typeIteratorEntry->GetTypeHandle().AsTAddr())) + goto ADVANCE_TYPE; + + //if (m_typeIteratorEntry->data != TypeHandle(m_mainMD->GetMethodTable())) + // goto ADVANCE_TYPE; + + // When looking up the AvailableParamTypes table we have to be really careful since + // the entries may be unrestored, and may have all sorts of encoded tokens in them. + // Similar logic occurs in the Lookup function for that table. We will clean this + // up in Whidbey Beta2. + TypeHandle th = m_typeIteratorEntry->GetTypeHandle(); + + if (th.IsEncodedFixup()) + goto ADVANCE_TYPE; + + if (th.IsTypeDesc()) + goto ADVANCE_TYPE; + + MethodTable *pMT = th.AsMethodTable(); + + if (!pMT->IsRestored()) + goto ADVANCE_TYPE; + + // Check the class token + if (pMT->GetTypeDefRid() != m_mainMD->GetMethodTable()->GetTypeDefRid()) + goto ADVANCE_TYPE; + + // Check the module is correct + if (pMT->GetModule() != m_module) + goto ADVANCE_TYPE; + } + else if (m_startedNonGenericType) + { + goto ADVANCE_MODULE; + } + else + { + m_startedNonGenericType = TRUE; + } + + if (m_mainMD->HasMethodInstantiation()) + { + m_methodIterator.Reset(); + } + else + { + m_startedNonGenericMethod = FALSE; + } + +ADVANCE_METHOD: + if (m_mainMD->HasMethodInstantiation()) + { + if (!GetCurrentModule()->GetInstMethodHashTable()->FindNext(&m_methodIterator, &m_methodIteratorEntry)) + goto ADVANCE_TYPE; + if (CORCOMPILE_IS_POINTER_TAGGED(dac_cast<TADDR>(m_methodIteratorEntry->GetMethod()))) + goto ADVANCE_METHOD; + if (!m_methodIteratorEntry->GetMethod()->IsRestored()) + goto ADVANCE_METHOD; + if (m_methodIteratorEntry->GetMethod()->GetModule() != m_module) + goto ADVANCE_METHOD; + if (m_methodIteratorEntry->GetMethod()->GetMemberDef() != m_md) + goto ADVANCE_METHOD; + } + else if (m_startedNonGenericMethod) + { + goto ADVANCE_TYPE; + } + else + { + m_startedNonGenericMethod = TRUE; + } + + // Note: We don't need to keep the assembly alive in DAC - see code:CollectibleAssemblyHolder#CAH_DAC +#ifndef DACCESS_COMPILE + _ASSERTE_MSG( + ((m_assemblyIterationMode == kModeSharedDomainAssemblies) || + (*pDomainAssemblyHolder == dbg_m_pDomainAssembly)), + "Caller probably modified the assembly holder, which he shouldn't - see method comment."); +#endif //DACCESS_COMPILE + + return TRUE; +} // LoadedMethodDescIterator::Next + + +Module * LoadedMethodDescIterator::GetCurrentModule() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END + + if (m_assemblyIterationMode == kModeSharedDomainAssemblies) + { + return m_sharedModuleIterator.GetModule(); + } + return m_moduleIterator.GetLoadedModule(); +} + + +BOOL LoadedMethodDescIterator::NextSharedModule() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } + CONTRACTL_END + + _ASSERTE(m_assemblyIterationMode == kModeSharedDomainAssemblies); + + while (m_sharedModuleIterator.Next()) + { + // NOTE: If this code is to be shared with the dbgapi, the dbgapi + // will probably want to substitute its own test for "loadedness" + // here. +#ifdef PROFILING_SUPPORTED + Module * pModule = m_sharedModuleIterator.GetModule(); + if (!pModule->IsProfilerNotified()) + continue; +#endif // PROFILING_SUPPORTED + + // If we made it this far, pModule is suitable for iterating over + return TRUE; + } + return FALSE; +} + +MethodDesc *LoadedMethodDescIterator::Current() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + PRECONDITION(CheckPointer(m_mainMD)); + } + CONTRACTL_END + + + if (m_mainMD->HasMethodInstantiation()) + { + _ASSERTE(m_methodIteratorEntry); + return m_methodIteratorEntry->GetMethod(); + } + + if (!m_mainMD->HasClassInstantiation()) + { + // No Method or Class instantiation,then it's not generic. + return m_mainMD; + } + + MethodTable *pMT = m_typeIteratorEntry->GetTypeHandle().GetMethodTable(); + PREFIX_ASSUME(pMT != NULL); + _ASSERTE(pMT); + + return pMT->GetMethodDescForSlot(m_mainMD->GetSlot()); +} + +// Initialize the iterator. It will cover generics + prejitted; +// but it is not EnC aware. +void +LoadedMethodDescIterator::Start( + AppDomain * pAppDomain, + Module *pModule, + mdMethodDef md, + AssemblyIterationMode assemblyIterationMode, + AssemblyIterationFlags assemblyIterationFlags, + ModuleIterationOption moduleIterationFlags) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + PRECONDITION(CheckPointer(pModule)); + PRECONDITION(CheckPointer(pAppDomain, NULL_OK)); + } + CONTRACTL_END; + + // Specifying different assembly/module iteration flags has only been tested for UnsharedADAssemblies mode so far. + // It probably doesn't work as you would expect in other modes. In particular the shared assembly iterator + // doesn't use flags, and the logic in this iterator does a hard-coded filter that roughly matches the unshared + // mode if you had specified these flags: + // Assembly: Loading | Loaded | Execution + // Module: kModIterIncludeAvailableToProfilers + _ASSERTE((assemblyIterationMode == kModeUnsharedADAssemblies) || + (assemblyIterationFlags == (AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution))); + _ASSERTE((assemblyIterationMode == kModeUnsharedADAssemblies) || + (moduleIterationFlags == kModIterIncludeLoaded)); + + m_assemblyIterationMode = assemblyIterationMode; + m_assemIterationFlags = assemblyIterationFlags; + m_moduleIterationFlags = moduleIterationFlags; + m_mainMD = NULL; + m_module = pModule; + m_md = md; + m_pAppDomain = pAppDomain; + m_fFirstTime = TRUE; + + // If we're not iterating through the SharedDomain, caller must specify the + // pAppDomain to search. + _ASSERTE((assemblyIterationMode == kModeSharedDomainAssemblies) || (pAppDomain != NULL)); + _ASSERTE(TypeFromToken(m_md) == mdtMethodDef); +} + +// This is special init for DAC only +// @TODO:: change it to dac compile only. +void +LoadedMethodDescIterator::Start( + AppDomain *pAppDomain, + Module *pModule, + mdMethodDef md, + MethodDesc *pMethodDesc) +{ + Start(pAppDomain, pModule, md, kModeAllADAssemblies); + m_mainMD = pMethodDesc; +} + +LoadedMethodDescIterator::LoadedMethodDescIterator(void) +{ + LIMITED_METHOD_CONTRACT; + m_mainMD = NULL; + m_module = NULL; + m_md = mdTokenNil; + m_pAppDomain = NULL; +} |