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 // ===========================================================================
10 // CEELOAD reads in the PE file format using LoadLibrary
11 // ===========================================================================
20 #include "reflectclasswriter.h"
25 #include "dbginterface.h"
26 #include "dllimport.h"
27 #include "eeprofinterfaces.h"
28 #include "perfcounters.h"
30 #include "jitinterface.h"
32 #include "dllimportcallback.h"
33 #include "contractimpl.h"
35 #include "instmethhash.h"
36 #include "virtualcallstub.h"
37 #include "typestring.h"
38 #include "stringliteralmap.h"
39 #include <formattype.h>
40 #include "fieldmarshaler.h"
41 #include "sigbuilder.h"
42 #include "metadataexports.h"
43 #include "inlinetracking.h"
47 #include "exceptionhandling.h"
48 #include "corcompile.h"
50 #include "nibblestream.h"
52 #endif //FEATURE_PREJIT
54 #ifdef FEATURE_COMINTEROP
55 #include "runtimecallablewrapper.h"
56 #include "comcallablewrapper.h"
57 #endif //FEATURE_COMINTEROP
61 #pragma warning(disable:4724)
64 #include "ngenhash.inl"
73 #include "../md/compiler/custattr.h"
75 #include "peimagelayout.inl"
76 #include "ildbsymlib.h"
79 #if defined(PROFILING_SUPPORTED)
80 #include "profilermetadataemitvalidator.h"
85 #pragma warning(disable:4244)
89 #define COR_VTABLE_PTRSIZED COR_VTABLE_64BIT
90 #define COR_VTABLE_NOT_PTRSIZED COR_VTABLE_32BIT
91 #else // !_TARGET_64BIT_
92 #define COR_VTABLE_PTRSIZED COR_VTABLE_32BIT
93 #define COR_VTABLE_NOT_PTRSIZED COR_VTABLE_64BIT
94 #endif // !_TARGET_64BIT_
96 #define CEE_FILE_GEN_GROWTH_COLLECTIBLE 2048
98 #define NGEN_STATICS_ALLCLASSES_WERE_LOADED -1
100 BOOL Module::HasInlineTrackingMap()
102 LIMITED_METHOD_DAC_CONTRACT;
103 #ifdef FEATURE_READYTORUN
104 if (IsReadyToRun() && GetReadyToRunInfo()->GetInlineTrackingMap() != NULL)
109 return (m_pPersistentInlineTrackingMapNGen != NULL);
112 COUNT_T Module::GetInliners(PTR_Module inlineeOwnerMod, mdMethodDef inlineeTkn, COUNT_T inlinersSize, MethodInModule inliners[], BOOL *incompleteData)
115 #ifdef FEATURE_READYTORUN
116 if(IsReadyToRun() && GetReadyToRunInfo()->GetInlineTrackingMap() != NULL)
118 return GetReadyToRunInfo()->GetInlineTrackingMap()->GetInliners(inlineeOwnerMod, inlineeTkn, inlinersSize, inliners, incompleteData);
121 if(m_pPersistentInlineTrackingMapNGen != NULL)
123 return m_pPersistentInlineTrackingMapNGen->GetInliners(inlineeOwnerMod, inlineeTkn, inlinersSize, inliners, incompleteData);
129 #ifndef DACCESS_COMPILE
133 // ===========================================================================
135 // ===========================================================================
137 //---------------------------------------------------------------------------------------------------
138 // This wrapper just invokes the real initialization inside a try/hook.
139 // szName is not null only for dynamic modules
140 //---------------------------------------------------------------------------------------------------
141 void Module::DoInit(AllocMemTracker *pamTracker, LPCWSTR szName)
150 #ifdef PROFILING_SUPPORTED
152 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
154 g_profControlBlock.pProfInterface->ModuleLoadStarted((ModuleID) this);
157 // Need TRY/HOOK instead of holder so we can get HR of exception thrown for profiler callback
161 Initialize(pamTracker, szName);
163 #ifdef PROFILING_SUPPORTED
169 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
170 g_profControlBlock.pProfInterface->ModuleLoadFinished((ModuleID) this, GET_EXCEPTION()->GetHR());
179 // Set the given bit on m_dwTransientFlags. Return true if we won the race to set the bit.
180 BOOL Module::SetTransientFlagInterlocked(DWORD dwFlag)
182 LIMITED_METHOD_CONTRACT;
186 DWORD dwTransientFlags = m_dwTransientFlags;
187 if ((dwTransientFlags & dwFlag) != 0)
189 if ((DWORD)FastInterlockCompareExchange((LONG*)&m_dwTransientFlags, dwTransientFlags | dwFlag, dwTransientFlags) == dwTransientFlags)
194 #if PROFILING_SUPPORTED
195 void Module::NotifyProfilerLoadFinished(HRESULT hr)
202 INJECT_FAULT(COMPlusThrowOM());
207 // Note that in general we wil reuse shared modules. So we need to make sure we only notify
208 // the profiler once.
209 if (SetTransientFlagInterlocked(IS_PROFILER_NOTIFIED))
211 // Record how many types are already present
212 DWORD countTypesOrig = 0;
213 DWORD countExportedTypesOrig = 0;
216 countTypesOrig = GetMDImport()->GetCountWithTokenKind(mdtTypeDef);
217 countExportedTypesOrig = GetMDImport()->GetCountWithTokenKind(mdtExportedType);
220 // Notify the profiler, this may cause metadata to be updated
222 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
225 g_profControlBlock.pProfInterface->ModuleLoadFinished((ModuleID) this, hr);
229 g_profControlBlock.pProfInterface->ModuleAttachedToAssembly((ModuleID) this,
230 (AssemblyID)m_pAssembly);
236 // If there are more types than before, add these new types to the
240 DWORD countTypesAfterProfilerUpdate = GetMDImport()->GetCountWithTokenKind(mdtTypeDef);
241 DWORD countExportedTypesAfterProfilerUpdate = GetMDImport()->GetCountWithTokenKind(mdtExportedType);
242 // typeDefs rids 0 and 1 aren't included in the count, thus X typeDefs before means rid X+1 was valid and our incremental addition should start at X+2
243 for (DWORD typeDefRid = countTypesOrig + 2; typeDefRid < countTypesAfterProfilerUpdate + 2; typeDefRid++)
245 GetAssembly()->AddType(this, TokenFromRid(typeDefRid, mdtTypeDef));
247 // exportedType rid 0 isn't included in the count, thus X exportedTypes before means rid X was valid and our incremental addition should start at X+1
248 for (DWORD exportedTypeDef = countExportedTypesOrig + 1; exportedTypeDef < countExportedTypesAfterProfilerUpdate + 1; exportedTypeDef++)
250 GetAssembly()->AddExportedType(TokenFromRid(exportedTypeDef, mdtExportedType));
255 BEGIN_PIN_PROFILER(CORProfilerTrackAssemblyLoads());
259 g_profControlBlock.pProfInterface->AssemblyLoadFinished((AssemblyID) m_pAssembly, hr);
266 #ifndef CROSSGEN_COMPILE
267 IMetaDataEmit *Module::GetValidatedEmitter()
274 INJECT_FAULT(COMPlusThrowOM());
279 if (m_pValidatedEmitter.Load() == NULL)
281 // In the past profilers could call any API they wanted on the the IMetaDataEmit interface and we didn't
282 // verify anything. To ensure we don't break back-compat the verifications are not enabled by default.
283 // Right now I have only added verifications for NGEN images, but in the future we might want verifications
285 IMetaDataEmit* pEmit = NULL;
286 if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_ProfAPI_ValidateNGENInstrumentation) && HasNativeImage())
288 ProfilerMetadataEmitValidator* pValidator = new ProfilerMetadataEmitValidator(GetEmitter());
289 pValidator->QueryInterface(IID_IMetaDataEmit, (void**)&pEmit);
293 pEmit = GetEmitter();
296 // Atomically swap it into the field (release it if we lose the race)
297 if (FastInterlockCompareExchangePointer(&m_pValidatedEmitter, pEmit, NULL) != NULL)
302 return m_pValidatedEmitter.Load();
304 #endif // CROSSGEN_COMPILE
305 #endif // PROFILING_SUPPORTED
307 void Module::NotifyEtwLoadFinished(HRESULT hr)
316 // we report only successful loads
318 ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
319 TRACE_LEVEL_INFORMATION,
322 BOOL fSharedModule = !SetTransientFlagInterlocked(IS_ETW_NOTIFIED);
323 ETW::LoaderLog::ModuleLoad(this, fSharedModule);
327 // Module initialization occurs in two phases: the constructor phase and the Initialize phase.
329 // The constructor phase initializes just enough so that Destruct() can be safely called.
330 // It cannot throw or fail.
332 Module::Module(Assembly *pAssembly, mdFile moduleRef, PEFile *file)
342 PREFIX_ASSUME(pAssembly != NULL);
344 m_pAssembly = pAssembly;
345 m_moduleRef = moduleRef;
347 m_dwTransientFlags = CLASSES_FREED;
349 if (!m_file->HasNativeImage())
351 // Memory allocated on LoaderHeap is zero-filled. Spot-check it here.
352 _ASSERTE(m_pBinder == NULL);
353 _ASSERTE(m_symbolFormat == eSymbolFormatNone);
359 void Module::InitializeForProfiling()
367 PRECONDITION(HasNativeOrReadyToRunImage());
371 COUNT_T cbProfileList = 0;
373 m_nativeImageProfiling = FALSE;
375 if (HasNativeImage())
377 PEImageLayout * pNativeImage = GetNativeImage();
378 CORCOMPILE_VERSION_INFO * pNativeVersionInfo = pNativeImage->GetNativeVersionInfoMaybeNull();
379 if ((pNativeVersionInfo != NULL) && (pNativeVersionInfo->wConfigFlags & CORCOMPILE_CONFIG_INSTRUMENTATION))
381 m_nativeImageProfiling = GetAssembly()->IsInstrumented();
384 // Link the module to the profile data list if available.
385 m_methodProfileList = pNativeImage->GetNativeProfileDataList(&cbProfileList);
387 else // ReadyToRun image
389 #ifdef FEATURE_READYTORUN
390 // We already setup the m_methodProfileList in the ReadyToRunInfo constructor
391 if (m_methodProfileList != nullptr)
393 ReadyToRunInfo * pInfo = GetReadyToRunInfo();
394 PEImageLayout * pImage = pInfo->GetImage();
396 // Enable profiling if the ZapBBInstr value says to
397 m_nativeImageProfiling = GetAssembly()->IsInstrumented();
402 #ifdef FEATURE_LAZY_COW_PAGES
403 // When running a IBC tuning image to gather profile data
404 // we increment the block counts contained in this area.
407 EnsureWritablePages(m_methodProfileList, cbProfileList);
411 #ifdef FEATURE_PREJIT
413 void Module::InitializeNativeImage(AllocMemTracker* pamTracker)
421 PRECONDITION(HasNativeImage());
425 PEImageLayout * pNativeImage = GetNativeImage();
427 ExecutionManager::AddNativeImageRange(dac_cast<TADDR>(pNativeImage->GetBase()), pNativeImage->GetVirtualSize(), this);
429 #ifndef CROSSGEN_COMPILE
432 #endif // CROSSGEN_COMPILE
434 #if defined(HAVE_GCCOVER)
435 if (GCStress<cfg_instr_ngen>::IsEnabled())
437 // Setting up gc coverage requires the base system classes
438 // to be initialized. So we must defer this for mscorlib.
441 SetupGcCoverageForNativeImage(this);
444 #endif // defined(HAVE_GCCOVER)
447 void Module::SetNativeMetadataAssemblyRefInCache(DWORD rid, PTR_Assembly pAssembly)
457 if (m_NativeMetadataAssemblyRefMap == NULL)
459 IMDInternalImport* pImport = GetNativeAssemblyImport();
460 DWORD dwMaxRid = pImport->GetCountWithTokenKind(mdtAssemblyRef);
461 _ASSERTE(dwMaxRid > 0);
463 S_SIZE_T dwAllocSize = S_SIZE_T(sizeof(PTR_Assembly)) * S_SIZE_T(dwMaxRid);
465 AllocMemTracker amTracker;
466 PTR_Assembly * NativeMetadataAssemblyRefMap = (PTR_Assembly *) amTracker.Track( GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(dwAllocSize) );
468 // Note: Memory allocated on loader heap is zero filled
470 if (InterlockedCompareExchangeT<PTR_Assembly *>(&m_NativeMetadataAssemblyRefMap, NativeMetadataAssemblyRefMap, NULL) == NULL)
471 amTracker.SuppressRelease();
473 _ASSERTE(m_NativeMetadataAssemblyRefMap != NULL);
475 _ASSERTE(rid <= GetNativeAssemblyImport()->GetCountWithTokenKind(mdtAssemblyRef));
476 m_NativeMetadataAssemblyRefMap[rid-1] = pAssembly;
478 #else // FEATURE_PREJIT
479 BOOL Module::IsPersistedObject(void *address)
481 LIMITED_METHOD_CONTRACT;
485 #endif // FEATURE_PREJIT
487 // Module initialization occurs in two phases: the constructor phase and the Initialize phase.
489 // The Initialize() phase completes the initialization after the constructor has run.
490 // It can throw exceptions but whether it throws or succeeds, it must leave the Module
491 // in a state where Destruct() can be safely called.
493 // szName is only used by dynamic modules, see ReflectionModule::Initialize
496 void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
502 PRECONDITION(szName == NULL);
506 m_pSimpleName = m_file->GetSimpleName();
508 m_Crst.Init(CrstModule);
509 m_LookupTableCrst.Init(CrstModuleLookupTable, CrstFlags(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD));
510 m_FixupCrst.Init(CrstModuleFixup, (CrstFlags)(CRST_HOST_BREAKABLE|CRST_REENTRANCY));
511 m_InstMethodHashTableCrst.Init(CrstInstMethodHashTable, CRST_REENTRANCY);
512 m_ISymUnmanagedReaderCrst.Init(CrstISymUnmanagedReader, CRST_DEBUGGER_THREAD);
514 if (!m_file->HasNativeImage())
519 (strcmp(m_pSimpleName, "System") == 0) ||
520 (strcmp(m_pSimpleName, "System.Core") == 0) ||
521 (strcmp(m_pSimpleName, "Windows.Foundation") == 0))
523 FastInterlockOr(&m_dwPersistedFlags, LOW_LEVEL_SYSTEM_ASSEMBLY_BY_NAME);
527 m_dwTransientFlags &= ~((DWORD)CLASSES_FREED); // Set flag indicating LookupMaps are now in a consistent and destructable state
529 #ifdef FEATURE_READYTORUN
530 if (!HasNativeImage() && !IsResource())
531 m_pReadyToRunInfo = ReadyToRunInfo::Initialize(this, pamTracker);
534 // Initialize the instance fields that we need for all non-Resource Modules
537 if (m_pAvailableClasses == NULL && !IsReadyToRun())
539 m_pAvailableClasses = EEClassHashTable::Create(this,
540 GetAssembly()->IsCollectible() ? AVAILABLE_CLASSES_HASH_BUCKETS_COLLECTIBLE : AVAILABLE_CLASSES_HASH_BUCKETS,
541 FALSE /* bCaseInsensitive */, pamTracker);
544 if (m_pAvailableParamTypes == NULL)
546 m_pAvailableParamTypes = EETypeHashTable::Create(GetLoaderAllocator(), this, PARAMTYPES_HASH_BUCKETS, pamTracker);
549 if (m_pInstMethodHashTable == NULL)
551 m_pInstMethodHashTable = InstMethodHashTable::Create(GetLoaderAllocator(), this, PARAMMETHODS_HASH_BUCKETS, pamTracker);
554 if(m_pMemberRefToDescHashTable == NULL)
558 m_pMemberRefToDescHashTable = MemberRefToDescHashTable::Create(this, MEMBERREF_MAP_INITIAL_SIZE, pamTracker);
562 IMDInternalImport * pImport = GetMDImport();
564 // Get #MemberRefs and create memberrefToDesc hash table
565 m_pMemberRefToDescHashTable = MemberRefToDescHashTable::Create(this, pImport->GetCountWithTokenKind(mdtMemberRef)+1, pamTracker);
569 #ifdef FEATURE_COMINTEROP
570 if (IsCompilationProcess() && m_pGuidToTypeHash == NULL)
572 // only allocate this during NGEN-ing
573 m_pGuidToTypeHash = GuidToMethodTableHashTable::Create(this, GUID_TO_TYPE_HASH_BUCKETS, pamTracker);
575 #endif // FEATURE_COMINTEROP
578 if (GetAssembly()->IsDomainNeutral() && !IsSingleAppDomain())
580 m_ModuleIndex = Module::AllocateModuleIndex();
581 m_ModuleID = (DomainLocalModule*)Module::IndexToID(m_ModuleIndex);
585 // this will be initialized a bit later.
587 m_ModuleIndex.m_dwIndex = (SIZE_T)-1;
590 #ifdef FEATURE_COLLECTIBLE_TYPES
591 if (GetAssembly()->IsCollectible())
593 FastInterlockOr(&m_dwPersistedFlags, COLLECTIBLE_MODULE);
595 #endif // FEATURE_COLLECTIBLE_TYPES
597 // Prepare statics that are known at module load time
598 AllocateStatics(pamTracker);
600 #ifdef FEATURE_PREJIT
601 // Set up native image
602 if (HasNativeImage())
604 InitializeNativeImage(pamTracker);
606 #endif // FEATURE_PREJIT
608 if (HasNativeOrReadyToRunImage())
610 InitializeForProfiling();
613 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
614 if (g_CorCompileVerboseLevel)
615 m_pNgenStats = new NgenStats();
618 if (!IsResource() && (m_AssemblyRefByNameTable == NULL))
620 Module::CreateAssemblyRefByNameTable(pamTracker);
623 // If the program has the "ForceEnc" env variable set we ensure every eligible
624 // module has EnC turned on.
625 if (g_pConfig->ForceEnc() && IsEditAndContinueCapable())
626 EnableEditAndContinue();
628 LOG((LF_CLASSLOADER, LL_INFO10, "Loaded pModule: \"%ws\".\n", GetDebugName()));
632 #endif // DACCESS_COMPILE
635 #ifdef FEATURE_COMINTEROP
637 #ifndef DACCESS_COMPILE
640 GuidToMethodTableHashTable* GuidToMethodTableHashTable::Create(Module* pModule, DWORD cInitialBuckets,
641 AllocMemTracker *pamTracker)
648 INJECT_FAULT(COMPlusThrowOM(););
649 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
653 LoaderHeap *pHeap = pModule->GetAssembly()->GetLowFrequencyHeap();
654 GuidToMethodTableHashTable *pThis = (GuidToMethodTableHashTable*)pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(GuidToMethodTableHashTable)));
656 // The base class get initialized through chaining of constructors. We allocated the hash instance via the
657 // loader heap instead of new so use an in-place new to call the constructors now.
658 new (pThis) GuidToMethodTableHashTable(pModule, pHeap, cInitialBuckets);
663 GuidToMethodTableEntry *GuidToMethodTableHashTable::InsertValue(PTR_GUID pGuid, PTR_MethodTable pMT,
664 BOOL bReplaceIfFound, AllocMemTracker *pamTracker)
671 INJECT_FAULT(COMPlusThrowOM(););
672 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
676 GuidToMethodTableEntry *pEntry = NULL;
680 pEntry = FindItem(pGuid, NULL);
689 pEntry = BaseAllocateEntry(pamTracker);
690 pEntry->m_Guid = pGuid;
693 DWORD hash = Hash(pGuid);
694 BaseInsertEntry(hash, pEntry);
700 #endif // !DACCESS_COMPILE
702 PTR_MethodTable GuidToMethodTableHashTable::GetValue(const GUID * pGuid, LookupContext *pContext)
710 PRECONDITION(CheckPointer(pGuid));
714 GuidToMethodTableEntry * pEntry = FindItem(pGuid, pContext);
717 return pEntry->m_pMT;
723 GuidToMethodTableEntry *GuidToMethodTableHashTable::FindItem(const GUID * pGuid, LookupContext *pContext)
731 PRECONDITION(CheckPointer(pGuid));
735 // It's legal for the caller not to pass us a LookupContext, but we might need to iterate
736 // internally (since we lookup via hash and hashes may collide). So substitute our own
737 // private context if one was not provided.
738 LookupContext sAltContext;
739 if (pContext == NULL)
740 pContext = &sAltContext;
742 // The base class provides the ability to enumerate all entries with the same hash code.
743 // We further check which of these entries actually match the full key.
744 PTR_GuidToMethodTableEntry pSearch = BaseFindFirstEntryByHash(Hash(pGuid), pContext);
747 if (CompareKeys(pSearch, pGuid))
752 pSearch = BaseFindNextEntryByHash(pContext);
758 BOOL GuidToMethodTableHashTable::CompareKeys(PTR_GuidToMethodTableEntry pEntry, const GUID * pGuid)
760 LIMITED_METHOD_DAC_CONTRACT;
761 return *pGuid == *(pEntry->m_Guid);
764 DWORD GuidToMethodTableHashTable::Hash(const GUID * pGuid)
766 LIMITED_METHOD_DAC_CONTRACT;
767 static_assert_no_msg(sizeof(GUID) % sizeof(DWORD) == 0);
768 static_assert_no_msg(sizeof(GUID) / sizeof(DWORD) == 4);
769 DWORD * pSlice = (DWORD*) pGuid;
770 return pSlice[0] ^ pSlice[1] ^ pSlice[2] ^ pSlice[3];
774 BOOL GuidToMethodTableHashTable::FindNext(Iterator *it, GuidToMethodTableEntry **ppEntry)
776 LIMITED_METHOD_DAC_CONTRACT;
778 if (!it->m_fIterating)
780 BaseInitIterator(&it->m_sIterator);
781 it->m_fIterating = true;
784 *ppEntry = it->m_sIterator.Next();
785 return *ppEntry ? TRUE : FALSE;
788 DWORD GuidToMethodTableHashTable::GetCount()
790 LIMITED_METHOD_DAC_CONTRACT;
791 return BaseGetElementCount();
794 #if defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
796 void GuidToMethodTableHashTable::Save(DataImage *pImage, CorProfileData *pProfileData)
799 Base_t::BaseSave(pImage, pProfileData);
802 void GuidToMethodTableHashTable::Fixup(DataImage *pImage)
805 Base_t::BaseFixup(pImage);
808 bool GuidToMethodTableHashTable::SaveEntry(DataImage *pImage, CorProfileData *pProfileData,
809 GuidToMethodTableEntry *pOldEntry, GuidToMethodTableEntry *pNewEntry,
810 EntryMappingTable *pMap)
812 LIMITED_METHOD_CONTRACT;
816 void GuidToMethodTableHashTable::FixupEntry(DataImage *pImage, GuidToMethodTableEntry *pEntry, void *pFixupBase, DWORD cbFixupOffset)
819 pImage->FixupField(pFixupBase, cbFixupOffset + offsetof(GuidToMethodTableEntry, m_pMT), pEntry->m_pMT);
820 pImage->FixupField(pFixupBase, cbFixupOffset + offsetof(GuidToMethodTableEntry, m_Guid), pEntry->m_Guid);
823 #endif // FEATURE_NATIVE_IMAGE_GENERATION && !DACCESS_COMPILE
826 #ifdef FEATURE_PREJIT
828 #ifndef DACCESS_COMPILE
829 BOOL Module::CanCacheWinRTTypeByGuid(MethodTable *pMT)
836 PRECONDITION(IsCompilationProcess());
840 // Don't cache mscorlib-internal declarations of WinRT types.
841 if (IsSystem() && pMT->IsProjectedFromWinRT())
844 // Don't cache redirected WinRT types.
845 if (WinRTTypeNameConverter::IsRedirectedWinRTSourceType(pMT))
848 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
849 // Don't cache in a module that's not the NGen target, since the result
850 // won't be saved, and since the such a module might be read-only.
851 if (GetAppDomain()->ToCompilationDomain()->GetTargetModule() != this)
858 void Module::CacheWinRTTypeByGuid(PTR_MethodTable pMT, PTR_GuidInfo pgi /*= NULL*/)
863 PRECONDITION(CheckPointer(pMT));
864 PRECONDITION(pMT->IsLegalNonArrayWinRTType());
865 PRECONDITION(pgi != NULL || pMT->GetGuidInfo() != NULL);
866 PRECONDITION(IsCompilationProcess());
872 pgi = pMT->GetGuidInfo();
876 m_pGuidToTypeHash->InsertValue(&pgi->m_Guid, pMT, TRUE, &amt);
877 amt.SuppressRelease();
880 #endif // !DACCESS_COMPILE
882 PTR_MethodTable Module::LookupTypeByGuid(const GUID & guid)
885 // Triton ni images do not have this hash.
886 if (m_pGuidToTypeHash != NULL)
887 return m_pGuidToTypeHash->GetValue(&guid, NULL);
892 void Module::GetCachedWinRTTypes(SArray<PTR_MethodTable> * pTypes, SArray<GUID> * pGuids)
901 // Triton ni images do not have this hash.
902 if (m_pGuidToTypeHash != NULL)
904 GuidToMethodTableHashTable::Iterator it(m_pGuidToTypeHash);
905 GuidToMethodTableEntry *pEntry;
906 while (m_pGuidToTypeHash->FindNext(&it, &pEntry))
908 pTypes->Append(pEntry->m_pMT);
909 pGuids->Append(*pEntry->m_Guid);
914 #endif // FEATURE_PREJIT
916 #endif // FEATURE_COMINTEROP
918 #ifndef DACCESS_COMPILE
919 MemberRefToDescHashTable* MemberRefToDescHashTable::Create(Module *pModule, DWORD cInitialBuckets, AllocMemTracker *pamTracker)
926 INJECT_FAULT(COMPlusThrowOM(););
927 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
931 LoaderHeap *pHeap = pModule->GetAssembly()->GetLowFrequencyHeap();
932 MemberRefToDescHashTable *pThis = (MemberRefToDescHashTable*)pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(MemberRefToDescHashTable)));
934 // The base class get initialized through chaining of constructors. We allocated the hash instance via the
935 // loader heap instead of new so use an in-place new to call the constructors now.
936 new (pThis) MemberRefToDescHashTable(pModule, pHeap, cInitialBuckets);
942 MemberRefToDescHashEntry* MemberRefToDescHashTable::Insert(mdMemberRef token , FieldDesc *value)
949 INJECT_FAULT(COMPlusThrowOM(););
950 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
954 LookupContext sAltContext;
956 _ASSERTE((dac_cast<TADDR>(value) & IS_FIELD_MEMBER_REF) == 0);
958 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(token), &sAltContext);
961 // If memberRef is hot token in that case entry for memberref is already persisted in ngen image. So entry for it will already be present in hash table.
962 // However its value will be null. We need to set its actual value.
963 if(pEntry->m_value == dac_cast<TADDR>(NULL))
965 EnsureWritablePages(&(pEntry->m_value));
966 pEntry->m_value = dac_cast<TADDR>(value)|IS_FIELD_MEMBER_REF;
969 _ASSERTE(pEntry->m_value == (dac_cast<TADDR>(value)|IS_FIELD_MEMBER_REF));
973 // For non hot tokens insert new entry in hashtable
974 pEntry = BaseAllocateEntry(NULL);
975 pEntry->m_value = dac_cast<TADDR>(value)|IS_FIELD_MEMBER_REF;
976 BaseInsertEntry(RidFromToken(token), pEntry);
982 MemberRefToDescHashEntry* MemberRefToDescHashTable::Insert(mdMemberRef token , MethodDesc *value)
989 INJECT_FAULT(COMPlusThrowOM(););
990 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
994 LookupContext sAltContext;
996 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(token), &sAltContext);
999 // If memberRef is hot token in that case entry for memberref is already persisted in ngen image. So entry for it will already be present in hash table.
1000 // However its value will be null. We need to set its actual value.
1001 if(pEntry->m_value == dac_cast<TADDR>(NULL))
1003 EnsureWritablePages(&(pEntry->m_value));
1004 pEntry->m_value = dac_cast<TADDR>(value);
1007 _ASSERTE(pEntry->m_value == dac_cast<TADDR>(value));
1011 // For non hot tokens insert new entry in hashtable
1012 pEntry = BaseAllocateEntry(NULL);
1013 pEntry->m_value = dac_cast<TADDR>(value);
1014 BaseInsertEntry(RidFromToken(token), pEntry);
1019 #if defined(FEATURE_NATIVE_IMAGE_GENERATION)
1020 void MemberRefToDescHashTable::Save(DataImage *pImage, CorProfileData *pProfileData)
1022 STANDARD_VM_CONTRACT;
1024 // Mark if the tokens are hot
1027 DWORD numInTokenList = pProfileData->GetHotTokens(mdtMemberRef>>24, 1<<RidMap, 1<<RidMap, NULL, 0);
1029 if (numInTokenList > 0)
1031 LookupContext sAltContext;
1033 mdToken *tokenList = (mdToken*)(void*)pImage->GetModule()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(mdToken)) * S_SIZE_T(numInTokenList));
1035 pProfileData->GetHotTokens(mdtMemberRef>>24, 1<<RidMap, 1<<RidMap, tokenList, numInTokenList);
1036 for (DWORD i = 0; i < numInTokenList; i++)
1038 DWORD rid = RidFromToken(tokenList[i]);
1039 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(tokenList[i]), &sAltContext);
1042 _ASSERTE((pEntry->m_value & 0x1) == 0);
1043 pEntry->m_value |= 0x1;
1049 BaseSave(pImage, pProfileData);
1052 void MemberRefToDescHashTable::FixupEntry(DataImage *pImage, MemberRefToDescHashEntry *pEntry, void *pFixupBase, DWORD cbFixupOffset)
1054 //As there is no more hard binding initialize MemberRef* to NULL
1055 pImage->ZeroPointerField(pFixupBase, cbFixupOffset + offsetof(MemberRefToDescHashEntry, m_value));
1058 #endif // FEATURE_NATIVE_IMAGE_GENERATION
1060 #endif // !DACCESS_COMPILE
1062 PTR_MemberRef MemberRefToDescHashTable::GetValue(mdMemberRef token, BOOL *pfIsMethod)
1073 LookupContext sAltContext;
1075 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(token), &sAltContext);
1078 if(pEntry->m_value & IS_FIELD_MEMBER_REF)
1079 *pfIsMethod = FALSE;
1082 return (PTR_MemberRef)(pEntry->m_value & (~MEMBER_REF_MAP_ALL_FLAGS));
1089 void Module::SetDebuggerInfoBits(DebuggerAssemblyControlFlags newBits)
1091 LIMITED_METHOD_CONTRACT;
1094 _ASSERTE(((newBits << DEBUGGER_INFO_SHIFT_PRIV) &
1095 ~DEBUGGER_INFO_MASK_PRIV) == 0);
1097 m_dwTransientFlags &= ~DEBUGGER_INFO_MASK_PRIV;
1098 m_dwTransientFlags |= (newBits << DEBUGGER_INFO_SHIFT_PRIV);
1100 #ifdef DEBUGGING_SUPPORTED
1101 BOOL setEnC = ((newBits & DACF_ENC_ENABLED) != 0) && IsEditAndContinueCapable();
1103 // IsEditAndContinueCapable should already check !GetAssembly()->IsDomainNeutral
1104 _ASSERTE(!setEnC || !GetAssembly()->IsDomainNeutral());
1106 // The only way can change Enc is through debugger override.
1109 EnableEditAndContinue();
1113 if (!g_pConfig->ForceEnc())
1114 DisableEditAndContinue();
1116 #endif // DEBUGGING_SUPPORTED
1118 #if defined(DACCESS_COMPILE)
1119 // Now that we've changed m_dwTransientFlags, update that in the target too.
1120 // This will fail for read-only target.
1121 // If this fails, it will throw an exception.
1122 // @dbgtodo dac write: finalize on plans for how DAC writes to the target.
1124 hrDac = DacWriteHostInstance(this, true);
1125 _ASSERTE(SUCCEEDED(hrDac)); // would throw if there was an error.
1126 #endif // DACCESS_COMPILE
1129 #ifndef DACCESS_COMPILE
1131 Module *Module::Create(Assembly *pAssembly, mdFile moduleRef, PEFile *file, AllocMemTracker *pamTracker)
1136 PRECONDITION(CheckPointer(pAssembly));
1137 PRECONDITION(CheckPointer(file));
1138 PRECONDITION(!IsNilToken(moduleRef) || file->IsAssembly());
1139 POSTCONDITION(CheckPointer(RETVAL));
1140 POSTCONDITION(RETVAL->GetFile() == file);
1144 // Hoist CONTRACT into separate routine because of EX incompatibility
1146 Module *pModule = NULL;
1148 // Create the module
1150 #ifdef FEATURE_PREJIT
1152 if (file->HasNativeImage())
1154 pModule = file->GetLoadedNative()->GetPersistedModuleImage();
1155 PREFIX_ASSUME(pModule != NULL);
1156 CONSISTENCY_CHECK_MSG(pModule->m_pAssembly == NULL || !pModule->IsTenured(), // if the module is not tenured it could be our previous attempt
1157 "Native image can only be used once per process\n");
1158 EnsureWritablePages(pModule);
1159 pModule = new ((void*) pModule) Module(pAssembly, moduleRef, file);
1160 PREFIX_ASSUME(pModule != NULL);
1163 #endif // FEATURE_PREJIT
1165 if (pModule == NULL)
1167 #ifdef EnC_SUPPORTED
1168 if (IsEditAndContinueCapable(pAssembly, file))
1170 // IsEditAndContinueCapable should already check !pAssembly->IsDomainNeutral
1171 _ASSERTE(!pAssembly->IsDomainNeutral());
1173 // if file is EnCCapable, always create an EnC-module, but EnC won't necessarily be enabled.
1174 // Debugger enables this by calling SetJITCompilerFlags on LoadModule callback.
1176 void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(EditAndContinueModule))));
1177 pModule = new (pMemory) EditAndContinueModule(pAssembly, moduleRef, file);
1180 #endif // EnC_SUPPORTED
1182 void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(Module))));
1183 pModule = new (pMemory) Module(pAssembly, moduleRef, file);
1187 PREFIX_ASSUME(pModule != NULL);
1188 ModuleHolder pModuleSafe(pModule);
1189 pModuleSafe->DoInit(pamTracker, NULL);
1191 RETURN pModuleSafe.Extract();
1194 void Module::ApplyMetaData()
1204 LOG((LF_CLASSLOADER, LL_INFO100, "Module::ApplyNewMetaData %x\n", this));
1209 // Ensure for TypeRef
1210 ulCount = GetMDImport()->GetCountWithTokenKind(mdtTypeRef) + 1;
1211 EnsureTypeRefCanBeStored(TokenFromRid(ulCount, mdtTypeRef));
1213 // Ensure for AssemblyRef
1214 ulCount = GetMDImport()->GetCountWithTokenKind(mdtAssemblyRef) + 1;
1215 EnsureAssemblyRefCanBeStored(TokenFromRid(ulCount, mdtAssemblyRef));
1219 // Destructor for Module
1222 void Module::Destruct()
1233 LOG((LF_EEMEM, INFO3, "Deleting module %x\n", this));
1234 #ifdef PROFILING_SUPPORTED
1236 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
1237 if (!IsBeingUnloaded())
1239 // Profiler is causing some peripheral class loads. Probably this just needs
1240 // to be turned into a Fault_not_fatal and moved to a specific place inside the profiler.
1244 g_profControlBlock.pProfInterface->ModuleUnloadStarted((ModuleID) this);
1249 EX_END_CATCH(SwallowAllExceptions);
1253 #endif // PROFILING_SUPPORTED
1256 DACNotify::DoModuleUnloadNotification(this);
1258 // Free classes in the class table
1263 #ifdef DEBUGGING_SUPPORTED
1264 if (g_pDebugInterface)
1267 g_pDebugInterface->DestructModule(this);
1270 #endif // DEBUGGING_SUPPORTED
1272 ReleaseISymUnmanagedReader();
1274 // Clean up sig cookies
1275 VASigCookieBlock *pVASigCookieBlock = m_pVASigCookieBlock;
1276 while (pVASigCookieBlock)
1278 VASigCookieBlock *pNext = pVASigCookieBlock->m_Next;
1279 delete pVASigCookieBlock;
1281 pVASigCookieBlock = pNext;
1284 // Clean up the IL stub cache
1285 if (m_pILStubCache != NULL)
1287 delete m_pILStubCache;
1292 #ifdef PROFILING_SUPPORTED
1294 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
1295 // Profiler is causing some peripheral class loads. Probably this just needs
1296 // to be turned into a Fault_not_fatal and moved to a specific place inside the profiler.
1300 g_profControlBlock.pProfInterface->ModuleUnloadFinished((ModuleID) this, S_OK);
1305 EX_END_CATCH(SwallowAllExceptions);
1309 if (m_pValidatedEmitter.Load() != NULL)
1311 m_pValidatedEmitter->Release();
1313 #endif // PROFILING_SUPPORTED
1316 // Warning - deleting the zap file will cause the module to be unmapped
1318 ClearInMemorySymbolStream();
1321 m_FixupCrst.Destroy();
1322 m_LookupTableCrst.Destroy();
1323 m_InstMethodHashTableCrst.Destroy();
1324 m_ISymUnmanagedReaderCrst.Destroy();
1327 if (m_debuggerSpecificData.m_pDynamicILCrst)
1329 delete m_debuggerSpecificData.m_pDynamicILCrst;
1332 if (m_debuggerSpecificData.m_pDynamicILBlobTable)
1334 delete m_debuggerSpecificData.m_pDynamicILBlobTable;
1337 if (m_debuggerSpecificData.m_pTemporaryILBlobTable)
1339 delete m_debuggerSpecificData.m_pTemporaryILBlobTable;
1342 if (m_debuggerSpecificData.m_pILOffsetMappingTable)
1344 for (ILOffsetMappingTable::Iterator pCurElem = m_debuggerSpecificData.m_pILOffsetMappingTable->Begin(),
1345 pEndElem = m_debuggerSpecificData.m_pILOffsetMappingTable->End();
1346 pCurElem != pEndElem;
1349 ILOffsetMappingEntry entry = *pCurElem;
1350 entry.m_mapping.Clear();
1352 delete m_debuggerSpecificData.m_pILOffsetMappingTable;
1355 #ifdef FEATURE_PREJIT
1357 if (HasNativeImage())
1362 #endif // FEATURE_PREJIT
1367 // If this module was loaded as domain-specific, then
1368 // we must free its ModuleIndex so that it can be reused
1372 #ifdef FEATURE_PREJIT
1373 void Module::DeleteNativeCodeRanges()
1384 if (HasNativeImage())
1386 PEImageLayout * pNativeImage = GetNativeImage();
1388 ExecutionManager::DeleteRange(dac_cast<TADDR>(pNativeImage->GetBase()));
1393 bool Module::NeedsGlobalMethodTable()
1404 IMDInternalImport * pImport = GetMDImport();
1405 if (!IsResource() && pImport->IsValidToken(COR_GLOBAL_PARENT_TOKEN))
1408 HENUMInternalHolder funcEnum(pImport);
1409 funcEnum.EnumGlobalFunctionsInit();
1410 if (pImport->EnumGetCount(&funcEnum) != 0)
1415 HENUMInternalHolder fieldEnum(pImport);
1416 fieldEnum.EnumGlobalFieldsInit();
1417 if (pImport->EnumGetCount(&fieldEnum) != 0)
1422 // resource module or no global statics nor global functions
1427 MethodTable *Module::GetGlobalMethodTable()
1429 CONTRACT (MethodTable *)
1435 INJECT_FAULT(CONTRACT_RETURN NULL;);
1436 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1441 if ((m_dwPersistedFlags & COMPUTED_GLOBAL_CLASS) == 0)
1443 MethodTable *pMT = NULL;
1445 if (NeedsGlobalMethodTable())
1447 pMT = ClassLoader::LoadTypeDefThrowing(this, COR_GLOBAL_PARENT_TOKEN,
1448 ClassLoader::ThrowIfNotFound,
1449 ClassLoader::FailIfUninstDefOrRef).AsMethodTable();
1452 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_GLOBAL_CLASS);
1457 RETURN LookupTypeDef(COR_GLOBAL_PARENT_TOKEN).AsMethodTable();
1462 #endif // !DACCESS_COMPILE
1464 #ifdef FEATURE_PREJIT
1467 BOOL Module::IsAlwaysSavedInPreferredZapModule(Instantiation classInst, // the type arguments to the type (if any)
1468 Instantiation methodInst) // the type arguments to the method (if any)
1470 LIMITED_METHOD_CONTRACT;
1472 return ClassLoader::IsTypicalSharedInstantiation(classInst) &&
1473 ClassLoader::IsTypicalSharedInstantiation(methodInst);
1476 //this gets called recursively for generics, so do a probe.
1477 PTR_Module Module::ComputePreferredZapModule(Module * pDefinitionModule,
1478 Instantiation classInst,
1479 Instantiation methodInst)
1491 PTR_Module ret = NULL;
1492 INTERIOR_STACK_PROBE_NOTHROW_CHECK_THREAD(DontCallDirectlyForceStackOverflow());
1494 ret = Module::ComputePreferredZapModuleHelper( pDefinitionModule,
1497 END_INTERIOR_STACK_PROBE;
1502 // Is pModule likely a dependency of pOtherModule? Heuristic used by preffered zap module algorithm.
1503 // It can return both false positives and negatives.
1505 static bool IsLikelyDependencyOf(Module * pModule, Module * pOtherModule)
1514 PRECONDITION(CheckPointer(pOtherModule));
1518 // Every module has a dependency with itself
1519 if (pModule == pOtherModule)
1523 // Explicit check for low level system assemblies is working around Win8P facades introducing extra layer between low level system assemblies
1524 // (System.dll or System.Core.dll) and the app assemblies. Because of this extra layer, the check below won't see the direct
1525 // reference between these low level system assemblies and the app assemblies. The prefererred zap module for instantiations of generic
1526 // collections from these low level system assemblies (like LinkedList<AppType>) should be module of AppType. It would be module of the generic
1527 // collection without this check. On desktop (FEATURE_FULL_NGEN defined), it would result into inefficient code because of the instantiations
1528 // would be speculative. On CoreCLR (FEATURE_FULL_NGEN not defined), it would result into the instantiations not getting saved into native
1531 // Similar problem exists for Windows.Foundation.winmd. There is a cycle between Windows.Foundation.winmd and Windows.Storage.winmd. This cycle
1532 // would cause prefererred zap module for instantiations of foundation types (like IAsyncOperation<StorageFolder>) to be Windows.Foundation.winmd.
1533 // It is a bad choice. It should be Windows.Storage.winmd instead. We explicitly push Windows.Foundation to lower level by treating it as
1534 // low level system assembly to avoid this problem.
1536 if (pModule->IsLowLevelSystemAssemblyByName())
1538 if (!pOtherModule->IsLowLevelSystemAssemblyByName())
1541 // Every module depends upon mscorlib
1542 if (pModule->IsSystem())
1545 // mscorlib does not depend upon any other module
1546 if (pOtherModule->IsSystem())
1551 if (pOtherModule->IsLowLevelSystemAssemblyByName())
1555 // At this point neither pModule or pOtherModule is mscorlib
1557 #ifndef DACCESS_COMPILE
1559 // We will check to see if the pOtherModule has a reference to pModule
1562 // If we can match the assembly ref in the ManifestModuleReferencesMap we can early out.
1563 // This early out kicks in less than half of the time. It hurts performance on average.
1564 // if (!IsNilToken(pOtherModule->FindAssemblyRef(pModule->GetAssembly())))
1567 if (pOtherModule->HasReferenceByName(pModule->GetSimpleName()))
1569 #endif // DACCESS_COMPILE
1574 // Determine the "preferred ngen home" for an instantiated type or method
1575 // * This is the first ngen module that the loader will look in;
1576 // * Also, we only hard bind to a type or method that lives in its preferred module
1577 // The following properties must hold of the preferred module:
1578 // - it must be one of the component type's declaring modules
1579 // - if the type or method is open then the preferred module must be that of one of the type parameters
1580 // (this ensures that we can always hard bind to open types and methods created during ngen)
1581 // - for always-saved instantiations it must be the declaring module of the generic definition
1582 // Otherwise, we try to pick a module that is likely to reference the type or method
1585 PTR_Module Module::ComputePreferredZapModuleHelper(
1586 Module * pDefinitionModule, // the module that declares the generic type or method
1587 Instantiation classInst, // the type arguments to the type (if any)
1588 Instantiation methodInst) // the type arguments to the method (if any)
1590 CONTRACT(PTR_Module)
1596 PRECONDITION(CheckPointer(pDefinitionModule, NULL_OK));
1597 // One of them will be non-null... Note we don't use CheckPointer
1598 // because that raises a breakpoint in the debugger
1599 PRECONDITION(pDefinitionModule != NULL || !classInst.IsEmpty() || !methodInst.IsEmpty());
1600 POSTCONDITION(CheckPointer(RETVAL));
1605 DWORD totalArgs = classInst.GetNumArgs() + methodInst.GetNumArgs();
1607 // The open type parameters takes precendence over closed type parameters since
1608 // we always hardbind to open types.
1609 for (DWORD i = 0; i < totalArgs; i++)
1611 TypeHandle thArg = (i < classInst.GetNumArgs()) ? classInst[i] : methodInst[i - classInst.GetNumArgs()];
1613 // Encoded types are never open
1614 _ASSERTE(!thArg.IsEncodedFixup());
1615 Module * pOpenModule = thArg.GetDefiningModuleForOpenType();
1616 if (pOpenModule != NULL)
1617 RETURN dac_cast<PTR_Module>(pOpenModule);
1620 // The initial value of pCurrentPZM is the pDefinitionModule or mscorlib
1621 Module* pCurrentPZM = (pDefinitionModule != NULL) ? pDefinitionModule : MscorlibBinder::GetModule();
1622 bool preferredZapModuleBasedOnValueType = false;
1624 for (DWORD i = 0; i < totalArgs; i++)
1626 TypeHandle pTypeParam = (i < classInst.GetNumArgs()) ? classInst[i] : methodInst[i - classInst.GetNumArgs()];
1628 _ASSERTE(pTypeParam != NULL);
1629 _ASSERTE(!pTypeParam.IsEncodedFixup());
1631 Module * pParamPZM = GetPreferredZapModuleForTypeHandle(pTypeParam);
1634 // If pCurrentPZM is not a dependency of pParamPZM
1635 // then we aren't going to update pCurrentPZM
1637 if (IsLikelyDependencyOf(pCurrentPZM, pParamPZM))
1639 // If we have a type parameter that is a value type
1640 // and we don't yet have a value type based pCurrentPZM
1641 // then we will select it's module as the new pCurrentPZM.
1643 if (pTypeParam.IsValueType() && !preferredZapModuleBasedOnValueType)
1645 pCurrentPZM = pParamPZM;
1646 preferredZapModuleBasedOnValueType = true;
1650 // The normal rule is to replace the pCurrentPZM only when
1651 // both of the following are true:
1652 // pCurrentPZM is a dependency of pParamPZM
1653 // and pParamPZM is not a dependency of pCurrentPZM
1655 // note that the second condition is alway true when pCurrentPZM is mscorlib
1657 if (!IsLikelyDependencyOf(pParamPZM, pCurrentPZM))
1659 pCurrentPZM = pParamPZM;
1665 RETURN dac_cast<PTR_Module>(pCurrentPZM);
1668 PTR_Module Module::ComputePreferredZapModule(TypeKey *pKey)
1680 if (pKey->GetKind() == ELEMENT_TYPE_CLASS)
1682 return Module::ComputePreferredZapModule(pKey->GetModule(),
1683 pKey->GetInstantiation());
1685 else if (pKey->GetKind() != ELEMENT_TYPE_FNPTR)
1686 return Module::GetPreferredZapModuleForTypeHandle(pKey->GetElementType());
1692 /* see code:Module::ComputePreferredZapModuleHelper for more */
1694 PTR_Module Module::GetPreferredZapModuleForMethodTable(MethodTable *pMT)
1706 PTR_Module pRet=NULL;
1708 INTERIOR_STACK_PROBE_FOR_NOTHROW_CHECK_THREAD(10, NO_FORBIDGC_LOADER_USE_ThrowSO(););
1712 TypeHandle elemTH = pMT->GetApproxArrayElementTypeHandle();
1713 pRet= ComputePreferredZapModule(NULL, Instantiation(&elemTH, 1));
1715 else if (pMT->HasInstantiation() && !pMT->IsGenericTypeDefinition())
1717 pRet= ComputePreferredZapModule(pMT->GetModule(),
1718 pMT->GetInstantiation());
1722 // If it is uninstantiated or it is the generic type definition itself
1723 // then its loader module is simply the module containing its TypeDef
1724 pRet= pMT->GetModule();
1726 END_INTERIOR_STACK_PROBE;
1732 PTR_Module Module::GetPreferredZapModuleForTypeDesc(PTR_TypeDesc pTD)
1743 if (pTD->HasTypeParam())
1744 return GetPreferredZapModuleForTypeHandle(pTD->GetTypeParam());
1745 else if (pTD->IsGenericVariable())
1746 return pTD->GetModule();
1748 _ASSERTE(pTD->GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
1749 PTR_FnPtrTypeDesc pFnPtrTD = dac_cast<PTR_FnPtrTypeDesc>(pTD);
1751 // Result type of function type is used for preferred zap module
1752 return GetPreferredZapModuleForTypeHandle(pFnPtrTD->GetRetAndArgTypesPointer()[0]);
1756 PTR_Module Module::GetPreferredZapModuleForTypeHandle(TypeHandle t)
1768 return GetPreferredZapModuleForTypeDesc(t.AsTypeDesc());
1770 return GetPreferredZapModuleForMethodTable(t.AsMethodTable());
1774 PTR_Module Module::GetPreferredZapModuleForMethodDesc(const MethodDesc *pMD)
1785 if (pMD->IsTypicalMethodDefinition())
1787 return PTR_Module(pMD->GetModule());
1789 else if (pMD->IsGenericMethodDefinition())
1791 return GetPreferredZapModuleForMethodTable(pMD->GetMethodTable());
1795 return ComputePreferredZapModule(pMD->GetModule(),
1796 pMD->GetClassInstantiation(),
1797 pMD->GetMethodInstantiation());
1801 /* see code:Module::ComputePreferredZapModuleHelper for more */
1803 PTR_Module Module::GetPreferredZapModuleForFieldDesc(FieldDesc * pFD)
1814 // The approx MT is sufficient: it's always the one that owns the FieldDesc
1816 return GetPreferredZapModuleForMethodTable(pFD->GetApproxEnclosingMethodTable());
1818 #endif // FEATURE_PREJIT
1821 BOOL Module::IsEditAndContinueCapable(Assembly *pAssembly, PEFile *file)
1833 _ASSERTE(pAssembly != NULL && file != NULL);
1835 // Some modules are never EnC-capable
1836 return ! (pAssembly->GetDebuggerInfoBits() & DACF_ALLOW_JIT_OPTS ||
1837 pAssembly->IsDomainNeutral() ||
1839 file->IsResource() ||
1840 file->HasNativeImage() ||
1844 BOOL Module::IsManifest()
1846 WRAPPER_NO_CONTRACT;
1847 return dac_cast<TADDR>(GetAssembly()->GetManifestModule()) ==
1848 dac_cast<TADDR>(this);
1851 DomainAssembly* Module::GetDomainAssembly(AppDomain *pDomain)
1853 CONTRACT(DomainAssembly *)
1856 PRECONDITION(CheckPointer(pDomain, NULL_OK));
1857 POSTCONDITION(CheckPointer(RETVAL));
1865 RETURN (DomainAssembly *) GetDomainFile(pDomain);
1867 RETURN (DomainAssembly *) m_pAssembly->GetDomainAssembly(pDomain);
1870 DomainFile *Module::GetDomainFile(AppDomain *pDomain)
1872 CONTRACT(DomainFile *)
1875 PRECONDITION(CheckPointer(pDomain));
1876 POSTCONDITION(CheckPointer(RETVAL));
1884 if (Module::IsEncodedModuleIndex(GetModuleID()))
1886 DomainLocalBlock *pLocalBlock = pDomain->GetDomainLocalBlock();
1887 DomainFile *pDomainFile = pLocalBlock->TryGetDomainFile(GetModuleIndex());
1889 #if !defined(DACCESS_COMPILE) && defined(FEATURE_LOADER_OPTIMIZATION)
1890 if (pDomainFile == NULL)
1891 pDomainFile = pDomain->LoadDomainNeutralModuleDependency(this, FILE_LOADED);
1892 #endif // !DACCESS_COMPILE
1894 RETURN (PTR_DomainFile) pDomainFile;
1899 CONSISTENCY_CHECK(dac_cast<TADDR>(pDomain) == dac_cast<TADDR>(GetDomain()) || IsSingleAppDomain());
1900 RETURN dac_cast<PTR_DomainFile>(m_ModuleID->GetDomainFile());
1904 DomainAssembly* Module::FindDomainAssembly(AppDomain *pDomain)
1906 CONTRACT(DomainAssembly *)
1909 PRECONDITION(CheckPointer(pDomain));
1910 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1920 RETURN dac_cast<PTR_DomainAssembly>(FindDomainFile(pDomain));
1922 RETURN m_pAssembly->FindDomainAssembly(pDomain);
1925 DomainModule *Module::GetDomainModule(AppDomain *pDomain)
1927 CONTRACT(DomainModule *)
1930 PRECONDITION(CheckPointer(pDomain));
1931 PRECONDITION(!IsManifest());
1932 POSTCONDITION(CheckPointer(RETVAL));
1940 RETURN (DomainModule *) GetDomainFile(pDomain);
1943 DomainFile *Module::FindDomainFile(AppDomain *pDomain)
1945 CONTRACT(DomainFile *)
1948 PRECONDITION(CheckPointer(pDomain));
1949 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1958 if (Module::IsEncodedModuleIndex(GetModuleID()))
1960 DomainLocalBlock *pLocalBlock = pDomain->GetDomainLocalBlock();
1961 RETURN pLocalBlock->TryGetDomainFile(GetModuleIndex());
1965 if (dac_cast<TADDR>(pDomain) == dac_cast<TADDR>(GetDomain()) || IsSingleAppDomain())
1966 RETURN m_ModuleID->GetDomainFile();
1972 DomainModule *Module::FindDomainModule(AppDomain *pDomain)
1974 CONTRACT(DomainModule *)
1977 PRECONDITION(CheckPointer(pDomain));
1978 PRECONDITION(!IsManifest());
1979 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1986 RETURN (DomainModule *) FindDomainFile(pDomain);
1989 #ifndef DACCESS_COMPILE
1990 #include "staticallocationhelpers.inl"
1992 // Parses metadata and initializes offsets of per-class static blocks.
1993 void Module::BuildStaticsOffsets(AllocMemTracker *pamTracker)
1995 STANDARD_VM_CONTRACT;
1997 // Trade off here. We want a slot for each type. That way we can get to 2 bits per class and
1998 // index directly and not need a mapping from ClassID to MethodTable (we will use the RID
2000 IMDInternalImport *pImport = GetMDImport();
2002 DWORD * pRegularStaticOffsets = NULL;
2003 DWORD * pThreadStaticOffsets = NULL;
2005 // Get the number of types/classes defined in this module. Add 1 to count the module itself
2006 DWORD dwNumTypes = pImport->GetCountWithTokenKind(mdtTypeDef) + 1; // +1 for module type
2008 // [0] covers regular statics, [1] covers thread statics
2009 DWORD dwGCHandles[2] = { 0, 0 };
2011 // Organization in memory of the static block
2017 // | Class Data (one byte per class) | pointer to gc statics | primitive type statics |
2020 #ifndef CROSSBITNESS_COMPILE
2021 // The assertions must hold in every non-crossbitness scenario
2022 _ASSERTE(OFFSETOF__DomainLocalModule__m_pDataBlob_ == DomainLocalModule::OffsetOfDataBlob());
2023 _ASSERTE(OFFSETOF__ThreadLocalModule__m_pDataBlob == ThreadLocalModule::OffsetOfDataBlob());
2026 DWORD dwNonGCBytes[2] = {
2027 DomainLocalModule::OffsetOfDataBlob() + sizeof(BYTE)*dwNumTypes,
2028 ThreadLocalModule::OffsetOfDataBlob() + sizeof(BYTE)*dwNumTypes
2031 HENUMInternalHolder hTypeEnum(pImport);
2032 hTypeEnum.EnumAllInit(mdtTypeDef);
2035 // Parse each type of the class
2036 while (pImport->EnumNext(&hTypeEnum, &type))
2038 // Set offset for this type
2039 DWORD dwIndex = RidFromToken(type) - 1;
2041 // [0] covers regular statics, [1] covers thread statics
2042 DWORD dwAlignment[2] = { 1, 1 };
2043 DWORD dwClassNonGCBytes[2] = { 0, 0 };
2044 DWORD dwClassGCHandles[2] = { 0, 0 };
2046 // need to check if the type is generic and if so exclude it from iteration as we don't know the size
2047 HENUMInternalHolder hGenericEnum(pImport);
2048 hGenericEnum.EnumInit(mdtGenericParam, type);
2049 ULONG cGenericParams = pImport->EnumGetCount(&hGenericEnum);
2050 if (cGenericParams == 0)
2052 HENUMInternalHolder hFieldEnum(pImport);
2053 hFieldEnum.EnumInit(mdtFieldDef, type);
2056 // Parse each field of the type
2057 while (pImport->EnumNext(&hFieldEnum, &field))
2061 CorElementType ElementType = ELEMENT_TYPE_END;
2062 mdToken tkValueTypeToken = 0;
2063 int kk; // Use one set of variables for regular statics, and the other set for thread statics
2065 fSkip = GetStaticFieldElementTypeForFieldDef(this, pImport, field, &ElementType, &tkValueTypeToken, &kk);
2069 // We account for "regular statics" and "thread statics" separately.
2070 // Currently we are lumping RVA and context statics into "regular statics",
2071 // but we probably shouldn't.
2072 switch (ElementType)
2074 case ELEMENT_TYPE_I1:
2075 case ELEMENT_TYPE_U1:
2076 case ELEMENT_TYPE_BOOLEAN:
2077 dwClassNonGCBytes[kk] += 1;
2079 case ELEMENT_TYPE_I2:
2080 case ELEMENT_TYPE_U2:
2081 case ELEMENT_TYPE_CHAR:
2082 dwAlignment[kk] = max(2, dwAlignment[kk]);
2083 dwClassNonGCBytes[kk] += 2;
2085 case ELEMENT_TYPE_I4:
2086 case ELEMENT_TYPE_U4:
2087 case ELEMENT_TYPE_R4:
2088 dwAlignment[kk] = max(4, dwAlignment[kk]);
2089 dwClassNonGCBytes[kk] += 4;
2091 case ELEMENT_TYPE_FNPTR:
2092 case ELEMENT_TYPE_PTR:
2093 case ELEMENT_TYPE_I:
2094 case ELEMENT_TYPE_U:
2095 dwAlignment[kk] = max((1 << LOG2_PTRSIZE), dwAlignment[kk]);
2096 dwClassNonGCBytes[kk] += (1 << LOG2_PTRSIZE);
2098 case ELEMENT_TYPE_I8:
2099 case ELEMENT_TYPE_U8:
2100 case ELEMENT_TYPE_R8:
2101 dwAlignment[kk] = max(8, dwAlignment[kk]);
2102 dwClassNonGCBytes[kk] += 8;
2104 case ELEMENT_TYPE_VAR:
2105 case ELEMENT_TYPE_MVAR:
2106 case ELEMENT_TYPE_STRING:
2107 case ELEMENT_TYPE_SZARRAY:
2108 case ELEMENT_TYPE_ARRAY:
2109 case ELEMENT_TYPE_CLASS:
2110 case ELEMENT_TYPE_OBJECT:
2111 dwClassGCHandles[kk] += 1;
2113 case ELEMENT_TYPE_VALUETYPE:
2114 // Statics for valuetypes where the valuetype is defined in this module are handled here. Other valuetype statics utilize the pessimistic model below.
2115 dwClassGCHandles[kk] += 1;
2117 case ELEMENT_TYPE_END:
2119 // The actual element type was ELEMENT_TYPE_VALUETYPE, but the as we don't want to load additional assemblies
2120 // to determine these static offsets, we've fallen back to a pessimistic model.
2121 if (tkValueTypeToken != 0)
2123 // We'll have to be pessimistic here
2124 dwClassNonGCBytes[kk] += MAX_PRIMITIVE_FIELD_SIZE;
2125 dwAlignment[kk] = max(MAX_PRIMITIVE_FIELD_SIZE, dwAlignment[kk]);
2127 dwClassGCHandles[kk] += 1;
2132 // field has an unexpected type
2133 ThrowHR(VER_E_FIELD_SIG);
2139 if (pRegularStaticOffsets == NULL && (dwClassGCHandles[0] != 0 || dwClassNonGCBytes[0] != 0))
2141 // Lazily allocate table for offsets. We need offsets for GC and non GC areas. We add +1 to use as a sentinel.
2142 pRegularStaticOffsets = (PTR_DWORD)pamTracker->Track(
2143 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
2144 (S_SIZE_T(2 * sizeof(DWORD))*(S_SIZE_T(dwNumTypes)+S_SIZE_T(1)))));
2146 for (DWORD i = 0; i < dwIndex; i++) {
2147 pRegularStaticOffsets[i * 2 ] = dwGCHandles[0]*TARGET_POINTER_SIZE;
2148 pRegularStaticOffsets[i * 2 + 1] = dwNonGCBytes[0];
2152 if (pThreadStaticOffsets == NULL && (dwClassGCHandles[1] != 0 || dwClassNonGCBytes[1] != 0))
2154 // Lazily allocate table for offsets. We need offsets for GC and non GC areas. We add +1 to use as a sentinel.
2155 pThreadStaticOffsets = (PTR_DWORD)pamTracker->Track(
2156 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
2157 (S_SIZE_T(2 * sizeof(DWORD))*(S_SIZE_T(dwNumTypes)+S_SIZE_T(1)))));
2159 for (DWORD i = 0; i < dwIndex; i++) {
2160 pThreadStaticOffsets[i * 2 ] = dwGCHandles[1]*TARGET_POINTER_SIZE;
2161 pThreadStaticOffsets[i * 2 + 1] = dwNonGCBytes[1];
2166 if (pRegularStaticOffsets != NULL)
2168 // Align the offset of non gc statics
2169 dwNonGCBytes[0] = (DWORD) ALIGN_UP(dwNonGCBytes[0], dwAlignment[0]);
2171 // Save current offsets
2172 pRegularStaticOffsets[dwIndex*2] = dwGCHandles[0]*TARGET_POINTER_SIZE;
2173 pRegularStaticOffsets[dwIndex*2 + 1] = dwNonGCBytes[0];
2175 // Increment for next class
2176 dwGCHandles[0] += dwClassGCHandles[0];
2177 dwNonGCBytes[0] += dwClassNonGCBytes[0];
2180 if (pThreadStaticOffsets != NULL)
2182 // Align the offset of non gc statics
2183 dwNonGCBytes[1] = (DWORD) ALIGN_UP(dwNonGCBytes[1], dwAlignment[1]);
2185 // Save current offsets
2186 pThreadStaticOffsets[dwIndex*2] = dwGCHandles[1]*TARGET_POINTER_SIZE;
2187 pThreadStaticOffsets[dwIndex*2 + 1] = dwNonGCBytes[1];
2189 // Increment for next class
2190 dwGCHandles[1] += dwClassGCHandles[1];
2191 dwNonGCBytes[1] += dwClassNonGCBytes[1];
2195 m_maxTypeRidStaticsAllocated = dwNumTypes;
2197 if (pRegularStaticOffsets != NULL)
2199 pRegularStaticOffsets[dwNumTypes*2] = dwGCHandles[0]*TARGET_POINTER_SIZE;
2200 pRegularStaticOffsets[dwNumTypes*2 + 1] = dwNonGCBytes[0];
2203 if (pThreadStaticOffsets != NULL)
2205 pThreadStaticOffsets[dwNumTypes*2] = dwGCHandles[1]*TARGET_POINTER_SIZE;
2206 pThreadStaticOffsets[dwNumTypes*2 + 1] = dwNonGCBytes[1];
2209 m_pRegularStaticOffsets = pRegularStaticOffsets;
2210 m_pThreadStaticOffsets = pThreadStaticOffsets;
2212 m_dwMaxGCRegularStaticHandles = dwGCHandles[0];
2213 m_dwMaxGCThreadStaticHandles = dwGCHandles[1];
2215 m_dwRegularStaticsBlockSize = dwNonGCBytes[0];
2216 m_dwThreadStaticsBlockSize = dwNonGCBytes[1];
2219 void Module::GetOffsetsForRegularStaticData(
2221 BOOL bDynamic, DWORD dwGCStaticHandles,
2222 DWORD dwNonGCStaticBytes,
2223 DWORD * pOutStaticHandleOffset,
2224 DWORD * pOutNonGCStaticOffset)
2230 INJECT_FAULT(COMPlusThrowOM());
2234 *pOutStaticHandleOffset = 0;
2235 *pOutNonGCStaticOffset = 0;
2237 if (!dwGCStaticHandles && !dwNonGCStaticBytes)
2242 #ifndef CROSSBITNESS_COMPILE
2243 _ASSERTE(OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob == DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob());
2245 // Statics for instantiated types are allocated dynamically per-instantiation
2248 // Non GC statics are embedded in the Dynamic Entry.
2249 *pOutNonGCStaticOffset = OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob;
2253 if (m_pRegularStaticOffsets == NULL)
2255 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2257 _ASSERTE(m_pRegularStaticOffsets != (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED);
2259 // We allocate in the big blob.
2260 DWORD index = RidFromToken(cl) - 1;
2262 *pOutStaticHandleOffset = m_pRegularStaticOffsets[index*2];
2264 *pOutNonGCStaticOffset = m_pRegularStaticOffsets[index*2 + 1];
2265 #ifdef CROSSBITNESS_COMPILE
2266 *pOutNonGCStaticOffset += OFFSETOF__DomainLocalModule__m_pDataBlob_ - DomainLocalModule::OffsetOfDataBlob();
2269 // Check we didnt go out of what we predicted we would need for the class
2270 if (*pOutStaticHandleOffset + TARGET_POINTER_SIZE*dwGCStaticHandles >
2271 m_pRegularStaticOffsets[(index+1)*2] ||
2272 *pOutNonGCStaticOffset + dwNonGCStaticBytes >
2273 m_pRegularStaticOffsets[(index+1)*2 + 1])
2274 { // It's most likely that this is due to bad metadata, thus the exception. However, the
2275 // previous comments for this bit of code mentioned that this could be a corner case bug
2276 // with static field size estimation, though this is entirely unlikely since the code has
2277 // been this way for at least two releases.
2278 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2283 void Module::GetOffsetsForThreadStaticData(
2285 BOOL bDynamic, DWORD dwGCStaticHandles,
2286 DWORD dwNonGCStaticBytes,
2287 DWORD * pOutStaticHandleOffset,
2288 DWORD * pOutNonGCStaticOffset)
2294 INJECT_FAULT(COMPlusThrowOM());
2298 *pOutStaticHandleOffset = 0;
2299 *pOutNonGCStaticOffset = 0;
2301 if (!dwGCStaticHandles && !dwNonGCStaticBytes)
2306 #ifndef CROSSBITNESS_COMPILE
2307 _ASSERTE(OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob == ThreadLocalModule::DynamicEntry::GetOffsetOfDataBlob());
2309 // Statics for instantiated types are allocated dynamically per-instantiation
2312 // Non GC thread statics are embedded in the Dynamic Entry.
2313 *pOutNonGCStaticOffset = OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob;
2317 if (m_pThreadStaticOffsets == NULL)
2319 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2321 _ASSERTE(m_pThreadStaticOffsets != (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED);
2323 // We allocate in the big blob.
2324 DWORD index = RidFromToken(cl) - 1;
2326 *pOutStaticHandleOffset = m_pThreadStaticOffsets[index*2];
2328 *pOutNonGCStaticOffset = m_pThreadStaticOffsets[index*2 + 1];
2329 #ifdef CROSSBITNESS_COMPILE
2330 *pOutNonGCStaticOffset += OFFSETOF__ThreadLocalModule__m_pDataBlob - ThreadLocalModule::GetOffsetOfDataBlob();
2333 // Check we didnt go out of what we predicted we would need for the class
2334 if (*pOutStaticHandleOffset + TARGET_POINTER_SIZE*dwGCStaticHandles >
2335 m_pThreadStaticOffsets[(index+1)*2] ||
2336 *pOutNonGCStaticOffset + dwNonGCStaticBytes >
2337 m_pThreadStaticOffsets[(index+1)*2 + 1])
2339 // It's most likely that this is due to bad metadata, thus the exception. However, the
2340 // previous comments for this bit of code mentioned that this could be a corner case bug
2341 // with static field size estimation, though this is entirely unlikely since the code has
2342 // been this way for at least two releases.
2343 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2348 // initialize Crst controlling the Dynamic IL hashtable
2349 void Module::InitializeDynamicILCrst()
2351 Crst * pCrst = new Crst(CrstDynamicIL, CrstFlags(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD));
2352 if (InterlockedCompareExchangeT(
2353 &m_debuggerSpecificData.m_pDynamicILCrst, pCrst, NULL) != NULL)
2359 // Add a (token, address) pair to the table of IL blobs for reflection/dynamics
2362 // token method token
2363 // blobAddress address of the start of the IL blob address, including the header
2364 // fTemporaryOverride
2365 // is this a permanent override that should go in the
2366 // DynamicILBlobTable, or a temporary one?
2367 // Output: not explicit, but if the pair was not already in the table it will be added.
2368 // Does not add duplicate tokens to the table.
2370 void Module::SetDynamicIL(mdToken token, TADDR blobAddress, BOOL fTemporaryOverride)
2372 DynamicILBlobEntry entry = {mdToken(token), TADDR(blobAddress)};
2374 // Lazily allocate a Crst to serialize update access to the info structure.
2375 // Carefully synchronize to ensure we don't leak a Crst in race conditions.
2376 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2378 InitializeDynamicILCrst();
2381 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2383 // Figure out which table to fill in
2384 PTR_DynamicILBlobTable &table(fTemporaryOverride ? m_debuggerSpecificData.m_pTemporaryILBlobTable
2385 : m_debuggerSpecificData.m_pDynamicILBlobTable);
2387 // Lazily allocate the hash table.
2390 table = PTR_DynamicILBlobTable(new DynamicILBlobTable);
2392 table->AddOrReplace(entry);
2395 #endif // !DACCESS_COMPILE
2397 // Get the stored address of the IL blob for reflection/dynamics
2400 // token method token
2401 // fAllowTemporary also check the temporary overrides
2402 // Return Value: starting (target) address of the IL blob corresponding to the input token
2404 TADDR Module::GetDynamicIL(mdToken token, BOOL fAllowTemporary)
2408 #ifndef DACCESS_COMPILE
2409 // The Crst to serialize update access to the info structure is lazily allocated.
2410 // If it hasn't been allocated yet, then we don't have any IL blobs (temporary or otherwise)
2411 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2416 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2419 // Both hash tables are lazily allocated, so if they're NULL
2420 // then we have no IL blobs
2422 if (fAllowTemporary && m_debuggerSpecificData.m_pTemporaryILBlobTable != NULL)
2424 DynamicILBlobEntry entry = m_debuggerSpecificData.m_pTemporaryILBlobTable->Lookup(token);
2426 // Only return a value if the lookup succeeded
2427 if (!DynamicILBlobTraits::IsNull(entry))
2433 if (m_debuggerSpecificData.m_pDynamicILBlobTable == NULL)
2438 DynamicILBlobEntry entry = m_debuggerSpecificData.m_pDynamicILBlobTable->Lookup(token);
2439 // If the lookup fails, it returns the 'NULL' entry
2440 // The 'NULL' entry has m_il set to NULL, so either way we're safe
2444 #if !defined(DACCESS_COMPILE)
2445 //---------------------------------------------------------------------------------------
2447 // Add instrumented IL offset mapping for the specified method.
2450 // token - the MethodDef token of the method in question
2451 // mapping - the mapping information between original IL offsets and instrumented IL offsets
2454 // * Once added, the mapping stays valid until the Module containing the method is destructed.
2455 // * The profiler may potentially update the mapping more than once.
2458 void Module::SetInstrumentedILOffsetMapping(mdMethodDef token, InstrumentedILOffsetMapping mapping)
2460 ILOffsetMappingEntry entry(token, mapping);
2462 // Lazily allocate a Crst to serialize update access to the hash table.
2463 // Carefully synchronize to ensure we don't leak a Crst in race conditions.
2464 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2466 InitializeDynamicILCrst();
2469 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2471 // Lazily allocate the hash table.
2472 if (m_debuggerSpecificData.m_pILOffsetMappingTable == NULL)
2474 m_debuggerSpecificData.m_pILOffsetMappingTable = PTR_ILOffsetMappingTable(new ILOffsetMappingTable);
2477 ILOffsetMappingEntry currentEntry = m_debuggerSpecificData.m_pILOffsetMappingTable->Lookup(ILOffsetMappingTraits::GetKey(entry));
2478 if (!ILOffsetMappingTraits::IsNull(currentEntry))
2479 currentEntry.m_mapping.Clear();
2481 m_debuggerSpecificData.m_pILOffsetMappingTable->AddOrReplace(entry);
2483 #endif // DACCESS_COMPILE
2485 //---------------------------------------------------------------------------------------
2487 // Retrieve the instrumented IL offset mapping for the specified method.
2490 // token - the MethodDef token of the method in question
2493 // Return the mapping information between original IL offsets and instrumented IL offsets.
2494 // Check InstrumentedILOffsetMapping::IsNull() to see if any mapping is available.
2497 // * Once added, the mapping stays valid until the Module containing the method is destructed.
2498 // * The profiler may potentially update the mapping more than once.
2501 InstrumentedILOffsetMapping Module::GetInstrumentedILOffsetMapping(mdMethodDef token)
2512 // Lazily allocate a Crst to serialize update access to the hash table.
2513 // If the Crst is NULL, then we couldn't possibly have added any mapping yet, so just return NULL.
2514 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2516 InstrumentedILOffsetMapping emptyMapping;
2517 return emptyMapping;
2520 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2522 // If the hash table hasn't been created, then we couldn't possibly have added any mapping yet,
2523 // so just return NULL.
2524 if (m_debuggerSpecificData.m_pILOffsetMappingTable == NULL)
2526 InstrumentedILOffsetMapping emptyMapping;
2527 return emptyMapping;
2530 ILOffsetMappingEntry entry = m_debuggerSpecificData.m_pILOffsetMappingTable->Lookup(token);
2531 return entry.m_mapping;
2534 #undef DECODE_TYPEID
2535 #undef ENCODE_TYPEID
2536 #undef IS_ENCODED_TYPEID
2540 #ifndef DACCESS_COMPILE
2543 BOOL Module::IsNoStringInterning()
2552 if (!(m_dwPersistedFlags & COMPUTED_STRING_INTERNING))
2554 // The flags should be precomputed in native images
2555 _ASSERTE(!HasNativeImage());
2557 // Default is string interning
2558 BOOL fNoStringInterning = FALSE;
2562 // This flag applies to assembly, but it is stored on module so it can be cached in ngen image
2563 // Thus, we should ever need it for manifest module only.
2564 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2568 IfFailThrow(mdImport->GetAssemblyFromScope(&token));
2573 hr = mdImport->GetCustomAttributeByName(token,
2574 COMPILATIONRELAXATIONS_TYPE,
2575 (const void**)&pVal, &cbVal);
2577 // Parse the attribute
2580 CustomAttributeParser cap(pVal, cbVal);
2581 IfFailThrow(cap.SkipProlog());
2585 IfFailThrow(cap.GetU4(&flags));
2587 if (flags & CompilationRelaxations_NoStringInterning)
2589 fNoStringInterning = TRUE;
2594 static ConfigDWORD g_NoStringInterning;
2595 DWORD dwOverride = g_NoStringInterning.val(CLRConfig::INTERNAL_NoStringInterning);
2597 if (dwOverride == 0)
2600 fNoStringInterning = FALSE;
2602 else if (dwOverride == 2)
2604 // Always true (testing)
2605 fNoStringInterning = TRUE;
2609 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_STRING_INTERNING |
2610 (fNoStringInterning ? NO_STRING_INTERNING : 0));
2613 return !!(m_dwPersistedFlags & NO_STRING_INTERNING);
2616 BOOL Module::GetNeutralResourcesLanguage(LPCUTF8 * cultureName, ULONG * cultureNameLength, INT16 * fallbackLocation, BOOL cacheAttribute)
2618 STANDARD_VM_CONTRACT;
2620 BOOL retVal = FALSE;
2621 if (!(m_dwPersistedFlags & NEUTRAL_RESOURCES_LANGUAGE_IS_CACHED))
2623 const BYTE *pVal = NULL;
2626 // This flag applies to assembly, but it is stored on module so it can be cached in ngen image
2627 // Thus, we should ever need it for manifest module only.
2628 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2632 IfFailThrow(mdImport->GetAssemblyFromScope(&token));
2634 // Check for the existance of the attribute.
2635 HRESULT hr = mdImport->GetCustomAttributeByName(token,"System.Resources.NeutralResourcesLanguageAttribute",(const void **)&pVal, &cbVal);
2638 // we should not have a native image (it would have been cached at ngen time)
2639 _ASSERTE(!HasNativeImage());
2641 CustomAttributeParser cap(pVal, cbVal);
2642 IfFailThrow(cap.SkipProlog());
2643 IfFailThrow(cap.GetString(cultureName, cultureNameLength));
2644 IfFailThrow(cap.GetI2(fallbackLocation));
2645 // Should only be true on Module.Save(). Update flag to show we have the attribute cached
2647 FastInterlockOr(&m_dwPersistedFlags, NEUTRAL_RESOURCES_LANGUAGE_IS_CACHED);
2654 *cultureName = m_pszCultureName;
2655 *cultureNameLength = m_CultureNameLength;
2656 *fallbackLocation = m_FallbackLocation;
2660 // confirm that the NGENed attribute is correct
2661 LPCUTF8 pszCultureNameCheck = NULL;
2662 ULONG cultureNameLengthCheck = 0;
2663 INT16 fallbackLocationCheck = 0;
2664 const BYTE *pVal = NULL;
2667 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2670 IfFailThrow(mdImport->GetAssemblyFromScope(&token));
2672 // Confirm that the attribute exists, and has the save value as when we ngen'd it
2673 HRESULT hr = mdImport->GetCustomAttributeByName(token,"System.Resources.NeutralResourcesLanguageAttribute",(const void **)&pVal, &cbVal);
2674 _ASSERTE(hr == S_OK);
2675 CustomAttributeParser cap(pVal, cbVal);
2676 IfFailThrow(cap.SkipProlog());
2677 IfFailThrow(cap.GetString(&pszCultureNameCheck, &cultureNameLengthCheck));
2678 IfFailThrow(cap.GetI2(&fallbackLocationCheck));
2679 _ASSERTE(cultureNameLengthCheck == m_CultureNameLength);
2680 _ASSERTE(fallbackLocationCheck == m_FallbackLocation);
2681 _ASSERTE(strncmp(pszCultureNameCheck,m_pszCultureName,m_CultureNameLength) == 0);
2689 BOOL Module::HasDefaultDllImportSearchPathsAttribute()
2699 if(IsDefaultDllImportSearchPathsAttributeCached())
2701 return (m_dwPersistedFlags & DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS) != 0 ;
2703 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2705 BOOL attributeIsFound = FALSE;
2706 attributeIsFound = GetDefaultDllImportSearchPathsAttributeValue(mdImport, TokenFromRid(1, mdtAssembly),&m_DefaultDllImportSearchPathsAttributeValue);
2707 if(attributeIsFound)
2709 FastInterlockOr(&m_dwPersistedFlags, DEFAULT_DLL_IMPORT_SEARCH_PATHS_IS_CACHED | DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS);
2713 FastInterlockOr(&m_dwPersistedFlags, DEFAULT_DLL_IMPORT_SEARCH_PATHS_IS_CACHED);
2716 return (m_dwPersistedFlags & DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS) != 0 ;
2719 // Returns a BOOL to indicate if we have computed whether compiler has instructed us to
2720 // wrap the non-CLS compliant exceptions or not.
2721 BOOL Module::IsRuntimeWrapExceptionsStatusComputed()
2723 LIMITED_METHOD_CONTRACT;
2725 return (m_dwPersistedFlags & COMPUTED_WRAP_EXCEPTIONS);
2728 BOOL Module::IsRuntimeWrapExceptions()
2733 if (IsRuntimeWrapExceptionsStatusComputed()) GC_NOTRIGGER; else GC_TRIGGERS;
2738 if (!(IsRuntimeWrapExceptionsStatusComputed()))
2740 // The flags should be precomputed in native images
2741 _ASSERTE(!HasNativeImage());
2744 BOOL fRuntimeWrapExceptions = FALSE;
2746 // This flag applies to assembly, but it is stored on module so it can be cached in ngen image
2747 // Thus, we should ever need it for manifest module only.
2748 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2751 IfFailGo(mdImport->GetAssemblyFromScope(&token));
2756 hr = mdImport->GetCustomAttributeByName(token,
2757 RUNTIMECOMPATIBILITY_TYPE,
2758 (const void**)&pVal, &cbVal);
2760 // Parse the attribute
2763 CustomAttributeParser ca(pVal, cbVal);
2764 CaNamedArg namedArgs[1] = {{0}};
2766 // First, the void constructor:
2767 IfFailGo(ParseKnownCaArgs(ca, NULL, 0));
2769 // Then, find the named argument
2770 namedArgs[0].InitBoolField("WrapNonExceptionThrows");
2772 IfFailGo(ParseKnownCaNamedArgs(ca, namedArgs, lengthof(namedArgs)));
2774 if (namedArgs[0].val.boolean)
2775 fRuntimeWrapExceptions = TRUE;
2778 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_WRAP_EXCEPTIONS |
2779 (fRuntimeWrapExceptions ? WRAP_EXCEPTIONS : 0));
2782 return !!(m_dwPersistedFlags & WRAP_EXCEPTIONS);
2785 BOOL Module::IsPreV4Assembly()
2795 if (!(m_dwPersistedFlags & COMPUTED_IS_PRE_V4_ASSEMBLY))
2797 // The flags should be precomputed in native images
2798 _ASSERTE(!HasNativeImage());
2800 IMDInternalImport *pImport = GetAssembly()->GetManifestImport();
2803 BOOL fIsPreV4Assembly = FALSE;
2804 LPCSTR szVersion = NULL;
2805 if (SUCCEEDED(pImport->GetVersionString(&szVersion)))
2807 if (szVersion != NULL && strlen(szVersion) > 2)
2809 fIsPreV4Assembly = (szVersion[0] == 'v' || szVersion[0] == 'V') &&
2810 (szVersion[1] == '1' || szVersion[1] == '2');
2814 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_IS_PRE_V4_ASSEMBLY |
2815 (fIsPreV4Assembly ? IS_PRE_V4_ASSEMBLY : 0));
2818 return !!(m_dwPersistedFlags & IS_PRE_V4_ASSEMBLY);
2822 ArrayDPTR(RelativeFixupPointer<PTR_MethodTable>) ModuleCtorInfo::GetGCStaticMTs(DWORD index)
2824 LIMITED_METHOD_CONTRACT;
2826 if (index < numHotGCStaticsMTs)
2828 _ASSERTE(ppHotGCStaticsMTs != NULL);
2830 return ppHotGCStaticsMTs + index;
2834 _ASSERTE(ppColdGCStaticsMTs != NULL);
2836 // shift the start of the cold table because all cold offsets are also shifted
2837 return ppColdGCStaticsMTs + (index - numHotGCStaticsMTs);
2841 DWORD Module::AllocateDynamicEntry(MethodTable *pMT)
2847 PRECONDITION(pMT->GetModuleForStatics() == this);
2848 PRECONDITION(pMT->IsDynamicStatics());
2849 PRECONDITION(!pMT->ContainsGenericVariables());
2853 DWORD newId = FastInterlockExchangeAdd((LONG*)&m_cDynamicEntries, 1);
2855 if (newId >= m_maxDynamicEntries)
2857 CrstHolder ch(&m_Crst);
2859 if (newId >= m_maxDynamicEntries)
2861 SIZE_T maxDynamicEntries = max(16, m_maxDynamicEntries);
2862 while (maxDynamicEntries <= newId)
2864 maxDynamicEntries *= 2;
2867 DynamicStaticsInfo* pNewDynamicStaticsInfo = (DynamicStaticsInfo*)
2868 (void*)GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(DynamicStaticsInfo)) * S_SIZE_T(maxDynamicEntries));
2870 if (m_pDynamicStaticsInfo)
2871 memcpy(pNewDynamicStaticsInfo, m_pDynamicStaticsInfo, sizeof(DynamicStaticsInfo) * m_maxDynamicEntries);
2873 m_pDynamicStaticsInfo = pNewDynamicStaticsInfo;
2874 m_maxDynamicEntries = maxDynamicEntries;
2878 EnsureWritablePages(&(m_pDynamicStaticsInfo[newId]))->pEnclosingMT = pMT;
2880 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Assigned dynamic ID %d to %s\n", newId, pMT->GetDebugClassName()));
2885 void Module::FreeModuleIndex()
2894 if (GetAssembly()->IsDomainNeutral())
2896 // We do not recycle ModuleIndexes used by domain neutral Modules.
2900 if (m_ModuleID != NULL)
2902 // Module's m_ModuleID should not contain the ID, it should
2903 // contain a pointer to the DLM
2904 _ASSERTE(!Module::IsEncodedModuleIndex((SIZE_T)m_ModuleID));
2905 _ASSERTE(m_ModuleIndex == m_ModuleID->GetModuleIndex());
2907 // Get the ModuleIndex from the DLM and free it
2908 Module::FreeModuleIndex(m_ModuleIndex);
2912 // This was an empty, short-lived Module object that
2913 // was never assigned a ModuleIndex...
2921 ModuleIndex Module::AllocateModuleIndex()
2924 g_pModuleIndexDispenser->NewId(NULL, val);
2926 // For various reasons, the IDs issued by the IdDispenser start at 1.
2927 // Domain neutral module IDs have historically started at 0, and we
2928 // have always assigned ID 0 to mscorlib. Thus, to make it so that
2929 // domain neutral module IDs start at 0, we will subtract 1 from the
2930 // ID that we got back from the ID dispenser.
2931 ModuleIndex index((SIZE_T)(val-1));
2936 void Module::FreeModuleIndex(ModuleIndex index)
2938 WRAPPER_NO_CONTRACT;
2939 // We subtracted 1 after we allocated this ID, so we need to
2940 // add 1 before we free it.
2941 DWORD val = index.m_dwIndex + 1;
2943 g_pModuleIndexDispenser->DisposeId(val);
2947 void Module::AllocateRegularStaticHandles(AppDomain* pDomain)
2956 #ifndef CROSSGEN_COMPILE
2957 if (NingenEnabled())
2960 // Allocate the handles we will need. Note that AllocateStaticFieldObjRefPtrs will only
2961 // allocate if pModuleData->GetGCStaticsBasePointerAddress(pMT) != 0, avoiding creating
2962 // handles more than once for a given MT or module
2964 DomainLocalModule *pModuleData = GetDomainLocalModule(pDomain);
2966 _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointerAddress() != NULL);
2967 if (this->m_dwMaxGCRegularStaticHandles > 0)
2969 // If we're setting up a non-default domain, we want the allocation to look like it's
2970 // coming from the created domain.
2972 // REVISIT_TODO: The comparison "pDomain != GetDomain()" will always be true for domain-neutral
2973 // modules, since GetDomain() will return the SharedDomain, which is NOT an AppDomain.
2974 // Was this intended? If so, there should be a clarifying comment. If not, then we should
2975 // probably do "pDomain != GetAppDomain()" instead.
2977 if (pDomain != GetDomain() &&
2978 pDomain != SystemDomain::System()->DefaultDomain() &&
2981 pDomain->AllocateStaticFieldObjRefPtrsCrossDomain(this->m_dwMaxGCRegularStaticHandles,
2982 pModuleData->GetPrecomputedGCStaticsBasePointerAddress());
2986 pDomain->AllocateStaticFieldObjRefPtrs(this->m_dwMaxGCRegularStaticHandles,
2987 pModuleData->GetPrecomputedGCStaticsBasePointerAddress());
2990 // We should throw if we fail to allocate and never hit this assert
2991 _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointer() != NULL);
2993 #endif // CROSSGEN_COMPILE
2996 BOOL Module::IsStaticStoragePrepared(mdTypeDef tkType)
2998 LIMITED_METHOD_CONTRACT;
3000 // Right now the design is that we do one static allocation pass during NGEN,
3001 // and a 2nd pass for it at module init time for modules that weren't NGENed or the NGEN
3002 // pass was unsucessful. If we are loading types after that then we must use dynamic
3003 // static storage. These dynamic statics require an additional indirection so they
3004 // don't perform quite as well.
3006 // This check was created for the scenario where a profiler adds additional types
3007 // however it seems likely this check would also accurately handle other dynamic
3008 // scenarios such as ref.emit and EnC as long as they are adding new types and
3009 // not new statics to existing types.
3010 _ASSERTE(TypeFromToken(tkType) == mdtTypeDef);
3011 return m_maxTypeRidStaticsAllocated >= RidFromToken(tkType);
3014 void Module::AllocateStatics(AllocMemTracker *pamTracker)
3016 STANDARD_VM_CONTRACT;
3020 m_dwRegularStaticsBlockSize = DomainLocalModule::OffsetOfDataBlob();
3021 m_dwThreadStaticsBlockSize = ThreadLocalModule::OffsetOfDataBlob();
3023 // If it has no code, we don't have to allocate anything
3024 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Resource module %s. No statics neeeded\n", GetSimpleName()));
3025 _ASSERTE(m_maxTypeRidStaticsAllocated == 0);
3028 #ifdef FEATURE_PREJIT
3029 if (m_pRegularStaticOffsets == (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED)
3031 _ASSERTE(HasNativeImage());
3033 // This is an ngen image and all the classes were loaded at ngen time, so we're done.
3034 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: 'Complete' Native image found, no statics parsing needed for module %s.\n", GetSimpleName()));
3035 // typeDefs rids 0 and 1 aren't included in the count, thus X typeDefs means rid X+1 is valid
3036 _ASSERTE(m_maxTypeRidStaticsAllocated == GetMDImport()->GetCountWithTokenKind(mdtTypeDef) + 1);
3040 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Allocating statics for module %s\n", GetSimpleName()));
3042 // Build the offset table, which will tell us what the offsets for the statics of each class are (one offset for gc handles, one offset
3043 // for non gc types)
3044 BuildStaticsOffsets(pamTracker);
3047 // This method will report GC static refs of the module. It doesn't have to be complete (ie, it's
3048 // currently used to opportunistically get more concurrency in the marking of statics), so it currently
3049 // ignores any statics that are not preallocated (ie: won't report statics from IsDynamicStatics() MT)
3050 // The reason this function is in Module and not in DomainFile (together with DomainLocalModule is because
3051 // for shared modules we need a very fast way of getting to the DomainLocalModule. For that we use
3052 // a table in DomainLocalBlock that's indexed with a module ID
3054 // This method is a secondary way for the GC to find statics, and it is only used when we are on
3055 // a multiproc machine and we are using the ServerHeap. The primary way used by the GC to find
3056 // statics is through the handle table. Module::AllocateRegularStaticHandles() allocates a GC handle
3057 // from the handle table, and the GC will trace this handle and find the statics.
3059 void Module::EnumRegularStaticGCRefs(AppDomain* pAppDomain, promote_func* fn, ScanContext* sc)
3068 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
3069 GCHeapUtilities::IsServerHeap() &&
3070 IsGCSpecialThread());
3073 DomainLocalModule *pModuleData = GetDomainLocalModule(pAppDomain);
3074 DWORD dwHandles = m_dwMaxGCRegularStaticHandles;
3081 LOG((LF_GC, LL_INFO100, "Scanning statics for module %s\n", GetSimpleName()));
3083 OBJECTREF* ppObjectRefs = pModuleData->GetPrecomputedGCStaticsBasePointer();
3084 for (DWORD i = 0 ; i < dwHandles ; i++)
3086 // Handles are allocated in SetDomainFile (except for bootstrapped mscorlib). In any
3087 // case, we shouldnt get called if the module hasn't had it's handles allocated (as we
3088 // only get here if IsActive() is true, which only happens after SetDomainFile(), which
3089 // is were we allocate handles.
3090 _ASSERTE(ppObjectRefs);
3091 fn((Object **)(ppObjectRefs+i), sc, 0);
3094 LOG((LF_GC, LL_INFO100, "Done scanning statics for module %s\n", GetSimpleName()));
3099 void Module::SetDomainFile(DomainFile *pDomainFile)
3104 PRECONDITION(CheckPointer(pDomainFile));
3105 PRECONDITION(IsManifest() == pDomainFile->IsAssembly());
3112 DomainLocalModule* pModuleData = 0;
3114 // Do we need to allocate memory for the non GC statics?
3115 if ((GetAssembly()->IsDomainNeutral() && !IsSingleAppDomain())|| m_ModuleID == NULL)
3117 // Allocate memory for the module statics.
3118 LoaderAllocator *pLoaderAllocator = NULL;
3119 if (GetAssembly()->IsCollectible())
3121 pLoaderAllocator = GetAssembly()->GetLoaderAllocator();
3125 pLoaderAllocator = pDomainFile->GetAppDomain()->GetLoaderAllocator();
3128 SIZE_T size = GetDomainLocalModuleSize();
3130 LOG((LF_CLASSLOADER, LL_INFO10, "STATICS: Allocating %i bytes for precomputed statics in module %S in LoaderAllocator %p\n",
3131 size, this->GetDebugName(), pLoaderAllocator));
3133 // We guarantee alignment for 64-bit regular statics on 32-bit platforms even without FEATURE_64BIT_ALIGNMENT for performance reasons.
3135 _ASSERTE(size >= DomainLocalModule::OffsetOfDataBlob());
3137 pModuleData = (DomainLocalModule*)(void*)
3138 pLoaderAllocator->GetHighFrequencyHeap()->AllocAlignedMem(
3139 size, MAX_PRIMITIVE_FIELD_SIZE);
3141 // Note: Memory allocated on loader heap is zero filled
3142 // memset(pModuleData, 0, size);
3144 // Verify that the space is really zero initialized
3145 _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointer() == NULL);
3147 // Make sure that the newly allocated DomainLocalModule gets
3148 // a copy of the domain-neutral module ID.
3149 if (GetAssembly()->IsDomainNeutral() && !IsSingleAppDomain())
3151 // If the module was loaded as domain-neutral, we can find the ID by
3152 // casting 'm_ModuleID'.
3154 _ASSERTE(Module::IDToIndex((SIZE_T)m_ModuleID) == this->m_ModuleIndex);
3155 pModuleData->m_ModuleIndex = Module::IDToIndex((SIZE_T)m_ModuleID);
3157 // Eventually I want to just do this instead...
3158 //pModuleData->m_ModuleIndex = this->m_ModuleIndex;
3162 // If the module was loaded as domain-specific, then we need to assign
3163 // this module a domain-neutral module ID.
3164 pModuleData->m_ModuleIndex = Module::AllocateModuleIndex();
3165 m_ModuleIndex = pModuleData->m_ModuleIndex;
3170 pModuleData = this->m_ModuleID;
3171 LOG((LF_CLASSLOADER, LL_INFO10, "STATICS: Allocation not needed for ngened non shared module %s in Appdomain %08x\n"));
3174 if (GetAssembly()->IsDomainNeutral() && !IsSingleAppDomain())
3176 DomainLocalBlock *pLocalBlock;
3178 pLocalBlock = pDomainFile->GetAppDomain()->GetDomainLocalBlock();
3179 pLocalBlock->SetModuleSlot(GetModuleIndex(), pModuleData);
3182 pLocalBlock->SetDomainFile(GetModuleIndex(), pDomainFile);
3186 // Non shared case, module points directly to the statics. In ngen case
3187 // m_pDomainModule is already set for the non shared case
3188 if (m_ModuleID == NULL)
3190 m_ModuleID = pModuleData;
3193 m_ModuleID->SetDomainFile(pDomainFile);
3196 // Allocate static handles now.
3197 // NOTE: Bootstrapping issue with mscorlib - we will manually allocate later
3198 // If the assembly is collectible, we don't initialize static handles for them
3199 // as it is currently initialized through the DomainLocalModule::PopulateClass in MethodTable::CheckRunClassInitThrowing
3200 // (If we don't do this, it would allocate here unused regular static handles that will be overridden later)
3201 if (g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] != NULL && !GetAssembly()->IsCollectible())
3202 AllocateRegularStaticHandles(pDomainFile->GetAppDomain());
3205 #ifndef CROSSGEN_COMPILE
3206 OBJECTREF Module::GetExposedObject()
3211 POSTCONDITION(RETVAL != NULL);
3218 RETURN GetDomainFile()->GetExposedModuleObject();
3220 #endif // CROSSGEN_COMPILE
3223 // AllocateMap allocates the RID maps based on the size of the current
3224 // metadata (if any)
3227 void Module::AllocateMaps()
3240 TYPEDEF_MAP_INITIAL_SIZE = 5,
3241 TYPEREF_MAP_INITIAL_SIZE = 5,
3242 MEMBERDEF_MAP_INITIAL_SIZE = 10,
3243 GENERICPARAM_MAP_INITIAL_SIZE = 5,
3244 GENERICTYPEDEF_MAP_INITIAL_SIZE = 5,
3245 FILEREFERENCES_MAP_INITIAL_SIZE = 5,
3246 ASSEMBLYREFERENCES_MAP_INITIAL_SIZE = 5,
3249 PTR_TADDR pTable = NULL;
3256 // For dynamic modules, it is essential that we at least have a TypeDefToMethodTable
3257 // map with an initial block. Otherwise, all the iterators will abort on an
3258 // initial empty table and we will e.g. corrupt the backpatching chains during
3259 // an appdomain unload.
3260 m_TypeDefToMethodTableMap.dwCount = TYPEDEF_MAP_INITIAL_SIZE;
3262 // The above is essential. The following ones are precautionary.
3263 m_TypeRefToMethodTableMap.dwCount = TYPEREF_MAP_INITIAL_SIZE;
3264 m_MethodDefToDescMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE;
3265 m_FieldDefToDescMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE;
3266 m_GenericParamToDescMap.dwCount = GENERICPARAM_MAP_INITIAL_SIZE;
3267 m_GenericTypeDefToCanonMethodTableMap.dwCount = TYPEDEF_MAP_INITIAL_SIZE;
3268 m_FileReferencesMap.dwCount = FILEREFERENCES_MAP_INITIAL_SIZE;
3269 m_ManifestModuleReferencesMap.dwCount = ASSEMBLYREFERENCES_MAP_INITIAL_SIZE;
3270 m_MethodDefToPropertyInfoMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE;
3274 IMDInternalImport * pImport = GetMDImport();
3276 // Get # TypeDefs (add 1 for COR_GLOBAL_PARENT_TOKEN)
3277 m_TypeDefToMethodTableMap.dwCount = pImport->GetCountWithTokenKind(mdtTypeDef)+2;
3280 m_TypeRefToMethodTableMap.dwCount = pImport->GetCountWithTokenKind(mdtTypeRef)+1;
3283 m_MethodDefToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtMethodDef)+1;
3286 m_FieldDefToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtFieldDef)+1;
3288 // Get # GenericParams
3289 m_GenericParamToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtGenericParam)+1;
3291 // Get the number of FileReferences in the map
3292 m_FileReferencesMap.dwCount = pImport->GetCountWithTokenKind(mdtFile)+1;
3294 // Get the number of AssemblyReferences in the map
3295 m_ManifestModuleReferencesMap.dwCount = pImport->GetCountWithTokenKind(mdtAssemblyRef)+1;
3297 // These maps are only added to during NGen, so for other scenarios leave them empty
3298 if (IsCompilationProcess())
3300 m_GenericTypeDefToCanonMethodTableMap.dwCount = m_TypeDefToMethodTableMap.dwCount;
3301 m_MethodDefToPropertyInfoMap.dwCount = m_MethodDefToDescMap.dwCount;
3305 m_GenericTypeDefToCanonMethodTableMap.dwCount = 0;
3306 m_MethodDefToPropertyInfoMap.dwCount = 0;
3312 nTotal += m_TypeDefToMethodTableMap.dwCount;
3313 nTotal += m_TypeRefToMethodTableMap.dwCount;
3314 nTotal += m_MethodDefToDescMap.dwCount;
3315 nTotal += m_FieldDefToDescMap.dwCount;
3316 nTotal += m_GenericParamToDescMap.dwCount;
3317 nTotal += m_GenericTypeDefToCanonMethodTableMap.dwCount;
3318 nTotal += m_FileReferencesMap.dwCount;
3319 nTotal += m_ManifestModuleReferencesMap.dwCount;
3320 nTotal += m_MethodDefToPropertyInfoMap.dwCount;
3322 _ASSERTE (m_pAssembly && m_pAssembly->GetLowFrequencyHeap());
3323 pTable = (PTR_TADDR)(void*)m_pAssembly->GetLowFrequencyHeap()->AllocMem(nTotal * S_SIZE_T(sizeof(TADDR)));
3325 // Note: Memory allocated on loader heap is zero filled
3326 // memset(pTable, 0, nTotal * sizeof(void*));
3328 m_TypeDefToMethodTableMap.pNext = NULL;
3329 m_TypeDefToMethodTableMap.supportedFlags = TYPE_DEF_MAP_ALL_FLAGS;
3330 m_TypeDefToMethodTableMap.pTable = pTable;
3332 m_TypeRefToMethodTableMap.pNext = NULL;
3333 m_TypeRefToMethodTableMap.supportedFlags = TYPE_REF_MAP_ALL_FLAGS;
3334 m_TypeRefToMethodTableMap.pTable = &pTable[m_TypeDefToMethodTableMap.dwCount];
3336 m_MethodDefToDescMap.pNext = NULL;
3337 m_MethodDefToDescMap.supportedFlags = METHOD_DEF_MAP_ALL_FLAGS;
3338 m_MethodDefToDescMap.pTable = &m_TypeRefToMethodTableMap.pTable[m_TypeRefToMethodTableMap.dwCount];
3340 m_FieldDefToDescMap.pNext = NULL;
3341 m_FieldDefToDescMap.supportedFlags = FIELD_DEF_MAP_ALL_FLAGS;
3342 m_FieldDefToDescMap.pTable = &m_MethodDefToDescMap.pTable[m_MethodDefToDescMap.dwCount];
3344 m_GenericParamToDescMap.pNext = NULL;
3345 m_GenericParamToDescMap.supportedFlags = GENERIC_PARAM_MAP_ALL_FLAGS;
3346 m_GenericParamToDescMap.pTable = &m_FieldDefToDescMap.pTable[m_FieldDefToDescMap.dwCount];
3348 m_GenericTypeDefToCanonMethodTableMap.pNext = NULL;
3349 m_GenericTypeDefToCanonMethodTableMap.supportedFlags = GENERIC_TYPE_DEF_MAP_ALL_FLAGS;
3350 m_GenericTypeDefToCanonMethodTableMap.pTable = &m_GenericParamToDescMap.pTable[m_GenericParamToDescMap.dwCount];
3352 m_FileReferencesMap.pNext = NULL;
3353 m_FileReferencesMap.supportedFlags = FILE_REF_MAP_ALL_FLAGS;
3354 m_FileReferencesMap.pTable = &m_GenericTypeDefToCanonMethodTableMap.pTable[m_GenericTypeDefToCanonMethodTableMap.dwCount];
3356 m_ManifestModuleReferencesMap.pNext = NULL;
3357 m_ManifestModuleReferencesMap.supportedFlags = MANIFEST_MODULE_MAP_ALL_FLAGS;
3358 m_ManifestModuleReferencesMap.pTable = &m_FileReferencesMap.pTable[m_FileReferencesMap.dwCount];
3360 m_MethodDefToPropertyInfoMap.pNext = NULL;
3361 m_MethodDefToPropertyInfoMap.supportedFlags = PROPERTY_INFO_MAP_ALL_FLAGS;
3362 m_MethodDefToPropertyInfoMap.pTable = &m_ManifestModuleReferencesMap.pTable[m_ManifestModuleReferencesMap.dwCount];
3367 // FreeClassTables frees the classes in the module
3370 void Module::FreeClassTables()
3381 if (m_dwTransientFlags & CLASSES_FREED)
3384 FastInterlockOr(&m_dwTransientFlags, CLASSES_FREED);
3386 // disable ibc here because it can cause errors during the destruction of classes
3387 IBCLoggingDisabler disableLogging;
3390 DebugLogRidMapOccupancy();
3394 // Free the types filled out in the TypeDefToEEClass map
3397 // Go through each linked block
3398 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
3399 while (typeDefIter.Next())
3401 MethodTable * pMT = typeDefIter.GetElement();
3403 if (pMT != NULL && pMT->IsRestored())
3405 pMT->GetClass()->Destruct(pMT);
3409 // Now do the same for constructed types (arrays and instantiated generic types)
3410 if (IsTenured()) // If we're destructing because of an error during the module's creation, we'll play it safe and not touch this table as its memory is freed by a
3411 { // separate AllocMemTracker. Though you're supposed to destruct everything else before destructing the AllocMemTracker, this is an easy invariant to break so
3412 // we'll play extra safe on this end.
3413 if (m_pAvailableParamTypes != NULL)
3415 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
3416 EETypeHashEntry *pEntry;
3417 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
3419 TypeHandle th = pEntry->GetTypeHandle();
3421 if (!th.IsRestored())
3424 #ifdef FEATURE_COMINTEROP
3425 // Some MethodTables/TypeDescs have COM interop goo attached to them which must be released
3426 if (!th.IsTypeDesc())
3428 MethodTable *pMT = th.AsMethodTable();
3429 if (pMT->HasCCWTemplate() && (!pMT->IsZapped() || pMT->GetZapModule() == this))
3431 // code:MethodTable::GetComCallWrapperTemplate() may go through canonical methodtable indirection cell.
3432 // The module load could be aborted before completing code:FILE_LOAD_EAGER_FIXUPS phase that's responsible
3433 // for resolving pre-restored indirection cells, so we have to check for it here explicitly.
3434 if (CORCOMPILE_IS_POINTER_TAGGED(pMT->GetCanonicalMethodTableFixup()))
3437 ComCallWrapperTemplate *pTemplate = pMT->GetComCallWrapperTemplate();
3438 if (pTemplate != NULL)
3440 pTemplate->Release();
3444 else if (th.IsArray())
3446 ComCallWrapperTemplate *pTemplate = th.AsArray()->GetComCallWrapperTemplate();
3447 if (pTemplate != NULL)
3449 pTemplate->Release();
3452 #endif // FEATURE_COMINTEROP
3454 // We need to call destruct on instances of EEClass whose "canonical" dependent lives in this table
3455 // There is nothing interesting to destruct on array EEClass
3456 if (!th.IsTypeDesc())
3458 MethodTable * pMT = th.AsMethodTable();
3459 if (pMT->IsCanonicalMethodTable() && (!pMT->IsZapped() || pMT->GetZapModule() == this))
3460 pMT->GetClass()->Destruct(pMT);
3467 #endif // !DACCESS_COMPILE
3469 ClassLoader *Module::GetClassLoader()
3471 WRAPPER_NO_CONTRACT;
3473 _ASSERTE(m_pAssembly != NULL);
3474 return m_pAssembly->GetLoader();
3477 PTR_BaseDomain Module::GetDomain()
3479 WRAPPER_NO_CONTRACT;
3481 _ASSERTE(m_pAssembly != NULL);
3482 return m_pAssembly->GetDomain();
3485 #ifndef DACCESS_COMPILE
3487 #ifndef CROSSGEN_COMPILE
3488 void Module::StartUnload()
3490 WRAPPER_NO_CONTRACT;
3491 #ifdef PROFILING_SUPPORTED
3493 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
3494 if (!IsBeingUnloaded())
3496 // Profiler is causing some peripheral class loads. Probably this just needs
3497 // to be turned into a Fault_not_fatal and moved to a specific place inside the profiler.
3501 g_profControlBlock.pProfInterface->ModuleUnloadStarted((ModuleID) this);
3506 EX_END_CATCH(SwallowAllExceptions);
3510 #endif // PROFILING_SUPPORTED
3511 #ifdef FEATURE_PREJIT
3512 if (g_IBCLogger.InstrEnabled())
3514 Thread * pThread = GetThread();
3515 ThreadLocalIBCInfo* pInfo = pThread->GetIBCInfo();
3517 // Acquire the Crst lock before creating the IBCLoggingDisabler object.
3518 // Only one thread at a time can be processing an IBC logging event.
3519 CrstHolder lock(g_IBCLogger.GetSync());
3521 IBCLoggingDisabler disableLogging( pInfo ); // runs IBCLoggingDisabler::DisableLogging
3523 // Write out the method profile data
3524 /*hr=*/WriteMethodProfileDataLogFile(true);
3527 #endif // FEATURE_PREJIT
3530 #endif // CROSSGEN_COMPILE
3532 void Module::ReleaseILData(void)
3534 WRAPPER_NO_CONTRACT;
3536 ReleaseISymUnmanagedReader();
3541 //---------------------------------------------------------------------------------------
3543 // Simple wrapper around calling IsAfContentType_WindowsRuntime() against the flags
3544 // returned from the PEAssembly's GetFlagsNoTrigger()
3547 // nonzero iff we successfully determined pModule is a WinMD. FALSE if pModule is not
3548 // a WinMD, or we fail trying to find out.
3550 BOOL Module::IsWindowsRuntimeModule()
3556 CAN_TAKE_LOCK; // Accesses metadata directly, which takes locks
3565 if (FAILED(GetAssembly()->GetManifestFile()->GetFlagsNoTrigger(&dwFlags)))
3568 return IsAfContentType_WindowsRuntime(dwFlags);
3571 BOOL Module::IsInCurrentVersionBubble()
3573 LIMITED_METHOD_CONTRACT;
3575 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
3576 if (!IsCompilationProcess())
3579 // The module being compiled is always part of the current version bubble
3580 AppDomain * pAppDomain = GetAppDomain();
3581 if (pAppDomain->IsCompilationDomain() && pAppDomain->ToCompilationDomain()->GetTargetModule() == this)
3584 if (IsReadyToRunCompilation())
3587 #ifdef FEATURE_COMINTEROP
3588 if (g_fNGenWinMDResilient)
3589 return !GetAssembly()->IsWinMD();
3593 #else // FEATURE_NATIVE_IMAGE_GENERATION
3595 #endif // FEATURE_NATIVE_IMAGE_GENERATION
3598 //---------------------------------------------------------------------------------------
3600 // WinMD-aware helper to grab a readable public metadata interface. Any place that thinks
3601 // it wants to use Module::GetRWImporter + QI now should use this wrapper instead.
3604 // * dwOpenFlags - Combo from CorOpenFlags. Better not contain ofWrite!
3605 // * riid - Public IID requested
3606 // * ppvInterface - [out] Requested interface. On success, *ppvInterface is returned
3607 // refcounted; caller responsible for Release.
3610 // HRESULT indicating success or failure.
3612 HRESULT Module::GetReadablePublicMetaDataInterface(DWORD dwOpenFlags, REFIID riid, LPVOID * ppvInterface)
3618 CAN_TAKE_LOCK; // IsWindowsRuntimeModule accesses metadata directly, which takes locks
3623 _ASSERTE((dwOpenFlags & ofWrite) == 0);
3625 // Temporary place to store public, AddRef'd interface pointers
3626 ReleaseHolder<IUnknown> pIUnkPublic;
3628 // Temporary place to store the IUnknown from which we'll do the final QI to get the
3629 // requested public interface. Any assignment to pIUnk assumes pIUnk does not need
3630 // to do a Release() (either the interface was internal and not AddRef'd, or was
3631 // public and will be released by the above holder).
3632 IUnknown * pIUnk = NULL;
3636 // Normally, we just get an RWImporter to do the QI on, and we're on our way.
3639 pIUnk = GetRWImporter();
3641 EX_CATCH_HRESULT_NO_ERRORINFO(hr);
3643 if (FAILED(hr) && IsWindowsRuntimeModule())
3645 // WinMD modules don't like creating RW importers. They also (currently)
3646 // have no plumbing to get to their public metadata interfaces from the
3647 // Module. So we actually have to start from scratch at the dispenser.
3649 // To start with, get a dispenser, and get the metadata memory blob we've
3650 // already loaded. If either of these fail, just return the error HRESULT
3651 // from the above GetRWImporter() call.
3653 // We'll get an addref'd IMetaDataDispenser, so use a holder to release it
3654 ReleaseHolder<IMetaDataDispenser> pDispenser;
3655 if (FAILED(InternalCreateMetaDataDispenser(IID_IMetaDataDispenser, &pDispenser)))
3657 _ASSERTE(FAILED(hr));
3661 COUNT_T cbMetadata = 0;
3662 PTR_CVOID pvMetadata = GetAssembly()->GetManifestFile()->GetLoadedMetadata(&cbMetadata);
3663 if ((pvMetadata == NULL) || (cbMetadata == 0))
3665 _ASSERTE(FAILED(hr));
3669 // Now that the pieces are ready, we can use the riid specified by the
3670 // profiler in this call to the dispenser to get the requested interface. If
3671 // this fails, then this is the interesting HRESULT for the caller to see.
3673 // We'll get an AddRef'd public interface, so use a holder to release it
3674 hr = pDispenser->OpenScopeOnMemory(
3677 (dwOpenFlags | ofReadOnly), // Force ofReadOnly on behalf of the profiler
3683 // Set pIUnk so we can do the final QI from it below as we do in the other
3685 pIUnk = pIUnkPublic;
3688 // Get the requested interface
3689 if (SUCCEEDED(hr) && (ppvInterface != NULL))
3691 _ASSERTE(pIUnk != NULL);
3692 hr = pIUnk->QueryInterface(riid, (void **) ppvInterface);
3698 // a special token that indicates no reader could be created - don't try again
3699 static ISymUnmanagedReader* const k_pInvalidSymReader = (ISymUnmanagedReader*)0x1;
3701 #if defined(FEATURE_ISYM_READER) && !defined(CROSSGEN_COMPILE)
3702 ISymUnmanagedReader *Module::GetISymUnmanagedReaderNoThrow(void)
3704 CONTRACT(ISymUnmanagedReader *)
3707 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
3709 WRAPPER(GC_TRIGGERS);
3714 ISymUnmanagedReader *ret = NULL;
3718 ret = GetISymUnmanagedReader();
3722 // We swallow any exception and say that we simply couldn't get a reader by returning NULL.
3723 // The only type of error that should be possible here is OOM.
3724 /* DISABLED due to Dev10 bug 619495
3725 CONSISTENCY_CHECK_MSG(
3726 GET_EXCEPTION()->GetHR() == E_OUTOFMEMORY,
3727 "Exception from GetISymUnmanagedReader");
3730 EX_END_CATCH(RethrowTerminalExceptions);
3735 ISymUnmanagedReader *Module::GetISymUnmanagedReader(void)
3737 CONTRACT(ISymUnmanagedReader *)
3740 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
3742 WRAPPER(GC_TRIGGERS);
3747 // No symbols for resource modules
3754 // Verify that symbol reading is permitted for this module.
3755 // If we know we've already created a symbol reader, don't bother checking. There is
3756 // no advantage to allowing symbol reading to be turned off if we've already created the reader.
3757 // Note that we can't just put this code in the creation block below because we might have to
3758 // call managed code to resolve security policy, and we can't do that while holding a lock.
3759 // There is no disadvantage other than a minor perf cost to calling this unnecessarily, so the
3760 // race on m_pISymUnmanagedReader here is OK. The perf cost is minor because the only real
3761 // work is done by the security system which caches the result.
3762 if( m_pISymUnmanagedReader == NULL && !IsSymbolReadingEnabled() )
3765 // Take the lock for the m_pISymUnmanagedReader
3766 // This ensures that we'll only ever attempt to create one reader at a time, and we won't
3767 // create a reader if we're in the middle of destroying one that has become stale.
3768 // Actual access to the reader can safely occur outside the lock as long as it has its own
3769 // AddRef which we take inside the lock at the bottom of this method.
3770 CrstHolder holder(&m_ISymUnmanagedReaderCrst);
3772 UINT lastErrorMode = 0;
3774 // If we haven't created a reader yet, do so now
3775 if (m_pISymUnmanagedReader == NULL)
3777 // Mark our reader as invalid so that if we fail to create the reader
3778 // (including if an exception is thrown), we won't keep trying.
3779 m_pISymUnmanagedReader = k_pInvalidSymReader;
3781 // There are 4 main cases here:
3782 // 1. Assembly is on disk and we'll get the symbols from a file next to the assembly
3783 // 2. Assembly is provided by the host and we'll get the symbols from the host
3784 // 3. Assembly was loaded in-memory (by byte array or ref-emit), and symbols were
3785 // provided along with it.
3786 // 4. Assembly was loaded in-memory but no symbols were provided.
3788 // Determine whether we should be looking in memory for the symbols (cases 2 & 3)
3789 bool fInMemorySymbols = ( m_file->IsIStream() || GetInMemorySymbolStream() );
3790 if( !fInMemorySymbols && m_file->GetPath().IsEmpty() )
3792 // Case 4. We don't have a module path, an IStream or an in memory symbol stream,
3793 // so there is no-where to try and get symbols from.
3797 // Create a binder to find the reader.
3799 // <REVISIT_TODO>@perf: this is slow, creating and destroying the binder every
3800 // time. We should cache this somewhere, but I'm not 100% sure
3801 // where right now...</REVISIT_TODO>
3804 SafeComHolder<ISymUnmanagedBinder> pBinder;
3806 if (g_pDebugInterface == NULL)
3808 // @TODO: this is reachable when debugging!
3809 UNREACHABLE_MSG("About to CoCreateInstance! This code should not be "
3810 "reachable or needs to be reimplemented for CoreCLR!");
3813 if (this->GetInMemorySymbolStreamFormat() == eSymbolFormatILDB)
3815 // We've got in-memory ILDB symbols, create the ILDB symbol binder
3816 // Note that in this case, we must be very careful not to use diasymreader.dll
3817 // at all - we don't trust it, and shouldn't run any code in it
3818 IfFailThrow(IldbSymbolsCreateInstance(CLSID_CorSymBinder_SxS, IID_ISymUnmanagedBinder, (void**)&pBinder));
3822 // We're going to be working with Windows PDB format symbols. Attempt to CoCreate the symbol binder.
3823 // CoreCLR supports not having a symbol reader installed, so CoCreate searches the PATH env var
3824 // and then tries coreclr dll location.
3825 // On desktop, the framework installer is supposed to install diasymreader.dll as well
3826 // and so this shouldn't happen.
3827 hr = FakeCoCreateInstanceEx(CLSID_CorSymBinder_SxS, NATIVE_SYMBOL_READER_DLL, IID_ISymUnmanagedBinder, (void**)&pBinder, NULL);
3830 PathString symbolReaderPath;
3831 hr = GetHModuleDirectory(GetModuleInst(), symbolReaderPath);
3836 symbolReaderPath.Append(NATIVE_SYMBOL_READER_DLL);
3837 hr = FakeCoCreateInstanceEx(CLSID_CorSymBinder_SxS, symbolReaderPath.GetUnicode(), IID_ISymUnmanagedBinder, (void**)&pBinder, NULL);
3845 LOG((LF_CORDB, LL_INFO10, "M::GISUR: Created binder\n"));
3847 // Note: we change the error mode here so we don't get any popups as the PDB symbol reader attempts to search the
3848 // hard disk for files.
3849 lastErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
3851 SafeComHolder<ISymUnmanagedReader> pReader;
3853 if (fInMemorySymbols)
3855 SafeComHolder<IStream> pIStream( NULL );
3857 // If debug stream is already specified, don't bother to go through fusion
3858 // This is the common case for case 2 (hosted modules) and case 3 (Ref.Emit).
3859 if (GetInMemorySymbolStream() )
3862 if( IsReflection() )
3864 // If this is Reflection.Emit, we must clone the stream because another thread may
3865 // update it when someone is using the reader we create here leading to AVs.
3866 // Note that the symbol stream should be up to date since we flush the writer
3867 // after every addition in Module::AddClass.
3868 IfFailThrow(GetInMemorySymbolStream()->Clone(&pIStream));
3872 // The stream is not changing. Just add-ref to it.
3873 pIStream = GetInMemorySymbolStream();
3879 hr = pBinder->GetReaderFromStream(GetRWImporter(), pIStream, &pReader);
3884 // The assembly is on disk, so try and load symbols based on the path to the assembly (case 1)
3885 const SString &path = m_file->GetPath();
3887 // Call Fusion to ensure that any PDB's are shadow copied before
3888 // trying to get a symbol reader. This has to be done once per
3890 // for this to work with winmds we cannot simply call GetRWImporter() as winmds are RO
3891 // and thus don't implement the RW interface. so we call this wrapper function which knows
3892 // how to get a IMetaDataImport interface regardless of the underlying module type.
3893 ReleaseHolder<IUnknown> pUnk = NULL;
3894 hr = GetReadablePublicMetaDataInterface(ofReadOnly, IID_IMetaDataImport, &pUnk);
3896 hr = pBinder->GetReaderForFile(pUnk, path, NULL, &pReader);
3899 SetErrorMode(lastErrorMode);
3903 m_pISymUnmanagedReader = pReader.Extract();
3904 LOG((LF_CORDB, LL_INFO10, "M::GISUR: Loaded symbols for module %S\n", GetDebugName()));
3908 // We failed to create the reader, don't try again next time
3909 LOG((LF_CORDB, LL_INFO10, "M::GISUR: Failed to load symbols for module %S\n", GetDebugName()));
3910 _ASSERTE( m_pISymUnmanagedReader == k_pInvalidSymReader );
3913 } // if( m_pISymUnmanagedReader == NULL )
3915 // If we previously failed to create the reader, return NULL
3916 if (m_pISymUnmanagedReader == k_pInvalidSymReader)
3921 // Success - return an AddRef'd copy of the reader
3922 m_pISymUnmanagedReader->AddRef();
3923 RETURN (m_pISymUnmanagedReader);
3925 #endif // FEATURE_ISYM_READER && !CROSSGEN_COMPILE
3927 BOOL Module::IsSymbolReadingEnabled()
3938 // The only time we need symbols available is for debugging and taking stack traces,
3939 // neither of which can be done if the assembly can't run. The advantage of being strict
3940 // is that there is a perf penalty adding types to a module if you must support reading
3941 // symbols at any time. If symbols don't need to be accesible then we can
3942 // optimize by only commiting symbols when the assembly is saved to disk. See DDB 671107.
3943 if(!GetAssembly()->HasRunAccess())
3948 // If the module has symbols in-memory (eg. RefEmit) that are in ILDB
3949 // format, then there isn't any reason not to supply them. The reader
3950 // code is always available, and we trust it's security.
3951 if (this->GetInMemorySymbolStreamFormat() == eSymbolFormatILDB)
3956 #ifdef DEBUGGING_SUPPORTED
3957 if (!g_pDebugInterface)
3959 // if debugging is disabled (no debug pack installed), do not load symbols
3960 // This is done for two reasons. We don't completely trust the security of
3961 // the diasymreader.dll code, so we don't want to use it in mainline scenarios.
3962 // Secondly, there's not reason that diasymreader.dll will even necssarily be
3963 // be on the machine if the debug pack isn't installed.
3966 #endif // DEBUGGING_SUPPORTED
3972 // At this point, this is only called when we're creating an appdomain
3973 // out of an array of bytes, so we'll keep the IStream that we create
3974 // around in case the debugger attaches later (including detach & re-attach!)
3975 void Module::SetSymbolBytes(LPCBYTE pbSyms, DWORD cbSyms)
3977 STANDARD_VM_CONTRACT;
3979 // Create a IStream from the memory for the syms.
3980 SafeComHolder<CGrowableStream> pStream(new CGrowableStream());
3982 // Do not need to AddRef the CGrowableStream because the constructor set it to 1
3983 // ref count already. The Module will keep a copy for its own use.
3985 // Make sure to set the symbol stream on the module before
3986 // attempting to send UpdateModuleSyms messages up for it.
3987 SetInMemorySymbolStream(pStream, eSymbolFormatPDB);
3989 // This can only be called when the module is being created. No-one should have
3990 // tried to use the symbols yet, and so there should not be a reader.
3991 // If instead, we wanted to call this when a reader could have been created, we need to
3992 // serialize access by taking the reader lock, and flush the old reader by calling
3993 // code:Module.ReleaseISymUnmanagedReader
3994 _ASSERTE( m_pISymUnmanagedReader == NULL );
3997 LPCWSTR pName = NULL;
3998 pName = GetDebugName();
4002 DWORD dwError = pStream->Write((const void *)pbSyms,
4005 IfFailThrow(HRESULT_FROM_WIN32(dwError));
4007 #if PROFILING_SUPPORTED && !defined(CROSSGEN_COMPILE)
4008 BEGIN_PIN_PROFILER(CORProfilerInMemorySymbolsUpdatesEnabled());
4010 g_profControlBlock.pProfInterface->ModuleInMemorySymbolsUpdated((ModuleID) this);
4013 #endif //PROFILING_SUPPORTED && !defined(CROSSGEN_COMPILE)
4015 ETW::CodeSymbolLog::EmitCodeSymbols(this);
4017 // Tell the debugger that symbols have been loaded for this
4018 // module. We iterate through all domains which contain this
4019 // module's assembly, and send a debugger notify for each one.
4020 // <REVISIT_TODO>@perf: it would scale better if we directly knew which domains
4021 // the assembly was loaded in.</REVISIT_TODO>
4022 if (CORDebuggerAttached())
4024 AppDomainIterator i(FALSE);
4028 AppDomain *pDomain = i.GetDomain();
4030 if (pDomain->IsDebuggerAttached() && (GetDomain() == SystemDomain::System() ||
4031 pDomain->ContainsAssembly(m_pAssembly)))
4033 g_pDebugInterface->SendUpdateModuleSymsEventAndBlock(this, pDomain);
4039 // Clear any cached symbol reader
4040 void Module::ReleaseISymUnmanagedReader(void)
4051 // Caller is responsible for taking the reader lock if the call could occur when
4052 // other threads are using or creating the reader
4053 if( m_pISymUnmanagedReader != NULL )
4055 // If we previously failed to create a reader, don't attempt to release it
4056 // but do clear it out so that we can try again (eg. symbols may have changed)
4057 if( m_pISymUnmanagedReader != k_pInvalidSymReader )
4059 m_pISymUnmanagedReader->Release();
4061 m_pISymUnmanagedReader = NULL;
4065 // Lazily creates a new IL stub cache for this module.
4066 ILStubCache* Module::GetILStubCache()
4073 INJECT_FAULT(COMPlusThrowOM(););
4077 // Use per-AD cache for domain specific modules when not NGENing
4078 BaseDomain *pDomain = GetDomain();
4079 if (!pDomain->IsSharedDomain() && !pDomain->AsAppDomain()->IsCompilationDomain())
4080 return pDomain->AsAppDomain()->GetILStubCache();
4082 if (m_pILStubCache == NULL)
4084 ILStubCache *pILStubCache = new ILStubCache(GetLoaderAllocator()->GetHighFrequencyHeap());
4086 if (FastInterlockCompareExchangePointer(&m_pILStubCache, pILStubCache, NULL) != NULL)
4088 // some thread swooped in and set the field
4089 delete pILStubCache;
4092 _ASSERTE(m_pILStubCache != NULL);
4093 return m_pILStubCache;
4096 // Called to finish the process of adding a new class with Reflection.Emit
4097 void Module::AddClass(mdTypeDef classdef)
4105 PRECONDITION(!IsResource());
4109 // The fake class associated with the module (global fields & functions) needs to be initialized here
4110 // Normal classes are added to the available class hash when their typedef is first created.
4111 if (RidFromToken(classdef) == 0)
4113 BuildClassForModule();
4116 // Since the module is being modified, the in-memory symbol stream
4117 // (if any) has probably also been modified. If we support reading the symbols
4118 // then we need to commit the changes to the writer and flush any old readers
4119 // However if we don't support reading then we can skip this which will give
4120 // a substantial perf improvement. See DDB 671107.
4121 if(IsSymbolReadingEnabled())
4123 CONSISTENCY_CHECK(IsReflection()); // this is only used for dynamic modules
4124 ISymUnmanagedWriter * pWriter = GetReflectionModule()->GetISymUnmanagedWriter();
4125 if (pWriter != NULL)
4127 // Serialize with any concurrent reader creations
4128 // Specifically, if we started creating a reader on one thread, and then updated the
4129 // symbols on another thread, we need to wait until the initial reader creation has
4130 // completed and release it so we don't get stuck with a stale reader.
4131 // Also, if we commit to the stream while we're in the process of creating a reader,
4132 // the reader will get corrupted/incomplete data.
4133 // Note that we must also be in co-operative mode here to ensure the debugger helper
4134 // thread can't be simultaneously reading this stream while the process is synchronized
4135 // (code:Debugger::GetSymbolBytes)
4136 CrstHolder holder(&m_ISymUnmanagedReaderCrst);
4138 // Flush writes to the symbol store to the symbol stream
4139 // Note that we do this when finishing the addition of the class, instead of
4140 // on-demand in GetISymUnmanagedReader because the writer is not thread-safe.
4141 // Here, we're inside the lock of TypeBuilder.CreateType, and so it's safe to
4142 // manipulate the writer.
4143 SafeComHolderPreemp<ISymUnmanagedWriter3> pWriter3;
4144 HRESULT thr = pWriter->QueryInterface(IID_ISymUnmanagedWriter3, (void**)&pWriter3);
4145 CONSISTENCY_CHECK(SUCCEEDED(thr));
4148 thr = pWriter3->Commit();
4151 // Flush any cached symbol reader to ensure we pick up any new symbols
4152 ReleaseISymUnmanagedReader();
4156 // If either the QI or Commit failed
4159 // The only way we expect this might fail is out-of-memory. In that
4160 // case we silently fail to update the symbol stream with new data, but
4161 // we leave the existing reader intact.
4162 CONSISTENCY_CHECK(thr==E_OUTOFMEMORY);
4168 //---------------------------------------------------------------------------
4169 // For the global class this builds the table of MethodDescs an adds the rids
4170 // to the MethodDef map.
4171 //---------------------------------------------------------------------------
4172 void Module::BuildClassForModule()
4183 IMDInternalImport * pImport = GetMDImport();
4184 DWORD cFunctions, cFields;
4187 // Obtain count of global functions
4188 HENUMInternalHolder hEnum(pImport);
4189 hEnum.EnumGlobalFunctionsInit();
4190 cFunctions = pImport->EnumGetCount(&hEnum);
4194 // Obtain count of global fields
4195 HENUMInternalHolder hEnum(pImport);
4196 hEnum.EnumGlobalFieldsInit();
4197 cFields = pImport->EnumGetCount(&hEnum);
4200 // If we have any work to do...
4201 if (cFunctions > 0 || cFields > 0)
4203 COUNTER_ONLY(size_t _HeapSize = 0);
4205 TypeKey typeKey(this, COR_GLOBAL_PARENT_TOKEN);
4206 TypeHandle typeHnd = GetClassLoader()->LoadTypeHandleForTypeKeyNoLock(&typeKey);
4208 #ifdef ENABLE_PERF_COUNTERS
4210 _HeapSize = GetLoaderAllocator()->GetHighFrequencyHeap()->GetSize();
4212 GetPerfCounters().m_Loading.cbLoaderHeapSize = _HeapSize;
4213 #endif // ENABLE_PERF_COUNTERS
4218 #endif // !DACCESS_COMPILE
4220 // Returns true iff the debugger should be notified about this module
4223 // Debugger doesn't need to be notified about modules that can't be executed,
4224 // like inspection and resource only. These are just pure data.
4226 // This should be immutable for an instance of a module. That ensures that the debugger gets consistent
4227 // notifications about it. It this value mutates, than the debugger may miss relevant notifications.
4228 BOOL Module::IsVisibleToDebugger()
4230 WRAPPER_NO_CONTRACT;
4238 // If for whatever other reason, we can't run it, then don't notify the debugger about it.
4239 Assembly * pAssembly = GetAssembly();
4240 if (!pAssembly->HasRunAccess())
4247 BOOL Module::HasNativeOrReadyToRunImage()
4249 #ifdef FEATURE_READYTORUN
4254 return HasNativeImage();
4257 PEImageLayout * Module::GetNativeOrReadyToRunImage()
4259 LIMITED_METHOD_CONTRACT;
4261 #ifdef FEATURE_READYTORUN
4263 return GetReadyToRunInfo()->GetImage();
4266 return GetNativeImage();
4269 PTR_CORCOMPILE_IMPORT_SECTION Module::GetImportSections(COUNT_T *pCount)
4278 #ifdef FEATURE_READYTORUN
4280 return GetReadyToRunInfo()->GetImportSections(pCount);
4283 return GetNativeImage()->GetNativeImportSections(pCount);
4286 PTR_CORCOMPILE_IMPORT_SECTION Module::GetImportSectionFromIndex(COUNT_T index)
4295 #ifdef FEATURE_READYTORUN
4297 return GetReadyToRunInfo()->GetImportSectionFromIndex(index);
4300 return GetNativeImage()->GetNativeImportSectionFromIndex(index);
4303 PTR_CORCOMPILE_IMPORT_SECTION Module::GetImportSectionForRVA(RVA rva)
4312 #ifdef FEATURE_READYTORUN
4314 return GetReadyToRunInfo()->GetImportSectionForRVA(rva);
4317 return GetNativeImage()->GetNativeImportSectionForRVA(rva);
4320 TADDR Module::GetIL(DWORD target)
4322 WRAPPER_NO_CONTRACT;
4328 return m_file->GetIL(target);
4331 PTR_VOID Module::GetRvaField(DWORD rva, BOOL fZapped)
4333 WRAPPER_NO_CONTRACT;
4336 #ifdef FEATURE_PREJIT
4337 if (fZapped && m_file->IsILOnly())
4339 return dac_cast<PTR_VOID>(m_file->GetLoadedNative()->GetRvaData(rva,NULL_OK));
4341 #endif // FEATURE_PREJIT
4343 return m_file->GetRvaField(rva);
4346 #ifndef DACCESS_COMPILE
4348 CHECK Module::CheckRvaField(RVA field)
4350 WRAPPER_NO_CONTRACT;
4351 if (!IsReflection())
4352 CHECK(m_file->CheckRvaField(field));
4356 CHECK Module::CheckRvaField(RVA field, COUNT_T size)
4365 if (!IsReflection())
4366 CHECK(m_file->CheckRvaField(field, size));
4370 #endif // !DACCESS_COMPILE
4372 BOOL Module::HasTls()
4374 WRAPPER_NO_CONTRACT;
4376 return m_file->HasTls();
4379 BOOL Module::IsRvaFieldTls(DWORD rva)
4381 WRAPPER_NO_CONTRACT;
4383 return m_file->IsRvaFieldTls(rva);
4386 UINT32 Module::GetFieldTlsOffset(DWORD rva)
4388 WRAPPER_NO_CONTRACT;
4390 return m_file->GetFieldTlsOffset(rva);
4393 UINT32 Module::GetTlsIndex()
4395 WRAPPER_NO_CONTRACT;
4397 return m_file->GetTlsIndex();
4401 // In DAC builds this function was being called on host addresses which may or may not
4402 // have been marshalled from the target. Such addresses can't be reliably mapped back to
4403 // target addresses, which means we can't tell whether they came from the IL or not
4405 // Security note: Any security which you might wish to gain by verifying the origin of
4406 // a signature isn't available in DAC. The attacker can provide a dump which spoofs all
4407 // module ranges. In other words the attacker can make the signature appear to come from
4408 // anywhere, but still violate all the rules that a signature from that location would
4409 // otherwise follow. I am removing this function from DAC in order to prevent anyone from
4410 // getting a false sense of security (in addition to its functional shortcomings)
4412 #ifndef DACCESS_COMPILE
4413 BOOL Module::IsSigInIL(PCCOR_SIGNATURE signature)
4426 return m_file->IsPtrInILImage(signature);
4429 #ifdef FEATURE_PREJIT
4430 StubMethodHashTable *Module::GetStubMethodHashTable()
4439 if (m_pStubMethodHashTable == NULL && SystemDomain::GetCurrentDomain()->IsCompilationDomain())
4441 // we only need to create the hash table when NGENing, it is read-only at run-time
4442 AllocMemTracker amTracker;
4443 m_pStubMethodHashTable = StubMethodHashTable::Create(GetLoaderAllocator(), this, METHOD_STUBS_HASH_BUCKETS, &amTracker);
4444 amTracker.SuppressRelease();
4447 return m_pStubMethodHashTable;
4449 #endif // FEATURE_PREJIT
4451 void Module::InitializeStringData(DWORD token, EEStringData *pstrData, CQuickBytes *pqb)
4459 INJECT_FAULT(COMPlusThrowOM());
4460 PRECONDITION(TypeFromToken(token) == mdtString);
4467 if (FAILED(GetMDImport()->GetUserString(token, &dwCharCount, &fIs80Plus, &pString)) ||
4470 THROW_BAD_FORMAT(BFA_BAD_STRING_TOKEN_RANGE, this);
4474 pstrData->SetStringBuffer(pString);
4475 #else // !!BIGENDIAN
4476 _ASSERTE(pqb != NULL);
4480 pSwapped = (LPWSTR) pqb->AllocThrows(dwCharCount * sizeof(WCHAR));
4481 memcpy((void*)pSwapped, (void*)pString, dwCharCount*sizeof(WCHAR));
4482 SwapStringLength(pSwapped, dwCharCount);
4484 pstrData->SetStringBuffer(pSwapped);
4485 #endif // !!BIGENDIAN
4487 // MD and String look at this bit in opposite ways. Here's where we'll do the conversion.
4488 // MD sets the bit to true if the string contains characters greater than 80.
4489 // String sets the bit to true if the string doesn't contain characters greater than 80.
4491 pstrData->SetCharCount(dwCharCount);
4492 pstrData->SetIsOnlyLowChars(!fIs80Plus);
4495 #ifndef CROSSGEN_COMPILE
4497 #ifdef FEATURE_PREJIT
4498 OBJECTHANDLE Module::ResolveStringRefHelper(DWORD token, BaseDomain *pDomain, PTR_CORCOMPILE_IMPORT_SECTION pSection, EEStringData *pStrData)
4500 PEImageLayout *pNativeImage = GetNativeImage();
4504 TADDR tableBase = pNativeImage->GetDirectoryData(&pSection->Section, &tableSize);
4506 // Walk the handle table.
4507 // @TODO: If we ever care about the perf of this function, we could sort the tokens
4508 // using as a key the string they point to, so we could do a binary search
4509 for (SIZE_T * pEntry = (SIZE_T *)tableBase ; pEntry < (SIZE_T *)(tableBase + tableSize); pEntry++)
4511 // Ensure that the compiler won't fetch the value twice
4512 SIZE_T entry = VolatileLoadWithoutBarrier(pEntry);
4514 if (CORCOMPILE_IS_POINTER_TAGGED(entry))
4516 BYTE * pBlob = (BYTE *) pNativeImage->GetRvaData(CORCOMPILE_UNTAG_TOKEN(entry));
4518 // Note that we only care about strings from current module, and so we do not check ENCODE_MODULE_OVERRIDE
4519 if (*pBlob++ == ENCODE_STRING_HANDLE &&
4520 TokenFromRid(CorSigUncompressData((PCCOR_SIGNATURE&) pBlob), mdtString) == token)
4522 EnsureWritablePages(pEntry);
4524 // This string hasn't been fixed up. Synchronize the update with the normal
4527 CrstHolder ch(this->GetFixupCrst());
4529 if (!CORCOMPILE_IS_POINTER_TAGGED(*pEntry))
4531 // We lost the race, just return current entry
4535 *pEntry = (SIZE_T) ResolveStringRef(token, pDomain, false);
4539 return (OBJECTHANDLE) *pEntry;
4544 OBJECTREF* pRef = (OBJECTREF*) entry;
4545 _ASSERTE((*pRef)->GetMethodTable() == g_pStringClass);
4547 STRINGREF stringRef = (STRINGREF) *pRef;
4549 // Is this the string we are trying to resolve?
4550 if (pStrData->GetCharCount() == stringRef->GetStringLength() &&
4551 memcmp((void*)pStrData->GetStringBuffer(),
4552 (void*) stringRef->GetBuffer(),
4553 pStrData->GetCharCount()*sizeof(WCHAR)) == 0)
4555 // We found it, so we just have to return this instance
4556 return (OBJECTHANDLE) entry;
4562 #endif // FEATURE_PREJIT
4564 OBJECTHANDLE Module::ResolveStringRef(DWORD token, BaseDomain *pDomain, bool bNeedToSyncWithFixups)
4572 INJECT_FAULT(COMPlusThrowOM());
4573 PRECONDITION(TypeFromToken(token) == mdtString);
4577 EEStringData strData;
4578 OBJECTHANDLE string = NULL;
4581 InitializeStringData(token, &strData, NULL);
4582 #else // !!BIGENDIAN
4584 InitializeStringData(token, &strData, &qb);
4585 #endif // !!BIGENDIAN
4589 // We can only do this for native images as they guarantee that resolvestringref will be
4590 // called only once per string from this module. @TODO: We really dont have any way of asserting
4591 // this, which would be nice... (and is needed to guarantee correctness)
4592 #ifdef FEATURE_PREJIT
4593 if (HasNativeImage() && IsNoStringInterning())
4595 if (bNeedToSyncWithFixups)
4597 // In an ngen image, it is possible that we get here but not be coming from a fixup,
4598 // (FixupNativeEntry case). In that unfortunate case (ngen partial images, dynamic methods,
4599 // lazy string inits) we will have to troll through the fixup list, and in the case the string is there,
4600 // reuse it, if it's there but hasn't been fixed up, fix it up now, and in the case it isn't
4601 // there at all, then go to our old style string interning. Going through this code path is
4602 // guaranteed to be slow. If necessary, we can further optimize it by sorting the token table,
4603 // Another way of solving this would be having a token to string table (would require knowing
4604 // all our posible stings in the ngen case (this is possible by looking at the IL))
4606 PEImageLayout * pNativeImage = GetNativeImage();
4609 PTR_CORCOMPILE_IMPORT_SECTION pSections = pNativeImage->GetNativeImportSections(&nSections);
4611 for (COUNT_T iSection = 0; iSection < nSections; iSection++)
4613 PTR_CORCOMPILE_IMPORT_SECTION pSection = pSections + iSection;
4615 if (pSection->Type != CORCOMPILE_IMPORT_TYPE_STRING_HANDLE)
4618 OBJECTHANDLE oh = ResolveStringRefHelper(token, pDomain, pSection, &strData);
4623 // The string is not in our fixup list, so just intern it old style (using hashtable)
4624 goto INTERN_OLD_STYLE;
4627 /* Unfortunately, this assert won't work in some cases of generics, consider the following scenario:
4629 1) Generic type in mscorlib.
4630 2) Instantiation of generic (1) (via valuetype) in another module
4631 3) other module now holds a copy of the code of the generic for that particular instantiation
4632 however, it is resolving the string literals against mscorlib, which breaks the invariant
4633 this assert was based on (no string fixups against other modules). In fact, with NoStringInterning,
4634 our behavior is not very intuitive.
4637 _ASSERTE(pDomain == GetAssembly()->GetDomain() && "If your are doing ldstr for a string"
4638 "in another module, either the JIT is very smart or you have a bug, check INLINE_NO_CALLEE_LDSTR");
4642 Dev10 804385 bugfix -
4643 We should be using appdomain that the string token lives in (GetAssembly->GetDomain())
4644 to allocate the System.String object instead of the appdomain that first uses the ldstr <token> (pDomain).
4646 Otherwise, it is possible to get into the situation that pDomain is unloaded but GetAssembly->GetDomain() is
4647 still kicking around. Anything else that is still using that string will now be pointing to an object
4648 that will be freed when the next GC happens.
4650 pDomain = GetAssembly()->GetDomain();
4652 // The caller is going to update an ngen fixup entry. The fixup entry
4653 // is used to reference the string and to ensure that the string is
4654 // allocated only once. Hence, this operation needs to be done under a lock.
4655 _ASSERTE(GetFixupCrst()->OwnedByCurrentThread());
4658 OBJECTREF* pRef = pDomain->AllocateObjRefPtrsInLargeTable(1);
4660 STRINGREF str = AllocateStringObject(&strData);
4661 SetObjectReference(pRef, str, NULL);
4664 int length = strData.GetCharCount();
4665 length = min(length, 100);
4666 WCHAR *szString = (WCHAR *)_alloca((length + 1) * sizeof(WCHAR));
4667 memcpyNoGCRefs((void*)szString, (void*)strData.GetStringBuffer(), length * sizeof(WCHAR));
4668 szString[length] = '\0';
4669 LOG((LF_APPDOMAIN, LL_INFO10000, "String literal \"%S\" won't be interned due to NoInterningAttribute\n", szString));
4672 return (OBJECTHANDLE) pRef;
4678 // Retrieve the string from the either the appropriate LoaderAllocator
4679 LoaderAllocator *pLoaderAllocator;
4681 if (this->IsCollectible())
4682 pLoaderAllocator = this->GetLoaderAllocator();
4684 pLoaderAllocator = pDomain->GetLoaderAllocator();
4686 string = (OBJECTHANDLE)pLoaderAllocator->GetStringObjRefPtrFromUnicodeString(&strData);
4690 #endif // CROSSGEN_COMPILE
4693 // Used by the verifier. Returns whether this stringref is valid.
4695 CHECK Module::CheckStringRef(DWORD token)
4697 LIMITED_METHOD_CONTRACT;
4698 CHECK(TypeFromToken(token)==mdtString);
4699 CHECK(!IsNilToken(token));
4700 CHECK(GetMDImport()->IsValidToken(token));
4704 mdToken Module::GetEntryPointToken()
4706 WRAPPER_NO_CONTRACT;
4708 return m_file->GetEntryPointToken();
4711 BYTE *Module::GetProfilerBase()
4721 if (m_file == NULL) // I'd rather assert this is not the case...
4725 else if (HasNativeImage())
4727 RETURN (BYTE*)(GetNativeImage()->GetBase());
4729 else if (m_file->IsLoaded())
4731 RETURN (BYTE*)(m_file->GetLoadedIL()->GetBase());
4739 void Module::AddActiveDependency(Module *pModule, BOOL unconditional)
4745 PRECONDITION(CheckPointer(pModule));
4746 PRECONDITION(pModule != this);
4747 PRECONDITION(!IsSystem());
4748 PRECONDITION(!GetAssembly()->IsDomainNeutral() || pModule->GetAssembly()->IsDomainNeutral() || GetAppDomain()->IsDefaultDomain());
4749 POSTCONDITION(IsSingleAppDomain() || HasActiveDependency(pModule));
4750 POSTCONDITION(IsSingleAppDomain() || !unconditional || HasUnconditionalActiveDependency(pModule));
4751 // Postcondition about activation
4755 // Activation tracking is not require in single domain mode. Activate the target immediately.
4756 if (IsSingleAppDomain())
4758 pModule->EnsureActive();
4762 // In the default AppDomain we delay a closure walk until a sharing attempt has been made
4763 // This might result in a situation where a domain neutral assembly from the default AppDomain
4764 // depends on something resolved by assembly resolve event (even Ref.Emit assemblies)
4765 // Since we won't actually share such assemblies, and the default AD itself cannot go away we
4766 // do not need to assert for such assemblies, thus " || GetAppDomain()->IsDefaultDomain()"
4768 CONSISTENCY_CHECK_MSG(!GetAssembly()->IsDomainNeutral() || pModule->GetAssembly()->IsDomainNeutral() || GetAppDomain()->IsDefaultDomain(),
4769 "Active dependency from domain neutral to domain bound is illegal");
4771 // We must track this dependency for multiple domains' use
4772 STRESS_LOG2(LF_CLASSLOADER, LL_INFO100000," %p -> %p\n",this,pModule);
4774 _ASSERTE(!unconditional || pModule->HasNativeImage());
4775 _ASSERTE(!unconditional || HasNativeImage());
4779 // this function can run in parallel with DomainFile::Activate and sychronizes via GetNumberOfActivations()
4780 // because we expose dependency only in the end Domain::Activate might miss it, but it will increment a counter module
4781 // so we can realize we have to additionally propagate a dependency into that appdomain.
4782 // currently we do it just by rescanning al appdomains.
4783 // needless to say, updating the counter and checking counter+adding dependency to the list should be atomic
4786 BOOL propagate = FALSE;
4787 ULONG startCounter=0;
4791 // First, add the dependency to the physical dependency list
4796 check=DomainFile::CheckUnactivatedInAllDomains(this);
4799 CrstHolder lock(&m_Crst);
4800 startCounter=GetNumberOfActivations();
4802 index = m_activeDependencies.FindElement(0, pModule);
4803 if (index == (COUNT_T) ArrayList::NOT_FOUND)
4806 STRESS_LOG3(LF_CLASSLOADER, LL_INFO100,"Adding new module dependency %p -> %p, unconditional=%i\n",this,pModule,unconditional);
4813 CONSISTENCY_CHECK_MSG(check,
4814 "Unconditional dependency cannot be added after module has already been activated");
4816 index = m_activeDependencies.GetCount();
4817 m_activeDependencies.Append(pModule);
4818 m_unconditionalDependencies.SetBit(index);
4819 STRESS_LOG2(LF_CLASSLOADER, LL_INFO100," Unconditional module dependency propagated %p -> %p\n",this,pModule);
4820 // Now other threads can skip this dependency without propagating.
4827 // Now we have to propagate any module activations in the loader
4832 _ASSERTE(!unconditional);
4833 DomainFile::PropagateNewActivation(this, pModule);
4835 CrstHolder lock(&m_Crst);
4836 STRESS_LOG2(LF_CLASSLOADER, LL_INFO100," Conditional module dependency propagated %p -> %p\n",this,pModule);
4837 // Now other threads can skip this dependency without propagating.
4838 endCounter=GetNumberOfActivations();
4839 if(startCounter==endCounter)
4840 m_activeDependencies.Append(pModule);
4843 }while(propagate && startCounter!=endCounter); //need to retry if someone was activated in parallel
4847 BOOL Module::HasActiveDependency(Module *pModule)
4854 PRECONDITION(CheckPointer(pModule));
4858 if (pModule == this)
4861 DependencyIterator i = IterateActiveDependencies();
4864 if (i.GetDependency() == pModule)
4871 BOOL Module::HasUnconditionalActiveDependency(Module *pModule)
4878 PRECONDITION(CheckPointer(pModule));
4882 if (pModule == this)
4885 DependencyIterator i = IterateActiveDependencies();
4888 if (i.GetDependency() == pModule
4889 && i.IsUnconditional())
4896 void Module::EnableModuleFailureTriggers(Module *pModuleTo, AppDomain *pDomain)
4905 // At this point we need to enable failure triggers we have placed in the code for this module. However,
4906 // the failure trigger codegen logic is NYI. To keep correctness, we just allow the exception to propagate
4907 // here. Note that in general this will enforce the failure invariants, but will also result in some rude
4908 // behavior as these failures will be propagated too widely rather than constrained to the appropriate
4909 // assemblies/app domains.
4911 // This should throw.
4912 STRESS_LOG2(LF_CLASSLOADER, LL_INFO100,"EnableModuleFailureTriggers for module %p in AppDomain %i\n",pModuleTo,pDomain->GetId().m_dwId);
4913 DomainFile *pDomainFileTo = pModuleTo->GetDomainFile(pDomain);
4914 pDomainFileTo->EnsureActive();
4916 // @NYI: shouldn't get here yet since we propagate failures
4917 UNREACHABLE_MSG("Module failure triggers NYI");
4920 #endif //!DACCESS_COMPILE
4923 // an GetAssemblyIfLoadedAppDomainIterator is used to iterate over all domains that
4924 // are known to be walkable at the time GetAssemblyIfLoaded is executed.
4926 // The iteration is guaranteed to include all domains that exist at the
4927 // start & end of the iteration that are safely accessible. This class is logically part
4928 // of GetAssemblyIfLoaded and logically has the same set of contracts.
4931 class GetAssemblyIfLoadedAppDomainIterator
4935 StackwalkingThreadIterator,
4936 AllAppDomainWalkingIterator,
4937 CurrentAppDomainIterator
4941 GetAssemblyIfLoadedAppDomainIterator() :
4942 m_adIteratorAll(TRUE),
4943 m_appDomainCurrent(NULL),
4945 m_fNextCalledForCurrentADIterator(FALSE)
4947 LIMITED_METHOD_CONTRACT;
4948 #ifndef DACCESS_COMPILE
4949 if (IsStackWalkerThread())
4951 Thread * pThread = (Thread *)ClrFlsGetValue(TlsIdx_StackWalkerWalkingThread);
4952 m_iterType = StackwalkingThreadIterator;
4953 m_pFrame = pThread->GetFrame();
4954 m_appDomainCurrent = pThread->GetDomain();
4956 else if (IsGCThread())
4958 m_iterType = AllAppDomainWalkingIterator;
4959 m_adIteratorAll.Init();
4963 _ASSERTE(::GetAppDomain() != NULL);
4964 m_appDomainCurrent = ::GetAppDomain();
4965 m_iterType = CurrentAppDomainIterator;
4967 #else //!DACCESS_COMPILE
4968 // We have to walk all AppDomains in debugger
4969 m_iterType = AllAppDomainWalkingIterator;
4970 m_adIteratorAll.Init();
4971 #endif //!DACCESS_COMPILE
4976 WRAPPER_NO_CONTRACT;
4980 #ifndef DACCESS_COMPILE
4981 case StackwalkingThreadIterator:
4982 if (!m_fNextCalledForCurrentADIterator)
4984 m_fNextCalledForCurrentADIterator = TRUE;
4986 // Try searching frame chain if the current domain is NULL
4987 if (m_appDomainCurrent == NULL)
4994 while (m_pFrame != FRAME_TOP)
4996 AppDomain * pDomain = m_pFrame->GetReturnDomain();
4997 if ((pDomain != NULL) && (pDomain != m_appDomainCurrent))
4999 m_appDomainCurrent = pDomain;
5002 m_pFrame = m_pFrame->PtrNextFrame();
5007 #endif //!DACCESS_COMPILE
5009 case AllAppDomainWalkingIterator:
5011 BOOL fSuccess = m_adIteratorAll.Next();
5013 m_appDomainCurrent = m_adIteratorAll.GetDomain();
5017 #ifndef DACCESS_COMPILE
5018 case CurrentAppDomainIterator:
5021 retVal = !m_fNextCalledForCurrentADIterator;
5022 m_fNextCalledForCurrentADIterator = TRUE;
5025 #endif //!DACCESS_COMPILE
5033 AppDomain * GetDomain()
5035 LIMITED_METHOD_CONTRACT;
5037 return m_appDomainCurrent;
5040 BOOL UsingCurrentAD()
5042 LIMITED_METHOD_CONTRACT;
5043 return m_iterType == CurrentAppDomainIterator;
5048 UnsafeAppDomainIterator m_adIteratorAll;
5049 AppDomain * m_appDomainCurrent;
5051 BOOL m_fNextCalledForCurrentADIterator;
5052 }; // class GetAssemblyIfLoadedAppDomainIterator
5054 #if !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
5055 // This function, given an AssemblyRef into the ngen generated native metadata section, will find the assembly referenced if
5056 // 1. The Assembly is defined with a different name than the AssemblyRef provides
5057 // 2. The Assembly has reached the stage of being loaded.
5058 // This function is used as a helper function to assist GetAssemblyIfLoaded with its tasks in the conditions
5059 // where GetAssemblyIfLoaded must succeed (or we violate various invariants in the system required for
5060 // correct implementation of GC, Stackwalking, and generic type loading.
5061 Assembly * Module::GetAssemblyIfLoadedFromNativeAssemblyRefWithRefDefMismatch(mdAssemblyRef kAssemblyRef, BOOL *pfDiscoveredAssemblyRefMatchesTargetDefExactly)
5063 CONTRACT(Assembly *)
5070 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5074 _ASSERTE(HasNativeImage());
5076 Assembly *pAssembly = NULL;
5077 IMDInternalImport *pImportFoundNativeImage = this->GetNativeAssemblyImport(FALSE);
5079 if (!pImportFoundNativeImage)
5084 if (kAssemblyRef != mdAssemblyRefNil)
5086 // Scan CORCOMPILE_DEPENDENCIES tables
5087 PEImageLayout* pNativeLayout = this->GetNativeImage();
5088 COUNT_T dependencyCount;
5089 CORCOMPILE_DEPENDENCY *pDependencies = pNativeLayout->GetNativeDependencies(&dependencyCount);
5091 // Find the assemblyDef that defines the exact target
5092 mdAssemblyRef foundAssemblyDef = mdAssemblyRefNil;
5094 for (COUNT_T i = 0; i < dependencyCount; ++i)
5096 CORCOMPILE_DEPENDENCY* pDependency = &(pDependencies[i]);
5097 if (pDependency->dwAssemblyRef == kAssemblyRef)
5099 foundAssemblyDef = pDependency->dwAssemblyDef;
5104 // In this case we know there is no assembly redirection involved. Skip any additional work.
5105 if (kAssemblyRef == foundAssemblyDef)
5107 *pfDiscoveredAssemblyRefMatchesTargetDefExactly = true;
5111 if (foundAssemblyDef != mdAssemblyRefNil)
5113 // Find out if THIS reference is satisfied
5114 // Specify fDoNotUtilizeExtraChecks to prevent recursion
5115 Assembly *pAssemblyCandidate = this->GetAssemblyIfLoaded(foundAssemblyDef, NULL, NULL, pImportFoundNativeImage, TRUE /*fDoNotUtilizeExtraChecks*/);
5117 // This extended check is designed only to find assemblies loaded via an AssemblySpecBindingCache based binder. Verify that's what we found.
5118 if(pAssemblyCandidate != NULL)
5120 if (!pAssemblyCandidate->GetManifestFile()->HasHostAssembly())
5122 pAssembly = pAssemblyCandidate;
5126 DWORD binderFlags = 0;
5127 ICLRPrivAssembly * pPrivBinder = pAssemblyCandidate->GetManifestFile()->GetHostAssembly();
5128 HRESULT hrBinderFlagCheck = pPrivBinder->GetBinderFlags(&binderFlags);
5129 if (SUCCEEDED(hrBinderFlagCheck) && (binderFlags & BINDER_FINDASSEMBLYBYSPEC_REQUIRES_EXACT_MATCH))
5131 pAssembly = pAssemblyCandidate;
5135 // This should only happen in the generic instantiation case when multiple threads are racing and
5136 // the assembly found is one which we will determine is the wrong assembly.
5138 // We can't assert that (as its possible under stress); however it shouldn't happen in the stack walk or GC case, so we assert in those cases.
5139 _ASSERTE("Non-AssemblySpecBindingCache based assembly found with extended search" && !(IsStackWalkerThread() || IsGCThread()) && IsGenericInstantiationLookupCompareThread());
5148 #endif // !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
5150 // Fills ppContainingWinRtAppDomain only if WinRT type name is passed and if the assembly is found (return value != NULL).
5152 Module::GetAssemblyIfLoaded(
5153 mdAssemblyRef kAssemblyRef,
5154 LPCSTR szWinRtNamespace, // = NULL
5155 LPCSTR szWinRtClassName, // = NULL
5156 IMDInternalImport * pMDImportOverride, // = NULL
5157 BOOL fDoNotUtilizeExtraChecks, // = FALSE
5158 ICLRPrivBinder *pBindingContextForLoadedAssembly // = NULL
5161 CONTRACT(Assembly *)
5168 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5173 Assembly * pAssembly = NULL;
5174 BOOL fCanUseRidMap = ((pMDImportOverride == NULL) &&
5175 (szWinRtNamespace == NULL));
5178 fCanUseRidMap = fCanUseRidMap && (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GetAssemblyIfLoadedIgnoreRidMap) == 0);
5181 // If we're here due to a generic instantiation, then we should only be querying information from the ngen image we're finding the generic instantiation in.
5182 #if !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
5183 _ASSERTE(!IsGenericInstantiationLookupCompareThread() || HasNativeImage());
5186 // Don't do a lookup if an override IMDInternalImport is provided, since the lookup is for the
5187 // standard IMDInternalImport and might result in an incorrect result.
5188 // WinRT references also do not update RID map, so don't try to look it up
5191 pAssembly = LookupAssemblyRef(kAssemblyRef);
5194 #ifndef DACCESS_COMPILE
5195 // Check if actually loaded, unless a GC is in progress or the current thread is
5196 // walking the stack (either its own stack, or another thread's stack) as that works
5197 // only with loaded assemblies
5199 // NOTE: The case where the current thread is walking a stack can be problematic for
5200 // other reasons, as the remaining code of this function uses "GetAppDomain()", when
5201 // in fact the right AppDomain to use is the one corresponding to the frame being
5202 // traversed on the walked thread. Dev10 TFS bug# 762348 tracks that issue.
5203 if ((pAssembly != NULL) && !IsGCThread() && !IsStackWalkerThread())
5205 _ASSERTE(::GetAppDomain() != NULL);
5206 DomainAssembly * pDomainAssembly = pAssembly->FindDomainAssembly(::GetAppDomain());
5207 if ((pDomainAssembly == NULL) || !pDomainAssembly->IsLoaded())
5210 #endif //!DACCESS_COMPILE
5212 if (pAssembly == NULL)
5214 // If in stackwalking or gc mode
5215 // For each AppDomain that is on the stack being walked...
5216 // For each AppDomain in the process... if gc'ing
5217 // For the current AppDomain ... if none of the above
5218 GetAssemblyIfLoadedAppDomainIterator appDomainIter;
5220 while (appDomainIter.Next())
5222 AppDomain * pAppDomainExamine = appDomainIter.GetDomain();
5224 DomainAssembly * pCurAssemblyInExamineDomain = GetAssembly()->FindDomainAssembly(pAppDomainExamine);
5225 if (pCurAssemblyInExamineDomain == NULL)
5230 #ifdef FEATURE_COMINTEROP
5231 if (szWinRtNamespace != NULL)
5233 _ASSERTE(szWinRtClassName != NULL);
5235 CLRPrivBinderWinRT * pWinRtBinder = pAppDomainExamine->GetWinRtBinder();
5236 if (pWinRtBinder == nullptr)
5237 { // We are most likely in AppX mode (calling AppX::IsAppXProcess() for verification is painful in DACCESS)
5238 #ifndef DACCESS_COMPILE
5239 // Note: We should also look
5240 // Check designer binding context present (only in AppXDesignMode)
5241 ICLRPrivBinder * pCurrentBinder = pAppDomainExamine->GetLoadContextHostBinder();
5242 if (pCurrentBinder != nullptr)
5243 { // We have designer binding context, look for the type in it
5244 ReleaseHolder<ICLRPrivWinRtTypeBinder> pCurrentWinRtTypeBinder;
5245 HRESULT hr = pCurrentBinder->QueryInterface(__uuidof(ICLRPrivWinRtTypeBinder), (void **)&pCurrentWinRtTypeBinder);
5247 // The binder should be an instance of code:CLRPrivBinderAppX class that implements the interface
5248 _ASSERTE(SUCCEEDED(hr) && (pCurrentWinRtTypeBinder != nullptr));
5252 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5253 pAssembly = (Assembly *)pCurrentWinRtTypeBinder->FindAssemblyForWinRtTypeIfLoaded(
5254 (void *)pAppDomainExamine,
5259 #endif //!DACCESS_COMPILE
5260 if (pAssembly == nullptr)
5265 if (pWinRtBinder != nullptr)
5267 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5268 pAssembly = pWinRtBinder->FindAssemblyForTypeIfLoaded(
5269 dac_cast<PTR_AppDomain>(pAppDomainExamine),
5274 // Never store WinMD AssemblyRefs into the rid map.
5275 if (pAssembly != NULL)
5280 // Never attemt to search the assembly spec binding cache for this form of WinRT assembly reference.
5283 #endif // FEATURE_COMINTEROP
5285 #ifndef DACCESS_COMPILE
5287 IMDInternalImport * pMDImport = (pMDImportOverride == NULL) ? (GetMDImport()) : (pMDImportOverride);
5289 //we have to be very careful here.
5290 //we are using InitializeSpecInternal so we need to make sure that under no condition
5291 //the data we pass to it can outlive the assembly spec.
5293 if (FAILED(spec.InitializeSpecInternal(kAssemblyRef,
5295 pCurAssemblyInExamineDomain,
5296 FALSE /*fAllowAllocation*/)))
5301 // If we have been passed the binding context for the loaded assembly that is being looked up in the
5302 // cache, then set it up in the AssemblySpec for the cache lookup to use it below.
5303 if (pBindingContextForLoadedAssembly != NULL)
5305 _ASSERTE(spec.GetBindingContext() == NULL);
5306 spec.SetBindingContext(pBindingContextForLoadedAssembly);
5308 DomainAssembly * pDomainAssembly = nullptr;
5311 pDomainAssembly = pAppDomainExamine->FindCachedAssembly(&spec, FALSE /*fThrow*/);
5314 if (pDomainAssembly && pDomainAssembly->IsLoaded())
5315 pAssembly = pDomainAssembly->GetCurrentAssembly(); // <NOTE> Do not use GetAssembly - that may force the completion of a load
5317 // Only store in the rid map if working with the current AppDomain.
5318 if (fCanUseRidMap && pAssembly && appDomainIter.UsingCurrentAD())
5319 StoreAssemblyRef(kAssemblyRef, pAssembly);
5321 if (pAssembly != NULL)
5324 #endif //!DACCESS_COMPILE
5328 #if !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
5329 if (pAssembly == NULL && (IsStackWalkerThread() || IsGCThread() || IsGenericInstantiationLookupCompareThread()) && !fDoNotUtilizeExtraChecks)
5331 // The GetAssemblyIfLoaded function must succeed in finding assemblies which have already been loaded in a series of interesting cases
5332 // (GC, Stackwalking, GenericInstantiationLookup). This logic is used to handle cases where the normal lookup done above
5333 // may fail, and more extensive (and slow) lookups are necessary. This logic is gated by a long series of checks to ensure it doesn't
5334 // run in cases which are not known to be problematic, or would not benefit from the logic here.
5336 // This is logic which tries extra possibilities to find an assembly. It is believed this logic can only be hit in cases where an ngen
5337 // image depends on an assembly through some sort of binding version/public key token adjustment (due to binding policy, unification, or portability rules)
5338 // and the assembly depended on was loaded through a binder that utilizes the AssemblySpecBindingCache for binder caching. (The cache's in the other
5339 // binder's successfully answer the GetAssemblyIfLoaded question in the case of non-exact matches where the match was discovered during
5340 // ngen resolution.)
5341 // This restricts the scenario to a somewhat restricted case.
5343 BOOL eligibleForAdditionalChecks = TRUE;
5344 if (szWinRtNamespace != NULL)
5345 eligibleForAdditionalChecks = FALSE; // WinRT binds do not support this scan
5346 else if (this->GetAssembly()->GetManifestFile()->IsDesignerBindingContext())
5348 eligibleForAdditionalChecks = FALSE;
5349 // assemblies loaded into leaf designer binding contexts cannot be ngen images, or be depended on by ngen assemblies that bind to different versions of assemblies.
5350 // However, in the shared designer binding context assemblies can be loaded with ngen images, and therefore can depend on assemblies in a designer binding context. (the shared context)
5351 // A more correct version of this check would probably allow assemblies loaded into the shared designer binding context to be eligibleForAdditionalChecks; however
5352 // there are problems. In particular, the logic below which scans through all native images is not strictly correct for scenarios involving a shared assembly context
5353 // as the shared assembly context may have different binding rules as compared to the root context. At this time, we prefer to not fix this scenario until
5354 // there is customer need for a fix.
5357 AssemblySpec specSearchAssemblyRef;
5359 // Get the assembly ref information that we are attempting to satisfy.
5360 if (eligibleForAdditionalChecks)
5362 IMDInternalImport * pMDImport = (pMDImportOverride == NULL) ? (GetMDImport()) : (pMDImportOverride);
5364 if (FAILED(specSearchAssemblyRef.InitializeSpecInternal(kAssemblyRef,
5367 FALSE /*fAllowAllocation*/)))
5369 eligibleForAdditionalChecks = FALSE; // If an assemblySpec can't be constructed then we're not going to succeed
5370 // This should not ever happen, due to the above checks, but this logic
5371 // is intended to be defensive against unexpected behavior.
5373 else if (specSearchAssemblyRef.IsContentType_WindowsRuntime())
5375 eligibleForAdditionalChecks = FALSE; // WinRT binds do not support this scan
5379 if (eligibleForAdditionalChecks)
5381 BOOL abortAdditionalChecks = false;
5383 // When working with an ngenn'd assembly, as an optimization we can scan only that module for dependency info.
5384 bool onlyScanCurrentModule = HasNativeImage() && GetFile()->IsAssembly();
5385 mdAssemblyRef foundAssemblyRef = mdAssemblyRefNil;
5387 GetAssemblyIfLoadedAppDomainIterator appDomainIter;
5389 // In each AppDomain that might be interesting, scan for an ngen image that is loaded that has a dependency on the same
5390 // assembly that is now being looked up. If that ngen image has the same dependency, then we can use the CORCOMPILE_DEPENDENCIES
5391 // table to find the exact AssemblyDef that defines the assembly, and attempt a load based on that information.
5392 // As this logic is expected to be used only in exceedingly rare situations, this code has not been tuned for performance
5394 while (!abortAdditionalChecks && appDomainIter.Next())
5396 AppDomain * pAppDomainExamine = appDomainIter.GetDomain();
5398 DomainAssembly * pCurAssemblyInExamineDomain = GetAssembly()->FindDomainAssembly(pAppDomainExamine);
5399 if (pCurAssemblyInExamineDomain == NULL)
5404 DomainFile *pDomainFileNativeImage;
5406 if (onlyScanCurrentModule)
5408 pDomainFileNativeImage = pCurAssemblyInExamineDomain;
5409 // Do not reset foundAssemblyRef.
5410 // This will allow us to avoid scanning for foundAssemblyRef in each domain we iterate through
5414 foundAssemblyRef = mdAssemblyRefNil;
5415 pDomainFileNativeImage = pAppDomainExamine->GetDomainFilesWithNativeImagesList();
5418 while (!abortAdditionalChecks && (pDomainFileNativeImage != NULL) && (pAssembly == NULL))
5420 Module *pNativeImageModule = pDomainFileNativeImage->GetCurrentModule();
5421 _ASSERTE(pNativeImageModule->HasNativeImage());
5422 IMDInternalImport *pImportFoundNativeImage = pNativeImageModule->GetNativeAssemblyImport(FALSE);
5423 if (pImportFoundNativeImage != NULL)
5425 if (IsNilToken(foundAssemblyRef))
5427 // Enumerate assembly refs in nmd space, and compare against held ref.
5428 HENUMInternalHolder hAssemblyRefEnum(pImportFoundNativeImage);
5429 if (FAILED(hAssemblyRefEnum.EnumInitNoThrow(mdtAssemblyRef, mdAssemblyRefNil)))
5434 mdAssemblyRef assemblyRef = mdAssemblyRefNil;
5436 // Find if the native image has a matching assembly ref in its compile dependencies.
5437 while (pImportFoundNativeImage->EnumNext(&hAssemblyRefEnum, &assemblyRef) && (pAssembly == NULL))
5439 AssemblySpec specFoundAssemblyRef;
5440 if (FAILED(specFoundAssemblyRef.InitializeSpecInternal(assemblyRef,
5441 pImportFoundNativeImage,
5443 FALSE /*fAllowAllocation*/)))
5445 continue; // If the spec cannot be loaded, it isn't the one we're looking for
5448 // Check for AssemblyRef equality
5449 if (specSearchAssemblyRef.CompareEx(&specFoundAssemblyRef))
5451 foundAssemblyRef = assemblyRef;
5457 pAssembly = pNativeImageModule->GetAssemblyIfLoadedFromNativeAssemblyRefWithRefDefMismatch(foundAssemblyRef, &abortAdditionalChecks);
5459 if (fCanUseRidMap && pAssembly && appDomainIter.UsingCurrentAD())
5460 StoreAssemblyRef(kAssemblyRef, pAssembly);
5463 // If we're only scanning one module for accurate dependency information, break the loop here.
5464 if (onlyScanCurrentModule)
5467 pDomainFileNativeImage = pDomainFileNativeImage->FindNextDomainFileWithNativeImage();
5472 #endif // !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
5474 // When walking the stack or computing GC information this function should never fail.
5475 _ASSERTE((pAssembly != NULL) || !(IsStackWalkerThread() || IsGCThread()));
5477 #ifdef DACCESS_COMPILE
5479 // Note: In rare cases when debugger walks the stack, we could actually have pAssembly=NULL here.
5480 // To fix that we should DACize the AppDomain-iteration code above (especially AssemblySpec).
5481 _ASSERTE(pAssembly != NULL);
5483 #endif //DACCESS_COMPILE
5486 } // Module::GetAssemblyIfLoaded
5489 Module::GetAssemblyRefFlags(
5490 mdAssemblyRef tkAssemblyRef)
5494 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
5500 _ASSERTE(TypeFromToken(tkAssemblyRef) == mdtAssemblyRef);
5502 LPCSTR pszAssemblyName;
5503 const void *pbPublicKeyOrToken;
5504 DWORD cbPublicKeyOrToken;
5506 DWORD dwAssemblyRefFlags;
5507 IfFailThrow(GetMDImport()->GetAssemblyRefProps(
5509 &pbPublicKeyOrToken,
5510 &cbPublicKeyOrToken,
5515 &dwAssemblyRefFlags));
5517 return dwAssemblyRefFlags;
5518 } // Module::GetAssemblyRefFlags
5520 #ifndef DACCESS_COMPILE
5523 // szWinRtTypeNamespace ... Namespace of WinRT type.
5524 // szWinRtTypeClassName ... Name of WinRT type, NULL for non-WinRT (classic) types.
5525 DomainAssembly * Module::LoadAssembly(
5526 AppDomain * pDomain,
5527 mdAssemblyRef kAssemblyRef,
5528 LPCUTF8 szWinRtTypeNamespace,
5529 LPCUTF8 szWinRtTypeClassName)
5531 CONTRACT(DomainAssembly *)
5534 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
5535 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
5536 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM();); }
5538 PRECONDITION(CheckPointer(pDomain));
5539 POSTCONDITION(CheckPointer(RETVAL, NULL_NOT_OK));
5540 //POSTCONDITION((CheckPointer(GetAssemblyIfLoaded(kAssemblyRef, szWinRtTypeNamespace, szWinRtTypeClassName)), NULL_NOT_OK));
5544 ETWOnStartup (LoaderCatchCall_V1, LoaderCatchCallEnd_V1);
5546 DomainAssembly * pDomainAssembly;
5549 // Early out quickly if the result is cached
5551 Assembly * pAssembly = LookupAssemblyRef(kAssemblyRef);
5552 if (pAssembly != NULL)
5554 _ASSERTE(HasBindableIdentity(kAssemblyRef));
5556 pDomainAssembly = pAssembly->FindDomainAssembly(pDomain);
5558 if (pDomainAssembly == NULL)
5559 pDomainAssembly = pAssembly->GetDomainAssembly(pDomain);
5560 pDomain->LoadDomainFile(pDomainAssembly, FILE_LOADED);
5562 RETURN pDomainAssembly;
5565 bool fHasBindableIdentity = HasBindableIdentity(kAssemblyRef);
5568 PEAssemblyHolder pFile = GetDomainFile(GetAppDomain())->GetFile()->LoadAssembly(
5571 szWinRtTypeNamespace,
5572 szWinRtTypeClassName);
5574 spec.InitializeSpec(kAssemblyRef, GetMDImport(), GetDomainFile(GetAppDomain())->GetDomainAssembly());
5575 // Set the binding context in the AssemblySpec if one is available. This can happen if the LoadAssembly ended up
5576 // invoking the custom AssemblyLoadContext implementation that returned a reference to an assembly bound to a different
5577 // AssemblyLoadContext implementation.
5578 ICLRPrivBinder *pBindingContext = pFile->GetBindingContext();
5579 if (pBindingContext != NULL)
5581 spec.SetBindingContext(pBindingContext);
5583 if (szWinRtTypeClassName != NULL)
5585 spec.SetWindowsRuntimeType(szWinRtTypeNamespace, szWinRtTypeClassName);
5587 pDomainAssembly = GetAppDomain()->LoadDomainAssembly(&spec, pFile, FILE_LOADED);
5590 if (pDomainAssembly != NULL)
5593 !fHasBindableIdentity || // GetAssemblyIfLoaded will not find non-bindable assemblies
5594 pDomainAssembly->IsSystem() || // GetAssemblyIfLoaded will not find mscorlib (see AppDomain::FindCachedFile)
5595 !pDomainAssembly->IsLoaded() || // GetAssemblyIfLoaded will not find not-yet-loaded assemblies
5596 GetAssemblyIfLoaded(kAssemblyRef, NULL, NULL, NULL, FALSE, pDomainAssembly->GetFile()->GetHostAssembly()) != NULL); // GetAssemblyIfLoaded should find all remaining cases
5598 // Note: We cannot cache WinRT AssemblyRef, because it is meaningless without the TypeRef context
5599 if (pDomainAssembly->GetCurrentAssembly() != NULL)
5601 if (fHasBindableIdentity)
5603 StoreAssemblyRef(kAssemblyRef, pDomainAssembly->GetCurrentAssembly());
5608 RETURN pDomainAssembly;
5611 #endif // !DACCESS_COMPILE
5613 Module *Module::GetModuleIfLoaded(mdFile kFile, BOOL onlyLoadedInAppDomain, BOOL permitResources)
5621 PRECONDITION(TypeFromToken(kFile) == mdtFile
5622 || TypeFromToken(kFile) == mdtModuleRef);
5623 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5629 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5631 // Handle the module ref case
5632 if (TypeFromToken(kFile) == mdtModuleRef)
5635 if (FAILED(GetMDImport()->GetModuleRefProps(kFile, &moduleName)))
5640 // This is required only because of some lower casing on the name
5641 kFile = GetAssembly()->GetManifestFileToken(moduleName);
5642 if (kFile == mdTokenNil)
5645 RETURN GetAssembly()->GetManifestModule()->GetModuleIfLoaded(kFile, onlyLoadedInAppDomain, permitResources);
5648 Module *pModule = LookupFile(kFile);
5649 if (pModule == NULL)
5653 if (kFile == mdFileNil)
5654 pModule = GetAssembly()->GetManifestModule();
5658 // If we didn't find it there, look at the "master rid map" in the manifest file
5659 Assembly *pAssembly = GetAssembly();
5662 // This is required only because of some lower casing on the name
5663 kMatch = pAssembly->GetManifestFileToken(GetMDImport(), kFile);
5664 if (IsNilToken(kMatch))
5666 if (kMatch == mdFileNil)
5668 pModule = pAssembly->GetManifestModule();
5676 pModule = pAssembly->GetManifestModule()->LookupFile(kMatch);
5679 #ifndef DACCESS_COMPILE
5680 if (pModule != NULL)
5681 StoreFileNoThrow(kFile, pModule);
5685 // We may not want to return a resource module
5686 if (!permitResources && pModule && pModule->IsResource())
5689 #ifndef DACCESS_COMPILE
5690 #endif // !DACCESS_COMPILE
5694 #ifndef DACCESS_COMPILE
5696 DomainFile *Module::LoadModule(AppDomain *pDomain, mdFile kFile,
5697 BOOL permitResources/*=TRUE*/, BOOL bindOnly/*=FALSE*/)
5699 CONTRACT(DomainFile *)
5705 PRECONDITION(TypeFromToken(kFile) == mdtFile
5706 || TypeFromToken(kFile) == mdtModuleRef);
5707 POSTCONDITION(CheckPointer(RETVAL, !permitResources || bindOnly ? NULL_OK : NULL_NOT_OK));
5717 LPCSTR psModuleName=NULL;
5718 if (TypeFromToken(kFile) == mdtModuleRef)
5720 // This is a moduleRef
5721 IfFailThrow(GetMDImport()->GetModuleRefProps(kFile, &psModuleName));
5726 IfFailThrow(GetAssembly()->GetManifestImport()->GetFileProps(kFile,
5732 SString name(SString::Utf8, psModuleName);
5733 EEFileLoadException::Throw(name, COR_E_MULTIMODULEASSEMBLIESDIALLOWED, NULL);
5736 #endif // !DACCESS_COMPILE
5738 PTR_Module Module::LookupModule(mdToken kFile,BOOL permitResources/*=TRUE*/)
5740 CONTRACT(PTR_Module)
5743 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
5744 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
5745 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT;
5746 else { INJECT_FAULT(COMPlusThrowOM()); }
5748 PRECONDITION(TypeFromToken(kFile) == mdtFile
5749 || TypeFromToken(kFile) == mdtModuleRef);
5750 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5755 if (TypeFromToken(kFile) == mdtModuleRef)
5758 IfFailThrow(GetMDImport()->GetModuleRefProps(kFile, &moduleName));
5759 mdFile kFileLocal = GetAssembly()->GetManifestFileToken(moduleName);
5761 if (kFileLocal == mdTokenNil)
5762 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
5764 RETURN GetAssembly()->GetManifestModule()->LookupModule(kFileLocal, permitResources);
5767 PTR_Module pModule = LookupFile(kFile);
5768 if (pModule == NULL && !IsManifest())
5770 // If we didn't find it there, look at the "master rid map" in the manifest file
5771 Assembly *pAssembly = GetAssembly();
5772 mdFile kMatch = pAssembly->GetManifestFileToken(GetMDImport(), kFile);
5773 if (IsNilToken(kMatch)) {
5774 if (kMatch == mdFileNil)
5775 pModule = pAssembly->GetManifestModule();
5777 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
5780 pModule = pAssembly->GetManifestModule()->LookupFile(kMatch);
5786 TypeHandle Module::LookupTypeRef(mdTypeRef token)
5788 STATIC_CONTRACT_NOTHROW;
5789 STATIC_CONTRACT_GC_NOTRIGGER;
5790 STATIC_CONTRACT_FORBID_FAULT;
5793 _ASSERTE(TypeFromToken(token) == mdtTypeRef);
5795 g_IBCLogger.LogRidMapAccess( MakePair( this, token ) );
5797 TypeHandle entry = TypeHandle::FromTAddr(dac_cast<TADDR>(m_TypeRefToMethodTableMap.GetElement(RidFromToken(token))));
5800 return TypeHandle();
5802 // Cannot do this in a NOTHROW function.
5803 // Note that this could be called while doing GC from the prestub of
5804 // a method to resolve typerefs in a signature. We cannot THROW
5807 // @PERF: Enable this so that we do not need to touch metadata
5808 // to resolve typerefs
5810 #ifdef FIXUPS_ALL_TYPEREFS
5812 if (CORCOMPILE_IS_POINTER_TAGGED((SIZE_T) entry.AsPtr()))
5814 #ifndef DACCESS_COMPILE
5815 Module::RestoreTypeHandlePointer(&entry, TRUE);
5816 m_TypeRefToMethodTableMap.SetElement(RidFromToken(token), dac_cast<PTR_TypeRef>(value.AsTAddr()));
5817 #else // DACCESS_COMPILE
5819 #endif // DACCESS_COMPILE
5822 #endif // FIXUPS_ALL_TYPEREFS
5827 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
5828 mdTypeRef Module::LookupTypeRefByMethodTable(MethodTable *pMT)
5830 STANDARD_VM_CONTRACT;
5832 HENUMInternalHolder hEnumTypeRefs(GetMDImport());
5834 hEnumTypeRefs.EnumAllInit(mdtTypeRef);
5835 while (hEnumTypeRefs.EnumNext(&token))
5837 TypeHandle thRef = LookupTypeRef(token);
5838 if (thRef.IsNull() || thRef.IsTypeDesc())
5843 MethodTable *pMTRef = thRef.AsMethodTable();
5844 if (pMT->HasSameTypeDefAs(pMTRef))
5846 _ASSERTE(pMTRef->IsTypicalTypeDefinition());
5851 #ifdef FEATURE_READYTORUN_COMPILER
5852 if (IsReadyToRunCompilation())
5854 if (pMT->GetClass()->IsEquivalentType())
5856 GetSvcLogger()->Log(W("ReadyToRun: Type reference to equivalent type cannot be encoded\n"));
5860 // FUTURE: Encoding of new cross-module references for ReadyToRun
5861 // This warning is hit for recursive cross-module inlining. It is commented out to avoid noise.
5862 // GetSvcLogger()->Log(W("ReadyToRun: Type reference outside of current version bubble cannot be encoded\n"));
5865 #endif // FEATURE_READYTORUN_COMPILER
5867 // FUTURE TODO: Version resilience
5868 _ASSERTE(!"Cross module type reference not found");
5873 mdMemberRef Module::LookupMemberRefByMethodDesc(MethodDesc *pMD)
5875 STANDARD_VM_CONTRACT;
5877 HENUMInternalHolder hEnumMemberRefs(GetMDImport());
5879 hEnumMemberRefs.EnumAllInit(mdtMemberRef);
5880 while (hEnumMemberRefs.EnumNext(&token))
5882 BOOL fIsMethod = FALSE;
5883 TADDR addr = LookupMemberRef(token, &fIsMethod);
5886 MethodDesc *pCurMD = dac_cast<PTR_MethodDesc>(addr);
5894 // FUTURE TODO: Version resilience
5895 _ASSERTE(!"Cross module method reference not found");
5898 #endif // FEATURE_NATIVE_IMAGE_GENERATION
5900 #ifndef DACCESS_COMPILE
5903 // Increase the size of one of the maps, such that it can handle a RID of at least "rid".
5905 // This function must also check that another thread didn't already add a LookupMap capable
5906 // of containing the same RID.
5908 PTR_TADDR LookupMapBase::GrowMap(Module * pModule, DWORD rid)
5916 INJECT_FAULT(ThrowOutOfMemory(););
5917 POSTCONDITION(CheckPointer(RETVAL));
5921 LookupMapBase *pMap = this;
5922 LookupMapBase *pPrev = NULL;
5923 LookupMapBase *pNewMap = NULL;
5925 // Initial block size
5926 DWORD dwIndex = rid;
5927 DWORD dwBlockSize = 16;
5930 CrstHolder ch(pModule->GetLookupTableCrst());
5931 // Check whether we can already handle this RID index
5934 if (dwIndex < pMap->dwCount)
5936 // Already there - some other thread must have added it
5937 RETURN pMap->GetIndexPtr(dwIndex);
5942 dwIndex -= pMap->dwCount;
5946 } while (pMap != NULL);
5948 _ASSERTE(pPrev != NULL); // should never happen, because there's always at least one map
5950 DWORD dwSizeToAllocate = max(dwIndex + 1, dwBlockSize);
5952 pNewMap = (LookupMapBase *) (void*)pModule->GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(LookupMapBase)) + S_SIZE_T(dwSizeToAllocate)*S_SIZE_T(sizeof(TADDR)));
5954 // Note: Memory allocated on loader heap is zero filled
5955 // memset(pNewMap, 0, sizeof(LookupMap) + dwSizeToAllocate*sizeof(void*));
5957 pNewMap->pNext = NULL;
5958 pNewMap->dwCount = dwSizeToAllocate;
5960 pNewMap->pTable = dac_cast<ArrayDPTR(TADDR)>(pNewMap + 1);
5962 // Link ourselves in
5963 VolatileStore<LookupMapBase*>(&(pPrev->pNext), pNewMap);
5966 RETURN pNewMap->GetIndexPtr(dwIndex);
5969 #endif // DACCESS_COMPILE
5971 PTR_TADDR LookupMapBase::GetElementPtr(DWORD rid)
5984 LookupMapBase * pMap = this;
5986 #ifdef FEATURE_PREJIT
5987 if (pMap->dwNumHotItems > 0)
5990 static DWORD counter = 0;
5992 if (counter >= pMap->dwNumHotItems)
5994 CheckConsistentHotItemList();
5997 #endif // _DEBUG_IMPL
5999 PTR_TADDR pHotItemValue = pMap->FindHotItemValuePtr(rid);
6002 return pHotItemValue;
6005 #endif // FEATURE_PREJIT
6007 DWORD dwIndex = rid;
6010 if (dwIndex < pMap->dwCount)
6012 return pMap->GetIndexPtr(dwIndex);
6015 dwIndex -= pMap->dwCount;
6017 } while (pMap != NULL);
6023 #ifdef FEATURE_PREJIT
6025 // This method can only be called on a compressed map (MapIsCompressed() == true). Compressed rid maps store
6026 // the array of values as packed deltas (each value is based on the accumulated of all the previous entries).
6027 // So this method takes the bit stream of compressed data we're navigating and the value of the last entry
6028 // retrieved allowing us to calculate the full value of the next entry. Note that the values passed in and out
6029 // here aren't the final values the top-level caller sees. In order to avoid having to touch the compressed
6030 // data on image base relocations we actually store a form of RVA (though relative to the map base rather than
6031 // the module base).
6032 INT32 LookupMapBase::GetNextCompressedEntry(BitStreamReader *pTableStream, INT32 iLastValue)
6042 PRECONDITION(MapIsCompressed());
6046 // The next kLookupMapLengthBits bits in the stream are an index into a per-map table that tells us the
6047 // length of the encoded delta.
6048 DWORD dwValueLength = rgEncodingLengths[pTableStream->Read(kLookupMapLengthBits)];
6050 // Then follows a single bit that indicates whether the delta should be added (1) or subtracted (0) from
6051 // the previous entry value to recover the current entry value.
6052 // Once we've read that bit we read the delta (encoded as an unsigned integer using the number of bits
6053 // that we read from the encoding lengths table above).
6054 if (pTableStream->ReadOneFast())
6055 return iLastValue + (INT32)(pTableStream->Read(dwValueLength));
6057 return iLastValue - (INT32)(pTableStream->Read(dwValueLength));
6060 // This method can only be called on a compressed map (MapIsCompressed() == true). Retrieves the final value
6061 // (e.g. MethodTable*, MethodDesc* etc. based on map type) given the rid of the entry.
6062 TADDR LookupMapBase::GetValueFromCompressedMap(DWORD rid)
6072 PRECONDITION(MapIsCompressed());
6076 // Normally to extract the nth entry in the table we have to linearly parse all (n - 1) preceding entries
6077 // (since entries are stored as the delta from the previous entry). Obviously this can yield exceptionally
6078 // poor performance for the later entries in large tables. So we also build an index of the compressed
6079 // stream. This index has an entry for every kLookupMapIndexStride entries in the compressed table. Each
6080 // index entry contains the full RVA (relative to the map) of the corresponding table entry plus the bit
6081 // offset in the stream from which to start parsing the next entry's data.
6082 // In this fashion we can get to within kLookupMapIndexStride entries of our target entry and then decode
6083 // our way to the final target.
6085 // Ensure that index does not go beyond end of the saved table
6089 // Calculate the nearest entry in the index that is lower than our target index in the full table.
6090 DWORD dwIndexEntry = rid / kLookupMapIndexStride;
6092 // Then calculate how many additional entries we'll need to decode from the compressed streams to recover
6093 // the target entry.
6094 DWORD dwSubIndex = rid % kLookupMapIndexStride;
6096 // Open a bit stream reader on the index and skip all the entries prior to the one we're interested in.
6097 BitStreamReader sIndexStream(pIndex);
6098 sIndexStream.Skip(dwIndexEntry * cIndexEntryBits);
6100 // The first kBitsPerRVA of the index entry contain the RVA of the corresponding entry in the compressed
6101 // table. If this is exactly the entry we want (dwSubIndex == 0) then we can use this RVA to recover the
6102 // value the caller wants. Our RVAs are based on the map address rather than the module base (simply
6103 // because we don't record the module base in LookupMapBase). A delta of zero encodes a null value,
6104 // otherwise we simply add the RVA to the our map address to recover the full pointer.
6105 // Note that most LookupMaps are embedded structures (in Module) so we can't directly dac_cast<TADDR> our
6106 // "this" pointer for DAC builds. Instead we have to use the slightly slower (in DAC) but more flexible
6107 // PTR_HOST_INT_TO_TADDR() which copes with interior host pointers.
6108 INT32 iValue = (INT32)sIndexStream.Read(kBitsPerRVA);
6109 if (dwSubIndex == 0)
6110 return iValue ? PTR_HOST_INT_TO_TADDR(this) + iValue : 0;
6112 // Otherwise we must parse one or more entries in the compressed table to accumulate more deltas to the
6113 // base RVA we read above. The remaining portion of the index entry has the bit offset into the compressed
6114 // table at which to begin parsing.
6115 BitStreamReader sTableStream(dac_cast<PTR_CBYTE>(pTable));
6116 sTableStream.Skip(sIndexStream.Read(cIndexEntryBits - kBitsPerRVA));
6118 // Parse all the entries up to our target entry. Each step takes the RVA from the previous cycle (or from
6119 // the index entry we read above) and applies the compressed delta of the next table entry to it.
6120 for (DWORD i = 0; i < dwSubIndex; i++)
6121 iValue = GetNextCompressedEntry(&sTableStream, iValue);
6123 // We have the final RVA so recover the actual pointer from it (a zero RVA encodes a NULL pointer). Note
6124 // the use of PTR_HOST_INT_TO_TADDR() rather than dac_cast<TADDR>, see previous comment on
6125 // PTR_HOST_INT_TO_TADDR for an explanation.
6126 return iValue ? PTR_HOST_INT_TO_TADDR(this) + iValue : 0;
6129 PTR_TADDR LookupMapBase::FindHotItemValuePtr(DWORD rid)
6131 LIMITED_METHOD_DAC_CONTRACT;
6133 if (dwNumHotItems < 5)
6135 // do simple linear search if there are only a few hot items
6136 for (DWORD i = 0; i < dwNumHotItems; i++)
6138 if (hotItemList[i].rid == rid)
6139 return dac_cast<PTR_TADDR>(
6140 dac_cast<TADDR>(hotItemList) + i * sizeof(HotItem) + offsetof(HotItem, value));
6145 // otherwise do binary search
6146 if (hotItemList[0].rid <= rid && rid <= hotItemList[dwNumHotItems-1].rid)
6149 DWORD r = dwNumHotItems;
6153 _ASSERTE(hotItemList[l].rid <= rid && (r >= dwNumHotItems || rid < hotItemList[r].rid));
6155 DWORD m = (l + r)/2;
6156 // loop condition implies l < m < r, hence interval shrinks every iteration, hence loop terminates
6157 _ASSERTE(l < m && m < r);
6158 if (rid < hotItemList[m].rid)
6163 // now we know l + 1 == r && hotItemList[l].rid <= rid < hotItemList[r].rid
6165 _ASSERTE(hotItemList[l].rid <= rid && (r >= dwNumHotItems || rid < hotItemList[r].rid));
6166 if (hotItemList[l].rid == rid)
6167 return dac_cast<PTR_TADDR>(
6168 dac_cast<TADDR>(hotItemList) + l * sizeof(HotItem) + offsetof(HotItem, value));
6175 void LookupMapBase::CheckConsistentHotItemList()
6177 LIMITED_METHOD_DAC_CONTRACT;
6179 for (DWORD i = 0; i < dwNumHotItems; i++)
6181 DWORD rid = hotItemList[i].rid;
6183 PTR_TADDR pHotValue = dac_cast<PTR_TADDR>(
6184 dac_cast<TADDR>(hotItemList) + i * sizeof(HotItem) + offsetof(HotItem, value));
6185 TADDR hotValue = RelativePointer<TADDR>::GetValueMaybeNullAtPtr(dac_cast<TADDR>(pHotValue));
6188 if (MapIsCompressed())
6190 value = GetValueFromCompressedMap(rid);
6194 PTR_TADDR pValue = GetIndexPtr(rid);
6195 value = RelativePointer<TADDR>::GetValueMaybeNullAtPtr(dac_cast<TADDR>(pValue));
6198 _ASSERTE(hotValue == value || value == NULL);
6203 #endif // FEATURE_PREJIT
6205 // Get number of RIDs that this table can store
6206 DWORD LookupMapBase::GetSize()
6218 LookupMapBase * pMap = this;
6222 dwSize += pMap->dwCount;
6224 } while (pMap != NULL);
6229 #ifndef DACCESS_COMPILE
6232 void LookupMapBase::DebugGetRidMapOccupancy(DWORD *pdwOccupied, DWORD *pdwSize)
6234 LIMITED_METHOD_CONTRACT;
6239 LookupMapBase * pMap = this;
6241 // Go through each linked block
6242 for (; pMap != NULL; pMap = pMap->pNext)
6244 DWORD dwIterCount = pMap->dwCount;
6246 for (DWORD i = 0; i < dwIterCount; i++)
6248 #ifdef FEATURE_PREJIT
6249 if (pMap->MapIsCompressed())
6251 if (pMap->GetValueFromCompressedMap(i))
6255 #endif // FEATURE_PREJIT
6256 if (pMap->pTable[i] != NULL)
6260 (*pdwSize) += dwIterCount;
6264 void Module::DebugLogRidMapOccupancy()
6266 WRAPPER_NO_CONTRACT;
6268 #define COMPUTE_RID_MAP_OCCUPANCY(var_suffix, map) \
6269 DWORD dwOccupied##var_suffix, dwSize##var_suffix, dwPercent##var_suffix; \
6270 map.DebugGetRidMapOccupancy(&dwOccupied##var_suffix, &dwSize##var_suffix); \
6271 dwPercent##var_suffix = dwOccupied##var_suffix ? ((dwOccupied##var_suffix * 100) / dwSize##var_suffix) : 0;
6273 COMPUTE_RID_MAP_OCCUPANCY(1, m_TypeDefToMethodTableMap);
6274 COMPUTE_RID_MAP_OCCUPANCY(2, m_TypeRefToMethodTableMap);
6275 COMPUTE_RID_MAP_OCCUPANCY(3, m_MethodDefToDescMap);
6276 COMPUTE_RID_MAP_OCCUPANCY(4, m_FieldDefToDescMap);
6277 COMPUTE_RID_MAP_OCCUPANCY(5, m_GenericParamToDescMap);
6278 COMPUTE_RID_MAP_OCCUPANCY(6, m_GenericTypeDefToCanonMethodTableMap);
6279 COMPUTE_RID_MAP_OCCUPANCY(7, m_FileReferencesMap);
6280 COMPUTE_RID_MAP_OCCUPANCY(8, m_ManifestModuleReferencesMap);
6281 COMPUTE_RID_MAP_OCCUPANCY(9, m_MethodDefToPropertyInfoMap);
6287 " TypeDefToMethodTable map: %4d/%4d (%2d %%)\n"
6288 " TypeRefToMethodTable map: %4d/%4d (%2d %%)\n"
6289 " MethodDefToDesc map: %4d/%4d (%2d %%)\n"
6290 " FieldDefToDesc map: %4d/%4d (%2d %%)\n"
6291 " GenericParamToDesc map: %4d/%4d (%2d %%)\n"
6292 " GenericTypeDefToCanonMethodTable map: %4d/%4d (%2d %%)\n"
6293 " FileReferences map: %4d/%4d (%2d %%)\n"
6294 " AssemblyReferences map: %4d/%4d (%2d %%)\n"
6295 " MethodDefToPropInfo map: %4d/%4d (%2d %%)\n"
6297 dwOccupied1, dwSize1, dwPercent1,
6298 dwOccupied2, dwSize2, dwPercent2,
6299 dwOccupied3, dwSize3, dwPercent3,
6300 dwOccupied4, dwSize4, dwPercent4,
6301 dwOccupied5, dwSize5, dwPercent5,
6302 dwOccupied6, dwSize6, dwPercent6,
6303 dwOccupied7, dwSize7, dwPercent7,
6304 dwOccupied8, dwSize8, dwPercent8,
6305 dwOccupied9, dwSize9, dwPercent9
6308 #undef COMPUTE_RID_MAP_OCCUPANCY
6312 BOOL Module::CanExecuteCode()
6314 WRAPPER_NO_CONTRACT;
6316 #ifdef FEATURE_PREJIT
6317 // In a passive domain, we lock down which assemblies can run code
6318 if (!GetAppDomain()->IsPassiveDomain())
6321 Assembly * pAssembly = GetAssembly();
6322 PEAssembly * pPEAssembly = pAssembly->GetManifestFile();
6324 // Only mscorlib is allowed to execute code in an ngen passive domain
6325 if (IsCompilationProcess())
6326 return pPEAssembly->IsSystem();
6328 // ExecuteDLLForAttach does not run the managed entry point in
6329 // a passive domain to avoid loader-lock deadlocks.
6330 // Hence, it is not safe to execute any code from this assembly.
6331 if (pPEAssembly->GetEntryPointToken(INDEBUG(TRUE)) != mdTokenNil)
6334 // EXEs loaded using LoadAssembly() may not be loaded at their
6335 // preferred base address. If they have any relocs, these may
6336 // not have been fixed up.
6337 if (!pPEAssembly->IsDll() && !pPEAssembly->IsILOnly())
6339 #endif // FEATURE_PREJIT
6345 // FindMethod finds a MethodDesc for a global function methoddef or ref
6348 MethodDesc *Module::FindMethodThrowing(mdToken pMethod)
6350 CONTRACT (MethodDesc *)
6356 POSTCONDITION(CheckPointer(RETVAL));
6360 SigTypeContext typeContext; /* empty type context: methods will not be generic */
6361 RETURN MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(this, pMethod,
6363 TRUE, /* strictMetadataChecks */
6364 FALSE /* dont get code shared between generic instantiations */);
6368 // FindMethod finds a MethodDesc for a global function methoddef or ref
6371 MethodDesc *Module::FindMethod(mdToken pMethod)
6373 CONTRACT (MethodDesc *) {
6378 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6381 MethodDesc *pMDRet = NULL;
6385 pMDRet = FindMethodThrowing(pMethod);
6390 CONTRACT_VIOLATION(ThrowsViolation);
6391 char szMethodName [MAX_CLASSNAME_LENGTH];
6392 CEEInfo::findNameOfToken(this, pMethod, szMethodName, COUNTOF (szMethodName));
6393 // This used to be LF_IJW, but changed to LW_INTEROP to reclaim a bit in our log facilities
6394 // IJW itself is not supported in coreclr so this code should never be run.
6395 LOG((LF_INTEROP, LL_INFO10, "Failed to find Method: %s for Vtable Fixup\n", szMethodName));
6398 EX_END_CATCH(SwallowAllExceptions)
6404 // PopulatePropertyInfoMap precomputes property information during NGen
6405 // that is expensive to look up from metadata at runtime.
6408 void Module::PopulatePropertyInfoMap()
6416 PRECONDITION(IsCompilationProcess());
6420 IMDInternalImport* mdImport = GetMDImport();
6421 HENUMInternalHolder hEnum(mdImport);
6422 hEnum.EnumAllInit(mdtMethodDef);
6425 while (hEnum.EnumNext(&md))
6427 mdProperty prop = 0;
6429 if (mdImport->GetPropertyInfoForMethodDef(md, &prop, NULL, &semantic) == S_OK)
6431 // Store the Rid in the lower 24 bits and the semantic in the upper 8
6432 _ASSERTE((semantic & 0xFFFFFF00) == 0);
6433 SIZE_T value = RidFromToken(prop) | (semantic << 24);
6435 // We need to make sure a value of zero indicates an empty LookupMap entry
6436 // Fortunately the semantic will prevent value from being zero
6437 _ASSERTE(value != 0);
6439 m_MethodDefToPropertyInfoMap.AddElement(this, RidFromToken(md), value);
6442 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_METHODDEF_TO_PROPERTYINFO_MAP);
6446 // GetPropertyInfoForMethodDef wraps the metadata function of the same name,
6447 // first trying to use the information stored in m_MethodDefToPropertyInfoMap.
6450 HRESULT Module::GetPropertyInfoForMethodDef(mdMethodDef md, mdProperty *ppd, LPCSTR *pName, ULONG *pSemantic)
6464 if ((m_dwPersistedFlags & COMPUTED_METHODDEF_TO_PROPERTYINFO_MAP) != 0)
6466 SIZE_T value = m_MethodDefToPropertyInfoMap.GetElement(RidFromToken(md));
6469 _ASSERTE(GetMDImport()->GetPropertyInfoForMethodDef(md, ppd, pName, pSemantic) == S_FALSE);
6474 // Decode the value into semantic and mdProperty as described in PopulatePropertyInfoMap
6475 ULONG semantic = (value & 0xFF000000) >> 24;
6476 mdProperty prop = TokenFromRid(value & 0x00FFFFFF, mdtProperty);
6482 _ASSERTE(GetMDImport()->GetPropertyInfoForMethodDef(md, &dbgPd, &dbgName, &dbgSemantic) == S_OK);
6488 _ASSERTE(*ppd == dbgPd);
6491 if (pSemantic != NULL)
6493 *pSemantic = semantic;
6494 _ASSERTE(*pSemantic == dbgSemantic);
6499 IfFailRet(GetMDImport()->GetPropertyProps(prop, pName, NULL, NULL, NULL));
6502 HRESULT hr = GetMDImport()->GetPropertyProps(prop, pName, NULL, NULL, NULL);
6503 _ASSERTE(hr == S_OK);
6504 _ASSERTE(strcmp(*pName, dbgName) == 0);
6512 return GetMDImport()->GetPropertyInfoForMethodDef(md, ppd, pName, pSemantic);
6515 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6516 // Fill the m_propertyNameSet hash filter with data that represents every
6517 // property and its name in the module.
6518 void Module::PrecomputeMatchingProperties(DataImage *image)
6523 PRECONDITION(IsCompilationProcess());
6527 IMDInternalImport* mdImport = GetMDImport();
6529 m_nPropertyNameSet = mdImport->GetCountWithTokenKind(mdtProperty);
6531 if (m_nPropertyNameSet == 0)
6536 m_propertyNameSet = new (image->GetHeap()) BYTE[m_nPropertyNameSet];
6538 DWORD nEnumeratedProperties = 0;
6540 HENUMInternalHolder hEnumTypes(mdImport);
6541 hEnumTypes.EnumAllInit(mdtTypeDef);
6543 // Enumerate all properties of all types
6545 while (hEnumTypes.EnumNext(&tkType))
6547 HENUMInternalHolder hEnumPropertiesForType(mdImport);
6548 hEnumPropertiesForType.EnumInit(mdtProperty, tkType);
6550 mdProperty tkProperty;
6551 while (hEnumPropertiesForType.EnumNext(&tkProperty))
6554 HRESULT hr = GetMDImport()->GetPropertyProps(tkProperty, &name, NULL, NULL, NULL);
6557 ++nEnumeratedProperties;
6559 // Use a case-insensitive hash so that we can use this value for
6560 // both case-sensitive and case-insensitive name lookups
6561 SString ssName(SString::Utf8Literal, name);
6562 ULONG nameHashValue = ssName.HashCaseInsensitive();
6564 // Set one bit in m_propertyNameSet per iteration
6565 // This will allow lookup to ensure that the bit from each iteration is set
6566 // and if any are not set, know that the (tkProperty,name) pair is not valid
6567 for (DWORD i = 0; i < NUM_PROPERTY_SET_HASHES; ++i)
6569 DWORD currentHashValue = HashThreeToOne(tkProperty, nameHashValue, i);
6570 DWORD bitPos = currentHashValue % (m_nPropertyNameSet * 8);
6571 m_propertyNameSet[bitPos / 8] |= (1 << bitPos % 8);
6576 _ASSERTE(nEnumeratedProperties == m_nPropertyNameSet);
6578 #endif // FEATURE_NATIVE_IMAGE_GENERATION
6580 // Check whether the module might possibly have a property with a name with
6581 // the passed hash value without accessing the property's name. This is done
6582 // by consulting a hash filter populated at NGen time.
6583 BOOL Module::MightContainMatchingProperty(mdProperty tkProperty, ULONG nameHash)
6594 if (m_propertyNameSet)
6596 _ASSERTE(HasNativeImage());
6598 // if this property was added after the name set was computed, conservatively
6599 // assume we might have it. This is known to occur in scenarios where a profiler
6600 // injects additional metadata at module load time for an NGEN'ed module. In the
6601 // future other dynamic additions to the module might produce a similar result.
6602 if (RidFromToken(tkProperty) > m_nPropertyNameSet)
6605 // Check one bit per iteration, failing if any are not set
6606 // We know that all will have been set for any valid (tkProperty,name) pair
6607 for (DWORD i = 0; i < NUM_PROPERTY_SET_HASHES; ++i)
6609 DWORD currentHashValue = HashThreeToOne(tkProperty, nameHash, i);
6610 DWORD bitPos = currentHashValue % (m_nPropertyNameSet * 8);
6611 if ((m_propertyNameSet[bitPos / 8] & (1 << bitPos % 8)) == 0)
6621 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6622 // Ensure that all elements and flags that we want persisted in the LookupMaps are present
6623 void Module::FinalizeLookupMapsPreSave(DataImage *image)
6628 PRECONDITION(IsCompilationProcess());
6632 // For each typedef, if it does not need a restore, add the ZAPPED_TYPE_NEEDS_NO_RESTORE flag
6634 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
6636 while (typeDefIter.Next())
6638 MethodTable * pMT = typeDefIter.GetElement();
6640 if (pMT != NULL && !pMT->NeedsRestore(image))
6642 m_TypeDefToMethodTableMap.AddFlag(RidFromToken(pMT->GetCl()), ZAPPED_TYPE_NEEDS_NO_RESTORE);
6647 // For each canonical instantiation of a generic type def, if it does not need a restore, add the ZAPPED_GENERIC_TYPE_NEEDS_NO_RESTORE flag
6649 LookupMap<PTR_MethodTable>::Iterator genericTypeDefIter(&m_GenericTypeDefToCanonMethodTableMap);
6651 while (genericTypeDefIter.Next())
6653 MethodTable * pMT = genericTypeDefIter.GetElement();
6655 if (pMT != NULL && !pMT->NeedsRestore(image))
6657 m_GenericTypeDefToCanonMethodTableMap.AddFlag(RidFromToken(pMT->GetCl()), ZAPPED_GENERIC_TYPE_NEEDS_NO_RESTORE);
6663 #endif // FEATURE_NATIVE_IMAGE_GENERATION
6665 // Return true if this module has any live (jitted) JMC functions.
6666 // If a module has no jitted JMC functions, then it's as if it's a
6668 bool Module::HasAnyJMCFunctions()
6670 LIMITED_METHOD_CONTRACT;
6672 // If we have any live JMC funcs in us, then we're a JMC module.
6673 // We count JMC functions when we either explicitly toggle their status
6674 // or when we get the code:DebuggerMethodInfo for them (which happens in a jit-complete).
6675 // Since we don't get the jit-completes for ngen modules, we also check the module's
6676 // "default" status. This means we may err on the side of believing we have
6678 return ((m_debuggerSpecificData.m_cTotalJMCFuncs > 0) || m_debuggerSpecificData.m_fDefaultJMCStatus);
6681 // Alter our module's count of JMC functions.
6682 // Since these may be called on multiple threads (say 2 threads are jitting
6683 // methods within a module), make it thread safe.
6684 void Module::IncJMCFuncCount()
6686 LIMITED_METHOD_CONTRACT;
6688 InterlockedIncrement(&m_debuggerSpecificData.m_cTotalJMCFuncs);
6691 void Module::DecJMCFuncCount()
6693 LIMITED_METHOD_CONTRACT;
6695 InterlockedDecrement(&m_debuggerSpecificData.m_cTotalJMCFuncs);
6698 // code:DebuggerMethodInfo are lazily created. Let them lookup what the default is.
6699 bool Module::GetJMCStatus()
6701 LIMITED_METHOD_CONTRACT;
6703 return m_debuggerSpecificData.m_fDefaultJMCStatus;
6706 // Set the default JMC status of this module.
6707 void Module::SetJMCStatus(bool fStatus)
6709 LIMITED_METHOD_CONTRACT;
6711 m_debuggerSpecificData.m_fDefaultJMCStatus = fStatus;
6714 // Update the dynamic metadata if needed. Nop for non-dynamic modules
6715 void Module::UpdateDynamicMetadataIfNeeded()
6724 // Only need to serializing metadata for dynamic modules. For non-dynamic modules, metadata is already available.
6725 if (!IsReflection())
6730 // Since serializing metadata to an auxillary buffer is only needed by the debugger,
6731 // we should only be doing this for modules that the debugger can see.
6732 if (!IsVisibleToDebugger())
6741 GetReflectionModule()->CaptureModuleMetaDataToMemory();
6743 EX_CATCH_HRESULT(hr);
6745 // This Metadata buffer is only used for the debugger, so it's a non-fatal exception for regular CLR execution.
6746 // Just swallow it and keep going. However, with the exception of out-of-memory, we do expect it to
6747 // succeed, so assert on failures.
6748 if (hr != E_OUTOFMEMORY)
6750 SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
6755 #ifdef DEBUGGING_SUPPORTED
6758 #endif // DEBUGGING_SUPPORTED
6760 BOOL Module::NotifyDebuggerLoad(AppDomain *pDomain, DomainFile * pDomainFile, int flags, BOOL attaching)
6762 WRAPPER_NO_CONTRACT;
6764 // We don't notify the debugger about modules that don't contain any code.
6765 if (!IsVisibleToDebugger())
6768 // Always capture metadata, even if no debugger is attached. If a debugger later attaches, it will use
6771 Module * pModule = pDomainFile->GetModule();
6772 pModule->UpdateDynamicMetadataIfNeeded();
6777 // Remaining work is only needed if a debugger is attached
6779 if (!attaching && !pDomain->IsDebuggerAttached())
6783 BOOL result = FALSE;
6785 if (flags & ATTACH_MODULE_LOAD)
6787 g_pDebugInterface->LoadModule(this,
6789 m_file->GetPath().GetCount(),
6798 if (flags & ATTACH_CLASS_LOAD)
6800 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
6801 while (typeDefIter.Next())
6803 MethodTable * pMT = typeDefIter.GetElement();
6805 if (pMT != NULL && pMT->IsRestored())
6807 result = TypeHandle(pMT).NotifyDebuggerLoad(pDomain, attaching) || result;
6815 void Module::NotifyDebuggerUnload(AppDomain *pDomain)
6817 LIMITED_METHOD_CONTRACT;
6819 if (!pDomain->IsDebuggerAttached())
6822 // We don't notify the debugger about modules that don't contain any code.
6823 if (!IsVisibleToDebugger())
6826 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
6827 while (typeDefIter.Next())
6829 MethodTable * pMT = typeDefIter.GetElement();
6831 if (pMT != NULL && pMT->IsRestored())
6833 TypeHandle(pMT).NotifyDebuggerUnload(pDomain);
6837 g_pDebugInterface->UnloadModule(this, pDomain);
6842 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6844 // These helpers are used in Module::ExpandAll
6845 // to avoid EX_TRY/EX_CATCH in a loop (uses _alloca and guzzles stack)
6847 static TypeHandle LoadTypeDefOrRefHelper(DataImage * image, Module * pModule, mdToken tk)
6849 STANDARD_VM_CONTRACT;
6855 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tk,
6856 ClassLoader::ThrowIfNotFound,
6857 ClassLoader::PermitUninstDefOrRef);
6861 image->GetPreloader()->Error(tk, GET_EXCEPTION());
6863 EX_END_CATCH(SwallowAllExceptions)
6868 static TypeHandle LoadTypeSpecHelper(DataImage * image, Module * pModule, mdToken tk,
6869 PCCOR_SIGNATURE pSig, ULONG cSig)
6871 STANDARD_VM_CONTRACT;
6877 SigPointer p(pSig, cSig);
6878 SigTypeContext typeContext;
6879 th = p.GetTypeHandleThrowing(pModule, &typeContext);
6883 image->GetPreloader()->Error(tk, GET_EXCEPTION());
6885 EX_END_CATCH(SwallowAllExceptions)
6890 static TypeHandle LoadGenericInstantiationHelper(DataImage * image, Module * pModule, mdToken tk, Instantiation inst)
6892 STANDARD_VM_CONTRACT;
6898 th = ClassLoader::LoadGenericInstantiationThrowing(pModule, tk, inst);
6902 image->GetPreloader()->Error(tk, GET_EXCEPTION());
6904 EX_END_CATCH(SwallowAllExceptions)
6909 static void GetDescFromMemberRefHelper(DataImage * image, Module * pModule, mdToken tk)
6911 STANDARD_VM_CONTRACT;
6915 MethodDesc * pMD = NULL;
6916 FieldDesc * pFD = NULL;
6919 // Note: using an empty type context is now OK, because even though the token is a MemberRef
6920 // neither the token nor its parent will directly refer to type variables.
6921 // @TODO GENERICS: want to allow loads of generic methods here but need strict metadata checks on parent
6922 SigTypeContext typeContext;
6923 MemberLoader::GetDescFromMemberRef(pModule, tk, &pMD, &pFD,
6925 FALSE /* strict metadata checks */, &th);
6929 image->GetPreloader()->Error(tk, GET_EXCEPTION());
6931 EX_END_CATCH(SwallowAllExceptions)
6934 void Module::SetProfileData(CorProfileData * profileData)
6936 LIMITED_METHOD_CONTRACT;
6937 m_pProfileData = profileData;
6940 CorProfileData * Module::GetProfileData()
6942 LIMITED_METHOD_CONTRACT;
6943 return m_pProfileData;
6946 mdTypeDef Module::LookupIbcTypeToken(Module * pExternalModule, mdToken ibcToken, SString* optionalFullNameOut)
6956 _ASSERTE(TypeFromToken(ibcToken) == ibcExternalType);
6958 CorProfileData * profileData = this->GetProfileData();
6960 CORBBTPROF_BLOB_TYPE_DEF_ENTRY * blobTypeDefEntry;
6961 blobTypeDefEntry = profileData->GetBlobExternalTypeDef(ibcToken);
6963 if (blobTypeDefEntry == NULL)
6964 return mdTypeDefNil;
6966 IbcNameHandle ibcName;
6967 ibcName.szName = &blobTypeDefEntry->name[0];
6968 ibcName.tkIbcNameSpace = blobTypeDefEntry->nameSpaceToken;
6969 ibcName.tkIbcNestedClass = blobTypeDefEntry->nestedClassToken;
6970 ibcName.szNamespace = NULL;
6971 ibcName.tkEnclosingClass = mdTypeDefNil;
6973 if (!IsNilToken(blobTypeDefEntry->nameSpaceToken))
6975 _ASSERTE(IsNilToken(blobTypeDefEntry->nestedClassToken));
6977 idExternalNamespace nameSpaceToken = blobTypeDefEntry->nameSpaceToken;
6978 _ASSERTE(TypeFromToken(nameSpaceToken) == ibcExternalNamespace);
6980 CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY * blobNamespaceDefEntry;
6981 blobNamespaceDefEntry = profileData->GetBlobExternalNamespaceDef(nameSpaceToken);
6983 if (blobNamespaceDefEntry == NULL)
6984 return mdTypeDefNil;
6986 ibcName.szNamespace = &blobNamespaceDefEntry->name[0];
6988 if (optionalFullNameOut != NULL)
6990 optionalFullNameOut->Append(W("["));
6991 optionalFullNameOut->AppendUTF8(pExternalModule->GetSimpleName());
6992 optionalFullNameOut->Append(W("]"));
6994 if ((ibcName.szNamespace != NULL) && ((*ibcName.szNamespace) != W('\0')))
6996 optionalFullNameOut->AppendUTF8(ibcName.szNamespace);
6997 optionalFullNameOut->Append(W("."));
6999 optionalFullNameOut->AppendUTF8(ibcName.szName);
7002 else if (!IsNilToken(blobTypeDefEntry->nestedClassToken))
7004 idExternalType nestedClassToken = blobTypeDefEntry->nestedClassToken;
7005 _ASSERTE(TypeFromToken(nestedClassToken) == ibcExternalType);
7007 ibcName.tkEnclosingClass = LookupIbcTypeToken(pExternalModule, nestedClassToken, optionalFullNameOut);
7009 if (optionalFullNameOut != NULL)
7011 optionalFullNameOut->Append(W("+"));
7012 optionalFullNameOut->AppendUTF8(ibcName.szName);
7015 if (IsNilToken(ibcName.tkEnclosingClass))
7016 return mdTypeDefNil;
7019 //*****************************************
7020 // look up function for TypeDef
7021 //*****************************************
7022 // STDMETHOD(FindTypeDef)(
7023 // LPCSTR szNamespace, // [IN] Namespace for the TypeDef.
7024 // LPCSTR szName, // [IN] Name of the TypeDef.
7025 // mdToken tkEnclosingClass, // [IN] TypeRef/TypeDef Token for the enclosing class.
7026 // mdTypeDef *ptypedef) PURE; // [IN] return typedef
7028 IMDInternalImport *pInternalImport = pExternalModule->GetMDImport();
7030 mdTypeDef mdResult = mdTypeDefNil;
7032 HRESULT hr = pInternalImport->FindTypeDef(ibcName.szNamespace, ibcName.szName, ibcName.tkEnclosingClass, &mdResult);
7035 mdResult = mdTypeDefNil;
7040 struct IbcCompareContext
7043 TypeHandle enclosingType;
7044 DWORD cMatch; // count of methods that had a matching method name
7045 bool useBestSig; // if true we should use the BestSig when we don't find an exact match
7046 PCCOR_SIGNATURE pvBestSig; // Current Best matching signature
7050 //---------------------------------------------------------------------------------------
7052 // Compare two signatures from the same scope.
7055 CompareIbcMethodSigs(
7056 PCCOR_SIGNATURE pvCandidateSig, // Candidate signature
7057 DWORD cbCandidateSig, //
7058 PCCOR_SIGNATURE pvIbcSignature, // The Ibc signature that we want to match
7059 DWORD cbIbcSignature, //
7060 void * pvContext) // void pointer to IbcCompareContext
7071 // Same pointer return TRUE
7073 if (pvCandidateSig == pvIbcSignature)
7075 _ASSERTE(cbCandidateSig == cbIbcSignature);
7080 // Check for exact match
7082 if (cbCandidateSig == cbIbcSignature)
7084 if (memcmp(pvCandidateSig, pvIbcSignature, cbIbcSignature) == 0)
7090 IbcCompareContext * context = (IbcCompareContext *) pvContext;
7093 // No exact match, we will return FALSE and keep looking at other matching method names
7095 // However since the method name was an exact match we will remember this signature,
7096 // so that if it is the best match we can look it up again and return it's methodDef token
7098 if (context->cMatch == 0)
7100 context->pvBestSig = pvCandidateSig;
7101 context->cbBestSig = cbCandidateSig;
7102 context->cMatch = 1;
7103 context->useBestSig = true;
7109 SigTypeContext emptyTypeContext;
7110 SigTypeContext ibcTypeContext = SigTypeContext(context->enclosingType);
7111 MetaSig ibcSignature (pvIbcSignature, cbIbcSignature, context->pModule, &ibcTypeContext);
7113 MetaSig candidateSig (pvCandidateSig, cbCandidateSig, context->pModule, &emptyTypeContext);
7114 MetaSig bestSignature(context->pvBestSig, context->cbBestSig, context->pModule, &emptyTypeContext);
7116 // Is candidateSig a better match than bestSignature?
7118 // First check the calling convention
7120 if (candidateSig.GetCallingConventionInfo() != bestSignature.GetCallingConventionInfo())
7122 if (bestSignature.GetCallingConventionInfo() == ibcSignature.GetCallingConventionInfo())
7124 if (candidateSig.GetCallingConventionInfo() == ibcSignature.GetCallingConventionInfo())
7125 goto SELECT_CANDIDATE;
7127 // Neither one is a match
7133 // Next check the number of arguments
7135 if (candidateSig.NumFixedArgs() != bestSignature.NumFixedArgs())
7138 // Does one of the two have the same number of args?
7140 if (bestSignature.NumFixedArgs() == ibcSignature.NumFixedArgs())
7142 if (candidateSig.NumFixedArgs() == ibcSignature.NumFixedArgs())
7143 goto SELECT_CANDIDATE;
7145 // Neither one is a match
7149 else if (candidateSig.NumFixedArgs() != ibcSignature.NumFixedArgs())
7152 // Neither one is a match
7157 CorElementType etIbc;
7158 CorElementType etCandidate;
7159 CorElementType etBest;
7161 // Next get the return element type
7163 // etIbc = ibcSignature.GetReturnProps().PeekElemTypeClosed(ibcSignature.GetSigTypeContext());
7164 IfFailThrow(ibcSignature.GetReturnProps().PeekElemType(&etIbc));
7165 IfFailThrow(candidateSig.GetReturnProps().PeekElemType(&etCandidate));
7166 IfFailThrow(bestSignature.GetReturnProps().PeekElemType(&etBest));
7168 // Do they have different return types?
7170 if (etCandidate != etBest)
7172 if (etBest == etIbc)
7175 if (etCandidate == etIbc)
7176 goto SELECT_CANDIDATE;
7180 // Now iterate over the method argument types to see which signature
7181 // is the better match
7183 for (DWORD i = 0; (i < ibcSignature.NumFixedArgs()); i++)
7185 ibcSignature.SkipArg();
7186 IfFailThrow(ibcSignature.GetArgProps().PeekElemType(&etIbc));
7188 candidateSig.SkipArg();
7189 IfFailThrow(candidateSig.GetArgProps().PeekElemType(&etCandidate));
7191 bestSignature.SkipArg();
7192 IfFailThrow(bestSignature.GetArgProps().PeekElemType(&etBest));
7195 // Do they have different argument types?
7197 if (etCandidate != etBest)
7199 if (etBest == etIbc)
7202 if (etCandidate == etIbc)
7203 goto SELECT_CANDIDATE;
7206 // When we fall though to here we did not find any differences
7207 // that we could base a choice on
7209 context->useBestSig = true;
7212 context->pvBestSig = pvCandidateSig;
7213 context->cbBestSig = cbCandidateSig;
7214 context->useBestSig = true;
7218 context->useBestSig = false;
7224 } // CompareIbcMethodSigs
7226 mdMethodDef Module::LookupIbcMethodToken(TypeHandle enclosingType, mdToken ibcToken, SString* optionalFullNameOut)
7236 _ASSERTE(TypeFromToken(ibcToken) == ibcExternalMethod);
7238 CorProfileData * profileData = this->GetProfileData();
7240 CORBBTPROF_BLOB_METHOD_DEF_ENTRY * blobMethodDefEntry;
7241 blobMethodDefEntry = profileData->GetBlobExternalMethodDef(ibcToken);
7243 if (blobMethodDefEntry == NULL)
7244 return mdMethodDefNil;
7246 idExternalType signatureToken = blobMethodDefEntry->signatureToken;
7247 _ASSERTE(!IsNilToken(signatureToken));
7248 _ASSERTE(TypeFromToken(signatureToken) == ibcExternalSignature);
7250 CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY * blobSignatureDefEntry;
7251 blobSignatureDefEntry = profileData->GetBlobExternalSignatureDef(signatureToken);
7253 if (blobSignatureDefEntry == NULL)
7254 return mdMethodDefNil;
7256 IbcNameHandle ibcName;
7257 ibcName.szName = &blobMethodDefEntry->name[0];
7258 ibcName.tkIbcNestedClass = blobMethodDefEntry->nestedClassToken;
7259 ibcName.tkIbcNameSpace = idExternalNamespaceNil;
7260 ibcName.szNamespace = NULL;
7261 ibcName.tkEnclosingClass = mdTypeDefNil;
7263 Module * pExternalModule = enclosingType.GetModule();
7264 PCCOR_SIGNATURE pvSig = NULL;
7267 _ASSERTE(!IsNilToken(ibcName.tkIbcNestedClass));
7268 _ASSERTE(TypeFromToken(ibcName.tkIbcNestedClass) == ibcExternalType);
7270 ibcName.tkEnclosingClass = LookupIbcTypeToken(pExternalModule, ibcName.tkIbcNestedClass, optionalFullNameOut);
7272 if (IsNilToken(ibcName.tkEnclosingClass))
7274 COMPlusThrow(kTypeLoadException, IDS_IBC_MISSING_EXTERNAL_TYPE);
7277 if (optionalFullNameOut != NULL)
7279 optionalFullNameOut->Append(W("."));
7280 optionalFullNameOut->AppendUTF8(ibcName.szName); // MethodName
7281 optionalFullNameOut->Append(W("()"));
7284 pvSig = blobSignatureDefEntry->sig;
7285 cbSig = blobSignatureDefEntry->cSig;
7287 //*****************************************
7288 // look up functions for TypeDef
7289 //*****************************************
7290 // STDMETHOD(FindMethodDefUsingCompare)(
7291 // mdTypeDef classdef, // [IN] given typedef
7292 // LPCSTR szName, // [IN] member name
7293 // PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of CLR signature
7294 // ULONG cbSigBlob, // [IN] count of bytes in the signature blob
7295 // PSIGCOMPARE pSignatureCompare, // [IN] Routine to compare signatures
7296 // void* pSignatureArgs, // [IN] Additional info to supply the compare function
7297 // mdMethodDef *pmd) PURE; // [OUT] matching memberdef
7300 IMDInternalImport * pInternalImport = pExternalModule->GetMDImport();
7302 IbcCompareContext context;
7303 memset(&context, 0, sizeof(IbcCompareContext));
7304 context.pModule = this;
7305 context.enclosingType = enclosingType;
7307 context.useBestSig = false;
7309 mdMethodDef mdResult = mdMethodDefNil;
7310 HRESULT hr = pInternalImport->FindMethodDefUsingCompare(ibcName.tkEnclosingClass, ibcName.szName,
7312 CompareIbcMethodSigs, (void *) &context,
7316 _ASSERTE(mdResult != mdMethodDefNil);
7318 else if (context.useBestSig)
7320 hr = pInternalImport->FindMethodDefUsingCompare(ibcName.tkEnclosingClass, ibcName.szName,
7321 context.pvBestSig, context.cbBestSig,
7322 CompareIbcMethodSigs, (void *) &context,
7324 _ASSERTE(SUCCEEDED(hr));
7325 _ASSERTE(mdResult != mdMethodDefNil);
7329 mdResult = mdMethodDefNil;
7335 TypeHandle Module::LoadIBCTypeHelper(DataImage *image, CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry)
7337 CONTRACT(TypeHandle)
7342 INJECT_FAULT(COMPlusThrowOM());
7343 PRECONDITION(CheckPointer(pBlobSigEntry));
7347 TypeHandle loadedType;
7349 PCCOR_SIGNATURE pSig = pBlobSigEntry->sig;
7350 ULONG cSig = pBlobSigEntry->cSig;
7352 SigPointer p(pSig, cSig);
7354 ZapSig::Context zapSigContext(this, (void *)this, ZapSig::IbcTokens);
7355 ZapSig::Context * pZapSigContext = &zapSigContext;
7359 // This is what ZapSig::FindTypeHandleFromSignature does...
7361 SigTypeContext typeContext; // empty type context
7363 loadedType = p.GetTypeHandleThrowing( this,
7365 ClassLoader::LoadTypes,
7370 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
7371 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_1);
7376 image->GetPreloader()->Error(pBlobSigEntry->blob.token, GET_EXCEPTION());
7377 loadedType = TypeHandle();
7379 EX_END_CATCH(SwallowAllExceptions)
7384 //---------------------------------------------------------------------------------------
7386 MethodDesc* Module::LoadIBCMethodHelper(DataImage *image, CORBBTPROF_BLOB_PARAM_SIG_ENTRY * pBlobSigEntry)
7388 CONTRACT(MethodDesc*)
7393 INJECT_FAULT(COMPlusThrowOM());
7394 PRECONDITION(CheckPointer(pBlobSigEntry));
7398 MethodDesc* pMethod = NULL;
7400 PCCOR_SIGNATURE pSig = pBlobSigEntry->sig;
7401 ULONG cSig = pBlobSigEntry->cSig;
7403 SigPointer p(pSig, cSig);
7405 ZapSig::Context zapSigContext(this, (void *)this, ZapSig::IbcTokens);
7406 ZapSig::Context * pZapSigContext = &zapSigContext;
7408 TypeHandle enclosingType;
7411 // First Decode and Load the enclosing type for this method
7415 // This is what ZapSig::FindTypeHandleFromSignature does...
7417 SigTypeContext typeContext; // empty type context
7419 enclosingType = p.GetTypeHandleThrowing( this,
7421 ClassLoader::LoadTypes,
7426 IfFailThrow(p.SkipExactlyOne());
7427 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
7428 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_2);
7433 image->GetPreloader()->Error(pBlobSigEntry->blob.token, GET_EXCEPTION());
7434 enclosingType = TypeHandle();
7436 EX_END_CATCH(SwallowAllExceptions)
7438 if (enclosingType.IsNull())
7442 // Now Decode and Load the method
7446 MethodTable *pOwnerMT = enclosingType.GetMethodTable();
7447 _ASSERTE(pOwnerMT != NULL);
7451 IfFailThrow(p.GetData(&methodFlags));
7452 BOOL isInstantiatingStub = ((methodFlags & ENCODE_METHOD_SIG_InstantiatingStub) == ENCODE_METHOD_SIG_InstantiatingStub);
7453 BOOL isUnboxingStub = ((methodFlags & ENCODE_METHOD_SIG_UnboxingStub) == ENCODE_METHOD_SIG_UnboxingStub);
7454 BOOL fMethodNeedsInstantiation = ((methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) == ENCODE_METHOD_SIG_MethodInstantiation);
7455 BOOL fMethodUsesSlotEncoding = ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == ENCODE_METHOD_SIG_SlotInsteadOfToken);
7457 if ( fMethodUsesSlotEncoding )
7459 // get the method desc using slot number
7461 IfFailThrow(p.GetData(&slot));
7463 pMethod = pOwnerMT->GetMethodDescForSlot(slot);
7465 else // otherwise we use the normal metadata MethodDef token encoding and we handle ibc tokens.
7468 // decode method token
7471 IfFailThrow(p.GetData(&methodRid));
7473 mdMethodDef methodToken;
7476 // Is our enclosingType from another module?
7478 if (this == enclosingType.GetModule())
7481 // The enclosing type is from our module
7482 // The method token is a normal MethodDef token
7484 methodToken = TokenFromRid(methodRid, mdtMethodDef);
7489 // The enclosing type is from an external module
7490 // The method token is a ibcExternalMethod token
7492 idExternalType ibcToken = RidToToken(methodRid, ibcExternalMethod);
7493 methodToken = this->LookupIbcMethodToken(enclosingType, ibcToken);
7495 if (IsNilToken(methodToken))
7497 COMPlusThrow(kTypeLoadException, IDS_IBC_MISSING_EXTERNAL_METHOD);
7501 SigTypeContext methodTypeContext( enclosingType );
7502 pMethod = MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(
7503 pOwnerMT->GetModule(),
7512 // Instantiate the method if needed, or create a stub to a static method in a generic class.
7513 if (fMethodNeedsInstantiation && pMethod->HasMethodInstantiation())
7515 DWORD nargs = pMethod->GetNumGenericMethodArgs();
7518 if (!ClrSafeInt<SIZE_T>::multiply(nargs, sizeof(TypeHandle), cbMem/* passed by ref */))
7519 ThrowHR(COR_E_OVERFLOW);
7521 TypeHandle * pInst = (TypeHandle*) _alloca(cbMem);
7522 SigTypeContext typeContext; // empty type context
7524 for (DWORD i = 0; i < nargs; i++)
7528 curInst = p.GetTypeHandleThrowing( this,
7530 ClassLoader::LoadTypes,
7536 // curInst will be nullptr when the type fails the versioning bubble check
7537 if (curInst.IsNull() && IsReadyToRunCompilation())
7539 COMPlusThrow(kTypeLoadException, IDS_IBC_MISSING_EXTERNAL_TYPE);
7543 IfFailThrow(p.SkipExactlyOne());
7546 inst = Instantiation(pInst, nargs);
7550 inst = pMethod->LoadMethodInstantiation();
7553 // We should now be able to create an instantiation for this generic method
7555 // This must be called even if nargs == 0, in order to create an instantiating
7556 // stub for static methods in generic classees if needed, also for BoxedEntryPointStubs
7557 // in non-generic structs.
7558 const bool allowInstParam = !(isInstantiatingStub || isUnboxingStub);
7560 pMethod = MethodDesc::FindOrCreateAssociatedMethodDesc(pMethod, pOwnerMT,
7562 inst, allowInstParam);
7564 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
7565 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_3);
7570 // Catch any kTypeLoadException that we may have thrown above
7572 image->GetPreloader()->Error(pBlobSigEntry->blob.token, GET_EXCEPTION());
7575 EX_END_CATCH(SwallowAllExceptions)
7578 } // Module::LoadIBCMethodHelper
7580 #ifdef FEATURE_COMINTEROP
7581 //---------------------------------------------------------------------------------------
7583 // This function is a workaround for missing IBC data in WinRT assemblies and
7584 // not-yet-implemented sharing of IL_STUB(__Canon arg) IL stubs for all interfaces.
7586 static void ExpandWindowsRuntimeType(TypeHandle t, DataImage *image)
7591 PRECONDITION(!t.IsNull());
7598 // This array contains our poor man's IBC data - instantiations that are known to
7599 // be used by other assemblies.
7602 LPCUTF8 m_szTypeName;
7603 BinderClassID m_GenericBinderClassID;
7605 rgForcedInstantiations[] = {
7606 { "Windows.UI.Xaml.Data.IGroupInfo", CLASS__IENUMERABLEGENERIC },
7607 { "Windows.UI.Xaml.UIElement", CLASS__ILISTGENERIC },
7608 { "Windows.UI.Xaml.Visibility", CLASS__CLRIREFERENCEIMPL },
7609 { "Windows.UI.Xaml.VerticalAlignment", CLASS__CLRIREFERENCEIMPL },
7610 { "Windows.UI.Xaml.HorizontalAlignment", CLASS__CLRIREFERENCEIMPL },
7611 // The following instantiations are used by Microsoft.PlayerFramework - http://playerframework.codeplex.com/
7612 { "Windows.UI.Xaml.Media.AudioCategory", CLASS__CLRIREFERENCEIMPL },
7613 { "Windows.UI.Xaml.Media.AudioDeviceType", CLASS__CLRIREFERENCEIMPL },
7614 { "Windows.UI.Xaml.Media.MediaElementState", CLASS__CLRIREFERENCEIMPL },
7615 { "Windows.UI.Xaml.Media.Stereo3DVideoRenderMode", CLASS__CLRIREFERENCEIMPL },
7616 { "Windows.UI.Xaml.Media.Stereo3DVideoPackingMode", CLASS__CLRIREFERENCEIMPL },
7619 DefineFullyQualifiedNameForClass();
7620 LPCUTF8 szTypeName = GetFullyQualifiedNameForClass(t.AsMethodTable());
7622 for (SIZE_T i = 0; i < COUNTOF(rgForcedInstantiations); i++)
7624 if (strcmp(szTypeName, rgForcedInstantiations[i].m_szTypeName) == 0)
7628 TypeHandle thGenericType = TypeHandle(MscorlibBinder::GetClass(rgForcedInstantiations[i].m_GenericBinderClassID));
7630 Instantiation inst(&t, 1);
7631 thGenericType.Instantiate(inst);
7635 image->GetPreloader()->Error(t.GetCl(), GET_EXCEPTION());
7637 EX_END_CATCH(SwallowAllExceptions)
7641 if (strcmp(szTypeName, "Windows.Foundation.Collections.IObservableVector`1") == 0)
7645 TypeHandle thArg = TypeHandle(g_pObjectClass);
7647 Instantiation inst(&thArg, 1);
7648 t.Instantiate(inst);
7652 image->GetPreloader()->Error(t.GetCl(), GET_EXCEPTION());
7654 EX_END_CATCH(SwallowAllExceptions)
7657 #endif // FEATURE_COMINTEROP
7659 //---------------------------------------------------------------------------------------
7661 void Module::ExpandAll(DataImage *image)
7666 PRECONDITION(!IsResource());
7671 DWORD assemblyFlags = GetAssembly()->GetFlags();
7674 // Explicitly load the global class.
7677 MethodTable *pGlobalMT = GetGlobalMethodTable();
7680 // Load all classes. This also fills out the
7681 // RID maps for the typedefs, method defs,
7685 IMDInternalImport *pInternalImport = GetMDImport();
7687 HENUMInternalHolder hEnum(pInternalImport);
7688 hEnum.EnumTypeDefInit();
7690 while (pInternalImport->EnumTypeDefNext(&hEnum, &tk))
7692 #ifdef FEATURE_COMINTEROP
7693 // Skip the non-managed WinRT types since they're only used by Javascript and C++
7695 // With WinRT files, we want to exclude certain types that cause us problems:
7696 // * Attribute types defined in Windows.Foundation. The constructor's methodimpl flags
7697 // specify it is an internal runtime function and gets set as an FCALL when we parse
7700 if (IsAfContentType_WindowsRuntime(assemblyFlags))
7703 pInternalImport->GetTypeDefProps(tk, NULL, &tkExtends);
7705 if (TypeFromToken(tkExtends) == mdtTypeRef)
7707 LPCSTR szNameSpace = NULL;
7708 LPCSTR szName = NULL;
7709 pInternalImport->GetNameOfTypeRef(tkExtends, &szNameSpace, &szName);
7711 if (!strcmp(szNameSpace, "System") && !_stricmp((szName), "Attribute"))
7717 #endif // FEATURE_COMINTEROP
7719 TypeHandle t = LoadTypeDefOrRefHelper(image, this, tk);
7721 if (t.IsNull()) // Skip this type
7724 if (!t.HasInstantiation())
7726 EEClassHashEntry_t *pBucket = NULL;
7728 StackSString ssFullyQualifiedName;
7730 EEClassHashTable *pTable = GetAvailableClassHash();
7732 _ASSERTE(pTable != NULL);
7734 t.GetName(ssFullyQualifiedName);
7737 StackScratchBuffer scratch;
7738 LPCUTF8 szFullyQualifiedName = ssFullyQualifiedName.GetUTF8(scratch);
7740 BOOL isNested = ClassLoader::IsNested(this, tk, &mdEncloser);
7741 EEClassHashTable::LookupContext sContext;
7742 pBucket = pTable->GetValue(szFullyQualifiedName, &data, isNested, &sContext);
7746 while (pBucket != NULL)
7748 _ASSERTE (TypeFromToken(tk) == mdtTypeDef);
7749 BOOL match = GetClassLoader()->CompareNestedEntryWithTypeDef( pInternalImport,
7751 GetAvailableClassHash(),
7752 pBucket->GetEncloser());
7756 pBucket = pTable->FindNextNestedClass(szFullyQualifiedName, &data, &sContext);
7760 // Save the typehandle instead of the token in the hash entry so that ngen'ed images
7761 // don't have to lookup based on token and update this entry
7762 if ((pBucket != NULL) && !t.IsNull() && t.IsRestored())
7763 pBucket->SetData(t.AsPtr());
7766 DWORD nGenericClassParams = t.GetNumGenericArgs();
7767 if (nGenericClassParams != 0)
7769 // For generic types, load the instantiation at Object
7771 if (!ClrSafeInt<SIZE_T>::multiply(sizeof(TypeHandle), nGenericClassParams, cbMem/* passed by ref */))
7773 ThrowHR(COR_E_OVERFLOW);
7775 CQuickBytes qbGenericClassArgs;
7776 TypeHandle *genericClassArgs = reinterpret_cast<TypeHandle*>(qbGenericClassArgs.AllocThrows(cbMem));
7777 for (DWORD i = 0; i < nGenericClassParams; i++)
7779 genericClassArgs[i] = TypeHandle(g_pCanonMethodTableClass);
7782 TypeHandle thCanonInst = LoadGenericInstantiationHelper(image, this, tk, Instantiation(genericClassArgs, nGenericClassParams));
7784 // If successful, add the instantiation to the Module's map of generic types instantiated at Object
7785 if (!thCanonInst.IsNull() && !thCanonInst.IsTypeDesc())
7787 MethodTable * pCanonMT = thCanonInst.AsMethodTable();
7788 m_GenericTypeDefToCanonMethodTableMap.AddElement(this, RidFromToken(pCanonMT->GetCl()), pCanonMT);
7792 #ifdef FEATURE_COMINTEROP
7793 if (IsAfContentType_WindowsRuntime(assemblyFlags))
7795 ExpandWindowsRuntimeType(t, image);
7797 #endif // FEATURE_COMINTEROP
7802 // Fill out TypeRef RID map
7806 HENUMInternalHolder hEnum(pInternalImport);
7807 hEnum.EnumAllInit(mdtTypeRef);
7809 while (pInternalImport->EnumNext(&hEnum, &tk))
7811 mdToken tkResolutionScope = mdTokenNil;
7812 pInternalImport->GetResolutionScopeOfTypeRef(tk, &tkResolutionScope);
7814 #ifdef FEATURE_COMINTEROP
7815 // WinRT first party files are authored with TypeRefs pointing to TypeDefs in the same module.
7816 // This causes us to load types we do not want to NGen such as custom attributes. We will not
7817 // expand any module local TypeRefs for WinMDs to prevent this.
7818 if(TypeFromToken(tkResolutionScope)==mdtModule && IsAfContentType_WindowsRuntime(assemblyFlags))
7820 #endif // FEATURE_COMINTEROP
7821 TypeHandle t = LoadTypeDefOrRefHelper(image, this, tk);
7823 if (t.IsNull()) // Skip this type
7826 #ifdef FEATURE_COMINTEROP
7827 if (!g_fNGenWinMDResilient && TypeFromToken(tkResolutionScope) == mdtAssemblyRef)
7829 DWORD dwAssemblyRefFlags;
7830 IfFailThrow(pInternalImport->GetAssemblyRefProps(tkResolutionScope, NULL, NULL, NULL, NULL, NULL, NULL, &dwAssemblyRefFlags));
7832 if (IsAfContentType_WindowsRuntime(dwAssemblyRefFlags))
7834 Assembly *pAssembly = t.GetAssembly();
7835 PEAssembly *pPEAssembly = pAssembly->GetManifestFile();
7836 AssemblySpec refSpec;
7837 refSpec.InitializeSpec(tkResolutionScope, pInternalImport);
7838 LPCSTR psznamespace;
7840 pInternalImport->GetNameOfTypeRef(tk, &psznamespace, &pszname);
7841 refSpec.SetWindowsRuntimeType(psznamespace, pszname);
7842 GetAppDomain()->ToCompilationDomain()->AddDependency(&refSpec,pPEAssembly);
7845 #endif // FEATURE_COMINTEROP
7850 // Load all type specs
7854 HENUMInternalHolder hEnum(pInternalImport);
7855 hEnum.EnumAllInit(mdtTypeSpec);
7857 while (pInternalImport->EnumNext(&hEnum, &tk))
7860 PCCOR_SIGNATURE pSig;
7862 IfFailThrow(pInternalImport->GetTypeSpecFromToken(tk, &pSig, &cSig));
7864 // Load all types specs that do not contain variables
7865 if (SigPointer(pSig, cSig).IsPolyType(NULL) == hasNoVars)
7867 LoadTypeSpecHelper(image, this, tk, pSig, cSig);
7873 // Load all the reported parameterized types and methods
7875 CorProfileData * profileData = this->GetProfileData();
7876 CORBBTPROF_BLOB_ENTRY *pBlobEntry = profileData->GetBlobStream();
7878 if (pBlobEntry != NULL)
7880 while (pBlobEntry->TypeIsValid())
7882 if (TypeFromToken(pBlobEntry->token) == ibcTypeSpec)
7884 _ASSERTE(pBlobEntry->type == ParamTypeSpec);
7885 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY *) pBlobEntry;
7887 TypeHandle th = LoadIBCTypeHelper(image, pBlobSigEntry);
7891 image->GetPreloader()->TriageTypeForZap(th, TRUE);
7894 else if (TypeFromToken(pBlobEntry->token) == ibcMethodSpec)
7896 _ASSERTE(pBlobEntry->type == ParamMethodSpec);
7897 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY *) pBlobEntry;
7899 MethodDesc *pMD = LoadIBCMethodHelper(image, pBlobSigEntry);
7901 pBlobEntry = pBlobEntry->GetNextEntry();
7903 _ASSERTE(pBlobEntry->type == EndOfBlobStream);
7907 // Record references to all of the hot methods specifiled by MethodProfilingData array
7908 // We call MethodReferencedByCompiledCode to indicate that we plan on compiling this method
7910 CORBBTPROF_TOKEN_INFO * pMethodProfilingData = profileData->GetTokenFlagsData(MethodProfilingData);
7911 DWORD cMethodProfilingData = profileData->GetTokenFlagsCount(MethodProfilingData);
7912 for (unsigned int i = 0; (i < cMethodProfilingData); i++)
7914 mdToken token = pMethodProfilingData[i].token;
7915 DWORD profilingFlags = pMethodProfilingData[i].flags;
7917 // We call MethodReferencedByCompiledCode only when the profile data indicates that
7918 // we executed (i.e read) the code for the method
7920 if (profilingFlags & (1 << ReadMethodCode))
7922 if (TypeFromToken(token) == mdtMethodDef)
7924 MethodDesc * pMD = LookupMethodDef(token);
7926 // Record a reference to a hot non-generic method
7928 image->GetPreloader()->MethodReferencedByCompiledCode((CORINFO_METHOD_HANDLE)pMD);
7930 else if (TypeFromToken(token) == ibcMethodSpec)
7932 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = profileData->GetBlobSigEntry(token);
7934 if (pBlobSigEntry != NULL)
7936 _ASSERTE(pBlobSigEntry->blob.token == token);
7937 MethodDesc * pMD = LoadIBCMethodHelper(image, pBlobSigEntry);
7941 // Occasionally a non-instantiated generic method shows up in the IBC data, we should NOT compile it.
7942 if (!pMD->IsTypicalMethodDefinition())
7945 // Record a reference to a hot instantiated generic method
7947 image->GetPreloader()->MethodReferencedByCompiledCode((CORINFO_METHOD_HANDLE)pMD);
7957 // Fill out MemberRef RID map and va sig cookies for
7958 // varargs member refs.
7961 HENUMInternalHolder hEnum(pInternalImport);
7962 hEnum.EnumAllInit(mdtMemberRef);
7964 while (pInternalImport->EnumNext(&hEnum, &tk))
7967 IfFailThrow(pInternalImport->GetParentOfMemberRef(tk, &parent));
7969 #ifdef FEATURE_COMINTEROP
7970 if (IsAfContentType_WindowsRuntime(assemblyFlags) && TypeFromToken(parent) == mdtTypeRef)
7972 mdToken tkResolutionScope = mdTokenNil;
7973 pInternalImport->GetResolutionScopeOfTypeRef(parent, &tkResolutionScope);
7974 // WinRT first party files are authored with TypeRefs pointing to TypeDefs in the same module.
7975 // This causes us to load types we do not want to NGen such as custom attributes. We will not
7976 // expand any module local TypeRefs for WinMDs to prevent this.
7977 if(TypeFromToken(tkResolutionScope)==mdtModule)
7980 LPCSTR szNameSpace = NULL;
7981 LPCSTR szName = NULL;
7982 if (SUCCEEDED(pInternalImport->GetNameOfTypeRef(parent, &szNameSpace, &szName)))
7984 if (WinMDAdapter::ConvertWellKnownTypeNameFromClrToWinRT(&szNameSpace, &szName))
7987 // This is a MemberRef from a redirected WinRT type
7988 // We should skip it as managed view will never see this MemberRef anyway
7989 // Not skipping this will result MissingMethodExceptions as members in redirected
7990 // types doesn't exactly match their redirected CLR type counter part
7992 // Typically we only need to do this for interfaces as we should never see MemberRef
7993 // from non-interfaces, but here to keep things simple I'm skipping every memberref that
7994 // belongs to redirected WinRT type
8001 #endif // FEATURE_COMINTEROP
8003 // If the MethodRef has a TypeSpec as a parent (i.e. refers to a method on an array type
8004 // or on a generic class), then it could in turn refer to type variables of
8005 // an unknown class/method. So we don't preresolve any MemberRefs which have TypeSpecs as
8006 // parents. The RID maps are not filled out for such tokens anyway.
8007 if (TypeFromToken(parent) != mdtTypeSpec)
8009 GetDescFromMemberRefHelper(image, this, tk);
8018 if (m_pBinder != NULL)
8020 m_pBinder->BindAll();
8023 } // Module::ExpandAll
8026 void Module::SaveMethodTable(DataImage * image,
8028 DWORD profilingFlags)
8030 STANDARD_VM_CONTRACT;
8032 if (image->IsStored(pMT))
8035 pMT->Save(image, profilingFlags);
8040 void Module::SaveTypeHandle(DataImage * image,
8042 DWORD profilingFlags)
8044 STANDARD_VM_CONTRACT;
8049 TypeDesc *pTD = t.AsTypeDesc();
8050 if (!image->IsStored(pTD))
8057 MethodTable *pMT = t.AsMethodTable();
8058 if (pMT != NULL && !image->IsStored(pMT))
8060 SaveMethodTable(image, pMT, profilingFlags);
8061 _ASSERTE(image->IsStored(pMT));
8065 if (LoggingOn(LF_JIT, LL_INFO100))
8067 Module *pPrefModule = Module::GetPreferredZapModuleForTypeHandle(t);
8068 if (image->GetModule() != pPrefModule)
8070 StackSString typeName;
8072 TypeString::AppendTypeDebug(typeName, t);
8073 LOG((LF_ZAP, LL_INFO100, "The type %S was saved outside its preferred module %S\n", typeName.GetUnicode(), pPrefModule->GetPath().GetUnicode()));
8079 #ifndef DACCESS_COMPILE
8081 void ModuleCtorInfo::Save(DataImage *image, CorProfileData *profileData)
8083 STANDARD_VM_CONTRACT;
8089 DWORD totalBoxedStatics = 0;
8091 // sort the tables so that
8092 // - the hot ppMT entries are at the beginning of the ppMT table
8093 // - the hot cctor entries are at the beginning of the cctorInfoHot table
8094 // - the cold cctor entries are at the end, and we make cctorInfoCold point
8095 // the first cold entry
8097 // the invariant in this loop is:
8098 // items 0...numElementsHot-1 are hot
8099 // items numElementsHot...i-1 are cold
8100 for (i = 0; i < numElements; i++)
8102 MethodTable *ppMTTemp = ppMT[i].GetValue();
8104 // Count the number of boxed statics along the way
8105 totalBoxedStatics += ppMTTemp->GetNumBoxedRegularStatics();
8107 bool hot = true; // if there's no profiling data, assume the entries are all hot.
8108 if (profileData->GetTokenFlagsData(TypeProfilingData))
8110 if ((profileData->GetTypeProfilingFlagsOfToken(ppMTTemp->GetCl()) & (1 << ReadCCtorInfo)) == 0)
8115 // swap ppMT[i] and ppMT[numElementsHot] to maintain the loop invariant
8116 ppMT[i].SetValue(ppMT[numElementsHot].GetValue());
8117 ppMT[numElementsHot].SetValue(ppMTTemp);
8123 numHotHashes = numElementsHot ? RoundUpToPower2((numElementsHot * sizeof(PTR_MethodTable)) / CACHE_LINE_SIZE) : 0;
8124 numColdHashes = (numElements - numElementsHot) ? RoundUpToPower2(((numElements - numElementsHot) *
8125 sizeof(PTR_MethodTable)) / CACHE_LINE_SIZE) : 0;
8127 LOG((LF_ZAP, LL_INFO10, "ModuleCtorInfo::numHotHashes: 0x%4x\n", numHotHashes));
8128 if (numColdHashes != 0)
8130 LOG((LF_ZAP, LL_INFO10, "ModuleCtorInfo::numColdHashes: 0x%4x\n", numColdHashes));
8133 // The "plus one" is so we can store the offset to the end of the array at the end of
8134 // the hashoffsets arrays, enabling faster lookups.
8135 hotHashOffsets = new DWORD[numHotHashes + 1];
8136 coldHashOffsets = new DWORD[numColdHashes + 1];
8138 DWORD *hashArray = new DWORD[numElements];
8140 for (i = 0; i < numElementsHot; i++)
8142 hashArray[i] = GenerateHash(ppMT[i].GetValue(), HOT);
8144 for (i = numElementsHot; i < numElements; i++)
8146 hashArray[i] = GenerateHash(ppMT[i].GetValue(), COLD);
8149 // Sort the two arrays by hash values to create regions with the same hash values.
8150 ClassCtorInfoEntryArraySort cctorInfoHotSort(hashArray, ppMT, numElementsHot);
8151 ClassCtorInfoEntryArraySort cctorInfoColdSort(hashArray + numElementsHot, ppMT + numElementsHot,
8152 numElements - numElementsHot);
8153 cctorInfoHotSort.Sort();
8154 cctorInfoColdSort.Sort();
8156 // Generate the indices that index into the correct "hash region" in the hot part of the ppMT array, and store
8157 // them in the hotHashOffests arrays.
8160 while (i < numElementsHot)
8162 if (curHash < hashArray[i])
8164 hotHashOffsets[curHash++] = i;
8166 else if (curHash == hashArray[i])
8168 hotHashOffsets[curHash++] = i++;
8175 while (curHash <= numHotHashes)
8177 hotHashOffsets[curHash++] = numElementsHot;
8180 // Generate the indices that index into the correct "hash region" in the hot part of the ppMT array, and store
8181 // them in the coldHashOffsets arrays.
8184 while (i < numElements)
8186 if (curHash < hashArray[i])
8188 coldHashOffsets[curHash++] = i;
8190 else if (curHash == hashArray[i])
8192 coldHashOffsets[curHash++] = i++;
8196 while (curHash <= numColdHashes)
8198 coldHashOffsets[curHash++] = numElements;
8204 cctorInfoHot = new ClassCtorInfoEntry[numElements];
8206 // make cctorInfoCold point to the first cold element
8207 cctorInfoCold = cctorInfoHot + numElementsHot;
8209 ppHotGCStaticsMTs = (totalBoxedStatics != 0) ? new RelativeFixupPointer<PTR_MethodTable>[totalBoxedStatics] : NULL;
8210 numHotGCStaticsMTs = totalBoxedStatics;
8212 DWORD iGCStaticMT = 0;
8214 for (i = 0; i < numElements; i++)
8216 if (numElements == numElementsHot)
8218 numHotGCStaticsMTs = iGCStaticMT;
8219 numColdGCStaticsMTs = (totalBoxedStatics - iGCStaticMT);
8221 // make ppColdGCStaticsMTs point to the first cold element
8222 ppColdGCStaticsMTs = ppHotGCStaticsMTs + numHotGCStaticsMTs;
8225 MethodTable* pMT = ppMT[i].GetValue();
8226 ClassCtorInfoEntry* pEntry = &cctorInfoHot[i];
8228 WORD numBoxedStatics = pMT->GetNumBoxedRegularStatics();
8229 pEntry->numBoxedStatics = numBoxedStatics;
8230 pEntry->hasFixedAddressVTStatics = !!pMT->HasFixedAddressVTStatics();
8232 FieldDesc *pField = pMT->HasGenericsStaticsInfo() ?
8233 pMT->GetGenericsStaticFieldDescs() : (pMT->GetApproxFieldDescListRaw() + pMT->GetNumIntroducedInstanceFields());
8234 FieldDesc *pFieldEnd = pField + pMT->GetNumStaticFields();
8236 pEntry->firstBoxedStaticOffset = (DWORD)-1;
8237 pEntry->firstBoxedStaticMTIndex = (DWORD)-1;
8239 DWORD numFoundBoxedStatics = 0;
8240 while (pField < pFieldEnd)
8242 _ASSERTE(pField->IsStatic());
8244 if (!pField->IsSpecialStatic() && pField->IsByValue())
8246 if (pEntry->firstBoxedStaticOffset == (DWORD)-1)
8248 pEntry->firstBoxedStaticOffset = pField->GetOffset();
8249 pEntry->firstBoxedStaticMTIndex = iGCStaticMT;
8251 _ASSERTE(pField->GetOffset() - pEntry->firstBoxedStaticOffset
8252 == (iGCStaticMT - pEntry->firstBoxedStaticMTIndex) * sizeof(MethodTable*));
8254 TypeHandle th = pField->GetFieldTypeHandleThrowing();
8255 ppHotGCStaticsMTs[iGCStaticMT++].SetValueMaybeNull(th.GetMethodTable());
8257 numFoundBoxedStatics++;
8261 _ASSERTE(numBoxedStatics == numFoundBoxedStatics);
8263 _ASSERTE(iGCStaticMT == totalBoxedStatics);
8265 if (numElementsHot > 0)
8267 image->StoreStructure(cctorInfoHot,
8268 sizeof(ClassCtorInfoEntry) * numElementsHot,
8269 DataImage::ITEM_MODULE_CCTOR_INFO_HOT);
8271 image->StoreStructure(hotHashOffsets,
8272 sizeof(DWORD) * (numHotHashes + 1),
8273 DataImage::ITEM_MODULE_CCTOR_INFO_HOT);
8276 if (numElements > 0)
8277 image->StoreStructure(ppMT,
8278 sizeof(RelativePointer<MethodTable *>) * numElements,
8279 DataImage::ITEM_MODULE_CCTOR_INFO_HOT);
8281 if (numElements > numElementsHot)
8283 image->StoreStructure(cctorInfoCold,
8284 sizeof(ClassCtorInfoEntry) * (numElements - numElementsHot),
8285 DataImage::ITEM_MODULE_CCTOR_INFO_COLD);
8287 image->StoreStructure(coldHashOffsets,
8288 sizeof(DWORD) * (numColdHashes + 1),
8289 DataImage::ITEM_MODULE_CCTOR_INFO_COLD);
8292 if ( numHotGCStaticsMTs )
8294 // Save the mt templates
8295 image->StoreStructure( ppHotGCStaticsMTs, numHotGCStaticsMTs * sizeof(RelativeFixupPointer<MethodTable*>),
8296 DataImage::ITEM_GC_STATIC_HANDLES_HOT);
8300 ppHotGCStaticsMTs = NULL;
8303 if ( numColdGCStaticsMTs )
8305 // Save the hot mt templates
8306 image->StoreStructure( ppColdGCStaticsMTs, numColdGCStaticsMTs * sizeof(RelativeFixupPointer<MethodTable*>),
8307 DataImage::ITEM_GC_STATIC_HANDLES_COLD);
8311 ppColdGCStaticsMTs = NULL;
8315 #endif // !DACCESS_COMPILE
8317 bool Module::AreAllClassesFullyLoaded()
8319 STANDARD_VM_CONTRACT;
8321 // Adjust for unused space
8322 IMDInternalImport *pImport = GetMDImport();
8324 HENUMInternalHolder hEnum(pImport);
8325 hEnum.EnumAllInit(mdtTypeDef);
8328 while (pImport->EnumNext(&hEnum, &token))
8330 _ASSERTE(TypeFromToken(token) == mdtTypeDef);
8332 // Special care has to been taken with COR_GLOBAL_PARENT_TOKEN, as the class
8333 // may not be needed, (but we have to distinguish between not needed and threw error).
8334 if (token == COR_GLOBAL_PARENT_TOKEN &&
8335 !NeedsGlobalMethodTable())
8337 // No EEClass for this token if there was no need for a global method table
8341 TypeHandle th = LookupTypeDef(token);
8345 if (!th.AsMethodTable()->IsFullyLoaded())
8352 void Module::PrepareTypesForSave(DataImage *image)
8354 STANDARD_VM_CONTRACT;
8360 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
8361 while (typeDefIter.Next())
8363 MethodTable * pMT = typeDefIter.GetElement();
8365 if (pMT == NULL || !pMT->IsFullyLoaded())
8373 // Prepare typespecs
8376 // Create a local copy in case the new elements are added to the hashtable during population
8377 InlineSArray<TypeHandle, 20> pTypes;
8379 // Make sure the iterator is destroyed before there is a chance of loading new types
8381 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
8382 EETypeHashEntry *pEntry;
8383 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
8385 TypeHandle t = pEntry->GetTypeHandle();
8390 if (!image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(t.AsPtr())))
8399 image->GetPreloader()->TriageForZap(FALSE, FALSE);
8402 static const char* const MethodTableRestoreReasonDescription[TotalMethodTables + 1] =
8404 #undef RESTORE_REASON_FUNC
8405 #define RESTORE_REASON_FUNC(s) #s,
8407 METHODTABLE_RESTORE_REASON()
8409 #undef RESTORE_REASON
8411 "TotalMethodTablesEvaluated"
8415 // MethodDescByMethodTableTraits could be a local class in Module::Save(), but g++ doesn't like
8416 // instantiating templates with private classes.
8417 class MethodDescByMethodTableTraits : public NoRemoveSHashTraits< DefaultSHashTraits<MethodDesc *> >
8420 typedef MethodTable * key_t;
8421 static MethodDesc * Null() { return NULL; }
8422 static bool IsNull(MethodDesc * pMD) { return pMD == NULL; }
8423 static MethodTable * GetKey(MethodDesc * pMD) { return pMD->GetMethodTable_NoLogging(); }
8424 static count_t Hash(MethodTable * pMT) { LIMITED_METHOD_CONTRACT; return (count_t) (UINT_PTR) pMT->GetTypeDefRid_NoLogging(); }
8425 static BOOL Equals(MethodTable * pMT1, MethodTable * pMT2)
8427 return pMT1 == pMT2;
8431 void Module::Save(DataImage *image)
8433 STANDARD_VM_CONTRACT;
8435 // Precompute type specific auxiliary information saved into NGen image
8436 // Note that this operation can load new types.
8437 PrepareTypesForSave(image);
8439 // Cache values of all persisted flags computed from custom attributes
8440 IsNoStringInterning();
8441 IsRuntimeWrapExceptions();
8444 HasDefaultDllImportSearchPathsAttribute();
8446 // Precompute property information to avoid runtime metadata lookup
8447 PopulatePropertyInfoMap();
8449 // Any any elements and compute values of any LookupMap flags that were not available previously
8450 FinalizeLookupMapsPreSave(image);
8456 ZapStoredStructure * pModuleNode = image->StoreStructure(this, sizeof(Module),
8457 DataImage::ITEM_MODULE);
8459 m_pNGenLayoutInfo = (NGenLayoutInfo *)(void *)image->GetModule()->GetLoaderAllocator()->
8460 GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(NGenLayoutInfo)));
8461 image->StoreStructure(m_pNGenLayoutInfo, sizeof(NGenLayoutInfo), DataImage::ITEM_BINDER_ITEMS);
8464 // If we are NGening, we don't need to keep a list of va
8465 // sig cookies, as we already have a complete set (of course we do
8466 // have to persist the cookies themselves, though.
8470 // Initialize maps of child data structures. Note that each tables's blocks are
8471 // concantentated to a single block in the process.
8473 CorProfileData * profileData = GetProfileData();
8475 // ngen the neutral resources culture
8476 if(GetNeutralResourcesLanguage(&m_pszCultureName, &m_CultureNameLength, &m_FallbackLocation, TRUE)) {
8477 image->StoreStructure((void *) m_pszCultureName,
8478 (ULONG)(m_CultureNameLength + 1),
8479 DataImage::ITEM_BINDER_ITEMS,
8484 m_TypeRefToMethodTableMap.Save(image, DataImage::ITEM_TYPEREF_MAP, profileData, mdtTypeRef);
8485 image->BindPointer(&m_TypeRefToMethodTableMap, pModuleNode, offsetof(Module, m_TypeRefToMethodTableMap));
8487 if(m_pMemberRefToDescHashTable)
8488 m_pMemberRefToDescHashTable->Save(image, profileData);
8490 m_TypeDefToMethodTableMap.Save(image, DataImage::ITEM_TYPEDEF_MAP, profileData, mdtTypeDef);
8491 image->BindPointer(&m_TypeDefToMethodTableMap, pModuleNode, offsetof(Module, m_TypeDefToMethodTableMap));
8493 m_MethodDefToDescMap.Save(image, DataImage::ITEM_METHODDEF_MAP, profileData, mdtMethodDef);
8494 image->BindPointer(&m_MethodDefToDescMap, pModuleNode, offsetof(Module, m_MethodDefToDescMap));
8496 m_FieldDefToDescMap.Save(image, DataImage::ITEM_FIELDDEF_MAP, profileData, mdtFieldDef);
8497 image->BindPointer(&m_FieldDefToDescMap, pModuleNode, offsetof(Module, m_FieldDefToDescMap));
8499 m_GenericParamToDescMap.Save(image, DataImage::ITEM_GENERICPARAM_MAP, profileData, mdtGenericParam);
8500 image->BindPointer(&m_GenericParamToDescMap, pModuleNode, offsetof(Module, m_GenericParamToDescMap));
8502 m_GenericTypeDefToCanonMethodTableMap.Save(image, DataImage::ITEM_GENERICTYPEDEF_MAP, profileData, mdtTypeDef);
8503 image->BindPointer(&m_GenericTypeDefToCanonMethodTableMap, pModuleNode, offsetof(Module, m_GenericTypeDefToCanonMethodTableMap));
8505 if (m_pAvailableClasses)
8506 m_pAvailableClasses->Save(image, profileData);
8509 // Also save the parent maps; the contents will
8510 // need to be rewritten, but we can allocate the
8511 // space in the image.
8514 // these items have no hot list and no attribution
8515 m_FileReferencesMap.Save(image, DataImage::ITEM_FILEREF_MAP, profileData, 0);
8516 image->BindPointer(&m_FileReferencesMap, pModuleNode, offsetof(Module, m_FileReferencesMap));
8518 m_ManifestModuleReferencesMap.Save(image, DataImage::ITEM_ASSEMREF_MAP, profileData, 0);
8519 image->BindPointer(&m_ManifestModuleReferencesMap, pModuleNode, offsetof(Module, m_ManifestModuleReferencesMap));
8521 m_MethodDefToPropertyInfoMap.Save(image, DataImage::ITEM_PROPERTYINFO_MAP, profileData, 0, TRUE /*fCopyValues*/);
8522 image->BindPointer(&m_MethodDefToPropertyInfoMap, pModuleNode, offsetof(Module, m_MethodDefToPropertyInfoMap));
8524 if (m_pBinder != NULL)
8525 m_pBinder->Save(image);
8531 // Saving hot things first is a very good thing, because we place items
8532 // in the order they are saved and things that have hot items are also
8533 // more likely to have their other structures touched, hence these should
8534 // also be placed together, at least if we don't have any further information to go on.
8535 // Note we place particular hot items with more care in the Arrange phase.
8537 CORBBTPROF_TOKEN_INFO * pTypeProfilingData = profileData->GetTokenFlagsData(TypeProfilingData);
8538 DWORD cTypeProfilingData = profileData->GetTokenFlagsCount(TypeProfilingData);
8540 for (unsigned int i = 0; i < cTypeProfilingData; i++)
8542 CORBBTPROF_TOKEN_INFO *entry = &pTypeProfilingData[i];
8543 mdToken token = entry->token;
8544 DWORD flags = entry->flags;
8545 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
8546 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_4);
8549 if ((flags & (1 << ReadMethodTable)) == 0)
8552 if (TypeFromToken(token) == mdtTypeDef)
8554 MethodTable *pMT = LookupTypeDef(token).GetMethodTable();
8555 if (pMT && pMT->IsFullyLoaded())
8557 SaveMethodTable(image, pMT, flags);
8560 else if (TypeFromToken(token) == ibcTypeSpec)
8562 CORBBTPROF_BLOB_ENTRY *pBlobEntry = profileData->GetBlobStream();
8565 while (pBlobEntry->TypeIsValid())
8567 if (TypeFromToken(pBlobEntry->token) == ibcTypeSpec)
8569 _ASSERTE(pBlobEntry->type == ParamTypeSpec);
8571 if (pBlobEntry->token == token)
8573 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY *) pBlobEntry;
8574 TypeHandle th = LoadIBCTypeHelper(image, pBlobSigEntry);
8578 // When we have stale IBC data the type could have been rejected from this image.
8579 if (image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(th.AsPtr())))
8581 SaveTypeHandle(image, th, flags);
8586 pBlobEntry = pBlobEntry->GetNextEntry();
8588 _ASSERTE(pBlobEntry->type == EndOfBlobStream);
8593 if (m_pAvailableParamTypes != NULL)
8595 // If we have V1 IBC data then we save the hot
8596 // out-of-module generic instantiations here
8598 CORBBTPROF_TOKEN_INFO * tokens_begin = profileData->GetTokenFlagsData(GenericTypeProfilingData);
8599 CORBBTPROF_TOKEN_INFO * tokens_end = tokens_begin + profileData->GetTokenFlagsCount(GenericTypeProfilingData);
8601 if (tokens_begin != tokens_end)
8603 SArray<CORBBTPROF_TOKEN_INFO> tokens(tokens_begin, tokens_end);
8604 tokens_begin = &tokens[0];
8605 tokens_end = tokens_begin + tokens.GetCount();
8607 util::sort(tokens_begin, tokens_end);
8609 // enumerate AvailableParamTypes map and find all hot generic instantiations
8610 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
8611 EETypeHashEntry *pEntry;
8612 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
8614 TypeHandle t = pEntry->GetTypeHandle();
8615 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
8616 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_5);
8619 if (t.HasInstantiation())
8622 t.GetName(tokenName);
8623 unsigned cur_token = tokenName.Hash() & 0xffff;
8625 CORBBTPROF_TOKEN_INFO * found = util::lower_bound(tokens_begin, tokens_end, CORBBTPROF_TOKEN_INFO(cur_token));
8626 if (found != tokens_end && found->token == cur_token && (found->flags & (1 << ReadMethodTable)))
8628 // When we have stale IBC data the type could have been rejected from this image.
8629 if (image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(t.AsPtr())))
8630 SaveTypeHandle(image, t, found->flags);
8639 // Now save any types in the TypeDefToMethodTableMap map
8642 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
8644 while (typeDefIter.Next())
8646 MethodTable * pMT = typeDefIter.GetElement();
8649 !image->IsStored(pMT) && pMT->IsFullyLoaded())
8651 image->BeginAssociatingStoredObjectsWithMethodTable(pMT);
8652 SaveMethodTable(image, pMT, 0);
8653 image->EndAssociatingStoredObjectsWithMethodTable();
8659 // Now save any TypeDescs in m_GenericParamToDescMap map
8662 LookupMap<PTR_TypeVarTypeDesc>::Iterator genericParamIter(&m_GenericParamToDescMap);
8664 while (genericParamIter.Next())
8666 TypeVarTypeDesc *pTD = genericParamIter.GetElement();
8676 SealGenericTypesAndMethods();
8680 // Now save any types in the AvailableParamTypes map
8682 if (m_pAvailableParamTypes != NULL)
8684 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
8685 EETypeHashEntry *pEntry;
8686 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
8688 TypeHandle t = pEntry->GetTypeHandle();
8690 if (image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(t.AsPtr())))
8692 if (t.GetCanonicalMethodTable() != NULL)
8694 image->BeginAssociatingStoredObjectsWithMethodTable(t.GetCanonicalMethodTable());
8695 SaveTypeHandle(image, t, 0);
8696 image->EndAssociatingStoredObjectsWithMethodTable();
8700 SaveTypeHandle(image, t, 0);
8707 // Now save any methods in the InstMethodHashTable
8709 if (m_pInstMethodHashTable != NULL)
8712 // Find all MethodDescs that we are going to save, and hash them with MethodTable as the key
8715 typedef SHash<MethodDescByMethodTableTraits> MethodDescByMethodTableHash;
8717 MethodDescByMethodTableHash methodDescs;
8719 InstMethodHashTable::Iterator it(m_pInstMethodHashTable);
8720 InstMethodHashEntry *pEntry;
8721 while (m_pInstMethodHashTable->FindNext(&it, &pEntry))
8723 MethodDesc *pMD = pEntry->GetMethod();
8725 _ASSERTE(!pMD->IsTightlyBoundToMethodTable());
8727 if (!image->IsStored(pMD) &&
8728 image->GetPreloader()->IsMethodInTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE(pMD)))
8730 methodDescs.Add(pMD);
8735 // Save all MethodDescs on the same MethodTable using one chunk builder
8738 for (MethodDescByMethodTableHash::Iterator i1 = methodDescs.Begin(), end1 = methodDescs.End(); i1 != end1; i1++)
8740 MethodDesc * pMD = *(i1);
8741 if (image->IsStored(pMD))
8744 MethodTable * pMT = pMD->GetMethodTable();
8746 MethodDesc::SaveChunk methodDescSaveChunk(image);
8748 for (MethodDescByMethodTableHash::KeyIterator i2 = methodDescs.Begin(pMT), end2 = methodDescs.End(pMT); i2 != end2; i2++)
8750 _ASSERTE(!image->IsStored(*i2));
8751 methodDescSaveChunk.Append(*i2);
8754 methodDescSaveChunk.Save();
8758 // Now save the tables themselves
8759 if (m_pAvailableParamTypes != NULL)
8761 m_pAvailableParamTypes->Save(image, this, profileData);
8764 if (m_pInstMethodHashTable != NULL)
8766 m_pInstMethodHashTable->Save(image, profileData);
8770 MethodTable * pStubMT = GetILStubCache()->GetStubMethodTable();
8771 if (pStubMT != NULL)
8773 SaveMethodTable(image, pStubMT, 0);
8777 if (m_pStubMethodHashTable != NULL)
8779 m_pStubMethodHashTable->Save(image, profileData);
8782 #ifdef FEATURE_COMINTEROP
8783 // the type saving operations above had the side effect of populating m_pGuidToTypeHash
8784 if (m_pGuidToTypeHash != NULL)
8786 m_pGuidToTypeHash->Save(image, profileData);
8788 #endif // FEATURE_COMINTEROP
8790 // Compute and save the property name set
8791 PrecomputeMatchingProperties(image);
8792 image->StoreStructure(m_propertyNameSet,
8793 m_nPropertyNameSet * sizeof(BYTE),
8794 DataImage::ITEM_PROPERTY_NAME_SET);
8797 // Sort the list of RVA statics in an ascending order wrt the RVA
8799 image->SaveRvaStructure();
8802 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Saving module static data\n"));
8804 // We have this scenario where ngen will fail to load some classes but will generate
8805 // a valid exe, or it will choose not to save some loaded classes due to some error
8806 // conditions, where statics will be committed at runtime for the classes that ngen
8807 // wasn't able to load or save. So we can't cut down the static block size blindly if we've
8808 // failed to load or save any class. We don't think this scenario deserves complicated code
8809 // paths to get the extra working set perf (you would be pulling in the jitter if
8810 // you need any of these classes), So we are basically simplifying this down, if we failed
8811 // to load or save any class we won't compress the statics block and will persist the original
8814 // All classes were loaded and saved, cut down the block
8815 if (AreAllClassesFullyLoaded())
8817 // Set a mark indicating we had all our classes loaded
8818 m_pRegularStaticOffsets = (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED;
8819 m_pThreadStaticOffsets = (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED;
8823 // Since not all of the classes loaded we want to zero the pointers to the offset tables so they'll be
8824 // recalculated at runtime. But we can't do that here since we might try to reload some of the failed
8825 // types during the arrange phase (as the result of trying to parse profiling data). So we'll defer
8826 // zero'ing anything until the fixup phase.
8828 // Not all classes were stored, revert to uncompressed maps to support run-time changes
8829 m_TypeDefToMethodTableMap.ConvertSavedMapToUncompressed(image, DataImage::ITEM_TYPEDEF_MAP);
8830 m_MethodDefToDescMap.ConvertSavedMapToUncompressed(image, DataImage::ITEM_METHODDEF_MAP);
8833 m_ModuleCtorInfo.Save(image, profileData);
8834 image->BindPointer(&m_ModuleCtorInfo, pModuleNode, offsetof(Module, m_ModuleCtorInfo));
8836 if (m_pDynamicStaticsInfo)
8838 image->StoreStructure(m_pDynamicStaticsInfo, m_maxDynamicEntries*sizeof(DynamicStaticsInfo),
8839 DataImage::ITEM_DYNAMIC_STATICS_INFO_TABLE);
8842 InlineTrackingMap *inlineTrackingMap = image->GetInlineTrackingMap();
8843 if (inlineTrackingMap)
8845 m_pPersistentInlineTrackingMapNGen = new (image->GetHeap()) PersistentInlineTrackingMapNGen(this);
8846 m_pPersistentInlineTrackingMapNGen->Save(image, inlineTrackingMap);
8849 if (m_pNgenStats && g_CorCompileVerboseLevel >= CORCOMPILE_STATS)
8851 GetSvcLogger()->Printf ("%-35s: %s\n", "MethodTable Restore Reason", "Count");
8853 for (int i=0; i<TotalMethodTables; i++)
8855 GetSvcLogger()->Printf ("%-35s: %d\n", MethodTableRestoreReasonDescription[i], m_pNgenStats->MethodTableRestoreNumReasons[i]);
8856 dwTotal += m_pNgenStats->MethodTableRestoreNumReasons[i];
8858 GetSvcLogger()->Printf ("%-35s: %d\n", "TotalMethodTablesNeedRestore", dwTotal);
8859 GetSvcLogger()->Printf ("%-35s: %d\n", MethodTableRestoreReasonDescription[TotalMethodTables], m_pNgenStats->MethodTableRestoreNumReasons[TotalMethodTables]);
8866 // We call these methods to seal the
8867 // lists: m_pAvailableClasses and m_pAvailableParamTypes
8869 void Module::SealGenericTypesAndMethods()
8871 LIMITED_METHOD_CONTRACT;
8872 // Enforce that after this point in ngen that no more types or methods will be loaded.
8874 // We increment the seal count here and only decrement it after we have completed the ngen image
8876 if (m_pAvailableParamTypes != NULL)
8878 m_pAvailableParamTypes->Seal();
8880 if (m_pInstMethodHashTable != NULL)
8882 m_pInstMethodHashTable->Seal();
8886 // We call these methods to unseal the
8887 // lists: m_pAvailableClasses and m_pAvailableParamTypes
8889 void Module::UnsealGenericTypesAndMethods()
8891 LIMITED_METHOD_CONTRACT;
8892 // Allow us to create generic types and methods again
8894 // We only decrement it after we have completed the ngen image
8896 if (m_pAvailableParamTypes != NULL)
8898 m_pAvailableParamTypes->Unseal();
8900 if (m_pInstMethodHashTable != NULL)
8902 m_pInstMethodHashTable->Unseal();
8908 void Module::PrepopulateDictionaries(DataImage *image, BOOL nonExpansive)
8910 STANDARD_VM_CONTRACT;
8912 // Prepopulating the dictionaries for instantiated types
8913 // is in theory an iteraive process, i.e. filling in
8914 // a dictionary slot may result in a class load of a new type whose
8915 // dictionary may itself need to be prepopulated. The type expressions
8916 // involved can get larger, so there's no a-priori reason to expect this
8917 // process to terminate.
8919 // Given a starting set of instantiated types, several strategies are
8920 // thus possible - no prepopulation (call this PP0), or
8921 // prepopulate only the dictionaries of the types that are in the initial
8922 // set (call this PP1), or do two iterations (call this PP2) etc. etc.
8923 // Whichever strategy we choose we can always afford to do
8924 // one round of prepopulation where we populate slots
8925 // whose corresponding resulting method/types are already loaded.
8926 // Call this PPn+PP-FINAL.
8928 // Below we implement PP1+PP-FINAL for instantiated types and PP0+PP-FINAL
8929 // for instantiations of generic methods. We use PP1 because most collection
8930 // classes (List, Dictionary etc.) only require one pass of prepopulation in order
8931 // to fully prepopulate the dictionary.
8933 // Do PP1 for instantiated types... Do one iteration where we force type loading...
8934 // Because this phase may cause new entries to appear in the hash table we
8935 // copy the array of types to the stack before we do anything else.
8936 if (!nonExpansive && CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Prepopulate1))
8938 if (m_pAvailableParamTypes != NULL)
8940 // Create a local copy in case the new elements are added to the hashtable during population
8941 InlineSArray<TypeHandle, 20> pTypes;
8943 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
8944 EETypeHashEntry *pEntry;
8945 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
8947 TypeHandle th = pEntry->GetTypeHandle();
8948 if (th.IsTypeDesc())
8951 // Don't do prepopulation for open types - they shouldn't really have dictionaries anyway.
8952 MethodTable * pMT = th.AsMethodTable();
8953 if (pMT->ContainsGenericVariables())
8956 // Only do PP1 on things that land in their preferred Zap module.
8957 // Forcing the load of dictionary entries in the case where we are
8958 // speculatively saving a copy of an instantiation outside its preferred
8959 // zap module is too expensive for the common collection class cases.
8961 // Invalid generic instantiations will not be fully loaded.
8962 // We want to ignore them as touching them will re-raise the TypeLoadException
8963 if (pMT->IsFullyLoaded() && image->GetModule() == GetPreferredZapModuleForMethodTable(pMT))
8970 for(COUNT_T i = 0; i < pTypes.GetCount(); i ++)
8972 TypeHandle th = pTypes[i];
8973 _ASSERTE(image->GetModule() == GetPreferredZapModuleForTypeHandle(th) );
8974 _ASSERTE(!th.IsTypeDesc() && !th.ContainsGenericVariables());
8975 th.AsMethodTable()->PrepopulateDictionary(image, FALSE /* not nonExpansive, i.e. can load types */);
8980 // PP-FINAL for instantiated types.
8981 // This is the final stage where we hardbind any remaining entries that map
8982 // to results that have already been loaded...
8983 // Thus we set the "nonExpansive" flag on PrepopulateDictionary
8984 // below, which may in turn greatly limit the amount of prepopulating we do
8985 // (partly because it's quite difficult to determine if some potential entries
8986 // in the dictionary are already loaded)
8988 if (m_pAvailableParamTypes != NULL)
8990 INDEBUG(DWORD nTypes = m_pAvailableParamTypes->GetCount());
8992 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
8993 EETypeHashEntry *pEntry;
8994 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
8996 TypeHandle th = pEntry->GetTypeHandle();
8997 if (th.IsTypeDesc())
9000 MethodTable * pMT = th.AsMethodTable();
9001 if (pMT->ContainsGenericVariables())
9004 pMT->PrepopulateDictionary(image, TRUE /* nonExpansive */);
9007 // No new instantiations should be added by nonExpansive prepopulation
9008 _ASSERTE(nTypes == m_pAvailableParamTypes->GetCount());
9011 // PP-FINAL for instantiations of generic methods.
9012 if (m_pInstMethodHashTable != NULL)
9014 INDEBUG(DWORD nMethods = m_pInstMethodHashTable->GetCount());
9016 InstMethodHashTable::Iterator it(m_pInstMethodHashTable);
9017 InstMethodHashEntry *pEntry;
9018 while (m_pInstMethodHashTable->FindNext(&it, &pEntry))
9020 MethodDesc *pMD = pEntry->GetMethod();
9021 if (!pMD->ContainsGenericVariables())
9023 pMD->PrepopulateDictionary(image, TRUE /* nonExpansive */);
9027 // No new instantiations should be added by nonExpansive prepopulation
9028 _ASSERTE(nMethods == m_pInstMethodHashTable->GetCount());
9032 void Module::PlaceType(DataImage *image, TypeHandle th, DWORD profilingFlags)
9034 STANDARD_VM_CONTRACT;
9039 MethodTable *pMT = th.GetMethodTable();
9041 if (pMT && pMT->GetLoaderModule() == this)
9043 EEClass *pClass = pMT->GetClass();
9045 if (profilingFlags & (1 << WriteMethodTableWriteableData))
9047 image->PlaceStructureForAddress(pMT->GetWriteableData(),CORCOMPILE_SECTION_WRITE);
9050 if (profilingFlags & (1 << ReadMethodTable))
9052 CorCompileSection section = CORCOMPILE_SECTION_READONLY_HOT;
9053 if (pMT->IsWriteable())
9054 section = CORCOMPILE_SECTION_HOT_WRITEABLE;
9055 image->PlaceStructureForAddress(pMT, section);
9057 if (pMT->HasInterfaceMap())
9058 image->PlaceInternedStructureForAddress(pMT->GetInterfaceMap(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9060 MethodTable::VtableIndirectionSlotIterator it = pMT->IterateVtableIndirectionSlots();
9063 image->PlaceInternedStructureForAddress(it.GetIndirectionSlot(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9066 image->PlaceStructureForAddress(pMT->GetWriteableData(), CORCOMPILE_SECTION_HOT);
9069 if (profilingFlags & (1 << ReadNonVirtualSlots))
9071 if (pMT->HasNonVirtualSlotsArray())
9072 image->PlaceStructureForAddress(pMT->GetNonVirtualSlotsArray(), CORCOMPILE_SECTION_READONLY_HOT);
9075 if (profilingFlags & (1 << ReadDispatchMap) && pMT->HasDispatchMapSlot())
9077 image->PlaceInternedStructureForAddress(pMT->GetDispatchMap(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9080 if (profilingFlags & (1 << WriteEEClass))
9082 image->PlaceStructureForAddress(pClass, CORCOMPILE_SECTION_WRITE);
9084 if (pClass->HasOptionalFields())
9085 image->PlaceStructureForAddress(pClass->GetOptionalFields(), CORCOMPILE_SECTION_WRITE);
9088 else if (profilingFlags & (1 << ReadEEClass))
9090 image->PlaceStructureForAddress(pClass, CORCOMPILE_SECTION_HOT);
9092 if (pClass->HasOptionalFields())
9093 image->PlaceStructureForAddress(pClass->GetOptionalFields(), CORCOMPILE_SECTION_HOT);
9095 if (pClass->GetVarianceInfo() != NULL)
9096 image->PlaceInternedStructureForAddress(pClass->GetVarianceInfo(), CORCOMPILE_SECTION_READONLY_WARM, CORCOMPILE_SECTION_READONLY_WARM);
9098 #ifdef FEATURE_COMINTEROP
9099 if (pClass->GetSparseCOMInteropVTableMap() != NULL)
9101 image->PlaceStructureForAddress(pClass->GetSparseCOMInteropVTableMap(), CORCOMPILE_SECTION_WARM);
9102 image->PlaceInternedStructureForAddress(pClass->GetSparseCOMInteropVTableMap()->GetMapList(), CORCOMPILE_SECTION_READONLY_WARM, CORCOMPILE_SECTION_READONLY_WARM);
9107 if (profilingFlags & (1 << ReadFieldDescs))
9109 image->PlaceStructureForAddress(pMT->GetApproxFieldDescListRaw(), CORCOMPILE_SECTION_READONLY_HOT);
9112 if (profilingFlags != 0)
9114 if (pMT->HasPerInstInfo())
9116 DPTR(MethodTable::PerInstInfoElem_t) pPerInstInfo = pMT->GetPerInstInfo();
9118 BOOL fIsEagerBound = pMT->CanEagerBindToParentDictionaries(image, NULL);
9122 if (MethodTable::PerInstInfoElem_t::isRelative)
9124 image->PlaceStructureForAddress(pPerInstInfo, CORCOMPILE_SECTION_READONLY_HOT);
9128 image->PlaceInternedStructureForAddress(pPerInstInfo, CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9133 image->PlaceStructureForAddress(pPerInstInfo, CORCOMPILE_SECTION_WRITE);
9137 Dictionary * pDictionary = pMT->GetDictionary();
9138 if (pDictionary != NULL)
9142 if (!pMT->IsCanonicalMethodTable())
9144 // CanEagerBindToMethodTable would not work for targeted patching here. The dictionary
9145 // layout is sensitive to compilation order that can be changed by TP compatible changes.
9146 BOOL canSaveSlots = (image->GetModule() == pMT->GetCanonicalMethodTable()->GetLoaderModule());
9148 fIsWriteable = pDictionary->IsWriteable(image, canSaveSlots,
9149 pMT->GetNumGenericArgs(),
9151 pClass->GetDictionaryLayout());
9155 fIsWriteable = FALSE;
9160 image->PlaceStructureForAddress(pDictionary, CORCOMPILE_SECTION_HOT_WRITEABLE);
9161 image->PlaceStructureForAddress(pClass->GetDictionaryLayout(), CORCOMPILE_SECTION_WARM);
9165 image->PlaceInternedStructureForAddress(pDictionary, CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9170 if (profilingFlags & (1 << ReadFieldMarshalers))
9172 if (pClass->HasLayout() && pClass->GetLayoutInfo()->GetNumCTMFields() > 0)
9174 image->PlaceStructureForAddress((void *)pClass->GetLayoutInfo()->GetFieldMarshalers(), CORCOMPILE_SECTION_HOT);
9178 if (th.IsTypeDesc())
9180 if (profilingFlags & (1 << WriteTypeDesc))
9181 image->PlaceStructureForAddress(th.AsTypeDesc(), CORCOMPILE_SECTION_WRITE);
9182 else if (profilingFlags & (1 << ReadTypeDesc))
9183 image->PlaceStructureForAddress(th.AsTypeDesc(), CORCOMPILE_SECTION_HOT);
9185 image->PlaceStructureForAddress(th.AsTypeDesc(), CORCOMPILE_SECTION_WARM);
9189 void Module::PlaceMethod(DataImage *image, MethodDesc *pMD, DWORD profilingFlags)
9191 STANDARD_VM_CONTRACT;
9196 if (pMD->GetLoaderModule() != this)
9199 if (profilingFlags & (1 << ReadMethodCode))
9201 if (pMD->IsNDirect())
9203 NDirectMethodDesc *pNMD = (NDirectMethodDesc *)pMD;
9204 image->PlaceStructureForAddress((void*) pNMD->GetWriteableData(), CORCOMPILE_SECTION_WRITE);
9206 #ifdef HAS_NDIRECT_IMPORT_PRECODE
9207 // The NDirect import thunk glue is used only if no marshaling is required
9208 if (!pNMD->MarshalingRequired())
9210 image->PlaceStructureForAddress((void*) pNMD->GetNDirectImportThunkGlue(), CORCOMPILE_SECTION_METHOD_PRECODE_HOT);
9212 #endif // HAS_NDIRECT_IMPORT_PRECODE
9214 // Late bound NDirect methods require their LibName at startup.
9215 if (!pNMD->IsQCall())
9217 image->PlaceStructureForAddress((void*) pNMD->GetLibName(), CORCOMPILE_SECTION_READONLY_HOT);
9218 image->PlaceStructureForAddress((void*) pNMD->GetEntrypointName(), CORCOMPILE_SECTION_READONLY_HOT);
9222 #ifdef FEATURE_COMINTEROP
9223 if (pMD->IsComPlusCall())
9225 ComPlusCallMethodDesc *pCMD = (ComPlusCallMethodDesc *)pMD;
9227 // If the ComPlusCallMethodDesc was actually used for interop, its ComPlusCallInfo should be hot.
9228 image->PlaceStructureForAddress((void*) pCMD->m_pComPlusCallInfo, CORCOMPILE_SECTION_HOT);
9230 #endif // FEATURE_COMINTEROP
9232 // Stubs-as-IL have writeable signatures sometimes, so can't place them
9233 // into read-only section. We should not get here for stubs-as-il anyway,
9234 // but we will filter them out just to be sure.
9235 if (pMD->HasStoredSig() && !pMD->IsILStub())
9237 StoredSigMethodDesc *pSMD = (StoredSigMethodDesc*) pMD;
9239 if (pSMD->HasStoredMethodSig())
9241 image->PlaceInternedStructureForAddress((void*) pSMD->GetStoredMethodSig(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9246 // We store the entire hot chunk in the SECTION_WRITE section
9247 if (profilingFlags & (1 << WriteMethodDesc))
9249 image->PlaceStructureForAddress(pMD, CORCOMPILE_SECTION_WRITE);
9253 if (profilingFlags & (1 << WriteMethodPrecode))
9255 Precode* pPrecode = pMD->GetSavedPrecodeOrNull(image);
9256 // protect against stale IBC data
9257 if (pPrecode != NULL)
9259 CorCompileSection section = CORCOMPILE_SECTION_METHOD_PRECODE_WRITE;
9260 if (pPrecode->IsPrebound(image))
9261 section = CORCOMPILE_SECTION_METHOD_PRECODE_HOT;
9262 // Note: This is going to place the entire PRECODE_FIXUP chunk if we have one
9263 image->PlaceStructureForAddress(pPrecode, section);
9266 else if (profilingFlags & (1 << ReadMethodPrecode))
9268 Precode* pPrecode = pMD->GetSavedPrecodeOrNull(image);
9269 // protect against stale IBC data
9270 if (pPrecode != NULL)
9272 // Note: This is going to place the entire PRECODE_FIXUP chunk if we have one
9273 image->PlaceStructureForAddress(pPrecode, CORCOMPILE_SECTION_METHOD_PRECODE_HOT);
9278 void Module::Arrange(DataImage *image)
9280 STANDARD_VM_CONTRACT;
9282 // We collect IBC logging profiling data and use that to guide the layout of the image.
9283 image->PlaceStructureForAddress(this, CORCOMPILE_SECTION_MODULE);
9285 // The stub method table is shared by all IL stubs in the module, so place it into the hot section
9286 MethodTable * pStubMT = GetILStubCache()->GetStubMethodTable();
9287 if (pStubMT != NULL)
9288 PlaceType(image, pStubMT, ReadMethodTable);
9290 CorProfileData * profileData = GetProfileData();
9294 // Place hot type structues in the order specifiled by TypeProfilingData array
9296 CORBBTPROF_TOKEN_INFO * pTypeProfilingData = profileData->GetTokenFlagsData(TypeProfilingData);
9297 DWORD cTypeProfilingData = profileData->GetTokenFlagsCount(TypeProfilingData);
9298 for (unsigned int i = 0; (i < cTypeProfilingData); i++)
9300 CORBBTPROF_TOKEN_INFO * entry = &pTypeProfilingData[i];
9301 mdToken token = entry->token;
9302 DWORD flags = entry->flags;
9303 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
9304 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_6);
9307 if (TypeFromToken(token) == mdtTypeDef)
9309 TypeHandle th = LookupTypeDef(token);
9311 // Place a hot normal type and it's data
9313 PlaceType(image, th, flags);
9315 else if (TypeFromToken(token) == ibcTypeSpec)
9317 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = profileData->GetBlobSigEntry(token);
9319 if (pBlobSigEntry == NULL)
9322 // Print an error message for the type load failure
9324 StackSString msg(W("Did not find definition for type token "));
9327 sprintf_s(buff, COUNTOF(buff), "%08x", token);
9328 StackSString szToken(SString::Ascii, &buff[0]);
9330 msg += W(" in profile data.\n");
9332 GetSvcLogger()->Log(msg, LogLevel_Info);
9334 else // (pBlobSigEntry != NULL)
9336 _ASSERTE(pBlobSigEntry->blob.token == token);
9338 // decode generic type signature
9340 TypeHandle th = LoadIBCTypeHelper(image, pBlobSigEntry);
9343 // Place a hot instantiated type and it's data
9345 PlaceType(image, th, flags);
9348 else if (TypeFromToken(token) == mdtFieldDef)
9350 FieldDesc *pFD = LookupFieldDef(token);
9351 if (pFD && pFD->IsRVA())
9353 if (entry->flags & (1 << RVAFieldData))
9355 BYTE *pRVAData = (BYTE*) pFD->GetStaticAddressHandle(NULL);
9357 // Place a hot RVA static field
9359 image->PlaceStructureForAddress(pRVAData, CORCOMPILE_SECTION_RVA_STATICS_HOT);
9366 // Place hot methods and method data in the order specifiled by MethodProfilingData array
9368 CORBBTPROF_TOKEN_INFO * pMethodProfilingData = profileData->GetTokenFlagsData(MethodProfilingData);
9369 DWORD cMethodProfilingData = profileData->GetTokenFlagsCount(MethodProfilingData);
9370 for (unsigned int i = 0; (i < cMethodProfilingData); i++)
9372 mdToken token = pMethodProfilingData[i].token;
9373 DWORD profilingFlags = pMethodProfilingData[i].flags;
9374 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
9375 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_7);
9378 if (TypeFromToken(token) == mdtMethodDef)
9380 MethodDesc * pMD = LookupMethodDef(token);
9382 // Place a hot normal method and it's data
9384 PlaceMethod(image, pMD, profilingFlags);
9386 else if (TypeFromToken(token) == ibcMethodSpec)
9388 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = profileData->GetBlobSigEntry(token);
9390 if (pBlobSigEntry == NULL)
9393 // Print an error message for the type load failure
9395 StackSString msg(W("Did not find definition for method token "));
9398 sprintf_s(buff, COUNTOF(buff), "%08x", token);
9399 StackSString szToken(SString::Ascii, &buff[0]);
9401 msg += W(" in profile data.\n");
9403 GetSvcLogger()->Log(msg, LogLevel_Info);
9405 else // (pBlobSigEntry != NULL)
9407 _ASSERTE(pBlobSigEntry->blob.token == token);
9408 MethodDesc * pMD = LoadIBCMethodHelper(image, pBlobSigEntry);
9413 // Place a hot instantiated method and it's data
9415 PlaceMethod(image, pMD, profilingFlags);
9422 // Now place all remaining items
9423 image->PlaceRemainingStructures();
9426 void ModuleCtorInfo::Fixup(DataImage *image)
9428 STANDARD_VM_CONTRACT;
9430 if (numElementsHot > 0)
9432 image->FixupPointerField(this, offsetof(ModuleCtorInfo, cctorInfoHot));
9433 image->FixupPointerField(this, offsetof(ModuleCtorInfo, hotHashOffsets));
9437 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, cctorInfoHot));
9438 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, hotHashOffsets));
9441 _ASSERTE(numElements > numElementsHot || numElements == numElementsHot);
9442 if (numElements > numElementsHot)
9444 image->FixupPointerField(this, offsetof(ModuleCtorInfo, cctorInfoCold));
9445 image->FixupPointerField(this, offsetof(ModuleCtorInfo, coldHashOffsets));
9449 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, cctorInfoCold));
9450 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, coldHashOffsets));
9453 if (numElements > 0)
9455 image->FixupPointerField(this, offsetof(ModuleCtorInfo, ppMT));
9457 for (DWORD i=0; i<numElements; i++)
9459 image->FixupRelativePointerField(ppMT, i * sizeof(ppMT[0]));
9464 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, ppMT));
9467 if (numHotGCStaticsMTs > 0)
9469 image->FixupPointerField(this, offsetof(ModuleCtorInfo, ppHotGCStaticsMTs));
9471 image->BeginRegion(CORINFO_REGION_HOT);
9472 for (DWORD i=0; i < numHotGCStaticsMTs; i++)
9474 image->FixupMethodTablePointer(ppHotGCStaticsMTs, &ppHotGCStaticsMTs[i]);
9476 image->EndRegion(CORINFO_REGION_HOT);
9480 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, ppHotGCStaticsMTs));
9483 if (numColdGCStaticsMTs > 0)
9485 image->FixupPointerField(this, offsetof(ModuleCtorInfo, ppColdGCStaticsMTs));
9487 image->BeginRegion(CORINFO_REGION_COLD);
9488 for (DWORD i=0; i < numColdGCStaticsMTs; i++)
9490 image->FixupMethodTablePointer(ppColdGCStaticsMTs, &ppColdGCStaticsMTs[i]);
9492 image->EndRegion(CORINFO_REGION_COLD);
9496 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, ppColdGCStaticsMTs));
9501 #pragma warning(push)
9502 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
9504 void Module::Fixup(DataImage *image)
9506 STANDARD_VM_CONTRACT;
9508 // Propagate all changes to the image copy
9509 memcpy(image->GetImagePointer(this), (void*)this, sizeof(Module));
9515 image->ZeroPointerField(this, 0);
9517 image->FixupPointerField(this, offsetof(Module, m_pNGenLayoutInfo));
9519 image->ZeroField(this, offsetof(Module, m_pSimpleName), sizeof(m_pSimpleName));
9521 image->ZeroField(this, offsetof(Module, m_file), sizeof(m_file));
9523 image->FixupPointerField(this, offsetof(Module, m_pDllMain));
9525 image->ZeroField(this, offsetof(Module, m_dwTransientFlags), sizeof(m_dwTransientFlags));
9527 image->ZeroField(this, offsetof(Module, m_pVASigCookieBlock), sizeof(m_pVASigCookieBlock));
9528 image->ZeroField(this, offsetof(Module, m_pAssembly), sizeof(m_pAssembly));
9529 image->ZeroField(this, offsetof(Module, m_moduleRef), sizeof(m_moduleRef));
9531 image->ZeroField(this, offsetof(Module, m_Crst), sizeof(m_Crst));
9532 image->ZeroField(this, offsetof(Module, m_FixupCrst), sizeof(m_FixupCrst));
9534 image->ZeroField(this, offsetof(Module, m_pProfilingBlobTable), sizeof(m_pProfilingBlobTable));
9535 image->ZeroField(this, offsetof(Module, m_pProfileData), sizeof(m_pProfileData));
9537 image->ZeroPointerField(this, offsetof(Module, m_pNgenStats));
9539 // fixup the pointer for NeutralResourcesLanguage, if we have it cached
9540 if(!!(m_dwPersistedFlags & NEUTRAL_RESOURCES_LANGUAGE_IS_CACHED)) {
9541 image->FixupPointerField(this, offsetof(Module, m_pszCultureName));
9544 // Fixup the property name set
9545 image->FixupPointerField(this, offsetof(Module, m_propertyNameSet));
9548 // Fixup the method table
9551 image->ZeroField(this, offsetof(Module, m_pISymUnmanagedReader), sizeof(m_pISymUnmanagedReader));
9552 image->ZeroField(this, offsetof(Module, m_ISymUnmanagedReaderCrst), sizeof(m_ISymUnmanagedReaderCrst));
9554 // Clear active dependencies - they will be refilled at load time
9555 image->ZeroField(this, offsetof(Module, m_activeDependencies), sizeof(m_activeDependencies));
9556 new (image->GetImagePointer(this, offsetof(Module, m_unconditionalDependencies))) SynchronizedBitMask();
9557 image->ZeroField(this, offsetof(Module, m_unconditionalDependencies) + offsetof(SynchronizedBitMask, m_bitMaskLock) + offsetof(SimpleRWLock,m_spinCount), sizeof(m_unconditionalDependencies.m_bitMaskLock.m_spinCount));
9558 image->ZeroField(this, offsetof(Module, m_dwNumberOfActivations), sizeof(m_dwNumberOfActivations));
9560 image->ZeroField(this, offsetof(Module, m_LookupTableCrst), sizeof(m_LookupTableCrst));
9562 m_TypeDefToMethodTableMap.Fixup(image);
9563 m_TypeRefToMethodTableMap.Fixup(image, FALSE);
9564 m_MethodDefToDescMap.Fixup(image);
9565 m_FieldDefToDescMap.Fixup(image);
9566 if(m_pMemberRefToDescHashTable != NULL)
9568 image->FixupPointerField(this, offsetof(Module, m_pMemberRefToDescHashTable));
9569 m_pMemberRefToDescHashTable->Fixup(image);
9571 m_GenericParamToDescMap.Fixup(image);
9572 m_GenericTypeDefToCanonMethodTableMap.Fixup(image);
9573 m_FileReferencesMap.Fixup(image, FALSE);
9574 m_ManifestModuleReferencesMap.Fixup(image, FALSE);
9575 m_MethodDefToPropertyInfoMap.Fixup(image, FALSE);
9577 image->ZeroPointerField(this, offsetof(Module, m_pILStubCache));
9579 if (m_pAvailableClasses != NULL) {
9580 image->FixupPointerField(this, offsetof(Module, m_pAvailableClasses));
9581 m_pAvailableClasses->Fixup(image);
9584 image->ZeroField(this, offsetof(Module, m_pAvailableClassesCaseIns), sizeof(m_pAvailableClassesCaseIns));
9585 image->ZeroField(this, offsetof(Module, m_InstMethodHashTableCrst), sizeof(m_InstMethodHashTableCrst));
9587 image->BeginRegion(CORINFO_REGION_COLD);
9589 if (m_pAvailableParamTypes) {
9590 image->FixupPointerField(this, offsetof(Module, m_pAvailableParamTypes));
9591 m_pAvailableParamTypes->Fixup(image);
9594 if (m_pInstMethodHashTable) {
9595 image->FixupPointerField(this, offsetof(Module, m_pInstMethodHashTable));
9596 m_pInstMethodHashTable->Fixup(image);
9600 MethodTable * pStubMT = GetILStubCache()->GetStubMethodTable();
9601 if (pStubMT != NULL)
9602 pStubMT->Fixup(image);
9605 if (m_pStubMethodHashTable) {
9606 image->FixupPointerField(this, offsetof(Module, m_pStubMethodHashTable));
9607 m_pStubMethodHashTable->Fixup(image);
9610 #ifdef FEATURE_COMINTEROP
9611 if (m_pGuidToTypeHash) {
9612 image->FixupPointerField(this, offsetof(Module, m_pGuidToTypeHash));
9613 m_pGuidToTypeHash->Fixup(image);
9615 #endif // FEATURE_COMINTEROP
9617 image->EndRegion(CORINFO_REGION_COLD);
9621 // Unseal the generic tables:
9623 // - We need to run managed code to serialize the Security attributes of the ngen image
9624 // and we are now using generic types in the Security/Reflection code.
9625 // - Compilation of other modules of multimodule assemblies may add more types
9626 // to the generic tables.
9628 UnsealGenericTypesAndMethods();
9631 m_ModuleCtorInfo.Fixup(image);
9637 if (m_pBinder != NULL)
9639 image->FixupPointerField(this, offsetof(Module, m_pBinder));
9640 m_pBinder->Fixup(image);
9649 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
9651 image->BeginRegion(CORINFO_REGION_COLD);
9652 while (typeDefIter.Next())
9654 MethodTable * t = typeDefIter.GetElement();
9655 if (image->IsStored(t))
9658 image->EndRegion(CORINFO_REGION_COLD);
9662 LookupMap<PTR_TypeRef>::Iterator typeRefIter(&m_TypeRefToMethodTableMap);
9665 image->BeginRegion(CORINFO_REGION_HOT);
9666 while (typeRefIter.Next())
9669 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(typeRefIter.GetElementAndFlags(&flags)));
9673 if (th.GetLoaderModule() != this || image->IsStored(th.AsPtr()))
9675 PTR_TADDR hotItemValuePtr = m_TypeRefToMethodTableMap.FindHotItemValuePtr(rid);
9678 if (image->CanEagerBindToTypeHandle(th))
9680 if (image->CanHardBindToZapModule(th.GetLoaderModule()))
9682 PVOID pTarget = th.IsTypeDesc() ? th.AsTypeDesc() : th.AsPtr();
9683 SSIZE_T offset = th.IsTypeDesc() ? 2 : 0;
9685 _ASSERTE((flags & offset) == 0);
9687 image->FixupField(m_TypeRefToMethodTableMap.pTable, rid * sizeof(TADDR),
9688 pTarget, flags | offset, IMAGE_REL_BASED_RelativePointer);
9690 // In case this item is also in the hot item subtable, fix it up there as well
9691 if (hotItemValuePtr != NULL)
9693 image->FixupField(m_TypeRefToMethodTableMap.hotItemList,
9694 (BYTE *)hotItemValuePtr - (BYTE *)m_TypeRefToMethodTableMap.hotItemList,
9695 pTarget, flags | offset, IMAGE_REL_BASED_RelativePointer);
9700 // Create the indirection only if the entry is hot or we do have indirection cell already
9701 if (hotItemValuePtr != NULL || image->GetExistingTypeHandleImport(th) != NULL)
9703 _ASSERTE((flags & FIXUP_POINTER_INDIRECTION) == 0);
9705 ZapNode * pImport = image->GetTypeHandleImport(th);
9706 image->FixupFieldToNode(m_TypeRefToMethodTableMap.pTable, rid * sizeof(TADDR),
9707 pImport, flags | FIXUP_POINTER_INDIRECTION, IMAGE_REL_BASED_RelativePointer);
9708 if (hotItemValuePtr != NULL)
9710 image->FixupFieldToNode(m_TypeRefToMethodTableMap.hotItemList,
9711 (BYTE *)hotItemValuePtr - (BYTE *)m_TypeRefToMethodTableMap.hotItemList,
9712 pImport, flags | FIXUP_POINTER_INDIRECTION, IMAGE_REL_BASED_RelativePointer);
9720 image->ZeroPointerField(m_TypeRefToMethodTableMap.pTable, rid * sizeof(TADDR));
9721 // In case this item is also in the hot item subtable, fix it up there as well
9722 if (hotItemValuePtr != NULL)
9724 image->ZeroPointerField(m_TypeRefToMethodTableMap.hotItemList,
9725 (BYTE *)hotItemValuePtr - (BYTE *)m_TypeRefToMethodTableMap.hotItemList);
9733 image->EndRegion(CORINFO_REGION_HOT);
9737 LookupMap<PTR_TypeVarTypeDesc>::Iterator genericParamIter(&m_GenericParamToDescMap);
9739 while (genericParamIter.Next())
9741 TypeVarTypeDesc * pTypeDesc = genericParamIter.GetElement();
9743 if (pTypeDesc != NULL)
9745 _ASSERTE(image->IsStored(pTypeDesc));
9746 pTypeDesc->Fixup(image);
9752 // Fixup the assembly reference map table
9756 LookupMap<PTR_Module>::Iterator manifestModuleIter(&m_ManifestModuleReferencesMap);
9759 while (manifestModuleIter.Next())
9762 Module * pModule = manifestModuleIter.GetElementAndFlags(&flags);
9764 if (pModule != NULL)
9766 if (image->CanEagerBindToModule(pModule))
9768 if (image->CanHardBindToZapModule(pModule))
9770 image->FixupField(m_ManifestModuleReferencesMap.pTable, rid * sizeof(TADDR),
9771 pModule, flags, IMAGE_REL_BASED_RelativePointer);
9775 image->ZeroPointerField(m_ManifestModuleReferencesMap.pTable, rid * sizeof(TADDR));
9780 image->ZeroPointerField(m_ManifestModuleReferencesMap.pTable, rid * sizeof(TADDR));
9789 // Zero out file references table.
9791 image->ZeroField(m_FileReferencesMap.pTable, 0,
9792 m_FileReferencesMap.GetSize() * sizeof(void*));
9795 image->ZeroField(this, offsetof(Module, m_debuggerSpecificData), sizeof(m_debuggerSpecificData));
9797 image->ZeroField(this, offsetof(Module, m_AssemblyRefByNameCount), sizeof(m_AssemblyRefByNameCount));
9798 image->ZeroPointerField(this, offsetof(Module, m_AssemblyRefByNameTable));
9800 image->ZeroPointerField(this,offsetof(Module, m_NativeMetadataAssemblyRefMap));
9805 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: fixing up module static data\n"));
9807 image->ZeroPointerField(this, offsetof(Module, m_ModuleID));
9808 image->ZeroField(this, offsetof(Module, m_ModuleIndex), sizeof(m_ModuleIndex));
9810 image->FixupPointerField(this, offsetof(Module, m_pDynamicStaticsInfo));
9812 DynamicStaticsInfo* pDSI = m_pDynamicStaticsInfo;
9813 for (DWORD i = 0; i < m_cDynamicEntries; i++, pDSI++)
9815 if (pDSI->pEnclosingMT->GetLoaderModule() == this &&
9816 // CEEPreloader::TriageTypeForZap() could have rejected this type
9817 image->IsStored(pDSI->pEnclosingMT))
9819 image->FixupPointerField(m_pDynamicStaticsInfo, (BYTE *)&pDSI->pEnclosingMT - (BYTE *)m_pDynamicStaticsInfo);
9823 // Some other (mutually-recursive) dependency must have loaded
9824 // a generic instantiation whose static were pumped into the
9825 // assembly being ngenned.
9826 image->ZeroPointerField(m_pDynamicStaticsInfo, (BYTE *)&pDSI->pEnclosingMT - (BYTE *)m_pDynamicStaticsInfo);
9830 // If we failed to load some types we need to reset the pointers to the static offset tables so they'll be
9831 // rebuilt at runtime.
9832 if (m_pRegularStaticOffsets != (PTR_DWORD)NGEN_STATICS_ALLCLASSES_WERE_LOADED)
9834 _ASSERTE(m_pThreadStaticOffsets != (PTR_DWORD)NGEN_STATICS_ALLCLASSES_WERE_LOADED);
9835 image->ZeroPointerField(this, offsetof(Module, m_pRegularStaticOffsets));
9836 image->ZeroPointerField(this, offsetof(Module, m_pThreadStaticOffsets));
9839 // Fix up inlining data
9840 if(m_pPersistentInlineTrackingMapNGen)
9842 image->FixupPointerField(this, offsetof(Module, m_pPersistentInlineTrackingMapNGen));
9843 m_pPersistentInlineTrackingMapNGen->Fixup(image);
9847 image->ZeroPointerField(this, offsetof(Module, m_pPersistentInlineTrackingMapNGen));
9853 #pragma warning(pop)
9856 #endif // FEATURE_NATIVE_IMAGE_GENERATION
9858 #ifdef FEATURE_PREJIT
9860 // Is "address" a data-structure in the native image?
9863 BOOL Module::IsPersistedObject(void *address)
9875 if (!HasNativeImage())
9878 PEImageLayout *pLayout = GetNativeImage();
9879 _ASSERTE(pLayout->IsMapped());
9881 return (address >= pLayout->GetBase()
9882 && address < (BYTE*)pLayout->GetBase() + pLayout->GetVirtualSize());
9885 Module *Module::GetModuleFromIndex(DWORD ix)
9893 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9897 if (HasNativeImage())
9899 PRECONDITION(GetNativeImage()->CheckNativeImportFromIndex(ix));
9900 CORCOMPILE_IMPORT_TABLE_ENTRY *p = GetNativeImage()->GetNativeImportFromIndex(ix);
9901 RETURN ZapSig::DecodeModuleFromIndexes(this, p->wAssemblyRid, p->wModuleRid);
9905 mdAssemblyRef mdAssemblyRefToken = TokenFromRid(ix, mdtAssemblyRef);
9906 Assembly *pAssembly = this->LookupAssemblyRef(mdAssemblyRefToken);
9909 RETURN pAssembly->GetManifestModule();
9913 // GetModuleFromIndex failed
9918 #endif // FEATURE_PREJIT
9920 #endif // !DACCESS_COMPILE
9922 #ifdef FEATURE_PREJIT
9924 Module *Module::GetModuleFromIndexIfLoaded(DWORD ix)
9932 PRECONDITION(HasNativeImage());
9933 PRECONDITION(GetNativeImage()->CheckNativeImportFromIndex(ix));
9934 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9938 #ifndef DACCESS_COMPILE
9939 CORCOMPILE_IMPORT_TABLE_ENTRY *p = GetNativeImage()->GetNativeImportFromIndex(ix);
9941 RETURN ZapSig::DecodeModuleFromIndexesIfLoaded(this, p->wAssemblyRid, p->wModuleRid);
9942 #else // DACCESS_COMPILE
9945 #endif // DACCESS_COMPILE
9948 #ifndef DACCESS_COMPILE
9950 BYTE *Module::GetNativeFixupBlobData(RVA rva)
9959 POSTCONDITION(CheckPointer(RETVAL));
9963 RETURN (BYTE *) GetNativeOrReadyToRunImage()->GetRvaData(rva);
9966 IMDInternalImport *Module::GetNativeAssemblyImport(BOOL loadAllowed)
9968 CONTRACT(IMDInternalImport *)
9971 if (loadAllowed) GC_TRIGGERS; else GC_NOTRIGGER;
9972 if (loadAllowed) THROWS; else NOTHROW;
9973 if (loadAllowed) INJECT_FAULT(COMPlusThrowOM()); else FORBID_FAULT;
9975 PRECONDITION(HasNativeImage());
9976 POSTCONDITION(CheckPointer(RETVAL));
9980 RETURN GetFile()->GetPersistentNativeImage()->GetNativeMDImport(loadAllowed);
9985 void Module::RestoreMethodTablePointerRaw(MethodTable ** ppMT,
9986 Module *pContainingModule,
9987 ClassLoadLevel level)
9997 // Ensure that the compiler won't fetch the value twice
9998 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppMT);
10001 if (pContainingModule != NULL)
10003 Module * dbg_pZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMT));
10004 _ASSERTE((dbg_pZapModule == NULL) || (pContainingModule == dbg_pZapModule));
10008 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10011 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10014 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10016 if (pContainingModule == NULL)
10017 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMT));
10018 PREFIX_ASSUME(pContainingModule != NULL);
10020 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_TYPE_HANDLE);
10022 Module * pInfoModule;
10023 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
10025 TypeHandle th = ZapSig::DecodeType(pContainingModule,
10029 *EnsureWritablePages(ppMT) = th.AsMethodTable();
10033 ClassLoader::EnsureLoaded(*ppMT, level);
10038 void Module::RestoreMethodTablePointer(FixupPointer<PTR_MethodTable> * ppMT,
10039 Module *pContainingModule,
10040 ClassLoadLevel level)
10050 if (ppMT->IsNull())
10053 if (ppMT->IsTagged())
10055 RestoreMethodTablePointerRaw(ppMT->GetValuePtr(), pContainingModule, level);
10059 ClassLoader::EnsureLoaded(ppMT->GetValue(), level);
10064 void Module::RestoreMethodTablePointer(RelativeFixupPointer<PTR_MethodTable> * ppMT,
10065 Module *pContainingModule,
10066 ClassLoadLevel level)
10076 if (ppMT->IsNull())
10079 if (ppMT->IsTagged((TADDR)ppMT))
10081 RestoreMethodTablePointerRaw(ppMT->GetValuePtr(), pContainingModule, level);
10085 ClassLoader::EnsureLoaded(ppMT->GetValue(), level);
10089 #endif // !DACCESS_COMPILE
10091 BOOL Module::IsZappedCode(PCODE code)
10102 if (!HasNativeImage())
10105 PEImageLayout *pNativeImage = GetNativeImage();
10108 PCODE pCodeSection;
10110 pCodeSection = pNativeImage->GetNativeHotCode(&cCode);
10111 if ((pCodeSection <= code) && (code < pCodeSection + cCode))
10116 pCodeSection = pNativeImage->GetNativeCode(&cCode);
10117 if ((pCodeSection <= code) && (code < pCodeSection + cCode))
10125 BOOL Module::IsZappedPrecode(PCODE code)
10136 if (m_pNGenLayoutInfo == NULL)
10139 for (SIZE_T i = 0; i < COUNTOF(m_pNGenLayoutInfo->m_Precodes); i++)
10141 if (m_pNGenLayoutInfo->m_Precodes[i].IsInRange(code))
10148 PCCOR_SIGNATURE Module::GetEncodedSig(RVA fixupRva, Module **ppDefiningModule)
10150 CONTRACT(PCCOR_SIGNATURE)
10157 POSTCONDITION(CheckPointer(RETVAL));
10162 #ifndef DACCESS_COMPILE
10163 PCCOR_SIGNATURE pBuffer = GetNativeFixupBlobData(fixupRva);
10165 BYTE kind = *pBuffer++;
10167 *ppDefiningModule = (kind & ENCODE_MODULE_OVERRIDE) ? GetModuleFromIndex(CorSigUncompressData(pBuffer)) : this;
10172 #endif // DACCESS_COMPILE
10175 PCCOR_SIGNATURE Module::GetEncodedSigIfLoaded(RVA fixupRva, Module **ppDefiningModule)
10177 CONTRACT(PCCOR_SIGNATURE)
10184 POSTCONDITION(CheckPointer(RETVAL));
10189 #ifndef DACCESS_COMPILE
10190 PCCOR_SIGNATURE pBuffer = GetNativeFixupBlobData(fixupRva);
10192 BYTE kind = *pBuffer++;
10194 *ppDefiningModule = (kind & ENCODE_MODULE_OVERRIDE) ? GetModuleFromIndexIfLoaded(CorSigUncompressData(pBuffer)) : this;
10198 *ppDefiningModule = NULL;
10200 #endif // DACCESS_COMPILE
10204 PTR_Module Module::RestoreModulePointerIfLoaded(DPTR(RelativeFixupPointer<PTR_Module>) ppModule, Module *pContainingModule)
10216 if (!ppModule->IsTagged(dac_cast<TADDR>(ppModule)))
10217 return ppModule->GetValue(dac_cast<TADDR>(ppModule));
10219 #ifndef DACCESS_COMPILE
10220 PTR_Module * ppValue = ppModule->GetValuePtr();
10222 // Ensure that the compiler won't fetch the value twice
10223 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppValue);
10225 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10229 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10232 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10234 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_MODULE_HANDLE);
10236 Module * pInfoModule;
10237 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSigIfLoaded(fixupRva, &pInfoModule);
10241 if (EnsureWritablePagesNoThrow(ppValue, sizeof(*ppValue)))
10242 *ppValue = pInfoModule;
10244 return pInfoModule;
10248 return PTR_Module(fixup);
10256 #ifndef DACCESS_COMPILE
10259 void Module::RestoreModulePointer(RelativeFixupPointer<PTR_Module> * ppModule, Module *pContainingModule)
10266 INJECT_FAULT(COMPlusThrowOM());
10270 if (!ppModule->IsTagged((TADDR)ppModule))
10273 PTR_Module * ppValue = ppModule->GetValuePtr();
10275 // Ensure that the compiler won't fetch the value twice
10276 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppValue);
10278 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10281 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10284 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10286 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_MODULE_HANDLE);
10288 Module * pInfoModule;
10289 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
10291 *EnsureWritablePages(ppValue) = pInfoModule;
10296 void Module::RestoreTypeHandlePointerRaw(TypeHandle *pHandle, Module* pContainingModule, ClassLoadLevel level)
10300 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
10301 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
10302 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else {INJECT_FAULT(COMPlusThrowOM(););}
10308 if (pContainingModule != NULL)
10310 Module * dbg_pZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(pHandle));
10311 _ASSERTE((dbg_pZapModule == NULL) || (pContainingModule == dbg_pZapModule));
10317 if (IS_ALIGNED(pHandle, sizeof(TypeHandle)))
10319 // Ensure that the compiler won't fetch the value twice
10320 fixup = VolatileLoadWithoutBarrier((TADDR *)pHandle);
10324 // This is necessary to handle in-place fixups (see by FixupTypeHandlePointerInplace)
10325 // in stubs-as-il signatures.
10328 // protect this unaligned read with the Module Crst for the rare case that
10329 // the TypeHandle to fixup is in a signature and unaligned.
10331 if (NULL == pContainingModule)
10333 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(pHandle));
10335 CrstHolder ch(&pContainingModule->m_Crst);
10336 fixup = *(TADDR UNALIGNED *)pHandle;
10339 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10342 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10345 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10347 if (NULL == pContainingModule)
10349 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(pHandle));
10351 PREFIX_ASSUME(pContainingModule != NULL);
10353 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_TYPE_HANDLE);
10355 Module * pInfoModule;
10356 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
10358 TypeHandle thResolved = ZapSig::DecodeType(pContainingModule,
10362 EnsureWritablePages(pHandle);
10363 if (IS_ALIGNED(pHandle, sizeof(TypeHandle)))
10365 *pHandle = thResolved;
10370 // protect this unaligned write with the Module Crst for the rare case that
10371 // the TypeHandle to fixup is in a signature and unaligned.
10373 CrstHolder ch(&pContainingModule->m_Crst);
10374 *(TypeHandle UNALIGNED *)pHandle = thResolved;
10377 else if (fixup != NULL)
10379 ClassLoader::EnsureLoaded(TypeHandle::FromTAddr(fixup), level);
10384 void Module::RestoreTypeHandlePointer(FixupPointer<TypeHandle> * pHandle,
10385 Module *pContainingModule,
10386 ClassLoadLevel level)
10396 if (pHandle->IsNull())
10399 if (pHandle->IsTagged())
10401 RestoreTypeHandlePointerRaw(pHandle->GetValuePtr(), pContainingModule, level);
10405 ClassLoader::EnsureLoaded(pHandle->GetValue(), level);
10410 void Module::RestoreTypeHandlePointer(RelativeFixupPointer<TypeHandle> * pHandle,
10411 Module *pContainingModule,
10412 ClassLoadLevel level)
10422 if (pHandle->IsNull())
10425 if (pHandle->IsTagged((TADDR)pHandle))
10427 RestoreTypeHandlePointerRaw(pHandle->GetValuePtr(), pContainingModule, level);
10431 ClassLoader::EnsureLoaded(pHandle->GetValue((TADDR)pHandle), level);
10436 void Module::RestoreMethodDescPointerRaw(PTR_MethodDesc * ppMD, Module *pContainingModule, ClassLoadLevel level)
10446 // Ensure that the compiler won't fetch the value twice
10447 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppMD);
10450 if (pContainingModule != NULL)
10452 Module * dbg_pZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMD));
10453 _ASSERTE((dbg_pZapModule == NULL) || (pContainingModule == dbg_pZapModule));
10457 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10462 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10465 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10467 if (pContainingModule == NULL)
10468 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMD));
10469 PREFIX_ASSUME(pContainingModule != NULL);
10471 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_METHOD_HANDLE);
10473 Module * pInfoModule;
10474 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
10476 *EnsureWritablePages(ppMD) = ZapSig::DecodeMethod(pContainingModule,
10481 (*ppMD)->CheckRestore(level);
10486 void Module::RestoreMethodDescPointer(FixupPointer<PTR_MethodDesc> * ppMD,
10487 Module *pContainingModule,
10488 ClassLoadLevel level)
10498 if (ppMD->IsNull())
10501 if (ppMD->IsTagged())
10503 RestoreMethodDescPointerRaw(ppMD->GetValuePtr(), pContainingModule, level);
10507 ppMD->GetValue()->CheckRestore(level);
10512 void Module::RestoreMethodDescPointer(RelativeFixupPointer<PTR_MethodDesc> * ppMD,
10513 Module *pContainingModule,
10514 ClassLoadLevel level)
10524 if (ppMD->IsNull())
10527 if (ppMD->IsTagged((TADDR)ppMD))
10529 RestoreMethodDescPointerRaw(ppMD->GetValuePtr(), pContainingModule, level);
10533 ppMD->GetValue((TADDR)ppMD)->CheckRestore(level);
10538 void Module::RestoreFieldDescPointer(RelativeFixupPointer<PTR_FieldDesc> * ppFD)
10548 if (!ppFD->IsTagged())
10551 PTR_FieldDesc * ppValue = ppFD->GetValuePtr();
10553 // Ensure that the compiler won't fetch the value twice
10554 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppValue);
10556 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10559 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10562 Module * pContainingModule = ExecutionManager::FindZapModule((TADDR)ppValue);
10563 PREFIX_ASSUME(pContainingModule != NULL);
10565 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10567 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_FIELD_HANDLE);
10569 Module * pInfoModule;
10570 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
10572 *EnsureWritablePages(ppValue) = ZapSig::DecodeField(pContainingModule,
10579 //-----------------------------------------------------------------------------
10583 This diagram illustrates the layout of fixups in the ngen image.
10584 This is the case where function foo2 has a class-restore fixup
10585 for class C1 in b.dll.
10587 zapBase+curTableVA+rva / FixupList (see Fixup Encoding below)
10589 +-------------------+
10590 pEntry->VA +--------------------+ | non-NULL | foo1
10591 |Handles | +-------------------+
10592 ZapHeader.ImportTable | | | non-NULL |
10593 | | +-------------------+
10594 +------------+ +--------------------+ | non-NULL |
10595 |a.dll | |Class cctors |<---+ +-------------------+
10597 | | p->VA/ | |<---+ \ +===================+
10598 | | blobs +--------------------+ \ +-------non-NULL | foo2
10599 +------------+ |Class restore | \ +-------------------+
10600 |b.dll | | | +-------non-NULL |
10601 | | | | +-------------------+
10602 | token_C1 |<--------------blob(=>fixedUp/0) |<--pBlob--------index |
10603 | | \ | | +-------------------+
10604 | | \ +--------------------+ | non-NULL |
10605 | | \ | | +-------------------+
10607 | | \ | . | +===================+
10608 +------------+ \ | . | | 0 | foo3
10609 \ | | +===================+
10610 \ +--------------------+ | non-NULL | foo4
10611 \ |Various fixups that | +-------------------+
10612 \ |need too happen | | 0 |
10613 \| | +===================+
10614 |(CorCompileTokenTable)
10616 pEntryEnd->VA +--------------------+
10622 //-----------------------------------------------------------------------------
10624 BOOL Module::FixupNativeEntry(CORCOMPILE_IMPORT_SECTION * pSection, SIZE_T fixupIndex, SIZE_T *fixupCell)
10629 PRECONDITION(CheckPointer(fixupCell));
10633 // Ensure that the compiler won't fetch the value twice
10634 SIZE_T fixup = VolatileLoadWithoutBarrier(fixupCell);
10636 if (pSection->Signatures != NULL)
10640 PTR_DWORD pSignatures = dac_cast<PTR_DWORD>(GetNativeOrReadyToRunImage()->GetRvaData(pSection->Signatures));
10642 if (!LoadDynamicInfoEntry(this, pSignatures[fixupIndex], fixupCell))
10645 _ASSERTE(*fixupCell != NULL);
10650 if (CORCOMPILE_IS_FIXUP_TAGGED(fixup, pSection))
10652 // Fixup has not been fixed up yet
10653 if (!LoadDynamicInfoEntry(this, (RVA)CORCOMPILE_UNTAG_TOKEN(fixup), fixupCell))
10656 _ASSERTE(!CORCOMPILE_IS_FIXUP_TAGGED(*fixupCell, pSection));
10661 // Handle tables are special. We may need to restore static handle or previous
10662 // attempts to load handle could have been partial.
10664 if (pSection->Type == CORCOMPILE_IMPORT_TYPE_TYPE_HANDLE)
10666 TypeHandle::FromPtr((void *)fixup).CheckRestore();
10669 if (pSection->Type == CORCOMPILE_IMPORT_TYPE_METHOD_HANDLE)
10671 ((MethodDesc *)(fixup))->CheckRestore();
10679 //-----------------------------------------------------------------------------
10681 void Module::RunEagerFixups()
10683 STANDARD_VM_CONTRACT;
10686 PTR_CORCOMPILE_IMPORT_SECTION pSections = GetImportSections(&nSections);
10688 if (nSections == 0)
10692 // Loading types during eager fixup is not a tested scenario. Make bugs out of any attempts to do so in a
10693 // debug build. Use holder to recover properly in case of exception.
10694 class ForbidTypeLoadHolder
10697 ForbidTypeLoadHolder()
10699 BEGIN_FORBID_TYPELOAD();
10702 ~ForbidTypeLoadHolder()
10704 END_FORBID_TYPELOAD();
10710 // TODO: Verify that eager fixup dependency graphs can contain no cycles
10711 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
10713 PEImageLayout *pNativeImage = GetNativeOrReadyToRunImage();
10715 for (COUNT_T iSection = 0; iSection < nSections; iSection++)
10717 PTR_CORCOMPILE_IMPORT_SECTION pSection = pSections + iSection;
10719 if ((pSection->Flags & CORCOMPILE_IMPORT_FLAGS_EAGER) == 0)
10723 TADDR tableBase = pNativeImage->GetDirectoryData(&pSection->Section, &tableSize);
10725 if (pSection->Signatures != NULL)
10727 PTR_DWORD pSignatures = dac_cast<PTR_DWORD>(pNativeImage->GetRvaData(pSection->Signatures));
10729 for (SIZE_T * fixupCell = (SIZE_T *)tableBase; fixupCell < (SIZE_T *)(tableBase + tableSize); fixupCell++)
10731 SIZE_T fixupIndex = fixupCell - (SIZE_T *)tableBase;
10732 if (!LoadDynamicInfoEntry(this, pSignatures[fixupIndex], fixupCell))
10734 _ASSERTE(!"LoadDynamicInfoEntry failed");
10735 ThrowHR(COR_E_BADIMAGEFORMAT);
10737 _ASSERTE(*fixupCell != NULL);
10742 for (SIZE_T * fixupCell = (SIZE_T *)tableBase; fixupCell < (SIZE_T *)(tableBase + tableSize); fixupCell++)
10744 // Ensure that the compiler won't fetch the value twice
10745 SIZE_T fixup = VolatileLoadWithoutBarrier(fixupCell);
10747 // This method may execute multiple times in multi-domain scenarios. Check that the fixup has not been
10749 if (CORCOMPILE_IS_FIXUP_TAGGED(fixup, pSection))
10751 if (!LoadDynamicInfoEntry(this, (RVA)CORCOMPILE_UNTAG_TOKEN(fixup), fixupCell))
10753 _ASSERTE(!"LoadDynamicInfoEntry failed");
10754 ThrowHR(COR_E_BADIMAGEFORMAT);
10756 _ASSERTE(!CORCOMPILE_IS_FIXUP_TAGGED(*fixupCell, pSection));
10763 void Module::LoadTokenTables()
10771 PRECONDITION(HasNativeImage());
10775 #ifndef CROSSGEN_COMPILE
10776 if (NingenEnabled())
10779 CORCOMPILE_EE_INFO_TABLE *pEEInfo = GetNativeImage()->GetNativeEEInfoTable();
10780 PREFIX_ASSUME(pEEInfo != NULL);
10782 pEEInfo->inlinedCallFrameVptr = InlinedCallFrame::GetMethodFrameVPtr();
10783 pEEInfo->addrOfCaptureThreadGlobal = (LONG *)&g_TrapReturningThreads;
10785 //CoreClr doesn't always have the debugger loaded
10786 //patch up the ngen image to point to this address so that the JIT bypasses JMC if there is no debugger
10787 static DWORD g_dummyJMCFlag = 0;
10788 pEEInfo->addrOfJMCFlag = g_pDebugInterface ? g_pDebugInterface->GetJMCFlagAddr(this) : &g_dummyJMCFlag;
10790 pEEInfo->gsCookie = GetProcessGSCookie();
10794 pEEInfo->emptyString = (CORINFO_Object **)StringObject::GetEmptyStringRefPtr();
10797 pEEInfo->threadTlsIndex = TLS_OUT_OF_INDEXES;
10798 pEEInfo->rvaStaticTlsIndex = NULL;
10799 #endif // CROSSGEN_COMPILE
10802 #endif // !DACCESS_COMPILE
10804 // Returns the RVA to the compressed debug information blob for the given method
10806 CORCOMPILE_DEBUG_ENTRY Module::GetMethodDebugInfoOffset(MethodDesc *pMD)
10808 CONTRACT(CORCOMPILE_DEBUG_ENTRY)
10811 PRECONDITION(HasNativeImage());
10812 PRECONDITION(CheckPointer(pMD) && pMD->IsPreImplemented());
10813 POSTCONDITION(GetNativeImage()->CheckRva(RETVAL, NULL_OK));
10821 if (!GetNativeImage()->HasNativeDebugMap() || pMD->IsRuntimeSupplied())
10825 PTR_CORCOMPILE_DEBUG_RID_ENTRY ridTable =
10826 dac_cast<PTR_CORCOMPILE_DEBUG_RID_ENTRY>(GetNativeImage()->GetNativeDebugMap(&size));
10828 COUNT_T count = size / sizeof(CORCOMPILE_DEBUG_RID_ENTRY);
10829 // The size should be odd for better hashing
10830 _ASSERTE((count & 1) != 0);
10832 CORCOMPILE_DEBUG_RID_ENTRY ridEntry = ridTable[GetDebugRidEntryHash(pMD->GetMemberDef()) % count];
10834 // Do we have multiple code corresponding to the same RID
10835 if (!IsMultipleLabelledEntries(ridEntry))
10840 PTR_CORCOMPILE_DEBUG_LABELLED_ENTRY pLabelledEntry =
10841 PTR_CORCOMPILE_DEBUG_LABELLED_ENTRY
10842 (GetNativeImage()->GetRvaData(ridEntry &
10843 ~CORCOMPILE_DEBUG_MULTIPLE_ENTRIES));
10845 DWORD codeRVA = GetNativeImage()->
10846 GetDataRva((const TADDR)pMD->GetNativeCode());
10847 #if defined(_TARGET_ARM_)
10848 // Since the Thumb Bit is set on ARM, the RVA calculated above will have it set as well
10849 // and will result in the failure of checks in the loop below. Hence, mask off the
10850 // bit before proceeding ahead.
10851 codeRVA = ThumbCodeToDataPointer<DWORD, DWORD>(codeRVA);
10852 #endif // _TARGET_ARM_
10856 if (pLabelledEntry->nativeCodeRVA == codeRVA)
10858 RETURN (pLabelledEntry->debugInfoOffset & ~CORCOMPILE_DEBUG_MULTIPLE_ENTRIES);
10861 if (!IsMultipleLabelledEntries(pLabelledEntry->debugInfoOffset))
10869 _ASSERTE(!"Debug info not found - corrupted ngen image?");
10873 PTR_BYTE Module::GetNativeDebugInfo(MethodDesc * pMD)
10878 PRECONDITION(HasNativeImage());
10879 PRECONDITION(CheckPointer(pMD));
10880 PRECONDITION(pMD->GetZapModule() == this);
10888 CORCOMPILE_DEBUG_ENTRY debugInfoOffset = GetMethodDebugInfoOffset(pMD);
10890 if (debugInfoOffset == 0)
10893 return dac_cast<PTR_BYTE>(GetNativeImage()->GetRvaData(debugInfoOffset));
10895 #endif //FEATURE_PREJIT
10899 #ifndef DACCESS_COMPILE
10901 #ifdef FEATURE_PREJIT
10903 // Profile data management
10906 ICorJitInfo::ProfileBuffer * Module::AllocateProfileBuffer(mdToken _token, DWORD _count, DWORD _ILSize)
10908 CONTRACT (ICorJitInfo::ProfileBuffer*)
10914 INJECT_FAULT(CONTRACT_RETURN NULL;);
10915 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
10919 assert(_ILSize != 0);
10921 DWORD listSize = sizeof(CORCOMPILE_METHOD_PROFILE_LIST);
10922 DWORD headerSize = sizeof(CORBBTPROF_METHOD_HEADER);
10923 DWORD blockSize = _count * sizeof(CORBBTPROF_BLOCK_DATA);
10924 DWORD totalSize = listSize + headerSize + blockSize;
10926 BYTE * memory = (BYTE *) (void *) this->m_pAssembly->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(totalSize));
10928 CORCOMPILE_METHOD_PROFILE_LIST * methodProfileList = (CORCOMPILE_METHOD_PROFILE_LIST *) (memory + 0);
10929 CORBBTPROF_METHOD_HEADER * methodProfileData = (CORBBTPROF_METHOD_HEADER *) (memory + listSize);
10931 // Note: Memory allocated on the LowFrequencyHeap is zero filled
10933 methodProfileData->size = headerSize + blockSize;
10934 methodProfileData->method.token = _token;
10935 methodProfileData->method.ILSize = _ILSize;
10936 methodProfileData->method.cBlock = _count;
10938 assert(methodProfileData->size == methodProfileData->Size());
10940 // Link it to the per module list of profile data buffers
10942 methodProfileList->next = m_methodProfileList;
10943 m_methodProfileList = methodProfileList;
10945 RETURN ((ICorJitInfo::ProfileBuffer *) &methodProfileData->method.block[0]);
10948 HANDLE Module::OpenMethodProfileDataLogFile(GUID mvid)
10959 HANDLE profileDataFile = INVALID_HANDLE_VALUE;
10962 LPCWSTR assemblyPath = m_file->GetPath();
10963 LPCWSTR ibcDir = g_pConfig->GetZapBBInstrDir(); // should we put the ibc data into a particular directory?
10965 path.Set(assemblyPath); // no, then put it beside the IL dll
10968 LPCWSTR assemblyFileName = wcsrchr(assemblyPath, '\\');
10969 if (assemblyFileName)
10970 assemblyFileName++; // skip past the \ char
10972 assemblyFileName = assemblyPath;
10974 path.Set(ibcDir); // yes, put it in the directory, named with the assembly name.
10976 path.Append(assemblyFileName);
10979 SString::Iterator ext = path.End(); // remove the extension
10980 if (path.FindBack(ext, '.'))
10981 path.Truncate(ext);
10982 path.Append(W(".ibc")); // replace with .ibc extension
10984 profileDataFile = WszCreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
10986 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
10989 if (profileDataFile == INVALID_HANDLE_VALUE) COMPlusThrowWin32();
10992 CORBBTPROF_FILE_HEADER fileHeader;
10994 SetFilePointer(profileDataFile, 0, NULL, FILE_BEGIN);
10995 BOOL result = ReadFile(profileDataFile, &fileHeader, sizeof(fileHeader), &count, NULL);
10997 (count == sizeof(fileHeader)) &&
10998 (fileHeader.HeaderSize == sizeof(CORBBTPROF_FILE_HEADER)) &&
10999 (fileHeader.Magic == CORBBTPROF_MAGIC) &&
11000 (fileHeader.Version == CORBBTPROF_CURRENT_VERSION) &&
11001 (fileHeader.MVID == mvid))
11004 // The existing file was from the same assembly version - just append to it.
11007 SetFilePointer(profileDataFile, 0, NULL, FILE_END);
11012 // Either this is a new file, or it's from a previous version. Replace the contents.
11015 SetFilePointer(profileDataFile, 0, NULL, FILE_BEGIN);
11018 return profileDataFile;
11021 // Note that this method cleans up the profile buffers, so it's crucial that
11022 // no managed code in the module is allowed to run once this method has
11028 SIZE_T getCurrentOffset() {WRAPPER_NO_CONTRACT; return buffer.Size();}
11030 void * getOffsetPtr(SIZE_T offset)
11032 LIMITED_METHOD_CONTRACT;
11033 _ASSERTE(offset <= buffer.Size());
11034 return ((void *) (((char *) buffer.Ptr()) + offset));
11037 void *Allocate(SIZE_T size)
11045 INJECT_FAULT(CONTRACT_RETURN NULL;);
11046 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
11050 SIZE_T oldSize = buffer.Size();
11051 buffer.ReSizeThrows(oldSize + size);
11052 RETURN getOffsetPtr(oldSize);
11056 CQuickBytes buffer;
11059 class ProfileEmitter
11065 LIMITED_METHOD_CONTRACT;
11066 pSectionList = NULL;
11071 WRAPPER_NO_CONTRACT;
11072 while (pSectionList)
11074 SectionList *temp = pSectionList->next;
11075 delete pSectionList;
11076 pSectionList = temp;
11080 ProfileMap *EmitNewSection(SectionFormat format)
11082 WRAPPER_NO_CONTRACT;
11083 SectionList *s = new SectionList();
11085 s->format = format;
11086 s->next = pSectionList;
11089 return &s->profileMap;
11093 // Serialize the profile sections into pMap
11096 void Serialize(ProfileMap *profileMap, GUID mvid)
11104 INJECT_FAULT(COMPlusThrowOM());
11109 // Allocate the file header
11112 CORBBTPROF_FILE_HEADER *fileHeader;
11113 fileHeader = (CORBBTPROF_FILE_HEADER *) profileMap->Allocate(sizeof(CORBBTPROF_FILE_HEADER));
11115 fileHeader->HeaderSize = sizeof(CORBBTPROF_FILE_HEADER);
11116 fileHeader->Magic = CORBBTPROF_MAGIC;
11117 fileHeader->Version = CORBBTPROF_CURRENT_VERSION;
11118 fileHeader->MVID = mvid;
11122 // Count the number of sections
11124 ULONG32 numSections = 0;
11125 for (SectionList *p = pSectionList; p; p = p->next)
11131 // Allocate the section table
11133 SIZE_T tableEntryOffset;
11135 CORBBTPROF_SECTION_TABLE_HEADER *tableHeader;
11136 tableHeader = (CORBBTPROF_SECTION_TABLE_HEADER *)
11137 profileMap->Allocate(sizeof(CORBBTPROF_SECTION_TABLE_HEADER));
11139 tableHeader->NumEntries = numSections;
11140 tableEntryOffset = profileMap->getCurrentOffset();
11142 CORBBTPROF_SECTION_TABLE_ENTRY *tableEntry;
11143 tableEntry = (CORBBTPROF_SECTION_TABLE_ENTRY *)
11144 profileMap->Allocate(sizeof(CORBBTPROF_SECTION_TABLE_ENTRY) * numSections);
11148 // Allocate the data sections
11151 ULONG secCount = 0;
11152 for (SectionList *pSec = pSectionList; pSec; pSec = pSec->next, secCount++)
11154 SIZE_T offset = profileMap->getCurrentOffset();
11155 assert((offset & 0x3) == 0);
11157 SIZE_T actualSize = pSec->profileMap.getCurrentOffset();
11158 SIZE_T alignUpSize = AlignUp(actualSize, sizeof(DWORD));
11160 profileMap->Allocate(alignUpSize);
11162 memcpy(profileMap->getOffsetPtr(offset), pSec->profileMap.getOffsetPtr(0), actualSize);
11163 if (alignUpSize > actualSize)
11165 memset(((BYTE*)profileMap->getOffsetPtr(offset))+actualSize, 0, (alignUpSize - actualSize));
11168 CORBBTPROF_SECTION_TABLE_ENTRY *tableEntry;
11169 tableEntry = (CORBBTPROF_SECTION_TABLE_ENTRY *) profileMap->getOffsetPtr(tableEntryOffset);
11170 tableEntry += secCount;
11171 tableEntry->FormatID = pSec->format;
11172 tableEntry->Data.Offset = offset;
11173 tableEntry->Data.Size = alignUpSize;
11178 // Allocate the end token marker
11182 endToken = (ULONG *) profileMap->Allocate(sizeof(ULONG));
11184 *endToken = CORBBTPROF_END_TOKEN;
11191 SectionFormat format;
11192 ProfileMap profileMap;
11195 SectionList * pSectionList;
11199 /*static*/ idTypeSpec TypeSpecBlobEntry::s_lastTypeSpecToken = idTypeSpecNil;
11200 /*static*/ idMethodSpec MethodSpecBlobEntry::s_lastMethodSpecToken = idMethodSpecNil;
11201 /*static*/ idExternalNamespace ExternalNamespaceBlobEntry::s_lastExternalNamespaceToken = idExternalNamespaceNil;
11202 /*static*/ idExternalType ExternalTypeBlobEntry::s_lastExternalTypeToken = idExternalTypeNil;
11203 /*static*/ idExternalSignature ExternalSignatureBlobEntry::s_lastExternalSignatureToken = idExternalSignatureNil;
11204 /*static*/ idExternalMethod ExternalMethodBlobEntry::s_lastExternalMethodToken = idExternalMethodNil;
11207 inline static size_t HashCombine(size_t h1, size_t h2)
11209 LIMITED_METHOD_CONTRACT;
11211 size_t result = (h1 * 129) ^ h2;
11215 bool TypeSpecBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11217 WRAPPER_NO_CONTRACT;
11219 if (this->kind() != other->kind())
11222 const TypeSpecBlobEntry * other2 = static_cast<const TypeSpecBlobEntry *>(other);
11224 if (this->cbSig() != other2->cbSig())
11227 PCCOR_SIGNATURE p1 = this->pSig();
11228 PCCOR_SIGNATURE p2 = other2->pSig();
11230 for (DWORD i=0; (i < this->cbSig()); i++)
11231 if (p1[i] != p2[i])
11237 size_t TypeSpecBlobEntry::Hash() const
11239 WRAPPER_NO_CONTRACT;
11241 size_t hashValue = HashInit();
11243 PCCOR_SIGNATURE p1 = pSig();
11244 for (DWORD i=0; (i < cbSig()); i++)
11245 hashValue = HashCombine(hashValue, p1[i]);
11250 TypeSpecBlobEntry::TypeSpecBlobEntry(DWORD _cbSig, PCCOR_SIGNATURE _pSig)
11256 PRECONDITION(_cbSig > 0);
11257 PRECONDITION(CheckPointer(_pSig));
11261 m_token = idTypeSpecNil;
11265 COR_SIGNATURE * pNewSig = (COR_SIGNATURE *) new (nothrow) BYTE[_cbSig];
11266 if (pNewSig != NULL)
11270 memcpy(pNewSig, _pSig, _cbSig);
11272 m_pSig = const_cast<PCCOR_SIGNATURE>(pNewSig);
11275 /* static */ const TypeSpecBlobEntry * TypeSpecBlobEntry::FindOrAdd(PTR_Module pModule,
11277 PCCOR_SIGNATURE _pSig)
11286 if ((_cbSig == 0) || (_pSig == NULL))
11289 TypeSpecBlobEntry sEntry(_cbSig, _pSig);
11291 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11292 if (pEntry == NULL)
11295 // Not Found, add a new type spec profiling blob entry
11297 TypeSpecBlobEntry * newEntry = new (nothrow) TypeSpecBlobEntry(_cbSig, _pSig);
11298 if (newEntry == NULL)
11301 newEntry->newToken(); // Assign a new ibc type spec token
11302 CONTRACT_VIOLATION(ThrowsViolation);
11303 pModule->GetProfilingBlobTable()->Add(newEntry);
11308 // Return the type spec entry that we found or the new one that we just created
11310 _ASSERTE(pEntry->kind() == ParamTypeSpec);
11311 return static_cast<const TypeSpecBlobEntry *>(pEntry);
11314 bool MethodSpecBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11316 WRAPPER_NO_CONTRACT;
11318 if (this->kind() != other->kind())
11321 const MethodSpecBlobEntry * other2 = static_cast<const MethodSpecBlobEntry *>(other);
11323 if (this->cbSig() != other2->cbSig())
11326 PCCOR_SIGNATURE p1 = this->pSig();
11327 PCCOR_SIGNATURE p2 = other2->pSig();
11329 for (DWORD i=0; (i < this->cbSig()); i++)
11330 if (p1[i] != p2[i])
11336 size_t MethodSpecBlobEntry::Hash() const
11338 WRAPPER_NO_CONTRACT;
11340 size_t hashValue = HashInit();
11342 PCCOR_SIGNATURE p1 = pSig();
11343 for (DWORD i=0; (i < cbSig()); i++)
11344 hashValue = HashCombine(hashValue, p1[i]);
11349 MethodSpecBlobEntry::MethodSpecBlobEntry(DWORD _cbSig, PCCOR_SIGNATURE _pSig)
11355 PRECONDITION(_cbSig > 0);
11356 PRECONDITION(CheckPointer(_pSig));
11360 m_token = idMethodSpecNil;
11364 COR_SIGNATURE * pNewSig = (COR_SIGNATURE *) new (nothrow) BYTE[_cbSig];
11365 if (pNewSig != NULL)
11369 memcpy(pNewSig, _pSig, _cbSig);
11371 m_pSig = const_cast<PCCOR_SIGNATURE>(pNewSig);
11374 /* static */ const MethodSpecBlobEntry * MethodSpecBlobEntry::FindOrAdd(PTR_Module pModule,
11376 PCCOR_SIGNATURE _pSig)
11385 if ((_cbSig == 0) || (_pSig == NULL))
11388 MethodSpecBlobEntry sEntry(_cbSig, _pSig);
11390 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11391 if (pEntry == NULL)
11394 // Not Found, add a new method spec profiling blob entry
11396 MethodSpecBlobEntry * newEntry = new (nothrow) MethodSpecBlobEntry(_cbSig, _pSig);
11397 if (newEntry == NULL)
11400 newEntry->newToken(); // Assign a new ibc method spec token
11401 CONTRACT_VIOLATION(ThrowsViolation);
11402 pModule->GetProfilingBlobTable()->Add(newEntry);
11407 // Return the method spec entry that we found or the new one that we just created
11409 _ASSERTE(pEntry->kind() == ParamMethodSpec);
11410 return static_cast<const MethodSpecBlobEntry *>(pEntry);
11413 bool ExternalNamespaceBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11415 WRAPPER_NO_CONTRACT;
11417 if (this->kind() != other->kind())
11420 const ExternalNamespaceBlobEntry * other2 = static_cast<const ExternalNamespaceBlobEntry *>(other);
11422 if (this->cbName() != other2->cbName())
11425 LPCSTR p1 = this->pName();
11426 LPCSTR p2 = other2->pName();
11428 for (DWORD i=0; (i < this->cbName()); i++)
11429 if (p1[i] != p2[i])
11435 size_t ExternalNamespaceBlobEntry::Hash() const
11437 WRAPPER_NO_CONTRACT;
11439 size_t hashValue = HashInit();
11441 LPCSTR p1 = pName();
11442 for (DWORD i=0; (i < cbName()); i++)
11443 hashValue = HashCombine(hashValue, p1[i]);
11448 ExternalNamespaceBlobEntry::ExternalNamespaceBlobEntry(LPCSTR _pName)
11454 PRECONDITION(CheckPointer(_pName));
11458 m_token = idExternalNamespaceNil;
11462 DWORD _cbName = (DWORD) strlen(_pName) + 1;
11463 LPSTR * pName = (LPSTR *) new (nothrow) CHAR[_cbName];
11466 m_cbName = _cbName;
11467 memcpy(pName, _pName, _cbName);
11468 m_pName = (LPCSTR) pName;
11472 /* static */ const ExternalNamespaceBlobEntry * ExternalNamespaceBlobEntry::FindOrAdd(PTR_Module pModule, LPCSTR _pName)
11481 if ((_pName == NULL) || (::strlen(_pName) == 0))
11484 ExternalNamespaceBlobEntry sEntry(_pName);
11486 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11487 if (pEntry == NULL)
11490 // Not Found, add a new external namespace blob entry
11492 ExternalNamespaceBlobEntry * newEntry = new (nothrow) ExternalNamespaceBlobEntry(_pName);
11493 if (newEntry == NULL)
11496 newEntry->newToken(); // Assign a new ibc external namespace token
11497 CONTRACT_VIOLATION(ThrowsViolation);
11498 pModule->GetProfilingBlobTable()->Add(newEntry);
11503 // Return the external namespace entry that we found or the new one that we just created
11505 _ASSERTE(pEntry->kind() == ExternalNamespaceDef);
11506 return static_cast<const ExternalNamespaceBlobEntry *>(pEntry);
11509 bool ExternalTypeBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11511 WRAPPER_NO_CONTRACT;
11513 if (this->kind() != other->kind())
11516 const ExternalTypeBlobEntry * other2 = static_cast<const ExternalTypeBlobEntry *>(other);
11518 if (this->assemblyRef() != other2->assemblyRef())
11521 if (this->nestedClass() != other2->nestedClass())
11524 if (this->nameSpace() != other2->nameSpace())
11527 if (this->cbName() != other2->cbName())
11530 LPCSTR p1 = this->pName();
11531 LPCSTR p2 = other2->pName();
11533 for (DWORD i=0; (i < this->cbName()); i++)
11534 if (p1[i] != p2[i])
11540 size_t ExternalTypeBlobEntry::Hash() const
11542 WRAPPER_NO_CONTRACT;
11544 size_t hashValue = HashInit();
11546 hashValue = HashCombine(hashValue, assemblyRef());
11547 hashValue = HashCombine(hashValue, nestedClass());
11548 hashValue = HashCombine(hashValue, nameSpace());
11550 LPCSTR p1 = pName();
11552 for (DWORD i=0; (i < cbName()); i++)
11553 hashValue = HashCombine(hashValue, p1[i]);
11558 ExternalTypeBlobEntry::ExternalTypeBlobEntry(mdToken _assemblyRef,
11559 mdToken _nestedClass,
11560 mdToken _nameSpace,
11567 PRECONDITION(CheckPointer(_pName));
11571 m_token = idExternalTypeNil;
11572 m_assemblyRef = mdAssemblyRefNil;
11573 m_nestedClass = idExternalTypeNil;
11574 m_nameSpace = idExternalNamespaceNil;
11578 DWORD _cbName = (DWORD) strlen(_pName) + 1;
11579 LPSTR * pName = (LPSTR *) new (nothrow) CHAR[_cbName];
11582 m_assemblyRef = _assemblyRef;
11583 m_nestedClass = _nestedClass;
11584 m_nameSpace = _nameSpace;
11585 m_cbName = _cbName;
11586 memcpy(pName, _pName, _cbName);
11587 m_pName = (LPCSTR) pName;
11591 /* static */ const ExternalTypeBlobEntry * ExternalTypeBlobEntry::FindOrAdd(PTR_Module pModule,
11592 mdToken _assemblyRef,
11593 mdToken _nestedClass,
11594 mdToken _nameSpace,
11604 if ((_pName == NULL) || (::strlen(_pName) == 0))
11607 ExternalTypeBlobEntry sEntry(_assemblyRef, _nestedClass, _nameSpace, _pName);
11609 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11610 if (pEntry == NULL)
11613 // Not Found, add a new external type blob entry
11615 ExternalTypeBlobEntry * newEntry = new (nothrow) ExternalTypeBlobEntry(_assemblyRef, _nestedClass, _nameSpace, _pName);
11616 if (newEntry == NULL)
11619 newEntry->newToken(); // Assign a new ibc external type token
11620 CONTRACT_VIOLATION(ThrowsViolation);
11621 pModule->GetProfilingBlobTable()->Add(newEntry);
11626 // Return the external type entry that we found or the new one that we just created
11628 _ASSERTE(pEntry->kind() == ExternalTypeDef);
11629 return static_cast<const ExternalTypeBlobEntry *>(pEntry);
11632 bool ExternalSignatureBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11634 WRAPPER_NO_CONTRACT;
11636 if (this->kind() != other->kind())
11639 const ExternalSignatureBlobEntry * other2 = static_cast<const ExternalSignatureBlobEntry *>(other);
11641 if (this->cbSig() != other2->cbSig())
11644 PCCOR_SIGNATURE p1 = this->pSig();
11645 PCCOR_SIGNATURE p2 = other2->pSig();
11647 for (DWORD i=0; (i < this->cbSig()); i++)
11648 if (p1[i] != p2[i])
11654 size_t ExternalSignatureBlobEntry::Hash() const
11656 WRAPPER_NO_CONTRACT;
11658 size_t hashValue = HashInit();
11660 hashValue = HashCombine(hashValue, cbSig());
11662 PCCOR_SIGNATURE p1 = pSig();
11664 for (DWORD i=0; (i < cbSig()); i++)
11665 hashValue = HashCombine(hashValue, p1[i]);
11670 ExternalSignatureBlobEntry::ExternalSignatureBlobEntry(DWORD _cbSig, PCCOR_SIGNATURE _pSig)
11676 PRECONDITION(_cbSig > 0);
11677 PRECONDITION(CheckPointer(_pSig));
11681 m_token = idExternalSignatureNil;
11684 COR_SIGNATURE * pNewSig = (COR_SIGNATURE *) new (nothrow) BYTE[_cbSig];
11685 if (pNewSig != NULL)
11688 memcpy(pNewSig, _pSig, _cbSig);
11690 m_pSig = const_cast<PCCOR_SIGNATURE>(pNewSig);
11693 /* static */ const ExternalSignatureBlobEntry * ExternalSignatureBlobEntry::FindOrAdd(PTR_Module pModule,
11695 PCCOR_SIGNATURE _pSig)
11704 if ((_cbSig == 0) || (_pSig == NULL))
11707 ExternalSignatureBlobEntry sEntry(_cbSig, _pSig);
11709 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11710 if (pEntry == NULL)
11713 // Not Found, add a new external signature blob entry
11715 ExternalSignatureBlobEntry * newEntry = new (nothrow) ExternalSignatureBlobEntry(_cbSig, _pSig);
11716 if (newEntry == NULL)
11719 newEntry->newToken(); // Assign a new ibc external signature token
11720 CONTRACT_VIOLATION(ThrowsViolation);
11721 pModule->GetProfilingBlobTable()->Add(newEntry);
11726 // Return the external signature entry that we found or the new one that we just created
11728 _ASSERTE(pEntry->kind() == ExternalSignatureDef);
11729 return static_cast<const ExternalSignatureBlobEntry *>(pEntry);
11732 bool ExternalMethodBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11734 WRAPPER_NO_CONTRACT;
11736 if (this->kind() != other->kind())
11739 const ExternalMethodBlobEntry * other2 = static_cast<const ExternalMethodBlobEntry *>(other);
11741 if (this->nestedClass() != other2->nestedClass())
11744 if (this->signature() != other2->signature())
11747 if (this->cbName() != other2->cbName())
11750 LPCSTR p1 = this->pName();
11751 LPCSTR p2 = other2->pName();
11753 for (DWORD i=0; (i < this->cbName()); i++)
11754 if (p1[i] != p2[i])
11760 size_t ExternalMethodBlobEntry::Hash() const
11762 WRAPPER_NO_CONTRACT;
11764 size_t hashValue = HashInit();
11766 hashValue = HashCombine(hashValue, nestedClass());
11767 hashValue = HashCombine(hashValue, signature());
11769 LPCSTR p1 = pName();
11771 for (DWORD i=0; (i < cbName()); i++)
11772 hashValue = HashCombine(hashValue, p1[i]);
11777 ExternalMethodBlobEntry::ExternalMethodBlobEntry(mdToken _nestedClass,
11778 mdToken _signature,
11785 PRECONDITION(CheckPointer(_pName));
11789 m_token = idExternalMethodNil;
11790 m_nestedClass = idExternalTypeNil;
11791 m_signature = idExternalSignatureNil;
11794 DWORD _cbName = (DWORD) strlen(_pName) + 1;
11795 LPSTR * pName = (LPSTR *) new (nothrow) CHAR[_cbName];
11798 m_nestedClass = _nestedClass;
11799 m_signature = _signature;
11800 m_cbName = _cbName;
11801 memcpy(pName, _pName, _cbName);
11802 m_pName = (LPSTR) pName;
11806 /* static */ const ExternalMethodBlobEntry * ExternalMethodBlobEntry::FindOrAdd(
11807 PTR_Module pModule,
11808 mdToken _nestedClass,
11809 mdToken _signature,
11816 PRECONDITION(CheckPointer(_pName));
11820 if ((_pName == NULL) || (::strlen(_pName) == 0))
11823 ExternalMethodBlobEntry sEntry(_nestedClass, _signature, _pName);
11825 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11826 if (pEntry == NULL)
11829 // Not Found, add a new external type blob entry
11831 ExternalMethodBlobEntry * newEntry;
11832 newEntry = new (nothrow) ExternalMethodBlobEntry(_nestedClass, _signature, _pName);
11833 if (newEntry == NULL)
11836 newEntry->newToken(); // Assign a new ibc external method token
11837 CONTRACT_VIOLATION(ThrowsViolation);
11838 pModule->GetProfilingBlobTable()->Add(newEntry);
11843 // Return the external method entry that we found or the new one that we just created
11845 _ASSERTE(pEntry->kind() == ExternalMethodDef);
11846 return static_cast<const ExternalMethodBlobEntry *>(pEntry);
11850 static bool GetBasename(LPCWSTR _src, __out_ecount(dstlen) __out_z LPWSTR _dst, int dstlen)
11852 LIMITED_METHOD_CONTRACT;
11853 LPCWSTR src = _src;
11856 if ((src == NULL) || (dstlen <= 0))
11859 bool inQuotes = false;
11860 LPWSTR dstLast = dst + (dstlen - 1);
11861 while (dst < dstLast)
11863 WCHAR wch = *src++;
11866 inQuotes = !inQuotes;
11877 if ((wch == W('\\')) || (wch == W(':')))
11881 else if (wch == W(' '))
11892 static void ProfileDataAllocateScenarioInfo(ProfileEmitter * pEmitter, LPCSTR scopeName, GUID* pMvid)
11899 INJECT_FAULT(COMPlusThrowOM());
11903 ProfileMap *profileMap = pEmitter->EmitNewSection(ScenarioInfo);
11906 // Allocate and initialize the scenario info section
11909 CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *siHeader;
11910 siHeader = (CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *) profileMap->Allocate(sizeof(CORBBTPROF_SCENARIO_INFO_SECTION_HEADER));
11912 siHeader->NumScenarios = 1;
11913 siHeader->TotalNumRuns = 1;
11917 // Allocate and initialize the scenario header section
11920 LPCWSTR pCmdLine = GetCommandLineW();
11921 S_SIZE_T cCmdLine = S_SIZE_T(wcslen(pCmdLine));
11923 if (cCmdLine.IsOverflow())
11925 ThrowHR(COR_E_OVERFLOW);
11928 LPCWSTR pSystemInfo = W("<machine,OS>");
11929 S_SIZE_T cSystemInfo = S_SIZE_T(wcslen(pSystemInfo));
11931 if (cSystemInfo.IsOverflow())
11933 ThrowHR(COR_E_OVERFLOW);
11936 FILETIME runTime, unused1, unused2, unused3;
11937 GetProcessTimes(GetCurrentProcess(), &runTime, &unused1, &unused2, &unused3);
11939 WCHAR scenarioName[256];
11940 GetBasename(pCmdLine, &scenarioName[0], 256);
11942 LPCWSTR pName = &scenarioName[0];
11943 S_SIZE_T cName = S_SIZE_T(wcslen(pName));
11945 if (cName.IsOverflow())
11947 ThrowHR(COR_E_OVERFLOW);
11950 S_SIZE_T sizeHeader = S_SIZE_T(sizeof(CORBBTPROF_SCENARIO_HEADER));
11951 sizeHeader += cName * S_SIZE_T(sizeof(WCHAR));
11952 if (sizeHeader.IsOverflow())
11954 ThrowHR(COR_E_OVERFLOW);
11957 S_SIZE_T sizeRun = S_SIZE_T(sizeof(CORBBTPROF_SCENARIO_RUN));
11958 sizeRun += cCmdLine * S_SIZE_T(sizeof(WCHAR));
11959 sizeRun += cSystemInfo * S_SIZE_T(sizeof(WCHAR));
11960 if (sizeRun.IsOverflow())
11962 ThrowHR(COR_E_OVERFLOW);
11966 // Allocate the Scenario Header struct
11968 SIZE_T sHeaderOffset;
11970 CORBBTPROF_SCENARIO_HEADER *sHeader;
11971 S_SIZE_T sHeaderSize = sizeHeader + sizeRun;
11972 if (sHeaderSize.IsOverflow())
11974 ThrowHR(COR_E_OVERFLOW);
11977 sHeaderOffset = profileMap->getCurrentOffset();
11978 sHeader = (CORBBTPROF_SCENARIO_HEADER *) profileMap->Allocate(sizeHeader.Value());
11980 sHeader->size = sHeaderSize.Value();
11981 sHeader->scenario.ordinal = 1;
11982 sHeader->scenario.mask = 1;
11983 sHeader->scenario.priority = 0;
11984 sHeader->scenario.numRuns = 1;
11985 sHeader->scenario.cName = cName.Value();
11986 wcscpy_s(sHeader->scenario.name, cName.Value(), pName);
11990 // Allocate the Scenario Run struct
11993 CORBBTPROF_SCENARIO_RUN *sRun;
11994 sRun = (CORBBTPROF_SCENARIO_RUN *) profileMap->Allocate(sizeRun.Value());
11996 sRun->runTime = runTime;
11997 sRun->mvid = *pMvid;
11998 sRun->cCmdLine = cCmdLine.Value();
11999 sRun->cSystemInfo = cSystemInfo.Value();
12000 wcscpy_s(sRun->cmdLine, cCmdLine.Value(), pCmdLine);
12001 wcscpy_s(sRun->cmdLine+cCmdLine.Value(), cSystemInfo.Value(), pSystemInfo);
12005 CORBBTPROF_SCENARIO_HEADER * sHeader;
12006 sHeader = (CORBBTPROF_SCENARIO_HEADER *) profileMap->getOffsetPtr(sHeaderOffset);
12007 assert(sHeader->size == sHeader->Size());
12013 static void ProfileDataAllocateMethodBlockCounts(ProfileEmitter * pEmitter, CORCOMPILE_METHOD_PROFILE_LIST * pMethodProfileListHead)
12020 INJECT_FAULT(COMPlusThrowOM());
12024 ProfileMap *profileMap = pEmitter->EmitNewSection(MethodBlockCounts);
12027 // Allocate and initialize the method block count section
12029 SIZE_T mbcHeaderOffset;
12031 CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *mbcHeader;
12032 mbcHeaderOffset = profileMap->getCurrentOffset();
12033 mbcHeader = (CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *)
12034 profileMap->Allocate(sizeof(CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER));
12035 mbcHeader->NumMethods = 0; // This gets filled in later
12038 ULONG numMethods = 0; // We count the number of methods that were executed
12040 for (CORCOMPILE_METHOD_PROFILE_LIST * methodProfileList = pMethodProfileListHead;
12042 methodProfileList = methodProfileList->next)
12044 CORBBTPROF_METHOD_HEADER * pInfo = methodProfileList->GetInfo();
12046 assert(pInfo->size == pInfo->Size());
12049 // We set methodWasExecuted based upon the ExecutionCount of the very first block
12051 bool methodWasExecuted = (pInfo->method.block[0].ExecutionCount > 0);
12054 // If the method was not executed then we don't need to output this methods block counts
12056 SIZE_T methodHeaderOffset;
12057 if (methodWasExecuted)
12059 DWORD profileDataSize = pInfo->size;
12060 methodHeaderOffset = profileMap->getCurrentOffset();
12061 CORBBTPROF_METHOD_HEADER *methodHeader = (CORBBTPROF_METHOD_HEADER *) profileMap->Allocate(profileDataSize);
12062 memcpy(methodHeader, pInfo, profileDataSize);
12066 // Reset all of the basic block counts to zero
12067 for (ULONG i=0; (i < pInfo->method.cBlock); i++ )
12070 // If methodWasExecuted is false then every block's ExecutionCount should also be zero
12072 _ASSERTE(methodWasExecuted || (pInfo->method.block[i].ExecutionCount == 0));
12074 pInfo->method.block[i].ExecutionCount = 0;
12079 CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *mbcHeader;
12080 // We have to refetch the mbcHeader as calls to Allocate will resize and thus move the mbcHeader
12081 mbcHeader = (CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *) profileMap->getOffsetPtr(mbcHeaderOffset);
12082 mbcHeader->NumMethods = numMethods;
12086 /*static*/ void Module::ProfileDataAllocateTokenLists(ProfileEmitter * pEmitter, Module::TokenProfileData* pTokenProfileData)
12093 INJECT_FAULT(COMPlusThrowOM());
12098 // Allocate and initialize the token list sections
12100 if (pTokenProfileData)
12102 for (int format = 0; format < (int)SectionFormatCount; format++)
12104 CQuickArray<CORBBTPROF_TOKEN_INFO> *pTokenArray = &(pTokenProfileData->m_formats[format].tokenArray);
12106 if (pTokenArray->Size() != 0)
12108 ProfileMap * profileMap = pEmitter->EmitNewSection((SectionFormat) format);
12110 CORBBTPROF_TOKEN_LIST_SECTION_HEADER *header;
12111 header = (CORBBTPROF_TOKEN_LIST_SECTION_HEADER *)
12112 profileMap->Allocate(sizeof(CORBBTPROF_TOKEN_LIST_SECTION_HEADER) +
12113 pTokenArray->Size() * sizeof(CORBBTPROF_TOKEN_INFO));
12115 header->NumTokens = pTokenArray->Size();
12116 memcpy( (header + 1), &((*pTokenArray)[0]), pTokenArray->Size() * sizeof(CORBBTPROF_TOKEN_INFO));
12118 // Reset the collected tokens
12119 for (unsigned i = 0; i < CORBBTPROF_TOKEN_MAX_NUM_FLAGS; i++)
12121 pTokenProfileData->m_formats[format].tokenBitmaps[i].Reset();
12123 pTokenProfileData->m_formats[format].tokenArray.ReSizeNoThrow(0);
12129 static void ProfileDataAllocateTokenDefinitions(ProfileEmitter * pEmitter, Module * pModule)
12136 INJECT_FAULT(COMPlusThrowOM());
12141 // Allocate and initialize the ibc token definition section (aka the Blob stream)
12143 ProfileMap * profileMap = pEmitter->EmitNewSection(BlobStream);
12145 // Compute the size of the metadata section:
12146 // It is the sum of all of the Metadata Profile pool entries
12147 // plus the sum of all of the Param signature entries
12149 size_t totalSize = 0;
12151 for (ProfilingBlobTable::Iterator cur = pModule->GetProfilingBlobTable()->Begin(),
12152 end = pModule->GetProfilingBlobTable()->End();
12156 const ProfilingBlobEntry * pEntry = *cur;
12157 size_t blobElementSize = pEntry->varSize();
12158 switch (pEntry->kind()) {
12159 case ParamTypeSpec:
12160 case ParamMethodSpec:
12161 blobElementSize += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
12164 case ExternalNamespaceDef:
12165 blobElementSize += sizeof(CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY);
12168 case ExternalTypeDef:
12169 blobElementSize += sizeof(CORBBTPROF_BLOB_TYPE_DEF_ENTRY);
12172 case ExternalSignatureDef:
12173 blobElementSize += sizeof(CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY);
12176 case ExternalMethodDef:
12177 blobElementSize += sizeof(CORBBTPROF_BLOB_METHOD_DEF_ENTRY);
12181 _ASSERTE(!"Unexpected blob type");
12184 totalSize += blobElementSize;
12187 profileMap->Allocate(totalSize);
12189 size_t currentPos = 0;
12191 // Traverse each element and record it
12192 size_t blobElementSize = 0;
12193 for (ProfilingBlobTable::Iterator cur = pModule->GetProfilingBlobTable()->Begin(),
12194 end = pModule->GetProfilingBlobTable()->End();
12196 cur++, currentPos += blobElementSize)
12198 const ProfilingBlobEntry * pEntry = *cur;
12199 blobElementSize = pEntry->varSize();
12200 void *profileData = profileMap->getOffsetPtr(currentPos);
12202 switch (pEntry->kind()) {
12203 case ParamTypeSpec:
12205 CORBBTPROF_BLOB_PARAM_SIG_ENTRY * bProfileData = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY*) profileData;
12206 const TypeSpecBlobEntry * typeSpecBlobEntry = static_cast<const TypeSpecBlobEntry *>(pEntry);
12208 blobElementSize += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
12209 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12210 bProfileData->blob.type = typeSpecBlobEntry->kind();
12211 bProfileData->blob.token = typeSpecBlobEntry->token();
12212 _ASSERTE(typeSpecBlobEntry->cbSig() > 0);
12213 bProfileData->cSig = typeSpecBlobEntry->cbSig();
12214 memcpy(&bProfileData->sig[0], typeSpecBlobEntry->pSig(), typeSpecBlobEntry->cbSig());
12218 case ParamMethodSpec:
12220 CORBBTPROF_BLOB_PARAM_SIG_ENTRY * bProfileData = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY*) profileData;
12221 const MethodSpecBlobEntry * methodSpecBlobEntry = static_cast<const MethodSpecBlobEntry *>(pEntry);
12223 blobElementSize += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
12224 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12225 bProfileData->blob.type = methodSpecBlobEntry->kind();
12226 bProfileData->blob.token = methodSpecBlobEntry->token();
12227 _ASSERTE(methodSpecBlobEntry->cbSig() > 0);
12228 bProfileData->cSig = methodSpecBlobEntry->cbSig();
12229 memcpy(&bProfileData->sig[0], methodSpecBlobEntry->pSig(), methodSpecBlobEntry->cbSig());
12233 case ExternalNamespaceDef:
12235 CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY*) profileData;
12236 const ExternalNamespaceBlobEntry * namespaceBlobEntry = static_cast<const ExternalNamespaceBlobEntry *>(pEntry);
12238 blobElementSize += sizeof(CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY);
12239 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12240 bProfileData->blob.type = namespaceBlobEntry->kind();
12241 bProfileData->blob.token = namespaceBlobEntry->token();
12242 _ASSERTE(namespaceBlobEntry->cbName() > 0);
12243 bProfileData->cName = namespaceBlobEntry->cbName();
12244 memcpy(&bProfileData->name[0], namespaceBlobEntry->pName(), namespaceBlobEntry->cbName());
12248 case ExternalTypeDef:
12250 CORBBTPROF_BLOB_TYPE_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_TYPE_DEF_ENTRY*) profileData;
12251 const ExternalTypeBlobEntry * typeBlobEntry = static_cast<const ExternalTypeBlobEntry *>(pEntry);
12253 blobElementSize += sizeof(CORBBTPROF_BLOB_TYPE_DEF_ENTRY);
12254 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12255 bProfileData->blob.type = typeBlobEntry->kind();
12256 bProfileData->blob.token = typeBlobEntry->token();
12257 bProfileData->assemblyRefToken = typeBlobEntry->assemblyRef();
12258 bProfileData->nestedClassToken = typeBlobEntry->nestedClass();
12259 bProfileData->nameSpaceToken = typeBlobEntry->nameSpace();
12260 _ASSERTE(typeBlobEntry->cbName() > 0);
12261 bProfileData->cName = typeBlobEntry->cbName();
12262 memcpy(&bProfileData->name[0], typeBlobEntry->pName(), typeBlobEntry->cbName());
12266 case ExternalSignatureDef:
12268 CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY*) profileData;
12269 const ExternalSignatureBlobEntry * signatureBlobEntry = static_cast<const ExternalSignatureBlobEntry *>(pEntry);
12271 blobElementSize += sizeof(CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY);
12272 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12273 bProfileData->blob.type = signatureBlobEntry->kind();
12274 bProfileData->blob.token = signatureBlobEntry->token();
12275 _ASSERTE(signatureBlobEntry->cbSig() > 0);
12276 bProfileData->cSig = signatureBlobEntry->cbSig();
12277 memcpy(&bProfileData->sig[0], signatureBlobEntry->pSig(), signatureBlobEntry->cbSig());
12281 case ExternalMethodDef:
12283 CORBBTPROF_BLOB_METHOD_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_METHOD_DEF_ENTRY*) profileData;
12284 const ExternalMethodBlobEntry * methodBlobEntry = static_cast<const ExternalMethodBlobEntry *>(pEntry);
12286 blobElementSize += sizeof(CORBBTPROF_BLOB_METHOD_DEF_ENTRY);
12287 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12288 bProfileData->blob.type = methodBlobEntry->kind();
12289 bProfileData->blob.token = methodBlobEntry->token();
12290 bProfileData->nestedClassToken = methodBlobEntry->nestedClass();
12291 bProfileData->signatureToken = methodBlobEntry->signature();
12292 _ASSERTE(methodBlobEntry->cbName() > 0);
12293 bProfileData->cName = methodBlobEntry->cbName();
12294 memcpy(&bProfileData->name[0], methodBlobEntry->pName(), methodBlobEntry->cbName());
12299 _ASSERTE(!"Unexpected blob type");
12304 _ASSERTE(currentPos == totalSize);
12306 // Emit a terminating entry with type EndOfBlobStream to mark the end
12307 DWORD mdElementSize = sizeof(CORBBTPROF_BLOB_ENTRY);
12308 void *profileData = profileMap->Allocate(mdElementSize);
12309 memset(profileData, 0, mdElementSize);
12311 CORBBTPROF_BLOB_ENTRY* mdProfileData = (CORBBTPROF_BLOB_ENTRY*) profileData;
12312 mdProfileData->type = EndOfBlobStream;
12313 mdProfileData->size = sizeof(CORBBTPROF_BLOB_ENTRY);
12316 // Responsible for writing out the profile data if the COMPlus_BBInstr
12317 // environment variable is set. This is called when the module is unloaded
12318 // (usually at shutdown).
12319 HRESULT Module::WriteMethodProfileDataLogFile(bool cleanup)
12327 INJECT_FAULT(return E_OUTOFMEMORY;);
12338 if (GetAssembly()->IsInstrumented() && (m_pProfilingBlobTable != NULL) && (m_tokenProfileData != NULL))
12340 ProfileEmitter * pEmitter = new ProfileEmitter();
12342 // Get this ahead of time - metadata access may be logged, which will
12343 // take the m_tokenProfileData->crst, which we take a couple lines below
12346 IfFailThrow(GetMDImport()->GetScopeProps(&pszName, &mvid));
12348 CrstHolder ch(&m_tokenProfileData->crst);
12351 // Create the scenario info section
12353 ProfileDataAllocateScenarioInfo(pEmitter, pszName, &mvid);
12356 // Create the method block count section
12358 ProfileDataAllocateMethodBlockCounts(pEmitter, m_methodProfileList);
12361 // Create the token list sections
12363 ProfileDataAllocateTokenLists(pEmitter, m_tokenProfileData);
12366 // Create the ibc token definition section (aka the Blob stream)
12368 ProfileDataAllocateTokenDefinitions(pEmitter, this);
12371 // Now store the profile data in the ibc file
12373 ProfileMap profileImage;
12374 pEmitter->Serialize(&profileImage, mvid);
12376 HandleHolder profileDataFile(OpenMethodProfileDataLogFile(mvid));
12379 BOOL result = WriteFile(profileDataFile, profileImage.getOffsetPtr(0), profileImage.getCurrentOffset(), &count, NULL);
12380 if (!result || (count != profileImage.getCurrentOffset()))
12382 DWORD lasterror = GetLastError();
12383 _ASSERTE(!"Error writing ibc profile data to file");
12384 hr = HRESULT_FROM_WIN32(lasterror);
12390 DeleteProfilingData();
12397 EX_END_CATCH(SwallowAllExceptions)
12404 void Module::WriteAllModuleProfileData(bool cleanup)
12414 // Iterate over all the app domains; for each one iterator over its
12415 // assemblies; for each one iterate over its modules.
12418 AppDomainIterator appDomainIterator(FALSE);
12419 while(appDomainIterator.Next())
12421 AppDomain * appDomain = appDomainIterator.GetDomain();
12422 AppDomain::AssemblyIterator assemblyIterator = appDomain->IterateAssembliesEx(
12423 (AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution));
12424 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
12426 while (assemblyIterator.Next(pDomainAssembly.This()))
12428 DomainModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
12431 /*hr=*/i.GetModule()->WriteMethodProfileDataLogFile(cleanup);
12438 EX_END_CATCH(SwallowAllExceptions);
12441 PTR_ProfilingBlobTable Module::GetProfilingBlobTable()
12443 LIMITED_METHOD_CONTRACT;
12444 return m_pProfilingBlobTable;
12447 void Module::CreateProfilingData()
12449 TokenProfileData *tpd = TokenProfileData::CreateNoThrow();
12451 PVOID pv = InterlockedCompareExchangeT(&m_tokenProfileData, tpd, NULL);
12457 PTR_ProfilingBlobTable ppbt = new (nothrow) ProfilingBlobTable();
12461 pv = InterlockedCompareExchangeT(&m_pProfilingBlobTable, ppbt, NULL);
12469 void Module::DeleteProfilingData()
12471 if (m_pProfilingBlobTable != NULL)
12473 for (ProfilingBlobTable::Iterator cur = m_pProfilingBlobTable->Begin(),
12474 end = m_pProfilingBlobTable->End();
12478 const ProfilingBlobEntry * pCurrentEntry = *cur;
12479 delete pCurrentEntry;
12481 delete m_pProfilingBlobTable;
12482 m_pProfilingBlobTable = NULL;
12485 if (m_tokenProfileData != NULL)
12487 delete m_tokenProfileData;
12488 m_tokenProfileData = NULL;
12491 // the metadataProfileData is free'ed in destructor of the corresponding MetaDataTracker
12493 #endif //FEATURE_PREJIT
12497 #ifdef FEATURE_PREJIT
12499 Module::TokenProfileData *Module::TokenProfileData::CreateNoThrow(void)
12501 STATIC_CONTRACT_NOTHROW;
12503 TokenProfileData *tpd = NULL;
12508 // This constructor calls crst.Init(), which may throw. So putting (nothrow) doesn't
12509 // do what we would want it to. Thus I wrap it here in a TRY/CATCH and revert to NULL
12512 tpd = new TokenProfileData();
12518 EX_END_CATCH(SwallowAllExceptions);
12523 #endif // FEATURE_PREJIT
12525 #endif // !DACCESS_COMPILE
12527 #ifndef DACCESS_COMPILE
12528 void Module::SetBeingUnloaded()
12530 LIMITED_METHOD_CONTRACT;
12531 FastInterlockOr((ULONG*)&m_dwTransientFlags, IS_BEING_UNLOADED);
12535 #ifdef FEATURE_PREJIT
12536 void Module::LogTokenAccess(mdToken token, SectionFormat format, ULONG flagnum)
12544 PRECONDITION(g_IBCLogger.InstrEnabled());
12545 PRECONDITION(flagnum < CORBBTPROF_TOKEN_MAX_NUM_FLAGS);
12549 #ifndef DACCESS_COMPILE
12552 // If we are in ngen instrumentation mode, then we should record this token.
12555 if (!m_nativeImageProfiling)
12558 if (flagnum >= CORBBTPROF_TOKEN_MAX_NUM_FLAGS)
12563 mdToken rid = RidFromToken(token);
12564 CorTokenType tkType = (CorTokenType) TypeFromToken(token);
12565 SectionFormat tkKind = (SectionFormat) (tkType >> 24);
12567 if ((rid == 0) && (tkKind < (SectionFormat) TBL_COUNT))
12572 _ASSERTE(TypeProfilingData == FirstTokenFlagSection + TBL_TypeDef);
12573 _ASSERTE(MethodProfilingData == FirstTokenFlagSection + TBL_Method);
12574 _ASSERTE(SectionFormatCount >= FirstTokenFlagSection + TBL_COUNT + 4);
12576 if (!m_tokenProfileData)
12578 CreateProfilingData();
12581 if (!m_tokenProfileData)
12586 if (tkKind == (SectionFormat) (ibcTypeSpec >> 24))
12587 tkKind = IbcTypeSpecSection;
12588 else if (tkKind == (SectionFormat) (ibcMethodSpec >> 24))
12589 tkKind = IbcMethodSpecSection;
12591 _ASSERTE(tkKind >= 0);
12592 _ASSERTE(tkKind < SectionFormatCount);
12593 if (tkKind < 0 || tkKind >= SectionFormatCount)
12598 CQuickArray<CORBBTPROF_TOKEN_INFO> * pTokenArray = &m_tokenProfileData->m_formats[format].tokenArray;
12599 RidBitmap * pTokenBitmap = &m_tokenProfileData->m_formats[tkKind].tokenBitmaps[flagnum];
12601 // Have we seen this token with this flag already?
12602 if (pTokenBitmap->IsTokenInBitmap(token))
12607 // Insert the token to the bitmap
12608 if (FAILED(pTokenBitmap->InsertToken(token)))
12613 ULONG flag = 1 << flagnum;
12615 // [ToDo] Fix: this is a sequential search and can be very slow
12616 for (unsigned int i = 0; i < pTokenArray->Size(); i++)
12618 if ((*pTokenArray)[i].token == token)
12620 _ASSERTE(! ((*pTokenArray)[i].flags & flag));
12621 (*pTokenArray)[i].flags |= flag;
12626 if (FAILED(pTokenArray->ReSizeNoThrow(pTokenArray->Size() + 1)))
12631 (*pTokenArray)[pTokenArray->Size() - 1].token = token;
12632 (*pTokenArray)[pTokenArray->Size() - 1].flags = flag;
12633 (*pTokenArray)[pTokenArray->Size() - 1].scenarios = 0;
12635 #endif // !DACCESS_COMPILE
12638 void Module::LogTokenAccess(mdToken token, ULONG flagNum)
12640 WRAPPER_NO_CONTRACT;
12641 SectionFormat format = (SectionFormat)((TypeFromToken(token)>>24) + FirstTokenFlagSection);
12642 if (FirstTokenFlagSection <= format && format < SectionFormatCount)
12644 LogTokenAccess(token, format, flagNum);
12647 #endif // FEATURE_PREJIT
12649 #ifndef DACCESS_COMPILE
12650 #ifdef FEATURE_PREJIT
12653 // Encoding callbacks
12656 /*static*/ DWORD Module::EncodeModuleHelper(void * pModuleContext, Module *pReferencedModule)
12658 Module* pReferencingModule = (Module *) pModuleContext;
12659 _ASSERTE(pReferencingModule != pReferencedModule);
12661 Assembly *pReferencingAssembly = pReferencingModule->GetAssembly();
12662 Assembly *pReferencedAssembly = pReferencedModule->GetAssembly();
12664 _ASSERTE(pReferencingAssembly != pReferencedAssembly);
12666 if (pReferencedAssembly == pReferencingAssembly)
12671 mdAssemblyRef token = pReferencingModule->FindAssemblyRef(pReferencedAssembly);
12673 if (IsNilToken(token))
12675 return ENCODE_MODULE_FAILED;
12678 return RidFromToken(token);
12681 /*static*/ void Module::TokenDefinitionHelper(void* pModuleContext, Module *pReferencedModule, DWORD index, mdToken* pToken)
12683 LIMITED_METHOD_CONTRACT;
12685 Module * pReferencingModule = (Module *) pModuleContext;
12686 mdAssemblyRef mdAssemblyRef = TokenFromRid(index, mdtAssemblyRef);
12687 IMDInternalImport * pImport = pReferencedModule->GetMDImport();
12688 LPCUTF8 szName = NULL;
12690 if (TypeFromToken(*pToken) == mdtTypeDef)
12693 // Compute nested type (if any)
12695 mdTypeDef mdEnclosingType = idExternalTypeNil;
12696 hr = pImport->GetNestedClassProps(*pToken, &mdEnclosingType);
12697 // If there's not enclosing type, then hr=CLDB_E_RECORD_NOTFOUND and mdEnclosingType is unchanged
12698 _ASSERTE((hr == S_OK) || (hr == CLDB_E_RECORD_NOTFOUND));
12700 if (!IsNilToken(mdEnclosingType))
12702 _ASSERT(TypeFromToken(mdEnclosingType) == mdtTypeDef);
12703 TokenDefinitionHelper(pModuleContext, pReferencedModule, index, &mdEnclosingType);
12705 _ASSERT(TypeFromToken(mdEnclosingType) == ibcExternalType);
12708 // Compute type name and namespace.
12710 LPCUTF8 szNamespace = NULL;
12711 hr = pImport->GetNameOfTypeDef(*pToken, &szName, &szNamespace);
12712 _ASSERTE(hr == S_OK);
12715 // Transform namespace string into ibc external namespace token
12717 idExternalNamespace idNamespace = idExternalNamespaceNil;
12718 if (szNamespace != NULL)
12720 const ExternalNamespaceBlobEntry * pNamespaceEntry;
12721 pNamespaceEntry = ExternalNamespaceBlobEntry::FindOrAdd(pReferencingModule, szNamespace);
12722 if (pNamespaceEntry != NULL)
12724 idNamespace = pNamespaceEntry->token();
12727 _ASSERTE(TypeFromToken(idNamespace) == ibcExternalNamespace);
12730 // Transform type name into ibc external type token
12732 idExternalType idType = idExternalTypeNil;
12733 _ASSERTE(szName != NULL);
12734 const ExternalTypeBlobEntry * pTypeEntry = NULL;
12735 pTypeEntry = ExternalTypeBlobEntry::FindOrAdd(pReferencingModule,
12740 if (pTypeEntry != NULL)
12742 idType = pTypeEntry->token();
12744 _ASSERTE(TypeFromToken(idType) == ibcExternalType);
12746 *pToken = idType; // Remap pToken to our idExternalType token
12748 else if (TypeFromToken(*pToken) == mdtMethodDef)
12751 // Compute nested type (if any)
12753 mdTypeDef mdEnclosingType = idExternalTypeNil;
12754 hr = pImport->GetParentToken(*pToken, &mdEnclosingType);
12755 _ASSERTE(!FAILED(hr));
12757 if (!IsNilToken(mdEnclosingType))
12759 _ASSERT(TypeFromToken(mdEnclosingType) == mdtTypeDef);
12760 TokenDefinitionHelper(pModuleContext, pReferencedModule, index, &mdEnclosingType);
12762 _ASSERT(TypeFromToken(mdEnclosingType) == ibcExternalType);
12765 // Compute the method name and signature
12767 PCCOR_SIGNATURE pSig = NULL;
12769 hr = pImport->GetNameAndSigOfMethodDef(*pToken, &pSig, &cbSig, &szName);
12770 _ASSERTE(hr == S_OK);
12773 // Transform signature into ibc external signature token
12775 idExternalSignature idSignature = idExternalSignatureNil;
12778 const ExternalSignatureBlobEntry * pSignatureEntry;
12779 pSignatureEntry = ExternalSignatureBlobEntry::FindOrAdd(pReferencingModule, cbSig, pSig);
12780 if (pSignatureEntry != NULL)
12782 idSignature = pSignatureEntry->token();
12785 _ASSERTE(TypeFromToken(idSignature) == ibcExternalSignature);
12788 // Transform method name into ibc external method token
12790 idExternalMethod idMethod = idExternalMethodNil;
12791 _ASSERTE(szName != NULL);
12792 const ExternalMethodBlobEntry * pMethodEntry = NULL;
12793 pMethodEntry = ExternalMethodBlobEntry::FindOrAdd(pReferencingModule,
12797 if (pMethodEntry != NULL)
12799 idMethod = pMethodEntry->token();
12801 _ASSERTE(TypeFromToken(idMethod) == ibcExternalMethod);
12803 *pToken = idMethod; // Remap pToken to our idMethodSpec token
12807 _ASSERTE(!"Unexpected token type");
12811 idTypeSpec Module::LogInstantiatedType(TypeHandle typeHnd, ULONG flagNum)
12813 CONTRACT(idTypeSpec)
12818 PRECONDITION(g_IBCLogger.InstrEnabled());
12819 PRECONDITION(!typeHnd.HasUnrestoredTypeKey());
12820 // We want to report the type only in its own loader module as a type's
12821 // MethodTable can only live in its own loader module.
12822 // We can relax this if we allow a (duplicate) MethodTable to live
12823 // in any module (which might be needed for ngen of generics)
12824 #ifdef FEATURE_PREJIT
12825 // All callsites already do this...
12826 // PRECONDITION(this == GetPreferredZapModuleForTypeHandle(typeHnd));
12831 idTypeSpec result = idTypeSpecNil;
12833 if (m_nativeImageProfiling)
12835 CONTRACT_VIOLATION(ThrowsViolation|FaultViolation|GCViolation);
12837 SigBuilder sigBuilder;
12839 ZapSig zapSig(this, this, ZapSig::IbcTokens,
12840 Module::EncodeModuleHelper, Module::TokenDefinitionHelper);
12841 BOOL fSuccess = zapSig.GetSignatureForTypeHandle(typeHnd, &sigBuilder);
12843 // a return value of 0 indicates a failure to create the signature
12847 PCCOR_SIGNATURE pSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cbSig);
12849 ULONG flag = (1 << flagNum);
12850 TypeSpecBlobEntry * pEntry = const_cast<TypeSpecBlobEntry *>(TypeSpecBlobEntry::FindOrAdd(this, cbSig, pSig));
12851 if (pEntry != NULL)
12853 // Update the flags with any new bits
12854 pEntry->orFlag(flag);
12855 result = pEntry->token();
12859 _ASSERTE(TypeFromToken(result) == ibcTypeSpec);
12864 idMethodSpec Module::LogInstantiatedMethod(const MethodDesc * md, ULONG flagNum)
12866 CONTRACT(idMethodSpec)
12871 PRECONDITION( md != NULL );
12875 idMethodSpec result = idMethodSpecNil;
12877 if (m_nativeImageProfiling)
12879 CONTRACT_VIOLATION(ThrowsViolation|FaultViolation|GCViolation);
12882 SigBuilder sigBuilder;
12885 fSuccess = ZapSig::EncodeMethod(const_cast<MethodDesc *>(md), this, &sigBuilder,
12887 (ENCODEMODULE_CALLBACK) Module::EncodeModuleHelper,
12888 (DEFINETOKEN_CALLBACK) Module::TokenDefinitionHelper);
12893 BYTE * pBlob = (BYTE *)sigBuilder.GetSignature(&dataSize);
12895 ULONG flag = (1 << flagNum);
12896 MethodSpecBlobEntry * pEntry = const_cast<MethodSpecBlobEntry *>(MethodSpecBlobEntry::FindOrAdd(this, dataSize, pBlob));
12897 if (pEntry != NULL)
12899 // Update the flags with any new bits
12900 pEntry->orFlag(flag);
12901 result = pEntry->token();
12906 _ASSERTE(TypeFromToken(result) == ibcMethodSpec);
12909 #endif // DACCESS_COMPILE
12910 #endif //FEATURE_PREJIT
12912 #ifndef DACCESS_COMPILE
12914 #ifndef CROSSGEN_COMPILE
12915 // ===========================================================================
12916 // ReflectionModule
12917 // ===========================================================================
12920 ReflectionModule *ReflectionModule::Create(Assembly *pAssembly, PEFile *pFile, AllocMemTracker *pamTracker, LPCWSTR szName, BOOL fIsTransient)
12922 CONTRACT(ReflectionModule *)
12925 PRECONDITION(CheckPointer(pAssembly));
12926 PRECONDITION(CheckPointer(pFile));
12927 PRECONDITION(pFile->IsDynamic());
12928 POSTCONDITION(CheckPointer(RETVAL));
12932 // Hoist CONTRACT into separate routine because of EX incompatibility
12935 _ASSERTE(pFile->IsAssembly());
12938 // Initial memory block for Modules must be zero-initialized (to make it harder
12939 // to introduce Destruct crashes arising from OOM's during initialization.)
12941 void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(ReflectionModule))));
12942 ReflectionModuleHolder pModule(new (pMemory) ReflectionModule(pAssembly, token, pFile));
12944 pModule->DoInit(pamTracker, szName);
12946 // Set this at module creation time. The m_fIsTransient field should never change during the lifetime of this ReflectionModule.
12947 pModule->SetIsTransient(fIsTransient ? true : false);
12949 RETURN pModule.Extract();
12953 // Module initialization occurs in two phases: the constructor phase and the Initialize phase.
12955 // The constructor phase initializes just enough so that Destruct() can be safely called.
12956 // It cannot throw or fail.
12958 ReflectionModule::ReflectionModule(Assembly *pAssembly, mdFile token, PEFile *pFile)
12959 : Module(pAssembly, token, pFile)
12969 m_pInMemoryWriter = NULL;
12970 m_sdataSection = NULL;
12971 m_pISymUnmanagedWriter = NULL;
12972 m_pCreatingAssembly = NULL;
12973 m_pCeeFileGen = NULL;
12974 m_pDynamicMetadata = NULL;
12975 m_fSuppressMetadataCapture = false;
12976 m_fIsTransient = false;
12979 HRESULT STDMETHODCALLTYPE CreateICeeGen(REFIID riid, void **pCeeGen);
12981 // Module initialization occurs in two phases: the constructor phase and the Initialize phase.
12983 // The Initialize() phase completes the initialization after the constructor has run.
12984 // It can throw exceptions but whether it throws or succeeds, it must leave the Module
12985 // in a state where Destruct() can be safely called.
12987 void ReflectionModule::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
12993 PRECONDITION(szName != NULL);
12997 Module::Initialize(pamTracker);
12999 IfFailThrow(CreateICeeGen(IID_ICeeGen, (void **)&m_pCeeFileGen));
13001 // Collectible modules should try to limit the growth of their associate IL section, as common scenarios for collectible
13002 // modules include single type modules
13003 if (IsCollectible())
13005 ReleaseHolder<ICeeGenInternal> pCeeGenInternal(NULL);
13006 IfFailThrow(m_pCeeFileGen->QueryInterface(IID_ICeeGenInternal, (void **)&pCeeGenInternal));
13007 IfFailThrow(pCeeGenInternal->SetInitialGrowth(CEE_FILE_GEN_GROWTH_COLLECTIBLE));
13010 m_pInMemoryWriter = new RefClassWriter();
13012 IfFailThrow(m_pInMemoryWriter->Init(GetCeeGen(), GetEmitter(), szName));
13014 m_CrstLeafLock.Init(CrstLeafLock);
13017 void ReflectionModule::Destruct()
13027 delete m_pInMemoryWriter;
13029 if (m_pISymUnmanagedWriter)
13031 m_pISymUnmanagedWriter->Close();
13032 m_pISymUnmanagedWriter->Release();
13033 m_pISymUnmanagedWriter = NULL;
13037 m_pCeeFileGen->Release();
13039 Module::Destruct();
13041 delete m_pDynamicMetadata;
13042 m_pDynamicMetadata = NULL;
13044 m_CrstLeafLock.Destroy();
13047 // Returns true iff metadata capturing is suppressed.
13050 // This is during the window after code:ReflectionModule.SuppressMetadataCapture and before
13051 // code:ReflectionModule.ResumeMetadataCapture.
13053 // If metadata updates are suppressed, then class-load notifications should be suppressed too.
13054 bool ReflectionModule::IsMetadataCaptureSuppressed()
13056 return m_fSuppressMetadataCapture;
13059 // Holder of changed value of MDUpdateMode via IMDInternalEmit::SetMDUpdateMode.
13060 // Returns back the original value on release.
13062 class MDUpdateModeHolder
13065 MDUpdateModeHolder()
13067 m_pInternalEmitter = NULL;
13068 m_OriginalMDUpdateMode = ULONG_MAX;
13070 ~MDUpdateModeHolder()
13072 WRAPPER_NO_CONTRACT;
13075 HRESULT SetMDUpdateMode(IMetaDataEmit *pEmitter, ULONG updateMode)
13077 LIMITED_METHOD_CONTRACT;
13080 _ASSERTE(updateMode != ULONG_MAX);
13082 IfFailRet(pEmitter->QueryInterface(IID_IMDInternalEmit, (void **)&m_pInternalEmitter));
13083 _ASSERTE(m_pInternalEmitter != NULL);
13085 IfFailRet(m_pInternalEmitter->SetMDUpdateMode(updateMode, &m_OriginalMDUpdateMode));
13086 _ASSERTE(m_OriginalMDUpdateMode != ULONG_MAX);
13090 HRESULT Release(ULONG expectedPreviousUpdateMode = ULONG_MAX)
13094 if (m_OriginalMDUpdateMode != ULONG_MAX)
13096 _ASSERTE(m_pInternalEmitter != NULL);
13097 ULONG previousUpdateMode;
13098 // Ignore the error when releasing
13099 hr = m_pInternalEmitter->SetMDUpdateMode(m_OriginalMDUpdateMode, &previousUpdateMode);
13100 m_OriginalMDUpdateMode = ULONG_MAX;
13102 if (expectedPreviousUpdateMode != ULONG_MAX)
13104 if ((hr == S_OK) && (expectedPreviousUpdateMode != previousUpdateMode))
13110 if (m_pInternalEmitter != NULL)
13112 (void)m_pInternalEmitter->Release();
13113 m_pInternalEmitter = NULL;
13117 ULONG GetOriginalMDUpdateMode()
13119 WRAPPER_NO_CONTRACT;
13120 _ASSERTE(m_OriginalMDUpdateMode != LONG_MAX);
13121 return m_OriginalMDUpdateMode;
13124 IMDInternalEmit *m_pInternalEmitter;
13125 ULONG m_OriginalMDUpdateMode;
13128 // Called in live paths to fetch metadata for dynamic modules. This makes the metadata available to the
13129 // debugger from out-of-process.
13132 // This buffer can be retrieved by the debugger via code:ReflectionModule.GetDynamicMetadataBuffer
13135 // - Callers must ensure nobody else is adding to the metadata.
13136 // - This function still takes its own locks to cooperate with the Debugger's out-of-process access.
13137 // The debugger can slip this thread outside the locks to ensure the data is consistent.
13139 // This does not raise a debug notification to invalidate the metadata. Reasoning is that this only
13140 // happens in two cases:
13141 // 1) manifest module is updated with the name of a new dynamic module.
13142 // 2) on each class load, in which case we already send a debug event. In this case, we already send a
13143 // class-load notification, so sending a separate "metadata-refresh" would make the eventing twice as
13144 // chatty. Class-load events are high-volume and events are slow.
13145 // Thus we can avoid the chatiness by ensuring the debugger knows that Class-load also means "refresh
13148 void ReflectionModule::CaptureModuleMetaDataToMemory()
13157 // If we've suppresed metadata capture, then skip this. We'll recapture when we enable it. This allows
13158 // for batching up capture.
13159 // If a debugger is attached, then the CLR will still send ClassLoad notifications for dynamic modules,
13160 // which mean we still need to keep the metadata available. This is the same as Whidbey.
13161 // An alternative (and better) design would be to suppress ClassLoad notifications too, but then we'd
13162 // need some way of sending a "catchup" notification to the debugger after we re-enable notifications.
13163 if (IsMetadataCaptureSuppressed() && !CORDebuggerAttached())
13168 // Do not release the emitter. This is a weak reference.
13169 IMetaDataEmit *pEmitter = this->GetEmitter();
13170 _ASSERTE(pEmitter != NULL);
13174 MDUpdateModeHolder hMDUpdateMode;
13175 IfFailThrow(hMDUpdateMode.SetMDUpdateMode(pEmitter, MDUpdateExtension));
13176 _ASSERTE(hMDUpdateMode.GetOriginalMDUpdateMode() == MDUpdateFull);
13179 hr = pEmitter->GetSaveSize(cssQuick, &numBytes);
13182 // Operate on local data, and then persist it into the module once we know it's valid.
13183 NewHolder<SBuffer> pBuffer(new SBuffer());
13184 _ASSERTE(pBuffer != NULL); // allocation would throw first
13186 // ReflectionModule is still in a consistent state, and now we're just operating on local data to
13187 // assemble the new metadata buffer. If this fails, then worst case is that metadata does not include
13188 // recently generated classes.
13190 // Caller ensures serialization that guarantees that the metadata doesn't grow underneath us.
13191 BYTE * pRawData = pBuffer->OpenRawBuffer(numBytes);
13192 hr = pEmitter->SaveToMemory(pRawData, numBytes);
13193 pBuffer->CloseRawBuffer();
13197 // Now that we're successful, transfer ownership back into the module.
13199 CrstHolder ch(&m_CrstLeafLock);
13201 delete m_pDynamicMetadata;
13203 m_pDynamicMetadata = pBuffer.Extract();
13208 hr = hMDUpdateMode.Release(MDUpdateExtension);
13209 // Will be S_FALSE if someone changed the MDUpdateMode (from MDUpdateExtension) meanwhile
13210 _ASSERTE(hr == S_OK);
13213 // Suppress the eager metadata serialization.
13216 // This casues code:ReflectionModule.CaptureModuleMetaDataToMemory to be a nop.
13217 // This is not nestable.
13218 // This exists purely for performance reasons.
13220 // Don't call this directly. Use a SuppressMetadataCaptureHolder holder to ensure it's
13221 // balanced with code:ReflectionModule.ResumeMetadataCapture
13223 // Types generating while eager metadata-capture is suppressed should not actually be executed until
13224 // after metadata capture is restored.
13225 void ReflectionModule::SuppressMetadataCapture()
13227 LIMITED_METHOD_CONTRACT;
13228 // If this fires, then you probably missed a call to ResumeMetadataCapture.
13229 CONSISTENCY_CHECK_MSG(!m_fSuppressMetadataCapture, "SuppressMetadataCapture is not nestable");
13230 m_fSuppressMetadataCapture = true;
13233 // Resumes eager metadata serialization.
13236 // This casues code:ReflectionModule.CaptureModuleMetaDataToMemory to resume eagerly serializing metadata.
13237 // This must be called after code:ReflectionModule.SuppressMetadataCapture.
13239 void ReflectionModule::ResumeMetadataCapture()
13241 WRAPPER_NO_CONTRACT;
13242 _ASSERTE(m_fSuppressMetadataCapture);
13243 m_fSuppressMetadataCapture = false;
13245 CaptureModuleMetaDataToMemory();
13248 void ReflectionModule::ReleaseILData()
13250 WRAPPER_NO_CONTRACT;
13252 if (m_pISymUnmanagedWriter)
13254 m_pISymUnmanagedWriter->Release();
13255 m_pISymUnmanagedWriter = NULL;
13258 Module::ReleaseILData();
13260 #endif // !CROSSGEN_COMPILE
13262 #endif // !DACCESS_COMPILE
13264 #ifdef DACCESS_COMPILE
13265 // Accessor to expose m_pDynamicMetadata to debugger.
13268 // Pointer to SBuffer containing metadata buffer. May be null.
13271 // Only used by the debugger, so only accessible via DAC.
13272 // The buffer is updated via code:ReflectionModule.CaptureModuleMetaDataToMemory
13273 PTR_SBuffer ReflectionModule::GetDynamicMetadataBuffer() const
13277 // If we ask for metadata, but have been suppressing capture, then we're out of date.
13278 // However, the debugger may be debugging already baked types in the module and so may need the metadata
13279 // for that. So we return what we do have.
13281 // Debugger will get the next metadata update:
13282 // 1) with the next load class
13283 // 2) or if this is right after the last class, see code:ReflectionModule.CaptureModuleMetaDataToMemory
13285 return m_pDynamicMetadata;
13289 TADDR ReflectionModule::GetIL(RVA il) // virtual
13291 #ifndef DACCESS_COMPILE
13292 WRAPPER_NO_CONTRACT;
13294 BYTE* pByte = NULL;
13295 m_pCeeFileGen->GetMethodBuffer(il, &pByte);
13296 return TADDR(pByte);
13297 #else // DACCESS_COMPILE
13301 #endif // DACCESS_COMPILE
13304 PTR_VOID ReflectionModule::GetRvaField(RVA field, BOOL fZapped) // virtual
13306 _ASSERTE(!fZapped);
13307 #ifndef DACCESS_COMPILE
13308 WRAPPER_NO_CONTRACT;
13309 // This function should be call only if the target is a field or a field with RVA.
13310 PTR_BYTE pByte = NULL;
13311 m_pCeeFileGen->ComputePointer(m_sdataSection, field, &pByte);
13312 return dac_cast<PTR_VOID>(pByte);
13313 #else // DACCESS_COMPILE
13317 #endif // DACCESS_COMPILE
13320 #ifndef DACCESS_COMPILE
13322 // ===========================================================================
13324 // ===========================================================================
13326 //==========================================================================
13327 // Enregisters a VASig.
13328 //==========================================================================
13329 VASigCookie *Module::GetVASigCookie(Signature vaSignature)
13331 CONTRACT(VASigCookie*)
13337 POSTCONDITION(CheckPointer(RETVAL));
13338 INJECT_FAULT(COMPlusThrowOM());
13342 VASigCookieBlock *pBlock;
13343 VASigCookie *pCookie;
13347 // First, see if we already enregistered this sig.
13348 // Note that we're outside the lock here, so be a bit careful with our logic
13349 for (pBlock = m_pVASigCookieBlock; pBlock != NULL; pBlock = pBlock->m_Next)
13351 for (UINT i = 0; i < pBlock->m_numcookies; i++)
13353 if (pBlock->m_cookies[i].signature.GetRawSig() == vaSignature.GetRawSig())
13355 pCookie = &(pBlock->m_cookies[i]);
13363 // If not, time to make a new one.
13365 // Compute the size of args first, outside of the lock.
13367 // @TODO GENERICS: We may be calling a varargs method from a
13368 // generic type/method. Using an empty context will make such a
13369 // case cause an unexpected exception. To make this work,
13370 // we need to create a specialized signature for every instantiation
13371 SigTypeContext typeContext;
13373 MetaSig metasig(vaSignature, this, &typeContext);
13374 ArgIterator argit(&metasig);
13376 // Upper estimate of the vararg size
13377 DWORD sizeOfArgs = argit.SizeOfArgStack();
13379 // enable gc before taking lock
13381 CrstHolder ch(&m_Crst);
13383 // Note that we were possibly racing to create the cookie, and another thread
13384 // may have already created it. We could put another check
13385 // here, but it's probably not worth the effort, so we'll just take an
13386 // occasional duplicate cookie instead.
13388 // Is the first block in the list full?
13389 if (m_pVASigCookieBlock && m_pVASigCookieBlock->m_numcookies
13390 < VASigCookieBlock::kVASigCookieBlockSize)
13392 // Nope, reserve a new slot in the existing block.
13393 pCookie = &(m_pVASigCookieBlock->m_cookies[m_pVASigCookieBlock->m_numcookies]);
13397 // Yes, create a new block.
13398 VASigCookieBlock *pNewBlock = new VASigCookieBlock();
13400 pNewBlock->m_Next = m_pVASigCookieBlock;
13401 pNewBlock->m_numcookies = 0;
13402 m_pVASigCookieBlock = pNewBlock;
13403 pCookie = &(pNewBlock->m_cookies[0]);
13406 // Now, fill in the new cookie (assuming we had enough memory to create one.)
13407 pCookie->pModule = this;
13408 pCookie->pNDirectILStub = NULL;
13409 pCookie->sizeOfArgs = sizeOfArgs;
13410 pCookie->signature = vaSignature;
13412 // Finally, now that it's safe for asynchronous readers to see it,
13413 // update the count.
13414 m_pVASigCookieBlock->m_numcookies++;
13421 // ===========================================================================
13423 // ===========================================================================
13424 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
13426 int __cdecl LookupMapBase::HotItem::Cmp(const void* a_, const void* b_)
13428 LIMITED_METHOD_CONTRACT;
13429 const HotItem *a = (const HotItem *)a_;
13430 const HotItem *b = (const HotItem *)b_;
13432 if (a->rid < b->rid)
13434 else if (a->rid > b->rid)
13440 void LookupMapBase::CreateHotItemList(DataImage *image, CorProfileData *profileData, int table, BOOL fSkipNullEntries /*= FALSE*/)
13442 STANDARD_VM_CONTRACT;
13443 _ASSERTE(!MapIsCompressed());
13447 DWORD numInTokenList = profileData->GetHotTokens(table, 1<<RidMap, 1<<RidMap, NULL, 0);
13449 if (numInTokenList > 0)
13451 HotItem *itemList = (HotItem*)(void*)image->GetModule()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(HotItem)) * S_SIZE_T(numInTokenList));
13452 mdToken *tokenList = (mdToken*)(void*)image->GetModule()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(mdToken)) * S_SIZE_T(numInTokenList));
13454 profileData->GetHotTokens(table, 1<<RidMap, 1<<RidMap, tokenList, numInTokenList);
13455 DWORD numItems = 0;
13456 for (DWORD i = 0; i < numInTokenList; i++)
13458 DWORD rid = RidFromToken(tokenList[i]);
13459 TADDR value = RelativePointer<TADDR>::GetValueMaybeNullAtPtr(dac_cast<TADDR>(GetElementPtr(RidFromToken(tokenList[i]))));
13460 if (!fSkipNullEntries || value != NULL)
13462 itemList[numItems].rid = rid;
13463 itemList[numItems].value = value;
13470 qsort(itemList, // start of array
13471 numItems, // array size in elements
13472 sizeof(HotItem), // element size in bytes
13473 HotItem::Cmp); // comparer function
13475 // Eliminate any duplicates in the list. Due to the qsort, they must be adjacent now.
13476 // We do this by walking the array and copying entries that are not duplicates of the previous one.
13477 // We can start the loop at +1, because 0 is not a duplicate of the previous entry, and does not
13478 // need to be copied either.
13480 for (DWORD i = 1; i < numItems; i++)
13482 if (itemList[i].rid != itemList[i-1].rid)
13484 itemList[j].rid = itemList[i].rid;
13485 itemList[j].value = itemList[i].value;
13489 _ASSERTE(j <= numItems);
13492 // We have treated the values as normal TADDRs to let qsort move them around freely.
13493 // Fix them up to be the relative pointers now.
13494 for (DWORD ii = 0; ii < numItems; ii++)
13496 if (itemList[ii].value != NULL)
13498 RelativePointer<TADDR> *pRelPtr = (RelativePointer<TADDR> *)&itemList[ii].value;
13499 pRelPtr->SetValueMaybeNull(itemList[ii].value);
13503 if (itemList != NULL)
13504 image->StoreStructure(itemList, sizeof(HotItem)*numItems,
13505 DataImage::ITEM_RID_MAP_HOT);
13507 hotItemList = itemList;
13508 dwNumHotItems = numItems;
13514 void LookupMapBase::Save(DataImage *image, DataImage::ItemKind kind, CorProfileData *profileData, int table, BOOL fCopyValues /*= FALSE*/)
13516 STANDARD_VM_CONTRACT;
13518 // the table index that comes in is a token mask, the upper 8 bits are the table type for the tokens, that's all we want
13522 hotItemList = NULL;
13526 // Because we use the same IBC encoding to record a touch to the m_GenericTypeDefToCanonMethodTableMap as
13527 // to the m_TypeDefToMethodTableMap, the hot items we get in both will be the union of the touches. This limitation
13528 // in the IBC infrastructure does not hurt us much because touching an entry for a generic type in one map often if
13529 // not always implies touching the corresponding entry in the other. But when saving the GENERICTYPEDEF_MAP it
13530 // does mean that we need to be prepared to see "hot" items whose data is NULL in this map (specifically, the non-
13531 // generic types). We don't want the hot list to be unnecessarily big with these entries, so tell CreateHotItemList to
13533 BOOL fSkipNullEntries = (kind == DataImage::ITEM_GENERICTYPEDEF_MAP);
13534 CreateHotItemList(image, profileData, table, fSkipNullEntries);
13537 // Determine whether we want to compress this lookup map (to improve density of cold pages in the map on
13538 // hot item cache misses). We only enable this optimization for the TypeDefToMethodTable, the
13539 // GenericTypeDefToCanonMethodTable, and the MethodDefToDesc maps since (a) they're the largest and
13540 // as a result reap the most space savings and (b) these maps are fully populated in an ngen image and immutable
13541 // at runtime, something that's important when dealing with a compressed version of the table.
13542 if (kind == DataImage::ITEM_TYPEDEF_MAP || kind == DataImage::ITEM_GENERICTYPEDEF_MAP || kind == DataImage::ITEM_METHODDEF_MAP)
13544 // The bulk of the compression work is done in the later stages of ngen image generation (since it
13545 // relies on knowing the final RVAs of each value stored in the table). So we create a specialzed
13546 // ZapNode that knows how to perform the compression for us.
13547 image->StoreCompressedLayoutMap(this, DataImage::ITEM_COMPRESSED_MAP);
13549 // We need to know we decided to compress during the Fixup stage but the table kind is not available
13550 // there. So we use the cIndexEntryBits field as a flag (this will be initialized to zero and is only
13551 // set to a meaningful value near the end of ngen image generation, during the compression of the
13553 cIndexEntryBits = 1;
13555 // The ZapNode we allocated above takes care of all the rest of the processing for this map, so we're
13560 SaveUncompressedMap(image, kind, fCopyValues);
13563 void LookupMapBase::SaveUncompressedMap(DataImage *image, DataImage::ItemKind kind, BOOL fCopyValues /*= FALSE*/)
13565 STANDARD_VM_CONTRACT;
13567 // We should only be calling this once per map
13568 _ASSERTE(!image->IsStored(pTable));
13571 // We will only store one (big) node instead of the full list,
13572 // and make the one node large enough to fit all the RIDs
13575 ZapStoredStructure * pTableNode = image->StoreStructure(NULL, GetSize() * sizeof(TADDR), kind);
13577 LookupMapBase *map = this;
13578 DWORD offsetIntoCombo = 0;
13579 while (map != NULL)
13581 DWORD len = map->dwCount * sizeof(void*);
13584 image->CopyDataToOffset(pTableNode, offsetIntoCombo, map->pTable, len);
13586 image->BindPointer(map->pTable,pTableNode,offsetIntoCombo);
13587 offsetIntoCombo += len;
13592 void LookupMapBase::ConvertSavedMapToUncompressed(DataImage *image, DataImage::ItemKind kind)
13594 STANDARD_VM_CONTRACT;
13596 // Check whether we decided to compress this map (see Save() above).
13597 if (cIndexEntryBits == 0)
13600 cIndexEntryBits = 0;
13601 SaveUncompressedMap(image, kind);
13604 void LookupMapBase::Fixup(DataImage *image, BOOL fFixupEntries /*=TRUE*/)
13606 STANDARD_VM_CONTRACT;
13608 if (hotItemList != NULL)
13609 image->FixupPointerField(this, offsetof(LookupMapBase, hotItemList));
13611 // Find the biggest RID supported by the entire list of LookupMaps.
13612 // We will only store one LookupMap node instead of the full list,
13613 // and make it big enough to fit all RIDs.
13614 *(DWORD *)image->GetImagePointer(this, offsetof(LookupMapBase, dwCount)) = GetSize();
13616 // Persist the supportedFlags that this particular instance was created with.
13617 *(TADDR *)image->GetImagePointer(this, offsetof(LookupMapBase, supportedFlags)) = supportedFlags;
13619 image->ZeroPointerField(this, offsetof(LookupMapBase, pNext));
13621 // Check whether we've decided to compress this map (see Save() above).
13622 if (cIndexEntryBits == 1)
13624 // In the compressed case most of the Fixup logic is performed by the specialized ZapNode we allocated
13625 // during Save(). But we still have to record fixups for any hot items we've cached (these aren't
13627 for (DWORD i = 0; i < dwNumHotItems; i++)
13629 TADDR *pHotValueLoc = &hotItemList[i].value;
13630 TADDR pHotValue = RelativePointer<TADDR>::GetValueMaybeNullAtPtr((TADDR)pHotValueLoc);
13631 TADDR flags = pHotValue & supportedFlags;
13632 pHotValue -= flags;
13634 if (image->IsStored((PVOID)pHotValue))
13636 image->FixupField(hotItemList,
13637 (BYTE *)pHotValueLoc - (BYTE *)hotItemList,
13638 (PVOID)pHotValue, flags, IMAGE_REL_BASED_RelativePointer);
13642 image->ZeroPointerField(hotItemList, (BYTE *)pHotValueLoc - (BYTE *)hotItemList);
13646 // The ZapNode will handle everything else so we're done.
13650 // Note that the caller is responsible for calling FixupPointerField()
13651 // or zeroing out the contents of pTable as appropriate
13652 image->FixupPointerField(this, offsetof(LookupMapBase, pTable));
13656 LookupMap<PVOID>::Iterator iter((LookupMap<PVOID> *)this);
13659 while (iter.Next())
13662 PVOID p = iter.GetElementAndFlags(&flags);
13663 PTR_TADDR hotItemValuePtr = FindHotItemValuePtr(rid);
13665 if (image->IsStored(p))
13667 image->FixupField(pTable, rid * sizeof(TADDR),
13668 p, flags, IMAGE_REL_BASED_RelativePointer);
13670 // In case this item is also in the hot item subtable, fix it up there as well
13671 if (hotItemValuePtr != NULL)
13672 image->FixupField(hotItemList,
13673 (BYTE *)hotItemValuePtr - (BYTE *)hotItemList,
13674 p, flags, IMAGE_REL_BASED_RelativePointer);
13678 image->ZeroPointerField(pTable, rid * sizeof(TADDR));
13679 // In case this item is also in the hot item subtable, zero it there as well
13680 if (hotItemValuePtr != NULL)
13681 image->ZeroPointerField(hotItemList,
13682 (BYTE *)hotItemValuePtr - (BYTE *)hotItemList);
13689 #endif // FEATURE_NATIVE_IMAGE_GENERATION
13691 #endif // !DACCESS_COMPILE
13693 #ifdef DACCESS_COMPILE
13696 LookupMapBase::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
13712 DacEnumHostDPtrMem(this);
13714 if (pTable.IsValid())
13716 #ifdef FEATURE_PREJIT
13717 if (MapIsCompressed())
13719 // Compressed maps have tables whose size cannot be calculated cheaply. Plus they have an
13720 // additional index blob.
13721 DacEnumMemoryRegion(dac_cast<TADDR>(pTable),
13723 DacEnumMemoryRegion(dac_cast<TADDR>(pIndex),
13727 #endif // FEATURE_PREJIT
13728 DacEnumMemoryRegion(dac_cast<TADDR>(pTable),
13729 dwCount * sizeof(TADDR));
13731 #ifdef FEATURE_PREJIT
13732 if (dwNumHotItems && hotItemList.IsValid())
13734 DacEnumMemoryRegion(dac_cast<TADDR>(hotItemList),
13735 dwNumHotItems * sizeof(HotItem));
13737 #endif // FEATURE_PREJIT
13743 LookupMapBase::ListEnumMemoryRegions(CLRDataEnumMemoryFlags flags)
13755 LookupMapBase * headMap = this;
13756 bool enumHead = false;
13759 headMap->EnumMemoryRegions(flags, enumHead);
13761 if (!headMap->pNext.IsValid())
13766 headMap = headMap->pNext;
13771 #endif // DACCESS_COMPILE
13774 // Optimization intended for Module::EnsureActive only
13775 #include <optsmallperfcritical.h>
13777 #ifndef DACCESS_COMPILE
13778 VOID Module::EnsureActive()
13787 GetDomainFile()->EnsureActive();
13789 #endif // DACCESS_COMPILE
13791 #include <optdefault.h>
13794 #ifndef DACCESS_COMPILE
13796 VOID Module::EnsureAllocated()
13806 GetDomainFile()->EnsureAllocated();
13809 VOID Module::EnsureLibraryLoaded()
13811 STANDARD_VM_CONTRACT;
13812 GetDomainFile()->EnsureLibraryLoaded();
13814 #endif // !DACCESS_COMPILE
13816 CHECK Module::CheckActivated()
13826 #ifndef DACCESS_COMPILE
13827 DomainFile *pDomainFile = FindDomainFile(GetAppDomain());
13828 CHECK(pDomainFile != NULL);
13829 PREFIX_ASSUME(pDomainFile != NULL);
13830 CHECK(pDomainFile->CheckActivated());
13835 #ifdef DACCESS_COMPILE
13838 ModuleCtorInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
13842 // This class is contained so do not enumerate 'this'.
13843 DacEnumMemoryRegion(dac_cast<TADDR>(ppMT), numElements *
13844 sizeof(RelativePointer<MethodTable *>));
13845 DacEnumMemoryRegion(dac_cast<TADDR>(cctorInfoHot), numElementsHot *
13846 sizeof(ClassCtorInfoEntry));
13847 DacEnumMemoryRegion(dac_cast<TADDR>(cctorInfoCold),
13848 (numElements - numElementsHot) *
13849 sizeof(ClassCtorInfoEntry));
13850 DacEnumMemoryRegion(dac_cast<TADDR>(hotHashOffsets), numHotHashes *
13852 DacEnumMemoryRegion(dac_cast<TADDR>(coldHashOffsets), numColdHashes *
13856 void Module::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
13873 EMEM_OUT(("MEM: %p Module\n", dac_cast<TADDR>(this)));
13876 //Save module id data only if it a real pointer, not a tagged sugestion to use ModuleIndex.
13877 if (!Module::IsEncodedModuleIndex(GetModuleID()))
13879 if (m_ModuleID.IsValid())
13881 m_ModuleID->EnumMemoryRegions(flags);
13885 // TODO: Enumerate DomainLocalModules? It's not clear if we need all AppDomains
13886 // in the multi-domain case (where m_ModuleID has it's low-bit set).
13887 if (m_file.IsValid())
13889 m_file->EnumMemoryRegions(flags);
13891 if (m_pAssembly.IsValid())
13893 m_pAssembly->EnumMemoryRegions(flags);
13896 m_TypeRefToMethodTableMap.ListEnumMemoryRegions(flags);
13897 m_TypeDefToMethodTableMap.ListEnumMemoryRegions(flags);
13899 if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
13901 if (m_pAvailableClasses.IsValid())
13903 m_pAvailableClasses->EnumMemoryRegions(flags);
13905 if (m_pAvailableParamTypes.IsValid())
13907 m_pAvailableParamTypes->EnumMemoryRegions(flags);
13909 if (m_pInstMethodHashTable.IsValid())
13911 m_pInstMethodHashTable->EnumMemoryRegions(flags);
13913 if (m_pAvailableClassesCaseIns.IsValid())
13915 m_pAvailableClassesCaseIns->EnumMemoryRegions(flags);
13917 #ifdef FEATURE_PREJIT
13918 if (m_pStubMethodHashTable.IsValid())
13920 m_pStubMethodHashTable->EnumMemoryRegions(flags);
13922 #endif // FEATURE_PREJIT
13923 if (m_pBinder.IsValid())
13925 m_pBinder->EnumMemoryRegions(flags);
13927 m_ModuleCtorInfo.EnumMemoryRegions(flags);
13929 // Save the LookupMap structures.
13930 m_MethodDefToDescMap.ListEnumMemoryRegions(flags);
13931 m_FieldDefToDescMap.ListEnumMemoryRegions(flags);
13932 m_pMemberRefToDescHashTable->EnumMemoryRegions(flags);
13933 m_GenericParamToDescMap.ListEnumMemoryRegions(flags);
13934 m_GenericTypeDefToCanonMethodTableMap.ListEnumMemoryRegions(flags);
13935 m_FileReferencesMap.ListEnumMemoryRegions(flags);
13936 m_ManifestModuleReferencesMap.ListEnumMemoryRegions(flags);
13937 m_MethodDefToPropertyInfoMap.ListEnumMemoryRegions(flags);
13939 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
13940 while (typeDefIter.Next())
13942 if (typeDefIter.GetElement())
13944 typeDefIter.GetElement()->EnumMemoryRegions(flags);
13948 LookupMap<PTR_TypeRef>::Iterator typeRefIter(&m_TypeRefToMethodTableMap);
13949 while (typeRefIter.Next())
13951 if (typeRefIter.GetElement())
13953 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(typeRefIter.GetElement()));
13954 th.EnumMemoryRegions(flags);
13958 LookupMap<PTR_MethodDesc>::Iterator methodDefIter(&m_MethodDefToDescMap);
13959 while (methodDefIter.Next())
13961 if (methodDefIter.GetElement())
13963 methodDefIter.GetElement()->EnumMemoryRegions(flags);
13967 LookupMap<PTR_FieldDesc>::Iterator fieldDefIter(&m_FieldDefToDescMap);
13968 while (fieldDefIter.Next())
13970 if (fieldDefIter.GetElement())
13972 fieldDefIter.GetElement()->EnumMemoryRegions(flags);
13976 LookupMap<PTR_TypeVarTypeDesc>::Iterator genericParamIter(&m_GenericParamToDescMap);
13977 while (genericParamIter.Next())
13979 if (genericParamIter.GetElement())
13981 genericParamIter.GetElement()->EnumMemoryRegions(flags);
13985 LookupMap<PTR_MethodTable>::Iterator genericTypeDefIter(&m_GenericTypeDefToCanonMethodTableMap);
13986 while (genericTypeDefIter.Next())
13988 if (genericTypeDefIter.GetElement())
13990 genericTypeDefIter.GetElement()->EnumMemoryRegions(flags);
13994 } // !CLRDATA_ENUM_MEM_MINI && !CLRDATA_ENUM_MEM_TRIAGE
13997 LookupMap<PTR_Module>::Iterator fileRefIter(&m_FileReferencesMap);
13998 while (fileRefIter.Next())
14000 if (fileRefIter.GetElement())
14002 fileRefIter.GetElement()->EnumMemoryRegions(flags, true);
14006 LookupMap<PTR_Module>::Iterator asmRefIter(&m_ManifestModuleReferencesMap);
14007 while (asmRefIter.Next())
14009 if (asmRefIter.GetElement())
14011 asmRefIter.GetElement()->GetAssembly()->EnumMemoryRegions(flags);
14015 ECall::EnumFCallMethods();
14018 FieldDesc *Module::LookupFieldDef(mdFieldDef token)
14020 WRAPPER_NO_CONTRACT;
14021 _ASSERTE(TypeFromToken(token) == mdtFieldDef);
14022 g_IBCLogger.LogRidMapAccess( MakePair( this, token ) );
14023 return m_FieldDefToDescMap.GetElement(RidFromToken(token));
14026 #endif // DACCESS_COMPILE
14032 //-------------------------------------------------------------------------------
14033 // Make best-case effort to obtain an image name for use in an error message.
14035 // This routine must expect to be called before the this object is fully loaded.
14036 // It can return an empty if the name isn't available or the object isn't initialized
14037 // enough to get a name, but it mustn't crash.
14038 //-------------------------------------------------------------------------------
14039 LPCWSTR Module::GetPathForErrorMessages()
14045 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
14049 PEFile *pFile = GetFile();
14053 return pFile->GetPathForErrorMessages();
14061 #if defined(_DEBUG) && !defined(DACCESS_COMPILE) && !defined(CROSS_COMPILE)
14062 void Module::ExpandAll()
14072 //This is called from inside EEStartupHelper, so it breaks the SO rules. However, this is debug only
14073 //(and only supported for limited jit testing), so it's ok here.
14074 CONTRACT_VIOLATION(SOToleranceViolation);
14076 //If the EE isn't started yet, it's not safe to jit. We fail in COM jitting a p/invoke.
14081 static void CompileMethodDesc(MethodDesc * pMD)
14083 //Must have a method body
14084 if (pMD->HasILHeader()
14085 //Can't jit open instantiations
14086 && !pMD->IsGenericMethodDefinition()
14087 //These are the only methods we can jit
14088 && (pMD->IsStatic() || pMD->GetNumGenericMethodArgs() == 0
14089 || pMD->HasClassInstantiation())
14090 && (pMD->MayHaveNativeCode() && !pMD->IsFCallOrIntrinsic()))
14092 pMD->PrepareInitialCode();
14095 static void CompileMethodsForMethodTable(MethodTable * pMT)
14097 MethodTable::MethodIterator it(pMT);
14098 for (; it.IsValid(); it.Next())
14100 MethodDesc * pMD = it.GetMethodDesc();
14101 CompileMethodDesc(pMD);
14105 static void CompileMethodsForTypeDef(Module * pModule, mdTypeDef td)
14107 TypeHandle th = ClassLoader::LoadTypeDefThrowing(pModule, td, ClassLoader::ThrowIfNotFound,
14108 ClassLoader::PermitUninstDefOrRef);
14110 MethodTable * pMT = th.GetMethodTable();
14111 CompileMethodsForMethodTable(pMT);
14114 static void CompileMethodsForTypeDefRefSpec(Module * pModule, mdToken tok)
14121 th = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
14124 NULL /*SigTypeContext*/);
14128 hr = GET_EXCEPTION()->GetHR();
14130 EX_END_CATCH(SwallowAllExceptions);
14132 //Only do this for non-generic types and unshared generic types
14133 //(canonical generics and value type generic instantiations).
14134 if (SUCCEEDED(hr) && !th.IsTypeDesc()
14135 && th.AsMethodTable()->IsCanonicalMethodTable())
14137 CompileMethodsForMethodTable(th.AsMethodTable());
14140 static void CompileMethodsForMethodDefRefSpec(Module * pModule, mdToken tok)
14146 MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(pModule, tok,
14147 /*SigTypeContext*/NULL,
14149 CompileMethodDesc(pMD);
14153 hr = GET_EXCEPTION()->GetHR();
14154 //@telesto what should we do with this HR? the Silverlight code doesn't seem
14155 //to do anything...but that doesn't seem safe...
14157 EX_END_CATCH(SwallowAllExceptions);
14160 //Jit all methods eagerly
14162 IMDInternalImport * pMDI = GetMDImport();
14163 HENUMTypeDefInternalHolder hEnum(pMDI);
14165 hEnum.EnumTypeDefInit();
14167 //verify global methods
14168 if (GetGlobalMethodTable())
14170 //jit everything in the MT.
14171 Local::CompileMethodsForTypeDefRefSpec(this, COR_GLOBAL_PARENT_TOKEN);
14173 while (pMDI->EnumTypeDefNext(&hEnum, &td))
14176 Local::CompileMethodsForTypeDefRefSpec(this, td);
14179 //Get the type refs. They're always awesome.
14180 HENUMInternalHolder hEnumTypeRefs(pMDI);
14183 hEnumTypeRefs.EnumAllInit(mdtTypeRef);
14184 while (hEnumTypeRefs.EnumNext(&tr))
14186 Local::CompileMethodsForTypeDefRefSpec(this, tr);
14189 //make sure to get the type specs
14190 HENUMInternalHolder hEnumTypeSpecs(pMDI);
14193 hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
14194 while (hEnumTypeSpecs.EnumNext(&ts))
14196 Local::CompileMethodsForTypeDefRefSpec(this, ts);
14200 //And now for the interesting generic methods
14201 HENUMInternalHolder hEnumMethodSpecs(pMDI);
14204 hEnumMethodSpecs.EnumAllInit(mdtMethodSpec);
14205 while (hEnumMethodSpecs.EnumNext(&ms))
14207 Local::CompileMethodsForMethodDefRefSpec(this, ms);
14210 #endif //_DEBUG && !DACCESS_COMPILE && !CROSS_COMPILE
14212 //-------------------------------------------------------------------------------
14214 // Verify consistency of asmconstants.h
14216 // Wrap all C_ASSERT's in asmconstants.h with a class definition. Many of the
14217 // fields referenced below are private, and this class is a friend of the
14218 // enclosing type. (A C_ASSERT isn't a compiler intrinsic, just a magic
14219 // typedef that produces a compiler error when the condition is false.)
14220 #include "clrvarargs.h" /* for VARARG C_ASSERTs in asmconstants.h */
14221 class CheckAsmOffsets
14223 #ifndef CROSSBITNESS_COMPILE
14224 #define ASMCONSTANTS_C_ASSERT(cond) static_assert(cond, #cond);
14225 #include "asmconstants.h"
14226 #endif // CROSSBITNESS_COMPILE
14229 //-------------------------------------------------------------------------------
14231 #ifndef DACCESS_COMPILE
14233 void Module::CreateAssemblyRefByNameTable(AllocMemTracker *pamTracker)
14239 INJECT_FAULT(COMPlusThrowOM(););
14243 LoaderHeap * pHeap = GetLoaderAllocator()->GetLowFrequencyHeap();
14244 IMDInternalImport * pImport = GetMDImport();
14246 DWORD dwMaxRid = pImport->GetCountWithTokenKind(mdtAssemblyRef);
14250 S_SIZE_T dwAllocSize = S_SIZE_T(sizeof(LPWSTR)) * S_SIZE_T(dwMaxRid);
14251 m_AssemblyRefByNameTable = (LPCSTR *) pamTracker->Track( pHeap->AllocMem(dwAllocSize) );
14254 for (DWORD rid=1; rid <= dwMaxRid; rid++)
14256 mdAssemblyRef mdToken = TokenFromRid(rid,mdtAssemblyRef);
14260 hr = pImport->GetAssemblyRefProps(mdToken, NULL, NULL, &szName, NULL, NULL, NULL, NULL);
14264 m_AssemblyRefByNameTable[dwCount++] = szName;
14267 m_AssemblyRefByNameCount = dwCount;
14270 bool Module::HasReferenceByName(LPCUTF8 pModuleName)
14272 LIMITED_METHOD_CONTRACT;
14274 for (DWORD i=0; i < m_AssemblyRefByNameCount; i++)
14276 if (0 == strcmp(pModuleName, m_AssemblyRefByNameTable[i]))
14285 #pragma warning(pop)
14286 #endif // _MSC_VER: warning C4244
14288 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
14289 NOINLINE void NgenForceFailure_AV()
14291 LIMITED_METHOD_CONTRACT;
14292 static int* alwaysNull = 0;
14296 NOINLINE void NgenForceFailure_TypeLoadException()
14298 WRAPPER_NO_CONTRACT;
14299 ::ThrowTypeLoadException("ForceIBC", "Failure", W("Assembly"), NULL, IDS_CLASSLOAD_BADFORMAT);
14302 void EEConfig::DebugCheckAndForceIBCFailure(BitForMask bitForMask)
14311 static DWORD s_ibcCheckCount = 0;
14313 // Both of these must be set to non-zero values for us to force a failure
14315 if ((NgenForceFailureCount() == 0) || (NgenForceFailureKind() == 0))
14318 // The bitForMask value must also beset in the FailureMask
14320 if ((((DWORD) bitForMask) & NgenForceFailureMask()) == 0)
14324 if (s_ibcCheckCount < NgenForceFailureCount())
14327 // We force one failure every NgenForceFailureCount()
14329 s_ibcCheckCount = 0;
14330 switch (NgenForceFailureKind())
14333 NgenForceFailure_TypeLoadException();
14336 NgenForceFailure_AV();
14340 #endif // defined(_DEBUG) && !defined(DACCESS_COMPILE)