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"
26 #include "dbginterface.h"
27 #include "dllimport.h"
28 #include "eeprofinterfaces.h"
29 #include "perfcounters.h"
31 #include "jitinterface.h"
33 #include "dllimportcallback.h"
34 #include "contractimpl.h"
36 #include "instmethhash.h"
37 #include "virtualcallstub.h"
38 #include "typestring.h"
39 #include "stringliteralmap.h"
40 #include <formattype.h>
41 #include "fieldmarshaler.h"
42 #include "sigbuilder.h"
44 #include "metadataexports.h"
45 #include "inlinetracking.h"
47 #ifdef FEATURE_REMOTING
49 #include "crossdomaincalls.h"
50 #include "objectclone.h"
54 #include "exceptionhandling.h"
55 #include "corcompile.h"
57 #include "nibblestream.h"
59 #endif //FEATURE_PREJIT
61 #ifdef FEATURE_COMINTEROP
62 #include "runtimecallablewrapper.h"
63 #include "comcallablewrapper.h"
64 #endif //FEATURE_COMINTEROP
68 #pragma warning(disable:4724)
71 #include "ngenhash.inl"
80 #include "../md/compiler/custattr.h"
81 #include "constrainedexecutionregion.h"
83 #include "peimagelayout.inl"
84 #include "ildbsymlib.h"
86 #if defined(FEATURE_APPX_BINDER)
87 #include "clrprivbinderappx.h"
88 #endif // defined(FEATURE_APPX_BINDER)
90 #if defined(PROFILING_SUPPORTED)
91 #include "profilermetadataemitvalidator.h"
96 #pragma warning(disable:4244)
100 #define COR_VTABLE_PTRSIZED COR_VTABLE_64BIT
101 #define COR_VTABLE_NOT_PTRSIZED COR_VTABLE_32BIT
103 #define COR_VTABLE_PTRSIZED COR_VTABLE_32BIT
104 #define COR_VTABLE_NOT_PTRSIZED COR_VTABLE_64BIT
107 #define CEE_FILE_GEN_GROWTH_COLLECTIBLE 2048
109 #define NGEN_STATICS_ALLCLASSES_WERE_LOADED -1
112 //---------------------------------------------------------------------------------------
113 InstrumentedILOffsetMapping::InstrumentedILOffsetMapping()
115 LIMITED_METHOD_DAC_CONTRACT;
122 //---------------------------------------------------------------------------------------
124 // Check whether there is any mapping information stored in this object.
127 // The memory should be alive throughout the process lifetime until
128 // the Module containing the instrumented method is destructed.
131 BOOL InstrumentedILOffsetMapping::IsNull()
133 LIMITED_METHOD_DAC_CONTRACT;
135 _ASSERTE((m_cMap == 0) == (m_rgMap == NULL));
136 return (m_cMap == 0);
139 #if !defined(DACCESS_COMPILE)
140 //---------------------------------------------------------------------------------------
142 // Release the memory used by the array of COR_IL_MAPs.
145 // * The memory should be alive throughout the process lifetime until the Module containing
146 // the instrumented method is destructed.
147 // * This struct should be read-only in DAC builds.
150 void InstrumentedILOffsetMapping::Clear()
152 LIMITED_METHOD_CONTRACT;
162 #endif // !DACCESS_COMPILE
164 #if !defined(DACCESS_COMPILE)
165 void InstrumentedILOffsetMapping::SetMappingInfo(SIZE_T cMap, COR_IL_MAP * rgMap)
168 _ASSERTE((cMap == 0) == (rgMap == NULL));
170 m_rgMap = ARRAY_PTR_COR_IL_MAP(rgMap);
172 #endif // !DACCESS_COMPILE
174 SIZE_T InstrumentedILOffsetMapping::GetCount() const
176 LIMITED_METHOD_DAC_CONTRACT;
178 _ASSERTE((m_cMap == 0) == (m_rgMap == NULL));
182 ARRAY_PTR_COR_IL_MAP InstrumentedILOffsetMapping::GetOffsets() const
184 LIMITED_METHOD_DAC_CONTRACT;
186 _ASSERTE((m_cMap == 0) == (m_rgMap == NULL));
190 PTR_PersistentInlineTrackingMap Module::GetNgenInlineTrackingMap()
192 LIMITED_METHOD_DAC_CONTRACT;
193 return m_persistentInlineTrackingMap;
197 #ifndef DACCESS_COMPILE
199 #ifdef FEATURE_MIXEDMODE
201 #include <pshpack1.h>
204 VASigCookie *m_pCookie;
205 PCCOR_SIGNATURE m_pSig;
210 LIMITED_METHOD_CONTRACT;
214 BYTE m_op1; //0x58 POP eax ;;pop return address
216 BYTE m_op2; //0x68 PUSH cookie
219 BYTE m_op3; //0x50 PUSH eax ;;repush return address
221 BYTE m_op4; //0xb8 MOV eax,target
223 BYTE m_jmp; //0xe9 JMP PInvokeCalliStub
225 #else // !_TARGET_X86_
228 LIMITED_METHOD_CONTRACT;
229 PORTABILITY_ASSERT("MUThunk not implemented on this platform");
232 #endif // !_TARGET_X86_
238 // A hashtable for u->m thunks not represented in the fixup tables.
240 class MUThunkHash : public CClosedHashBase {
242 //----------------------------------------------------
243 // Hash key for CClosedHashBase
244 //----------------------------------------------------
247 PCCOR_SIGNATURE m_pSig;
251 //----------------------------------------------------
252 // Hash entry for CClosedHashBase
253 //----------------------------------------------------
256 ELEMENTSTATUS m_status;
261 MUThunkHash(Module *pModule) :
266 17, // CClosedHashTable will grow as necessary
272 m_crst(CrstMUThunkHash)
291 UTHEntry *phe = (UTHEntry*)GetFirst();
293 delete (BYTE*)phe->m_pMUThunk->m_pSig;
294 DeleteExecutable(phe->m_pMUThunk);
295 phe = (UTHEntry*)GetNext((BYTE*)phe);
302 #ifdef FEATURE_MIXEDMODE
304 LPVOID GetMUThunk(LPVOID pTarget, PCCOR_SIGNATURE pSig0, DWORD cSig)
306 STATIC_CONTRACT_THROWS;
308 // A persistent copy of the sig
309 NewArrayHolder<COR_SIGNATURE> sigHolder = new COR_SIGNATURE[cSig];
311 memcpyNoGCRefs(sigHolder.GetValue(), pSig0, cSig);
312 sigHolder[0] = IMAGE_CEE_CS_CALLCONV_STDCALL;
314 // Have to lookup cookie eagerly because once we've added a blank
315 // entry to the hashtable, it's not easy to tolerate failure.
316 VASigCookie *pCookie = m_pModule->GetVASigCookie(Signature(sigHolder, cSig));
322 sigHolder.SuppressRelease();
323 return GetMUThunkHelper(pTarget, sigHolder, cSig, pCookie);
326 LPVOID GetMUThunkHelper(LPVOID pTarget, PCCOR_SIGNATURE pSig, DWORD cSig, VASigCookie *pCookie)
334 INJECT_FAULT(COMPlusThrowOM());
335 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
340 CrstHolder ch(&m_crst);
343 key.m_pTarget = pTarget;
348 phe = (UTHEntry*)FindOrAdd((LPVOID)&key, /*modifies*/bNew);
354 phe->m_pMUThunk = new (executable) MUThunk;
355 phe->m_pMUThunk->m_pCookie = pCookie;
356 phe->m_pMUThunk->m_pSig = pSig;
357 phe->m_pMUThunk->m_pTarget = pTarget;
359 phe->m_pMUThunk->m_op1 = 0x58; //POP EAX
360 phe->m_pMUThunk->m_op2 = 0x68; //PUSH
361 phe->m_pMUThunk->m_opcookie = (UINT32)(size_t)pCookie;
362 phe->m_pMUThunk->m_op3 = 0x50; //POP EAX
363 phe->m_pMUThunk->m_op4 = 0xb8; //mov eax
364 phe->m_pMUThunk->m_optarget = (UINT32)(size_t)pTarget;
365 phe->m_pMUThunk->m_jmp = 0xe9; //jmp
366 phe->m_pMUThunk->m_jmptarg = (UINT32)(GetEEFuncEntryPoint(GenericPInvokeCalliHelper) - ((size_t)( 1 + &(phe->m_pMUThunk->m_jmptarg))));
367 #else // !_TARGET_X86_
368 PORTABILITY_ASSERT("MUThunkHash not implemented on this platform");
369 #endif // !_TARGET_X86_
372 phe->m_status = USED;
376 delete[] (BYTE*)pSig;
381 delete[] (BYTE*)pSig;
385 RETURN (LPVOID)(phe->m_pMUThunk->GetCode());
389 #endif // FEATURE_MIXEDMODE
393 // *** OVERRIDES FOR CClosedHashBase ***/
395 //*****************************************************************************
396 // Hash is called with a pointer to an element in the table. You must override
397 // this method and provide a hash algorithm for your element type.
398 //*****************************************************************************
399 virtual unsigned int Hash( // The key value.
400 void const *pData) // Raw data to hash.
402 LIMITED_METHOD_CONTRACT;
404 UTHKey *pKey = (UTHKey*)pData;
405 return (ULONG)(size_t)(pKey->m_pTarget);
409 //*****************************************************************************
410 // Compare is used in the typical memcmp way, 0 is eqaulity, -1/1 indicate
411 // direction of miscompare. In this system everything is always equal or not.
412 //*****************************************************************************
413 unsigned int Compare( // 0, -1, or 1.
414 void const *pData, // Raw key data on lookup.
415 BYTE *pElement) // The element to compare data against.
425 UTHKey *pkey1 = (UTHKey*)pData;
426 UTHKey *pkey2 = &( ((UTHEntry*)pElement)->m_key );
428 if (pkey1->m_pTarget != pkey2->m_pTarget)
431 if (S_OK != MetaSig::CompareMethodSigsNT(pkey1->m_pSig, pkey1->m_cSig, m_pModule, NULL, pkey2->m_pSig, pkey2->m_cSig, m_pModule, NULL))
437 //*****************************************************************************
438 // Return true if the element is free to be used.
439 //*****************************************************************************
440 virtual ELEMENTSTATUS Status( // The status of the entry.
441 BYTE *pElement) // The element to check.
443 LIMITED_METHOD_CONTRACT;
445 return ((UTHEntry*)pElement)->m_status;
448 //*****************************************************************************
449 // Sets the status of the given element.
450 //*****************************************************************************
451 virtual void SetStatus(
452 BYTE *pElement, // The element to set status for.
453 ELEMENTSTATUS eStatus) // New status.
455 LIMITED_METHOD_CONTRACT;
457 ((UTHEntry*)pElement)->m_status = eStatus;
460 //*****************************************************************************
461 // Returns the internal key value for an element.
462 //*****************************************************************************
463 virtual void *GetKey( // The data to hash on.
464 BYTE *pElement) // The element to return data ptr for.
466 LIMITED_METHOD_CONTRACT;
467 return (BYTE*) &(((UTHEntry*)pElement)->m_key);
475 #endif // FEATURE_MIXEDMODE
478 // ===========================================================================
480 // ===========================================================================
482 //---------------------------------------------------------------------------------------------------
483 // This wrapper just invokes the real initialization inside a try/hook.
484 // szName is not null only for dynamic modules
485 //---------------------------------------------------------------------------------------------------
486 void Module::DoInit(AllocMemTracker *pamTracker, LPCWSTR szName)
495 #ifdef PROFILING_SUPPORTED
497 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
499 g_profControlBlock.pProfInterface->ModuleLoadStarted((ModuleID) this);
502 // Need TRY/HOOK instead of holder so we can get HR of exception thrown for profiler callback
506 Initialize(pamTracker, szName);
508 #ifdef PROFILING_SUPPORTED
514 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
515 g_profControlBlock.pProfInterface->ModuleLoadFinished((ModuleID) this, GET_EXCEPTION()->GetHR());
524 // Set the given bit on m_dwTransientFlags. Return true if we won the race to set the bit.
525 BOOL Module::SetTransientFlagInterlocked(DWORD dwFlag)
527 LIMITED_METHOD_CONTRACT;
531 DWORD dwTransientFlags = m_dwTransientFlags;
532 if ((dwTransientFlags & dwFlag) != 0)
534 if ((DWORD)FastInterlockCompareExchange((LONG*)&m_dwTransientFlags, dwTransientFlags | dwFlag, dwTransientFlags) == dwTransientFlags)
539 #if PROFILING_SUPPORTED
540 void Module::NotifyProfilerLoadFinished(HRESULT hr)
547 INJECT_FAULT(COMPlusThrowOM());
552 // Note that in general we wil reuse shared modules. So we need to make sure we only notify
553 // the profiler once.
554 if (SetTransientFlagInterlocked(IS_PROFILER_NOTIFIED))
556 // Record how many types are already present
557 DWORD countTypesOrig = 0;
558 DWORD countExportedTypesOrig = 0;
561 countTypesOrig = GetMDImport()->GetCountWithTokenKind(mdtTypeDef);
562 countExportedTypesOrig = GetMDImport()->GetCountWithTokenKind(mdtExportedType);
565 // Notify the profiler, this may cause metadata to be updated
567 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
570 g_profControlBlock.pProfInterface->ModuleLoadFinished((ModuleID) this, hr);
574 g_profControlBlock.pProfInterface->ModuleAttachedToAssembly((ModuleID) this,
575 (AssemblyID)m_pAssembly);
581 // If there are more types than before, add these new types to the
585 DWORD countTypesAfterProfilerUpdate = GetMDImport()->GetCountWithTokenKind(mdtTypeDef);
586 DWORD countExportedTypesAfterProfilerUpdate = GetMDImport()->GetCountWithTokenKind(mdtExportedType);
587 // 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
588 for (DWORD typeDefRid = countTypesOrig + 2; typeDefRid < countTypesAfterProfilerUpdate + 2; typeDefRid++)
590 GetAssembly()->AddType(this, TokenFromRid(typeDefRid, mdtTypeDef));
592 // 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
593 for (DWORD exportedTypeDef = countExportedTypesOrig + 1; exportedTypeDef < countExportedTypesAfterProfilerUpdate + 1; exportedTypeDef++)
595 GetAssembly()->AddExportedType(TokenFromRid(exportedTypeDef, mdtExportedType));
600 BEGIN_PIN_PROFILER(CORProfilerTrackAssemblyLoads());
604 g_profControlBlock.pProfInterface->AssemblyLoadFinished((AssemblyID) m_pAssembly, hr);
611 #ifndef CROSSGEN_COMPILE
612 IMetaDataEmit *Module::GetValidatedEmitter()
619 INJECT_FAULT(COMPlusThrowOM());
624 if (m_pValidatedEmitter.Load() == NULL)
626 // In the past profilers could call any API they wanted on the the IMetaDataEmit interface and we didn't
627 // verify anything. To ensure we don't break back-compat the verifications are not enabled by default.
628 // Right now I have only added verifications for NGEN images, but in the future we might want verifications
630 IMetaDataEmit* pEmit = NULL;
631 if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_ProfAPI_ValidateNGENInstrumentation) && HasNativeImage())
633 ProfilerMetadataEmitValidator* pValidator = new ProfilerMetadataEmitValidator(GetEmitter());
634 pValidator->QueryInterface(IID_IMetaDataEmit, (void**)&pEmit);
638 pEmit = GetEmitter();
641 // Atomically swap it into the field (release it if we lose the race)
642 if (FastInterlockCompareExchangePointer(&m_pValidatedEmitter, pEmit, NULL) != NULL)
647 return m_pValidatedEmitter.Load();
649 #endif // CROSSGEN_COMPILE
650 #endif // PROFILING_SUPPORTED
652 void Module::NotifyEtwLoadFinished(HRESULT hr)
661 // we report only successful loads
663 ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
664 TRACE_LEVEL_INFORMATION,
667 BOOL fSharedModule = !SetTransientFlagInterlocked(IS_ETW_NOTIFIED);
668 ETW::LoaderLog::ModuleLoad(this, fSharedModule);
672 // Module initialization occurs in two phases: the constructor phase and the Initialize phase.
674 // The constructor phase initializes just enough so that Destruct() can be safely called.
675 // It cannot throw or fail.
677 Module::Module(Assembly *pAssembly, mdFile moduleRef, PEFile *file)
687 PREFIX_ASSUME(pAssembly != NULL);
689 m_pAssembly = pAssembly;
690 m_moduleRef = moduleRef;
692 m_dwTransientFlags = CLASSES_FREED;
694 if (!m_file->HasNativeImage())
696 // Memory allocated on LoaderHeap is zero-filled. Spot-check it here.
697 _ASSERTE(m_pBinder == NULL);
698 _ASSERTE(m_symbolFormat == eSymbolFormatNone);
705 #ifdef FEATURE_PREJIT
707 void Module::InitializeNativeImage(AllocMemTracker* pamTracker)
715 PRECONDITION(HasNativeImage());
719 if(m_pModuleSecurityDescriptor)
721 _ASSERTE(m_pModuleSecurityDescriptor->GetModule() == this);
724 PEImageLayout * pNativeImage = GetNativeImage();
726 ExecutionManager::AddNativeImageRange(dac_cast<TADDR>(pNativeImage->GetBase()), pNativeImage->GetVirtualSize(), this);
728 CORCOMPILE_VERSION_INFO * pNativeVersionInfo = pNativeImage->GetNativeVersionInfoMaybeNull();
729 if ((pNativeVersionInfo != NULL) && (pNativeVersionInfo->wConfigFlags & CORCOMPILE_CONFIG_INSTRUMENTATION))
731 m_nativeImageProfiling = GetAssembly()->IsInstrumented();
734 // Link the module to the profile data list if available.
735 COUNT_T cbProfileList;
736 m_methodProfileList = pNativeImage->GetNativeProfileDataList(&cbProfileList);
737 #ifdef FEATURE_LAZY_COW_PAGES
739 EnsureWritablePages(m_methodProfileList, cbProfileList);
742 #ifndef CROSSGEN_COMPILE
745 #endif // CROSSGEN_COMPILE
747 #if defined(HAVE_GCCOVER)
748 if (GCStress<cfg_instr_ngen>::IsEnabled())
750 // Setting up gc coverage requires the base system classes
751 // to be initialized. So we must defer this for mscorlib.
754 SetupGcCoverageForNativeImage(this);
757 #endif // defined(HAVE_GCCOVER)
760 void Module::SetNativeMetadataAssemblyRefInCache(DWORD rid, PTR_Assembly pAssembly)
770 if (m_NativeMetadataAssemblyRefMap == NULL)
772 IMDInternalImport* pImport = GetNativeAssemblyImport();
773 DWORD dwMaxRid = pImport->GetCountWithTokenKind(mdtAssemblyRef);
774 _ASSERTE(dwMaxRid > 0);
776 S_SIZE_T dwAllocSize = S_SIZE_T(sizeof(PTR_Assembly)) * S_SIZE_T(dwMaxRid);
778 AllocMemTracker amTracker;
779 PTR_Assembly * NativeMetadataAssemblyRefMap = (PTR_Assembly *) amTracker.Track( GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(dwAllocSize) );
781 // Note: Memory allocated on loader heap is zero filled
783 if (InterlockedCompareExchangeT<PTR_Assembly *>(&m_NativeMetadataAssemblyRefMap, NativeMetadataAssemblyRefMap, NULL) == NULL)
784 amTracker.SuppressRelease();
786 _ASSERTE(m_NativeMetadataAssemblyRefMap != NULL);
788 _ASSERTE(rid <= GetNativeAssemblyImport()->GetCountWithTokenKind(mdtAssemblyRef));
789 m_NativeMetadataAssemblyRefMap[rid-1] = pAssembly;
791 #else // FEATURE_PREJIT
792 BOOL Module::IsPersistedObject(void *address)
794 LIMITED_METHOD_CONTRACT;
798 #endif // FEATURE_PREJIT
800 // Module initialization occurs in two phases: the constructor phase and the Initialize phase.
802 // The Initialize() phase completes the initialization after the constructor has run.
803 // It can throw exceptions but whether it throws or succeeds, it must leave the Module
804 // in a state where Destruct() can be safely called.
806 // szName is only used by dynamic modules, see ReflectionModule::Initialize
809 void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
815 PRECONDITION(szName == NULL);
819 m_pSimpleName = m_file->GetSimpleName();
821 m_Crst.Init(CrstModule);
822 m_LookupTableCrst.Init(CrstModuleLookupTable, CrstFlags(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD));
823 m_FixupCrst.Init(CrstModuleFixup, (CrstFlags)(CRST_HOST_BREAKABLE|CRST_REENTRANCY));
824 m_InstMethodHashTableCrst.Init(CrstInstMethodHashTable, CRST_REENTRANCY);
825 m_ISymUnmanagedReaderCrst.Init(CrstISymUnmanagedReader, CRST_DEBUGGER_THREAD);
827 if (!m_file->HasNativeImage())
832 (strcmp(m_pSimpleName, "System") == 0) ||
833 (strcmp(m_pSimpleName, "System.Core") == 0) ||
834 (strcmp(m_pSimpleName, "Windows.Foundation") == 0))
836 FastInterlockOr(&m_dwPersistedFlags, LOW_LEVEL_SYSTEM_ASSEMBLY_BY_NAME);
839 _ASSERT(m_pModuleSecurityDescriptor == NULL);
840 m_pModuleSecurityDescriptor = new ModuleSecurityDescriptor(this);
843 m_dwTransientFlags &= ~((DWORD)CLASSES_FREED); // Set flag indicating LookupMaps are now in a consistent and destructable state
845 #ifdef FEATURE_READYTORUN
846 if (!HasNativeImage() && !IsResource())
847 m_pReadyToRunInfo = ReadyToRunInfo::Initialize(this, pamTracker);
850 // Initialize the instance fields that we need for all non-Resource Modules
853 if (m_pAvailableClasses == NULL && !IsReadyToRun())
855 m_pAvailableClasses = EEClassHashTable::Create(this,
856 GetAssembly()->IsCollectible() ? AVAILABLE_CLASSES_HASH_BUCKETS_COLLECTIBLE : AVAILABLE_CLASSES_HASH_BUCKETS,
857 FALSE /* bCaseInsensitive */, pamTracker);
860 if (m_pAvailableParamTypes == NULL)
862 m_pAvailableParamTypes = EETypeHashTable::Create(GetLoaderAllocator(), this, PARAMTYPES_HASH_BUCKETS, pamTracker);
865 if (m_pInstMethodHashTable == NULL)
867 m_pInstMethodHashTable = InstMethodHashTable::Create(GetLoaderAllocator(), this, PARAMMETHODS_HASH_BUCKETS, pamTracker);
870 if(m_pMemberRefToDescHashTable == NULL)
874 m_pMemberRefToDescHashTable = MemberRefToDescHashTable::Create(this, MEMBERREF_MAP_INITIAL_SIZE, pamTracker);
878 IMDInternalImport * pImport = GetMDImport();
880 // Get #MemberRefs and create memberrefToDesc hash table
881 m_pMemberRefToDescHashTable = MemberRefToDescHashTable::Create(this, pImport->GetCountWithTokenKind(mdtMemberRef)+1, pamTracker);
885 #ifdef FEATURE_COMINTEROP
886 if (IsCompilationProcess() && m_pGuidToTypeHash == NULL)
888 // only allocate this during NGEN-ing
889 m_pGuidToTypeHash = GuidToMethodTableHashTable::Create(this, GUID_TO_TYPE_HASH_BUCKETS, pamTracker);
891 #endif // FEATURE_COMINTEROP
894 if (GetAssembly()->IsDomainNeutral() && !IsSingleAppDomain())
896 m_ModuleIndex = Module::AllocateModuleIndex();
897 m_ModuleID = (DomainLocalModule*)Module::IndexToID(m_ModuleIndex);
901 // this will be initialized a bit later.
903 m_ModuleIndex.m_dwIndex = (SIZE_T)-1;
906 #ifdef FEATURE_COLLECTIBLE_TYPES
907 if (GetAssembly()->IsCollectible())
909 FastInterlockOr(&m_dwPersistedFlags, COLLECTIBLE_MODULE);
911 #endif // FEATURE_COLLECTIBLE_TYPES
913 // Prepare statics that are known at module load time
914 AllocateStatics(pamTracker);
916 #ifdef FEATURE_PREJIT
917 // Set up native image
918 if (HasNativeImage())
919 InitializeNativeImage(pamTracker);
920 #endif // FEATURE_PREJIT
923 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
924 if (g_CorCompileVerboseLevel)
925 m_pNgenStats = new NgenStats();
928 if (!IsResource() && (m_AssemblyRefByNameTable == NULL))
930 Module::CreateAssemblyRefByNameTable(pamTracker);
933 // If the program has the "ForceEnc" env variable set we ensure every eligible
934 // module has EnC turned on.
935 if (g_pConfig->ForceEnc() && IsEditAndContinueCapable())
936 EnableEditAndContinue();
938 LOG((LF_CLASSLOADER, LL_INFO10, "Loaded pModule: \"%ws\".\n", GetDebugName()));
942 #endif // DACCESS_COMPILE
945 #ifdef FEATURE_COMINTEROP
947 #ifndef DACCESS_COMPILE
950 GuidToMethodTableHashTable* GuidToMethodTableHashTable::Create(Module* pModule, DWORD cInitialBuckets,
951 AllocMemTracker *pamTracker)
958 INJECT_FAULT(COMPlusThrowOM(););
959 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
963 LoaderHeap *pHeap = pModule->GetAssembly()->GetLowFrequencyHeap();
964 GuidToMethodTableHashTable *pThis = (GuidToMethodTableHashTable*)pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(GuidToMethodTableHashTable)));
966 // The base class get initialized through chaining of constructors. We allocated the hash instance via the
967 // loader heap instead of new so use an in-place new to call the constructors now.
968 new (pThis) GuidToMethodTableHashTable(pModule, pHeap, cInitialBuckets);
973 GuidToMethodTableEntry *GuidToMethodTableHashTable::InsertValue(PTR_GUID pGuid, PTR_MethodTable pMT,
974 BOOL bReplaceIfFound, AllocMemTracker *pamTracker)
981 INJECT_FAULT(COMPlusThrowOM(););
982 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
986 GuidToMethodTableEntry *pEntry = NULL;
991 pEntry = FindItem(pGuid, NULL);
1000 pEntry = BaseAllocateEntry(pamTracker);
1001 pEntry->m_Guid = pGuid;
1002 pEntry->m_pMT = pMT;
1004 DWORD hash = Hash(pGuid);
1005 BaseInsertEntry(hash, pEntry);
1011 #endif // !DACCESS_COMPILE
1013 PTR_MethodTable GuidToMethodTableHashTable::GetValue(const GUID * pGuid, LookupContext *pContext)
1021 PRECONDITION(CheckPointer(pGuid));
1025 GuidToMethodTableEntry * pEntry = FindItem(pGuid, pContext);
1028 return pEntry->m_pMT;
1034 GuidToMethodTableEntry *GuidToMethodTableHashTable::FindItem(const GUID * pGuid, LookupContext *pContext)
1042 PRECONDITION(CheckPointer(pGuid));
1046 // It's legal for the caller not to pass us a LookupContext, but we might need to iterate
1047 // internally (since we lookup via hash and hashes may collide). So substitute our own
1048 // private context if one was not provided.
1049 LookupContext sAltContext;
1050 if (pContext == NULL)
1051 pContext = &sAltContext;
1053 // The base class provides the ability to enumerate all entries with the same hash code.
1054 // We further check which of these entries actually match the full key.
1055 PTR_GuidToMethodTableEntry pSearch = BaseFindFirstEntryByHash(Hash(pGuid), pContext);
1058 if (CompareKeys(pSearch, pGuid))
1063 pSearch = BaseFindNextEntryByHash(pContext);
1069 BOOL GuidToMethodTableHashTable::CompareKeys(PTR_GuidToMethodTableEntry pEntry, const GUID * pGuid)
1071 LIMITED_METHOD_DAC_CONTRACT;
1072 return *pGuid == *(pEntry->m_Guid);
1075 DWORD GuidToMethodTableHashTable::Hash(const GUID * pGuid)
1077 LIMITED_METHOD_DAC_CONTRACT;
1078 static_assert_no_msg(sizeof(GUID) % sizeof(DWORD) == 0);
1079 static_assert_no_msg(sizeof(GUID) / sizeof(DWORD) == 4);
1080 DWORD * pSlice = (DWORD*) pGuid;
1081 return pSlice[0] ^ pSlice[1] ^ pSlice[2] ^ pSlice[3];
1085 BOOL GuidToMethodTableHashTable::FindNext(Iterator *it, GuidToMethodTableEntry **ppEntry)
1087 LIMITED_METHOD_DAC_CONTRACT;
1089 if (!it->m_fIterating)
1091 BaseInitIterator(&it->m_sIterator);
1092 it->m_fIterating = true;
1095 *ppEntry = it->m_sIterator.Next();
1096 return *ppEntry ? TRUE : FALSE;
1099 DWORD GuidToMethodTableHashTable::GetCount()
1101 LIMITED_METHOD_DAC_CONTRACT;
1102 return BaseGetElementCount();
1105 #if defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
1107 void GuidToMethodTableHashTable::Save(DataImage *pImage, CorProfileData *pProfileData)
1109 WRAPPER_NO_CONTRACT;
1110 Base_t::BaseSave(pImage, pProfileData);
1113 void GuidToMethodTableHashTable::Fixup(DataImage *pImage)
1115 WRAPPER_NO_CONTRACT;
1116 Base_t::BaseFixup(pImage);
1119 bool GuidToMethodTableHashTable::SaveEntry(DataImage *pImage, CorProfileData *pProfileData,
1120 GuidToMethodTableEntry *pOldEntry, GuidToMethodTableEntry *pNewEntry,
1121 EntryMappingTable *pMap)
1123 LIMITED_METHOD_CONTRACT;
1127 void GuidToMethodTableHashTable::FixupEntry(DataImage *pImage, GuidToMethodTableEntry *pEntry, void *pFixupBase, DWORD cbFixupOffset)
1129 WRAPPER_NO_CONTRACT;
1130 pImage->FixupField(pFixupBase, cbFixupOffset + offsetof(GuidToMethodTableEntry, m_pMT), pEntry->m_pMT);
1131 pImage->FixupField(pFixupBase, cbFixupOffset + offsetof(GuidToMethodTableEntry, m_Guid), pEntry->m_Guid);
1134 #endif // FEATURE_NATIVE_IMAGE_GENERATION && !DACCESS_COMPILE
1137 #ifdef FEATURE_PREJIT
1139 #ifndef DACCESS_COMPILE
1140 BOOL Module::CanCacheWinRTTypeByGuid(MethodTable *pMT)
1147 PRECONDITION(IsCompilationProcess());
1151 // Don't cache mscorlib-internal declarations of WinRT types.
1152 if (IsSystem() && pMT->IsProjectedFromWinRT())
1155 // Don't cache redirected WinRT types.
1156 if (WinRTTypeNameConverter::IsRedirectedWinRTSourceType(pMT))
1159 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
1160 // Don't cache in a module that's not the NGen target, since the result
1161 // won't be saved, and since the such a module might be read-only.
1162 if (GetAppDomain()->ToCompilationDomain()->GetTargetModule() != this)
1169 void Module::CacheWinRTTypeByGuid(PTR_MethodTable pMT, PTR_GuidInfo pgi /*= NULL*/)
1174 PRECONDITION(CheckPointer(pMT));
1175 PRECONDITION(pMT->IsLegalNonArrayWinRTType());
1176 PRECONDITION(pgi != NULL || pMT->GetGuidInfo() != NULL);
1177 PRECONDITION(IsCompilationProcess());
1183 pgi = pMT->GetGuidInfo();
1186 AllocMemTracker amt;
1187 m_pGuidToTypeHash->InsertValue(&pgi->m_Guid, pMT, TRUE, &amt);
1188 amt.SuppressRelease();
1191 #endif // !DACCESS_COMPILE
1193 PTR_MethodTable Module::LookupTypeByGuid(const GUID & guid)
1195 WRAPPER_NO_CONTRACT;
1196 // Triton ni images do not have this hash.
1197 if (m_pGuidToTypeHash != NULL)
1198 return m_pGuidToTypeHash->GetValue(&guid, NULL);
1203 void Module::GetCachedWinRTTypes(SArray<PTR_MethodTable> * pTypes, SArray<GUID> * pGuids)
1212 // Triton ni images do not have this hash.
1213 if (m_pGuidToTypeHash != NULL)
1215 GuidToMethodTableHashTable::Iterator it(m_pGuidToTypeHash);
1216 GuidToMethodTableEntry *pEntry;
1217 while (m_pGuidToTypeHash->FindNext(&it, &pEntry))
1219 pTypes->Append(pEntry->m_pMT);
1220 pGuids->Append(*pEntry->m_Guid);
1225 #endif // FEATURE_PREJIT
1227 #endif // FEATURE_COMINTEROP
1229 #ifndef DACCESS_COMPILE
1230 MemberRefToDescHashTable* MemberRefToDescHashTable::Create(Module *pModule, DWORD cInitialBuckets, AllocMemTracker *pamTracker)
1237 INJECT_FAULT(COMPlusThrowOM(););
1238 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
1242 LoaderHeap *pHeap = pModule->GetAssembly()->GetLowFrequencyHeap();
1243 MemberRefToDescHashTable *pThis = (MemberRefToDescHashTable*)pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(MemberRefToDescHashTable)));
1245 // The base class get initialized through chaining of constructors. We allocated the hash instance via the
1246 // loader heap instead of new so use an in-place new to call the constructors now.
1247 new (pThis) MemberRefToDescHashTable(pModule, pHeap, cInitialBuckets);
1253 MemberRefToDescHashEntry* MemberRefToDescHashTable::Insert(mdMemberRef token , FieldDesc *value)
1260 INJECT_FAULT(COMPlusThrowOM(););
1261 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
1265 LookupContext sAltContext;
1267 _ASSERTE((dac_cast<TADDR>(value) & IS_FIELD_MEMBER_REF) == 0);
1269 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(token), &sAltContext);
1272 // 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.
1273 // However its value will be null. We need to set its actual value.
1274 if(pEntry->m_value == dac_cast<TADDR>(NULL))
1276 EnsureWritablePages(&(pEntry->m_value));
1277 pEntry->m_value = dac_cast<TADDR>(value)|IS_FIELD_MEMBER_REF;
1280 _ASSERTE(pEntry->m_value == (dac_cast<TADDR>(value)|IS_FIELD_MEMBER_REF));
1284 // For non hot tokens insert new entry in hashtable
1285 pEntry = BaseAllocateEntry(NULL);
1286 pEntry->m_value = dac_cast<TADDR>(value)|IS_FIELD_MEMBER_REF;
1287 BaseInsertEntry(RidFromToken(token), pEntry);
1293 MemberRefToDescHashEntry* MemberRefToDescHashTable::Insert(mdMemberRef token , MethodDesc *value)
1300 INJECT_FAULT(COMPlusThrowOM(););
1301 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
1305 LookupContext sAltContext;
1307 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(token), &sAltContext);
1310 // 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.
1311 // However its value will be null. We need to set its actual value.
1312 if(pEntry->m_value == dac_cast<TADDR>(NULL))
1314 EnsureWritablePages(&(pEntry->m_value));
1315 pEntry->m_value = dac_cast<TADDR>(value);
1318 _ASSERTE(pEntry->m_value == dac_cast<TADDR>(value));
1322 // For non hot tokens insert new entry in hashtable
1323 pEntry = BaseAllocateEntry(NULL);
1324 pEntry->m_value = dac_cast<TADDR>(value);
1325 BaseInsertEntry(RidFromToken(token), pEntry);
1330 #if defined(FEATURE_NATIVE_IMAGE_GENERATION)
1331 void MemberRefToDescHashTable::Save(DataImage *pImage, CorProfileData *pProfileData)
1333 STANDARD_VM_CONTRACT;
1335 // Mark if the tokens are hot
1338 DWORD numInTokenList = pProfileData->GetHotTokens(mdtMemberRef>>24, 1<<RidMap, 1<<RidMap, NULL, 0);
1340 if (numInTokenList > 0)
1342 LookupContext sAltContext;
1344 mdToken *tokenList = (mdToken*)(void*)pImage->GetModule()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(mdToken)) * S_SIZE_T(numInTokenList));
1346 pProfileData->GetHotTokens(mdtMemberRef>>24, 1<<RidMap, 1<<RidMap, tokenList, numInTokenList);
1347 for (DWORD i = 0; i < numInTokenList; i++)
1349 DWORD rid = RidFromToken(tokenList[i]);
1350 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(tokenList[i]), &sAltContext);
1353 _ASSERTE((pEntry->m_value & 0x1) == 0);
1354 pEntry->m_value |= 0x1;
1360 BaseSave(pImage, pProfileData);
1363 void MemberRefToDescHashTable::FixupEntry(DataImage *pImage, MemberRefToDescHashEntry *pEntry, void *pFixupBase, DWORD cbFixupOffset)
1365 //As there is no more hard binding initialize MemberRef* to NULL
1366 pImage->ZeroPointerField(pFixupBase, cbFixupOffset + offsetof(MemberRefToDescHashEntry, m_value));
1369 #endif // FEATURE_NATIVE_IMAGE_GENERATION
1371 #endif // !DACCESS_COMPILE
1373 PTR_MemberRef MemberRefToDescHashTable::GetValue(mdMemberRef token, BOOL *pfIsMethod)
1384 LookupContext sAltContext;
1386 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(token), &sAltContext);
1389 if(pEntry->m_value & IS_FIELD_MEMBER_REF)
1390 *pfIsMethod = FALSE;
1393 return (PTR_MemberRef)(pEntry->m_value & (~MEMBER_REF_MAP_ALL_FLAGS));
1400 void Module::SetDebuggerInfoBits(DebuggerAssemblyControlFlags newBits)
1402 LIMITED_METHOD_CONTRACT;
1405 _ASSERTE(((newBits << DEBUGGER_INFO_SHIFT_PRIV) &
1406 ~DEBUGGER_INFO_MASK_PRIV) == 0);
1408 m_dwTransientFlags &= ~DEBUGGER_INFO_MASK_PRIV;
1409 m_dwTransientFlags |= (newBits << DEBUGGER_INFO_SHIFT_PRIV);
1411 #ifdef DEBUGGING_SUPPORTED
1412 BOOL setEnC = ((newBits & DACF_ENC_ENABLED) != 0) && IsEditAndContinueCapable();
1414 // IsEditAndContinueCapable should already check !GetAssembly()->IsDomainNeutral
1415 _ASSERTE(!setEnC || !GetAssembly()->IsDomainNeutral());
1417 // The only way can change Enc is through debugger override.
1420 EnableEditAndContinue();
1424 if (!g_pConfig->ForceEnc())
1425 DisableEditAndContinue();
1427 #endif // DEBUGGING_SUPPORTED
1429 #if defined(DACCESS_COMPILE)
1430 // Now that we've changed m_dwTransientFlags, update that in the target too.
1431 // This will fail for read-only target.
1432 // If this fails, it will throw an exception.
1433 // @dbgtodo dac write: finalize on plans for how DAC writes to the target.
1435 hrDac = DacWriteHostInstance(this, true);
1436 _ASSERTE(SUCCEEDED(hrDac)); // would throw if there was an error.
1437 #endif // DACCESS_COMPILE
1440 #ifndef DACCESS_COMPILE
1442 Module *Module::Create(Assembly *pAssembly, mdFile moduleRef, PEFile *file, AllocMemTracker *pamTracker)
1447 PRECONDITION(CheckPointer(pAssembly));
1448 PRECONDITION(CheckPointer(file));
1449 PRECONDITION(!IsNilToken(moduleRef) || file->IsAssembly());
1450 POSTCONDITION(CheckPointer(RETVAL));
1451 POSTCONDITION(RETVAL->GetFile() == file);
1455 // Hoist CONTRACT into separate routine because of EX incompatibility
1457 Module *pModule = NULL;
1459 // Create the module
1461 #ifdef FEATURE_PREJIT
1463 if (file->HasNativeImage())
1465 pModule = file->GetLoadedNative()->GetPersistedModuleImage();
1466 PREFIX_ASSUME(pModule != NULL);
1467 CONSISTENCY_CHECK_MSG(pModule->m_pAssembly == NULL || !pModule->IsTenured(), // if the module is not tenured it could be our previous attempt
1468 "Native image can only be used once per process\n");
1469 EnsureWritablePages(pModule);
1470 pModule = new ((void*) pModule) Module(pAssembly, moduleRef, file);
1471 PREFIX_ASSUME(pModule != NULL);
1474 #endif // FEATURE_PREJIT
1476 if (pModule == NULL)
1478 #ifdef EnC_SUPPORTED
1479 if (IsEditAndContinueCapable(pAssembly, file))
1481 // IsEditAndContinueCapable should already check !pAssembly->IsDomainNeutral
1482 _ASSERTE(!pAssembly->IsDomainNeutral());
1484 // if file is EnCCapable, always create an EnC-module, but EnC won't necessarily be enabled.
1485 // Debugger enables this by calling SetJITCompilerFlags on LoadModule callback.
1487 void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(EditAndContinueModule))));
1488 pModule = new (pMemory) EditAndContinueModule(pAssembly, moduleRef, file);
1491 #endif // EnC_SUPPORTED
1493 void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(Module))));
1494 pModule = new (pMemory) Module(pAssembly, moduleRef, file);
1498 PREFIX_ASSUME(pModule != NULL);
1499 ModuleHolder pModuleSafe(pModule);
1500 pModuleSafe->DoInit(pamTracker, NULL);
1502 RETURN pModuleSafe.Extract();
1505 void Module::ApplyMetaData()
1515 LOG((LF_CLASSLOADER, LL_INFO100, "Module::ApplyNewMetaData %x\n", this));
1520 // Ensure for TypeRef
1521 ulCount = GetMDImport()->GetCountWithTokenKind(mdtTypeRef) + 1;
1522 EnsureTypeRefCanBeStored(TokenFromRid(ulCount, mdtTypeRef));
1524 // Ensure for AssemblyRef
1525 ulCount = GetMDImport()->GetCountWithTokenKind(mdtAssemblyRef) + 1;
1526 EnsureAssemblyRefCanBeStored(TokenFromRid(ulCount, mdtAssemblyRef));
1530 // Destructor for Module
1533 void Module::Destruct()
1544 LOG((LF_EEMEM, INFO3, "Deleting module %x\n", this));
1545 #ifdef PROFILING_SUPPORTED
1547 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
1548 if (!IsBeingUnloaded())
1550 // Profiler is causing some peripheral class loads. Probably this just needs
1551 // to be turned into a Fault_not_fatal and moved to a specific place inside the profiler.
1555 g_profControlBlock.pProfInterface->ModuleUnloadStarted((ModuleID) this);
1560 EX_END_CATCH(SwallowAllExceptions);
1564 #endif // PROFILING_SUPPORTED
1567 DACNotify::DoModuleUnloadNotification(this);
1569 // Free classes in the class table
1573 #if defined(FEATURE_REMOTING) && !defined(HAS_REMOTING_PRECODE)
1574 // Destroys thunks for all methods included in hash table.
1575 if (m_pInstMethodHashTable != NULL)
1577 InstMethodHashTable::Iterator it(m_pInstMethodHashTable);
1578 InstMethodHashEntry *pEntry;
1580 while (m_pInstMethodHashTable->FindNext(&it, &pEntry))
1582 MethodDesc *pMD = pEntry->GetMethod();
1583 if (!pMD->IsRestored())
1586 if(pMD->GetMethodTable()->IsMarshaledByRef())
1587 CRemotingServices::DestroyThunk(pMD);
1590 #endif // FEATURE_REMOTING && !HAS_REMOTING_PRECODE
1592 #ifdef DEBUGGING_SUPPORTED
1593 if (g_pDebugInterface)
1596 g_pDebugInterface->DestructModule(this);
1599 #endif // DEBUGGING_SUPPORTED
1601 ReleaseISymUnmanagedReader();
1603 // Clean up sig cookies
1604 VASigCookieBlock *pVASigCookieBlock = m_pVASigCookieBlock;
1605 while (pVASigCookieBlock)
1607 VASigCookieBlock *pNext = pVASigCookieBlock->m_Next;
1608 delete pVASigCookieBlock;
1610 pVASigCookieBlock = pNext;
1613 // Clean up the IL stub cache
1614 if (m_pILStubCache != NULL)
1616 delete m_pILStubCache;
1619 #ifdef FEATURE_MIXEDMODE // IJW
1620 delete m_pMUThunkHash;
1621 delete m_pThunkHeap;
1622 #endif // FEATURE_MIXEDMODE // IJW
1625 #ifdef PROFILING_SUPPORTED
1627 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
1628 // Profiler is causing some peripheral class loads. Probably this just needs
1629 // to be turned into a Fault_not_fatal and moved to a specific place inside the profiler.
1633 g_profControlBlock.pProfInterface->ModuleUnloadFinished((ModuleID) this, S_OK);
1638 EX_END_CATCH(SwallowAllExceptions);
1642 if (m_pValidatedEmitter.Load() != NULL)
1644 m_pValidatedEmitter->Release();
1646 #endif // PROFILING_SUPPORTED
1649 // Warning - deleting the zap file will cause the module to be unmapped
1651 ClearInMemorySymbolStream();
1654 m_FixupCrst.Destroy();
1655 m_LookupTableCrst.Destroy();
1656 m_InstMethodHashTableCrst.Destroy();
1657 m_ISymUnmanagedReaderCrst.Destroy();
1662 _ASSERTE(m_pCerCrst != NULL);
1663 CrstHolder sCrstHolder(m_pCerCrst);
1665 EEHashTableIteration sIter;
1666 m_pCerPrepInfo->IterateStart(&sIter);
1667 while (m_pCerPrepInfo->IterateNext(&sIter)) {
1668 CerPrepInfo *pPrepInfo = (CerPrepInfo*)m_pCerPrepInfo->IterateGetValue(&sIter);
1672 delete m_pCerPrepInfo;
1676 #endif // FEATURE_CER
1678 if (m_debuggerSpecificData.m_pDynamicILCrst)
1680 delete m_debuggerSpecificData.m_pDynamicILCrst;
1683 if (m_debuggerSpecificData.m_pDynamicILBlobTable)
1685 delete m_debuggerSpecificData.m_pDynamicILBlobTable;
1688 if (m_debuggerSpecificData.m_pTemporaryILBlobTable)
1690 delete m_debuggerSpecificData.m_pTemporaryILBlobTable;
1693 if (m_debuggerSpecificData.m_pILOffsetMappingTable)
1695 for (ILOffsetMappingTable::Iterator pCurElem = m_debuggerSpecificData.m_pILOffsetMappingTable->Begin(),
1696 pEndElem = m_debuggerSpecificData.m_pILOffsetMappingTable->End();
1697 pCurElem != pEndElem;
1700 ILOffsetMappingEntry entry = *pCurElem;
1701 entry.m_mapping.Clear();
1703 delete m_debuggerSpecificData.m_pILOffsetMappingTable;
1706 #ifdef FEATURE_PREJIT
1708 if (m_pCerNgenRootTable && (m_dwTransientFlags & M_CER_ROOT_TABLE_ON_HEAP))
1709 delete m_pCerNgenRootTable;
1712 if (HasNativeImage())
1717 #endif // FEATURE_PREJIT
1721 if (m_pModuleSecurityDescriptor)
1722 delete m_pModuleSecurityDescriptor;
1725 // If this module was loaded as domain-specific, then
1726 // we must free its ModuleIndex so that it can be reused
1730 #ifdef FEATURE_PREJIT
1731 void Module::DeleteNativeCodeRanges()
1742 if (HasNativeImage())
1744 PEImageLayout * pNativeImage = GetNativeImage();
1746 ExecutionManager::DeleteRange(dac_cast<TADDR>(pNativeImage->GetBase()));
1751 bool Module::NeedsGlobalMethodTable()
1762 IMDInternalImport * pImport = GetMDImport();
1763 if (!IsResource() && pImport->IsValidToken(COR_GLOBAL_PARENT_TOKEN))
1766 HENUMInternalHolder funcEnum(pImport);
1767 funcEnum.EnumGlobalFunctionsInit();
1768 if (pImport->EnumGetCount(&funcEnum) != 0)
1773 HENUMInternalHolder fieldEnum(pImport);
1774 fieldEnum.EnumGlobalFieldsInit();
1775 if (pImport->EnumGetCount(&fieldEnum) != 0)
1780 // resource module or no global statics nor global functions
1785 MethodTable *Module::GetGlobalMethodTable()
1787 CONTRACT (MethodTable *)
1793 INJECT_FAULT(CONTRACT_RETURN NULL;);
1794 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1799 if ((m_dwPersistedFlags & COMPUTED_GLOBAL_CLASS) == 0)
1801 MethodTable *pMT = NULL;
1803 if (NeedsGlobalMethodTable())
1805 pMT = ClassLoader::LoadTypeDefThrowing(this, COR_GLOBAL_PARENT_TOKEN,
1806 ClassLoader::ThrowIfNotFound,
1807 ClassLoader::FailIfUninstDefOrRef).AsMethodTable();
1810 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_GLOBAL_CLASS);
1815 RETURN LookupTypeDef(COR_GLOBAL_PARENT_TOKEN).AsMethodTable();
1820 #endif // !DACCESS_COMPILE
1822 #ifdef FEATURE_PREJIT
1825 BOOL Module::IsAlwaysSavedInPreferredZapModule(Instantiation classInst, // the type arguments to the type (if any)
1826 Instantiation methodInst) // the type arguments to the method (if any)
1828 LIMITED_METHOD_CONTRACT;
1830 return ClassLoader::IsTypicalSharedInstantiation(classInst) &&
1831 ClassLoader::IsTypicalSharedInstantiation(methodInst);
1834 //this gets called recursively for generics, so do a probe.
1835 PTR_Module Module::ComputePreferredZapModule(Module * pDefinitionModule,
1836 Instantiation classInst,
1837 Instantiation methodInst)
1849 PTR_Module ret = NULL;
1850 INTERIOR_STACK_PROBE_NOTHROW_CHECK_THREAD(DontCallDirectlyForceStackOverflow());
1852 ret = Module::ComputePreferredZapModuleHelper( pDefinitionModule,
1855 END_INTERIOR_STACK_PROBE;
1860 // Is pModule likely a dependency of pOtherModule? Heuristic used by preffered zap module algorithm.
1861 // It can return both false positives and negatives.
1863 static bool IsLikelyDependencyOf(Module * pModule, Module * pOtherModule)
1872 PRECONDITION(CheckPointer(pOtherModule));
1876 // Every module has a dependency with itself
1877 if (pModule == pOtherModule)
1881 // Explicit check for low level system assemblies is working around Win8P facades introducing extra layer between low level system assemblies
1882 // (System.dll or System.Core.dll) and the app assemblies. Because of this extra layer, the check below won't see the direct
1883 // reference between these low level system assemblies and the app assemblies. The prefererred zap module for instantiations of generic
1884 // collections from these low level system assemblies (like LinkedList<AppType>) should be module of AppType. It would be module of the generic
1885 // collection without this check. On desktop (FEATURE_FULL_NGEN defined), it would result into inefficient code because of the instantiations
1886 // would be speculative. On CoreCLR (FEATURE_FULL_NGEN not defined), it would result into the instantiations not getting saved into native
1889 // Similar problem exists for Windows.Foundation.winmd. There is a cycle between Windows.Foundation.winmd and Windows.Storage.winmd. This cycle
1890 // would cause prefererred zap module for instantiations of foundation types (like IAsyncOperation<StorageFolder>) to be Windows.Foundation.winmd.
1891 // It is a bad choice. It should be Windows.Storage.winmd instead. We explicitly push Windows.Foundation to lower level by treating it as
1892 // low level system assembly to avoid this problem.
1894 if (pModule->IsLowLevelSystemAssemblyByName())
1896 if (!pOtherModule->IsLowLevelSystemAssemblyByName())
1899 // Every module depends upon mscorlib
1900 if (pModule->IsSystem())
1903 // mscorlib does not depend upon any other module
1904 if (pOtherModule->IsSystem())
1909 if (pOtherModule->IsLowLevelSystemAssemblyByName())
1913 // At this point neither pModule or pOtherModule is mscorlib
1915 #ifndef DACCESS_COMPILE
1917 // We will check to see if the pOtherModule has a reference to pModule
1920 // If we can match the assembly ref in the ManifestModuleReferencesMap we can early out.
1921 // This early out kicks in less than half of the time. It hurts performance on average.
1922 // if (!IsNilToken(pOtherModule->FindAssemblyRef(pModule->GetAssembly())))
1925 if (pOtherModule->HasReferenceByName(pModule->GetSimpleName()))
1927 #endif // DACCESS_COMPILE
1932 // Determine the "preferred ngen home" for an instantiated type or method
1933 // * This is the first ngen module that the loader will look in;
1934 // * Also, we only hard bind to a type or method that lives in its preferred module
1935 // The following properties must hold of the preferred module:
1936 // - it must be one of the component type's declaring modules
1937 // - if the type or method is open then the preferred module must be that of one of the type parameters
1938 // (this ensures that we can always hard bind to open types and methods created during ngen)
1939 // - for always-saved instantiations it must be the declaring module of the generic definition
1940 // Otherwise, we try to pick a module that is likely to reference the type or method
1943 PTR_Module Module::ComputePreferredZapModuleHelper(
1944 Module * pDefinitionModule, // the module that declares the generic type or method
1945 Instantiation classInst, // the type arguments to the type (if any)
1946 Instantiation methodInst) // the type arguments to the method (if any)
1948 CONTRACT(PTR_Module)
1954 PRECONDITION(CheckPointer(pDefinitionModule, NULL_OK));
1955 // One of them will be non-null... Note we don't use CheckPointer
1956 // because that raises a breakpoint in the debugger
1957 PRECONDITION(pDefinitionModule != NULL || !classInst.IsEmpty() || !methodInst.IsEmpty());
1958 POSTCONDITION(CheckPointer(RETVAL));
1963 DWORD totalArgs = classInst.GetNumArgs() + methodInst.GetNumArgs();
1965 // The open type parameters takes precendence over closed type parameters since
1966 // we always hardbind to open types.
1967 for (DWORD i = 0; i < totalArgs; i++)
1969 TypeHandle thArg = (i < classInst.GetNumArgs()) ? classInst[i] : methodInst[i - classInst.GetNumArgs()];
1971 // Encoded types are never open
1972 _ASSERTE(!thArg.IsEncodedFixup());
1973 Module * pOpenModule = thArg.GetDefiningModuleForOpenType();
1974 if (pOpenModule != NULL)
1975 RETURN dac_cast<PTR_Module>(pOpenModule);
1978 // The initial value of pCurrentPZM is the pDefinitionModule or mscorlib
1979 Module* pCurrentPZM = (pDefinitionModule != NULL) ? pDefinitionModule : MscorlibBinder::GetModule();
1980 bool preferredZapModuleBasedOnValueType = false;
1982 for (DWORD i = 0; i < totalArgs; i++)
1984 TypeHandle pTypeParam = (i < classInst.GetNumArgs()) ? classInst[i] : methodInst[i - classInst.GetNumArgs()];
1986 _ASSERTE(pTypeParam != NULL);
1987 _ASSERTE(!pTypeParam.IsEncodedFixup());
1989 Module * pParamPZM = GetPreferredZapModuleForTypeHandle(pTypeParam);
1992 // If pCurrentPZM is not a dependency of pParamPZM
1993 // then we aren't going to update pCurrentPZM
1995 if (IsLikelyDependencyOf(pCurrentPZM, pParamPZM))
1997 // If we have a type parameter that is a value type
1998 // and we don't yet have a value type based pCurrentPZM
1999 // then we will select it's module as the new pCurrentPZM.
2001 if (pTypeParam.IsValueType() && !preferredZapModuleBasedOnValueType)
2003 pCurrentPZM = pParamPZM;
2004 preferredZapModuleBasedOnValueType = true;
2008 // The normal rule is to replace the pCurrentPZM only when
2009 // both of the following are true:
2010 // pCurrentPZM is a dependency of pParamPZM
2011 // and pParamPZM is not a dependency of pCurrentPZM
2013 // note that the second condition is alway true when pCurrentPZM is mscorlib
2015 if (!IsLikelyDependencyOf(pParamPZM, pCurrentPZM))
2017 pCurrentPZM = pParamPZM;
2023 RETURN dac_cast<PTR_Module>(pCurrentPZM);
2026 PTR_Module Module::ComputePreferredZapModule(TypeKey *pKey)
2038 if (pKey->GetKind() == ELEMENT_TYPE_CLASS)
2040 return Module::ComputePreferredZapModule(pKey->GetModule(),
2041 pKey->GetInstantiation());
2043 else if (pKey->GetKind() != ELEMENT_TYPE_FNPTR)
2044 return Module::GetPreferredZapModuleForTypeHandle(pKey->GetElementType());
2050 /* see code:Module::ComputePreferredZapModuleHelper for more */
2052 PTR_Module Module::GetPreferredZapModuleForMethodTable(MethodTable *pMT)
2064 PTR_Module pRet=NULL;
2066 INTERIOR_STACK_PROBE_FOR_NOTHROW_CHECK_THREAD(10, NO_FORBIDGC_LOADER_USE_ThrowSO(););
2070 TypeHandle elemTH = pMT->GetApproxArrayElementTypeHandle();
2071 pRet= ComputePreferredZapModule(NULL, Instantiation(&elemTH, 1));
2073 else if (pMT->HasInstantiation() && !pMT->IsGenericTypeDefinition())
2075 pRet= ComputePreferredZapModule(pMT->GetModule(),
2076 pMT->GetInstantiation());
2080 // If it is uninstantiated or it is the generic type definition itself
2081 // then its loader module is simply the module containing its TypeDef
2082 pRet= pMT->GetModule();
2084 END_INTERIOR_STACK_PROBE;
2090 PTR_Module Module::GetPreferredZapModuleForTypeDesc(PTR_TypeDesc pTD)
2101 if (pTD->HasTypeParam())
2102 return GetPreferredZapModuleForTypeHandle(pTD->GetTypeParam());
2103 else if (pTD->IsGenericVariable())
2104 return pTD->GetModule();
2106 _ASSERTE(pTD->GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
2107 PTR_FnPtrTypeDesc pFnPtrTD = dac_cast<PTR_FnPtrTypeDesc>(pTD);
2109 // Result type of function type is used for preferred zap module
2110 return GetPreferredZapModuleForTypeHandle(pFnPtrTD->GetRetAndArgTypesPointer()[0]);
2114 PTR_Module Module::GetPreferredZapModuleForTypeHandle(TypeHandle t)
2126 return GetPreferredZapModuleForTypeDesc(t.AsTypeDesc());
2128 return GetPreferredZapModuleForMethodTable(t.AsMethodTable());
2132 PTR_Module Module::GetPreferredZapModuleForMethodDesc(const MethodDesc *pMD)
2143 if (pMD->IsTypicalMethodDefinition())
2145 return PTR_Module(pMD->GetModule());
2147 else if (pMD->IsGenericMethodDefinition())
2149 return GetPreferredZapModuleForMethodTable(pMD->GetMethodTable());
2153 return ComputePreferredZapModule(pMD->GetModule(),
2154 pMD->GetClassInstantiation(),
2155 pMD->GetMethodInstantiation());
2159 /* see code:Module::ComputePreferredZapModuleHelper for more */
2161 PTR_Module Module::GetPreferredZapModuleForFieldDesc(FieldDesc * pFD)
2172 // The approx MT is sufficient: it's always the one that owns the FieldDesc
2174 return GetPreferredZapModuleForMethodTable(pFD->GetApproxEnclosingMethodTable());
2176 #endif // FEATURE_PREJIT
2179 BOOL Module::IsEditAndContinueCapable(Assembly *pAssembly, PEFile *file)
2191 _ASSERTE(pAssembly != NULL && file != NULL);
2193 // Some modules are never EnC-capable
2194 return ! (pAssembly->GetDebuggerInfoBits() & DACF_ALLOW_JIT_OPTS ||
2195 pAssembly->IsDomainNeutral() ||
2197 file->IsResource() ||
2198 file->HasNativeImage() ||
2202 BOOL Module::IsManifest()
2204 WRAPPER_NO_CONTRACT;
2205 return dac_cast<TADDR>(GetAssembly()->GetManifestModule()) ==
2206 dac_cast<TADDR>(this);
2209 DomainAssembly* Module::GetDomainAssembly(AppDomain *pDomain)
2211 CONTRACT(DomainAssembly *)
2214 PRECONDITION(CheckPointer(pDomain, NULL_OK));
2215 POSTCONDITION(CheckPointer(RETVAL));
2223 RETURN (DomainAssembly *) GetDomainFile(pDomain);
2225 RETURN (DomainAssembly *) m_pAssembly->GetDomainAssembly(pDomain);
2228 DomainFile *Module::GetDomainFile(AppDomain *pDomain)
2230 CONTRACT(DomainFile *)
2233 PRECONDITION(CheckPointer(pDomain));
2234 POSTCONDITION(CheckPointer(RETVAL));
2242 if (Module::IsEncodedModuleIndex(GetModuleID()))
2244 DomainLocalBlock *pLocalBlock = pDomain->GetDomainLocalBlock();
2245 DomainFile *pDomainFile = pLocalBlock->TryGetDomainFile(GetModuleIndex());
2247 #if !defined(DACCESS_COMPILE) && defined(FEATURE_LOADER_OPTIMIZATION)
2248 if (pDomainFile == NULL)
2249 pDomainFile = pDomain->LoadDomainNeutralModuleDependency(this, FILE_LOADED);
2250 #endif // !DACCESS_COMPILE
2252 RETURN (PTR_DomainFile) pDomainFile;
2257 CONSISTENCY_CHECK(dac_cast<TADDR>(pDomain) == dac_cast<TADDR>(GetDomain()) || IsSingleAppDomain());
2258 RETURN dac_cast<PTR_DomainFile>(m_ModuleID->GetDomainFile());
2262 DomainAssembly* Module::FindDomainAssembly(AppDomain *pDomain)
2264 CONTRACT(DomainAssembly *)
2267 PRECONDITION(CheckPointer(pDomain));
2268 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2278 RETURN dac_cast<PTR_DomainAssembly>(FindDomainFile(pDomain));
2280 RETURN m_pAssembly->FindDomainAssembly(pDomain);
2283 DomainModule *Module::GetDomainModule(AppDomain *pDomain)
2285 CONTRACT(DomainModule *)
2288 PRECONDITION(CheckPointer(pDomain));
2289 PRECONDITION(!IsManifest());
2290 POSTCONDITION(CheckPointer(RETVAL));
2298 RETURN (DomainModule *) GetDomainFile(pDomain);
2301 DomainFile *Module::FindDomainFile(AppDomain *pDomain)
2303 CONTRACT(DomainFile *)
2306 PRECONDITION(CheckPointer(pDomain));
2307 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2316 if (Module::IsEncodedModuleIndex(GetModuleID()))
2318 DomainLocalBlock *pLocalBlock = pDomain->GetDomainLocalBlock();
2319 RETURN pLocalBlock->TryGetDomainFile(GetModuleIndex());
2323 if (dac_cast<TADDR>(pDomain) == dac_cast<TADDR>(GetDomain()) || IsSingleAppDomain())
2324 RETURN m_ModuleID->GetDomainFile();
2330 DomainModule *Module::FindDomainModule(AppDomain *pDomain)
2332 CONTRACT(DomainModule *)
2335 PRECONDITION(CheckPointer(pDomain));
2336 PRECONDITION(!IsManifest());
2337 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2344 RETURN (DomainModule *) FindDomainFile(pDomain);
2347 #ifndef DACCESS_COMPILE
2348 #include "staticallocationhelpers.inl"
2350 // Parses metadata and initializes offsets of per-class static blocks.
2351 void Module::BuildStaticsOffsets(AllocMemTracker *pamTracker)
2353 STANDARD_VM_CONTRACT;
2355 // Trade off here. We want a slot for each type. That way we can get to 2 bits per class and
2356 // index directly and not need a mapping from ClassID to MethodTable (we will use the RID
2358 IMDInternalImport *pImport = GetMDImport();
2360 DWORD * pRegularStaticOffsets = NULL;
2361 DWORD * pThreadStaticOffsets = NULL;
2363 // Get the number of types/classes defined in this module. Add 1 to count the module itself
2364 DWORD dwNumTypes = pImport->GetCountWithTokenKind(mdtTypeDef) + 1; // +1 for module type
2366 // [0] covers regular statics, [1] covers thread statics
2367 DWORD dwGCHandles[2] = { 0, 0 };
2369 // Organization in memory of the static block
2375 // | Class Data (one byte per class) | pointer to gc statics | primitive type statics |
2378 DWORD dwNonGCBytes[2] = {
2379 DomainLocalModule::OffsetOfDataBlob() + sizeof(BYTE)*dwNumTypes,
2380 ThreadLocalModule::OffsetOfDataBlob() + sizeof(BYTE)*dwNumTypes
2383 HENUMInternalHolder hTypeEnum(pImport);
2384 hTypeEnum.EnumAllInit(mdtTypeDef);
2387 // Parse each type of the class
2388 while (pImport->EnumNext(&hTypeEnum, &type))
2390 // Set offset for this type
2391 DWORD dwIndex = RidFromToken(type) - 1;
2393 // [0] covers regular statics, [1] covers thread statics
2394 DWORD dwAlignment[2] = { 1, 1 };
2395 DWORD dwClassNonGCBytes[2] = { 0, 0 };
2396 DWORD dwClassGCHandles[2] = { 0, 0 };
2398 // need to check if the type is generic and if so exclude it from iteration as we don't know the size
2399 HENUMInternalHolder hGenericEnum(pImport);
2400 hGenericEnum.EnumInit(mdtGenericParam, type);
2401 ULONG cGenericParams = pImport->EnumGetCount(&hGenericEnum);
2402 if (cGenericParams == 0)
2404 HENUMInternalHolder hFieldEnum(pImport);
2405 hFieldEnum.EnumInit(mdtFieldDef, type);
2408 // Parse each field of the type
2409 while (pImport->EnumNext(&hFieldEnum, &field))
2413 CorElementType ElementType = ELEMENT_TYPE_END;
2414 mdToken tkValueTypeToken = 0;
2415 int kk; // Use one set of variables for regular statics, and the other set for thread statics
2417 fSkip = GetStaticFieldElementTypeForFieldDef(this, pImport, field, &ElementType, &tkValueTypeToken, &kk);
2421 // We account for "regular statics" and "thread statics" separately.
2422 // Currently we are lumping RVA and context statics into "regular statics",
2423 // but we probably shouldn't.
2424 switch (ElementType)
2426 case ELEMENT_TYPE_I1:
2427 case ELEMENT_TYPE_U1:
2428 case ELEMENT_TYPE_BOOLEAN:
2429 dwClassNonGCBytes[kk] += 1;
2431 case ELEMENT_TYPE_I2:
2432 case ELEMENT_TYPE_U2:
2433 case ELEMENT_TYPE_CHAR:
2434 dwAlignment[kk] = max(2, dwAlignment[kk]);
2435 dwClassNonGCBytes[kk] += 2;
2437 case ELEMENT_TYPE_I4:
2438 case ELEMENT_TYPE_U4:
2439 case ELEMENT_TYPE_R4:
2440 dwAlignment[kk] = max(4, dwAlignment[kk]);
2441 dwClassNonGCBytes[kk] += 4;
2443 case ELEMENT_TYPE_FNPTR:
2444 case ELEMENT_TYPE_PTR:
2445 case ELEMENT_TYPE_I:
2446 case ELEMENT_TYPE_U:
2447 dwAlignment[kk] = max((1 << LOG2_PTRSIZE), dwAlignment[kk]);
2448 dwClassNonGCBytes[kk] += (1 << LOG2_PTRSIZE);
2450 case ELEMENT_TYPE_I8:
2451 case ELEMENT_TYPE_U8:
2452 case ELEMENT_TYPE_R8:
2453 dwAlignment[kk] = max(8, dwAlignment[kk]);
2454 dwClassNonGCBytes[kk] += 8;
2456 case ELEMENT_TYPE_VAR:
2457 case ELEMENT_TYPE_MVAR:
2458 case ELEMENT_TYPE_STRING:
2459 case ELEMENT_TYPE_SZARRAY:
2460 case ELEMENT_TYPE_ARRAY:
2461 case ELEMENT_TYPE_CLASS:
2462 case ELEMENT_TYPE_OBJECT:
2463 dwClassGCHandles[kk] += 1;
2465 case ELEMENT_TYPE_VALUETYPE:
2466 // Statics for valuetypes where the valuetype is defined in this module are handled here. Other valuetype statics utilize the pessimistic model below.
2467 dwClassGCHandles[kk] += 1;
2469 case ELEMENT_TYPE_END:
2471 // The actual element type was ELEMENT_TYPE_VALUETYPE, but the as we don't want to load additional assemblies
2472 // to determine these static offsets, we've fallen back to a pessimistic model.
2473 if (tkValueTypeToken != 0)
2475 // We'll have to be pessimistic here
2476 dwClassNonGCBytes[kk] += MAX_PRIMITIVE_FIELD_SIZE;
2477 dwAlignment[kk] = max(MAX_PRIMITIVE_FIELD_SIZE, dwAlignment[kk]);
2479 dwClassGCHandles[kk] += 1;
2484 // field has an unexpected type
2485 ThrowHR(VER_E_FIELD_SIG);
2491 if (pRegularStaticOffsets == NULL && (dwClassGCHandles[0] != 0 || dwClassNonGCBytes[0] != 0))
2493 // Lazily allocate table for offsets. We need offsets for GC and non GC areas. We add +1 to use as a sentinel.
2494 pRegularStaticOffsets = (PTR_DWORD)pamTracker->Track(
2495 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
2496 (S_SIZE_T(2 * sizeof(DWORD))*(S_SIZE_T(dwNumTypes)+S_SIZE_T(1)))));
2498 for (DWORD i = 0; i < dwIndex; i++) {
2499 pRegularStaticOffsets[i * 2 ] = dwGCHandles[0]*sizeof(OBJECTREF);
2500 pRegularStaticOffsets[i * 2 + 1] = dwNonGCBytes[0];
2504 if (pThreadStaticOffsets == NULL && (dwClassGCHandles[1] != 0 || dwClassNonGCBytes[1] != 0))
2506 // Lazily allocate table for offsets. We need offsets for GC and non GC areas. We add +1 to use as a sentinel.
2507 pThreadStaticOffsets = (PTR_DWORD)pamTracker->Track(
2508 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
2509 (S_SIZE_T(2 * sizeof(DWORD))*(S_SIZE_T(dwNumTypes)+S_SIZE_T(1)))));
2511 for (DWORD i = 0; i < dwIndex; i++) {
2512 pThreadStaticOffsets[i * 2 ] = dwGCHandles[1]*sizeof(OBJECTREF);
2513 pThreadStaticOffsets[i * 2 + 1] = dwNonGCBytes[1];
2518 if (pRegularStaticOffsets != NULL)
2520 // Align the offset of non gc statics
2521 dwNonGCBytes[0] = (DWORD) ALIGN_UP(dwNonGCBytes[0], dwAlignment[0]);
2523 // Save current offsets
2524 pRegularStaticOffsets[dwIndex*2] = dwGCHandles[0]*sizeof(OBJECTREF);
2525 pRegularStaticOffsets[dwIndex*2 + 1] = dwNonGCBytes[0];
2527 // Increment for next class
2528 dwGCHandles[0] += dwClassGCHandles[0];
2529 dwNonGCBytes[0] += dwClassNonGCBytes[0];
2532 if (pThreadStaticOffsets != NULL)
2534 // Align the offset of non gc statics
2535 dwNonGCBytes[1] = (DWORD) ALIGN_UP(dwNonGCBytes[1], dwAlignment[1]);
2537 // Save current offsets
2538 pThreadStaticOffsets[dwIndex*2] = dwGCHandles[1]*sizeof(OBJECTREF);
2539 pThreadStaticOffsets[dwIndex*2 + 1] = dwNonGCBytes[1];
2541 // Increment for next class
2542 dwGCHandles[1] += dwClassGCHandles[1];
2543 dwNonGCBytes[1] += dwClassNonGCBytes[1];
2547 m_maxTypeRidStaticsAllocated = dwNumTypes;
2549 if (pRegularStaticOffsets != NULL)
2551 pRegularStaticOffsets[dwNumTypes*2] = dwGCHandles[0]*sizeof(OBJECTREF);
2552 pRegularStaticOffsets[dwNumTypes*2 + 1] = dwNonGCBytes[0];
2555 if (pThreadStaticOffsets != NULL)
2557 pThreadStaticOffsets[dwNumTypes*2] = dwGCHandles[1]*sizeof(OBJECTREF);
2558 pThreadStaticOffsets[dwNumTypes*2 + 1] = dwNonGCBytes[1];
2561 m_pRegularStaticOffsets = pRegularStaticOffsets;
2562 m_pThreadStaticOffsets = pThreadStaticOffsets;
2564 m_dwMaxGCRegularStaticHandles = dwGCHandles[0];
2565 m_dwMaxGCThreadStaticHandles = dwGCHandles[1];
2567 m_dwRegularStaticsBlockSize = dwNonGCBytes[0];
2568 m_dwThreadStaticsBlockSize = dwNonGCBytes[1];
2571 void Module::GetOffsetsForRegularStaticData(
2573 BOOL bDynamic, DWORD dwGCStaticHandles,
2574 DWORD dwNonGCStaticBytes,
2575 DWORD * pOutStaticHandleOffset,
2576 DWORD * pOutNonGCStaticOffset)
2582 INJECT_FAULT(COMPlusThrowOM());
2586 *pOutStaticHandleOffset = 0;
2587 *pOutNonGCStaticOffset = 0;
2589 if (!dwGCStaticHandles && !dwNonGCStaticBytes)
2594 // Statics for instantiated types are allocated dynamically per-instantiation
2597 // Non GC statics are embedded in the Dynamic Entry.
2598 *pOutNonGCStaticOffset = DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob();
2602 if (m_pRegularStaticOffsets == NULL)
2604 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2606 _ASSERTE(m_pRegularStaticOffsets != (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED);
2608 // We allocate in the big blob.
2609 DWORD index = RidFromToken(cl) - 1;
2611 *pOutStaticHandleOffset = m_pRegularStaticOffsets[index*2];
2613 *pOutNonGCStaticOffset = m_pRegularStaticOffsets[index*2 + 1];
2615 // Check we didnt go out of what we predicted we would need for the class
2616 if (*pOutStaticHandleOffset + sizeof(OBJECTREF*)*dwGCStaticHandles >
2617 m_pRegularStaticOffsets[(index+1)*2] ||
2618 *pOutNonGCStaticOffset + dwNonGCStaticBytes >
2619 m_pRegularStaticOffsets[(index+1)*2 + 1])
2620 { // It's most likely that this is due to bad metadata, thus the exception. However, the
2621 // previous comments for this bit of code mentioned that this could be a corner case bug
2622 // with static field size estimation, though this is entirely unlikely since the code has
2623 // been this way for at least two releases.
2624 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2629 void Module::GetOffsetsForThreadStaticData(
2631 BOOL bDynamic, DWORD dwGCStaticHandles,
2632 DWORD dwNonGCStaticBytes,
2633 DWORD * pOutStaticHandleOffset,
2634 DWORD * pOutNonGCStaticOffset)
2640 INJECT_FAULT(COMPlusThrowOM());
2644 *pOutStaticHandleOffset = 0;
2645 *pOutNonGCStaticOffset = 0;
2647 if (!dwGCStaticHandles && !dwNonGCStaticBytes)
2652 // Statics for instantiated types are allocated dynamically per-instantiation
2655 // Non GC thread statics are embedded in the Dynamic Entry.
2656 *pOutNonGCStaticOffset = ThreadLocalModule::DynamicEntry::GetOffsetOfDataBlob();
2660 if (m_pThreadStaticOffsets == NULL)
2662 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2664 _ASSERTE(m_pThreadStaticOffsets != (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED);
2666 // We allocate in the big blob.
2667 DWORD index = RidFromToken(cl) - 1;
2669 *pOutStaticHandleOffset = m_pThreadStaticOffsets[index*2];
2671 *pOutNonGCStaticOffset = m_pThreadStaticOffsets[index*2 + 1];
2673 // Check we didnt go out of what we predicted we would need for the class
2674 if (*pOutStaticHandleOffset + sizeof(OBJECTREF*)*dwGCStaticHandles >
2675 m_pThreadStaticOffsets[(index+1)*2] ||
2676 *pOutNonGCStaticOffset + dwNonGCStaticBytes >
2677 m_pThreadStaticOffsets[(index+1)*2 + 1])
2679 // It's most likely that this is due to bad metadata, thus the exception. However, the
2680 // previous comments for this bit of code mentioned that this could be a corner case bug
2681 // with static field size estimation, though this is entirely unlikely since the code has
2682 // been this way for at least two releases.
2683 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2688 // initialize Crst controlling the Dynamic IL hashtable
2689 void Module::InitializeDynamicILCrst()
2691 Crst * pCrst = new Crst(CrstDynamicIL, CrstFlags(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD));
2692 if (InterlockedCompareExchangeT(
2693 &m_debuggerSpecificData.m_pDynamicILCrst, pCrst, NULL) != NULL)
2699 // Add a (token, address) pair to the table of IL blobs for reflection/dynamics
2702 // token method token
2703 // blobAddress address of the start of the IL blob address, including the header
2704 // fTemporaryOverride
2705 // is this a permanent override that should go in the
2706 // DynamicILBlobTable, or a temporary one?
2707 // Output: not explicit, but if the pair was not already in the table it will be added.
2708 // Does not add duplicate tokens to the table.
2710 void Module::SetDynamicIL(mdToken token, TADDR blobAddress, BOOL fTemporaryOverride)
2712 DynamicILBlobEntry entry = {mdToken(token), TADDR(blobAddress)};
2714 // Lazily allocate a Crst to serialize update access to the info structure.
2715 // Carefully synchronize to ensure we don't leak a Crst in race conditions.
2716 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2718 InitializeDynamicILCrst();
2721 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2723 // Figure out which table to fill in
2724 PTR_DynamicILBlobTable &table(fTemporaryOverride ? m_debuggerSpecificData.m_pTemporaryILBlobTable
2725 : m_debuggerSpecificData.m_pDynamicILBlobTable);
2727 // Lazily allocate the hash table.
2730 table = PTR_DynamicILBlobTable(new DynamicILBlobTable);
2732 table->AddOrReplace(entry);
2735 #endif // !DACCESS_COMPILE
2737 // Get the stored address of the IL blob for reflection/dynamics
2740 // token method token
2741 // fAllowTemporary also check the temporary overrides
2742 // Return Value: starting (target) address of the IL blob corresponding to the input token
2744 TADDR Module::GetDynamicIL(mdToken token, BOOL fAllowTemporary)
2748 #ifndef DACCESS_COMPILE
2749 // The Crst to serialize update access to the info structure is lazily allocated.
2750 // If it hasn't been allocated yet, then we don't have any IL blobs (temporary or otherwise)
2751 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2756 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2759 // Both hash tables are lazily allocated, so if they're NULL
2760 // then we have no IL blobs
2762 if (fAllowTemporary && m_debuggerSpecificData.m_pTemporaryILBlobTable != NULL)
2764 DynamicILBlobEntry entry = m_debuggerSpecificData.m_pTemporaryILBlobTable->Lookup(token);
2766 // Only return a value if the lookup succeeded
2767 if (!DynamicILBlobTraits::IsNull(entry))
2773 if (m_debuggerSpecificData.m_pDynamicILBlobTable == NULL)
2778 DynamicILBlobEntry entry = m_debuggerSpecificData.m_pDynamicILBlobTable->Lookup(token);
2779 // If the lookup fails, it returns the 'NULL' entry
2780 // The 'NULL' entry has m_il set to NULL, so either way we're safe
2784 #if !defined(DACCESS_COMPILE)
2785 //---------------------------------------------------------------------------------------
2787 // Add instrumented IL offset mapping for the specified method.
2790 // token - the MethodDef token of the method in question
2791 // mapping - the mapping information between original IL offsets and instrumented IL offsets
2794 // * Once added, the mapping stays valid until the Module containing the method is destructed.
2795 // * The profiler may potentially update the mapping more than once.
2798 void Module::SetInstrumentedILOffsetMapping(mdMethodDef token, InstrumentedILOffsetMapping mapping)
2800 ILOffsetMappingEntry entry(token, mapping);
2802 // Lazily allocate a Crst to serialize update access to the hash table.
2803 // Carefully synchronize to ensure we don't leak a Crst in race conditions.
2804 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2806 InitializeDynamicILCrst();
2809 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2811 // Lazily allocate the hash table.
2812 if (m_debuggerSpecificData.m_pILOffsetMappingTable == NULL)
2814 m_debuggerSpecificData.m_pILOffsetMappingTable = PTR_ILOffsetMappingTable(new ILOffsetMappingTable);
2817 ILOffsetMappingEntry currentEntry = m_debuggerSpecificData.m_pILOffsetMappingTable->Lookup(ILOffsetMappingTraits::GetKey(entry));
2818 if (!ILOffsetMappingTraits::IsNull(currentEntry))
2819 currentEntry.m_mapping.Clear();
2821 m_debuggerSpecificData.m_pILOffsetMappingTable->AddOrReplace(entry);
2823 #endif // DACCESS_COMPILE
2825 //---------------------------------------------------------------------------------------
2827 // Retrieve the instrumented IL offset mapping for the specified method.
2830 // token - the MethodDef token of the method in question
2833 // Return the mapping information between original IL offsets and instrumented IL offsets.
2834 // Check InstrumentedILOffsetMapping::IsNull() to see if any mapping is available.
2837 // * Once added, the mapping stays valid until the Module containing the method is destructed.
2838 // * The profiler may potentially update the mapping more than once.
2841 InstrumentedILOffsetMapping Module::GetInstrumentedILOffsetMapping(mdMethodDef token)
2852 // Lazily allocate a Crst to serialize update access to the hash table.
2853 // If the Crst is NULL, then we couldn't possibly have added any mapping yet, so just return NULL.
2854 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2856 InstrumentedILOffsetMapping emptyMapping;
2857 return emptyMapping;
2860 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2862 // If the hash table hasn't been created, then we couldn't possibly have added any mapping yet,
2863 // so just return NULL.
2864 if (m_debuggerSpecificData.m_pILOffsetMappingTable == NULL)
2866 InstrumentedILOffsetMapping emptyMapping;
2867 return emptyMapping;
2870 ILOffsetMappingEntry entry = m_debuggerSpecificData.m_pILOffsetMappingTable->Lookup(token);
2871 return entry.m_mapping;
2874 #undef DECODE_TYPEID
2875 #undef ENCODE_TYPEID
2876 #undef IS_ENCODED_TYPEID
2880 #ifndef DACCESS_COMPILE
2883 BOOL Module::IsNoStringInterning()
2892 if (!(m_dwPersistedFlags & COMPUTED_STRING_INTERNING))
2894 // The flags should be precomputed in native images
2895 _ASSERTE(!HasNativeImage());
2897 // Default is string interning
2898 BOOL fNoStringInterning = FALSE;
2902 // This flag applies to assembly, but it is stored on module so it can be cached in ngen image
2903 // Thus, we should ever need it for manifest module only.
2904 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2908 IfFailThrow(mdImport->GetAssemblyFromScope(&token));
2913 hr = mdImport->GetCustomAttributeByName(token,
2914 COMPILATIONRELAXATIONS_TYPE,
2915 (const void**)&pVal, &cbVal);
2917 // Parse the attribute
2920 CustomAttributeParser cap(pVal, cbVal);
2921 IfFailThrow(cap.SkipProlog());
2925 IfFailThrow(cap.GetU4(&flags));
2927 if (flags & CompilationRelaxations_NoStringInterning)
2929 fNoStringInterning = TRUE;
2934 static ConfigDWORD g_NoStringInterning;
2935 DWORD dwOverride = g_NoStringInterning.val(CLRConfig::INTERNAL_NoStringInterning);
2937 if (dwOverride == 0)
2940 fNoStringInterning = FALSE;
2942 else if (dwOverride == 2)
2944 // Always true (testing)
2945 fNoStringInterning = TRUE;
2949 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_STRING_INTERNING |
2950 (fNoStringInterning ? NO_STRING_INTERNING : 0));
2953 return !!(m_dwPersistedFlags & NO_STRING_INTERNING);
2956 BOOL Module::GetNeutralResourcesLanguage(LPCUTF8 * cultureName, ULONG * cultureNameLength, INT16 * fallbackLocation, BOOL cacheAttribute)
2958 STANDARD_VM_CONTRACT;
2960 BOOL retVal = FALSE;
2961 if (!(m_dwPersistedFlags & NEUTRAL_RESOURCES_LANGUAGE_IS_CACHED))
2963 const BYTE *pVal = NULL;
2966 // This flag applies to assembly, but it is stored on module so it can be cached in ngen image
2967 // Thus, we should ever need it for manifest module only.
2968 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2972 IfFailThrow(mdImport->GetAssemblyFromScope(&token));
2974 // Check for the existance of the attribute.
2975 HRESULT hr = mdImport->GetCustomAttributeByName(token,"System.Resources.NeutralResourcesLanguageAttribute",(const void **)&pVal, &cbVal);
2978 // we should not have a native image (it would have been cached at ngen time)
2979 _ASSERTE(!HasNativeImage());
2981 CustomAttributeParser cap(pVal, cbVal);
2982 IfFailThrow(cap.SkipProlog());
2983 IfFailThrow(cap.GetString(cultureName, cultureNameLength));
2984 IfFailThrow(cap.GetI2(fallbackLocation));
2985 // Should only be true on Module.Save(). Update flag to show we have the attribute cached
2987 FastInterlockOr(&m_dwPersistedFlags, NEUTRAL_RESOURCES_LANGUAGE_IS_CACHED);
2994 *cultureName = m_pszCultureName;
2995 *cultureNameLength = m_CultureNameLength;
2996 *fallbackLocation = m_FallbackLocation;
3000 // confirm that the NGENed attribute is correct
3001 LPCUTF8 pszCultureNameCheck = NULL;
3002 ULONG cultureNameLengthCheck = 0;
3003 INT16 fallbackLocationCheck = 0;
3004 const BYTE *pVal = NULL;
3007 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
3010 IfFailThrow(mdImport->GetAssemblyFromScope(&token));
3012 // Confirm that the attribute exists, and has the save value as when we ngen'd it
3013 HRESULT hr = mdImport->GetCustomAttributeByName(token,"System.Resources.NeutralResourcesLanguageAttribute",(const void **)&pVal, &cbVal);
3014 _ASSERTE(hr == S_OK);
3015 CustomAttributeParser cap(pVal, cbVal);
3016 IfFailThrow(cap.SkipProlog());
3017 IfFailThrow(cap.GetString(&pszCultureNameCheck, &cultureNameLengthCheck));
3018 IfFailThrow(cap.GetI2(&fallbackLocationCheck));
3019 _ASSERTE(cultureNameLengthCheck == m_CultureNameLength);
3020 _ASSERTE(fallbackLocationCheck == m_FallbackLocation);
3021 _ASSERTE(strncmp(pszCultureNameCheck,m_pszCultureName,m_CultureNameLength) == 0);
3029 BOOL Module::HasDefaultDllImportSearchPathsAttribute()
3039 if(IsDefaultDllImportSearchPathsAttributeCached())
3041 return (m_dwPersistedFlags & DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS) != 0 ;
3043 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
3045 BOOL attributeIsFound = FALSE;
3046 attributeIsFound = GetDefaultDllImportSearchPathsAttributeValue(mdImport, TokenFromRid(1, mdtAssembly),&m_DefaultDllImportSearchPathsAttributeValue);
3047 if(attributeIsFound)
3049 FastInterlockOr(&m_dwPersistedFlags, DEFAULT_DLL_IMPORT_SEARCH_PATHS_IS_CACHED | DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS);
3053 FastInterlockOr(&m_dwPersistedFlags, DEFAULT_DLL_IMPORT_SEARCH_PATHS_IS_CACHED);
3056 return (m_dwPersistedFlags & DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS) != 0 ;
3059 // Returns a BOOL to indicate if we have computed whether compiler has instructed us to
3060 // wrap the non-CLS compliant exceptions or not.
3061 BOOL Module::IsRuntimeWrapExceptionsStatusComputed()
3063 LIMITED_METHOD_CONTRACT;
3065 return (m_dwPersistedFlags & COMPUTED_WRAP_EXCEPTIONS);
3068 BOOL Module::IsRuntimeWrapExceptions()
3073 if (IsRuntimeWrapExceptionsStatusComputed()) GC_NOTRIGGER; else GC_TRIGGERS;
3078 if (!(IsRuntimeWrapExceptionsStatusComputed()))
3080 // The flags should be precomputed in native images
3081 _ASSERTE(!HasNativeImage());
3084 BOOL fRuntimeWrapExceptions = FALSE;
3086 // This flag applies to assembly, but it is stored on module so it can be cached in ngen image
3087 // Thus, we should ever need it for manifest module only.
3088 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
3091 IfFailGo(mdImport->GetAssemblyFromScope(&token));
3096 hr = mdImport->GetCustomAttributeByName(token,
3097 RUNTIMECOMPATIBILITY_TYPE,
3098 (const void**)&pVal, &cbVal);
3100 // Parse the attribute
3103 CustomAttributeParser ca(pVal, cbVal);
3104 CaNamedArg namedArgs[1] = {{0}};
3106 // First, the void constructor:
3107 IfFailGo(ParseKnownCaArgs(ca, NULL, 0));
3109 // Then, find the named argument
3110 namedArgs[0].InitBoolField("WrapNonExceptionThrows");
3112 IfFailGo(ParseKnownCaNamedArgs(ca, namedArgs, lengthof(namedArgs)));
3114 if (namedArgs[0].val.boolean)
3115 fRuntimeWrapExceptions = TRUE;
3118 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_WRAP_EXCEPTIONS |
3119 (fRuntimeWrapExceptions ? WRAP_EXCEPTIONS : 0));
3122 return !!(m_dwPersistedFlags & WRAP_EXCEPTIONS);
3125 BOOL Module::IsPreV4Assembly()
3135 if (!(m_dwPersistedFlags & COMPUTED_IS_PRE_V4_ASSEMBLY))
3137 // The flags should be precomputed in native images
3138 _ASSERTE(!HasNativeImage());
3140 IMDInternalImport *pImport = GetAssembly()->GetManifestImport();
3143 BOOL fIsPreV4Assembly = FALSE;
3144 LPCSTR szVersion = NULL;
3145 if (SUCCEEDED(pImport->GetVersionString(&szVersion)))
3147 if (szVersion != NULL && strlen(szVersion) > 2)
3149 fIsPreV4Assembly = (szVersion[0] == 'v' || szVersion[0] == 'V') &&
3150 (szVersion[1] == '1' || szVersion[1] == '2');
3154 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_IS_PRE_V4_ASSEMBLY |
3155 (fIsPreV4Assembly ? IS_PRE_V4_ASSEMBLY : 0));
3158 return !!(m_dwPersistedFlags & IS_PRE_V4_ASSEMBLY);
3162 DWORD Module::GetReliabilityContract()
3172 if (!(m_dwPersistedFlags & COMPUTED_RELIABILITY_CONTRACT))
3174 // The flags should be precomputed in native images
3175 _ASSERTE(!HasNativeImage());
3177 // This flag applies to assembly, but it is stored on module so it can be cached in ngen image
3178 // Thus, we should ever need it for manifest module only.
3179 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
3181 m_dwReliabilityContract = ::GetReliabilityContract(mdImport, TokenFromRid(1, mdtAssembly));
3183 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_RELIABILITY_CONTRACT);
3186 return m_dwReliabilityContract;
3188 #endif // FEATURE_CER
3190 ArrayDPTR(FixupPointer<PTR_MethodTable>) ModuleCtorInfo::GetGCStaticMTs(DWORD index)
3192 LIMITED_METHOD_CONTRACT;
3194 if (index < numHotGCStaticsMTs)
3196 _ASSERTE(ppHotGCStaticsMTs != NULL);
3198 return ppHotGCStaticsMTs + index;
3202 _ASSERTE(ppColdGCStaticsMTs != NULL);
3204 // shift the start of the cold table because all cold offsets are also shifted
3205 return ppColdGCStaticsMTs + (index - numHotGCStaticsMTs);
3209 DWORD Module::AllocateDynamicEntry(MethodTable *pMT)
3215 PRECONDITION(pMT->GetModuleForStatics() == this);
3216 PRECONDITION(pMT->IsDynamicStatics());
3217 PRECONDITION(!pMT->ContainsGenericVariables());
3221 DWORD newId = FastInterlockExchangeAdd((LONG*)&m_cDynamicEntries, 1);
3223 if (newId >= m_maxDynamicEntries)
3225 CrstHolder ch(&m_Crst);
3227 if (newId >= m_maxDynamicEntries)
3229 SIZE_T maxDynamicEntries = max(16, m_maxDynamicEntries);
3230 while (maxDynamicEntries <= newId)
3232 maxDynamicEntries *= 2;
3235 DynamicStaticsInfo* pNewDynamicStaticsInfo = (DynamicStaticsInfo*)
3236 (void*)GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(DynamicStaticsInfo)) * S_SIZE_T(maxDynamicEntries));
3238 if (m_pDynamicStaticsInfo)
3239 memcpy(pNewDynamicStaticsInfo, m_pDynamicStaticsInfo, sizeof(DynamicStaticsInfo) * m_maxDynamicEntries);
3241 m_pDynamicStaticsInfo = pNewDynamicStaticsInfo;
3242 m_maxDynamicEntries = maxDynamicEntries;
3246 EnsureWritablePages(&(m_pDynamicStaticsInfo[newId]))->pEnclosingMT = pMT;
3248 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Assigned dynamic ID %d to %s\n", newId, pMT->GetDebugClassName()));
3253 void Module::FreeModuleIndex()
3262 if (GetAssembly()->IsDomainNeutral())
3264 // We do not recycle ModuleIndexes used by domain neutral Modules.
3268 if (m_ModuleID != NULL)
3270 // Module's m_ModuleID should not contain the ID, it should
3271 // contain a pointer to the DLM
3272 _ASSERTE(!Module::IsEncodedModuleIndex((SIZE_T)m_ModuleID));
3273 _ASSERTE(m_ModuleIndex == m_ModuleID->GetModuleIndex());
3275 // Get the ModuleIndex from the DLM and free it
3276 Module::FreeModuleIndex(m_ModuleIndex);
3280 // This was an empty, short-lived Module object that
3281 // was never assigned a ModuleIndex...
3289 ModuleIndex Module::AllocateModuleIndex()
3292 g_pModuleIndexDispenser->NewId(NULL, val);
3294 // For various reasons, the IDs issued by the IdDispenser start at 1.
3295 // Domain neutral module IDs have historically started at 0, and we
3296 // have always assigned ID 0 to mscorlib. Thus, to make it so that
3297 // domain neutral module IDs start at 0, we will subtract 1 from the
3298 // ID that we got back from the ID dispenser.
3299 ModuleIndex index((SIZE_T)(val-1));
3304 void Module::FreeModuleIndex(ModuleIndex index)
3306 WRAPPER_NO_CONTRACT;
3307 // We subtracted 1 after we allocated this ID, so we need to
3308 // add 1 before we free it.
3309 DWORD val = index.m_dwIndex + 1;
3311 g_pModuleIndexDispenser->DisposeId(val);
3315 void Module::AllocateRegularStaticHandles(AppDomain* pDomain)
3324 #ifndef CROSSGEN_COMPILE
3325 if (NingenEnabled())
3328 // Allocate the handles we will need. Note that AllocateStaticFieldObjRefPtrs will only
3329 // allocate if pModuleData->GetGCStaticsBasePointerAddress(pMT) != 0, avoiding creating
3330 // handles more than once for a given MT or module
3332 DomainLocalModule *pModuleData = GetDomainLocalModule(pDomain);
3334 _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointerAddress() != NULL);
3335 if (this->m_dwMaxGCRegularStaticHandles > 0)
3337 // If we're setting up a non-default domain, we want the allocation to look like it's
3338 // coming from the created domain.
3340 // REVISIT_TODO: The comparison "pDomain != GetDomain()" will always be true for domain-neutral
3341 // modules, since GetDomain() will return the SharedDomain, which is NOT an AppDomain.
3342 // Was this intended? If so, there should be a clarifying comment. If not, then we should
3343 // probably do "pDomain != GetAppDomain()" instead.
3345 if (pDomain != GetDomain() &&
3346 pDomain != SystemDomain::System()->DefaultDomain() &&
3349 pDomain->AllocateStaticFieldObjRefPtrsCrossDomain(this->m_dwMaxGCRegularStaticHandles,
3350 pModuleData->GetPrecomputedGCStaticsBasePointerAddress());
3354 pDomain->AllocateStaticFieldObjRefPtrs(this->m_dwMaxGCRegularStaticHandles,
3355 pModuleData->GetPrecomputedGCStaticsBasePointerAddress());
3358 // We should throw if we fail to allocate and never hit this assert
3359 _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointer() != NULL);
3361 #endif // CROSSGEN_COMPILE
3364 BOOL Module::IsStaticStoragePrepared(mdTypeDef tkType)
3366 LIMITED_METHOD_CONTRACT;
3368 // Right now the design is that we do one static allocation pass during NGEN,
3369 // and a 2nd pass for it at module init time for modules that weren't NGENed or the NGEN
3370 // pass was unsucessful. If we are loading types after that then we must use dynamic
3371 // static storage. These dynamic statics require an additional indirection so they
3372 // don't perform quite as well.
3374 // This check was created for the scenario where a profiler adds additional types
3375 // however it seems likely this check would also accurately handle other dynamic
3376 // scenarios such as ref.emit and EnC as long as they are adding new types and
3377 // not new statics to existing types.
3378 _ASSERTE(TypeFromToken(tkType) == mdtTypeDef);
3379 return m_maxTypeRidStaticsAllocated >= RidFromToken(tkType);
3382 void Module::AllocateStatics(AllocMemTracker *pamTracker)
3384 STANDARD_VM_CONTRACT;
3388 m_dwRegularStaticsBlockSize = DomainLocalModule::OffsetOfDataBlob();
3389 m_dwThreadStaticsBlockSize = ThreadLocalModule::OffsetOfDataBlob();
3391 // If it has no code, we don't have to allocate anything
3392 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Resource module %s. No statics neeeded\n", GetSimpleName()));
3393 _ASSERTE(m_maxTypeRidStaticsAllocated == 0);
3396 #ifdef FEATURE_PREJIT
3397 if (m_pRegularStaticOffsets == (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED)
3399 _ASSERTE(HasNativeImage());
3401 // This is an ngen image and all the classes were loaded at ngen time, so we're done.
3402 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: 'Complete' Native image found, no statics parsing needed for module %s.\n", GetSimpleName()));
3403 // typeDefs rids 0 and 1 aren't included in the count, thus X typeDefs means rid X+1 is valid
3404 _ASSERTE(m_maxTypeRidStaticsAllocated == GetMDImport()->GetCountWithTokenKind(mdtTypeDef) + 1);
3408 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Allocating statics for module %s\n", GetSimpleName()));
3410 // 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
3411 // for non gc types)
3412 BuildStaticsOffsets(pamTracker);
3415 // This method will report GC static refs of the module. It doesn't have to be complete (ie, it's
3416 // currently used to opportunistically get more concurrency in the marking of statics), so it currently
3417 // ignores any statics that are not preallocated (ie: won't report statics from IsDynamicStatics() MT)
3418 // The reason this function is in Module and not in DomainFile (together with DomainLocalModule is because
3419 // for shared modules we need a very fast way of getting to the DomainLocalModule. For that we use
3420 // a table in DomainLocalBlock that's indexed with a module ID
3422 // This method is a secondary way for the GC to find statics, and it is only used when we are on
3423 // a multiproc machine and we are using the ServerHeap. The primary way used by the GC to find
3424 // statics is through the handle table. Module::AllocateRegularStaticHandles() allocates a GC handle
3425 // from the handle table, and the GC will trace this handle and find the statics.
3427 void Module::EnumRegularStaticGCRefs(AppDomain* pAppDomain, promote_func* fn, ScanContext* sc)
3436 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
3437 GCHeapUtilities::IsServerHeap() &&
3438 IsGCSpecialThread());
3441 DomainLocalModule *pModuleData = GetDomainLocalModule(pAppDomain);
3442 DWORD dwHandles = m_dwMaxGCRegularStaticHandles;
3449 LOG((LF_GC, LL_INFO100, "Scanning statics for module %s\n", GetSimpleName()));
3451 OBJECTREF* ppObjectRefs = pModuleData->GetPrecomputedGCStaticsBasePointer();
3452 for (DWORD i = 0 ; i < dwHandles ; i++)
3454 // Handles are allocated in SetDomainFile (except for bootstrapped mscorlib). In any
3455 // case, we shouldnt get called if the module hasn't had it's handles allocated (as we
3456 // only get here if IsActive() is true, which only happens after SetDomainFile(), which
3457 // is were we allocate handles.
3458 _ASSERTE(ppObjectRefs);
3459 fn((Object **)(ppObjectRefs+i), sc, 0);
3462 LOG((LF_GC, LL_INFO100, "Done scanning statics for module %s\n", GetSimpleName()));
3467 void Module::SetDomainFile(DomainFile *pDomainFile)
3472 PRECONDITION(CheckPointer(pDomainFile));
3473 PRECONDITION(IsManifest() == pDomainFile->IsAssembly());
3480 DomainLocalModule* pModuleData = 0;
3482 // Do we need to allocate memory for the non GC statics?
3483 if ((GetAssembly()->IsDomainNeutral() && !IsSingleAppDomain())|| m_ModuleID == NULL)
3485 // Allocate memory for the module statics.
3486 LoaderAllocator *pLoaderAllocator = NULL;
3487 if (GetAssembly()->IsCollectible())
3489 pLoaderAllocator = GetAssembly()->GetLoaderAllocator();
3493 pLoaderAllocator = pDomainFile->GetAppDomain()->GetLoaderAllocator();
3496 SIZE_T size = GetDomainLocalModuleSize();
3498 LOG((LF_CLASSLOADER, LL_INFO10, "STATICS: Allocating %i bytes for precomputed statics in module %S in LoaderAllocator %p\n",
3499 size, this->GetDebugName(), pLoaderAllocator));
3501 // We guarantee alignment for 64-bit regular statics on 32-bit platforms even without FEATURE_64BIT_ALIGNMENT for performance reasons.
3503 _ASSERTE(size >= DomainLocalModule::OffsetOfDataBlob());
3505 pModuleData = (DomainLocalModule*)(void*)
3506 pLoaderAllocator->GetHighFrequencyHeap()->AllocAlignedMem(
3507 size, MAX_PRIMITIVE_FIELD_SIZE);
3509 // Note: Memory allocated on loader heap is zero filled
3510 // memset(pModuleData, 0, size);
3512 // Verify that the space is really zero initialized
3513 _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointer() == NULL);
3515 // Make sure that the newly allocated DomainLocalModule gets
3516 // a copy of the domain-neutral module ID.
3517 if (GetAssembly()->IsDomainNeutral() && !IsSingleAppDomain())
3519 // If the module was loaded as domain-neutral, we can find the ID by
3520 // casting 'm_ModuleID'.
3522 _ASSERTE(Module::IDToIndex((SIZE_T)m_ModuleID) == this->m_ModuleIndex);
3523 pModuleData->m_ModuleIndex = Module::IDToIndex((SIZE_T)m_ModuleID);
3525 // Eventually I want to just do this instead...
3526 //pModuleData->m_ModuleIndex = this->m_ModuleIndex;
3530 // If the module was loaded as domain-specific, then we need to assign
3531 // this module a domain-neutral module ID.
3532 pModuleData->m_ModuleIndex = Module::AllocateModuleIndex();
3533 m_ModuleIndex = pModuleData->m_ModuleIndex;
3538 pModuleData = this->m_ModuleID;
3539 LOG((LF_CLASSLOADER, LL_INFO10, "STATICS: Allocation not needed for ngened non shared module %s in Appdomain %08x\n"));
3542 if (GetAssembly()->IsDomainNeutral() && !IsSingleAppDomain())
3544 DomainLocalBlock *pLocalBlock;
3546 pLocalBlock = pDomainFile->GetAppDomain()->GetDomainLocalBlock();
3547 pLocalBlock->SetModuleSlot(GetModuleIndex(), pModuleData);
3550 pLocalBlock->SetDomainFile(GetModuleIndex(), pDomainFile);
3554 // Non shared case, module points directly to the statics. In ngen case
3555 // m_pDomainModule is already set for the non shared case
3556 if (m_ModuleID == NULL)
3558 m_ModuleID = pModuleData;
3561 m_ModuleID->SetDomainFile(pDomainFile);
3564 // Allocate static handles now.
3565 // NOTE: Bootstrapping issue with mscorlib - we will manually allocate later
3566 if (g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] != NULL)
3567 AllocateRegularStaticHandles(pDomainFile->GetAppDomain());
3570 #ifndef CROSSGEN_COMPILE
3571 OBJECTREF Module::GetExposedObject()
3576 POSTCONDITION(RETVAL != NULL);
3583 RETURN GetDomainFile()->GetExposedModuleObject();
3585 #endif // CROSSGEN_COMPILE
3588 // AllocateMap allocates the RID maps based on the size of the current
3589 // metadata (if any)
3592 void Module::AllocateMaps()
3605 TYPEDEF_MAP_INITIAL_SIZE = 5,
3606 TYPEREF_MAP_INITIAL_SIZE = 5,
3607 MEMBERDEF_MAP_INITIAL_SIZE = 10,
3608 GENERICPARAM_MAP_INITIAL_SIZE = 5,
3609 GENERICTYPEDEF_MAP_INITIAL_SIZE = 5,
3610 FILEREFERENCES_MAP_INITIAL_SIZE = 5,
3611 ASSEMBLYREFERENCES_MAP_INITIAL_SIZE = 5,
3614 PTR_TADDR pTable = NULL;
3621 // For dynamic modules, it is essential that we at least have a TypeDefToMethodTable
3622 // map with an initial block. Otherwise, all the iterators will abort on an
3623 // initial empty table and we will e.g. corrupt the backpatching chains during
3624 // an appdomain unload.
3625 m_TypeDefToMethodTableMap.dwCount = TYPEDEF_MAP_INITIAL_SIZE;
3627 // The above is essential. The following ones are precautionary.
3628 m_TypeRefToMethodTableMap.dwCount = TYPEREF_MAP_INITIAL_SIZE;
3629 m_MethodDefToDescMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE;
3630 m_FieldDefToDescMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE;
3631 m_GenericParamToDescMap.dwCount = GENERICPARAM_MAP_INITIAL_SIZE;
3632 m_GenericTypeDefToCanonMethodTableMap.dwCount = TYPEDEF_MAP_INITIAL_SIZE;
3633 m_FileReferencesMap.dwCount = FILEREFERENCES_MAP_INITIAL_SIZE;
3634 m_ManifestModuleReferencesMap.dwCount = ASSEMBLYREFERENCES_MAP_INITIAL_SIZE;
3635 m_MethodDefToPropertyInfoMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE;
3639 IMDInternalImport * pImport = GetMDImport();
3641 // Get # TypeDefs (add 1 for COR_GLOBAL_PARENT_TOKEN)
3642 m_TypeDefToMethodTableMap.dwCount = pImport->GetCountWithTokenKind(mdtTypeDef)+2;
3645 m_TypeRefToMethodTableMap.dwCount = pImport->GetCountWithTokenKind(mdtTypeRef)+1;
3648 m_MethodDefToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtMethodDef)+1;
3651 m_FieldDefToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtFieldDef)+1;
3653 // Get # GenericParams
3654 m_GenericParamToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtGenericParam)+1;
3656 // Get the number of FileReferences in the map
3657 m_FileReferencesMap.dwCount = pImport->GetCountWithTokenKind(mdtFile)+1;
3659 // Get the number of AssemblyReferences in the map
3660 m_ManifestModuleReferencesMap.dwCount = pImport->GetCountWithTokenKind(mdtAssemblyRef)+1;
3662 // These maps are only added to during NGen, so for other scenarios leave them empty
3663 if (IsCompilationProcess())
3665 m_GenericTypeDefToCanonMethodTableMap.dwCount = m_TypeDefToMethodTableMap.dwCount;
3666 m_MethodDefToPropertyInfoMap.dwCount = m_MethodDefToDescMap.dwCount;
3670 m_GenericTypeDefToCanonMethodTableMap.dwCount = 0;
3671 m_MethodDefToPropertyInfoMap.dwCount = 0;
3677 nTotal += m_TypeDefToMethodTableMap.dwCount;
3678 nTotal += m_TypeRefToMethodTableMap.dwCount;
3679 nTotal += m_MethodDefToDescMap.dwCount;
3680 nTotal += m_FieldDefToDescMap.dwCount;
3681 nTotal += m_GenericParamToDescMap.dwCount;
3682 nTotal += m_GenericTypeDefToCanonMethodTableMap.dwCount;
3683 nTotal += m_FileReferencesMap.dwCount;
3684 nTotal += m_ManifestModuleReferencesMap.dwCount;
3685 nTotal += m_MethodDefToPropertyInfoMap.dwCount;
3687 _ASSERTE (m_pAssembly && m_pAssembly->GetLowFrequencyHeap());
3688 pTable = (PTR_TADDR)(void*)m_pAssembly->GetLowFrequencyHeap()->AllocMem(nTotal * S_SIZE_T(sizeof(TADDR)));
3690 // Note: Memory allocated on loader heap is zero filled
3691 // memset(pTable, 0, nTotal * sizeof(void*));
3693 m_TypeDefToMethodTableMap.pNext = NULL;
3694 m_TypeDefToMethodTableMap.supportedFlags = TYPE_DEF_MAP_ALL_FLAGS;
3695 m_TypeDefToMethodTableMap.pTable = pTable;
3697 m_TypeRefToMethodTableMap.pNext = NULL;
3698 m_TypeRefToMethodTableMap.supportedFlags = TYPE_REF_MAP_ALL_FLAGS;
3699 m_TypeRefToMethodTableMap.pTable = &pTable[m_TypeDefToMethodTableMap.dwCount];
3701 m_MethodDefToDescMap.pNext = NULL;
3702 m_MethodDefToDescMap.supportedFlags = METHOD_DEF_MAP_ALL_FLAGS;
3703 m_MethodDefToDescMap.pTable = &m_TypeRefToMethodTableMap.pTable[m_TypeRefToMethodTableMap.dwCount];
3705 m_FieldDefToDescMap.pNext = NULL;
3706 m_FieldDefToDescMap.supportedFlags = FIELD_DEF_MAP_ALL_FLAGS;
3707 m_FieldDefToDescMap.pTable = &m_MethodDefToDescMap.pTable[m_MethodDefToDescMap.dwCount];
3709 m_GenericParamToDescMap.pNext = NULL;
3710 m_GenericParamToDescMap.supportedFlags = GENERIC_PARAM_MAP_ALL_FLAGS;
3711 m_GenericParamToDescMap.pTable = &m_FieldDefToDescMap.pTable[m_FieldDefToDescMap.dwCount];
3713 m_GenericTypeDefToCanonMethodTableMap.pNext = NULL;
3714 m_GenericTypeDefToCanonMethodTableMap.supportedFlags = GENERIC_TYPE_DEF_MAP_ALL_FLAGS;
3715 m_GenericTypeDefToCanonMethodTableMap.pTable = &m_GenericParamToDescMap.pTable[m_GenericParamToDescMap.dwCount];
3717 m_FileReferencesMap.pNext = NULL;
3718 m_FileReferencesMap.supportedFlags = FILE_REF_MAP_ALL_FLAGS;
3719 m_FileReferencesMap.pTable = &m_GenericTypeDefToCanonMethodTableMap.pTable[m_GenericTypeDefToCanonMethodTableMap.dwCount];
3721 m_ManifestModuleReferencesMap.pNext = NULL;
3722 m_ManifestModuleReferencesMap.supportedFlags = MANIFEST_MODULE_MAP_ALL_FLAGS;
3723 m_ManifestModuleReferencesMap.pTable = &m_FileReferencesMap.pTable[m_FileReferencesMap.dwCount];
3725 m_MethodDefToPropertyInfoMap.pNext = NULL;
3726 m_MethodDefToPropertyInfoMap.supportedFlags = PROPERTY_INFO_MAP_ALL_FLAGS;
3727 m_MethodDefToPropertyInfoMap.pTable = &m_ManifestModuleReferencesMap.pTable[m_ManifestModuleReferencesMap.dwCount];
3732 // FreeClassTables frees the classes in the module
3735 void Module::FreeClassTables()
3746 if (m_dwTransientFlags & CLASSES_FREED)
3749 FastInterlockOr(&m_dwTransientFlags, CLASSES_FREED);
3751 // disable ibc here because it can cause errors during the destruction of classes
3752 IBCLoggingDisabler disableLogging;
3755 DebugLogRidMapOccupancy();
3759 // Free the types filled out in the TypeDefToEEClass map
3762 // Go through each linked block
3763 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
3764 while (typeDefIter.Next())
3766 MethodTable * pMT = typeDefIter.GetElement();
3768 if (pMT != NULL && pMT->IsRestored())
3770 pMT->GetClass()->Destruct(pMT);
3774 // Now do the same for constructed types (arrays and instantiated generic types)
3775 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
3776 { // separate AllocMemTracker. Though you're supposed to destruct everything else before destructing the AllocMemTracker, this is an easy invariant to break so
3777 // we'll play extra safe on this end.
3778 if (m_pAvailableParamTypes != NULL)
3780 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
3781 EETypeHashEntry *pEntry;
3782 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
3784 TypeHandle th = pEntry->GetTypeHandle();
3786 if (!th.IsRestored())
3789 #ifdef FEATURE_COMINTEROP
3790 // Some MethodTables/TypeDescs have COM interop goo attached to them which must be released
3791 if (!th.IsTypeDesc())
3793 MethodTable *pMT = th.AsMethodTable();
3794 if (pMT->HasCCWTemplate() && (!pMT->IsZapped() || pMT->GetZapModule() == this))
3796 // code:MethodTable::GetComCallWrapperTemplate() may go through canonical methodtable indirection cell.
3797 // The module load could be aborted before completing code:FILE_LOAD_EAGER_FIXUPS phase that's responsible
3798 // for resolving pre-restored indirection cells, so we have to check for it here explicitly.
3799 if (CORCOMPILE_IS_POINTER_TAGGED(pMT->GetCanonicalMethodTableFixup()))
3802 ComCallWrapperTemplate *pTemplate = pMT->GetComCallWrapperTemplate();
3803 if (pTemplate != NULL)
3805 pTemplate->Release();
3809 else if (th.IsArray())
3811 ComCallWrapperTemplate *pTemplate = th.AsArray()->GetComCallWrapperTemplate();
3812 if (pTemplate != NULL)
3814 pTemplate->Release();
3817 #endif // FEATURE_COMINTEROP
3819 // We need to call destruct on instances of EEClass whose "canonical" dependent lives in this table
3820 // There is nothing interesting to destruct on array EEClass
3821 if (!th.IsTypeDesc())
3823 MethodTable * pMT = th.AsMethodTable();
3824 if (pMT->IsCanonicalMethodTable() && (!pMT->IsZapped() || pMT->GetZapModule() == this))
3825 pMT->GetClass()->Destruct(pMT);
3832 #endif // !DACCESS_COMPILE
3834 ClassLoader *Module::GetClassLoader()
3836 WRAPPER_NO_CONTRACT;
3838 _ASSERTE(m_pAssembly != NULL);
3839 return m_pAssembly->GetLoader();
3842 PTR_BaseDomain Module::GetDomain()
3844 WRAPPER_NO_CONTRACT;
3846 _ASSERTE(m_pAssembly != NULL);
3847 return m_pAssembly->GetDomain();
3850 #ifndef DACCESS_COMPILE
3852 IAssemblySecurityDescriptor *Module::GetSecurityDescriptor()
3854 WRAPPER_NO_CONTRACT;
3855 _ASSERTE(m_pAssembly != NULL);
3856 return m_pAssembly->GetSecurityDescriptor();
3859 #ifndef CROSSGEN_COMPILE
3860 void Module::StartUnload()
3862 WRAPPER_NO_CONTRACT;
3863 #ifdef PROFILING_SUPPORTED
3865 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
3866 if (!IsBeingUnloaded())
3868 // Profiler is causing some peripheral class loads. Probably this just needs
3869 // to be turned into a Fault_not_fatal and moved to a specific place inside the profiler.
3873 g_profControlBlock.pProfInterface->ModuleUnloadStarted((ModuleID) this);
3878 EX_END_CATCH(SwallowAllExceptions);
3882 #endif // PROFILING_SUPPORTED
3883 #ifdef FEATURE_PREJIT
3884 // Write out the method profile data
3885 /*hr=*/WriteMethodProfileDataLogFile(true);
3886 #endif // FEATURE_PREJIT
3889 #endif // CROSSGEN_COMPILE
3891 void Module::ReleaseILData(void)
3893 WRAPPER_NO_CONTRACT;
3895 ReleaseISymUnmanagedReader();
3899 #ifdef FEATURE_FUSION
3902 // Module::FusionCopyPDBs asks Fusion to copy PDBs for a given
3903 // assembly if they need to be copied. This is for the case where a PE
3904 // file is shadow copied to the Fusion cache. Fusion needs to be told
3905 // to take the time to copy the PDB, too.
3907 STDAPI CopyPDBs(IAssembly *pAsm); // private fusion API
3908 void Module::FusionCopyPDBs(LPCWSTR moduleName)
3919 Assembly *pAssembly = GetAssembly();
3921 // Just return if we've already done this for this Module's
3923 if ((pAssembly->GetDebuggerInfoBits() & DACF_PDBS_COPIED) ||
3924 (pAssembly->GetFusionAssembly() == NULL))
3926 LOG((LF_CORDB, LL_INFO10,
3927 "Don't need to copy PDB's for module %S\n",
3933 LOG((LF_CORDB, LL_INFO10,
3934 "Attempting to copy PDB's for module %S\n", moduleName));
3937 hr = CopyPDBs(pAssembly->GetFusionAssembly());
3938 LOG((LF_CORDB, LL_INFO10,
3939 "Fusion.dll!CopyPDBs returned hr=0x%08x for module 0x%08x\n",
3942 // Remember that we've copied the PDBs for this assembly.
3943 pAssembly->SetCopiedPDBs();
3946 // This function will return PDB stream if exist.
3947 // It is the caller responsibility to call release on *ppStream after a successful
3949 // We will first check to see if we have a cached pdb stream available. If not,
3950 // we will ask fusion which in terms to ask host vis HostProvideAssembly. Host may
3951 // decide to provide one or not.
3953 HRESULT Module::GetHostPdbStream(IStream **ppStream)
3958 if(GetThread()) {GC_TRIGGERS;} else {GC_NOTRIGGER;}
3962 HRESULT hr = NOERROR;
3968 if (m_file->IsIStream() == false)
3970 // not a host stream
3974 // Maybe fusion can ask our host. This will give us back a PDB stream if
3975 // host decides to provide one.
3977 if (m_file->IsAssembly())
3980 hr = ((PEAssembly*)m_file)->GetIHostAssembly()->GetAssemblyDebugStream(ppStream);
3984 _ASSERTE(m_file->IsModule());
3985 IHostAssemblyModuleImport *pIHAMI;
3986 MAKE_WIDEPTR_FROMUTF8_NOTHROW(pName, m_file->GetSimpleName());
3988 return E_OUTOFMEMORY;
3989 IfFailRet(m_file->GetAssembly()->GetIHostAssembly()->GetModuleByName(pName, &pIHAMI));
3990 hr = pIHAMI->GetModuleDebugStream(ppStream);
3997 //---------------------------------------------------------------------------------------
3999 // Simple wrapper around calling IsAfContentType_WindowsRuntime() against the flags
4000 // returned from the PEAssembly's GetFlagsNoTrigger()
4003 // nonzero iff we successfully determined pModule is a WinMD. FALSE if pModule is not
4004 // a WinMD, or we fail trying to find out.
4006 BOOL Module::IsWindowsRuntimeModule()
4012 CAN_TAKE_LOCK; // Accesses metadata directly, which takes locks
4021 if (FAILED(GetAssembly()->GetManifestFile()->GetFlagsNoTrigger(&dwFlags)))
4024 return IsAfContentType_WindowsRuntime(dwFlags);
4027 BOOL Module::IsInCurrentVersionBubble()
4029 LIMITED_METHOD_CONTRACT;
4031 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
4032 if (!IsCompilationProcess())
4035 // The module being compiled is always part of the current version bubble
4036 AppDomain * pAppDomain = GetAppDomain();
4037 if (pAppDomain->IsCompilationDomain() && pAppDomain->ToCompilationDomain()->GetTargetModule() == this)
4040 if (IsReadyToRunCompilation())
4043 #ifdef FEATURE_COMINTEROP
4044 if (g_fNGenWinMDResilient)
4045 return !GetAssembly()->IsWinMD();
4049 #else // FEATURE_NATIVE_IMAGE_GENERATION
4051 #endif // FEATURE_NATIVE_IMAGE_GENERATION
4054 //---------------------------------------------------------------------------------------
4056 // WinMD-aware helper to grab a readable public metadata interface. Any place that thinks
4057 // it wants to use Module::GetRWImporter + QI now should use this wrapper instead.
4060 // * dwOpenFlags - Combo from CorOpenFlags. Better not contain ofWrite!
4061 // * riid - Public IID requested
4062 // * ppvInterface - [out] Requested interface. On success, *ppvInterface is returned
4063 // refcounted; caller responsible for Release.
4066 // HRESULT indicating success or failure.
4068 HRESULT Module::GetReadablePublicMetaDataInterface(DWORD dwOpenFlags, REFIID riid, LPVOID * ppvInterface)
4074 CAN_TAKE_LOCK; // IsWindowsRuntimeModule accesses metadata directly, which takes locks
4079 _ASSERTE((dwOpenFlags & ofWrite) == 0);
4081 // Temporary place to store public, AddRef'd interface pointers
4082 ReleaseHolder<IUnknown> pIUnkPublic;
4084 // Temporary place to store the IUnknown from which we'll do the final QI to get the
4085 // requested public interface. Any assignment to pIUnk assumes pIUnk does not need
4086 // to do a Release() (either the interface was internal and not AddRef'd, or was
4087 // public and will be released by the above holder).
4088 IUnknown * pIUnk = NULL;
4092 // Normally, we just get an RWImporter to do the QI on, and we're on our way.
4095 pIUnk = GetRWImporter();
4097 EX_CATCH_HRESULT_NO_ERRORINFO(hr);
4099 if (FAILED(hr) && IsWindowsRuntimeModule())
4101 // WinMD modules don't like creating RW importers. They also (currently)
4102 // have no plumbing to get to their public metadata interfaces from the
4103 // Module. So we actually have to start from scratch at the dispenser.
4105 // To start with, get a dispenser, and get the metadata memory blob we've
4106 // already loaded. If either of these fail, just return the error HRESULT
4107 // from the above GetRWImporter() call.
4109 // We'll get an addref'd IMetaDataDispenser, so use a holder to release it
4110 ReleaseHolder<IMetaDataDispenser> pDispenser;
4111 if (FAILED(InternalCreateMetaDataDispenser(IID_IMetaDataDispenser, &pDispenser)))
4113 _ASSERTE(FAILED(hr));
4117 COUNT_T cbMetadata = 0;
4118 PTR_CVOID pvMetadata = GetAssembly()->GetManifestFile()->GetLoadedMetadata(&cbMetadata);
4119 if ((pvMetadata == NULL) || (cbMetadata == 0))
4121 _ASSERTE(FAILED(hr));
4125 // Now that the pieces are ready, we can use the riid specified by the
4126 // profiler in this call to the dispenser to get the requested interface. If
4127 // this fails, then this is the interesting HRESULT for the caller to see.
4129 // We'll get an AddRef'd public interface, so use a holder to release it
4130 hr = pDispenser->OpenScopeOnMemory(
4133 (dwOpenFlags | ofReadOnly), // Force ofReadOnly on behalf of the profiler
4139 // Set pIUnk so we can do the final QI from it below as we do in the other
4141 pIUnk = pIUnkPublic;
4144 // Get the requested interface
4145 if (SUCCEEDED(hr) && (ppvInterface != NULL))
4147 _ASSERTE(pIUnk != NULL);
4148 hr = pIUnk->QueryInterface(riid, (void **) ppvInterface);
4154 // a special token that indicates no reader could be created - don't try again
4155 static ISymUnmanagedReader* const k_pInvalidSymReader = (ISymUnmanagedReader*)0x1;
4157 #if defined(FEATURE_ISYM_READER) && !defined(CROSSGEN_COMPILE)
4158 ISymUnmanagedReader *Module::GetISymUnmanagedReaderNoThrow(void)
4160 CONTRACT(ISymUnmanagedReader *)
4163 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
4165 WRAPPER(GC_TRIGGERS);
4170 ISymUnmanagedReader *ret = NULL;
4174 ret = GetISymUnmanagedReader();
4178 // We swallow any exception and say that we simply couldn't get a reader by returning NULL.
4179 // The only type of error that should be possible here is OOM.
4180 /* DISABLED due to Dev10 bug 619495
4181 CONSISTENCY_CHECK_MSG(
4182 GET_EXCEPTION()->GetHR() == E_OUTOFMEMORY,
4183 "Exception from GetISymUnmanagedReader");
4186 EX_END_CATCH(RethrowTerminalExceptions);
4191 ISymUnmanagedReader *Module::GetISymUnmanagedReader(void)
4193 CONTRACT(ISymUnmanagedReader *)
4196 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
4197 PRECONDITION(Security::IsResolved(GetAssembly()));
4199 WRAPPER(GC_TRIGGERS);
4204 // No symbols for resource modules
4211 // Verify that symbol reading is permitted for this module.
4212 // If we know we've already created a symbol reader, don't bother checking. There is
4213 // no advantage to allowing symbol reading to be turned off if we've already created the reader.
4214 // Note that we can't just put this code in the creation block below because we might have to
4215 // call managed code to resolve security policy, and we can't do that while holding a lock.
4216 // There is no disadvantage other than a minor perf cost to calling this unnecessarily, so the
4217 // race on m_pISymUnmanagedReader here is OK. The perf cost is minor because the only real
4218 // work is done by the security system which caches the result.
4219 if( m_pISymUnmanagedReader == NULL && !IsSymbolReadingEnabled() )
4222 // Take the lock for the m_pISymUnmanagedReader
4223 // This ensures that we'll only ever attempt to create one reader at a time, and we won't
4224 // create a reader if we're in the middle of destroying one that has become stale.
4225 // Actual access to the reader can safely occur outside the lock as long as it has its own
4226 // AddRef which we take inside the lock at the bottom of this method.
4227 CrstHolder holder(&m_ISymUnmanagedReaderCrst);
4229 UINT lastErrorMode = 0;
4231 // If we haven't created a reader yet, do so now
4232 if (m_pISymUnmanagedReader == NULL)
4234 // Mark our reader as invalid so that if we fail to create the reader
4235 // (including if an exception is thrown), we won't keep trying.
4236 m_pISymUnmanagedReader = k_pInvalidSymReader;
4238 // There are 4 main cases here:
4239 // 1. Assembly is on disk and we'll get the symbols from a file next to the assembly
4240 // 2. Assembly is provided by the host and we'll get the symbols from the host
4241 // 3. Assembly was loaded in-memory (by byte array or ref-emit), and symbols were
4242 // provided along with it.
4243 // 4. Assembly was loaded in-memory but no symbols were provided.
4245 // Determine whether we should be looking in memory for the symbols (cases 2 & 3)
4246 bool fInMemorySymbols = ( m_file->IsIStream() || GetInMemorySymbolStream() );
4247 if( !fInMemorySymbols && m_file->GetPath().IsEmpty() )
4249 // Case 4. We don't have a module path, an IStream or an in memory symbol stream,
4250 // so there is no-where to try and get symbols from.
4254 // Create a binder to find the reader.
4256 // <REVISIT_TODO>@perf: this is slow, creating and destroying the binder every
4257 // time. We should cache this somewhere, but I'm not 100% sure
4258 // where right now...</REVISIT_TODO>
4261 SafeComHolder<ISymUnmanagedBinder> pBinder;
4263 if (g_pDebugInterface == NULL)
4265 // @TODO: this is reachable when debugging!
4266 UNREACHABLE_MSG("About to CoCreateInstance! This code should not be "
4267 "reachable or needs to be reimplemented for CoreCLR!");
4270 if (this->GetInMemorySymbolStreamFormat() == eSymbolFormatILDB)
4272 // We've got in-memory ILDB symbols, create the ILDB symbol binder
4273 // Note that in this case, we must be very careful not to use diasymreader.dll
4274 // at all - we don't trust it, and shouldn't run any code in it
4275 IfFailThrow(IldbSymbolsCreateInstance(CLSID_CorSymBinder_SxS,
4276 IID_ISymUnmanagedBinder,
4281 // We're going to be working with PDB format symbols
4282 // Attempt to coCreate the symbol binder.
4283 // CoreCLR supports not having a symbol reader installed, so this is expected there.
4284 // On desktop, the framework installer is supposed to install diasymreader.dll as well
4285 // and so this shouldn't happen.
4286 hr = FakeCoCreateInstanceEx(CLSID_CorSymBinder_SxS,
4287 NATIVE_SYMBOL_READER_DLL,
4288 IID_ISymUnmanagedBinder,
4298 LOG((LF_CORDB, LL_INFO10, "M::GISUR: Created binder\n"));
4300 // Note: we change the error mode here so we don't get any popups as the PDB symbol reader attempts to search the
4301 // hard disk for files.
4302 lastErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
4304 SafeComHolder<ISymUnmanagedReader> pReader;
4306 if (fInMemorySymbols)
4308 SafeComHolder<IStream> pIStream( NULL );
4310 // If debug stream is already specified, don't bother to go through fusion
4311 // This is the common case for case 2 (hosted modules) and case 3 (Ref.Emit).
4312 if (GetInMemorySymbolStream() )
4315 if( IsReflection() )
4317 // If this is Reflection.Emit, we must clone the stream because another thread may
4318 // update it when someone is using the reader we create here leading to AVs.
4319 // Note that the symbol stream should be up to date since we flush the writer
4320 // after every addition in Module::AddClass.
4321 IfFailThrow(GetInMemorySymbolStream()->Clone(&pIStream));
4325 // The stream is not changing. Just add-ref to it.
4326 pIStream = GetInMemorySymbolStream();
4330 #ifdef FEATURE_FUSION
4333 // Verified this above.
4334 _ASSERTE(m_file->IsIStream());
4336 // Case 2: get assembly from host.
4337 // This commonly would be cached already as GetInMemorySymbolStream() in code:Module.FetchPdbsFromHost,
4338 // but may not be cached if the host didn't provide the PDBs at the time.
4339 hr = GetHostPdbStream(&pIStream);
4344 hr = pBinder->GetReaderFromStream(GetRWImporter(), pIStream, &pReader);
4349 // The assembly is on disk, so try and load symbols based on the path to the assembly (case 1)
4350 const SString &path = m_file->GetPath();
4352 // Call Fusion to ensure that any PDB's are shadow copied before
4353 // trying to get a symbol reader. This has to be done once per
4355 #ifdef FEATURE_FUSION
4356 FusionCopyPDBs(path);
4358 // for this to work with winmds we cannot simply call GetRWImporter() as winmds are RO
4359 // and thus don't implement the RW interface. so we call this wrapper function which knows
4360 // how to get a IMetaDataImport interface regardless of the underlying module type.
4361 ReleaseHolder<IUnknown> pUnk = NULL;
4362 hr = GetReadablePublicMetaDataInterface(ofReadOnly, IID_IMetaDataImport, &pUnk);
4364 hr = pBinder->GetReaderForFile(pUnk, path, NULL, &pReader);
4367 SetErrorMode(lastErrorMode);
4371 m_pISymUnmanagedReader = pReader.Extract();
4372 LOG((LF_CORDB, LL_INFO10, "M::GISUR: Loaded symbols for module %S\n", GetDebugName()));
4376 // We failed to create the reader, don't try again next time
4377 LOG((LF_CORDB, LL_INFO10, "M::GISUR: Failed to load symbols for module %S\n", GetDebugName()));
4378 _ASSERTE( m_pISymUnmanagedReader == k_pInvalidSymReader );
4381 } // if( m_pISymUnmanagedReader == NULL )
4383 // If we previously failed to create the reader, return NULL
4384 if (m_pISymUnmanagedReader == k_pInvalidSymReader)
4389 // Success - return an AddRef'd copy of the reader
4390 m_pISymUnmanagedReader->AddRef();
4391 RETURN (m_pISymUnmanagedReader);
4393 #endif // FEATURE_ISYM_READER && !CROSSGEN_COMPILE
4395 BOOL Module::IsSymbolReadingEnabled()
4406 // The only time we need symbols available is for debugging and taking stack traces,
4407 // neither of which can be done if the assembly can't run. The advantage of being strict
4408 // is that there is a perf penalty adding types to a module if you must support reading
4409 // symbols at any time. If symbols don't need to be accesible then we can
4410 // optimize by only commiting symbols when the assembly is saved to disk. See DDB 671107.
4411 if(!GetAssembly()->HasRunAccess())
4416 // If the module has symbols in-memory (eg. RefEmit) that are in ILDB
4417 // format, then there isn't any reason not to supply them. The reader
4418 // code is always available, and we trust it's security.
4419 if (this->GetInMemorySymbolStreamFormat() == eSymbolFormatILDB)
4424 #ifdef DEBUGGING_SUPPORTED
4425 if (!g_pDebugInterface)
4427 // if debugging is disabled (no debug pack installed), do not load symbols
4428 // This is done for two reasons. We don't completely trust the security of
4429 // the diasymreader.dll code, so we don't want to use it in mainline scenarios.
4430 // Secondly, there's not reason that diasymreader.dll will even necssarily be
4431 // be on the machine if the debug pack isn't installed.
4434 #endif // DEBUGGING_SUPPORTED
4436 #ifdef FEATURE_INCLUDE_ALL_INTERFACES
4437 // See if there is an explicit policy configuration overriding our default.
4438 // This can be set by the SymbolReadingPolicy config switch or by a host via
4439 // ICLRDebugManager.AllowFileLineInfo.
4440 ESymbolReadingPolicy policy = CCLRDebugManager::GetSymbolReadingPolicy();
4441 if( policy == eSymbolReadingAlways )
4445 else if( policy == eSymbolReadingNever )
4449 _ASSERTE( policy == eSymbolReadingFullTrustOnly );
4450 #endif // FEATURE_INCLUDE_ALL_INTERFACES
4452 // Default policy - only read symbols corresponding to full-trust assemblies.
4453 // Note that there is no strong (cryptographic) connection between a symbol file and its assembly.
4454 // The intent here is just to ensure that the common high-risk scenarios (AppLaunch, etc)
4455 // will never be able to load untrusted PDB files.
4457 if (GetSecurityDescriptor()->IsFullyTrusted())
4464 // At this point, this is only called when we're creating an appdomain
4465 // out of an array of bytes, so we'll keep the IStream that we create
4466 // around in case the debugger attaches later (including detach & re-attach!)
4467 void Module::SetSymbolBytes(LPCBYTE pbSyms, DWORD cbSyms)
4469 STANDARD_VM_CONTRACT;
4471 // Create a IStream from the memory for the syms.
4472 SafeComHolder<CGrowableStream> pStream(new CGrowableStream());
4474 // Do not need to AddRef the CGrowableStream because the constructor set it to 1
4475 // ref count already. The Module will keep a copy for its own use.
4477 // Make sure to set the symbol stream on the module before
4478 // attempting to send UpdateModuleSyms messages up for it.
4479 SetInMemorySymbolStream(pStream, eSymbolFormatPDB);
4481 // This can only be called when the module is being created. No-one should have
4482 // tried to use the symbols yet, and so there should not be a reader.
4483 // If instead, we wanted to call this when a reader could have been created, we need to
4484 // serialize access by taking the reader lock, and flush the old reader by calling
4485 // code:Module.ReleaseISymUnmanagedReader
4486 _ASSERTE( m_pISymUnmanagedReader == NULL );
4489 LPCWSTR pName = NULL;
4490 pName = GetDebugName();
4494 DWORD dwError = pStream->Write((const void *)pbSyms,
4497 IfFailThrow(HRESULT_FROM_WIN32(dwError));
4499 #if PROFILING_SUPPORTED && !defined(CROSSGEN_COMPILE)
4500 BEGIN_PIN_PROFILER(CORProfilerInMemorySymbolsUpdatesEnabled());
4502 g_profControlBlock.pProfInterface->ModuleInMemorySymbolsUpdated((ModuleID) this);
4505 #endif //PROFILING_SUPPORTED && !defined(CROSSGEN_COMPILE)
4507 ETW::CodeSymbolLog::EmitCodeSymbols(this);
4509 // Tell the debugger that symbols have been loaded for this
4510 // module. We iterate through all domains which contain this
4511 // module's assembly, and send a debugger notify for each one.
4512 // <REVISIT_TODO>@perf: it would scale better if we directly knew which domains
4513 // the assembly was loaded in.</REVISIT_TODO>
4514 if (CORDebuggerAttached())
4516 AppDomainIterator i(FALSE);
4520 AppDomain *pDomain = i.GetDomain();
4522 if (pDomain->IsDebuggerAttached() && (GetDomain() == SystemDomain::System() ||
4523 pDomain->ContainsAssembly(m_pAssembly)))
4525 g_pDebugInterface->SendUpdateModuleSymsEventAndBlock(this, pDomain);
4531 // Clear any cached symbol reader
4532 void Module::ReleaseISymUnmanagedReader(void)
4543 // Caller is responsible for taking the reader lock if the call could occur when
4544 // other threads are using or creating the reader
4545 if( m_pISymUnmanagedReader != NULL )
4547 // If we previously failed to create a reader, don't attempt to release it
4548 // but do clear it out so that we can try again (eg. symbols may have changed)
4549 if( m_pISymUnmanagedReader != k_pInvalidSymReader )
4551 m_pISymUnmanagedReader->Release();
4553 m_pISymUnmanagedReader = NULL;
4557 // Lazily creates a new IL stub cache for this module.
4558 ILStubCache* Module::GetILStubCache()
4565 INJECT_FAULT(COMPlusThrowOM(););
4569 // Use per-AD cache for domain specific modules when not NGENing
4570 BaseDomain *pDomain = GetDomain();
4571 if (!pDomain->IsSharedDomain() && !pDomain->AsAppDomain()->IsCompilationDomain())
4572 return pDomain->AsAppDomain()->GetILStubCache();
4574 if (m_pILStubCache == NULL)
4576 ILStubCache *pILStubCache = new ILStubCache(GetLoaderAllocator()->GetHighFrequencyHeap());
4578 if (FastInterlockCompareExchangePointer(&m_pILStubCache, pILStubCache, NULL) != NULL)
4580 // some thread swooped in and set the field
4581 delete pILStubCache;
4584 _ASSERTE(m_pILStubCache != NULL);
4585 return m_pILStubCache;
4588 // Called to finish the process of adding a new class with Reflection.Emit
4589 void Module::AddClass(mdTypeDef classdef)
4597 PRECONDITION(!IsResource());
4601 // The fake class associated with the module (global fields & functions) needs to be initialized here
4602 // Normal classes are added to the available class hash when their typedef is first created.
4603 if (RidFromToken(classdef) == 0)
4605 BuildClassForModule();
4608 // Since the module is being modified, the in-memory symbol stream
4609 // (if any) has probably also been modified. If we support reading the symbols
4610 // then we need to commit the changes to the writer and flush any old readers
4611 // However if we don't support reading then we can skip this which will give
4612 // a substantial perf improvement. See DDB 671107.
4613 if(IsSymbolReadingEnabled())
4615 CONSISTENCY_CHECK(IsReflection()); // this is only used for dynamic modules
4616 ISymUnmanagedWriter * pWriter = GetReflectionModule()->GetISymUnmanagedWriter();
4617 if (pWriter != NULL)
4619 // Serialize with any concurrent reader creations
4620 // Specifically, if we started creating a reader on one thread, and then updated the
4621 // symbols on another thread, we need to wait until the initial reader creation has
4622 // completed and release it so we don't get stuck with a stale reader.
4623 // Also, if we commit to the stream while we're in the process of creating a reader,
4624 // the reader will get corrupted/incomplete data.
4625 // Note that we must also be in co-operative mode here to ensure the debugger helper
4626 // thread can't be simultaneously reading this stream while the process is synchronized
4627 // (code:Debugger::GetSymbolBytes)
4628 CrstHolder holder(&m_ISymUnmanagedReaderCrst);
4630 // Flush writes to the symbol store to the symbol stream
4631 // Note that we do this when finishing the addition of the class, instead of
4632 // on-demand in GetISymUnmanagedReader because the writer is not thread-safe.
4633 // Here, we're inside the lock of TypeBuilder.CreateType, and so it's safe to
4634 // manipulate the writer.
4635 SafeComHolderPreemp<ISymUnmanagedWriter3> pWriter3;
4636 HRESULT thr = pWriter->QueryInterface(IID_ISymUnmanagedWriter3, (void**)&pWriter3);
4637 CONSISTENCY_CHECK(SUCCEEDED(thr));
4640 thr = pWriter3->Commit();
4643 // Flush any cached symbol reader to ensure we pick up any new symbols
4644 ReleaseISymUnmanagedReader();
4648 // If either the QI or Commit failed
4651 // The only way we expect this might fail is out-of-memory. In that
4652 // case we silently fail to update the symbol stream with new data, but
4653 // we leave the existing reader intact.
4654 CONSISTENCY_CHECK(thr==E_OUTOFMEMORY);
4660 //---------------------------------------------------------------------------
4661 // For the global class this builds the table of MethodDescs an adds the rids
4662 // to the MethodDef map.
4663 //---------------------------------------------------------------------------
4664 void Module::BuildClassForModule()
4675 IMDInternalImport * pImport = GetMDImport();
4676 DWORD cFunctions, cFields;
4679 // Obtain count of global functions
4680 HENUMInternalHolder hEnum(pImport);
4681 hEnum.EnumGlobalFunctionsInit();
4682 cFunctions = pImport->EnumGetCount(&hEnum);
4686 // Obtain count of global fields
4687 HENUMInternalHolder hEnum(pImport);
4688 hEnum.EnumGlobalFieldsInit();
4689 cFields = pImport->EnumGetCount(&hEnum);
4692 // If we have any work to do...
4693 if (cFunctions > 0 || cFields > 0)
4695 COUNTER_ONLY(size_t _HeapSize = 0);
4697 TypeKey typeKey(this, COR_GLOBAL_PARENT_TOKEN);
4698 TypeHandle typeHnd = GetClassLoader()->LoadTypeHandleForTypeKeyNoLock(&typeKey);
4700 #ifdef ENABLE_PERF_COUNTERS
4702 _HeapSize = GetLoaderAllocator()->GetHighFrequencyHeap()->GetSize();
4704 GetPerfCounters().m_Loading.cbLoaderHeapSize = _HeapSize;
4705 #endif // ENABLE_PERF_COUNTERS
4710 #endif // !DACCESS_COMPILE
4712 // Returns true iff the debugger should be notified about this module
4715 // Debugger doesn't need to be notified about modules that can't be executed,
4716 // like inspection and resource only. These are just pure data.
4718 // This should be immutable for an instance of a module. That ensures that the debugger gets consistent
4719 // notifications about it. It this value mutates, than the debugger may miss relevant notifications.
4720 BOOL Module::IsVisibleToDebugger()
4722 WRAPPER_NO_CONTRACT;
4730 if (IsIntrospectionOnly())
4736 // If for whatever other reason, we can't run it, then don't notify the debugger about it.
4737 Assembly * pAssembly = GetAssembly();
4738 if (!pAssembly->HasRunAccess())
4745 PEImageLayout * Module::GetNativeOrReadyToRunImage()
4747 LIMITED_METHOD_CONTRACT;
4749 #ifdef FEATURE_READYTORUN
4751 return GetReadyToRunInfo()->GetImage();
4754 return GetNativeImage();
4757 PTR_CORCOMPILE_IMPORT_SECTION Module::GetImportSections(COUNT_T *pCount)
4766 #ifdef FEATURE_READYTORUN
4768 return GetReadyToRunInfo()->GetImportSections(pCount);
4771 return GetNativeImage()->GetNativeImportSections(pCount);
4774 PTR_CORCOMPILE_IMPORT_SECTION Module::GetImportSectionFromIndex(COUNT_T index)
4783 #ifdef FEATURE_READYTORUN
4785 return GetReadyToRunInfo()->GetImportSectionFromIndex(index);
4788 return GetNativeImage()->GetNativeImportSectionFromIndex(index);
4791 PTR_CORCOMPILE_IMPORT_SECTION Module::GetImportSectionForRVA(RVA rva)
4800 #ifdef FEATURE_READYTORUN
4802 return GetReadyToRunInfo()->GetImportSectionForRVA(rva);
4805 return GetNativeImage()->GetNativeImportSectionForRVA(rva);
4808 TADDR Module::GetIL(DWORD target)
4810 WRAPPER_NO_CONTRACT;
4816 return m_file->GetIL(target);
4819 PTR_VOID Module::GetRvaField(DWORD rva, BOOL fZapped)
4821 WRAPPER_NO_CONTRACT;
4824 #ifdef FEATURE_PREJIT
4825 if (fZapped && m_file->IsILOnly())
4827 return dac_cast<PTR_VOID>(m_file->GetLoadedNative()->GetRvaData(rva,NULL_OK));
4829 #endif // FEATURE_PREJIT
4831 return m_file->GetRvaField(rva);
4834 #ifndef DACCESS_COMPILE
4836 CHECK Module::CheckRvaField(RVA field)
4838 WRAPPER_NO_CONTRACT;
4839 if (!IsReflection())
4840 CHECK(m_file->CheckRvaField(field));
4844 CHECK Module::CheckRvaField(RVA field, COUNT_T size)
4853 if (!IsReflection())
4854 CHECK(m_file->CheckRvaField(field, size));
4858 #endif // !DACCESS_COMPILE
4860 BOOL Module::HasTls()
4862 WRAPPER_NO_CONTRACT;
4864 return m_file->HasTls();
4867 BOOL Module::IsRvaFieldTls(DWORD rva)
4869 WRAPPER_NO_CONTRACT;
4871 return m_file->IsRvaFieldTls(rva);
4874 UINT32 Module::GetFieldTlsOffset(DWORD rva)
4876 WRAPPER_NO_CONTRACT;
4878 return m_file->GetFieldTlsOffset(rva);
4881 UINT32 Module::GetTlsIndex()
4883 WRAPPER_NO_CONTRACT;
4885 return m_file->GetTlsIndex();
4888 PCCOR_SIGNATURE Module::GetSignature(RVA signature)
4890 WRAPPER_NO_CONTRACT;
4892 return m_file->GetSignature(signature);
4895 RVA Module::GetSignatureRva(PCCOR_SIGNATURE signature)
4897 WRAPPER_NO_CONTRACT;
4899 return m_file->GetSignatureRva(signature);
4904 // In DAC builds this function was being called on host addresses which may or may not
4905 // have been marshalled from the target. Such addresses can't be reliably mapped back to
4906 // target addresses, which means we can't tell whether they came from the IL or not
4908 // Security note: Any security which you might wish to gain by verifying the origin of
4909 // a signature isn't available in DAC. The attacker can provide a dump which spoofs all
4910 // module ranges. In other words the attacker can make the signature appear to come from
4911 // anywhere, but still violate all the rules that a signature from that location would
4912 // otherwise follow. I am removing this function from DAC in order to prevent anyone from
4913 // getting a false sense of security (in addition to its functional shortcomings)
4915 #ifndef DACCESS_COMPILE
4916 BOOL Module::IsSigInIL(PCCOR_SIGNATURE signature)
4929 return m_file->IsPtrInILImage(signature);
4932 #ifdef FEATURE_PREJIT
4933 StubMethodHashTable *Module::GetStubMethodHashTable()
4942 if (m_pStubMethodHashTable == NULL && SystemDomain::GetCurrentDomain()->IsCompilationDomain())
4944 // we only need to create the hash table when NGENing, it is read-only at run-time
4945 AllocMemTracker amTracker;
4946 m_pStubMethodHashTable = StubMethodHashTable::Create(GetLoaderAllocator(), this, METHOD_STUBS_HASH_BUCKETS, &amTracker);
4947 amTracker.SuppressRelease();
4950 return m_pStubMethodHashTable;
4952 #endif // FEATURE_PREJIT
4954 CHECK Module::CheckSignatureRva(RVA signature)
4956 WRAPPER_NO_CONTRACT;
4957 CHECK(m_file->CheckSignatureRva(signature));
4961 CHECK Module::CheckSignature(PCCOR_SIGNATURE signature)
4963 WRAPPER_NO_CONTRACT;
4964 CHECK(m_file->CheckSignature(signature));
4968 void Module::InitializeStringData(DWORD token, EEStringData *pstrData, CQuickBytes *pqb)
4976 INJECT_FAULT(COMPlusThrowOM());
4977 PRECONDITION(TypeFromToken(token) == mdtString);
4984 if (FAILED(GetMDImport()->GetUserString(token, &dwCharCount, &fIs80Plus, &pString)) ||
4987 THROW_BAD_FORMAT(BFA_BAD_STRING_TOKEN_RANGE, this);
4991 pstrData->SetStringBuffer(pString);
4992 #else // !!BIGENDIAN
4993 _ASSERTE(pqb != NULL);
4997 pSwapped = (LPWSTR) pqb->AllocThrows(dwCharCount * sizeof(WCHAR));
4998 memcpy((void*)pSwapped, (void*)pString, dwCharCount*sizeof(WCHAR));
4999 SwapStringLength(pSwapped, dwCharCount);
5001 pstrData->SetStringBuffer(pSwapped);
5002 #endif // !!BIGENDIAN
5004 // MD and String look at this bit in opposite ways. Here's where we'll do the conversion.
5005 // MD sets the bit to true if the string contains characters greater than 80.
5006 // String sets the bit to true if the string doesn't contain characters greater than 80.
5008 pstrData->SetCharCount(dwCharCount);
5009 pstrData->SetIsOnlyLowChars(!fIs80Plus);
5012 #ifndef CROSSGEN_COMPILE
5014 #ifdef FEATURE_PREJIT
5015 OBJECTHANDLE Module::ResolveStringRefHelper(DWORD token, BaseDomain *pDomain, PTR_CORCOMPILE_IMPORT_SECTION pSection, EEStringData *pStrData)
5017 PEImageLayout *pNativeImage = GetNativeImage();
5021 TADDR tableBase = pNativeImage->GetDirectoryData(&pSection->Section, &tableSize);
5023 // Walk the handle table.
5024 // @TODO: If we ever care about the perf of this function, we could sort the tokens
5025 // using as a key the string they point to, so we could do a binary search
5026 for (SIZE_T * pEntry = (SIZE_T *)tableBase ; pEntry < (SIZE_T *)(tableBase + tableSize); pEntry++)
5028 // Ensure that the compiler won't fetch the value twice
5029 SIZE_T entry = VolatileLoadWithoutBarrier(pEntry);
5031 if (CORCOMPILE_IS_POINTER_TAGGED(entry))
5033 BYTE * pBlob = (BYTE *) pNativeImage->GetRvaData(CORCOMPILE_UNTAG_TOKEN(entry));
5035 // Note that we only care about strings from current module, and so we do not check ENCODE_MODULE_OVERRIDE
5036 if (*pBlob++ == ENCODE_STRING_HANDLE &&
5037 TokenFromRid(CorSigUncompressData((PCCOR_SIGNATURE&) pBlob), mdtString) == token)
5039 EnsureWritablePages(pEntry);
5041 // This string hasn't been fixed up. Synchronize the update with the normal
5044 CrstHolder ch(this->GetFixupCrst());
5046 if (!CORCOMPILE_IS_POINTER_TAGGED(*pEntry))
5048 // We lost the race, just return current entry
5052 *pEntry = (SIZE_T) ResolveStringRef(token, pDomain, false);
5056 return (OBJECTHANDLE) *pEntry;
5061 OBJECTREF* pRef = (OBJECTREF*) entry;
5062 _ASSERTE((*pRef)->GetMethodTable() == g_pStringClass);
5064 STRINGREF stringRef = (STRINGREF) *pRef;
5066 // Is this the string we are trying to resolve?
5067 if (pStrData->GetCharCount() == stringRef->GetStringLength() &&
5068 memcmp((void*)pStrData->GetStringBuffer(),
5069 (void*) stringRef->GetBuffer(),
5070 pStrData->GetCharCount()*sizeof(WCHAR)) == 0)
5072 // We found it, so we just have to return this instance
5073 return (OBJECTHANDLE) entry;
5079 #endif // FEATURE_PREJIT
5081 OBJECTHANDLE Module::ResolveStringRef(DWORD token, BaseDomain *pDomain, bool bNeedToSyncWithFixups)
5089 INJECT_FAULT(COMPlusThrowOM());
5090 PRECONDITION(TypeFromToken(token) == mdtString);
5094 EEStringData strData;
5095 OBJECTHANDLE string = NULL;
5098 InitializeStringData(token, &strData, NULL);
5099 #else // !!BIGENDIAN
5101 InitializeStringData(token, &strData, &qb);
5102 #endif // !!BIGENDIAN
5106 // We can only do this for native images as they guarantee that resolvestringref will be
5107 // called only once per string from this module. @TODO: We really dont have any way of asserting
5108 // this, which would be nice... (and is needed to guarantee correctness)
5109 #ifdef FEATURE_PREJIT
5110 if (HasNativeImage() && IsNoStringInterning())
5112 if (bNeedToSyncWithFixups)
5114 // In an ngen image, it is possible that we get here but not be coming from a fixup,
5115 // (FixupNativeEntry case). In that unfortunate case (ngen partial images, dynamic methods,
5116 // lazy string inits) we will have to troll through the fixup list, and in the case the string is there,
5117 // reuse it, if it's there but hasn't been fixed up, fix it up now, and in the case it isn't
5118 // there at all, then go to our old style string interning. Going through this code path is
5119 // guaranteed to be slow. If necessary, we can further optimize it by sorting the token table,
5120 // Another way of solving this would be having a token to string table (would require knowing
5121 // all our posible stings in the ngen case (this is possible by looking at the IL))
5123 PEImageLayout * pNativeImage = GetNativeImage();
5126 PTR_CORCOMPILE_IMPORT_SECTION pSections = pNativeImage->GetNativeImportSections(&nSections);
5128 for (COUNT_T iSection = 0; iSection < nSections; iSection++)
5130 PTR_CORCOMPILE_IMPORT_SECTION pSection = pSections + iSection;
5132 if (pSection->Type != CORCOMPILE_IMPORT_TYPE_STRING_HANDLE)
5135 OBJECTHANDLE oh = ResolveStringRefHelper(token, pDomain, pSection, &strData);
5140 // The string is not in our fixup list, so just intern it old style (using hashtable)
5141 goto INTERN_OLD_STYLE;
5144 /* Unfortunately, this assert won't work in some cases of generics, consider the following scenario:
5146 1) Generic type in mscorlib.
5147 2) Instantiation of generic (1) (via valuetype) in another module
5148 3) other module now holds a copy of the code of the generic for that particular instantiation
5149 however, it is resolving the string literals against mscorlib, which breaks the invariant
5150 this assert was based on (no string fixups against other modules). In fact, with NoStringInterning,
5151 our behavior is not very intuitive.
5154 _ASSERTE(pDomain == GetAssembly()->GetDomain() && "If your are doing ldstr for a string"
5155 "in another module, either the JIT is very smart or you have a bug, check INLINE_NO_CALLEE_LDSTR");
5159 Dev10 804385 bugfix -
5160 We should be using appdomain that the string token lives in (GetAssembly->GetDomain())
5161 to allocate the System.String object instead of the appdomain that first uses the ldstr <token> (pDomain).
5163 Otherwise, it is possible to get into the situation that pDomain is unloaded but GetAssembly->GetDomain() is
5164 still kicking around. Anything else that is still using that string will now be pointing to an object
5165 that will be freed when the next GC happens.
5167 pDomain = GetAssembly()->GetDomain();
5169 // The caller is going to update an ngen fixup entry. The fixup entry
5170 // is used to reference the string and to ensure that the string is
5171 // allocated only once. Hence, this operation needs to be done under a lock.
5172 _ASSERTE(GetFixupCrst()->OwnedByCurrentThread());
5175 OBJECTREF* pRef = pDomain->AllocateObjRefPtrsInLargeTable(1);
5177 STRINGREF str = AllocateStringObject(&strData);
5178 SetObjectReference(pRef, str, NULL);
5181 int length = strData.GetCharCount();
5182 length = min(length, 100);
5183 WCHAR *szString = (WCHAR *)_alloca((length + 1) * sizeof(WCHAR));
5184 memcpyNoGCRefs((void*)szString, (void*)strData.GetStringBuffer(), length * sizeof(WCHAR));
5185 szString[length] = '\0';
5186 LOG((LF_APPDOMAIN, LL_INFO10000, "String literal \"%S\" won't be interned due to NoInterningAttribute\n", szString));
5189 return (OBJECTHANDLE) pRef;
5195 // Retrieve the string from the either the appropriate LoaderAllocator
5196 LoaderAllocator *pLoaderAllocator;
5198 if (this->IsCollectible())
5199 pLoaderAllocator = this->GetLoaderAllocator();
5201 pLoaderAllocator = pDomain->GetLoaderAllocator();
5203 string = (OBJECTHANDLE)pLoaderAllocator->GetStringObjRefPtrFromUnicodeString(&strData);
5207 #endif // CROSSGEN_COMPILE
5210 // Used by the verifier. Returns whether this stringref is valid.
5212 CHECK Module::CheckStringRef(DWORD token)
5214 LIMITED_METHOD_CONTRACT;
5215 CHECK(TypeFromToken(token)==mdtString);
5216 CHECK(!IsNilToken(token));
5217 CHECK(GetMDImport()->IsValidToken(token));
5221 mdToken Module::GetEntryPointToken()
5223 WRAPPER_NO_CONTRACT;
5225 return m_file->GetEntryPointToken();
5228 BYTE *Module::GetProfilerBase()
5238 if (m_file == NULL) // I'd rather assert this is not the case...
5242 else if (HasNativeImage())
5244 RETURN (BYTE*)(GetNativeImage()->GetBase());
5246 else if (m_file->IsLoaded())
5248 RETURN (BYTE*)(m_file->GetLoadedIL()->GetBase());
5256 void Module::AddActiveDependency(Module *pModule, BOOL unconditional)
5262 PRECONDITION(CheckPointer(pModule));
5263 PRECONDITION(pModule != this);
5264 PRECONDITION(!IsSystem());
5265 PRECONDITION(!GetAssembly()->IsDomainNeutral() || pModule->GetAssembly()->IsDomainNeutral() || GetAppDomain()->IsDefaultDomain());
5266 POSTCONDITION(IsSingleAppDomain() || HasActiveDependency(pModule));
5267 POSTCONDITION(IsSingleAppDomain() || !unconditional || HasUnconditionalActiveDependency(pModule));
5268 // Postcondition about activation
5272 // Activation tracking is not require in single domain mode. Activate the target immediately.
5273 if (IsSingleAppDomain())
5275 pModule->EnsureActive();
5279 // In the default AppDomain we delay a closure walk until a sharing attempt has been made
5280 // This might result in a situation where a domain neutral assembly from the default AppDomain
5281 // depends on something resolved by assembly resolve event (even Ref.Emit assemblies)
5282 // Since we won't actually share such assemblies, and the default AD itself cannot go away we
5283 // do not need to assert for such assemblies, thus " || GetAppDomain()->IsDefaultDomain()"
5285 CONSISTENCY_CHECK_MSG(!GetAssembly()->IsDomainNeutral() || pModule->GetAssembly()->IsDomainNeutral() || GetAppDomain()->IsDefaultDomain(),
5286 "Active dependency from domain neutral to domain bound is illegal");
5288 // We must track this dependency for multiple domains' use
5289 STRESS_LOG2(LF_CLASSLOADER, LL_INFO100000," %p -> %p\n",this,pModule);
5291 _ASSERTE(!unconditional || pModule->HasNativeImage());
5292 _ASSERTE(!unconditional || HasNativeImage());
5296 // this function can run in parallel with DomainFile::Activate and sychronizes via GetNumberOfActivations()
5297 // because we expose dependency only in the end Domain::Activate might miss it, but it will increment a counter module
5298 // so we can realize we have to additionally propagate a dependency into that appdomain.
5299 // currently we do it just by rescanning al appdomains.
5300 // needless to say, updating the counter and checking counter+adding dependency to the list should be atomic
5303 BOOL propagate = FALSE;
5304 ULONG startCounter=0;
5308 // First, add the dependency to the physical dependency list
5313 check=DomainFile::CheckUnactivatedInAllDomains(this);
5316 CrstHolder lock(&m_Crst);
5317 startCounter=GetNumberOfActivations();
5319 index = m_activeDependencies.FindElement(0, pModule);
5320 if (index == (COUNT_T) ArrayList::NOT_FOUND)
5323 STRESS_LOG3(LF_CLASSLOADER, LL_INFO100,"Adding new module dependency %p -> %p, unconditional=%i\n",this,pModule,unconditional);
5330 CONSISTENCY_CHECK_MSG(check,
5331 "Unconditional dependency cannot be added after module has already been activated");
5333 index = m_activeDependencies.GetCount();
5334 m_activeDependencies.Append(pModule);
5335 m_unconditionalDependencies.SetBit(index);
5336 STRESS_LOG2(LF_CLASSLOADER, LL_INFO100," Unconditional module dependency propagated %p -> %p\n",this,pModule);
5337 // Now other threads can skip this dependency without propagating.
5344 // Now we have to propagate any module activations in the loader
5349 _ASSERTE(!unconditional);
5350 DomainFile::PropagateNewActivation(this, pModule);
5352 CrstHolder lock(&m_Crst);
5353 STRESS_LOG2(LF_CLASSLOADER, LL_INFO100," Conditional module dependency propagated %p -> %p\n",this,pModule);
5354 // Now other threads can skip this dependency without propagating.
5355 endCounter=GetNumberOfActivations();
5356 if(startCounter==endCounter)
5357 m_activeDependencies.Append(pModule);
5360 }while(propagate && startCounter!=endCounter); //need to retry if someone was activated in parallel
5364 BOOL Module::HasActiveDependency(Module *pModule)
5371 PRECONDITION(CheckPointer(pModule));
5375 if (pModule == this)
5378 DependencyIterator i = IterateActiveDependencies();
5381 if (i.GetDependency() == pModule)
5388 BOOL Module::HasUnconditionalActiveDependency(Module *pModule)
5395 PRECONDITION(CheckPointer(pModule));
5399 if (pModule == this)
5402 DependencyIterator i = IterateActiveDependencies();
5405 if (i.GetDependency() == pModule
5406 && i.IsUnconditional())
5413 void Module::EnableModuleFailureTriggers(Module *pModuleTo, AppDomain *pDomain)
5422 // At this point we need to enable failure triggers we have placed in the code for this module. However,
5423 // the failure trigger codegen logic is NYI. To keep correctness, we just allow the exception to propagate
5424 // here. Note that in general this will enforce the failure invariants, but will also result in some rude
5425 // behavior as these failures will be propagated too widely rather than constrained to the appropriate
5426 // assemblies/app domains.
5428 // This should throw.
5429 STRESS_LOG2(LF_CLASSLOADER, LL_INFO100,"EnableModuleFailureTriggers for module %p in AppDomain %i\n",pModuleTo,pDomain->GetId().m_dwId);
5430 DomainFile *pDomainFileTo = pModuleTo->GetDomainFile(pDomain);
5431 pDomainFileTo->EnsureActive();
5433 // @NYI: shouldn't get here yet since we propagate failures
5434 UNREACHABLE_MSG("Module failure triggers NYI");
5437 #endif //!DACCESS_COMPILE
5440 // an GetAssemblyIfLoadedAppDomainIterator is used to iterate over all domains that
5441 // are known to be walkable at the time GetAssemblyIfLoaded is executed.
5443 // The iteration is guaranteed to include all domains that exist at the
5444 // start & end of the iteration that are safely accessible. This class is logically part
5445 // of GetAssemblyIfLoaded and logically has the same set of contracts.
5448 class GetAssemblyIfLoadedAppDomainIterator
5452 StackwalkingThreadIterator,
5453 AllAppDomainWalkingIterator,
5454 CurrentAppDomainIterator
5458 GetAssemblyIfLoadedAppDomainIterator() :
5459 m_adIteratorAll(TRUE),
5460 m_appDomainCurrent(NULL),
5462 m_fNextCalledForCurrentADIterator(FALSE)
5464 LIMITED_METHOD_CONTRACT;
5465 #ifndef DACCESS_COMPILE
5466 if (IsStackWalkerThread())
5468 Thread * pThread = (Thread *)ClrFlsGetValue(TlsIdx_StackWalkerWalkingThread);
5469 m_iterType = StackwalkingThreadIterator;
5470 m_pFrame = pThread->GetFrame();
5471 m_appDomainCurrent = pThread->GetDomain();
5473 else if (IsGCThread())
5475 m_iterType = AllAppDomainWalkingIterator;
5476 m_adIteratorAll.Init();
5480 _ASSERTE(::GetAppDomain() != NULL);
5481 m_appDomainCurrent = ::GetAppDomain();
5482 m_iterType = CurrentAppDomainIterator;
5484 #else //!DACCESS_COMPILE
5485 // We have to walk all AppDomains in debugger
5486 m_iterType = AllAppDomainWalkingIterator;
5487 m_adIteratorAll.Init();
5488 #endif //!DACCESS_COMPILE
5493 WRAPPER_NO_CONTRACT;
5497 #ifndef DACCESS_COMPILE
5498 case StackwalkingThreadIterator:
5499 if (!m_fNextCalledForCurrentADIterator)
5501 m_fNextCalledForCurrentADIterator = TRUE;
5503 // Try searching frame chain if the current domain is NULL
5504 if (m_appDomainCurrent == NULL)
5511 while (m_pFrame != FRAME_TOP)
5513 AppDomain * pDomain = m_pFrame->GetReturnDomain();
5514 if ((pDomain != NULL) && (pDomain != m_appDomainCurrent))
5516 m_appDomainCurrent = pDomain;
5519 m_pFrame = m_pFrame->PtrNextFrame();
5524 #endif //!DACCESS_COMPILE
5526 case AllAppDomainWalkingIterator:
5528 BOOL fSuccess = m_adIteratorAll.Next();
5530 m_appDomainCurrent = m_adIteratorAll.GetDomain();
5534 #ifndef DACCESS_COMPILE
5535 case CurrentAppDomainIterator:
5538 retVal = !m_fNextCalledForCurrentADIterator;
5539 m_fNextCalledForCurrentADIterator = TRUE;
5542 #endif //!DACCESS_COMPILE
5550 AppDomain * GetDomain()
5552 LIMITED_METHOD_CONTRACT;
5554 return m_appDomainCurrent;
5557 BOOL UsingCurrentAD()
5559 LIMITED_METHOD_CONTRACT;
5560 return m_iterType == CurrentAppDomainIterator;
5565 UnsafeAppDomainIterator m_adIteratorAll;
5566 AppDomain * m_appDomainCurrent;
5568 BOOL m_fNextCalledForCurrentADIterator;
5569 }; // class GetAssemblyIfLoadedAppDomainIterator
5571 #if !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
5572 // This function, given an AssemblyRef into the ngen generated native metadata section, will find the assembly referenced if
5573 // 1. The Assembly is defined with a different name than the AssemblyRef provides
5574 // 2. The Assembly has reached the stage of being loaded.
5575 // This function is used as a helper function to assist GetAssemblyIfLoaded with its tasks in the conditions
5576 // where GetAssemblyIfLoaded must succeed (or we violate various invariants in the system required for
5577 // correct implementation of GC, Stackwalking, and generic type loading.
5578 Assembly * Module::GetAssemblyIfLoadedFromNativeAssemblyRefWithRefDefMismatch(mdAssemblyRef kAssemblyRef, BOOL *pfDiscoveredAssemblyRefMatchesTargetDefExactly)
5580 CONTRACT(Assembly *)
5587 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5591 _ASSERTE(HasNativeImage());
5593 Assembly *pAssembly = NULL;
5594 IMDInternalImport *pImportFoundNativeImage = this->GetNativeAssemblyImport(FALSE);
5596 if (!pImportFoundNativeImage)
5601 if (kAssemblyRef != mdAssemblyRefNil)
5603 // Scan CORCOMPILE_DEPENDENCIES tables
5604 PEImageLayout* pNativeLayout = this->GetNativeImage();
5605 COUNT_T dependencyCount;
5606 CORCOMPILE_DEPENDENCY *pDependencies = pNativeLayout->GetNativeDependencies(&dependencyCount);
5608 // Find the assemblyDef that defines the exact target
5609 mdAssemblyRef foundAssemblyDef = mdAssemblyRefNil;
5611 for (COUNT_T i = 0; i < dependencyCount; ++i)
5613 CORCOMPILE_DEPENDENCY* pDependency = &(pDependencies[i]);
5614 if (pDependency->dwAssemblyRef == kAssemblyRef)
5616 foundAssemblyDef = pDependency->dwAssemblyDef;
5621 // In this case we know there is no assembly redirection involved. Skip any additional work.
5622 if (kAssemblyRef == foundAssemblyDef)
5624 *pfDiscoveredAssemblyRefMatchesTargetDefExactly = true;
5628 if (foundAssemblyDef != mdAssemblyRefNil)
5630 // Find out if THIS reference is satisfied
5631 // Specify fDoNotUtilizeExtraChecks to prevent recursion
5632 Assembly *pAssemblyCandidate = this->GetAssemblyIfLoaded(foundAssemblyDef, NULL, NULL, pImportFoundNativeImage, TRUE /*fDoNotUtilizeExtraChecks*/);
5634 // This extended check is designed only to find assemblies loaded via an AssemblySpecBindingCache based binder. Verify that's what we found.
5635 if(pAssemblyCandidate != NULL)
5637 if (!pAssemblyCandidate->GetManifestFile()->HasHostAssembly())
5639 pAssembly = pAssemblyCandidate;
5643 DWORD binderFlags = 0;
5644 ICLRPrivAssembly * pPrivBinder = pAssemblyCandidate->GetManifestFile()->GetHostAssembly();
5645 HRESULT hrBinderFlagCheck = pPrivBinder->GetBinderFlags(&binderFlags);
5646 if (SUCCEEDED(hrBinderFlagCheck) && (binderFlags & BINDER_FINDASSEMBLYBYSPEC_REQUIRES_EXACT_MATCH))
5648 pAssembly = pAssemblyCandidate;
5652 // This should only happen in the generic instantiation case when multiple threads are racing and
5653 // the assembly found is one which we will determine is the wrong assembly.
5655 // 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.
5656 _ASSERTE("Non-AssemblySpecBindingCache based assembly found with extended search" && !(IsStackWalkerThread() || IsGCThread()) && IsGenericInstantiationLookupCompareThread());
5665 #endif // !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
5667 // Fills ppContainingWinRtAppDomain only if WinRT type name is passed and if the assembly is found (return value != NULL).
5669 Module::GetAssemblyIfLoaded(
5670 mdAssemblyRef kAssemblyRef,
5671 LPCSTR szWinRtNamespace, // = NULL
5672 LPCSTR szWinRtClassName, // = NULL
5673 IMDInternalImport * pMDImportOverride, // = NULL
5674 BOOL fDoNotUtilizeExtraChecks, // = FALSE
5675 ICLRPrivBinder *pBindingContextForLoadedAssembly // = NULL
5678 CONTRACT(Assembly *)
5685 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5690 Assembly * pAssembly = NULL;
5691 BOOL fCanUseRidMap = ((pMDImportOverride == NULL) &&
5692 (szWinRtNamespace == NULL));
5695 fCanUseRidMap = fCanUseRidMap && (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GetAssemblyIfLoadedIgnoreRidMap) == 0);
5698 // 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.
5699 #if !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
5700 _ASSERTE(!IsGenericInstantiationLookupCompareThread() || HasNativeImage());
5703 // Don't do a lookup if an override IMDInternalImport is provided, since the lookup is for the
5704 // standard IMDInternalImport and might result in an incorrect result.
5705 // WinRT references also do not update RID map, so don't try to look it up
5708 pAssembly = LookupAssemblyRef(kAssemblyRef);
5711 #ifndef DACCESS_COMPILE
5712 // Check if actually loaded, unless a GC is in progress or the current thread is
5713 // walking the stack (either its own stack, or another thread's stack) as that works
5714 // only with loaded assemblies
5716 // NOTE: The case where the current thread is walking a stack can be problematic for
5717 // other reasons, as the remaining code of this function uses "GetAppDomain()", when
5718 // in fact the right AppDomain to use is the one corresponding to the frame being
5719 // traversed on the walked thread. Dev10 TFS bug# 762348 tracks that issue.
5720 if ((pAssembly != NULL) && !IsGCThread() && !IsStackWalkerThread())
5722 _ASSERTE(::GetAppDomain() != NULL);
5723 DomainAssembly * pDomainAssembly = pAssembly->FindDomainAssembly(::GetAppDomain());
5724 if ((pDomainAssembly == NULL) || !pDomainAssembly->IsLoaded())
5727 #endif //!DACCESS_COMPILE
5729 if (pAssembly == NULL)
5731 // If in stackwalking or gc mode
5732 // For each AppDomain that is on the stack being walked...
5733 // For each AppDomain in the process... if gc'ing
5734 // For the current AppDomain ... if none of the above
5735 GetAssemblyIfLoadedAppDomainIterator appDomainIter;
5737 while (appDomainIter.Next())
5739 AppDomain * pAppDomainExamine = appDomainIter.GetDomain();
5741 DomainAssembly * pCurAssemblyInExamineDomain = GetAssembly()->FindDomainAssembly(pAppDomainExamine);
5742 if (pCurAssemblyInExamineDomain == NULL)
5747 #ifdef FEATURE_COMINTEROP
5748 if (szWinRtNamespace != NULL)
5750 if (IsIntrospectionOnly())
5751 { // We do not have to implement this method for ReflectionOnly WinRT type requests
5752 // ReflectionOnly WinRT types will never have instances on GC heap to be inspected by stackwalking or by debugger
5756 _ASSERTE(szWinRtClassName != NULL);
5758 CLRPrivBinderWinRT * pWinRtBinder = pAppDomainExamine->GetWinRtBinder();
5759 if (pWinRtBinder == nullptr)
5760 { // We are most likely in AppX mode (calling AppX::IsAppXProcess() for verification is painful in DACCESS)
5761 #ifndef DACCESS_COMPILE
5762 // Note: We should also look
5763 // Check designer binding context present (only in AppXDesignMode)
5764 ICLRPrivBinder * pCurrentBinder = pAppDomainExamine->GetLoadContextHostBinder();
5765 if (pCurrentBinder != nullptr)
5766 { // We have designer binding context, look for the type in it
5767 ReleaseHolder<ICLRPrivWinRtTypeBinder> pCurrentWinRtTypeBinder;
5768 HRESULT hr = pCurrentBinder->QueryInterface(__uuidof(ICLRPrivWinRtTypeBinder), (void **)&pCurrentWinRtTypeBinder);
5770 // The binder should be an instance of code:CLRPrivBinderAppX class that implements the interface
5771 _ASSERTE(SUCCEEDED(hr) && (pCurrentWinRtTypeBinder != nullptr));
5775 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5776 pAssembly = (Assembly *)pCurrentWinRtTypeBinder->FindAssemblyForWinRtTypeIfLoaded(
5777 (void *)pAppDomainExamine,
5782 #endif //!DACCESS_COMPILE
5783 if (pAssembly == nullptr)
5785 #if defined(FEATURE_APPX_BINDER)
5786 // Use WinRT binder from "global" AppX binder (there's only 1 AppDomain in non-design mode)
5787 CLRPrivBinderAppX * pAppXBinder = CLRPrivBinderAppX::GetBinderOrNull();
5788 if (pAppXBinder != nullptr)
5790 pWinRtBinder = pAppXBinder->GetWinRtBinder();
5792 #endif // defined(FEATURE_APPX_BINDER)
5796 if (pWinRtBinder != nullptr)
5798 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5799 pAssembly = pWinRtBinder->FindAssemblyForTypeIfLoaded(
5800 dac_cast<PTR_AppDomain>(pAppDomainExamine),
5805 // Never store WinMD AssemblyRefs into the rid map.
5806 if (pAssembly != NULL)
5811 // Never attemt to search the assembly spec binding cache for this form of WinRT assembly reference.
5814 #endif // FEATURE_COMINTEROP
5816 #ifndef DACCESS_COMPILE
5818 IMDInternalImport * pMDImport = (pMDImportOverride == NULL) ? (GetMDImport()) : (pMDImportOverride);
5820 //we have to be very careful here.
5821 //we are using InitializeSpecInternal so we need to make sure that under no condition
5822 //the data we pass to it can outlive the assembly spec.
5824 if (FAILED(spec.InitializeSpecInternal(kAssemblyRef,
5826 pCurAssemblyInExamineDomain,
5827 IsIntrospectionOnly(),
5828 FALSE /*fAllowAllocation*/)))
5833 // If we have been passed the binding context for the loaded assembly that is being looked up in the
5834 // cache, then set it up in the AssemblySpec for the cache lookup to use it below.
5835 if (pBindingContextForLoadedAssembly != NULL)
5837 _ASSERTE(spec.GetBindingContext() == NULL);
5838 spec.SetBindingContext(pBindingContextForLoadedAssembly);
5840 DomainAssembly * pDomainAssembly = nullptr;
5842 #ifdef FEATURE_APPX_BINDER
5843 if (AppX::IsAppXProcess_Initialized_NoFault() && GetAssembly()->GetManifestFile()->HasHostAssembly())
5845 ICLRPrivAssembly * pPrivBinder = GetAssembly()->GetManifestFile()->GetHostAssembly();
5846 ReleaseHolder<ICLRPrivAssembly> pPrivAssembly;
5847 HRESULT hrCachedResult;
5848 if (SUCCEEDED(pPrivBinder->FindAssemblyBySpec(pAppDomainExamine, &spec, &hrCachedResult, &pPrivAssembly)) &&
5849 SUCCEEDED(hrCachedResult))
5851 pDomainAssembly = pAppDomainExamine->FindAssembly(pPrivAssembly);
5855 #endif // FEATURE_APPX_BINDER
5857 pDomainAssembly = pAppDomainExamine->FindCachedAssembly(&spec, FALSE /*fThrow*/);
5860 if (pDomainAssembly && pDomainAssembly->IsLoaded())
5861 pAssembly = pDomainAssembly->GetCurrentAssembly(); // <NOTE> Do not use GetAssembly - that may force the completion of a load
5863 // Only store in the rid map if working with the current AppDomain.
5864 if (fCanUseRidMap && pAssembly && appDomainIter.UsingCurrentAD())
5865 StoreAssemblyRef(kAssemblyRef, pAssembly);
5867 if (pAssembly != NULL)
5870 #endif //!DACCESS_COMPILE
5874 #if !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
5875 if (pAssembly == NULL && (IsStackWalkerThread() || IsGCThread() || IsGenericInstantiationLookupCompareThread()) && !fDoNotUtilizeExtraChecks)
5877 // The GetAssemblyIfLoaded function must succeed in finding assemblies which have already been loaded in a series of interesting cases
5878 // (GC, Stackwalking, GenericInstantiationLookup). This logic is used to handle cases where the normal lookup done above
5879 // 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
5880 // run in cases which are not known to be problematic, or would not benefit from the logic here.
5882 // 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
5883 // image depends on an assembly through some sort of binding version/public key token adjustment (due to binding policy, unification, or portability rules)
5884 // and the assembly depended on was loaded through a binder that utilizes the AssemblySpecBindingCache for binder caching. (The cache's in the other
5885 // binder's successfully answer the GetAssemblyIfLoaded question in the case of non-exact matches where the match was discovered during
5886 // ngen resolution.)
5887 // This restricts the scenario to a somewhat restricted case.
5889 BOOL eligibleForAdditionalChecks = TRUE;
5890 if (szWinRtNamespace != NULL)
5891 eligibleForAdditionalChecks = FALSE; // WinRT binds do not support this scan
5892 #ifdef FEATURE_FUSION
5893 else if ((this->GetAssembly()->GetManifestFile()->GetLoadContext() != LOADCTX_TYPE_DEFAULT) && (this->GetAssembly()->GetManifestFile()->GetLoadContext() != LOADCTX_TYPE_HOSTED))
5894 eligibleForAdditionalChecks = FALSE; // Only load and hosted context binds support this kind of discovery.
5895 #endif // FEATURE_FUSION
5896 else if (this->GetAssembly()->GetManifestFile()->IsDesignerBindingContext())
5898 eligibleForAdditionalChecks = FALSE;
5899 // 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.
5900 // 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)
5901 // A more correct version of this check would probably allow assemblies loaded into the shared designer binding context to be eligibleForAdditionalChecks; however
5902 // 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
5903 // 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
5904 // there is customer need for a fix.
5906 else if (IsIntrospectionOnly())
5907 eligibleForAdditionalChecks = FALSE;
5909 AssemblySpec specSearchAssemblyRef;
5911 // Get the assembly ref information that we are attempting to satisfy.
5912 if (eligibleForAdditionalChecks)
5914 IMDInternalImport * pMDImport = (pMDImportOverride == NULL) ? (GetMDImport()) : (pMDImportOverride);
5916 if (FAILED(specSearchAssemblyRef.InitializeSpecInternal(kAssemblyRef,
5920 FALSE /*fAllowAllocation*/)))
5922 eligibleForAdditionalChecks = FALSE; // If an assemblySpec can't be constructed then we're not going to succeed
5923 // This should not ever happen, due to the above checks, but this logic
5924 // is intended to be defensive against unexpected behavior.
5926 else if (specSearchAssemblyRef.IsContentType_WindowsRuntime())
5928 eligibleForAdditionalChecks = FALSE; // WinRT binds do not support this scan
5932 if (eligibleForAdditionalChecks)
5934 BOOL abortAdditionalChecks = false;
5936 // When working with an ngenn'd assembly, as an optimization we can scan only that module for dependency info.
5937 bool onlyScanCurrentModule = HasNativeImage() && GetFile()->IsAssembly();
5938 mdAssemblyRef foundAssemblyRef = mdAssemblyRefNil;
5940 GetAssemblyIfLoadedAppDomainIterator appDomainIter;
5942 // In each AppDomain that might be interesting, scan for an ngen image that is loaded that has a dependency on the same
5943 // assembly that is now being looked up. If that ngen image has the same dependency, then we can use the CORCOMPILE_DEPENDENCIES
5944 // table to find the exact AssemblyDef that defines the assembly, and attempt a load based on that information.
5945 // As this logic is expected to be used only in exceedingly rare situations, this code has not been tuned for performance
5947 while (!abortAdditionalChecks && appDomainIter.Next())
5949 AppDomain * pAppDomainExamine = appDomainIter.GetDomain();
5951 DomainAssembly * pCurAssemblyInExamineDomain = GetAssembly()->FindDomainAssembly(pAppDomainExamine);
5952 if (pCurAssemblyInExamineDomain == NULL)
5957 DomainFile *pDomainFileNativeImage;
5959 if (onlyScanCurrentModule)
5961 pDomainFileNativeImage = pCurAssemblyInExamineDomain;
5962 // Do not reset foundAssemblyRef.
5963 // This will allow us to avoid scanning for foundAssemblyRef in each domain we iterate through
5967 foundAssemblyRef = mdAssemblyRefNil;
5968 pDomainFileNativeImage = pAppDomainExamine->GetDomainFilesWithNativeImagesList();
5971 while (!abortAdditionalChecks && (pDomainFileNativeImage != NULL) && (pAssembly == NULL))
5973 Module *pNativeImageModule = pDomainFileNativeImage->GetCurrentModule();
5974 _ASSERTE(pNativeImageModule->HasNativeImage());
5975 IMDInternalImport *pImportFoundNativeImage = pNativeImageModule->GetNativeAssemblyImport(FALSE);
5976 if (pImportFoundNativeImage != NULL)
5978 if (IsNilToken(foundAssemblyRef))
5980 // Enumerate assembly refs in nmd space, and compare against held ref.
5981 HENUMInternalHolder hAssemblyRefEnum(pImportFoundNativeImage);
5982 if (FAILED(hAssemblyRefEnum.EnumInitNoThrow(mdtAssemblyRef, mdAssemblyRefNil)))
5987 mdAssemblyRef assemblyRef = mdAssemblyRefNil;
5989 // Find if the native image has a matching assembly ref in its compile dependencies.
5990 while (pImportFoundNativeImage->EnumNext(&hAssemblyRefEnum, &assemblyRef) && (pAssembly == NULL))
5992 AssemblySpec specFoundAssemblyRef;
5993 if (FAILED(specFoundAssemblyRef.InitializeSpecInternal(assemblyRef,
5994 pImportFoundNativeImage,
5997 FALSE /*fAllowAllocation*/)))
5999 continue; // If the spec cannot be loaded, it isn't the one we're looking for
6002 // Check for AssemblyRef equality
6003 if (specSearchAssemblyRef.CompareEx(&specFoundAssemblyRef))
6005 foundAssemblyRef = assemblyRef;
6011 pAssembly = pNativeImageModule->GetAssemblyIfLoadedFromNativeAssemblyRefWithRefDefMismatch(foundAssemblyRef, &abortAdditionalChecks);
6013 if (fCanUseRidMap && pAssembly && appDomainIter.UsingCurrentAD())
6014 StoreAssemblyRef(kAssemblyRef, pAssembly);
6017 // If we're only scanning one module for accurate dependency information, break the loop here.
6018 if (onlyScanCurrentModule)
6021 pDomainFileNativeImage = pDomainFileNativeImage->FindNextDomainFileWithNativeImage();
6026 #endif // !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
6028 // When walking the stack or computing GC information this function should never fail.
6029 _ASSERTE((pAssembly != NULL) || !(IsStackWalkerThread() || IsGCThread()));
6031 #ifdef DACCESS_COMPILE
6033 // Note: In rare cases when debugger walks the stack, we could actually have pAssembly=NULL here.
6034 // To fix that we should DACize the AppDomain-iteration code above (especially AssemblySpec).
6035 _ASSERTE(pAssembly != NULL);
6037 #endif //DACCESS_COMPILE
6040 } // Module::GetAssemblyIfLoaded
6043 Module::GetAssemblyRefFlags(
6044 mdAssemblyRef tkAssemblyRef)
6048 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
6054 _ASSERTE(TypeFromToken(tkAssemblyRef) == mdtAssemblyRef);
6056 LPCSTR pszAssemblyName;
6057 const void *pbPublicKeyOrToken;
6058 DWORD cbPublicKeyOrToken;
6060 DWORD dwAssemblyRefFlags;
6061 IfFailThrow(GetMDImport()->GetAssemblyRefProps(
6063 &pbPublicKeyOrToken,
6064 &cbPublicKeyOrToken,
6069 &dwAssemblyRefFlags));
6071 return dwAssemblyRefFlags;
6072 } // Module::GetAssemblyRefFlags
6074 #ifndef DACCESS_COMPILE
6077 // szWinRtTypeNamespace ... Namespace of WinRT type.
6078 // szWinRtTypeClassName ... Name of WinRT type, NULL for non-WinRT (classic) types.
6079 DomainAssembly * Module::LoadAssembly(
6080 AppDomain * pDomain,
6081 mdAssemblyRef kAssemblyRef,
6082 LPCUTF8 szWinRtTypeNamespace,
6083 LPCUTF8 szWinRtTypeClassName)
6085 CONTRACT(DomainAssembly *)
6088 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
6089 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
6090 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM();); }
6092 PRECONDITION(CheckPointer(pDomain));
6093 POSTCONDITION(CheckPointer(RETVAL, NULL_NOT_OK));
6094 //POSTCONDITION((CheckPointer(GetAssemblyIfLoaded(kAssemblyRef, szWinRtTypeNamespace, szWinRtTypeClassName)), NULL_NOT_OK));
6098 ETWOnStartup (LoaderCatchCall_V1, LoaderCatchCallEnd_V1);
6100 DomainAssembly * pDomainAssembly;
6103 // Early out quickly if the result is cached
6105 Assembly * pAssembly = LookupAssemblyRef(kAssemblyRef);
6106 if (pAssembly != NULL)
6108 _ASSERTE(HasBindableIdentity(kAssemblyRef));
6110 pDomainAssembly = pAssembly->FindDomainAssembly(pDomain);
6112 if (pDomainAssembly == NULL)
6113 pDomainAssembly = pAssembly->GetDomainAssembly(pDomain);
6114 pDomain->LoadDomainFile(pDomainAssembly, FILE_LOADED);
6116 RETURN pDomainAssembly;
6119 bool fHasBindableIdentity = HasBindableIdentity(kAssemblyRef);
6121 #ifdef FEATURE_REFLECTION_ONLY_LOAD
6122 if (IsIntrospectionOnly())
6124 // We will not get here on GC thread
6128 spec.InitializeSpec(kAssemblyRef, GetMDImport(), GetDomainFile(GetAppDomain())->GetDomainAssembly(), IsIntrospectionOnly());
6129 if (szWinRtTypeClassName != NULL)
6131 spec.SetWindowsRuntimeType(szWinRtTypeNamespace, szWinRtTypeClassName);
6133 pDomainAssembly = GetAppDomain()->BindAssemblySpecForIntrospectionDependencies(&spec);
6136 #endif //FEATURE_REFLECTION_ONLY_LOAD
6138 PEAssemblyHolder pFile = GetDomainFile(GetAppDomain())->GetFile()->LoadAssembly(
6141 szWinRtTypeNamespace,
6142 szWinRtTypeClassName);
6144 spec.InitializeSpec(kAssemblyRef, GetMDImport(), GetDomainFile(GetAppDomain())->GetDomainAssembly(), IsIntrospectionOnly());
6145 // Set the binding context in the AssemblySpec if one is available. This can happen if the LoadAssembly ended up
6146 // invoking the custom AssemblyLoadContext implementation that returned a reference to an assembly bound to a different
6147 // AssemblyLoadContext implementation.
6148 ICLRPrivBinder *pBindingContext = pFile->GetBindingContext();
6149 if (pBindingContext != NULL)
6151 spec.SetBindingContext(pBindingContext);
6153 if (szWinRtTypeClassName != NULL)
6155 spec.SetWindowsRuntimeType(szWinRtTypeNamespace, szWinRtTypeClassName);
6157 pDomainAssembly = GetAppDomain()->LoadDomainAssembly(&spec, pFile, FILE_LOADED, NULL);
6160 if (pDomainAssembly != NULL)
6163 IsIntrospectionOnly() || // GetAssemblyIfLoaded will not find introspection-only assemblies
6164 !fHasBindableIdentity || // GetAssemblyIfLoaded will not find non-bindable assemblies
6165 pDomainAssembly->IsSystem() || // GetAssemblyIfLoaded will not find mscorlib (see AppDomain::FindCachedFile)
6166 !pDomainAssembly->IsLoaded() || // GetAssemblyIfLoaded will not find not-yet-loaded assemblies
6167 GetAssemblyIfLoaded(kAssemblyRef, NULL, NULL, NULL, FALSE, pDomainAssembly->GetFile()->GetHostAssembly()) != NULL); // GetAssemblyIfLoaded should find all remaining cases
6169 // Note: We cannot cache WinRT AssemblyRef, because it is meaningless without the TypeRef context
6170 if (pDomainAssembly->GetCurrentAssembly() != NULL)
6172 if (fHasBindableIdentity)
6174 StoreAssemblyRef(kAssemblyRef, pDomainAssembly->GetCurrentAssembly());
6179 RETURN pDomainAssembly;
6182 #endif // !DACCESS_COMPILE
6184 Module *Module::GetModuleIfLoaded(mdFile kFile, BOOL onlyLoadedInAppDomain, BOOL permitResources)
6192 PRECONDITION(TypeFromToken(kFile) == mdtFile
6193 || TypeFromToken(kFile) == mdtModuleRef);
6194 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6200 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
6202 // Handle the module ref case
6203 if (TypeFromToken(kFile) == mdtModuleRef)
6206 if (FAILED(GetMDImport()->GetModuleRefProps(kFile, &moduleName)))
6211 // This is required only because of some lower casing on the name
6212 kFile = GetAssembly()->GetManifestFileToken(moduleName);
6213 if (kFile == mdTokenNil)
6216 RETURN GetAssembly()->GetManifestModule()->GetModuleIfLoaded(kFile, onlyLoadedInAppDomain, permitResources);
6219 Module *pModule = LookupFile(kFile);
6220 if (pModule == NULL)
6224 if (kFile == mdFileNil)
6225 pModule = GetAssembly()->GetManifestModule();
6229 // If we didn't find it there, look at the "master rid map" in the manifest file
6230 Assembly *pAssembly = GetAssembly();
6233 // This is required only because of some lower casing on the name
6234 kMatch = pAssembly->GetManifestFileToken(GetMDImport(), kFile);
6235 if (IsNilToken(kMatch))
6237 if (kMatch == mdFileNil)
6239 pModule = pAssembly->GetManifestModule();
6247 pModule = pAssembly->GetManifestModule()->LookupFile(kMatch);
6250 #ifndef DACCESS_COMPILE
6251 if (pModule != NULL)
6252 StoreFileNoThrow(kFile, pModule);
6256 // We may not want to return a resource module
6257 if (!permitResources && pModule && pModule->IsResource())
6260 #ifndef DACCESS_COMPILE
6261 #if defined(FEATURE_MULTIMODULE_ASSEMBLIES)
6262 // check if actually loaded, unless happens during GC (GC works only with loaded assemblies)
6263 if (!GCHeapUtilities::IsGCInProgress() && onlyLoadedInAppDomain && pModule && !pModule->IsManifest())
6265 DomainModule *pDomainModule = pModule->FindDomainModule(GetAppDomain());
6266 if (pDomainModule == NULL || !pDomainModule->IsLoaded())
6269 #endif // FEATURE_MULTIMODULE_ASSEMBLIES
6270 #endif // !DACCESS_COMPILE
6274 #ifndef DACCESS_COMPILE
6276 DomainFile *Module::LoadModule(AppDomain *pDomain, mdFile kFile,
6277 BOOL permitResources/*=TRUE*/, BOOL bindOnly/*=FALSE*/)
6279 CONTRACT(DomainFile *)
6285 PRECONDITION(TypeFromToken(kFile) == mdtFile
6286 || TypeFromToken(kFile) == mdtModuleRef);
6287 POSTCONDITION(CheckPointer(RETVAL, !permitResources || bindOnly ? NULL_OK : NULL_NOT_OK));
6291 #ifdef FEATURE_MULTIMODULE_ASSEMBLIES
6293 // Handle the module ref case
6294 if (TypeFromToken(kFile) == mdtModuleRef)
6297 IfFailThrow(GetMDImport()->GetModuleRefProps(kFile, &moduleName));
6299 mdFile kFileLocal = GetAssembly()->GetManifestFileToken(moduleName);
6301 if (kFileLocal == mdTokenNil)
6303 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6306 RETURN GetAssembly()->GetManifestModule()->LoadModule(pDomain, kFileLocal, permitResources, bindOnly);
6309 // First, make sure the assembly is loaded in our domain
6311 DomainAssembly *pDomainAssembly = GetAssembly()->FindDomainAssembly(pDomain);
6314 if (pDomainAssembly == NULL)
6315 pDomainAssembly = GetAssembly()->GetDomainAssembly(pDomain);
6316 pDomain->LoadDomainFile(pDomainAssembly, FILE_LOADED);
6319 if (kFile == mdFileNil)
6320 RETURN pDomainAssembly;
6322 if (pDomainAssembly == NULL)
6325 // Now look for the module in the rid maps
6327 Module *pModule = LookupFile(kFile);
6328 if (pModule == NULL && !IsManifest())
6330 // If we didn't find it there, look at the "master rid map" in the manifest file
6331 Assembly *pAssembly = GetAssembly();
6332 mdFile kMatch = pAssembly->GetManifestFileToken(GetMDImport(), kFile);
6333 if (IsNilToken(kMatch)) {
6334 if (kMatch == mdFileNil)
6335 pModule = pAssembly->GetManifestModule();
6337 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6340 pModule = pAssembly->GetManifestModule()->LookupFile(kMatch);
6343 // Get a DomainModule for our domain
6345 DomainModule *pDomainModule = NULL;
6348 pDomainModule = pModule->FindDomainModule(pDomain);
6350 if (!bindOnly && (permitResources || !pModule->IsResource()))
6352 if (pDomainModule == NULL)
6353 pDomainModule = pDomain->LoadDomainModule(pDomainAssembly, (PEModule*) pModule->GetFile(), FILE_LOADED);
6355 pDomain->LoadDomainFile(pDomainModule, FILE_LOADED);
6360 PEModuleHolder pFile(GetAssembly()->LoadModule_AddRef(kFile, permitResources));
6362 pDomainModule = pDomain->LoadDomainModule(pDomainAssembly, pFile, FILE_LOADED);
6365 if (pDomainModule != NULL && pDomainModule->GetCurrentModule() != NULL)
6367 // Make sure the module we're loading isn't its own assembly
6368 if (pDomainModule->GetCurrentModule()->IsManifest())
6369 COMPlusThrowHR(COR_E_ASSEMBLY_NOT_EXPECTED);
6371 // Cache the result in the rid map
6372 StoreFileThrowing(kFile, pDomainModule->GetCurrentModule());
6375 // Make sure we didn't load a different module than what was in the rid map
6376 CONSISTENCY_CHECK(pDomainModule == NULL || pModule == NULL || pDomainModule->GetModule() == pModule);
6378 // We may not want to return a resource module
6379 if (!permitResources && pDomainModule != NULL && pDomainModule->GetFile()->IsResource())
6380 pDomainModule = NULL;
6382 RETURN pDomainModule;
6383 #else //!FEATURE_MULTIMODULE_ASSEMBLIES
6390 LPCSTR psModuleName=NULL;
6391 if (TypeFromToken(kFile) == mdtModuleRef)
6393 // This is a moduleRef
6394 IfFailThrow(GetMDImport()->GetModuleRefProps(kFile, &psModuleName));
6399 IfFailThrow(GetAssembly()->GetManifestImport()->GetFileProps(kFile,
6405 SString name(SString::Utf8, psModuleName);
6406 EEFileLoadException::Throw(name, COR_E_MULTIMODULEASSEMBLIESDIALLOWED, NULL);
6408 #endif // FEATURE_MULTIMODULE_ASSEMBLIES
6410 #endif // !DACCESS_COMPILE
6412 PTR_Module Module::LookupModule(mdToken kFile,BOOL permitResources/*=TRUE*/)
6414 CONTRACT(PTR_Module)
6417 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
6418 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
6419 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT;
6420 else { INJECT_FAULT(COMPlusThrowOM()); }
6422 PRECONDITION(TypeFromToken(kFile) == mdtFile
6423 || TypeFromToken(kFile) == mdtModuleRef);
6424 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6429 if (TypeFromToken(kFile) == mdtModuleRef)
6432 IfFailThrow(GetMDImport()->GetModuleRefProps(kFile, &moduleName));
6433 mdFile kFileLocal = GetAssembly()->GetManifestFileToken(moduleName);
6435 if (kFileLocal == mdTokenNil)
6436 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6438 RETURN GetAssembly()->GetManifestModule()->LookupModule(kFileLocal, permitResources);
6441 PTR_Module pModule = LookupFile(kFile);
6442 if (pModule == NULL && !IsManifest())
6444 // If we didn't find it there, look at the "master rid map" in the manifest file
6445 Assembly *pAssembly = GetAssembly();
6446 mdFile kMatch = pAssembly->GetManifestFileToken(GetMDImport(), kFile);
6447 if (IsNilToken(kMatch)) {
6448 if (kMatch == mdFileNil)
6449 pModule = pAssembly->GetManifestModule();
6451 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6454 pModule = pAssembly->GetManifestModule()->LookupFile(kMatch);
6460 TypeHandle Module::LookupTypeRef(mdTypeRef token)
6462 STATIC_CONTRACT_NOTHROW;
6463 STATIC_CONTRACT_GC_NOTRIGGER;
6464 STATIC_CONTRACT_FORBID_FAULT;
6467 _ASSERTE(TypeFromToken(token) == mdtTypeRef);
6469 g_IBCLogger.LogRidMapAccess( MakePair( this, token ) );
6471 TypeHandle entry = TypeHandle::FromTAddr(dac_cast<TADDR>(m_TypeRefToMethodTableMap.GetElement(RidFromToken(token))));
6474 return TypeHandle();
6476 // Cannot do this in a NOTHROW function.
6477 // Note that this could be called while doing GC from the prestub of
6478 // a method to resolve typerefs in a signature. We cannot THROW
6481 // @PERF: Enable this so that we do not need to touch metadata
6482 // to resolve typerefs
6484 #ifdef FIXUPS_ALL_TYPEREFS
6486 if (CORCOMPILE_IS_POINTER_TAGGED((SIZE_T) entry.AsPtr()))
6488 #ifndef DACCESS_COMPILE
6489 Module::RestoreTypeHandlePointer(&entry, TRUE);
6490 m_TypeRefToMethodTableMap.SetElement(RidFromToken(token), dac_cast<PTR_TypeRef>(value.AsTAddr()));
6491 #else // DACCESS_COMPILE
6493 #endif // DACCESS_COMPILE
6496 #endif // FIXUPS_ALL_TYPEREFS
6501 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6502 mdTypeRef Module::LookupTypeRefByMethodTable(MethodTable *pMT)
6504 STANDARD_VM_CONTRACT;
6506 HENUMInternalHolder hEnumTypeRefs(GetMDImport());
6508 hEnumTypeRefs.EnumAllInit(mdtTypeRef);
6509 while (hEnumTypeRefs.EnumNext(&token))
6511 TypeHandle thRef = LookupTypeRef(token);
6512 if (thRef.IsNull() || thRef.IsTypeDesc())
6517 MethodTable *pMTRef = thRef.AsMethodTable();
6518 if (pMT->HasSameTypeDefAs(pMTRef))
6520 _ASSERTE(pMTRef->IsTypicalTypeDefinition());
6525 #ifdef FEATURE_READYTORUN_COMPILER
6526 if (IsReadyToRunCompilation())
6528 if (pMT->GetClass()->IsEquivalentType())
6530 GetSvcLogger()->Log(W("ReadyToRun: Type reference to equivalent type cannot be encoded\n"));
6534 // FUTURE: Encoding of new cross-module references for ReadyToRun
6535 // This warning is hit for recursive cross-module inlining. It is commented out to avoid noise.
6536 // GetSvcLogger()->Log(W("ReadyToRun: Type reference outside of current version bubble cannot be encoded\n"));
6539 #endif // FEATURE_READYTORUN_COMPILER
6541 // FUTURE TODO: Version resilience
6542 _ASSERTE(!"Cross module type reference not found");
6547 mdMemberRef Module::LookupMemberRefByMethodDesc(MethodDesc *pMD)
6549 STANDARD_VM_CONTRACT;
6551 HENUMInternalHolder hEnumMemberRefs(GetMDImport());
6553 hEnumMemberRefs.EnumAllInit(mdtMemberRef);
6554 while (hEnumMemberRefs.EnumNext(&token))
6556 BOOL fIsMethod = FALSE;
6557 TADDR addr = LookupMemberRef(token, &fIsMethod);
6560 MethodDesc *pCurMD = dac_cast<PTR_MethodDesc>(addr);
6568 // FUTURE TODO: Version resilience
6569 _ASSERTE(!"Cross module method reference not found");
6572 #endif // FEATURE_NATIVE_IMAGE_GENERATION
6574 #ifndef DACCESS_COMPILE
6577 // Increase the size of one of the maps, such that it can handle a RID of at least "rid".
6579 // This function must also check that another thread didn't already add a LookupMap capable
6580 // of containing the same RID.
6582 PTR_TADDR LookupMapBase::GrowMap(Module * pModule, DWORD rid)
6590 INJECT_FAULT(ThrowOutOfMemory(););
6591 POSTCONDITION(CheckPointer(RETVAL));
6595 LookupMapBase *pMap = this;
6596 LookupMapBase *pPrev = NULL;
6597 LookupMapBase *pNewMap = NULL;
6599 // Initial block size
6600 DWORD dwIndex = rid;
6601 DWORD dwBlockSize = 16;
6604 CrstHolder ch(pModule->GetLookupTableCrst());
6605 // Check whether we can already handle this RID index
6608 if (dwIndex < pMap->dwCount)
6610 // Already there - some other thread must have added it
6611 RETURN pMap->GetIndexPtr(dwIndex);
6616 dwIndex -= pMap->dwCount;
6620 } while (pMap != NULL);
6622 _ASSERTE(pPrev != NULL); // should never happen, because there's always at least one map
6624 DWORD dwSizeToAllocate = max(dwIndex + 1, dwBlockSize);
6626 pNewMap = (LookupMapBase *) (void*)pModule->GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(LookupMapBase)) + S_SIZE_T(dwSizeToAllocate)*S_SIZE_T(sizeof(TADDR)));
6628 // Note: Memory allocated on loader heap is zero filled
6629 // memset(pNewMap, 0, sizeof(LookupMap) + dwSizeToAllocate*sizeof(void*));
6631 pNewMap->pNext = NULL;
6632 pNewMap->dwCount = dwSizeToAllocate;
6634 pNewMap->pTable = dac_cast<ArrayDPTR(TADDR)>(pNewMap + 1);
6636 // Link ourselves in
6637 VolatileStore<LookupMapBase*>(&(pPrev->pNext), pNewMap);
6640 RETURN pNewMap->GetIndexPtr(dwIndex);
6643 #endif // DACCESS_COMPILE
6645 PTR_TADDR LookupMapBase::GetElementPtr(DWORD rid)
6658 LookupMapBase * pMap = this;
6660 #ifdef FEATURE_PREJIT
6661 if (pMap->dwNumHotItems > 0)
6664 static DWORD counter = 0;
6666 if (counter >= pMap->dwNumHotItems)
6668 CheckConsistentHotItemList();
6671 #endif // _DEBUG_IMPL
6673 PTR_TADDR pHotItemValue = pMap->FindHotItemValuePtr(rid);
6676 return pHotItemValue;
6679 #endif // FEATURE_PREJIT
6681 DWORD dwIndex = rid;
6684 if (dwIndex < pMap->dwCount)
6686 return pMap->GetIndexPtr(dwIndex);
6689 dwIndex -= pMap->dwCount;
6691 } while (pMap != NULL);
6697 #ifdef FEATURE_PREJIT
6699 // This method can only be called on a compressed map (MapIsCompressed() == true). Compressed rid maps store
6700 // the array of values as packed deltas (each value is based on the accumulated of all the previous entries).
6701 // So this method takes the bit stream of compressed data we're navigating and the value of the last entry
6702 // retrieved allowing us to calculate the full value of the next entry. Note that the values passed in and out
6703 // here aren't the final values the top-level caller sees. In order to avoid having to touch the compressed
6704 // data on image base relocations we actually store a form of RVA (though relative to the map base rather than
6705 // the module base).
6706 INT32 LookupMapBase::GetNextCompressedEntry(BitStreamReader *pTableStream, INT32 iLastValue)
6716 PRECONDITION(MapIsCompressed());
6720 // The next kLookupMapLengthBits bits in the stream are an index into a per-map table that tells us the
6721 // length of the encoded delta.
6722 DWORD dwValueLength = rgEncodingLengths[pTableStream->Read(kLookupMapLengthBits)];
6724 // Then follows a single bit that indicates whether the delta should be added (1) or subtracted (0) from
6725 // the previous entry value to recover the current entry value.
6726 // Once we've read that bit we read the delta (encoded as an unsigned integer using the number of bits
6727 // that we read from the encoding lengths table above).
6728 if (pTableStream->ReadOneFast())
6729 return iLastValue + (INT32)(pTableStream->Read(dwValueLength));
6731 return iLastValue - (INT32)(pTableStream->Read(dwValueLength));
6734 // This method can only be called on a compressed map (MapIsCompressed() == true). Retrieves the final value
6735 // (e.g. MethodTable*, MethodDesc* etc. based on map type) given the rid of the entry.
6736 TADDR LookupMapBase::GetValueFromCompressedMap(DWORD rid)
6746 PRECONDITION(MapIsCompressed());
6750 // Normally to extract the nth entry in the table we have to linearly parse all (n - 1) preceding entries
6751 // (since entries are stored as the delta from the previous entry). Obviously this can yield exceptionally
6752 // poor performance for the later entries in large tables. So we also build an index of the compressed
6753 // stream. This index has an entry for every kLookupMapIndexStride entries in the compressed table. Each
6754 // index entry contains the full RVA (relative to the map) of the corresponding table entry plus the bit
6755 // offset in the stream from which to start parsing the next entry's data.
6756 // In this fashion we can get to within kLookupMapIndexStride entries of our target entry and then decode
6757 // our way to the final target.
6759 // Ensure that index does not go beyond end of the saved table
6763 // Calculate the nearest entry in the index that is lower than our target index in the full table.
6764 DWORD dwIndexEntry = rid / kLookupMapIndexStride;
6766 // Then calculate how many additional entries we'll need to decode from the compressed streams to recover
6767 // the target entry.
6768 DWORD dwSubIndex = rid % kLookupMapIndexStride;
6770 // Open a bit stream reader on the index and skip all the entries prior to the one we're interested in.
6771 BitStreamReader sIndexStream(pIndex);
6772 sIndexStream.Skip(dwIndexEntry * cIndexEntryBits);
6774 // The first kBitsPerRVA of the index entry contain the RVA of the corresponding entry in the compressed
6775 // table. If this is exactly the entry we want (dwSubIndex == 0) then we can use this RVA to recover the
6776 // value the caller wants. Our RVAs are based on the map address rather than the module base (simply
6777 // because we don't record the module base in LookupMapBase). A delta of zero encodes a null value,
6778 // otherwise we simply add the RVA to the our map address to recover the full pointer.
6779 // Note that most LookupMaps are embedded structures (in Module) so we can't directly dac_cast<TADDR> our
6780 // "this" pointer for DAC builds. Instead we have to use the slightly slower (in DAC) but more flexible
6781 // PTR_HOST_INT_TO_TADDR() which copes with interior host pointers.
6782 INT32 iValue = (INT32)sIndexStream.Read(kBitsPerRVA);
6783 if (dwSubIndex == 0)
6784 return iValue ? PTR_HOST_INT_TO_TADDR(this) + iValue : 0;
6786 // Otherwise we must parse one or more entries in the compressed table to accumulate more deltas to the
6787 // base RVA we read above. The remaining portion of the index entry has the bit offset into the compressed
6788 // table at which to begin parsing.
6789 BitStreamReader sTableStream(dac_cast<PTR_CBYTE>(pTable));
6790 sTableStream.Skip(sIndexStream.Read(cIndexEntryBits - kBitsPerRVA));
6792 // Parse all the entries up to our target entry. Each step takes the RVA from the previous cycle (or from
6793 // the index entry we read above) and applies the compressed delta of the next table entry to it.
6794 for (DWORD i = 0; i < dwSubIndex; i++)
6795 iValue = GetNextCompressedEntry(&sTableStream, iValue);
6797 // We have the final RVA so recover the actual pointer from it (a zero RVA encodes a NULL pointer). Note
6798 // the use of PTR_HOST_INT_TO_TADDR() rather than dac_cast<TADDR>, see previous comment on
6799 // PTR_HOST_INT_TO_TADDR for an explanation.
6800 return iValue ? PTR_HOST_INT_TO_TADDR(this) + iValue : 0;
6803 PTR_TADDR LookupMapBase::FindHotItemValuePtr(DWORD rid)
6805 LIMITED_METHOD_DAC_CONTRACT;
6807 if (dwNumHotItems < 5)
6809 // do simple linear search if there are only a few hot items
6810 for (DWORD i = 0; i < dwNumHotItems; i++)
6812 if (hotItemList[i].rid == rid)
6813 return dac_cast<PTR_TADDR>(
6814 dac_cast<TADDR>(hotItemList) + i * sizeof(HotItem) + offsetof(HotItem, value));
6819 // otherwise do binary search
6820 if (hotItemList[0].rid <= rid && rid <= hotItemList[dwNumHotItems-1].rid)
6823 DWORD r = dwNumHotItems;
6827 _ASSERTE(hotItemList[l].rid <= rid && (r >= dwNumHotItems || rid < hotItemList[r].rid));
6829 DWORD m = (l + r)/2;
6830 // loop condition implies l < m < r, hence interval shrinks every iteration, hence loop terminates
6831 _ASSERTE(l < m && m < r);
6832 if (rid < hotItemList[m].rid)
6837 // now we know l + 1 == r && hotItemList[l].rid <= rid < hotItemList[r].rid
6839 _ASSERTE(hotItemList[l].rid <= rid && (r >= dwNumHotItems || rid < hotItemList[r].rid));
6840 if (hotItemList[l].rid == rid)
6841 return dac_cast<PTR_TADDR>(
6842 dac_cast<TADDR>(hotItemList) + l * sizeof(HotItem) + offsetof(HotItem, value));
6849 void LookupMapBase::CheckConsistentHotItemList()
6851 LIMITED_METHOD_DAC_CONTRACT;
6853 for (DWORD i = 0; i < dwNumHotItems; i++)
6855 DWORD rid = hotItemList[i].rid;
6857 PTR_TADDR pHotValue = dac_cast<PTR_TADDR>(
6858 dac_cast<TADDR>(hotItemList) + i * sizeof(HotItem) + offsetof(HotItem, value));
6859 TADDR hotValue = RelativePointer<TADDR>::GetValueMaybeNullAtPtr(dac_cast<TADDR>(pHotValue));
6862 if (MapIsCompressed())
6864 value = GetValueFromCompressedMap(rid);
6868 PTR_TADDR pValue = GetIndexPtr(rid);
6869 value = RelativePointer<TADDR>::GetValueMaybeNullAtPtr(dac_cast<TADDR>(pValue));
6872 _ASSERTE(hotValue == value || value == NULL);
6877 #endif // FEATURE_PREJIT
6879 // Get number of RIDs that this table can store
6880 DWORD LookupMapBase::GetSize()
6892 LookupMapBase * pMap = this;
6896 dwSize += pMap->dwCount;
6898 } while (pMap != NULL);
6903 #ifndef DACCESS_COMPILE
6906 void LookupMapBase::DebugGetRidMapOccupancy(DWORD *pdwOccupied, DWORD *pdwSize)
6908 LIMITED_METHOD_CONTRACT;
6913 LookupMapBase * pMap = this;
6915 // Go through each linked block
6916 for (; pMap != NULL; pMap = pMap->pNext)
6918 DWORD dwIterCount = pMap->dwCount;
6920 for (DWORD i = 0; i < dwIterCount; i++)
6922 #ifdef FEATURE_PREJIT
6923 if (pMap->MapIsCompressed())
6925 if (pMap->GetValueFromCompressedMap(i))
6929 #endif // FEATURE_PREJIT
6930 if (pMap->pTable[i] != NULL)
6934 (*pdwSize) += dwIterCount;
6938 void Module::DebugLogRidMapOccupancy()
6940 WRAPPER_NO_CONTRACT;
6942 #define COMPUTE_RID_MAP_OCCUPANCY(var_suffix, map) \
6943 DWORD dwOccupied##var_suffix, dwSize##var_suffix, dwPercent##var_suffix; \
6944 map.DebugGetRidMapOccupancy(&dwOccupied##var_suffix, &dwSize##var_suffix); \
6945 dwPercent##var_suffix = dwOccupied##var_suffix ? ((dwOccupied##var_suffix * 100) / dwSize##var_suffix) : 0;
6947 COMPUTE_RID_MAP_OCCUPANCY(1, m_TypeDefToMethodTableMap);
6948 COMPUTE_RID_MAP_OCCUPANCY(2, m_TypeRefToMethodTableMap);
6949 COMPUTE_RID_MAP_OCCUPANCY(3, m_MethodDefToDescMap);
6950 COMPUTE_RID_MAP_OCCUPANCY(4, m_FieldDefToDescMap);
6951 COMPUTE_RID_MAP_OCCUPANCY(5, m_GenericParamToDescMap);
6952 COMPUTE_RID_MAP_OCCUPANCY(6, m_GenericTypeDefToCanonMethodTableMap);
6953 COMPUTE_RID_MAP_OCCUPANCY(7, m_FileReferencesMap);
6954 COMPUTE_RID_MAP_OCCUPANCY(8, m_ManifestModuleReferencesMap);
6955 COMPUTE_RID_MAP_OCCUPANCY(9, m_MethodDefToPropertyInfoMap);
6961 " TypeDefToMethodTable map: %4d/%4d (%2d %%)\n"
6962 " TypeRefToMethodTable map: %4d/%4d (%2d %%)\n"
6963 " MethodDefToDesc map: %4d/%4d (%2d %%)\n"
6964 " FieldDefToDesc map: %4d/%4d (%2d %%)\n"
6965 " GenericParamToDesc map: %4d/%4d (%2d %%)\n"
6966 " GenericTypeDefToCanonMethodTable map: %4d/%4d (%2d %%)\n"
6967 " FileReferences map: %4d/%4d (%2d %%)\n"
6968 " AssemblyReferences map: %4d/%4d (%2d %%)\n"
6969 " MethodDefToPropInfo map: %4d/%4d (%2d %%)\n"
6971 dwOccupied1, dwSize1, dwPercent1,
6972 dwOccupied2, dwSize2, dwPercent2,
6973 dwOccupied3, dwSize3, dwPercent3,
6974 dwOccupied4, dwSize4, dwPercent4,
6975 dwOccupied5, dwSize5, dwPercent5,
6976 dwOccupied6, dwSize6, dwPercent6,
6977 dwOccupied7, dwSize7, dwPercent7,
6978 dwOccupied8, dwSize8, dwPercent8,
6979 dwOccupied9, dwSize9, dwPercent9
6982 #undef COMPUTE_RID_MAP_OCCUPANCY
6986 BOOL Module::CanExecuteCode()
6988 WRAPPER_NO_CONTRACT;
6990 #ifdef FEATURE_PREJIT
6991 // In a passive domain, we lock down which assemblies can run code
6992 if (!GetAppDomain()->IsPassiveDomain())
6995 Assembly * pAssembly = GetAssembly();
6996 PEAssembly * pPEAssembly = pAssembly->GetManifestFile();
6998 // Only mscorlib is allowed to execute code in an ngen passive domain
6999 if (IsCompilationProcess())
7000 return pPEAssembly->IsSystem();
7002 // ExecuteDLLForAttach does not run the managed entry point in
7003 // a passive domain to avoid loader-lock deadlocks.
7004 // Hence, it is not safe to execute any code from this assembly.
7005 if (pPEAssembly->GetEntryPointToken(INDEBUG(TRUE)) != mdTokenNil)
7008 // EXEs loaded using LoadAssembly() may not be loaded at their
7009 // preferred base address. If they have any relocs, these may
7010 // not have been fixed up.
7011 if (!pPEAssembly->IsDll() && !pPEAssembly->IsILOnly())
7014 // If the assembly does not have FullTrust, we should not execute its code.
7015 if (!pAssembly->GetSecurityDescriptor()->IsFullyTrusted())
7017 #endif // FEATURE_PREJIT
7023 // FindMethod finds a MethodDesc for a global function methoddef or ref
7026 MethodDesc *Module::FindMethodThrowing(mdToken pMethod)
7028 CONTRACT (MethodDesc *)
7034 POSTCONDITION(CheckPointer(RETVAL));
7038 SigTypeContext typeContext; /* empty type context: methods will not be generic */
7039 RETURN MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(this, pMethod,
7041 TRUE, /* strictMetadataChecks */
7042 FALSE /* dont get code shared between generic instantiations */);
7046 // FindMethod finds a MethodDesc for a global function methoddef or ref
7049 MethodDesc *Module::FindMethod(mdToken pMethod)
7051 CONTRACT (MethodDesc *) {
7056 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
7059 MethodDesc *pMDRet = NULL;
7063 pMDRet = FindMethodThrowing(pMethod);
7068 CONTRACT_VIOLATION(ThrowsViolation);
7069 char szMethodName [MAX_CLASSNAME_LENGTH];
7070 CEEInfo::findNameOfToken(this, pMethod, szMethodName, COUNTOF (szMethodName));
7071 LOG((LF_IJW, LL_INFO10, "Failed to find Method: %s for Vtable Fixup\n", szMethodName));
7074 EX_END_CATCH(SwallowAllExceptions)
7080 // PopulatePropertyInfoMap precomputes property information during NGen
7081 // that is expensive to look up from metadata at runtime.
7084 void Module::PopulatePropertyInfoMap()
7092 PRECONDITION(IsCompilationProcess());
7096 IMDInternalImport* mdImport = GetMDImport();
7097 HENUMInternalHolder hEnum(mdImport);
7098 hEnum.EnumAllInit(mdtMethodDef);
7101 while (hEnum.EnumNext(&md))
7103 mdProperty prop = 0;
7105 if (mdImport->GetPropertyInfoForMethodDef(md, &prop, NULL, &semantic) == S_OK)
7107 // Store the Rid in the lower 24 bits and the semantic in the upper 8
7108 _ASSERTE((semantic & 0xFFFFFF00) == 0);
7109 SIZE_T value = RidFromToken(prop) | (semantic << 24);
7111 // We need to make sure a value of zero indicates an empty LookupMap entry
7112 // Fortunately the semantic will prevent value from being zero
7113 _ASSERTE(value != 0);
7115 m_MethodDefToPropertyInfoMap.AddElement(this, RidFromToken(md), value);
7118 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_METHODDEF_TO_PROPERTYINFO_MAP);
7122 // GetPropertyInfoForMethodDef wraps the metadata function of the same name,
7123 // first trying to use the information stored in m_MethodDefToPropertyInfoMap.
7126 HRESULT Module::GetPropertyInfoForMethodDef(mdMethodDef md, mdProperty *ppd, LPCSTR *pName, ULONG *pSemantic)
7140 if ((m_dwPersistedFlags & COMPUTED_METHODDEF_TO_PROPERTYINFO_MAP) != 0)
7142 SIZE_T value = m_MethodDefToPropertyInfoMap.GetElement(RidFromToken(md));
7145 _ASSERTE(GetMDImport()->GetPropertyInfoForMethodDef(md, ppd, pName, pSemantic) == S_FALSE);
7150 // Decode the value into semantic and mdProperty as described in PopulatePropertyInfoMap
7151 ULONG semantic = (value & 0xFF000000) >> 24;
7152 mdProperty prop = TokenFromRid(value & 0x00FFFFFF, mdtProperty);
7158 _ASSERTE(GetMDImport()->GetPropertyInfoForMethodDef(md, &dbgPd, &dbgName, &dbgSemantic) == S_OK);
7164 _ASSERTE(*ppd == dbgPd);
7167 if (pSemantic != NULL)
7169 *pSemantic = semantic;
7170 _ASSERTE(*pSemantic == dbgSemantic);
7175 IfFailRet(GetMDImport()->GetPropertyProps(prop, pName, NULL, NULL, NULL));
7178 HRESULT hr = GetMDImport()->GetPropertyProps(prop, pName, NULL, NULL, NULL);
7179 _ASSERTE(hr == S_OK);
7180 _ASSERTE(strcmp(*pName, dbgName) == 0);
7188 return GetMDImport()->GetPropertyInfoForMethodDef(md, ppd, pName, pSemantic);
7191 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
7192 // Fill the m_propertyNameSet hash filter with data that represents every
7193 // property and its name in the module.
7194 void Module::PrecomputeMatchingProperties(DataImage *image)
7199 PRECONDITION(IsCompilationProcess());
7203 IMDInternalImport* mdImport = GetMDImport();
7205 m_nPropertyNameSet = mdImport->GetCountWithTokenKind(mdtProperty);
7207 if (m_nPropertyNameSet == 0)
7212 m_propertyNameSet = new (image->GetHeap()) BYTE[m_nPropertyNameSet];
7214 DWORD nEnumeratedProperties = 0;
7216 HENUMInternalHolder hEnumTypes(mdImport);
7217 hEnumTypes.EnumAllInit(mdtTypeDef);
7219 // Enumerate all properties of all types
7221 while (hEnumTypes.EnumNext(&tkType))
7223 HENUMInternalHolder hEnumPropertiesForType(mdImport);
7224 hEnumPropertiesForType.EnumInit(mdtProperty, tkType);
7226 mdProperty tkProperty;
7227 while (hEnumPropertiesForType.EnumNext(&tkProperty))
7230 HRESULT hr = GetMDImport()->GetPropertyProps(tkProperty, &name, NULL, NULL, NULL);
7233 ++nEnumeratedProperties;
7235 // Use a case-insensitive hash so that we can use this value for
7236 // both case-sensitive and case-insensitive name lookups
7237 SString ssName(SString::Utf8Literal, name);
7238 ULONG nameHashValue = ssName.HashCaseInsensitive();
7240 // Set one bit in m_propertyNameSet per iteration
7241 // This will allow lookup to ensure that the bit from each iteration is set
7242 // and if any are not set, know that the (tkProperty,name) pair is not valid
7243 for (DWORD i = 0; i < NUM_PROPERTY_SET_HASHES; ++i)
7245 DWORD currentHashValue = HashThreeToOne(tkProperty, nameHashValue, i);
7246 DWORD bitPos = currentHashValue % (m_nPropertyNameSet * 8);
7247 m_propertyNameSet[bitPos / 8] |= (1 << bitPos % 8);
7252 _ASSERTE(nEnumeratedProperties == m_nPropertyNameSet);
7254 #endif // FEATURE_NATIVE_IMAGE_GENERATION
7256 // Check whether the module might possibly have a property with a name with
7257 // the passed hash value without accessing the property's name. This is done
7258 // by consulting a hash filter populated at NGen time.
7259 BOOL Module::MightContainMatchingProperty(mdProperty tkProperty, ULONG nameHash)
7270 if (m_propertyNameSet)
7272 _ASSERTE(HasNativeImage());
7274 // if this property was added after the name set was computed, conservatively
7275 // assume we might have it. This is known to occur in scenarios where a profiler
7276 // injects additional metadata at module load time for an NGEN'ed module. In the
7277 // future other dynamic additions to the module might produce a similar result.
7278 if (RidFromToken(tkProperty) > m_nPropertyNameSet)
7281 // Check one bit per iteration, failing if any are not set
7282 // We know that all will have been set for any valid (tkProperty,name) pair
7283 for (DWORD i = 0; i < NUM_PROPERTY_SET_HASHES; ++i)
7285 DWORD currentHashValue = HashThreeToOne(tkProperty, nameHash, i);
7286 DWORD bitPos = currentHashValue % (m_nPropertyNameSet * 8);
7287 if ((m_propertyNameSet[bitPos / 8] & (1 << bitPos % 8)) == 0)
7297 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
7298 // Ensure that all elements and flags that we want persisted in the LookupMaps are present
7299 void Module::FinalizeLookupMapsPreSave(DataImage *image)
7304 PRECONDITION(IsCompilationProcess());
7308 // For each typedef, if it does not need a restore, add the ZAPPED_TYPE_NEEDS_NO_RESTORE flag
7310 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
7312 while (typeDefIter.Next())
7314 MethodTable * pMT = typeDefIter.GetElement();
7316 if (pMT != NULL && !pMT->NeedsRestore(image))
7318 m_TypeDefToMethodTableMap.AddFlag(RidFromToken(pMT->GetCl()), ZAPPED_TYPE_NEEDS_NO_RESTORE);
7323 // 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
7325 LookupMap<PTR_MethodTable>::Iterator genericTypeDefIter(&m_GenericTypeDefToCanonMethodTableMap);
7327 while (genericTypeDefIter.Next())
7329 MethodTable * pMT = genericTypeDefIter.GetElement();
7331 if (pMT != NULL && !pMT->NeedsRestore(image))
7333 m_GenericTypeDefToCanonMethodTableMap.AddFlag(RidFromToken(pMT->GetCl()), ZAPPED_GENERIC_TYPE_NEEDS_NO_RESTORE);
7339 #endif // FEATURE_NATIVE_IMAGE_GENERATION
7341 // Return true if this module has any live (jitted) JMC functions.
7342 // If a module has no jitted JMC functions, then it's as if it's a
7344 bool Module::HasAnyJMCFunctions()
7346 LIMITED_METHOD_CONTRACT;
7348 // If we have any live JMC funcs in us, then we're a JMC module.
7349 // We count JMC functions when we either explicitly toggle their status
7350 // or when we get the code:DebuggerMethodInfo for them (which happens in a jit-complete).
7351 // Since we don't get the jit-completes for ngen modules, we also check the module's
7352 // "default" status. This means we may err on the side of believing we have
7354 return ((m_debuggerSpecificData.m_cTotalJMCFuncs > 0) || m_debuggerSpecificData.m_fDefaultJMCStatus);
7357 // Alter our module's count of JMC functions.
7358 // Since these may be called on multiple threads (say 2 threads are jitting
7359 // methods within a module), make it thread safe.
7360 void Module::IncJMCFuncCount()
7362 LIMITED_METHOD_CONTRACT;
7364 InterlockedIncrement(&m_debuggerSpecificData.m_cTotalJMCFuncs);
7367 void Module::DecJMCFuncCount()
7369 LIMITED_METHOD_CONTRACT;
7371 InterlockedDecrement(&m_debuggerSpecificData.m_cTotalJMCFuncs);
7374 // code:DebuggerMethodInfo are lazily created. Let them lookup what the default is.
7375 bool Module::GetJMCStatus()
7377 LIMITED_METHOD_CONTRACT;
7379 return m_debuggerSpecificData.m_fDefaultJMCStatus;
7382 // Set the default JMC status of this module.
7383 void Module::SetJMCStatus(bool fStatus)
7385 LIMITED_METHOD_CONTRACT;
7387 m_debuggerSpecificData.m_fDefaultJMCStatus = fStatus;
7390 // Update the dynamic metadata if needed. Nop for non-dynamic modules
7391 void Module::UpdateDynamicMetadataIfNeeded()
7400 // Only need to serializing metadata for dynamic modules. For non-dynamic modules, metadata is already available.
7401 if (!IsReflection())
7406 // Since serializing metadata to an auxillary buffer is only needed by the debugger,
7407 // we should only be doing this for modules that the debugger can see.
7408 if (!IsVisibleToDebugger())
7417 GetReflectionModule()->CaptureModuleMetaDataToMemory();
7419 EX_CATCH_HRESULT(hr);
7421 // This Metadata buffer is only used for the debugger, so it's a non-fatal exception for regular CLR execution.
7422 // Just swallow it and keep going. However, with the exception of out-of-memory, we do expect it to
7423 // succeed, so assert on failures.
7424 if (hr != E_OUTOFMEMORY)
7426 SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
7431 #ifdef DEBUGGING_SUPPORTED
7433 #ifdef FEATURE_FUSION
7435 // Fetch Pdbs from the host
7438 // No explicit return value.
7439 // Caches the pdb stream on the module instance if available.
7440 // Does nothing if not hosted or if the host does not provide a stream.
7441 // Throws on exception if the host does provide a stream, but we can't copy it out.
7444 // This fetches PDBs from the host and caches them so that they are available for when the debugger attaches.
7445 // This lets Arrowhead tools run against Whidbey hosts in a compatibility mode.
7446 // We expect to add a hosting knob that will allow a host to disable this eager fetching and not run in
7448 void Module::FetchPdbsFromHost()
7460 ReleaseHolder<IStream> pHostStream;
7462 hr = GetHostPdbStream(&pHostStream); // addrefs, holder will release
7463 if (pHostStream == NULL)
7465 // Common failure case, we're either not hosted, or the host doesn't have a stream.
7468 // pHostStream is a stream implemented by the host, so be extra cautious about methods failing,
7469 // especially with E_NOTIMPL.
7471 SafeComHolder<CGrowableStream> pStream(new CGrowableStream()); // throws
7474 // Copy from pHostStream (owned by host) to CGrowableStream (owned by CLR, and visible to debugger from OOP).
7477 // Get number of bytes to copy.
7478 STATSTG SizeData = {0};
7479 hr = pHostStream->Stat(&SizeData, STATFLAG_NONAME);
7481 ULARGE_INTEGER streamSize = SizeData.cbSize;
7483 if (streamSize.u.HighPart > 0)
7485 // Too big. We shouldn't have a PDB larger than 4gb.
7486 ThrowHR(E_OUTOFMEMORY);
7488 ULONG cbRequest = streamSize.u.LowPart;
7492 hr = pStream->SetSize(streamSize);
7495 _ASSERTE(pStream->GetRawBuffer().Size() == cbRequest);
7497 // Do the actual copy
7498 ULONG cbActualRead = 0;
7499 hr = pHostStream->Read(pStream->GetRawBuffer().StartAddress(), cbRequest, &cbActualRead);
7501 if (cbRequest != cbActualRead)
7503 ThrowWin32(ERROR_READ_FAULT);
7506 // We now have a full copy of the PDB provided from the host.
7507 // This addrefs pStream, which lets it survive past the holder's scope.
7508 SetInMemorySymbolStream(pStream, eSymbolFormatPDB);
7510 #endif // FEATURE_FUSION
7512 #endif // DEBUGGING_SUPPORTED
7514 BOOL Module::NotifyDebuggerLoad(AppDomain *pDomain, DomainFile * pDomainFile, int flags, BOOL attaching)
7516 WRAPPER_NO_CONTRACT;
7518 // We don't notify the debugger about modules that don't contain any code.
7519 if (!IsVisibleToDebugger())
7522 // Always capture metadata, even if no debugger is attached. If a debugger later attaches, it will use
7525 Module * pModule = pDomainFile->GetModule();
7526 pModule->UpdateDynamicMetadataIfNeeded();
7529 #ifdef FEATURE_FUSION
7530 // Eagerly fetch pdbs for hosted modules.
7531 // This is only needed for debugging, so errors are not fatal in normal cases.
7532 HRESULT hrFetchPdbs = S_OK;
7535 FetchPdbsFromHost();
7537 EX_CATCH_HRESULT(hrFetchPdbs);
7538 #endif // FEATURE_FUSION
7541 // Remaining work is only needed if a debugger is attached
7543 if (!attaching && !pDomain->IsDebuggerAttached())
7547 BOOL result = FALSE;
7549 if (flags & ATTACH_MODULE_LOAD)
7551 g_pDebugInterface->LoadModule(this,
7553 m_file->GetPath().GetCount(),
7562 if (flags & ATTACH_CLASS_LOAD)
7564 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
7565 while (typeDefIter.Next())
7567 MethodTable * pMT = typeDefIter.GetElement();
7569 if (pMT != NULL && pMT->IsRestored())
7571 result = TypeHandle(pMT).NotifyDebuggerLoad(pDomain, attaching) || result;
7579 void Module::NotifyDebuggerUnload(AppDomain *pDomain)
7581 LIMITED_METHOD_CONTRACT;
7583 if (!pDomain->IsDebuggerAttached())
7586 // We don't notify the debugger about modules that don't contain any code.
7587 if (!IsVisibleToDebugger())
7590 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
7591 while (typeDefIter.Next())
7593 MethodTable * pMT = typeDefIter.GetElement();
7595 if (pMT != NULL && pMT->IsRestored())
7597 TypeHandle(pMT).NotifyDebuggerUnload(pDomain);
7601 g_pDebugInterface->UnloadModule(this, pDomain);
7604 #if defined(FEATURE_MIXEDMODE) && !defined(CROSSGEN_COMPILE)
7606 //======================================================================================
7607 // These are used to call back to the shim to get the information about
7608 // thunks, and to set the new targets.
7609 typedef mdToken STDMETHODCALLTYPE GetTokenForVTableEntry_t(HINSTANCE hInst, BYTE **ppVTEntry);
7610 typedef void STDMETHODCALLTYPE SetTargetForVTableEntry_t(HINSTANCE hInst, BYTE **ppVTEntry, BYTE *pTarget);
7611 typedef BYTE * STDMETHODCALLTYPE GetTargetForVTableEntry_t(HINSTANCE hInst, BYTE **ppVTEntry);
7613 GetTokenForVTableEntry_t *g_pGetTokenForVTableEntry = NULL;
7614 SetTargetForVTableEntry_t *g_pSetTargetForVTableEntry = NULL;
7615 GetTargetForVTableEntry_t *g_pGetTargetForVTableEntry = NULL;
7617 //======================================================================================
7618 void InitThunkCallbackFunctions(HINSTANCE hInstShim)
7627 e_INITIALIZED_SUCCESS,
7630 static InitState_t s_state = e_UNINITIALIZED;
7631 if (s_state == e_UNINITIALIZED) {
7632 g_pGetTokenForVTableEntry = (GetTokenForVTableEntry_t *)GetProcAddress(hInstShim, "GetTokenForVTableEntry");
7633 if (g_pGetTokenForVTableEntry == NULL) {
7634 COMPlusThrow(kMissingMethodException, IDS_EE_MSCOREE_MISSING_ENTRYPOINT, W("GetTokenForVTableEntry"));
7636 g_pSetTargetForVTableEntry = (SetTargetForVTableEntry_t *)GetProcAddress(hInstShim, "SetTargetForVTableEntry");
7637 if (g_pSetTargetForVTableEntry == NULL) {
7638 COMPlusThrow(kMissingMethodException, IDS_EE_MSCOREE_MISSING_ENTRYPOINT, W("SetTargetForVTableEntry"));
7640 g_pGetTargetForVTableEntry = (GetTargetForVTableEntry_t *)GetProcAddress(hInstShim, "GetTargetForVTableEntry");
7641 if (g_pGetTargetForVTableEntry == NULL) {
7642 COMPlusThrow(kMissingMethodException, IDS_EE_MSCOREE_MISSING_ENTRYPOINT, W("GetTargetForVTableEntry"));
7644 s_state = e_INITIALIZED_SUCCESS;
7646 CONSISTENCY_CHECK(s_state != e_UNINITIALIZED);
7649 //======================================================================================
7650 void InitShimHINSTANCE()
7657 if (g_hInstShim == NULL) {
7658 g_hInstShim = WszLoadLibrary(MSCOREE_SHIM_W);
7659 if (g_hInstShim == NULL) {
7660 InlineSString<80> ssErrorFormat;
7661 if(!ssErrorFormat.LoadResource(CCompRC::Optional, IDS_EE_MSCOREE_MISSING))
7663 // Keep this in sync with the actual message
7664 ssErrorFormat.Set(W("MSCOREE is not loaded."));
7666 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, ssErrorFormat.GetUnicode());
7671 //======================================================================================
7672 HINSTANCE GetShimHINSTANCE() // dead code?
7674 WRAPPER_NO_CONTRACT;
7675 InitShimHINSTANCE();
7679 //======================================================================================
7680 // Fixup vtables stored in the header to contain pointers to method desc
7681 // prestubs rather than metadata method tokens.
7682 void Module::FixupVTables()
7690 // If we've already fixed up, or this is not an IJW module, just return.
7691 // NOTE: This relies on ILOnly files not having fixups. If this changes,
7692 // we need to change this conditional.
7693 if (IsIJWFixedUp() || m_file->IsILOnly() || IsIntrospectionOnly()) {
7697 // An EEException will be thrown if either MSCOREE or any of the required
7698 // entrypoints cannot be found.
7699 InitShimHINSTANCE();
7700 InitThunkCallbackFunctions(g_hInstShim);
7702 HINSTANCE hInstThis = GetFile()->GetIJWBase();
7704 // <REVISIT_TODO>@todo: workaround!</REVISIT_TODO>
7705 // If we are compiling in-process, we don't want to fixup the vtables - as it
7706 // will have side effects on the other copy of the module!
7707 if (SystemDomain::GetCurrentDomain()->IsPassiveDomain()) {
7711 #ifdef FEATURE_PREJIT
7712 // We delayed filling in this value until the LoadLibrary occurred
7713 if (HasTls() && HasNativeImage()) {
7714 CORCOMPILE_EE_INFO_TABLE *pEEInfo = GetNativeImage()->GetNativeEEInfoTable();
7715 pEEInfo->rvaStaticTlsIndex = GetTlsIndex();
7718 // Get vtable fixup data
7719 COUNT_T cFixupRecords;
7720 IMAGE_COR_VTABLEFIXUP *pFixupTable = m_file->GetVTableFixups(&cFixupRecords);
7722 // No records then return
7723 if (cFixupRecords == 0) {
7727 // Now, we need to take a lock to serialize fixup.
7728 PEImage::IJWFixupData *pData = PEImage::GetIJWData(m_file->GetIJWBase());
7730 // If it's already been fixed (in some other appdomain), record the fact and return
7731 if (pData->IsFixedUp()) {
7736 //////////////////////////////////////////////////////
7738 // This is done in three stages:
7739 // 1. We enumerate the types we'll need to load
7740 // 2. We load the types
7741 // 3. We create and install the thunks
7744 COUNT_T cVtableThunks = 0;
7745 struct MethodLoadData
7750 MethodLoadData *rgMethodsToLoad = NULL;
7751 COUNT_T cMethodsToLoad = 0;
7757 // Each fixup entry describes a vtable, so iterate the vtables and sum their counts
7760 for (iFixup = 0; iFixup < cFixupRecords; iFixup++)
7761 cVtableThunks += pFixupTable[iFixup].Count;
7764 Thread *pThread = GetThread();
7765 StackingAllocator *pAlloc = &pThread->m_MarshalAlloc;
7766 CheckPointHolder cph(pAlloc->GetCheckpoint());
7768 // Allocate the working array of tokens.
7769 cMethodsToLoad = cVtableThunks;
7771 rgMethodsToLoad = new (pAlloc) MethodLoadData[cMethodsToLoad];
7772 memset(rgMethodsToLoad, 0, cMethodsToLoad*sizeof(MethodLoadData));
7774 // Now take the IJW module lock and get all the tokens
7777 CrstHolder lockHolder(pData->GetLock());
7779 // If someone has beaten us, just return
7780 if (pData->IsFixedUp())
7786 COUNT_T iCurMethod = 0;
7788 if (cFixupRecords != 0)
7790 for (COUNT_T iFixup = 0; iFixup < cFixupRecords; iFixup++)
7792 // Vtables can be 32 or 64 bit.
7793 if ((pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED)) ||
7794 (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED|COR_VTABLE_FROM_UNMANAGED)) ||
7795 (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED|COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN)))
7797 const BYTE** pPointers = (const BYTE **) m_file->GetVTable(pFixupTable[iFixup].RVA);
7798 for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++)
7800 if (pData->IsMethodFixedUp(iFixup,iMethod))
7802 mdToken mdTok = (*g_pGetTokenForVTableEntry)(hInstThis, (BYTE **)(pPointers + iMethod));
7803 CONSISTENCY_CHECK(mdTok != mdTokenNil);
7804 rgMethodsToLoad[iCurMethod++].token = mdTok;
7813 // Stage 2 - Load the types
7817 for (COUNT_T iCurMethod = 0; iCurMethod < cMethodsToLoad; iCurMethod++)
7819 mdToken curTok = rgMethodsToLoad[iCurMethod].token;
7820 if(!GetMDImport()->IsValidToken(curTok))
7822 _ASSERTE(!"Invalid token in v-table fix-up table");
7823 ThrowHR(COR_E_BADIMAGEFORMAT);
7827 // Find the method desc
7831 CONTRACT_VIOLATION(LoadsTypeViolation);
7832 pMD = FindMethodThrowing(curTok);
7835 CONSISTENCY_CHECK(CheckPointer(pMD));
7837 rgMethodsToLoad[iCurMethod].pMD = pMD;
7842 // Stage 3 - Create the thunk data
7846 CrstHolder lockHolder(pData->GetLock());
7848 // If someone has beaten us, just return
7849 if (pData->IsFixedUp())
7855 // This is the app domain which all of our U->M thunks for this module will have
7856 // affinity with. Note that if the module is shared between multiple domains, all thunks will marshal back
7857 // to the original domain, so some of the thunks may cause a surprising domain switch to occur.
7858 // (And furthermore note that if the original domain is unloaded, all the thunks will simply throw an
7861 // (The essential problem is that these thunks are shared via the global process address space
7862 // rather than per domain, thus there is no context to figure out our domain from. We could
7863 // use the current thread's domain, but that is effectively undefined in unmanaged space.)
7865 // The bottom line is that the IJW model just doesn't fit with multiple app domain design very well, so
7866 // better to have well defined limitations than flaky behavior.
7870 AppDomain *pAppDomain = GetAppDomain();
7872 // Used to index into rgMethodsToLoad
7873 COUNT_T iCurMethod = 0;
7876 // Each fixup entry describes a vtable (each slot contains a metadata token
7879 for (iFixup = 0; iFixup < cFixupRecords; iFixup++)
7880 cVtableThunks += pFixupTable[iFixup].Count;
7883 DWORD dwThunkIndex = 0;
7885 // Now to fill in the thunk table.
7886 for (iFixup = 0; iFixup < cFixupRecords; iFixup++)
7888 const BYTE** pPointers = (const BYTE **)
7889 m_file->GetVTable(pFixupTable[iFixup].RVA);
7891 // Vtables can be 32 or 64 bit.
7892 if (pFixupTable[iFixup].Type == COR_VTABLE_PTRSIZED)
7894 for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++)
7896 if (pData->IsMethodFixedUp(iFixup,iMethod))
7899 mdToken mdTok = rgMethodsToLoad[iCurMethod].token;
7900 MethodDesc *pMD = rgMethodsToLoad[iCurMethod].pMD;
7904 if (pMD->IsNDirect())
7906 LOG((LF_IJW, LL_INFO10, "[0x%lx] <-- PINV thunk for \"%s\" (target = 0x%lx)\n",
7907 (size_t)&(pPointers[iMethod]), pMD->m_pszDebugMethodName,
7908 (size_t) (((NDirectMethodDesc*)pMD)->GetNDirectTarget())));
7912 CONSISTENCY_CHECK(dwThunkIndex < cVtableThunks);
7914 // Point the local vtable slot to the thunk we created
7915 (*g_pSetTargetForVTableEntry)(hInstThis, (BYTE **)&pPointers[iMethod], (BYTE *)pMD->GetMultiCallableAddrOfCode());
7917 pData->MarkMethodFixedUp(iFixup,iMethod);
7923 else if (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED|COR_VTABLE_FROM_UNMANAGED))
7926 for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++)
7928 if (pData->IsMethodFixedUp(iFixup,iMethod))
7931 mdToken mdTok = rgMethodsToLoad[iCurMethod].token;
7932 MethodDesc *pMD = rgMethodsToLoad[iCurMethod].pMD;
7934 LOG((LF_IJW, LL_INFO10, "[0x%p] <-- VTable thunk for \"%s\" (pMD = 0x%p)\n",
7935 (UINT_PTR)&(pPointers[iMethod]), pMD->m_pszDebugMethodName, pMD));
7937 UMEntryThunk *pUMEntryThunk = (UMEntryThunk*)(void*)(GetDllThunkHeap()->AllocAlignedMem(sizeof(UMEntryThunk), CODE_SIZE_ALIGN)); // UMEntryThunk contains code
7938 FillMemory(pUMEntryThunk, sizeof(*pUMEntryThunk), 0);
7940 UMThunkMarshInfo *pUMThunkMarshInfo = (UMThunkMarshInfo*)(void*)(GetThunkHeap()->AllocAlignedMem(sizeof(UMThunkMarshInfo), CODE_SIZE_ALIGN));
7941 FillMemory(pUMThunkMarshInfo, sizeof(*pUMThunkMarshInfo), 0);
7943 pUMThunkMarshInfo->LoadTimeInit(pMD);
7944 pUMEntryThunk->LoadTimeInit(NULL, NULL, pUMThunkMarshInfo, pMD, pAppDomain->GetId());
7945 (*g_pSetTargetForVTableEntry)(hInstThis, (BYTE **)&pPointers[iMethod], (BYTE *)pUMEntryThunk->GetCode());
7947 pData->MarkMethodFixedUp(iFixup,iMethod);
7950 else if (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED|COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN))
7953 for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++)
7955 if (pData->IsMethodFixedUp(iFixup,iMethod))
7958 mdToken mdTok = rgMethodsToLoad[iCurMethod].token;
7961 IJWNOADThunk* pThunkLocal = new(GetDllThunkHeap()->AllocAlignedMem(sizeof(IJWNOADThunk), CODE_SIZE_ALIGN)) IJWNOADThunk(GetFile()->GetIJWBase(),dwIndex++,mdTok);
7962 (*g_pSetTargetForVTableEntry)(hInstThis, (BYTE **)&pPointers[iMethod], (BYTE *)pThunkLocal->GetCode());
7964 pData->MarkMethodFixedUp(iFixup,iMethod);
7967 else if ((pFixupTable[iFixup].Type & COR_VTABLE_NOT_PTRSIZED) == COR_VTABLE_NOT_PTRSIZED)
7969 // fixup type doesn't match the platform
7970 THROW_BAD_FORMAT(BFA_FIXUP_WRONG_PLATFORM, this);
7974 _ASSERTE(!"Unknown vtable fixup type");
7979 if(!GetAssembly()->IsDomainNeutral())
7980 CreateDomainThunks();
7982 SetDomainIdOfIJWFixups(pAppDomain->GetId());
7983 #ifdef FEATURE_PREJIT
7984 if (HasNativeImage()) {
7985 CORCOMPILE_EE_INFO_TABLE *pEEInfo = GetNativeImage()->GetNativeEEInfoTable();
7987 if (pEEInfo->nativeEntryPointStart != 0) {
7988 PTR_PEImageLayout pIJWLayout = m_file->GetLoadedIL();
7989 SIZE_T base = (SIZE_T)pIJWLayout->GetBase();
7991 _ASSERTE(pIJWLayout->CheckRva((RVA)pEEInfo->nativeEntryPointStart));
7992 _ASSERTE(pIJWLayout->CheckRva((RVA)pEEInfo->nativeEntryPointEnd));
7994 pEEInfo->nativeEntryPointStart += base;
7995 pEEInfo->nativeEntryPointEnd += base;
7998 _ASSERTE(pEEInfo->nativeEntryPointEnd == 0);
8002 // Indicate that this module has been fixed before releasing the lock
8003 pData->SetIsFixedUp(); // On the data
8004 SetIsIJWFixedUp(); // On the module
8008 // Self-initializing accessor for m_pThunkHeap
8009 LoaderHeap *Module::GetDllThunkHeap()
8018 return PEImage::GetDllThunkHeap(GetFile()->GetIJWBase());
8021 LoaderHeap *Module::GetThunkHeap()
8023 CONTRACT (LoaderHeap *)
8029 INJECT_FAULT(COMPlusThrowOM());
8030 POSTCONDITION(CheckPointer(RETVAL));
8036 size_t * pPrivatePCLBytes = NULL;
8037 size_t * pGlobalPCLBytes = NULL;
8039 #ifdef PROFILING_SUPPORTED
8040 pPrivatePCLBytes = &(GetPerfCounters().m_Loading.cbLoaderHeapSize);
8043 LoaderHeap *pNewHeap = new LoaderHeap(VIRTUAL_ALLOC_RESERVE_GRANULARITY, // DWORD dwReserveBlockSize
8044 0, // DWORD dwCommitBlockSize
8046 ThunkHeapStubManager::g_pManager->GetRangeList(),
8047 TRUE); // BOOL fMakeExecutable
8049 if (FastInterlockCompareExchangePointer(&m_pThunkHeap, pNewHeap, 0) != 0)
8055 RETURN m_pThunkHeap;
8058 void Module::SetADThunkTable(UMEntryThunk* pTable)
8069 GetDomainLocalModule()->SetADThunkTable(pTable);
8072 UMEntryThunk* Module::GetADThunkTable()
8074 CONTRACT(UMEntryThunk*)
8080 INJECT_FAULT(COMPlusThrowOM());
8081 POSTCONDITION(CheckPointer(RETVAL));
8085 DomainLocalModule* pMod=GetDomainLocalModule();
8087 UMEntryThunk * pADThunkTable = pMod->GetADThunkTable();
8088 if (pADThunkTable == NULL)
8090 CreateDomainThunks();
8091 pADThunkTable = pMod->GetADThunkTable();
8092 _ASSERTE(pADThunkTable != NULL);
8095 RETURN (UMEntryThunk*)pADThunkTable;
8098 void Module::CreateDomainThunks()
8106 INJECT_FAULT(COMPlusThrowOM());
8110 AppDomain *pAppDomain = GetAppDomain();
8113 _ASSERTE(!"No appdomain");
8117 UINT32 cFixupRecords;
8118 IMAGE_COR_VTABLEFIXUP *pFixupTable = m_file->GetVTableFixups(&cFixupRecords);
8121 DWORD cVtableThunks=0;
8122 for (iFixup = 0; iFixup < cFixupRecords; iFixup++)
8124 if (pFixupTable[iFixup].Type==(COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN|COR_VTABLE_PTRSIZED))
8126 cVtableThunks += pFixupTable[iFixup].Count;
8130 if (cVtableThunks==0)
8135 AllocMemTracker amTracker;
8136 AllocMemTracker *pamTracker = &amTracker;
8138 UMEntryThunk* pTable=((UMEntryThunk*)pamTracker->Track(pAppDomain->GetStubHeap()->AllocAlignedMem(sizeof(UMEntryThunk)*cVtableThunks, CODE_SIZE_ALIGN)));
8139 DWORD dwCurrIndex=0;
8140 for (iFixup = 0; iFixup < cFixupRecords; iFixup++)
8142 if (pFixupTable[iFixup].Type == (COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN|COR_VTABLE_PTRSIZED))
8144 const BYTE **pPointers = (const BYTE **) m_file->GetVTable(pFixupTable[iFixup].RVA);
8145 for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++)
8147 PCODE pCode = (PCODE)
8148 (*g_pGetTargetForVTableEntry)((HINSTANCE)GetFile()->GetIJWBase(), (BYTE **)&pPointers[iMethod]);
8149 IJWNOADThunk* pThnk = IJWNOADThunk::FromCode(pCode);
8150 mdToken tok=pThnk->GetToken(); //!!
8151 if(!GetMDImport()->IsValidToken(tok))
8153 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN);
8157 MethodDesc *pMD = FindMethodThrowing(tok);
8159 // @TODO: Check for out of memory
8160 UMThunkMarshInfo *pUMThunkMarshInfo = (UMThunkMarshInfo*)pamTracker->Track(pAppDomain->GetStubHeap()->AllocAlignedMem(sizeof(UMThunkMarshInfo), CODE_SIZE_ALIGN));
8161 _ASSERTE(pUMThunkMarshInfo != NULL);
8163 pUMThunkMarshInfo->LoadTimeInit(pMD);
8164 pTable[dwCurrIndex].LoadTimeInit(NULL, NULL, pUMThunkMarshInfo, pMD, pAppDomain->GetId());
8166 // If we're setting up a domain that is cached, update the code pointer in the cache
8167 if (pThnk->IsCachedAppDomainID(pAppDomain->GetId()))
8168 pThnk->SetCachedInfo(pAppDomain->GetId(), (LPVOID)GetEEFuncEntryPoint((LPVOID)pTable[dwCurrIndex].GetCode()));
8175 pamTracker->SuppressRelease();
8176 SetADThunkTable(pTable);
8179 LPVOID Module::GetUMThunk(LPVOID pManagedIp, PCCOR_SIGNATURE pSig, ULONG cSig)
8190 return GetDomainFile()->GetUMThunk(pManagedIp, pSig, cSig);
8194 void *Module::GetMUThunk(LPVOID pUnmanagedIp, PCCOR_SIGNATURE pSig, ULONG cSig)
8202 INJECT_FAULT(COMPlusThrowOM());
8203 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
8207 if (m_pMUThunkHash == NULL)
8209 MUThunkHash *pMUThunkHash = new MUThunkHash(this);
8210 if (FastInterlockCompareExchangePointer(&m_pMUThunkHash, pMUThunkHash, NULL) != NULL)
8211 delete pMUThunkHash;
8213 RETURN m_pMUThunkHash->GetMUThunk(pUnmanagedIp, pSig, cSig);
8216 #endif //FEATURE_MIXEDMODE && !CROSSGEN_COMPILE
8219 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
8221 // These helpers are used in Module::ExpandAll
8222 // to avoid EX_TRY/EX_CATCH in a loop (uses _alloca and guzzles stack)
8224 static TypeHandle LoadTypeDefOrRefHelper(DataImage * image, Module * pModule, mdToken tk)
8226 STANDARD_VM_CONTRACT;
8232 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tk,
8233 ClassLoader::ThrowIfNotFound,
8234 ClassLoader::PermitUninstDefOrRef);
8238 image->GetPreloader()->Error(tk, GET_EXCEPTION());
8240 EX_END_CATCH(SwallowAllExceptions)
8245 static TypeHandle LoadTypeSpecHelper(DataImage * image, Module * pModule, mdToken tk,
8246 PCCOR_SIGNATURE pSig, ULONG cSig)
8248 STANDARD_VM_CONTRACT;
8254 SigPointer p(pSig, cSig);
8255 SigTypeContext typeContext;
8256 th = p.GetTypeHandleThrowing(pModule, &typeContext);
8260 image->GetPreloader()->Error(tk, GET_EXCEPTION());
8262 EX_END_CATCH(SwallowAllExceptions)
8267 static TypeHandle LoadGenericInstantiationHelper(DataImage * image, Module * pModule, mdToken tk, Instantiation inst)
8269 STANDARD_VM_CONTRACT;
8275 th = ClassLoader::LoadGenericInstantiationThrowing(pModule, tk, inst);
8279 image->GetPreloader()->Error(tk, GET_EXCEPTION());
8281 EX_END_CATCH(SwallowAllExceptions)
8286 static void GetDescFromMemberRefHelper(DataImage * image, Module * pModule, mdToken tk)
8288 STANDARD_VM_CONTRACT;
8292 MethodDesc * pMD = NULL;
8293 FieldDesc * pFD = NULL;
8296 // Note: using an empty type context is now OK, because even though the token is a MemberRef
8297 // neither the token nor its parent will directly refer to type variables.
8298 // @TODO GENERICS: want to allow loads of generic methods here but need strict metadata checks on parent
8299 SigTypeContext typeContext;
8300 MemberLoader::GetDescFromMemberRef(pModule, tk, &pMD, &pFD,
8302 FALSE /* strict metadata checks */, &th);
8306 image->GetPreloader()->Error(tk, GET_EXCEPTION());
8308 EX_END_CATCH(SwallowAllExceptions)
8311 void Module::SetProfileData(CorProfileData * profileData)
8313 LIMITED_METHOD_CONTRACT;
8314 m_pProfileData = profileData;
8317 CorProfileData * Module::GetProfileData()
8319 LIMITED_METHOD_CONTRACT;
8320 return m_pProfileData;
8323 mdTypeDef Module::LookupIbcTypeToken(Module * pExternalModule, mdToken ibcToken, SString* optionalFullNameOut)
8333 _ASSERTE(TypeFromToken(ibcToken) == ibcExternalType);
8335 CorProfileData * profileData = this->GetProfileData();
8337 CORBBTPROF_BLOB_TYPE_DEF_ENTRY * blobTypeDefEntry;
8338 blobTypeDefEntry = profileData->GetBlobExternalTypeDef(ibcToken);
8340 if (blobTypeDefEntry == NULL)
8341 return mdTypeDefNil;
8343 IbcNameHandle ibcName;
8344 ibcName.szName = &blobTypeDefEntry->name[0];
8345 ibcName.tkIbcNameSpace = blobTypeDefEntry->nameSpaceToken;
8346 ibcName.tkIbcNestedClass = blobTypeDefEntry->nestedClassToken;
8347 ibcName.szNamespace = NULL;
8348 ibcName.tkEnclosingClass = mdTypeDefNil;
8350 if (!IsNilToken(blobTypeDefEntry->nameSpaceToken))
8352 _ASSERTE(IsNilToken(blobTypeDefEntry->nestedClassToken));
8354 idExternalNamespace nameSpaceToken = blobTypeDefEntry->nameSpaceToken;
8355 _ASSERTE(TypeFromToken(nameSpaceToken) == ibcExternalNamespace);
8357 CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY * blobNamespaceDefEntry;
8358 blobNamespaceDefEntry = profileData->GetBlobExternalNamespaceDef(nameSpaceToken);
8360 if (blobNamespaceDefEntry == NULL)
8361 return mdTypeDefNil;
8363 ibcName.szNamespace = &blobNamespaceDefEntry->name[0];
8365 if (optionalFullNameOut != NULL)
8367 optionalFullNameOut->Append(W("["));
8368 optionalFullNameOut->AppendUTF8(pExternalModule->GetSimpleName());
8369 optionalFullNameOut->Append(W("]"));
8371 if ((ibcName.szNamespace != NULL) && ((*ibcName.szNamespace) != W('\0')))
8373 optionalFullNameOut->AppendUTF8(ibcName.szNamespace);
8374 optionalFullNameOut->Append(W("."));
8376 optionalFullNameOut->AppendUTF8(ibcName.szName);
8379 else if (!IsNilToken(blobTypeDefEntry->nestedClassToken))
8381 idExternalType nestedClassToken = blobTypeDefEntry->nestedClassToken;
8382 _ASSERTE(TypeFromToken(nestedClassToken) == ibcExternalType);
8384 ibcName.tkEnclosingClass = LookupIbcTypeToken(pExternalModule, nestedClassToken, optionalFullNameOut);
8386 if (optionalFullNameOut != NULL)
8388 optionalFullNameOut->Append(W("+"));
8389 optionalFullNameOut->AppendUTF8(ibcName.szName);
8392 if (IsNilToken(ibcName.tkEnclosingClass))
8393 return mdTypeDefNil;
8396 //*****************************************
8397 // look up function for TypeDef
8398 //*****************************************
8399 // STDMETHOD(FindTypeDef)(
8400 // LPCSTR szNamespace, // [IN] Namespace for the TypeDef.
8401 // LPCSTR szName, // [IN] Name of the TypeDef.
8402 // mdToken tkEnclosingClass, // [IN] TypeRef/TypeDef Token for the enclosing class.
8403 // mdTypeDef *ptypedef) PURE; // [IN] return typedef
8405 IMDInternalImport *pInternalImport = pExternalModule->GetMDImport();
8407 mdTypeDef mdResult = mdTypeDefNil;
8409 HRESULT hr = pInternalImport->FindTypeDef(ibcName.szNamespace, ibcName.szName, ibcName.tkEnclosingClass, &mdResult);
8412 mdResult = mdTypeDefNil;
8417 struct IbcCompareContext
8420 TypeHandle enclosingType;
8421 DWORD cMatch; // count of methods that had a matching method name
8422 bool useBestSig; // if true we should use the BestSig when we don't find an exact match
8423 PCCOR_SIGNATURE pvBestSig; // Current Best matching signature
8427 //---------------------------------------------------------------------------------------
8429 // Compare two signatures from the same scope.
8432 CompareIbcMethodSigs(
8433 PCCOR_SIGNATURE pvCandidateSig, // Candidate signature
8434 DWORD cbCandidateSig, //
8435 PCCOR_SIGNATURE pvIbcSignature, // The Ibc signature that we want to match
8436 DWORD cbIbcSignature, //
8437 void * pvContext) // void pointer to IbcCompareContext
8448 // Same pointer return TRUE
8450 if (pvCandidateSig == pvIbcSignature)
8452 _ASSERTE(cbCandidateSig == cbIbcSignature);
8457 // Check for exact match
8459 if (cbCandidateSig == cbIbcSignature)
8461 if (memcmp(pvCandidateSig, pvIbcSignature, cbIbcSignature) == 0)
8467 IbcCompareContext * context = (IbcCompareContext *) pvContext;
8470 // No exact match, we will return FALSE and keep looking at other matching method names
8472 // However since the method name was an exact match we will remember this signature,
8473 // so that if it is the best match we can look it up again and return it's methodDef token
8475 if (context->cMatch == 0)
8477 context->pvBestSig = pvCandidateSig;
8478 context->cbBestSig = cbCandidateSig;
8479 context->cMatch = 1;
8480 context->useBestSig = true;
8486 SigTypeContext emptyTypeContext;
8487 SigTypeContext ibcTypeContext = SigTypeContext(context->enclosingType);
8488 MetaSig ibcSignature (pvIbcSignature, cbIbcSignature, context->pModule, &ibcTypeContext);
8490 MetaSig candidateSig (pvCandidateSig, cbCandidateSig, context->pModule, &emptyTypeContext);
8491 MetaSig bestSignature(context->pvBestSig, context->cbBestSig, context->pModule, &emptyTypeContext);
8493 // Is candidateSig a better match than bestSignature?
8495 // First check the calling convention
8497 if (candidateSig.GetCallingConventionInfo() != bestSignature.GetCallingConventionInfo())
8499 if (bestSignature.GetCallingConventionInfo() == ibcSignature.GetCallingConventionInfo())
8501 if (candidateSig.GetCallingConventionInfo() == ibcSignature.GetCallingConventionInfo())
8502 goto SELECT_CANDIDATE;
8504 // Neither one is a match
8510 // Next check the number of arguments
8512 if (candidateSig.NumFixedArgs() != bestSignature.NumFixedArgs())
8515 // Does one of the two have the same number of args?
8517 if (bestSignature.NumFixedArgs() == ibcSignature.NumFixedArgs())
8519 if (candidateSig.NumFixedArgs() == ibcSignature.NumFixedArgs())
8520 goto SELECT_CANDIDATE;
8522 // Neither one is a match
8526 else if (candidateSig.NumFixedArgs() != ibcSignature.NumFixedArgs())
8529 // Neither one is a match
8534 CorElementType etIbc;
8535 CorElementType etCandidate;
8536 CorElementType etBest;
8538 // Next get the return element type
8540 // etIbc = ibcSignature.GetReturnProps().PeekElemTypeClosed(ibcSignature.GetSigTypeContext());
8541 IfFailThrow(ibcSignature.GetReturnProps().PeekElemType(&etIbc));
8542 IfFailThrow(candidateSig.GetReturnProps().PeekElemType(&etCandidate));
8543 IfFailThrow(bestSignature.GetReturnProps().PeekElemType(&etBest));
8545 // Do they have different return types?
8547 if (etCandidate != etBest)
8549 if (etBest == etIbc)
8552 if (etCandidate == etIbc)
8553 goto SELECT_CANDIDATE;
8557 // Now iterate over the method argument types to see which signature
8558 // is the better match
8560 for (DWORD i = 0; (i < ibcSignature.NumFixedArgs()); i++)
8562 ibcSignature.SkipArg();
8563 IfFailThrow(ibcSignature.GetArgProps().PeekElemType(&etIbc));
8565 candidateSig.SkipArg();
8566 IfFailThrow(candidateSig.GetArgProps().PeekElemType(&etCandidate));
8568 bestSignature.SkipArg();
8569 IfFailThrow(bestSignature.GetArgProps().PeekElemType(&etBest));
8572 // Do they have different argument types?
8574 if (etCandidate != etBest)
8576 if (etBest == etIbc)
8579 if (etCandidate == etIbc)
8580 goto SELECT_CANDIDATE;
8583 // When we fall though to here we did not find any differences
8584 // that we could base a choice on
8586 context->useBestSig = true;
8589 context->pvBestSig = pvCandidateSig;
8590 context->cbBestSig = cbCandidateSig;
8591 context->useBestSig = true;
8595 context->useBestSig = false;
8601 } // CompareIbcMethodSigs
8603 mdMethodDef Module::LookupIbcMethodToken(TypeHandle enclosingType, mdToken ibcToken, SString* optionalFullNameOut)
8613 _ASSERTE(TypeFromToken(ibcToken) == ibcExternalMethod);
8615 CorProfileData * profileData = this->GetProfileData();
8617 CORBBTPROF_BLOB_METHOD_DEF_ENTRY * blobMethodDefEntry;
8618 blobMethodDefEntry = profileData->GetBlobExternalMethodDef(ibcToken);
8620 if (blobMethodDefEntry == NULL)
8621 return mdMethodDefNil;
8623 idExternalType signatureToken = blobMethodDefEntry->signatureToken;
8624 _ASSERTE(!IsNilToken(signatureToken));
8625 _ASSERTE(TypeFromToken(signatureToken) == ibcExternalSignature);
8627 CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY * blobSignatureDefEntry;
8628 blobSignatureDefEntry = profileData->GetBlobExternalSignatureDef(signatureToken);
8630 if (blobSignatureDefEntry == NULL)
8631 return mdMethodDefNil;
8633 IbcNameHandle ibcName;
8634 ibcName.szName = &blobMethodDefEntry->name[0];
8635 ibcName.tkIbcNestedClass = blobMethodDefEntry->nestedClassToken;
8636 ibcName.tkIbcNameSpace = idExternalNamespaceNil;
8637 ibcName.szNamespace = NULL;
8638 ibcName.tkEnclosingClass = mdTypeDefNil;
8640 Module * pExternalModule = enclosingType.GetModule();
8641 PCCOR_SIGNATURE pvSig = NULL;
8644 _ASSERTE(!IsNilToken(ibcName.tkIbcNestedClass));
8645 _ASSERTE(TypeFromToken(ibcName.tkIbcNestedClass) == ibcExternalType);
8647 ibcName.tkEnclosingClass = LookupIbcTypeToken(pExternalModule, ibcName.tkIbcNestedClass, optionalFullNameOut);
8649 if (IsNilToken(ibcName.tkEnclosingClass))
8650 THROW_BAD_FORMAT(BFA_MISSING_IBC_EXTERNAL_TYPE, this);
8652 if (optionalFullNameOut != NULL)
8654 optionalFullNameOut->Append(W("."));
8655 optionalFullNameOut->AppendUTF8(ibcName.szName); // MethodName
8656 optionalFullNameOut->Append(W("()"));
8659 pvSig = blobSignatureDefEntry->sig;
8660 cbSig = blobSignatureDefEntry->cSig;
8662 //*****************************************
8663 // look up functions for TypeDef
8664 //*****************************************
8665 // STDMETHOD(FindMethodDefUsingCompare)(
8666 // mdTypeDef classdef, // [IN] given typedef
8667 // LPCSTR szName, // [IN] member name
8668 // PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of CLR signature
8669 // ULONG cbSigBlob, // [IN] count of bytes in the signature blob
8670 // PSIGCOMPARE pSignatureCompare, // [IN] Routine to compare signatures
8671 // void* pSignatureArgs, // [IN] Additional info to supply the compare function
8672 // mdMethodDef *pmd) PURE; // [OUT] matching memberdef
8675 IMDInternalImport * pInternalImport = pExternalModule->GetMDImport();
8677 IbcCompareContext context;
8678 memset(&context, 0, sizeof(IbcCompareContext));
8679 context.pModule = this;
8680 context.enclosingType = enclosingType;
8682 context.useBestSig = false;
8684 mdMethodDef mdResult = mdMethodDefNil;
8685 HRESULT hr = pInternalImport->FindMethodDefUsingCompare(ibcName.tkEnclosingClass, ibcName.szName,
8687 CompareIbcMethodSigs, (void *) &context,
8691 _ASSERTE(mdResult != mdMethodDefNil);
8693 else if (context.useBestSig)
8695 hr = pInternalImport->FindMethodDefUsingCompare(ibcName.tkEnclosingClass, ibcName.szName,
8696 context.pvBestSig, context.cbBestSig,
8697 CompareIbcMethodSigs, (void *) &context,
8699 _ASSERTE(SUCCEEDED(hr));
8700 _ASSERTE(mdResult != mdMethodDefNil);
8704 mdResult = mdMethodDefNil;
8710 SString * Module::IBCErrorNameString()
8718 INJECT_FAULT(COMPlusThrowOM());
8719 POSTCONDITION(CheckPointer(RETVAL));
8723 if (m_pIBCErrorNameString == NULL)
8725 m_pIBCErrorNameString = new SString();
8728 RETURN m_pIBCErrorNameString;
8731 void Module::IBCTypeLoadFailed(CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry,
8732 SString& exceptionMessage, SString* typeNameError)
8739 INJECT_FAULT(COMPlusThrowOM());
8740 PRECONDITION(CheckPointer(pBlobSigEntry));
8745 // Print an error message for the type load failure
8747 StackSString msg(W("Failed to load type token "));
8751 sprintf_s(buff, COUNTOF(buff), "%08x", pBlobSigEntry->blob.token);
8752 StackSString szToken(SString::Ascii, &buff[0]);
8755 if (!exceptionMessage.IsEmpty())
8757 if ((typeNameError != NULL) && !typeNameError->IsEmpty())
8759 msg += W(" for the profile data in ");
8760 msg.Append(exceptionMessage);
8763 msg += W(" The type was ");
8764 msg.Append(*typeNameError);
8769 msg += W(" from profile data. The error is ");
8770 msg.Append(exceptionMessage);
8775 GetSvcLogger()->Log(msg, LogLevel_Info);
8778 void Module::IBCMethodLoadFailed(CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry,
8779 SString& exceptionMessage, SString* methodNameError)
8786 INJECT_FAULT(COMPlusThrowOM());
8787 PRECONDITION(CheckPointer(pBlobSigEntry));
8792 // Print an error message for the type load failure
8794 StackSString msg(W("Failed to load method token "));
8797 sprintf_s(buff, COUNTOF(buff), "%08x", pBlobSigEntry->blob.token);
8798 StackSString szToken(SString::Ascii, &buff[0]);
8801 if (!exceptionMessage.IsEmpty())
8803 if ((methodNameError != NULL) && !methodNameError->IsEmpty())
8805 msg += W(" for the profile data in ");
8806 msg.Append(exceptionMessage);
8809 msg += W(" The method was ");
8810 msg.Append(*methodNameError);
8815 msg += W(" from profile data. The error is ");
8816 msg.Append(exceptionMessage);
8821 GetSvcLogger()->Log(msg, LogLevel_Info);
8824 TypeHandle Module::LoadIBCTypeHelper(CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry)
8826 CONTRACT(TypeHandle)
8831 INJECT_FAULT(COMPlusThrowOM());
8832 PRECONDITION(CheckPointer(pBlobSigEntry));
8836 TypeHandle loadedType;
8838 PCCOR_SIGNATURE pSig = pBlobSigEntry->sig;
8839 ULONG cSig = pBlobSigEntry->cSig;
8841 SigPointer p(pSig, cSig);
8843 ZapSig::Context zapSigContext(this, (void *)this, ZapSig::IbcTokens);
8844 ZapSig::Context * pZapSigContext = &zapSigContext;
8848 IBCErrorNameString()->Clear();
8850 // This is what ZapSig::FindTypeHandleFromSignature does...
8852 SigTypeContext typeContext; // empty type context
8854 loadedType = p.GetTypeHandleThrowing( this,
8856 ClassLoader::LoadTypes,
8861 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
8862 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_1);
8867 CONTRACT_VIOLATION(ThrowsViolation);
8869 StackSString exceptionMessage;
8870 GET_EXCEPTION()->GetMessage(exceptionMessage);
8871 IBCTypeLoadFailed(pBlobSigEntry, exceptionMessage, IBCErrorNameString());
8872 loadedType = TypeHandle();
8874 EX_END_CATCH(SwallowAllExceptions)
8879 //---------------------------------------------------------------------------------------
8881 MethodDesc* Module::LoadIBCMethodHelper(CORBBTPROF_BLOB_PARAM_SIG_ENTRY * pBlobSigEntry)
8883 CONTRACT(MethodDesc*)
8888 INJECT_FAULT(COMPlusThrowOM());
8889 PRECONDITION(CheckPointer(pBlobSigEntry));
8893 MethodDesc* pMethod = NULL;
8895 PCCOR_SIGNATURE pSig = pBlobSigEntry->sig;
8896 ULONG cSig = pBlobSigEntry->cSig;
8898 SigPointer p(pSig, cSig);
8900 ZapSig::Context zapSigContext(this, (void *)this, ZapSig::IbcTokens);
8901 ZapSig::Context * pZapSigContext = &zapSigContext;
8903 TypeHandle enclosingType;
8906 // First Decode and Load the enclosing type for this method
8910 IBCErrorNameString()->Clear();
8912 // This is what ZapSig::FindTypeHandleFromSignature does...
8914 SigTypeContext typeContext; // empty type context
8916 enclosingType = p.GetTypeHandleThrowing( this,
8918 ClassLoader::LoadTypes,
8923 IfFailThrow(p.SkipExactlyOne());
8924 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
8925 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_2);
8930 CONTRACT_VIOLATION(ThrowsViolation);
8932 StackSString exceptionMessage;
8933 GET_EXCEPTION()->GetMessage(exceptionMessage);
8934 IBCTypeLoadFailed(pBlobSigEntry, exceptionMessage, IBCErrorNameString());
8935 enclosingType = TypeHandle();
8937 EX_END_CATCH(SwallowAllExceptions)
8939 if (enclosingType.IsNull())
8943 // Now Decode and Load the method
8947 MethodTable *pOwnerMT = enclosingType.GetMethodTable();
8948 _ASSERTE(pOwnerMT != NULL);
8952 IfFailThrow(p.GetData(&methodFlags));
8953 BOOL isInstantiatingStub = ((methodFlags & ENCODE_METHOD_SIG_InstantiatingStub) == ENCODE_METHOD_SIG_InstantiatingStub);
8954 BOOL isUnboxingStub = ((methodFlags & ENCODE_METHOD_SIG_UnboxingStub) == ENCODE_METHOD_SIG_UnboxingStub);
8955 BOOL fMethodNeedsInstantiation = ((methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) == ENCODE_METHOD_SIG_MethodInstantiation);
8956 BOOL fMethodUsesSlotEncoding = ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == ENCODE_METHOD_SIG_SlotInsteadOfToken);
8958 if ( fMethodUsesSlotEncoding )
8960 // get the method desc using slot number
8962 IfFailThrow(p.GetData(&slot));
8964 pMethod = pOwnerMT->GetMethodDescForSlot(slot);
8966 else // otherwise we use the normal metadata MethodDef token encoding and we handle ibc tokens.
8969 // decode method token
8972 IfFailThrow(p.GetData(&methodRid));
8974 mdMethodDef methodToken;
8977 // Is our enclosingType from another module?
8979 if (this == enclosingType.GetModule())
8982 // The enclosing type is from our module
8983 // The method token is a normal MethodDef token
8985 methodToken = TokenFromRid(methodRid, mdtMethodDef);
8990 // The enclosing type is from an external module
8991 // The method token is a ibcExternalMethod token
8993 idExternalType ibcToken = RidToToken(methodRid, ibcExternalMethod);
8994 methodToken = this->LookupIbcMethodToken(enclosingType, ibcToken);
8996 if (IsNilToken(methodToken))
8998 SString * fullTypeName = IBCErrorNameString();
8999 fullTypeName->Clear();
9000 this->LookupIbcMethodToken(enclosingType, ibcToken, fullTypeName);
9002 THROW_BAD_FORMAT(BFA_MISSING_IBC_EXTERNAL_METHOD, this);
9007 SigTypeContext methodTypeContext( enclosingType );
9008 pMethod = MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(
9009 pOwnerMT->GetModule(),
9018 // Instantiate the method if needed, or create a stub to a static method in a generic class.
9019 if (fMethodNeedsInstantiation && pMethod->HasMethodInstantiation())
9021 DWORD nargs = pMethod->GetNumGenericMethodArgs();
9024 if (!ClrSafeInt<SIZE_T>::multiply(nargs, sizeof(TypeHandle), cbMem/* passed by ref */))
9025 ThrowHR(COR_E_OVERFLOW);
9027 TypeHandle * pInst = (TypeHandle*) _alloca(cbMem);
9028 SigTypeContext typeContext; // empty type context
9030 for (DWORD i = 0; i < nargs; i++)
9032 pInst[i] = p.GetTypeHandleThrowing( this,
9034 ClassLoader::LoadTypes,
9039 IfFailThrow(p.SkipExactlyOne());
9042 inst = Instantiation(pInst, nargs);
9046 inst = pMethod->LoadMethodInstantiation();
9049 // This must be called even if nargs == 0, in order to create an instantiating
9050 // stub for static methods in generic classees if needed, also for BoxedEntryPointStubs
9051 // in non-generic structs.
9052 pMethod = MethodDesc::FindOrCreateAssociatedMethodDesc(pMethod, pOwnerMT,
9055 !(isInstantiatingStub || isUnboxingStub));
9057 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
9058 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_3);
9064 CONTRACT_VIOLATION(ThrowsViolation);
9066 StackSString exceptionMessage;
9067 GET_EXCEPTION()->GetMessage(exceptionMessage);
9068 IBCMethodLoadFailed(pBlobSigEntry, exceptionMessage, IBCErrorNameString());
9071 EX_END_CATCH(SwallowAllExceptions)
9074 } // Module::LoadIBCMethodHelper
9076 #ifdef FEATURE_COMINTEROP
9077 //---------------------------------------------------------------------------------------
9079 // This function is a workaround for missing IBC data in WinRT assemblies and
9080 // not-yet-implemented sharing of IL_STUB(__Canon arg) IL stubs for all interfaces.
9082 static void ExpandWindowsRuntimeType(TypeHandle t, DataImage *image)
9087 PRECONDITION(!t.IsNull());
9094 // This array contains our poor man's IBC data - instantiations that are known to
9095 // be used by other assemblies.
9098 LPCUTF8 m_szTypeName;
9099 BinderClassID m_GenericBinderClassID;
9101 rgForcedInstantiations[] = {
9102 { "Windows.UI.Xaml.Data.IGroupInfo", CLASS__IENUMERABLEGENERIC },
9103 { "Windows.UI.Xaml.UIElement", CLASS__ILISTGENERIC },
9104 { "Windows.UI.Xaml.Visibility", CLASS__CLRIREFERENCEIMPL },
9105 { "Windows.UI.Xaml.VerticalAlignment", CLASS__CLRIREFERENCEIMPL },
9106 { "Windows.UI.Xaml.HorizontalAlignment", CLASS__CLRIREFERENCEIMPL },
9107 // The following instantiations are used by Microsoft.PlayerFramework - http://playerframework.codeplex.com/
9108 { "Windows.UI.Xaml.Media.AudioCategory", CLASS__CLRIREFERENCEIMPL },
9109 { "Windows.UI.Xaml.Media.AudioDeviceType", CLASS__CLRIREFERENCEIMPL },
9110 { "Windows.UI.Xaml.Media.MediaElementState", CLASS__CLRIREFERENCEIMPL },
9111 { "Windows.UI.Xaml.Media.Stereo3DVideoRenderMode", CLASS__CLRIREFERENCEIMPL },
9112 { "Windows.UI.Xaml.Media.Stereo3DVideoPackingMode", CLASS__CLRIREFERENCEIMPL },
9115 DefineFullyQualifiedNameForClass();
9116 LPCUTF8 szTypeName = GetFullyQualifiedNameForClass(t.AsMethodTable());
9118 for (SIZE_T i = 0; i < COUNTOF(rgForcedInstantiations); i++)
9120 if (strcmp(szTypeName, rgForcedInstantiations[i].m_szTypeName) == 0)
9124 TypeHandle thGenericType = TypeHandle(MscorlibBinder::GetClass(rgForcedInstantiations[i].m_GenericBinderClassID));
9126 Instantiation inst(&t, 1);
9127 thGenericType.Instantiate(inst);
9131 image->GetPreloader()->Error(t.GetCl(), GET_EXCEPTION());
9133 EX_END_CATCH(SwallowAllExceptions)
9137 if (strcmp(szTypeName, "Windows.Foundation.Collections.IObservableVector`1") == 0)
9141 TypeHandle thArg = TypeHandle(g_pObjectClass);
9143 Instantiation inst(&thArg, 1);
9144 t.Instantiate(inst);
9148 image->GetPreloader()->Error(t.GetCl(), GET_EXCEPTION());
9150 EX_END_CATCH(SwallowAllExceptions)
9153 #endif // FEATURE_COMINTEROP
9155 //---------------------------------------------------------------------------------------
9157 void Module::ExpandAll(DataImage *image)
9162 PRECONDITION(!IsResource());
9167 DWORD assemblyFlags = GetAssembly()->GetFlags();
9170 // Explicitly load the global class.
9173 MethodTable *pGlobalMT = GetGlobalMethodTable();
9176 // Load all classes. This also fills out the
9177 // RID maps for the typedefs, method defs,
9181 IMDInternalImport *pInternalImport = GetMDImport();
9183 HENUMInternalHolder hEnum(pInternalImport);
9184 hEnum.EnumTypeDefInit();
9186 while (pInternalImport->EnumTypeDefNext(&hEnum, &tk))
9188 #ifdef FEATURE_COMINTEROP
9189 // Skip the non-managed WinRT types since they're only used by Javascript and C++
9191 // With WinRT files, we want to exclude certain types that cause us problems:
9192 // * Attribute types defined in Windows.Foundation. The constructor's methodimpl flags
9193 // specify it is an internal runtime function and gets set as an FCALL when we parse
9196 if (IsAfContentType_WindowsRuntime(assemblyFlags))
9199 pInternalImport->GetTypeDefProps(tk, NULL, &tkExtends);
9201 if (TypeFromToken(tkExtends) == mdtTypeRef)
9203 LPCSTR szNameSpace = NULL;
9204 LPCSTR szName = NULL;
9205 pInternalImport->GetNameOfTypeRef(tkExtends, &szNameSpace, &szName);
9207 if (!strcmp(szNameSpace, "System") && !_stricmp((szName), "Attribute"))
9213 #endif // FEATURE_COMINTEROP
9215 TypeHandle t = LoadTypeDefOrRefHelper(image, this, tk);
9217 if (t.IsNull()) // Skip this type
9220 if (!t.HasInstantiation())
9222 EEClassHashEntry_t *pBucket = NULL;
9224 StackSString ssFullyQualifiedName;
9226 EEClassHashTable *pTable = GetAvailableClassHash();
9228 _ASSERTE(pTable != NULL);
9230 t.GetName(ssFullyQualifiedName);
9233 StackScratchBuffer scratch;
9234 LPCUTF8 szFullyQualifiedName = ssFullyQualifiedName.GetUTF8(scratch);
9236 BOOL isNested = ClassLoader::IsNested(this, tk, &mdEncloser);
9237 EEClassHashTable::LookupContext sContext;
9238 pBucket = pTable->GetValue(szFullyQualifiedName, &data, isNested, &sContext);
9242 while (pBucket != NULL)
9244 _ASSERTE (TypeFromToken(tk) == mdtTypeDef);
9245 BOOL match = GetClassLoader()->CompareNestedEntryWithTypeDef( pInternalImport,
9247 GetAvailableClassHash(),
9248 pBucket->GetEncloser());
9252 pBucket = pTable->FindNextNestedClass(szFullyQualifiedName, &data, &sContext);
9256 // Save the typehandle instead of the token in the hash entry so that ngen'ed images
9257 // don't have to lookup based on token and update this entry
9258 if ((pBucket != NULL) && !t.IsNull() && t.IsRestored())
9259 pBucket->SetData(t.AsPtr());
9262 DWORD nGenericClassParams = t.GetNumGenericArgs();
9263 if (nGenericClassParams != 0)
9265 // For generic types, load the instantiation at Object
9267 if (!ClrSafeInt<SIZE_T>::multiply(sizeof(TypeHandle), nGenericClassParams, cbMem/* passed by ref */))
9269 ThrowHR(COR_E_OVERFLOW);
9271 CQuickBytes qbGenericClassArgs;
9272 TypeHandle *genericClassArgs = reinterpret_cast<TypeHandle*>(qbGenericClassArgs.AllocThrows(cbMem));
9273 for (DWORD i = 0; i < nGenericClassParams; i++)
9275 genericClassArgs[i] = TypeHandle(g_pCanonMethodTableClass);
9278 TypeHandle thCanonInst = LoadGenericInstantiationHelper(image, this, tk, Instantiation(genericClassArgs, nGenericClassParams));
9280 // If successful, add the instantiation to the Module's map of generic types instantiated at Object
9281 if (!thCanonInst.IsNull() && !thCanonInst.IsTypeDesc())
9283 MethodTable * pCanonMT = thCanonInst.AsMethodTable();
9284 m_GenericTypeDefToCanonMethodTableMap.AddElement(this, RidFromToken(pCanonMT->GetCl()), pCanonMT);
9288 #ifdef FEATURE_COMINTEROP
9289 if (IsAfContentType_WindowsRuntime(assemblyFlags))
9291 ExpandWindowsRuntimeType(t, image);
9293 #endif // FEATURE_COMINTEROP
9298 // Fill out TypeRef RID map
9302 HENUMInternalHolder hEnum(pInternalImport);
9303 hEnum.EnumAllInit(mdtTypeRef);
9305 while (pInternalImport->EnumNext(&hEnum, &tk))
9307 mdToken tkResolutionScope = mdTokenNil;
9308 pInternalImport->GetResolutionScopeOfTypeRef(tk, &tkResolutionScope);
9310 #ifdef FEATURE_COMINTEROP
9311 // WinRT first party files are authored with TypeRefs pointing to TypeDefs in the same module.
9312 // This causes us to load types we do not want to NGen such as custom attributes. We will not
9313 // expand any module local TypeRefs for WinMDs to prevent this.
9314 if(TypeFromToken(tkResolutionScope)==mdtModule && IsAfContentType_WindowsRuntime(assemblyFlags))
9316 #endif // FEATURE_COMINTEROP
9317 TypeHandle t = LoadTypeDefOrRefHelper(image, this, tk);
9319 if (t.IsNull()) // Skip this type
9322 #ifdef FEATURE_COMINTEROP
9323 if (!g_fNGenWinMDResilient && TypeFromToken(tkResolutionScope) == mdtAssemblyRef)
9325 DWORD dwAssemblyRefFlags;
9326 IfFailThrow(pInternalImport->GetAssemblyRefProps(tkResolutionScope, NULL, NULL, NULL, NULL, NULL, NULL, &dwAssemblyRefFlags));
9328 if (IsAfContentType_WindowsRuntime(dwAssemblyRefFlags))
9330 Assembly *pAssembly = t.GetAssembly();
9331 PEAssembly *pPEAssembly = pAssembly->GetManifestFile();
9332 AssemblySpec refSpec;
9333 refSpec.InitializeSpec(tkResolutionScope, pInternalImport);
9334 LPCSTR psznamespace;
9336 pInternalImport->GetNameOfTypeRef(tk, &psznamespace, &pszname);
9337 refSpec.SetWindowsRuntimeType(psznamespace, pszname);
9338 GetAppDomain()->ToCompilationDomain()->AddDependency(&refSpec,pPEAssembly);
9341 #endif // FEATURE_COMINTEROP
9346 // Load all type specs
9350 HENUMInternalHolder hEnum(pInternalImport);
9351 hEnum.EnumAllInit(mdtTypeSpec);
9353 while (pInternalImport->EnumNext(&hEnum, &tk))
9356 PCCOR_SIGNATURE pSig;
9358 IfFailThrow(pInternalImport->GetTypeSpecFromToken(tk, &pSig, &cSig));
9360 // Load all types specs that do not contain variables
9361 if (SigPointer(pSig, cSig).IsPolyType(NULL) == hasNoVars)
9363 LoadTypeSpecHelper(image, this, tk, pSig, cSig);
9369 // Load all the reported parameterized types and methods
9371 CORBBTPROF_BLOB_ENTRY *pBlobEntry = GetProfileData()->GetBlobStream();
9373 if (pBlobEntry != NULL)
9375 while (pBlobEntry->TypeIsValid())
9377 if (TypeFromToken(pBlobEntry->token) == ibcTypeSpec)
9379 _ASSERTE(pBlobEntry->type == ParamTypeSpec);
9380 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY *) pBlobEntry;
9382 TypeHandle th = LoadIBCTypeHelper(pBlobSigEntry);
9385 image->GetPreloader()->TriageTypeForZap(th, TRUE);
9388 else if (TypeFromToken(pBlobEntry->token) == ibcMethodSpec)
9390 _ASSERTE(pBlobEntry->type == ParamMethodSpec);
9391 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY *) pBlobEntry;
9393 MethodDesc *pMD = LoadIBCMethodHelper(pBlobSigEntry);
9396 image->GetPreloader()->TriageMethodForZap(pMD, TRUE);
9399 pBlobEntry = pBlobEntry->GetNextEntry();
9401 _ASSERTE(pBlobEntry->type == EndOfBlobStream);
9406 // Fill out MemberRef RID map and va sig cookies for
9407 // varargs member refs.
9410 HENUMInternalHolder hEnum(pInternalImport);
9411 hEnum.EnumAllInit(mdtMemberRef);
9413 while (pInternalImport->EnumNext(&hEnum, &tk))
9416 IfFailThrow(pInternalImport->GetParentOfMemberRef(tk, &parent));
9418 #ifdef FEATURE_COMINTEROP
9419 if (IsAfContentType_WindowsRuntime(assemblyFlags) && TypeFromToken(parent) == mdtTypeRef)
9421 mdToken tkResolutionScope = mdTokenNil;
9422 pInternalImport->GetResolutionScopeOfTypeRef(parent, &tkResolutionScope);
9423 // WinRT first party files are authored with TypeRefs pointing to TypeDefs in the same module.
9424 // This causes us to load types we do not want to NGen such as custom attributes. We will not
9425 // expand any module local TypeRefs for WinMDs to prevent this.
9426 if(TypeFromToken(tkResolutionScope)==mdtModule)
9429 LPCSTR szNameSpace = NULL;
9430 LPCSTR szName = NULL;
9431 if (SUCCEEDED(pInternalImport->GetNameOfTypeRef(parent, &szNameSpace, &szName)))
9433 if (WinMDAdapter::ConvertWellKnownTypeNameFromClrToWinRT(&szNameSpace, &szName))
9436 // This is a MemberRef from a redirected WinRT type
9437 // We should skip it as managed view will never see this MemberRef anyway
9438 // Not skipping this will result MissingMethodExceptions as members in redirected
9439 // types doesn't exactly match their redirected CLR type counter part
9441 // Typically we only need to do this for interfaces as we should never see MemberRef
9442 // from non-interfaces, but here to keep things simple I'm skipping every memberref that
9443 // belongs to redirected WinRT type
9450 #endif // FEATURE_COMINTEROP
9452 // If the MethodRef has a TypeSpec as a parent (i.e. refers to a method on an array type
9453 // or on a generic class), then it could in turn refer to type variables of
9454 // an unknown class/method. So we don't preresolve any MemberRefs which have TypeSpecs as
9455 // parents. The RID maps are not filled out for such tokens anyway.
9456 if (TypeFromToken(parent) != mdtTypeSpec)
9458 GetDescFromMemberRefHelper(image, this, tk);
9467 if (m_pBinder != NULL)
9469 m_pBinder->BindAll();
9472 } // Module::ExpandAll
9475 void Module::SaveMethodTable(DataImage * image,
9477 DWORD profilingFlags)
9479 STANDARD_VM_CONTRACT;
9481 if (image->IsStored(pMT))
9484 pMT->Save(image, profilingFlags);
9489 void Module::SaveTypeHandle(DataImage * image,
9491 DWORD profilingFlags)
9493 STANDARD_VM_CONTRACT;
9498 TypeDesc *pTD = t.AsTypeDesc();
9499 if (!image->IsStored(pTD))
9506 MethodTable *pMT = t.AsMethodTable();
9507 if (pMT != NULL && !image->IsStored(pMT))
9509 SaveMethodTable(image, pMT, profilingFlags);
9510 _ASSERTE(image->IsStored(pMT));
9514 if (LoggingOn(LF_JIT, LL_INFO100))
9516 Module *pPrefModule = Module::GetPreferredZapModuleForTypeHandle(t);
9517 if (image->GetModule() != pPrefModule)
9519 StackSString typeName;
9521 TypeString::AppendTypeDebug(typeName, t);
9522 LOG((LF_ZAP, LL_INFO100, "The type %S was saved outside its preferred module %S\n", typeName.GetUnicode(), pPrefModule->GetPath().GetUnicode()));
9528 void ModuleCtorInfo::Save(DataImage *image, CorProfileData *profileData)
9530 STANDARD_VM_CONTRACT;
9536 DWORD totalBoxedStatics = 0;
9538 // sort the tables so that
9539 // - the hot ppMT entries are at the beginning of the ppMT table
9540 // - the hot cctor entries are at the beginning of the cctorInfoHot table
9541 // - the cold cctor entries are at the end, and we make cctorInfoCold point
9542 // the first cold entry
9544 // the invariant in this loop is:
9545 // items 0...numElementsHot-1 are hot
9546 // items numElementsHot...i-1 are cold
9547 for (i = 0; i < numElements; i++)
9549 MethodTable *ppMTTemp = ppMT[i];
9551 // Count the number of boxed statics along the way
9552 totalBoxedStatics += ppMTTemp->GetNumBoxedRegularStatics();
9554 bool hot = true; // if there's no profiling data, assume the entries are all hot.
9555 if (profileData->GetTokenFlagsData(TypeProfilingData))
9557 if ((profileData->GetTypeProfilingFlagsOfToken(ppMTTemp->GetCl()) & (1 << ReadCCtorInfo)) == 0)
9562 // swap ppMT[i] and ppMT[numElementsHot] to maintain the loop invariant
9563 ppMT[i] = ppMT[numElementsHot];
9564 ppMT[numElementsHot] = ppMTTemp;
9570 numHotHashes = numElementsHot ? RoundUpToPower2((numElementsHot * sizeof(PTR_MethodTable)) / CACHE_LINE_SIZE) : 0;
9571 numColdHashes = (numElements - numElementsHot) ? RoundUpToPower2(((numElements - numElementsHot) *
9572 sizeof(PTR_MethodTable)) / CACHE_LINE_SIZE) : 0;
9574 LOG((LF_ZAP, LL_INFO10, "ModuleCtorInfo::numHotHashes: 0x%4x\n", numHotHashes));
9575 if (numColdHashes != 0)
9577 LOG((LF_ZAP, LL_INFO10, "ModuleCtorInfo::numColdHashes: 0x%4x\n", numColdHashes));
9580 // The "plus one" is so we can store the offset to the end of the array at the end of
9581 // the hashoffsets arrays, enabling faster lookups.
9582 hotHashOffsets = new DWORD[numHotHashes + 1];
9583 coldHashOffsets = new DWORD[numColdHashes + 1];
9585 DWORD *hashArray = new DWORD[numElements];
9587 for (i = 0; i < numElementsHot; i++)
9589 hashArray[i] = GenerateHash(ppMT[i], HOT);
9591 for (i = numElementsHot; i < numElements; i++)
9593 hashArray[i] = GenerateHash(ppMT[i], COLD);
9596 // Sort the two arrays by hash values to create regions with the same hash values.
9597 ClassCtorInfoEntryArraySort cctorInfoHotSort(hashArray, ppMT, numElementsHot);
9598 ClassCtorInfoEntryArraySort cctorInfoColdSort(hashArray + numElementsHot, ppMT + numElementsHot,
9599 numElements - numElementsHot);
9600 cctorInfoHotSort.Sort();
9601 cctorInfoColdSort.Sort();
9603 // Generate the indices that index into the correct "hash region" in the hot part of the ppMT array, and store
9604 // them in the hotHashOffests arrays.
9607 while (i < numElementsHot)
9609 if (curHash < hashArray[i])
9611 hotHashOffsets[curHash++] = i;
9613 else if (curHash == hashArray[i])
9615 hotHashOffsets[curHash++] = i++;
9622 while (curHash <= numHotHashes)
9624 hotHashOffsets[curHash++] = numElementsHot;
9627 // Generate the indices that index into the correct "hash region" in the hot part of the ppMT array, and store
9628 // them in the coldHashOffsets arrays.
9631 while (i < numElements)
9633 if (curHash < hashArray[i])
9635 coldHashOffsets[curHash++] = i;
9637 else if (curHash == hashArray[i])
9639 coldHashOffsets[curHash++] = i++;
9643 while (curHash <= numColdHashes)
9645 coldHashOffsets[curHash++] = numElements;
9651 cctorInfoHot = new ClassCtorInfoEntry[numElements];
9653 // make cctorInfoCold point to the first cold element
9654 cctorInfoCold = cctorInfoHot + numElementsHot;
9656 ppHotGCStaticsMTs = (totalBoxedStatics != 0) ? new FixupPointer<PTR_MethodTable>[totalBoxedStatics] : NULL;
9657 numHotGCStaticsMTs = totalBoxedStatics;
9659 DWORD iGCStaticMT = 0;
9661 for (i = 0; i < numElements; i++)
9663 if (numElements == numElementsHot)
9665 numHotGCStaticsMTs = iGCStaticMT;
9666 numColdGCStaticsMTs = (totalBoxedStatics - iGCStaticMT);
9668 // make ppColdGCStaticsMTs point to the first cold element
9669 ppColdGCStaticsMTs = ppHotGCStaticsMTs + numHotGCStaticsMTs;
9672 MethodTable* pMT = ppMT[i];
9673 ClassCtorInfoEntry* pEntry = &cctorInfoHot[i];
9675 WORD numBoxedStatics = pMT->GetNumBoxedRegularStatics();
9676 pEntry->numBoxedStatics = numBoxedStatics;
9677 pEntry->hasFixedAddressVTStatics = !!pMT->HasFixedAddressVTStatics();
9679 FieldDesc *pField = pMT->HasGenericsStaticsInfo() ?
9680 pMT->GetGenericsStaticFieldDescs() : (pMT->GetApproxFieldDescListRaw() + pMT->GetNumIntroducedInstanceFields());
9681 FieldDesc *pFieldEnd = pField + pMT->GetNumStaticFields();
9683 pEntry->firstBoxedStaticOffset = (DWORD)-1;
9684 pEntry->firstBoxedStaticMTIndex = (DWORD)-1;
9686 DWORD numFoundBoxedStatics = 0;
9687 while (pField < pFieldEnd)
9689 _ASSERTE(pField->IsStatic());
9691 if (!pField->IsSpecialStatic() && pField->IsByValue())
9693 if (pEntry->firstBoxedStaticOffset == (DWORD)-1)
9695 pEntry->firstBoxedStaticOffset = pField->GetOffset();
9696 pEntry->firstBoxedStaticMTIndex = iGCStaticMT;
9698 _ASSERTE(pField->GetOffset() - pEntry->firstBoxedStaticOffset
9699 == (iGCStaticMT - pEntry->firstBoxedStaticMTIndex) * sizeof(MethodTable*));
9701 TypeHandle th = pField->GetFieldTypeHandleThrowing();
9702 ppHotGCStaticsMTs[iGCStaticMT++].SetValue(th.GetMethodTable());
9704 numFoundBoxedStatics++;
9708 _ASSERTE(numBoxedStatics == numFoundBoxedStatics);
9710 _ASSERTE(iGCStaticMT == totalBoxedStatics);
9712 if (numElementsHot > 0)
9714 image->StoreStructure(cctorInfoHot,
9715 sizeof(ClassCtorInfoEntry) * numElementsHot,
9716 DataImage::ITEM_MODULE_CCTOR_INFO_HOT);
9718 image->StoreStructure(hotHashOffsets,
9719 sizeof(DWORD) * (numHotHashes + 1),
9720 DataImage::ITEM_MODULE_CCTOR_INFO_HOT);
9723 if (numElements > 0)
9724 image->StoreStructure(ppMT,
9725 sizeof(MethodTable *) * numElements,
9726 DataImage::ITEM_MODULE_CCTOR_INFO_HOT);
9728 if (numElements > numElementsHot)
9730 image->StoreStructure(cctorInfoCold,
9731 sizeof(ClassCtorInfoEntry) * (numElements - numElementsHot),
9732 DataImage::ITEM_MODULE_CCTOR_INFO_COLD);
9734 image->StoreStructure(coldHashOffsets,
9735 sizeof(DWORD) * (numColdHashes + 1),
9736 DataImage::ITEM_MODULE_CCTOR_INFO_COLD);
9739 if ( numHotGCStaticsMTs )
9741 // Save the mt templates
9742 image->StoreStructure( ppHotGCStaticsMTs, numHotGCStaticsMTs * sizeof(MethodTable*),
9743 DataImage::ITEM_GC_STATIC_HANDLES_HOT);
9747 ppHotGCStaticsMTs = NULL;
9750 if ( numColdGCStaticsMTs )
9752 // Save the hot mt templates
9753 image->StoreStructure( ppColdGCStaticsMTs, numColdGCStaticsMTs * sizeof(MethodTable*),
9754 DataImage::ITEM_GC_STATIC_HANDLES_COLD);
9758 ppColdGCStaticsMTs = NULL;
9762 #ifdef FEATURE_REMOTING
9763 static void IsCrossAppDomainOptimizableWrapper(MethodDesc * pMD,
9766 STANDARD_VM_CONTRACT;
9772 if (pMD->GetNumGenericMethodArgs() == 0 && !pMD->IsStatic())
9773 RemotableMethodInfo::IsCrossAppDomainOptimizable(pMD, pnumDwords);
9777 // If there is an exception, it'll mean the info for this method will remain uninitialized.
9778 // Just ignore the exception. At runtime, we'll try to initialize it
9779 // An exception is possible during ngen if all dependencies are not available
9781 EX_END_CATCH(SwallowAllExceptions)
9784 static void PrepareRemotableMethodInfo(MethodTable * pMT)
9786 STANDARD_VM_CONTRACT;
9788 if (!pMT->HasRemotableMethodInfo())
9791 MethodTable::MethodIterator it(pMT);
9792 for (; it.IsValid(); it.Next())
9794 DWORD numDwords = 0;
9795 IsCrossAppDomainOptimizableWrapper(it.GetMethodDesc(), &numDwords);
9798 #endif // FEATURE_REMOTING
9800 bool Module::AreAllClassesFullyLoaded()
9802 STANDARD_VM_CONTRACT;
9804 // Adjust for unused space
9805 IMDInternalImport *pImport = GetMDImport();
9807 HENUMInternalHolder hEnum(pImport);
9808 hEnum.EnumAllInit(mdtTypeDef);
9811 while (pImport->EnumNext(&hEnum, &token))
9813 _ASSERTE(TypeFromToken(token) == mdtTypeDef);
9815 // Special care has to been taken with COR_GLOBAL_PARENT_TOKEN, as the class
9816 // may not be needed, (but we have to distinguish between not needed and threw error).
9817 if (token == COR_GLOBAL_PARENT_TOKEN &&
9818 !NeedsGlobalMethodTable())
9820 // No EEClass for this token if there was no need for a global method table
9824 TypeHandle th = LookupTypeDef(token);
9828 if (!th.AsMethodTable()->IsFullyLoaded())
9835 void Module::PrepareTypesForSave(DataImage *image)
9837 STANDARD_VM_CONTRACT;
9843 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
9844 while (typeDefIter.Next())
9846 MethodTable * pMT = typeDefIter.GetElement();
9848 if (pMT == NULL || !pMT->IsFullyLoaded())
9851 #ifdef FEATURE_REMOTING
9852 PrepareRemotableMethodInfo(pMT);
9853 #endif // FEATURE_REMOTING
9856 // If this module defines any CriticalFinalizerObject derived classes,
9857 // then we'll prepare these types for Constrained Execution Regions (CER) now.
9858 // (Normally they're prepared at object instantiation time, a little too late for ngen).
9859 PrepareCriticalType(pMT);
9860 #endif // FEATURE_CER
9865 // Prepare typespecs
9868 // Create a local copy in case the new elements are added to the hashtable during population
9869 InlineSArray<TypeHandle, 20> pTypes;
9871 // Make sure the iterator is destroyed before there is a chance of loading new types
9873 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
9874 EETypeHashEntry *pEntry;
9875 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
9877 TypeHandle t = pEntry->GetTypeHandle();
9882 if (!image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(t.AsPtr())))
9889 #ifdef FEATURE_REMOTING
9890 for(COUNT_T i = 0; i < pTypes.GetCount(); i ++)
9892 MethodTable * pMT = pTypes[i].AsMethodTable();
9894 PrepareRemotableMethodInfo(pMT);
9896 // @todo: prepare critical instantiated types?
9898 #endif // FEATURE_REMOTING
9901 image->GetPreloader()->TriageForZap(FALSE, FALSE);
9904 static const char* const MethodTableRestoreReasonDescription[TotalMethodTables + 1] =
9906 #undef RESTORE_REASON_FUNC
9907 #define RESTORE_REASON_FUNC(s) #s,
9909 METHODTABLE_RESTORE_REASON()
9911 #undef RESTORE_REASON
9913 "TotalMethodTablesEvaluated"
9917 // MethodDescByMethodTableTraits could be a local class in Module::Save(), but g++ doesn't like
9918 // instantiating templates with private classes.
9919 class MethodDescByMethodTableTraits : public NoRemoveSHashTraits< DefaultSHashTraits<MethodDesc *> >
9922 typedef MethodTable * key_t;
9923 static MethodDesc * Null() { return NULL; }
9924 static bool IsNull(MethodDesc * pMD) { return pMD == NULL; }
9925 static MethodTable * GetKey(MethodDesc * pMD) { return pMD->GetMethodTable_NoLogging(); }
9926 static count_t Hash(MethodTable * pMT) { LIMITED_METHOD_CONTRACT; return (count_t) (UINT_PTR) pMT->GetTypeDefRid_NoLogging(); }
9927 static BOOL Equals(MethodTable * pMT1, MethodTable * pMT2)
9929 return pMT1 == pMT2;
9933 void Module::Save(DataImage *image)
9935 STANDARD_VM_CONTRACT;
9937 // Precompute type specific auxiliary information saved into NGen image
9938 // Note that this operation can load new types.
9939 PrepareTypesForSave(image);
9941 // Cache values of all persisted flags computed from custom attributes
9942 IsNoStringInterning();
9943 IsRuntimeWrapExceptions();
9945 GetReliabilityContract();
9949 HasDefaultDllImportSearchPathsAttribute();
9951 // Precompute property information to avoid runtime metadata lookup
9952 PopulatePropertyInfoMap();
9954 // Any any elements and compute values of any LookupMap flags that were not available previously
9955 FinalizeLookupMapsPreSave(image);
9961 ZapStoredStructure * pModuleNode = image->StoreStructure(this, sizeof(Module),
9962 DataImage::ITEM_MODULE);
9964 m_pNGenLayoutInfo = (NGenLayoutInfo *)(void *)image->GetModule()->GetLoaderAllocator()->
9965 GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(NGenLayoutInfo)));
9966 image->StoreStructure(m_pNGenLayoutInfo, sizeof(NGenLayoutInfo), DataImage::ITEM_BINDER_ITEMS);
9969 // If we are NGening, we don't need to keep a list of va
9970 // sig cookies, as we already have a complete set (of course we do
9971 // have to persist the cookies themselves, though.
9975 // Initialize maps of child data structures. Note that each tables's blocks are
9976 // concantentated to a single block in the process.
9978 CorProfileData * profileData = GetProfileData();
9980 // ngen the neutral resources culture
9981 if(GetNeutralResourcesLanguage(&m_pszCultureName, &m_CultureNameLength, &m_FallbackLocation, TRUE)) {
9982 image->StoreStructure((void *) m_pszCultureName,
9983 (ULONG)(m_CultureNameLength + 1),
9984 DataImage::ITEM_BINDER_ITEMS,
9989 m_TypeRefToMethodTableMap.Save(image, DataImage::ITEM_TYPEREF_MAP, profileData, mdtTypeRef);
9990 image->BindPointer(&m_TypeRefToMethodTableMap, pModuleNode, offsetof(Module, m_TypeRefToMethodTableMap));
9992 if(m_pMemberRefToDescHashTable)
9993 m_pMemberRefToDescHashTable->Save(image, profileData);
9995 m_TypeDefToMethodTableMap.Save(image, DataImage::ITEM_TYPEDEF_MAP, profileData, mdtTypeDef);
9996 image->BindPointer(&m_TypeDefToMethodTableMap, pModuleNode, offsetof(Module, m_TypeDefToMethodTableMap));
9998 m_MethodDefToDescMap.Save(image, DataImage::ITEM_METHODDEF_MAP, profileData, mdtMethodDef);
9999 image->BindPointer(&m_MethodDefToDescMap, pModuleNode, offsetof(Module, m_MethodDefToDescMap));
10001 m_FieldDefToDescMap.Save(image, DataImage::ITEM_FIELDDEF_MAP, profileData, mdtFieldDef);
10002 image->BindPointer(&m_FieldDefToDescMap, pModuleNode, offsetof(Module, m_FieldDefToDescMap));
10004 m_GenericParamToDescMap.Save(image, DataImage::ITEM_GENERICPARAM_MAP, profileData, mdtGenericParam);
10005 image->BindPointer(&m_GenericParamToDescMap, pModuleNode, offsetof(Module, m_GenericParamToDescMap));
10007 m_GenericTypeDefToCanonMethodTableMap.Save(image, DataImage::ITEM_GENERICTYPEDEF_MAP, profileData, mdtTypeDef);
10008 image->BindPointer(&m_GenericTypeDefToCanonMethodTableMap, pModuleNode, offsetof(Module, m_GenericTypeDefToCanonMethodTableMap));
10010 if (m_pAvailableClasses)
10011 m_pAvailableClasses->Save(image, profileData);
10014 // Also save the parent maps; the contents will
10015 // need to be rewritten, but we can allocate the
10016 // space in the image.
10019 // these items have no hot list and no attribution
10020 m_FileReferencesMap.Save(image, DataImage::ITEM_FILEREF_MAP, profileData, 0);
10021 image->BindPointer(&m_FileReferencesMap, pModuleNode, offsetof(Module, m_FileReferencesMap));
10023 m_ManifestModuleReferencesMap.Save(image, DataImage::ITEM_ASSEMREF_MAP, profileData, 0);
10024 image->BindPointer(&m_ManifestModuleReferencesMap, pModuleNode, offsetof(Module, m_ManifestModuleReferencesMap));
10026 m_MethodDefToPropertyInfoMap.Save(image, DataImage::ITEM_PROPERTYINFO_MAP, profileData, 0, TRUE /*fCopyValues*/);
10027 image->BindPointer(&m_MethodDefToPropertyInfoMap, pModuleNode, offsetof(Module, m_MethodDefToPropertyInfoMap));
10029 if (m_pBinder != NULL)
10030 m_pBinder->Save(image);
10036 // Saving hot things first is a very good thing, because we place items
10037 // in the order they are saved and things that have hot items are also
10038 // more likely to have their other structures touched, hence these should
10039 // also be placed together, at least if we don't have any further information to go on.
10040 // Note we place particular hot items with more care in the Arrange phase.
10042 CORBBTPROF_TOKEN_INFO * pTypeProfilingData = profileData->GetTokenFlagsData(TypeProfilingData);
10043 DWORD cTypeProfilingData = profileData->GetTokenFlagsCount(TypeProfilingData);
10045 for (unsigned int i = 0; i < cTypeProfilingData; i++)
10047 CORBBTPROF_TOKEN_INFO *entry = &pTypeProfilingData[i];
10048 mdToken token = entry->token;
10049 DWORD flags = entry->flags;
10050 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
10051 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_4);
10054 if ((flags & (1 << ReadMethodTable)) == 0)
10057 if (TypeFromToken(token) == mdtTypeDef)
10059 MethodTable *pMT = LookupTypeDef(token).GetMethodTable();
10060 if (pMT && pMT->IsFullyLoaded())
10062 SaveMethodTable(image, pMT, flags);
10065 else if (TypeFromToken(token) == ibcTypeSpec)
10067 CORBBTPROF_BLOB_ENTRY *pBlobEntry = profileData->GetBlobStream();
10070 while (pBlobEntry->TypeIsValid())
10072 if (TypeFromToken(pBlobEntry->token) == ibcTypeSpec)
10074 _ASSERTE(pBlobEntry->type == ParamTypeSpec);
10076 if (pBlobEntry->token == token)
10078 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY *) pBlobEntry;
10079 TypeHandle th = LoadIBCTypeHelper(pBlobSigEntry);
10083 // When we have stale IBC data the type could have been rejected from this image.
10084 if (image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(th.AsPtr())))
10086 SaveTypeHandle(image, th, flags);
10091 pBlobEntry = pBlobEntry->GetNextEntry();
10093 _ASSERTE(pBlobEntry->type == EndOfBlobStream);
10098 if (m_pAvailableParamTypes != NULL)
10100 // If we have V1 IBC data then we save the hot
10101 // out-of-module generic instantiations here
10103 CORBBTPROF_TOKEN_INFO * tokens_begin = profileData->GetTokenFlagsData(GenericTypeProfilingData);
10104 CORBBTPROF_TOKEN_INFO * tokens_end = tokens_begin + profileData->GetTokenFlagsCount(GenericTypeProfilingData);
10106 if (tokens_begin != tokens_end)
10108 SArray<CORBBTPROF_TOKEN_INFO> tokens(tokens_begin, tokens_end);
10109 tokens_begin = &tokens[0];
10110 tokens_end = tokens_begin + tokens.GetCount();
10112 util::sort(tokens_begin, tokens_end);
10114 // enumerate AvailableParamTypes map and find all hot generic instantiations
10115 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
10116 EETypeHashEntry *pEntry;
10117 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
10119 TypeHandle t = pEntry->GetTypeHandle();
10120 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
10121 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_5);
10124 if (t.HasInstantiation())
10127 t.GetName(tokenName);
10128 unsigned cur_token = tokenName.Hash() & 0xffff;
10130 CORBBTPROF_TOKEN_INFO * found = util::lower_bound(tokens_begin, tokens_end, CORBBTPROF_TOKEN_INFO(cur_token));
10131 if (found != tokens_end && found->token == cur_token && (found->flags & (1 << ReadMethodTable)))
10133 // When we have stale IBC data the type could have been rejected from this image.
10134 if (image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(t.AsPtr())))
10135 SaveTypeHandle(image, t, found->flags);
10144 // Now save any types in the TypeDefToMethodTableMap map
10147 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
10149 while (typeDefIter.Next())
10151 MethodTable * pMT = typeDefIter.GetElement();
10154 !image->IsStored(pMT) && pMT->IsFullyLoaded())
10156 image->BeginAssociatingStoredObjectsWithMethodTable(pMT);
10157 SaveMethodTable(image, pMT, 0);
10158 image->EndAssociatingStoredObjectsWithMethodTable();
10164 // Now save any TypeDescs in m_GenericParamToDescMap map
10167 LookupMap<PTR_TypeVarTypeDesc>::Iterator genericParamIter(&m_GenericParamToDescMap);
10169 while (genericParamIter.Next())
10171 TypeVarTypeDesc *pTD = genericParamIter.GetElement();
10181 SealGenericTypesAndMethods();
10185 // Now save any types in the AvailableParamTypes map
10187 if (m_pAvailableParamTypes != NULL)
10189 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
10190 EETypeHashEntry *pEntry;
10191 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
10193 TypeHandle t = pEntry->GetTypeHandle();
10195 if (image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(t.AsPtr())))
10197 if (t.GetCanonicalMethodTable() != NULL)
10199 image->BeginAssociatingStoredObjectsWithMethodTable(t.GetCanonicalMethodTable());
10200 SaveTypeHandle(image, t, 0);
10201 image->EndAssociatingStoredObjectsWithMethodTable();
10205 SaveTypeHandle(image, t, 0);
10212 // Now save any methods in the InstMethodHashTable
10214 if (m_pInstMethodHashTable != NULL)
10217 // Find all MethodDescs that we are going to save, and hash them with MethodTable as the key
10220 typedef SHash<MethodDescByMethodTableTraits> MethodDescByMethodTableHash;
10222 MethodDescByMethodTableHash methodDescs;
10224 InstMethodHashTable::Iterator it(m_pInstMethodHashTable);
10225 InstMethodHashEntry *pEntry;
10226 while (m_pInstMethodHashTable->FindNext(&it, &pEntry))
10228 MethodDesc *pMD = pEntry->GetMethod();
10230 _ASSERTE(!pMD->IsTightlyBoundToMethodTable());
10232 if (!image->IsStored(pMD) &&
10233 image->GetPreloader()->IsMethodInTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE(pMD)))
10235 methodDescs.Add(pMD);
10240 // Save all MethodDescs on the same MethodTable using one chunk builder
10243 for (MethodDescByMethodTableHash::Iterator i1 = methodDescs.Begin(), end1 = methodDescs.End(); i1 != end1; i1++)
10245 MethodDesc * pMD = *(i1);
10246 if (image->IsStored(pMD))
10249 MethodTable * pMT = pMD->GetMethodTable();
10251 MethodDesc::SaveChunk methodDescSaveChunk(image);
10253 for (MethodDescByMethodTableHash::KeyIterator i2 = methodDescs.Begin(pMT), end2 = methodDescs.End(pMT); i2 != end2; i2++)
10255 _ASSERTE(!image->IsStored(*i2));
10256 methodDescSaveChunk.Append(*i2);
10259 methodDescSaveChunk.Save();
10263 // Now save the tables themselves
10264 if (m_pAvailableParamTypes != NULL)
10266 m_pAvailableParamTypes->Save(image, this, profileData);
10269 if (m_pInstMethodHashTable != NULL)
10271 m_pInstMethodHashTable->Save(image, profileData);
10275 MethodTable * pStubMT = GetILStubCache()->GetStubMethodTable();
10276 if (pStubMT != NULL)
10278 SaveMethodTable(image, pStubMT, 0);
10282 if (m_pStubMethodHashTable != NULL)
10284 m_pStubMethodHashTable->Save(image, profileData);
10287 #ifdef FEATURE_COMINTEROP
10288 // the type saving operations above had the side effect of populating m_pGuidToTypeHash
10289 if (m_pGuidToTypeHash != NULL)
10291 m_pGuidToTypeHash->Save(image, profileData);
10293 #endif // FEATURE_COMINTEROP
10295 // Compute and save the property name set
10296 PrecomputeMatchingProperties(image);
10297 image->StoreStructure(m_propertyNameSet,
10298 m_nPropertyNameSet * sizeof(BYTE),
10299 DataImage::ITEM_PROPERTY_NAME_SET);
10302 // Save Constrained Execution Region (CER) fixup information (used to eagerly fixup trees of methods to avoid any runtime
10303 // induced failures when invoking the tree).
10304 if (m_pCerNgenRootTable != NULL)
10305 m_pCerNgenRootTable->Save(image, profileData);
10308 // Sort the list of RVA statics in an ascending order wrt the RVA
10310 image->SaveRvaStructure();
10312 // Save static data
10313 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Saving module static data\n"));
10315 // We have this scenario where ngen will fail to load some classes but will generate
10316 // a valid exe, or it will choose not to save some loaded classes due to some error
10317 // conditions, where statics will be committed at runtime for the classes that ngen
10318 // wasn't able to load or save. So we can't cut down the static block size blindly if we've
10319 // failed to load or save any class. We don't think this scenario deserves complicated code
10320 // paths to get the extra working set perf (you would be pulling in the jitter if
10321 // you need any of these classes), So we are basically simplifying this down, if we failed
10322 // to load or save any class we won't compress the statics block and will persist the original
10325 // All classes were loaded and saved, cut down the block
10326 if (AreAllClassesFullyLoaded())
10328 // Set a mark indicating we had all our classes loaded
10329 m_pRegularStaticOffsets = (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED;
10330 m_pThreadStaticOffsets = (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED;
10334 // Since not all of the classes loaded we want to zero the pointers to the offset tables so they'll be
10335 // recalculated at runtime. But we can't do that here since we might try to reload some of the failed
10336 // types during the arrange phase (as the result of trying to parse profiling data). So we'll defer
10337 // zero'ing anything until the fixup phase.
10339 // Not all classes were stored, revert to uncompressed maps to support run-time changes
10340 m_TypeDefToMethodTableMap.ConvertSavedMapToUncompressed(image, DataImage::ITEM_TYPEDEF_MAP);
10341 m_MethodDefToDescMap.ConvertSavedMapToUncompressed(image, DataImage::ITEM_METHODDEF_MAP);
10344 m_ModuleCtorInfo.Save(image, profileData);
10345 image->BindPointer(&m_ModuleCtorInfo, pModuleNode, offsetof(Module, m_ModuleCtorInfo));
10347 if (m_pDynamicStaticsInfo)
10349 image->StoreStructure(m_pDynamicStaticsInfo, m_maxDynamicEntries*sizeof(DynamicStaticsInfo),
10350 DataImage::ITEM_DYNAMIC_STATICS_INFO_TABLE);
10353 // save the module security descriptor
10354 if (m_pModuleSecurityDescriptor)
10356 m_pModuleSecurityDescriptor->Save(image);
10359 InlineTrackingMap *inlineTrackingMap = image->GetInlineTrackingMap();
10360 if (inlineTrackingMap)
10362 m_persistentInlineTrackingMap = new (image->GetHeap()) PersistentInlineTrackingMap(this);
10363 m_persistentInlineTrackingMap->Save(image, inlineTrackingMap);
10366 if (m_pNgenStats && g_CorCompileVerboseLevel >= CORCOMPILE_STATS)
10368 GetSvcLogger()->Printf ("%-35s: %s\n", "MethodTable Restore Reason", "Count");
10370 for (int i=0; i<TotalMethodTables; i++)
10372 GetSvcLogger()->Printf ("%-35s: %d\n", MethodTableRestoreReasonDescription[i], m_pNgenStats->MethodTableRestoreNumReasons[i]);
10373 dwTotal += m_pNgenStats->MethodTableRestoreNumReasons[i];
10375 GetSvcLogger()->Printf ("%-35s: %d\n", "TotalMethodTablesNeedRestore", dwTotal);
10376 GetSvcLogger()->Printf ("%-35s: %d\n", MethodTableRestoreReasonDescription[TotalMethodTables], m_pNgenStats->MethodTableRestoreNumReasons[TotalMethodTables]);
10383 // We call these methods to seal the
10384 // lists: m_pAvailableClasses and m_pAvailableParamTypes
10386 void Module::SealGenericTypesAndMethods()
10388 LIMITED_METHOD_CONTRACT;
10389 // Enforce that after this point in ngen that no more types or methods will be loaded.
10391 // We increment the seal count here and only decrement it after we have completed the ngen image
10393 if (m_pAvailableParamTypes != NULL)
10395 m_pAvailableParamTypes->Seal();
10397 if (m_pInstMethodHashTable != NULL)
10399 m_pInstMethodHashTable->Seal();
10403 // We call these methods to unseal the
10404 // lists: m_pAvailableClasses and m_pAvailableParamTypes
10406 void Module::UnsealGenericTypesAndMethods()
10408 LIMITED_METHOD_CONTRACT;
10409 // Allow us to create generic types and methods again
10411 // We only decrement it after we have completed the ngen image
10413 if (m_pAvailableParamTypes != NULL)
10415 m_pAvailableParamTypes->Unseal();
10417 if (m_pInstMethodHashTable != NULL)
10419 m_pInstMethodHashTable->Unseal();
10425 void Module::PrepopulateDictionaries(DataImage *image, BOOL nonExpansive)
10427 STANDARD_VM_CONTRACT;
10429 // Prepopulating the dictionaries for instantiated types
10430 // is in theory an iteraive process, i.e. filling in
10431 // a dictionary slot may result in a class load of a new type whose
10432 // dictionary may itself need to be prepopulated. The type expressions
10433 // involved can get larger, so there's no a-priori reason to expect this
10434 // process to terminate.
10436 // Given a starting set of instantiated types, several strategies are
10437 // thus possible - no prepopulation (call this PP0), or
10438 // prepopulate only the dictionaries of the types that are in the initial
10439 // set (call this PP1), or do two iterations (call this PP2) etc. etc.
10440 // Whichever strategy we choose we can always afford to do
10441 // one round of prepopulation where we populate slots
10442 // whose corresponding resulting method/types are already loaded.
10443 // Call this PPn+PP-FINAL.
10445 // Below we implement PP1+PP-FINAL for instantiated types and PP0+PP-FINAL
10446 // for instantiations of generic methods. We use PP1 because most collection
10447 // classes (List, Dictionary etc.) only require one pass of prepopulation in order
10448 // to fully prepopulate the dictionary.
10450 // Do PP1 for instantiated types... Do one iteration where we force type loading...
10451 // Because this phase may cause new entries to appear in the hash table we
10452 // copy the array of types to the stack before we do anything else.
10453 if (!nonExpansive && CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Prepopulate1))
10455 if (m_pAvailableParamTypes != NULL)
10457 // Create a local copy in case the new elements are added to the hashtable during population
10458 InlineSArray<TypeHandle, 20> pTypes;
10460 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
10461 EETypeHashEntry *pEntry;
10462 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
10464 TypeHandle th = pEntry->GetTypeHandle();
10465 if (th.IsTypeDesc())
10468 // Don't do prepopulation for open types - they shouldn't really have dictionaries anyway.
10469 MethodTable * pMT = th.AsMethodTable();
10470 if (pMT->ContainsGenericVariables())
10473 // Only do PP1 on things that land in their preferred Zap module.
10474 // Forcing the load of dictionary entries in the case where we are
10475 // speculatively saving a copy of an instantiation outside its preferred
10476 // zap module is too expensive for the common collection class cases.
10478 // Invalid generic instantiations will not be fully loaded.
10479 // We want to ignore them as touching them will re-raise the TypeLoadException
10480 if (pMT->IsFullyLoaded() && image->GetModule() == GetPreferredZapModuleForMethodTable(pMT))
10487 for(COUNT_T i = 0; i < pTypes.GetCount(); i ++)
10489 TypeHandle th = pTypes[i];
10490 _ASSERTE(image->GetModule() == GetPreferredZapModuleForTypeHandle(th) );
10491 _ASSERTE(!th.IsTypeDesc() && !th.ContainsGenericVariables());
10492 th.AsMethodTable()->PrepopulateDictionary(image, FALSE /* not nonExpansive, i.e. can load types */);
10497 // PP-FINAL for instantiated types.
10498 // This is the final stage where we hardbind any remaining entries that map
10499 // to results that have already been loaded...
10500 // Thus we set the "nonExpansive" flag on PrepopulateDictionary
10501 // below, which may in turn greatly limit the amount of prepopulating we do
10502 // (partly because it's quite difficult to determine if some potential entries
10503 // in the dictionary are already loaded)
10505 if (m_pAvailableParamTypes != NULL)
10507 INDEBUG(DWORD nTypes = m_pAvailableParamTypes->GetCount());
10509 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
10510 EETypeHashEntry *pEntry;
10511 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
10513 TypeHandle th = pEntry->GetTypeHandle();
10514 if (th.IsTypeDesc())
10517 MethodTable * pMT = th.AsMethodTable();
10518 if (pMT->ContainsGenericVariables())
10521 pMT->PrepopulateDictionary(image, TRUE /* nonExpansive */);
10524 // No new instantiations should be added by nonExpansive prepopulation
10525 _ASSERTE(nTypes == m_pAvailableParamTypes->GetCount());
10528 // PP-FINAL for instantiations of generic methods.
10529 if (m_pInstMethodHashTable != NULL)
10531 INDEBUG(DWORD nMethods = m_pInstMethodHashTable->GetCount());
10533 InstMethodHashTable::Iterator it(m_pInstMethodHashTable);
10534 InstMethodHashEntry *pEntry;
10535 while (m_pInstMethodHashTable->FindNext(&it, &pEntry))
10537 MethodDesc *pMD = pEntry->GetMethod();
10538 if (!pMD->ContainsGenericVariables())
10540 pMD->PrepopulateDictionary(image, TRUE /* nonExpansive */);
10544 // No new instantiations should be added by nonExpansive prepopulation
10545 _ASSERTE(nMethods == m_pInstMethodHashTable->GetCount());
10549 void Module::PlaceType(DataImage *image, TypeHandle th, DWORD profilingFlags)
10551 STANDARD_VM_CONTRACT;
10556 MethodTable *pMT = th.GetMethodTable();
10558 if (pMT && pMT->GetLoaderModule() == this)
10560 EEClass *pClass = pMT->GetClass();
10562 if (profilingFlags & (1 << WriteMethodTableWriteableData))
10564 image->PlaceStructureForAddress(pMT->GetWriteableData(),CORCOMPILE_SECTION_WRITE);
10567 if (profilingFlags & (1 << ReadMethodTable))
10569 CorCompileSection section = CORCOMPILE_SECTION_READONLY_HOT;
10570 if (pMT->IsWriteable())
10571 section = CORCOMPILE_SECTION_HOT_WRITEABLE;
10572 image->PlaceStructureForAddress(pMT, section);
10574 if (pMT->HasInterfaceMap())
10575 image->PlaceInternedStructureForAddress(pMT->GetInterfaceMap(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
10577 MethodTable::VtableIndirectionSlotIterator it = pMT->IterateVtableIndirectionSlots();
10580 image->PlaceInternedStructureForAddress(it.GetIndirectionSlot(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
10583 image->PlaceStructureForAddress(pMT->GetWriteableData(), CORCOMPILE_SECTION_HOT);
10586 if (profilingFlags & (1 << ReadNonVirtualSlots))
10588 if (pMT->HasNonVirtualSlotsArray())
10589 image->PlaceStructureForAddress(pMT->GetNonVirtualSlotsArray(), CORCOMPILE_SECTION_READONLY_HOT);
10592 if (profilingFlags & (1 << ReadDispatchMap) && pMT->HasDispatchMapSlot())
10594 image->PlaceInternedStructureForAddress(pMT->GetDispatchMap(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
10597 if (profilingFlags & (1 << WriteEEClass))
10599 image->PlaceStructureForAddress(pClass, CORCOMPILE_SECTION_WRITE);
10601 if (pClass->HasOptionalFields())
10602 image->PlaceStructureForAddress(pClass->GetOptionalFields(), CORCOMPILE_SECTION_WRITE);
10605 else if (profilingFlags & (1 << ReadEEClass))
10607 image->PlaceStructureForAddress(pClass, CORCOMPILE_SECTION_HOT);
10609 if (pClass->HasOptionalFields())
10610 image->PlaceStructureForAddress(pClass->GetOptionalFields(), CORCOMPILE_SECTION_HOT);
10612 if (pClass->GetVarianceInfo() != NULL)
10613 image->PlaceInternedStructureForAddress(pClass->GetVarianceInfo(), CORCOMPILE_SECTION_READONLY_WARM, CORCOMPILE_SECTION_READONLY_WARM);
10615 #ifdef FEATURE_COMINTEROP
10616 if (pClass->GetSparseCOMInteropVTableMap() != NULL)
10618 image->PlaceStructureForAddress(pClass->GetSparseCOMInteropVTableMap(), CORCOMPILE_SECTION_WARM);
10619 image->PlaceInternedStructureForAddress(pClass->GetSparseCOMInteropVTableMap()->GetMapList(), CORCOMPILE_SECTION_READONLY_WARM, CORCOMPILE_SECTION_READONLY_WARM);
10624 if (profilingFlags & (1 << ReadFieldDescs))
10626 image->PlaceStructureForAddress(pMT->GetApproxFieldDescListRaw(), CORCOMPILE_SECTION_READONLY_HOT);
10629 if (profilingFlags != 0)
10631 if (pMT->HasPerInstInfo())
10633 Dictionary ** pPerInstInfo = pMT->GetPerInstInfo();
10635 BOOL fIsEagerBound = pMT->CanEagerBindToParentDictionaries(image, NULL);
10639 image->PlaceInternedStructureForAddress(pPerInstInfo, CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
10643 image->PlaceStructureForAddress(pPerInstInfo, CORCOMPILE_SECTION_WRITE);
10647 Dictionary * pDictionary = pMT->GetDictionary();
10648 if (pDictionary != NULL)
10652 if (!pMT->IsCanonicalMethodTable())
10654 // CanEagerBindToMethodTable would not work for targeted patching here. The dictionary
10655 // layout is sensitive to compilation order that can be changed by TP compatible changes.
10656 BOOL canSaveSlots = (image->GetModule() == pMT->GetCanonicalMethodTable()->GetLoaderModule());
10658 fIsWriteable = pDictionary->IsWriteable(image, canSaveSlots,
10659 pMT->GetNumGenericArgs(),
10661 pClass->GetDictionaryLayout());
10665 fIsWriteable = FALSE;
10670 image->PlaceStructureForAddress(pDictionary, CORCOMPILE_SECTION_HOT_WRITEABLE);
10671 image->PlaceStructureForAddress(pClass->GetDictionaryLayout(), CORCOMPILE_SECTION_WARM);
10675 image->PlaceInternedStructureForAddress(pDictionary, CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
10680 if (profilingFlags & (1 << ReadFieldMarshalers))
10682 if (pClass->HasLayout() && pClass->GetLayoutInfo()->GetNumCTMFields() > 0)
10684 image->PlaceStructureForAddress((void *)pClass->GetLayoutInfo()->GetFieldMarshalers(), CORCOMPILE_SECTION_HOT);
10688 if (th.IsTypeDesc())
10690 if (profilingFlags & (1 << WriteTypeDesc))
10691 image->PlaceStructureForAddress(th.AsTypeDesc(), CORCOMPILE_SECTION_WRITE);
10692 else if (profilingFlags & (1 << ReadTypeDesc))
10693 image->PlaceStructureForAddress(th.AsTypeDesc(), CORCOMPILE_SECTION_HOT);
10695 image->PlaceStructureForAddress(th.AsTypeDesc(), CORCOMPILE_SECTION_WARM);
10699 void Module::PlaceMethod(DataImage *image, MethodDesc *pMD, DWORD profilingFlags)
10701 STANDARD_VM_CONTRACT;
10706 if (pMD->GetLoaderModule() != this)
10709 if (profilingFlags & (1 << ReadMethodCode))
10711 if (pMD->IsNDirect())
10713 NDirectMethodDesc *pNMD = (NDirectMethodDesc *)pMD;
10714 image->PlaceStructureForAddress((void*) pNMD->GetWriteableData(), CORCOMPILE_SECTION_WRITE);
10716 #ifdef HAS_NDIRECT_IMPORT_PRECODE
10717 // The NDirect import thunk glue is used only if no marshaling is required
10718 if (!pNMD->MarshalingRequired())
10720 image->PlaceStructureForAddress((void*) pNMD->GetNDirectImportThunkGlue(), CORCOMPILE_SECTION_METHOD_PRECODE_HOT);
10722 #endif // HAS_NDIRECT_IMPORT_PRECODE
10724 // Late bound NDirect methods require their LibName at startup.
10725 if (!pNMD->IsQCall())
10727 image->PlaceStructureForAddress((void*) pNMD->GetLibName(), CORCOMPILE_SECTION_READONLY_HOT);
10728 image->PlaceStructureForAddress((void*) pNMD->GetEntrypointName(), CORCOMPILE_SECTION_READONLY_HOT);
10732 #ifdef FEATURE_COMINTEROP
10733 if (pMD->IsComPlusCall())
10735 ComPlusCallMethodDesc *pCMD = (ComPlusCallMethodDesc *)pMD;
10737 // If the ComPlusCallMethodDesc was actually used for interop, its ComPlusCallInfo should be hot.
10738 image->PlaceStructureForAddress((void*) pCMD->m_pComPlusCallInfo, CORCOMPILE_SECTION_HOT);
10740 #endif // FEATURE_COMINTEROP
10742 // Stubs-as-IL have writeable signatures sometimes, so can't place them
10743 // into read-only section. We should not get here for stubs-as-il anyway,
10744 // but we will filter them out just to be sure.
10745 if (pMD->HasStoredSig() && !pMD->IsILStub())
10747 StoredSigMethodDesc *pSMD = (StoredSigMethodDesc*) pMD;
10749 if (pSMD->HasStoredMethodSig())
10751 image->PlaceInternedStructureForAddress((void*) pSMD->GetStoredMethodSig(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
10756 // We store the entire hot chunk in the SECTION_WRITE section
10757 if (profilingFlags & (1 << WriteMethodDesc))
10759 image->PlaceStructureForAddress(pMD, CORCOMPILE_SECTION_WRITE);
10763 if (profilingFlags & (1 << ReadCerMethodList))
10765 // protect against stale IBC data
10766 // Check if the profiling data incorrectly set the ReadCerMethodList bit.
10767 // This is more likely to happen with incremental IBC.
10768 if ((m_pCerNgenRootTable != NULL) && m_pCerNgenRootTable->IsNgenRootMethod(pMD))
10770 image->PlaceStructureForAddress(m_pCerNgenRootTable->GetList(pMD), CORCOMPILE_SECTION_HOT);
10773 #endif // FEATURE_CER
10775 if (profilingFlags & (1 << WriteMethodPrecode))
10777 Precode* pPrecode = pMD->GetSavedPrecodeOrNull(image);
10778 // protect against stale IBC data
10779 if (pPrecode != NULL)
10781 CorCompileSection section = CORCOMPILE_SECTION_METHOD_PRECODE_WRITE;
10782 if (pPrecode->IsPrebound(image))
10783 section = CORCOMPILE_SECTION_METHOD_PRECODE_HOT;
10784 // Note: This is going to place the entire PRECODE_FIXUP chunk if we have one
10785 image->PlaceStructureForAddress(pPrecode, section);
10788 else if (profilingFlags & (1 << ReadMethodPrecode))
10790 Precode* pPrecode = pMD->GetSavedPrecodeOrNull(image);
10791 // protect against stale IBC data
10792 if (pPrecode != NULL)
10794 // Note: This is going to place the entire PRECODE_FIXUP chunk if we have one
10795 image->PlaceStructureForAddress(pPrecode, CORCOMPILE_SECTION_METHOD_PRECODE_HOT);
10800 void Module::Arrange(DataImage *image)
10802 STANDARD_VM_CONTRACT;
10804 // We collect IBC logging profiling data and use that to guide the layout of the image.
10805 image->PlaceStructureForAddress(this, CORCOMPILE_SECTION_MODULE);
10807 // The stub method table is shared by all IL stubs in the module, so place it into the hot section
10808 MethodTable * pStubMT = GetILStubCache()->GetStubMethodTable();
10809 if (pStubMT != NULL)
10810 PlaceType(image, pStubMT, ReadMethodTable);
10812 CorProfileData * profileData = GetProfileData();
10816 // Place hot type structues in the order specifiled by TypeProfilingData array
10818 CORBBTPROF_TOKEN_INFO * pTypeProfilingData = profileData->GetTokenFlagsData(TypeProfilingData);
10819 DWORD cTypeProfilingData = profileData->GetTokenFlagsCount(TypeProfilingData);
10820 for (unsigned int i = 0; (i < cTypeProfilingData); i++)
10822 CORBBTPROF_TOKEN_INFO * entry = &pTypeProfilingData[i];
10823 mdToken token = entry->token;
10824 DWORD flags = entry->flags;
10825 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
10826 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_6);
10829 if (TypeFromToken(token) == mdtTypeDef)
10831 TypeHandle th = LookupTypeDef(token);
10833 // Place a hot normal type and it's data
10835 PlaceType(image, th, flags);
10837 else if (TypeFromToken(token) == ibcTypeSpec)
10839 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = profileData->GetBlobSigEntry(token);
10841 if (pBlobSigEntry == NULL)
10844 // Print an error message for the type load failure
10846 StackSString msg(W("Did not find definition for type token "));
10849 sprintf_s(buff, COUNTOF(buff), "%08x", token);
10850 StackSString szToken(SString::Ascii, &buff[0]);
10852 msg += W(" in profile data.\n");
10854 GetSvcLogger()->Log(msg, LogLevel_Info);
10856 else // (pBlobSigEntry != NULL)
10858 _ASSERTE(pBlobSigEntry->blob.token == token);
10860 // decode generic type signature
10862 TypeHandle th = LoadIBCTypeHelper(pBlobSigEntry);
10865 // Place a hot instantiated type and it's data
10867 PlaceType(image, th, flags);
10870 else if (TypeFromToken(token) == mdtFieldDef)
10872 FieldDesc *pFD = LookupFieldDef(token);
10873 if (pFD && pFD->IsILOnlyRVAField())
10875 if (entry->flags & (1 << RVAFieldData))
10877 BYTE *pRVAData = (BYTE*) pFD->GetStaticAddressHandle(NULL);
10879 // Place a hot RVA static field
10881 image->PlaceStructureForAddress(pRVAData, CORCOMPILE_SECTION_RVA_STATICS_HOT);
10888 // Place hot methods and method data in the order specifiled by MethodProfilingData array
10890 CORBBTPROF_TOKEN_INFO * pMethodProfilingData = profileData->GetTokenFlagsData(MethodProfilingData);
10891 DWORD cMethodProfilingData = profileData->GetTokenFlagsCount(MethodProfilingData);
10892 for (unsigned int i = 0; (i < cMethodProfilingData); i++)
10894 mdToken token = pMethodProfilingData[i].token;
10895 DWORD profilingFlags = pMethodProfilingData[i].flags;
10896 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
10897 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_7);
10900 if (TypeFromToken(token) == mdtMethodDef)
10902 MethodDesc * pMD = LookupMethodDef(token);
10904 // Place a hot normal method and it's data
10906 PlaceMethod(image, pMD, profilingFlags);
10908 else if (TypeFromToken(token) == ibcMethodSpec)
10910 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = profileData->GetBlobSigEntry(token);
10912 if (pBlobSigEntry == NULL)
10915 // Print an error message for the type load failure
10917 StackSString msg(W("Did not find definition for method token "));
10920 sprintf_s(buff, COUNTOF(buff), "%08x", token);
10921 StackSString szToken(SString::Ascii, &buff[0]);
10923 msg += W(" in profile data.\n");
10925 GetSvcLogger()->Log(msg, LogLevel_Info);
10927 else // (pBlobSigEntry != NULL)
10929 _ASSERTE(pBlobSigEntry->blob.token == token);
10930 MethodDesc * pMD = LoadIBCMethodHelper(pBlobSigEntry);
10935 // Place a hot instantiated method and it's data
10937 PlaceMethod(image, pMD, profilingFlags);
10944 // Now place all remaining items
10945 image->PlaceRemainingStructures();
10948 void ModuleCtorInfo::Fixup(DataImage *image)
10950 STANDARD_VM_CONTRACT;
10952 if (numElementsHot > 0)
10954 image->FixupPointerField(this, offsetof(ModuleCtorInfo, cctorInfoHot));
10955 image->FixupPointerField(this, offsetof(ModuleCtorInfo, hotHashOffsets));
10959 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, cctorInfoHot));
10960 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, hotHashOffsets));
10963 _ASSERTE(numElements > numElementsHot || numElements == numElementsHot);
10964 if (numElements > numElementsHot)
10966 image->FixupPointerField(this, offsetof(ModuleCtorInfo, cctorInfoCold));
10967 image->FixupPointerField(this, offsetof(ModuleCtorInfo, coldHashOffsets));
10971 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, cctorInfoCold));
10972 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, coldHashOffsets));
10975 if (numElements > 0)
10977 image->FixupPointerField(this, offsetof(ModuleCtorInfo, ppMT));
10979 for (DWORD i=0; i<numElements; i++)
10981 image->FixupPointerField(ppMT, i * sizeof(ppMT[0]));
10986 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, ppMT));
10989 if (numHotGCStaticsMTs > 0)
10991 image->FixupPointerField(this, offsetof(ModuleCtorInfo, ppHotGCStaticsMTs));
10993 image->BeginRegion(CORINFO_REGION_HOT);
10994 for (DWORD i=0; i < numHotGCStaticsMTs; i++)
10996 image->FixupMethodTablePointer(ppHotGCStaticsMTs, &ppHotGCStaticsMTs[i]);
10998 image->EndRegion(CORINFO_REGION_HOT);
11002 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, ppHotGCStaticsMTs));
11005 if (numColdGCStaticsMTs > 0)
11007 image->FixupPointerField(this, offsetof(ModuleCtorInfo, ppColdGCStaticsMTs));
11009 image->BeginRegion(CORINFO_REGION_COLD);
11010 for (DWORD i=0; i < numColdGCStaticsMTs; i++)
11012 image->FixupMethodTablePointer(ppColdGCStaticsMTs, &ppColdGCStaticsMTs[i]);
11014 image->EndRegion(CORINFO_REGION_COLD);
11018 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, ppColdGCStaticsMTs));
11023 #pragma warning(push)
11024 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
11026 void Module::Fixup(DataImage *image)
11028 STANDARD_VM_CONTRACT;
11030 // Propagate all changes to the image copy
11031 memcpy(image->GetImagePointer(this), (void*)this, sizeof(Module));
11037 image->ZeroPointerField(this, 0);
11039 image->FixupPointerField(this, offsetof(Module, m_pNGenLayoutInfo));
11041 image->ZeroField(this, offsetof(Module, m_pSimpleName), sizeof(m_pSimpleName));
11043 image->ZeroField(this, offsetof(Module, m_file), sizeof(m_file));
11045 image->FixupPointerField(this, offsetof(Module, m_pDllMain));
11047 image->ZeroField(this, offsetof(Module, m_dwTransientFlags), sizeof(m_dwTransientFlags));
11049 image->ZeroField(this, offsetof(Module, m_pVASigCookieBlock), sizeof(m_pVASigCookieBlock));
11050 image->ZeroField(this, offsetof(Module, m_pAssembly), sizeof(m_pAssembly));
11051 image->ZeroField(this, offsetof(Module, m_moduleRef), sizeof(m_moduleRef));
11053 image->ZeroField(this, offsetof(Module, m_Crst), sizeof(m_Crst));
11054 image->ZeroField(this, offsetof(Module, m_FixupCrst), sizeof(m_FixupCrst));
11056 image->ZeroField(this, offsetof(Module, m_pProfilingBlobTable), sizeof(m_pProfilingBlobTable));
11057 image->ZeroField(this, offsetof(Module, m_pProfileData), sizeof(m_pProfileData));
11058 image->ZeroPointerField(this, offsetof(Module, m_pIBCErrorNameString));
11060 image->ZeroPointerField(this, offsetof(Module, m_pNgenStats));
11062 // fixup the pointer for NeutralResourcesLanguage, if we have it cached
11063 if(!!(m_dwPersistedFlags & NEUTRAL_RESOURCES_LANGUAGE_IS_CACHED)) {
11064 image->FixupPointerField(this, offsetof(Module, m_pszCultureName));
11067 // Fixup the property name set
11068 image->FixupPointerField(this, offsetof(Module, m_propertyNameSet));
11071 // Fixup the method table
11074 image->ZeroField(this, offsetof(Module, m_pISymUnmanagedReader), sizeof(m_pISymUnmanagedReader));
11075 image->ZeroField(this, offsetof(Module, m_ISymUnmanagedReaderCrst), sizeof(m_ISymUnmanagedReaderCrst));
11077 // Clear active dependencies - they will be refilled at load time
11078 image->ZeroField(this, offsetof(Module, m_activeDependencies), sizeof(m_activeDependencies));
11079 new (image->GetImagePointer(this, offsetof(Module, m_unconditionalDependencies))) SynchronizedBitMask();
11080 image->ZeroField(this, offsetof(Module, m_unconditionalDependencies) + offsetof(SynchronizedBitMask, m_bitMaskLock) + offsetof(SimpleRWLock,m_spinCount), sizeof(m_unconditionalDependencies.m_bitMaskLock.m_spinCount));
11081 image->ZeroField(this, offsetof(Module, m_dwNumberOfActivations), sizeof(m_dwNumberOfActivations));
11083 image->ZeroField(this, offsetof(Module, m_LookupTableCrst), sizeof(m_LookupTableCrst));
11085 m_TypeDefToMethodTableMap.Fixup(image);
11086 m_TypeRefToMethodTableMap.Fixup(image, FALSE);
11087 m_MethodDefToDescMap.Fixup(image);
11088 m_FieldDefToDescMap.Fixup(image);
11089 if(m_pMemberRefToDescHashTable != NULL)
11091 image->FixupPointerField(this, offsetof(Module, m_pMemberRefToDescHashTable));
11092 m_pMemberRefToDescHashTable->Fixup(image);
11094 m_GenericParamToDescMap.Fixup(image);
11095 m_GenericTypeDefToCanonMethodTableMap.Fixup(image);
11096 m_FileReferencesMap.Fixup(image, FALSE);
11097 m_ManifestModuleReferencesMap.Fixup(image, FALSE);
11098 m_MethodDefToPropertyInfoMap.Fixup(image, FALSE);
11100 image->ZeroPointerField(this, offsetof(Module, m_pILStubCache));
11102 if (m_pAvailableClasses != NULL) {
11103 image->FixupPointerField(this, offsetof(Module, m_pAvailableClasses));
11104 m_pAvailableClasses->Fixup(image);
11107 image->ZeroField(this, offsetof(Module, m_pAvailableClassesCaseIns), sizeof(m_pAvailableClassesCaseIns));
11108 image->ZeroField(this, offsetof(Module, m_InstMethodHashTableCrst), sizeof(m_InstMethodHashTableCrst));
11110 image->BeginRegion(CORINFO_REGION_COLD);
11112 if (m_pAvailableParamTypes) {
11113 image->FixupPointerField(this, offsetof(Module, m_pAvailableParamTypes));
11114 m_pAvailableParamTypes->Fixup(image);
11117 if (m_pInstMethodHashTable) {
11118 image->FixupPointerField(this, offsetof(Module, m_pInstMethodHashTable));
11119 m_pInstMethodHashTable->Fixup(image);
11123 MethodTable * pStubMT = GetILStubCache()->GetStubMethodTable();
11124 if (pStubMT != NULL)
11125 pStubMT->Fixup(image);
11128 if (m_pStubMethodHashTable) {
11129 image->FixupPointerField(this, offsetof(Module, m_pStubMethodHashTable));
11130 m_pStubMethodHashTable->Fixup(image);
11133 #ifdef FEATURE_COMINTEROP
11134 if (m_pGuidToTypeHash) {
11135 image->FixupPointerField(this, offsetof(Module, m_pGuidToTypeHash));
11136 m_pGuidToTypeHash->Fixup(image);
11138 #endif // FEATURE_COMINTEROP
11140 image->EndRegion(CORINFO_REGION_COLD);
11144 // Unseal the generic tables:
11146 // - We need to run managed code to serialize the Security attributes of the ngen image
11147 // and we are now using generic types in the Security/Reflection code.
11148 // - Compilation of other modules of multimodule assemblies may add more types
11149 // to the generic tables.
11151 UnsealGenericTypesAndMethods();
11154 m_ModuleCtorInfo.Fixup(image);
11160 if (m_pBinder != NULL)
11162 image->FixupPointerField(this, offsetof(Module, m_pBinder));
11163 m_pBinder->Fixup(image);
11172 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
11174 image->BeginRegion(CORINFO_REGION_COLD);
11175 while (typeDefIter.Next())
11177 MethodTable * t = typeDefIter.GetElement();
11178 if (image->IsStored(t))
11181 image->EndRegion(CORINFO_REGION_COLD);
11185 LookupMap<PTR_TypeRef>::Iterator typeRefIter(&m_TypeRefToMethodTableMap);
11188 image->BeginRegion(CORINFO_REGION_HOT);
11189 while (typeRefIter.Next())
11192 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(typeRefIter.GetElementAndFlags(&flags)));
11196 if (th.GetLoaderModule() != this || image->IsStored(th.AsPtr()))
11198 PTR_TADDR hotItemValuePtr = m_TypeRefToMethodTableMap.FindHotItemValuePtr(rid);
11201 if (image->CanEagerBindToTypeHandle(th))
11203 if (image->CanHardBindToZapModule(th.GetLoaderModule()))
11205 PVOID pTarget = th.IsTypeDesc() ? th.AsTypeDesc() : th.AsPtr();
11206 SSIZE_T offset = th.IsTypeDesc() ? 2 : 0;
11208 _ASSERTE((flags & offset) == 0);
11210 image->FixupField(m_TypeRefToMethodTableMap.pTable, rid * sizeof(TADDR),
11211 pTarget, flags | offset, IMAGE_REL_BASED_RelativePointer);
11213 // In case this item is also in the hot item subtable, fix it up there as well
11214 if (hotItemValuePtr != NULL)
11216 image->FixupField(m_TypeRefToMethodTableMap.hotItemList,
11217 (BYTE *)hotItemValuePtr - (BYTE *)m_TypeRefToMethodTableMap.hotItemList,
11218 pTarget, flags | offset, IMAGE_REL_BASED_RelativePointer);
11223 // Create the indirection only if the entry is hot or we do have indirection cell already
11224 if (hotItemValuePtr != NULL || image->GetExistingTypeHandleImport(th) != NULL)
11226 _ASSERTE((flags & FIXUP_POINTER_INDIRECTION) == 0);
11228 ZapNode * pImport = image->GetTypeHandleImport(th);
11229 image->FixupFieldToNode(m_TypeRefToMethodTableMap.pTable, rid * sizeof(TADDR),
11230 pImport, flags | FIXUP_POINTER_INDIRECTION, IMAGE_REL_BASED_RelativePointer);
11231 if (hotItemValuePtr != NULL)
11233 image->FixupFieldToNode(m_TypeRefToMethodTableMap.hotItemList,
11234 (BYTE *)hotItemValuePtr - (BYTE *)m_TypeRefToMethodTableMap.hotItemList,
11235 pImport, flags | FIXUP_POINTER_INDIRECTION, IMAGE_REL_BASED_RelativePointer);
11243 image->ZeroPointerField(m_TypeRefToMethodTableMap.pTable, rid * sizeof(TADDR));
11244 // In case this item is also in the hot item subtable, fix it up there as well
11245 if (hotItemValuePtr != NULL)
11247 image->ZeroPointerField(m_TypeRefToMethodTableMap.hotItemList,
11248 (BYTE *)hotItemValuePtr - (BYTE *)m_TypeRefToMethodTableMap.hotItemList);
11256 image->EndRegion(CORINFO_REGION_HOT);
11260 LookupMap<PTR_TypeVarTypeDesc>::Iterator genericParamIter(&m_GenericParamToDescMap);
11262 while (genericParamIter.Next())
11264 TypeVarTypeDesc * pTypeDesc = genericParamIter.GetElement();
11266 if (pTypeDesc != NULL)
11268 _ASSERTE(image->IsStored(pTypeDesc));
11269 pTypeDesc->Fixup(image);
11275 // Fixup the assembly reference map table
11279 LookupMap<PTR_Module>::Iterator manifestModuleIter(&m_ManifestModuleReferencesMap);
11282 while (manifestModuleIter.Next())
11285 Module * pModule = manifestModuleIter.GetElementAndFlags(&flags);
11287 if (pModule != NULL)
11289 if (image->CanEagerBindToModule(pModule))
11291 if (image->CanHardBindToZapModule(pModule))
11293 image->FixupField(m_ManifestModuleReferencesMap.pTable, rid * sizeof(TADDR),
11294 pModule, flags, IMAGE_REL_BASED_RelativePointer);
11298 image->ZeroPointerField(m_ManifestModuleReferencesMap.pTable, rid * sizeof(TADDR));
11303 image->ZeroPointerField(m_ManifestModuleReferencesMap.pTable, rid * sizeof(TADDR));
11312 // Zero out file references table.
11314 image->ZeroField(m_FileReferencesMap.pTable, 0,
11315 m_FileReferencesMap.GetSize() * sizeof(void*));
11319 // Fixup Constrained Execution Regions restoration records.
11321 if (m_pCerNgenRootTable != NULL)
11323 image->BeginRegion(CORINFO_REGION_HOT);
11324 image->FixupPointerField(this, offsetof(Module, m_pCerNgenRootTable));
11325 m_pCerNgenRootTable->Fixup(image);
11326 image->EndRegion(CORINFO_REGION_HOT);
11329 image->ZeroPointerField(this, offsetof(Module, m_pCerNgenRootTable));
11331 // Zero out fields we always compute at runtime lazily.
11332 image->ZeroField(this, offsetof(Module, m_pCerPrepInfo), sizeof(m_pCerPrepInfo));
11333 image->ZeroField(this, offsetof(Module, m_pCerCrst), sizeof(m_pCerCrst));
11334 #endif // FEATURE_CER
11336 image->ZeroField(this, offsetof(Module, m_debuggerSpecificData), sizeof(m_debuggerSpecificData));
11338 image->ZeroField(this, offsetof(Module, m_AssemblyRefByNameCount), sizeof(m_AssemblyRefByNameCount));
11339 image->ZeroPointerField(this, offsetof(Module, m_AssemblyRefByNameTable));
11341 image->ZeroPointerField(this,offsetof(Module, m_NativeMetadataAssemblyRefMap));
11346 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: fixing up module static data\n"));
11348 image->ZeroPointerField(this, offsetof(Module, m_ModuleID));
11349 image->ZeroField(this, offsetof(Module, m_ModuleIndex), sizeof(m_ModuleIndex));
11351 image->FixupPointerField(this, offsetof(Module, m_pDynamicStaticsInfo));
11353 DynamicStaticsInfo* pDSI = m_pDynamicStaticsInfo;
11354 for (DWORD i = 0; i < m_cDynamicEntries; i++, pDSI++)
11356 if (pDSI->pEnclosingMT->GetLoaderModule() == this &&
11357 // CEEPreloader::TriageTypeForZap() could have rejected this type
11358 image->IsStored(pDSI->pEnclosingMT))
11360 image->FixupPointerField(m_pDynamicStaticsInfo, (BYTE *)&pDSI->pEnclosingMT - (BYTE *)m_pDynamicStaticsInfo);
11364 // Some other (mutually-recursive) dependency must have loaded
11365 // a generic instantiation whose static were pumped into the
11366 // assembly being ngenned.
11367 image->ZeroPointerField(m_pDynamicStaticsInfo, (BYTE *)&pDSI->pEnclosingMT - (BYTE *)m_pDynamicStaticsInfo);
11371 // fix up module security descriptor
11372 if (m_pModuleSecurityDescriptor)
11374 image->FixupPointerField(this, offsetof(Module, m_pModuleSecurityDescriptor));
11375 m_pModuleSecurityDescriptor->Fixup(image);
11379 image->ZeroPointerField(this, offsetof(Module, m_pModuleSecurityDescriptor));
11382 // If we failed to load some types we need to reset the pointers to the static offset tables so they'll be
11383 // rebuilt at runtime.
11384 if (m_pRegularStaticOffsets != (PTR_DWORD)NGEN_STATICS_ALLCLASSES_WERE_LOADED)
11386 _ASSERTE(m_pThreadStaticOffsets != (PTR_DWORD)NGEN_STATICS_ALLCLASSES_WERE_LOADED);
11387 image->ZeroPointerField(this, offsetof(Module, m_pRegularStaticOffsets));
11388 image->ZeroPointerField(this, offsetof(Module, m_pThreadStaticOffsets));
11391 // Fix up inlining data
11392 if(m_persistentInlineTrackingMap)
11394 image->FixupPointerField(this, offsetof(Module, m_persistentInlineTrackingMap));
11395 m_persistentInlineTrackingMap->Fixup(image);
11399 image->ZeroPointerField(this, offsetof(Module, m_persistentInlineTrackingMap));
11402 SetIsModuleSaved();
11405 #pragma warning(pop)
11408 #endif // FEATURE_NATIVE_IMAGE_GENERATION
11410 #ifdef FEATURE_PREJIT
11412 // Is "address" a data-structure in the native image?
11415 BOOL Module::IsPersistedObject(void *address)
11427 if (!HasNativeImage())
11430 PEImageLayout *pLayout = GetNativeImage();
11431 _ASSERTE(pLayout->IsMapped());
11433 return (address >= pLayout->GetBase()
11434 && address < (BYTE*)pLayout->GetBase() + pLayout->GetVirtualSize());
11437 Module *Module::GetModuleFromIndex(DWORD ix)
11445 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
11449 if (HasNativeImage())
11451 PRECONDITION(GetNativeImage()->CheckNativeImportFromIndex(ix));
11452 CORCOMPILE_IMPORT_TABLE_ENTRY *p = GetNativeImage()->GetNativeImportFromIndex(ix);
11453 RETURN ZapSig::DecodeModuleFromIndexes(this, p->wAssemblyRid, p->wModuleRid);
11457 mdAssemblyRef mdAssemblyRefToken = TokenFromRid(ix, mdtAssemblyRef);
11458 Assembly *pAssembly = this->LookupAssemblyRef(mdAssemblyRefToken);
11461 RETURN pAssembly->GetManifestModule();
11465 // GetModuleFromIndex failed
11470 #endif // FEATURE_PREJIT
11472 #endif // !DACCESS_COMPILE
11474 #ifdef FEATURE_PREJIT
11476 Module *Module::GetModuleFromIndexIfLoaded(DWORD ix)
11484 PRECONDITION(HasNativeImage());
11485 PRECONDITION(GetNativeImage()->CheckNativeImportFromIndex(ix));
11486 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
11490 #ifndef DACCESS_COMPILE
11491 CORCOMPILE_IMPORT_TABLE_ENTRY *p = GetNativeImage()->GetNativeImportFromIndex(ix);
11493 RETURN ZapSig::DecodeModuleFromIndexesIfLoaded(this, p->wAssemblyRid, p->wModuleRid);
11494 #else // DACCESS_COMPILE
11497 #endif // DACCESS_COMPILE
11500 #ifndef DACCESS_COMPILE
11502 BYTE *Module::GetNativeFixupBlobData(RVA rva)
11511 POSTCONDITION(CheckPointer(RETVAL));
11515 RETURN (BYTE *) GetNativeOrReadyToRunImage()->GetRvaData(rva);
11518 IMDInternalImport *Module::GetNativeAssemblyImport(BOOL loadAllowed)
11520 CONTRACT(IMDInternalImport *)
11523 if (loadAllowed) GC_TRIGGERS; else GC_NOTRIGGER;
11524 if (loadAllowed) THROWS; else NOTHROW;
11525 if (loadAllowed) INJECT_FAULT(COMPlusThrowOM()); else FORBID_FAULT;
11527 PRECONDITION(HasNativeImage());
11528 POSTCONDITION(CheckPointer(RETVAL));
11532 RETURN GetFile()->GetPersistentNativeImage()->GetNativeMDImport(loadAllowed);
11537 void Module::RestoreMethodTablePointerRaw(MethodTable ** ppMT,
11538 Module *pContainingModule,
11539 ClassLoadLevel level)
11549 // Ensure that the compiler won't fetch the value twice
11550 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppMT);
11553 if (pContainingModule != NULL)
11555 Module * dbg_pZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMT));
11556 _ASSERTE((dbg_pZapModule == NULL) || (pContainingModule == dbg_pZapModule));
11560 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
11563 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
11566 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
11568 if (pContainingModule == NULL)
11569 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMT));
11570 PREFIX_ASSUME(pContainingModule != NULL);
11572 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_TYPE_HANDLE);
11574 Module * pInfoModule;
11575 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
11577 TypeHandle th = ZapSig::DecodeType(pContainingModule,
11581 *EnsureWritablePages(ppMT) = th.AsMethodTable();
11585 ClassLoader::EnsureLoaded(*ppMT, level);
11590 void Module::RestoreMethodTablePointer(FixupPointer<PTR_MethodTable> * ppMT,
11591 Module *pContainingModule,
11592 ClassLoadLevel level)
11602 if (ppMT->IsNull())
11605 if (ppMT->IsTagged())
11607 RestoreMethodTablePointerRaw(ppMT->GetValuePtr(), pContainingModule, level);
11611 ClassLoader::EnsureLoaded(ppMT->GetValue(), level);
11616 void Module::RestoreMethodTablePointer(RelativeFixupPointer<PTR_MethodTable> * ppMT,
11617 Module *pContainingModule,
11618 ClassLoadLevel level)
11628 if (ppMT->IsNull())
11631 if (ppMT->IsTagged((TADDR)ppMT))
11633 RestoreMethodTablePointerRaw(ppMT->GetValuePtr((TADDR)ppMT), pContainingModule, level);
11637 ClassLoader::EnsureLoaded(ppMT->GetValue((TADDR)ppMT), level);
11641 #endif // !DACCESS_COMPILE
11643 BOOL Module::IsZappedCode(PCODE code)
11654 if (!HasNativeImage())
11657 PEImageLayout *pNativeImage = GetNativeImage();
11660 PCODE pCodeSection;
11662 pCodeSection = pNativeImage->GetNativeHotCode(&cCode);
11663 if ((pCodeSection <= code) && (code < pCodeSection + cCode))
11668 pCodeSection = pNativeImage->GetNativeCode(&cCode);
11669 if ((pCodeSection <= code) && (code < pCodeSection + cCode))
11677 BOOL Module::IsZappedPrecode(PCODE code)
11688 if (m_pNGenLayoutInfo == NULL)
11691 for (SIZE_T i = 0; i < COUNTOF(m_pNGenLayoutInfo->m_Precodes); i++)
11693 if (m_pNGenLayoutInfo->m_Precodes[i].IsInRange(code))
11700 PCCOR_SIGNATURE Module::GetEncodedSig(RVA fixupRva, Module **ppDefiningModule)
11702 CONTRACT(PCCOR_SIGNATURE)
11709 POSTCONDITION(CheckPointer(RETVAL));
11714 #ifndef DACCESS_COMPILE
11715 PCCOR_SIGNATURE pBuffer = GetNativeFixupBlobData(fixupRva);
11717 BYTE kind = *pBuffer++;
11719 *ppDefiningModule = (kind & ENCODE_MODULE_OVERRIDE) ? GetModuleFromIndex(CorSigUncompressData(pBuffer)) : this;
11724 #endif // DACCESS_COMPILE
11727 PCCOR_SIGNATURE Module::GetEncodedSigIfLoaded(RVA fixupRva, Module **ppDefiningModule)
11729 CONTRACT(PCCOR_SIGNATURE)
11736 POSTCONDITION(CheckPointer(RETVAL));
11741 #ifndef DACCESS_COMPILE
11742 PCCOR_SIGNATURE pBuffer = GetNativeFixupBlobData(fixupRva);
11744 BYTE kind = *pBuffer++;
11746 *ppDefiningModule = (kind & ENCODE_MODULE_OVERRIDE) ? GetModuleFromIndexIfLoaded(CorSigUncompressData(pBuffer)) : this;
11750 *ppDefiningModule = NULL;
11752 #endif // DACCESS_COMPILE
11756 PTR_Module Module::RestoreModulePointerIfLoaded(DPTR(RelativeFixupPointer<PTR_Module>) ppModule, Module *pContainingModule)
11768 if (!ppModule->IsTagged(dac_cast<TADDR>(ppModule)))
11769 return ppModule->GetValue(dac_cast<TADDR>(ppModule));
11771 #ifndef DACCESS_COMPILE
11772 PTR_Module * ppValue = ppModule->GetValuePtr(dac_cast<TADDR>(ppModule));
11774 // Ensure that the compiler won't fetch the value twice
11775 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppValue);
11777 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
11781 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
11784 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
11786 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_MODULE_HANDLE);
11788 Module * pInfoModule;
11789 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSigIfLoaded(fixupRva, &pInfoModule);
11793 if (EnsureWritablePagesNoThrow(ppValue, sizeof(*ppValue)))
11794 *ppValue = pInfoModule;
11796 return pInfoModule;
11800 return PTR_Module(fixup);
11808 #ifndef DACCESS_COMPILE
11811 void Module::RestoreModulePointer(RelativeFixupPointer<PTR_Module> * ppModule, Module *pContainingModule)
11818 INJECT_FAULT(COMPlusThrowOM());
11822 if (!ppModule->IsTagged((TADDR)ppModule))
11825 PTR_Module * ppValue = ppModule->GetValuePtr((TADDR)ppModule);
11827 // Ensure that the compiler won't fetch the value twice
11828 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppValue);
11830 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
11833 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
11836 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
11838 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_MODULE_HANDLE);
11840 Module * pInfoModule;
11841 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
11843 *EnsureWritablePages(ppValue) = pInfoModule;
11848 void Module::RestoreTypeHandlePointerRaw(TypeHandle *pHandle, Module* pContainingModule, ClassLoadLevel level)
11852 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
11853 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
11854 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else {INJECT_FAULT(COMPlusThrowOM(););}
11860 if (pContainingModule != NULL)
11862 Module * dbg_pZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(pHandle));
11863 _ASSERTE((dbg_pZapModule == NULL) || (pContainingModule == dbg_pZapModule));
11869 if (IS_ALIGNED(pHandle, sizeof(TypeHandle)))
11871 // Ensure that the compiler won't fetch the value twice
11872 fixup = VolatileLoadWithoutBarrier((TADDR *)pHandle);
11876 // This is necessary to handle in-place fixups (see by FixupTypeHandlePointerInplace)
11877 // in stubs-as-il signatures.
11880 // protect this unaligned read with the Module Crst for the rare case that
11881 // the TypeHandle to fixup is in a signature and unaligned.
11883 if (NULL == pContainingModule)
11885 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(pHandle));
11887 CrstHolder ch(&pContainingModule->m_Crst);
11888 fixup = *(TADDR UNALIGNED *)pHandle;
11891 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
11894 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
11897 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
11899 if (NULL == pContainingModule)
11901 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(pHandle));
11903 PREFIX_ASSUME(pContainingModule != NULL);
11905 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_TYPE_HANDLE);
11907 Module * pInfoModule;
11908 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
11910 TypeHandle thResolved = ZapSig::DecodeType(pContainingModule,
11914 EnsureWritablePages(pHandle);
11915 if (IS_ALIGNED(pHandle, sizeof(TypeHandle)))
11917 *pHandle = thResolved;
11922 // protect this unaligned write with the Module Crst for the rare case that
11923 // the TypeHandle to fixup is in a signature and unaligned.
11925 CrstHolder ch(&pContainingModule->m_Crst);
11926 *(TypeHandle UNALIGNED *)pHandle = thResolved;
11929 else if (fixup != NULL)
11931 ClassLoader::EnsureLoaded(TypeHandle::FromTAddr(fixup), level);
11936 void Module::RestoreTypeHandlePointer(FixupPointer<TypeHandle> * pHandle,
11937 Module *pContainingModule,
11938 ClassLoadLevel level)
11948 if (pHandle->IsNull())
11951 if (pHandle->IsTagged())
11953 RestoreTypeHandlePointerRaw(pHandle->GetValuePtr(), pContainingModule, level);
11957 ClassLoader::EnsureLoaded(pHandle->GetValue(), level);
11962 void Module::RestoreTypeHandlePointer(RelativeFixupPointer<TypeHandle> * pHandle,
11963 Module *pContainingModule,
11964 ClassLoadLevel level)
11974 if (pHandle->IsNull())
11977 if (pHandle->IsTagged((TADDR)pHandle))
11979 RestoreTypeHandlePointerRaw(pHandle->GetValuePtr((TADDR)pHandle), pContainingModule, level);
11983 ClassLoader::EnsureLoaded(pHandle->GetValue((TADDR)pHandle), level);
11988 void Module::RestoreMethodDescPointerRaw(PTR_MethodDesc * ppMD, Module *pContainingModule, ClassLoadLevel level)
11998 // Ensure that the compiler won't fetch the value twice
11999 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppMD);
12002 if (pContainingModule != NULL)
12004 Module * dbg_pZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMD));
12005 _ASSERTE((dbg_pZapModule == NULL) || (pContainingModule == dbg_pZapModule));
12009 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
12014 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
12017 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
12019 if (pContainingModule == NULL)
12020 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMD));
12021 PREFIX_ASSUME(pContainingModule != NULL);
12023 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_METHOD_HANDLE);
12025 Module * pInfoModule;
12026 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
12028 *EnsureWritablePages(ppMD) = ZapSig::DecodeMethod(pContainingModule,
12033 (*ppMD)->CheckRestore(level);
12038 void Module::RestoreMethodDescPointer(FixupPointer<PTR_MethodDesc> * ppMD,
12039 Module *pContainingModule,
12040 ClassLoadLevel level)
12050 if (ppMD->IsNull())
12053 if (ppMD->IsTagged())
12055 RestoreMethodDescPointerRaw(ppMD->GetValuePtr(), pContainingModule, level);
12059 ppMD->GetValue()->CheckRestore(level);
12064 void Module::RestoreMethodDescPointer(RelativeFixupPointer<PTR_MethodDesc> * ppMD,
12065 Module *pContainingModule,
12066 ClassLoadLevel level)
12076 if (ppMD->IsNull())
12079 if (ppMD->IsTagged((TADDR)ppMD))
12081 RestoreMethodDescPointerRaw(ppMD->GetValuePtr((TADDR)ppMD), pContainingModule, level);
12085 ppMD->GetValue((TADDR)ppMD)->CheckRestore(level);
12090 void Module::RestoreFieldDescPointer(FixupPointer<PTR_FieldDesc> * ppFD)
12100 PTR_FieldDesc * ppValue = ppFD->GetValuePtr();
12102 // Ensure that the compiler won't fetch the value twice
12103 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppValue);
12105 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
12108 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
12111 Module * pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppValue));
12112 PREFIX_ASSUME(pContainingModule != NULL);
12114 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
12116 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_FIELD_HANDLE);
12118 Module * pInfoModule;
12119 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
12121 *EnsureWritablePages(ppValue) = ZapSig::DecodeField(pContainingModule,
12128 //-----------------------------------------------------------------------------
12132 This diagram illustrates the layout of fixups in the ngen image.
12133 This is the case where function foo2 has a class-restore fixup
12134 for class C1 in b.dll.
12136 zapBase+curTableVA+rva / FixupList (see Fixup Encoding below)
12138 +-------------------+
12139 pEntry->VA +--------------------+ | non-NULL | foo1
12140 |Handles | +-------------------+
12141 ZapHeader.ImportTable | | | non-NULL |
12142 | | +-------------------+
12143 +------------+ +--------------------+ | non-NULL |
12144 |a.dll | |Class cctors |<---+ +-------------------+
12146 | | p->VA/ | |<---+ \ +===================+
12147 | | blobs +--------------------+ \ +-------non-NULL | foo2
12148 +------------+ |Class restore | \ +-------------------+
12149 |b.dll | | | +-------non-NULL |
12150 | | | | +-------------------+
12151 | token_C1 |<--------------blob(=>fixedUp/0) |<--pBlob--------index |
12152 | | \ | | +-------------------+
12153 | | \ +--------------------+ | non-NULL |
12154 | | \ | | +-------------------+
12156 | | \ | . | +===================+
12157 +------------+ \ | . | | 0 | foo3
12158 \ | | +===================+
12159 \ +--------------------+ | non-NULL | foo4
12160 \ |Various fixups that | +-------------------+
12161 \ |need too happen | | 0 |
12162 \| | +===================+
12163 |(CorCompileTokenTable)
12165 pEntryEnd->VA +--------------------+
12171 //-----------------------------------------------------------------------------
12173 BOOL Module::FixupNativeEntry(CORCOMPILE_IMPORT_SECTION * pSection, SIZE_T fixupIndex, SIZE_T *fixupCell)
12178 PRECONDITION(CheckPointer(fixupCell));
12182 // Ensure that the compiler won't fetch the value twice
12183 SIZE_T fixup = VolatileLoadWithoutBarrier(fixupCell);
12185 if (pSection->Signatures != NULL)
12189 PTR_DWORD pSignatures = dac_cast<PTR_DWORD>(GetNativeOrReadyToRunImage()->GetRvaData(pSection->Signatures));
12191 if (!LoadDynamicInfoEntry(this, pSignatures[fixupIndex], fixupCell))
12194 _ASSERTE(*fixupCell != NULL);
12199 if (CORCOMPILE_IS_FIXUP_TAGGED(fixup, pSection))
12201 // Fixup has not been fixed up yet
12202 if (!LoadDynamicInfoEntry(this, (RVA)CORCOMPILE_UNTAG_TOKEN(fixup), fixupCell))
12205 _ASSERTE(!CORCOMPILE_IS_FIXUP_TAGGED(*fixupCell, pSection));
12210 // Handle tables are special. We may need to restore static handle or previous
12211 // attempts to load handle could have been partial.
12213 if (pSection->Type == CORCOMPILE_IMPORT_TYPE_TYPE_HANDLE)
12215 TypeHandle::FromPtr((void *)fixup).CheckRestore();
12218 if (pSection->Type == CORCOMPILE_IMPORT_TYPE_METHOD_HANDLE)
12220 ((MethodDesc *)(fixup))->CheckRestore();
12228 //-----------------------------------------------------------------------------
12230 void Module::RunEagerFixups()
12232 STANDARD_VM_CONTRACT;
12235 PTR_CORCOMPILE_IMPORT_SECTION pSections = GetImportSections(&nSections);
12237 if (nSections == 0)
12241 // Loading types during eager fixup is not a tested scenario. Make bugs out of any attempts to do so in a
12242 // debug build. Use holder to recover properly in case of exception.
12243 class ForbidTypeLoadHolder
12246 ForbidTypeLoadHolder()
12248 BEGIN_FORBID_TYPELOAD();
12251 ~ForbidTypeLoadHolder()
12253 END_FORBID_TYPELOAD();
12259 // TODO: Verify that eager fixup dependency graphs can contain no cycles
12260 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
12262 PEImageLayout *pNativeImage = GetNativeOrReadyToRunImage();
12264 for (COUNT_T iSection = 0; iSection < nSections; iSection++)
12266 PTR_CORCOMPILE_IMPORT_SECTION pSection = pSections + iSection;
12268 if ((pSection->Flags & CORCOMPILE_IMPORT_FLAGS_EAGER) == 0)
12272 TADDR tableBase = pNativeImage->GetDirectoryData(&pSection->Section, &tableSize);
12274 if (pSection->Signatures != NULL)
12276 PTR_DWORD pSignatures = dac_cast<PTR_DWORD>(pNativeImage->GetRvaData(pSection->Signatures));
12278 for (SIZE_T * fixupCell = (SIZE_T *)tableBase; fixupCell < (SIZE_T *)(tableBase + tableSize); fixupCell++)
12280 SIZE_T fixupIndex = fixupCell - (SIZE_T *)tableBase;
12281 if (!LoadDynamicInfoEntry(this, pSignatures[fixupIndex], fixupCell))
12283 _ASSERTE(!"LoadDynamicInfoEntry failed");
12284 ThrowHR(COR_E_BADIMAGEFORMAT);
12286 _ASSERTE(*fixupCell != NULL);
12291 for (SIZE_T * fixupCell = (SIZE_T *)tableBase; fixupCell < (SIZE_T *)(tableBase + tableSize); fixupCell++)
12293 // Ensure that the compiler won't fetch the value twice
12294 SIZE_T fixup = VolatileLoadWithoutBarrier(fixupCell);
12296 // This method may execute multiple times in multi-domain scenarios. Check that the fixup has not been
12298 if (CORCOMPILE_IS_FIXUP_TAGGED(fixup, pSection))
12300 if (!LoadDynamicInfoEntry(this, (RVA)CORCOMPILE_UNTAG_TOKEN(fixup), fixupCell))
12302 _ASSERTE(!"LoadDynamicInfoEntry failed");
12303 ThrowHR(COR_E_BADIMAGEFORMAT);
12305 _ASSERTE(!CORCOMPILE_IS_FIXUP_TAGGED(*fixupCell, pSection));
12312 void Module::LoadTokenTables()
12320 PRECONDITION(HasNativeImage());
12324 #ifndef CROSSGEN_COMPILE
12325 if (NingenEnabled())
12328 CORCOMPILE_EE_INFO_TABLE *pEEInfo = GetNativeImage()->GetNativeEEInfoTable();
12329 PREFIX_ASSUME(pEEInfo != NULL);
12331 pEEInfo->inlinedCallFrameVptr = InlinedCallFrame::GetMethodFrameVPtr();
12332 pEEInfo->addrOfCaptureThreadGlobal = (LONG *)&g_TrapReturningThreads;
12334 //CoreClr doesn't always have the debugger loaded
12335 //patch up the ngen image to point to this address so that the JIT bypasses JMC if there is no debugger
12336 static DWORD g_dummyJMCFlag = 0;
12337 pEEInfo->addrOfJMCFlag = g_pDebugInterface ? g_pDebugInterface->GetJMCFlagAddr(this) : &g_dummyJMCFlag;
12339 pEEInfo->gsCookie = GetProcessGSCookie();
12343 pEEInfo->emptyString = (CORINFO_Object **)StringObject::GetEmptyStringRefPtr();
12346 #ifdef FEATURE_IMPLICIT_TLS
12347 pEEInfo->threadTlsIndex = TLS_OUT_OF_INDEXES;
12349 pEEInfo->threadTlsIndex = GetThreadTLSIndex();
12351 pEEInfo->rvaStaticTlsIndex = NULL;
12352 #endif // CROSSGEN_COMPILE
12355 #endif // !DACCESS_COMPILE
12357 // Returns the RVA to the compressed debug information blob for the given method
12359 CORCOMPILE_DEBUG_ENTRY Module::GetMethodDebugInfoOffset(MethodDesc *pMD)
12361 CONTRACT(CORCOMPILE_DEBUG_ENTRY)
12364 PRECONDITION(HasNativeImage());
12365 PRECONDITION(CheckPointer(pMD) && pMD->IsPreImplemented());
12366 POSTCONDITION(GetNativeImage()->CheckRva(RETVAL, NULL_OK));
12374 if (!GetNativeImage()->HasNativeDebugMap() || pMD->IsRuntimeSupplied())
12378 PTR_CORCOMPILE_DEBUG_RID_ENTRY ridTable =
12379 dac_cast<PTR_CORCOMPILE_DEBUG_RID_ENTRY>(GetNativeImage()->GetNativeDebugMap(&size));
12381 COUNT_T count = size / sizeof(CORCOMPILE_DEBUG_RID_ENTRY);
12382 // The size should be odd for better hashing
12383 _ASSERTE((count & 1) != 0);
12385 CORCOMPILE_DEBUG_RID_ENTRY ridEntry = ridTable[GetDebugRidEntryHash(pMD->GetMemberDef()) % count];
12387 // Do we have multiple code corresponding to the same RID
12388 if (!IsMultipleLabelledEntries(ridEntry))
12393 PTR_CORCOMPILE_DEBUG_LABELLED_ENTRY pLabelledEntry =
12394 PTR_CORCOMPILE_DEBUG_LABELLED_ENTRY
12395 (GetNativeImage()->GetRvaData(ridEntry &
12396 ~CORCOMPILE_DEBUG_MULTIPLE_ENTRIES));
12398 DWORD codeRVA = GetNativeImage()->
12399 GetDataRva((const TADDR)pMD->GetNativeCode());
12400 #if defined(_TARGET_ARM_)
12401 // Since the Thumb Bit is set on ARM, the RVA calculated above will have it set as well
12402 // and will result in the failure of checks in the loop below. Hence, mask off the
12403 // bit before proceeding ahead.
12404 codeRVA = ThumbCodeToDataPointer<DWORD, DWORD>(codeRVA);
12405 #endif // _TARGET_ARM_
12409 if (pLabelledEntry->nativeCodeRVA == codeRVA)
12411 RETURN (pLabelledEntry->debugInfoOffset & ~CORCOMPILE_DEBUG_MULTIPLE_ENTRIES);
12414 if (!IsMultipleLabelledEntries(pLabelledEntry->debugInfoOffset))
12422 _ASSERTE(!"Debug info not found - corrupted ngen image?");
12426 PTR_BYTE Module::GetNativeDebugInfo(MethodDesc * pMD)
12431 PRECONDITION(HasNativeImage());
12432 PRECONDITION(CheckPointer(pMD));
12433 PRECONDITION(pMD->GetZapModule() == this);
12441 CORCOMPILE_DEBUG_ENTRY debugInfoOffset = GetMethodDebugInfoOffset(pMD);
12443 if (debugInfoOffset == 0)
12446 return dac_cast<PTR_BYTE>(GetNativeImage()->GetRvaData(debugInfoOffset));
12448 #endif //FEATURE_PREJIT
12452 #ifndef DACCESS_COMPILE
12454 #ifdef FEATURE_PREJIT
12456 // Profile data management
12459 ICorJitInfo::ProfileBuffer * Module::AllocateProfileBuffer(mdToken _token, DWORD _count, DWORD _ILSize)
12461 CONTRACT (ICorJitInfo::ProfileBuffer*)
12467 INJECT_FAULT(CONTRACT_RETURN NULL;);
12468 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
12472 assert(_ILSize != 0);
12474 DWORD listSize = sizeof(CORCOMPILE_METHOD_PROFILE_LIST);
12475 DWORD headerSize = sizeof(CORBBTPROF_METHOD_HEADER);
12476 DWORD blockSize = _count * sizeof(CORBBTPROF_BLOCK_DATA);
12477 DWORD totalSize = listSize + headerSize + blockSize;
12479 BYTE * memory = (BYTE *) (void *) this->m_pAssembly->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(totalSize));
12481 CORCOMPILE_METHOD_PROFILE_LIST * methodProfileList = (CORCOMPILE_METHOD_PROFILE_LIST *) (memory + 0);
12482 CORBBTPROF_METHOD_HEADER * methodProfileData = (CORBBTPROF_METHOD_HEADER *) (memory + listSize);
12484 // Note: Memory allocated on the LowFrequencyHeap is zero filled
12486 methodProfileData->size = headerSize + blockSize;
12487 methodProfileData->method.token = _token;
12488 methodProfileData->method.ILSize = _ILSize;
12489 methodProfileData->method.cBlock = _count;
12491 assert(methodProfileData->size == methodProfileData->Size());
12493 // Link it to the per module list of profile data buffers
12495 methodProfileList->next = m_methodProfileList;
12496 m_methodProfileList = methodProfileList;
12498 RETURN ((ICorJitInfo::ProfileBuffer *) &methodProfileData->method.block[0]);
12501 HANDLE Module::OpenMethodProfileDataLogFile(GUID mvid)
12512 HANDLE profileDataFile = INVALID_HANDLE_VALUE;
12515 LPCWSTR assemblyPath = m_file->GetPath();
12516 LPCWSTR ibcDir = g_pConfig->GetZapBBInstrDir(); // should we put the ibc data into a particular directory?
12518 path.Set(assemblyPath); // no, then put it beside the IL dll
12521 LPCWSTR assemblyFileName = wcsrchr(assemblyPath, '\\');
12522 if (assemblyFileName)
12523 assemblyFileName++; // skip past the \ char
12525 assemblyFileName = assemblyPath;
12527 path.Set(ibcDir); // yes, put it in the directory, named with the assembly name.
12529 path.Append(assemblyFileName);
12532 SString::Iterator ext = path.End(); // remove the extension
12533 if (path.FindBack(ext, '.'))
12534 path.Truncate(ext);
12535 path.Append(W(".ibc")); // replace with .ibc extension
12537 profileDataFile = WszCreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
12539 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
12542 if (profileDataFile == INVALID_HANDLE_VALUE) COMPlusThrowWin32();
12545 CORBBTPROF_FILE_HEADER fileHeader;
12547 SetFilePointer(profileDataFile, 0, NULL, FILE_BEGIN);
12548 BOOL result = ReadFile(profileDataFile, &fileHeader, sizeof(fileHeader), &count, NULL);
12550 (count == sizeof(fileHeader)) &&
12551 (fileHeader.HeaderSize == sizeof(CORBBTPROF_FILE_HEADER)) &&
12552 (fileHeader.Magic == CORBBTPROF_MAGIC) &&
12553 (fileHeader.Version == CORBBTPROF_CURRENT_VERSION) &&
12554 (fileHeader.MVID == mvid))
12557 // The existing file was from the same assembly version - just append to it.
12560 SetFilePointer(profileDataFile, 0, NULL, FILE_END);
12565 // Either this is a new file, or it's from a previous version. Replace the contents.
12568 SetFilePointer(profileDataFile, 0, NULL, FILE_BEGIN);
12571 return profileDataFile;
12574 // Note that this method cleans up the profile buffers, so it's crucial that
12575 // no managed code in the module is allowed to run once this method has
12581 SIZE_T getCurrentOffset() {WRAPPER_NO_CONTRACT; return buffer.Size();}
12583 void * getOffsetPtr(SIZE_T offset)
12585 LIMITED_METHOD_CONTRACT;
12586 _ASSERTE(offset <= buffer.Size());
12587 return ((void *) (((char *) buffer.Ptr()) + offset));
12590 void *Allocate(SIZE_T size)
12598 INJECT_FAULT(CONTRACT_RETURN NULL;);
12599 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
12603 SIZE_T oldSize = buffer.Size();
12604 buffer.ReSizeThrows(oldSize + size);
12605 RETURN getOffsetPtr(oldSize);
12609 CQuickBytes buffer;
12612 class ProfileEmitter
12618 LIMITED_METHOD_CONTRACT;
12619 pSectionList = NULL;
12624 WRAPPER_NO_CONTRACT;
12625 while (pSectionList)
12627 SectionList *temp = pSectionList->next;
12628 delete pSectionList;
12629 pSectionList = temp;
12633 ProfileMap *EmitNewSection(SectionFormat format)
12635 WRAPPER_NO_CONTRACT;
12636 SectionList *s = new SectionList();
12638 s->format = format;
12639 s->next = pSectionList;
12642 return &s->profileMap;
12646 // Serialize the profile sections into pMap
12649 void Serialize(ProfileMap *profileMap, GUID mvid)
12657 INJECT_FAULT(COMPlusThrowOM());
12662 // Allocate the file header
12665 CORBBTPROF_FILE_HEADER *fileHeader;
12666 fileHeader = (CORBBTPROF_FILE_HEADER *) profileMap->Allocate(sizeof(CORBBTPROF_FILE_HEADER));
12668 fileHeader->HeaderSize = sizeof(CORBBTPROF_FILE_HEADER);
12669 fileHeader->Magic = CORBBTPROF_MAGIC;
12670 fileHeader->Version = CORBBTPROF_CURRENT_VERSION;
12671 fileHeader->MVID = mvid;
12675 // Count the number of sections
12677 ULONG32 numSections = 0;
12678 for (SectionList *p = pSectionList; p; p = p->next)
12684 // Allocate the section table
12686 SIZE_T tableEntryOffset;
12688 CORBBTPROF_SECTION_TABLE_HEADER *tableHeader;
12689 tableHeader = (CORBBTPROF_SECTION_TABLE_HEADER *)
12690 profileMap->Allocate(sizeof(CORBBTPROF_SECTION_TABLE_HEADER));
12692 tableHeader->NumEntries = numSections;
12693 tableEntryOffset = profileMap->getCurrentOffset();
12695 CORBBTPROF_SECTION_TABLE_ENTRY *tableEntry;
12696 tableEntry = (CORBBTPROF_SECTION_TABLE_ENTRY *)
12697 profileMap->Allocate(sizeof(CORBBTPROF_SECTION_TABLE_ENTRY) * numSections);
12701 // Allocate the data sections
12704 ULONG secCount = 0;
12705 for (SectionList *pSec = pSectionList; pSec; pSec = pSec->next, secCount++)
12707 SIZE_T offset = profileMap->getCurrentOffset();
12708 assert((offset & 0x3) == 0);
12710 SIZE_T actualSize = pSec->profileMap.getCurrentOffset();
12711 SIZE_T alignUpSize = AlignUp(actualSize, sizeof(DWORD));
12713 profileMap->Allocate(alignUpSize);
12715 memcpy(profileMap->getOffsetPtr(offset), pSec->profileMap.getOffsetPtr(0), actualSize);
12716 if (alignUpSize > actualSize)
12718 memset(((BYTE*)profileMap->getOffsetPtr(offset))+actualSize, 0, (alignUpSize - actualSize));
12721 CORBBTPROF_SECTION_TABLE_ENTRY *tableEntry;
12722 tableEntry = (CORBBTPROF_SECTION_TABLE_ENTRY *) profileMap->getOffsetPtr(tableEntryOffset);
12723 tableEntry += secCount;
12724 tableEntry->FormatID = pSec->format;
12725 tableEntry->Data.Offset = offset;
12726 tableEntry->Data.Size = alignUpSize;
12731 // Allocate the end token marker
12735 endToken = (ULONG *) profileMap->Allocate(sizeof(ULONG));
12737 *endToken = CORBBTPROF_END_TOKEN;
12744 SectionFormat format;
12745 ProfileMap profileMap;
12748 SectionList * pSectionList;
12752 /*static*/ idTypeSpec TypeSpecBlobEntry::s_lastTypeSpecToken = idTypeSpecNil;
12753 /*static*/ idMethodSpec MethodSpecBlobEntry::s_lastMethodSpecToken = idMethodSpecNil;
12754 /*static*/ idExternalNamespace ExternalNamespaceBlobEntry::s_lastExternalNamespaceToken = idExternalNamespaceNil;
12755 /*static*/ idExternalType ExternalTypeBlobEntry::s_lastExternalTypeToken = idExternalTypeNil;
12756 /*static*/ idExternalSignature ExternalSignatureBlobEntry::s_lastExternalSignatureToken = idExternalSignatureNil;
12757 /*static*/ idExternalMethod ExternalMethodBlobEntry::s_lastExternalMethodToken = idExternalMethodNil;
12760 inline static size_t HashCombine(size_t h1, size_t h2)
12762 LIMITED_METHOD_CONTRACT;
12764 size_t result = (h1 * 129) ^ h2;
12768 bool TypeSpecBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
12770 WRAPPER_NO_CONTRACT;
12772 if (this->kind() != other->kind())
12775 const TypeSpecBlobEntry * other2 = static_cast<const TypeSpecBlobEntry *>(other);
12777 if (this->cbSig() != other2->cbSig())
12780 PCCOR_SIGNATURE p1 = this->pSig();
12781 PCCOR_SIGNATURE p2 = other2->pSig();
12783 for (DWORD i=0; (i < this->cbSig()); i++)
12784 if (p1[i] != p2[i])
12790 size_t TypeSpecBlobEntry::Hash() const
12792 WRAPPER_NO_CONTRACT;
12794 size_t hashValue = HashInit();
12796 PCCOR_SIGNATURE p1 = pSig();
12797 for (DWORD i=0; (i < cbSig()); i++)
12798 hashValue = HashCombine(hashValue, p1[i]);
12803 TypeSpecBlobEntry::TypeSpecBlobEntry(DWORD _cbSig, PCCOR_SIGNATURE _pSig)
12809 PRECONDITION(_cbSig > 0);
12810 PRECONDITION(CheckPointer(_pSig));
12814 m_token = idTypeSpecNil;
12818 COR_SIGNATURE * pNewSig = (COR_SIGNATURE *) new (nothrow) BYTE[_cbSig];
12819 if (pNewSig != NULL)
12823 memcpy(pNewSig, _pSig, _cbSig);
12825 m_pSig = const_cast<PCCOR_SIGNATURE>(pNewSig);
12828 /* static */ const TypeSpecBlobEntry * TypeSpecBlobEntry::FindOrAdd(PTR_Module pModule,
12830 PCCOR_SIGNATURE _pSig)
12839 if ((_cbSig == 0) || (_pSig == NULL))
12842 TypeSpecBlobEntry sEntry(_cbSig, _pSig);
12844 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
12845 if (pEntry == NULL)
12848 // Not Found, add a new type spec profiling blob entry
12850 TypeSpecBlobEntry * newEntry = new (nothrow) TypeSpecBlobEntry(_cbSig, _pSig);
12851 if (newEntry == NULL)
12854 newEntry->newToken(); // Assign a new ibc type spec token
12855 CONTRACT_VIOLATION(ThrowsViolation);
12856 pModule->GetProfilingBlobTable()->Add(newEntry);
12861 // Return the type spec entry that we found or the new one that we just created
12863 _ASSERTE(pEntry->kind() == ParamTypeSpec);
12864 return static_cast<const TypeSpecBlobEntry *>(pEntry);
12867 bool MethodSpecBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
12869 WRAPPER_NO_CONTRACT;
12871 if (this->kind() != other->kind())
12874 const MethodSpecBlobEntry * other2 = static_cast<const MethodSpecBlobEntry *>(other);
12876 if (this->cbSig() != other2->cbSig())
12879 PCCOR_SIGNATURE p1 = this->pSig();
12880 PCCOR_SIGNATURE p2 = other2->pSig();
12882 for (DWORD i=0; (i < this->cbSig()); i++)
12883 if (p1[i] != p2[i])
12889 size_t MethodSpecBlobEntry::Hash() const
12891 WRAPPER_NO_CONTRACT;
12893 size_t hashValue = HashInit();
12895 PCCOR_SIGNATURE p1 = pSig();
12896 for (DWORD i=0; (i < cbSig()); i++)
12897 hashValue = HashCombine(hashValue, p1[i]);
12902 MethodSpecBlobEntry::MethodSpecBlobEntry(DWORD _cbSig, PCCOR_SIGNATURE _pSig)
12908 PRECONDITION(_cbSig > 0);
12909 PRECONDITION(CheckPointer(_pSig));
12913 m_token = idMethodSpecNil;
12917 COR_SIGNATURE * pNewSig = (COR_SIGNATURE *) new (nothrow) BYTE[_cbSig];
12918 if (pNewSig != NULL)
12922 memcpy(pNewSig, _pSig, _cbSig);
12924 m_pSig = const_cast<PCCOR_SIGNATURE>(pNewSig);
12927 /* static */ const MethodSpecBlobEntry * MethodSpecBlobEntry::FindOrAdd(PTR_Module pModule,
12929 PCCOR_SIGNATURE _pSig)
12938 if ((_cbSig == 0) || (_pSig == NULL))
12941 MethodSpecBlobEntry sEntry(_cbSig, _pSig);
12943 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
12944 if (pEntry == NULL)
12947 // Not Found, add a new method spec profiling blob entry
12949 MethodSpecBlobEntry * newEntry = new (nothrow) MethodSpecBlobEntry(_cbSig, _pSig);
12950 if (newEntry == NULL)
12953 newEntry->newToken(); // Assign a new ibc method spec token
12954 CONTRACT_VIOLATION(ThrowsViolation);
12955 pModule->GetProfilingBlobTable()->Add(newEntry);
12960 // Return the method spec entry that we found or the new one that we just created
12962 _ASSERTE(pEntry->kind() == ParamMethodSpec);
12963 return static_cast<const MethodSpecBlobEntry *>(pEntry);
12966 bool ExternalNamespaceBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
12968 WRAPPER_NO_CONTRACT;
12970 if (this->kind() != other->kind())
12973 const ExternalNamespaceBlobEntry * other2 = static_cast<const ExternalNamespaceBlobEntry *>(other);
12975 if (this->cbName() != other2->cbName())
12978 LPCSTR p1 = this->pName();
12979 LPCSTR p2 = other2->pName();
12981 for (DWORD i=0; (i < this->cbName()); i++)
12982 if (p1[i] != p2[i])
12988 size_t ExternalNamespaceBlobEntry::Hash() const
12990 WRAPPER_NO_CONTRACT;
12992 size_t hashValue = HashInit();
12994 LPCSTR p1 = pName();
12995 for (DWORD i=0; (i < cbName()); i++)
12996 hashValue = HashCombine(hashValue, p1[i]);
13001 ExternalNamespaceBlobEntry::ExternalNamespaceBlobEntry(LPCSTR _pName)
13007 PRECONDITION(CheckPointer(_pName));
13011 m_token = idExternalNamespaceNil;
13015 DWORD _cbName = (DWORD) strlen(_pName) + 1;
13016 LPSTR * pName = (LPSTR *) new (nothrow) CHAR[_cbName];
13019 m_cbName = _cbName;
13020 memcpy(pName, _pName, _cbName);
13021 m_pName = (LPCSTR) pName;
13025 /* static */ const ExternalNamespaceBlobEntry * ExternalNamespaceBlobEntry::FindOrAdd(PTR_Module pModule, LPCSTR _pName)
13034 if ((_pName == NULL) || (::strlen(_pName) == 0))
13037 ExternalNamespaceBlobEntry sEntry(_pName);
13039 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
13040 if (pEntry == NULL)
13043 // Not Found, add a new external namespace blob entry
13045 ExternalNamespaceBlobEntry * newEntry = new (nothrow) ExternalNamespaceBlobEntry(_pName);
13046 if (newEntry == NULL)
13049 newEntry->newToken(); // Assign a new ibc external namespace token
13050 CONTRACT_VIOLATION(ThrowsViolation);
13051 pModule->GetProfilingBlobTable()->Add(newEntry);
13056 // Return the external namespace entry that we found or the new one that we just created
13058 _ASSERTE(pEntry->kind() == ExternalNamespaceDef);
13059 return static_cast<const ExternalNamespaceBlobEntry *>(pEntry);
13062 bool ExternalTypeBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
13064 WRAPPER_NO_CONTRACT;
13066 if (this->kind() != other->kind())
13069 const ExternalTypeBlobEntry * other2 = static_cast<const ExternalTypeBlobEntry *>(other);
13071 if (this->assemblyRef() != other2->assemblyRef())
13074 if (this->nestedClass() != other2->nestedClass())
13077 if (this->nameSpace() != other2->nameSpace())
13080 if (this->cbName() != other2->cbName())
13083 LPCSTR p1 = this->pName();
13084 LPCSTR p2 = other2->pName();
13086 for (DWORD i=0; (i < this->cbName()); i++)
13087 if (p1[i] != p2[i])
13093 size_t ExternalTypeBlobEntry::Hash() const
13095 WRAPPER_NO_CONTRACT;
13097 size_t hashValue = HashInit();
13099 hashValue = HashCombine(hashValue, assemblyRef());
13100 hashValue = HashCombine(hashValue, nestedClass());
13101 hashValue = HashCombine(hashValue, nameSpace());
13103 LPCSTR p1 = pName();
13105 for (DWORD i=0; (i < cbName()); i++)
13106 hashValue = HashCombine(hashValue, p1[i]);
13111 ExternalTypeBlobEntry::ExternalTypeBlobEntry(mdToken _assemblyRef,
13112 mdToken _nestedClass,
13113 mdToken _nameSpace,
13120 PRECONDITION(CheckPointer(_pName));
13124 m_token = idExternalTypeNil;
13125 m_assemblyRef = mdAssemblyRefNil;
13126 m_nestedClass = idExternalTypeNil;
13127 m_nameSpace = idExternalNamespaceNil;
13131 DWORD _cbName = (DWORD) strlen(_pName) + 1;
13132 LPSTR * pName = (LPSTR *) new (nothrow) CHAR[_cbName];
13135 m_assemblyRef = _assemblyRef;
13136 m_nestedClass = _nestedClass;
13137 m_nameSpace = _nameSpace;
13138 m_cbName = _cbName;
13139 memcpy(pName, _pName, _cbName);
13140 m_pName = (LPCSTR) pName;
13144 /* static */ const ExternalTypeBlobEntry * ExternalTypeBlobEntry::FindOrAdd(PTR_Module pModule,
13145 mdToken _assemblyRef,
13146 mdToken _nestedClass,
13147 mdToken _nameSpace,
13157 if ((_pName == NULL) || (::strlen(_pName) == 0))
13160 ExternalTypeBlobEntry sEntry(_assemblyRef, _nestedClass, _nameSpace, _pName);
13162 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
13163 if (pEntry == NULL)
13166 // Not Found, add a new external type blob entry
13168 ExternalTypeBlobEntry * newEntry = new (nothrow) ExternalTypeBlobEntry(_assemblyRef, _nestedClass, _nameSpace, _pName);
13169 if (newEntry == NULL)
13172 newEntry->newToken(); // Assign a new ibc external type token
13173 CONTRACT_VIOLATION(ThrowsViolation);
13174 pModule->GetProfilingBlobTable()->Add(newEntry);
13179 // Return the external type entry that we found or the new one that we just created
13181 _ASSERTE(pEntry->kind() == ExternalTypeDef);
13182 return static_cast<const ExternalTypeBlobEntry *>(pEntry);
13185 bool ExternalSignatureBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
13187 WRAPPER_NO_CONTRACT;
13189 if (this->kind() != other->kind())
13192 const ExternalSignatureBlobEntry * other2 = static_cast<const ExternalSignatureBlobEntry *>(other);
13194 if (this->cbSig() != other2->cbSig())
13197 PCCOR_SIGNATURE p1 = this->pSig();
13198 PCCOR_SIGNATURE p2 = other2->pSig();
13200 for (DWORD i=0; (i < this->cbSig()); i++)
13201 if (p1[i] != p2[i])
13207 size_t ExternalSignatureBlobEntry::Hash() const
13209 WRAPPER_NO_CONTRACT;
13211 size_t hashValue = HashInit();
13213 hashValue = HashCombine(hashValue, cbSig());
13215 PCCOR_SIGNATURE p1 = pSig();
13217 for (DWORD i=0; (i < cbSig()); i++)
13218 hashValue = HashCombine(hashValue, p1[i]);
13223 ExternalSignatureBlobEntry::ExternalSignatureBlobEntry(DWORD _cbSig, PCCOR_SIGNATURE _pSig)
13229 PRECONDITION(_cbSig > 0);
13230 PRECONDITION(CheckPointer(_pSig));
13234 m_token = idExternalSignatureNil;
13237 COR_SIGNATURE * pNewSig = (COR_SIGNATURE *) new (nothrow) BYTE[_cbSig];
13238 if (pNewSig != NULL)
13241 memcpy(pNewSig, _pSig, _cbSig);
13243 m_pSig = const_cast<PCCOR_SIGNATURE>(pNewSig);
13246 /* static */ const ExternalSignatureBlobEntry * ExternalSignatureBlobEntry::FindOrAdd(PTR_Module pModule,
13248 PCCOR_SIGNATURE _pSig)
13257 if ((_cbSig == 0) || (_pSig == NULL))
13260 ExternalSignatureBlobEntry sEntry(_cbSig, _pSig);
13262 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
13263 if (pEntry == NULL)
13266 // Not Found, add a new external signature blob entry
13268 ExternalSignatureBlobEntry * newEntry = new (nothrow) ExternalSignatureBlobEntry(_cbSig, _pSig);
13269 if (newEntry == NULL)
13272 newEntry->newToken(); // Assign a new ibc external signature token
13273 CONTRACT_VIOLATION(ThrowsViolation);
13274 pModule->GetProfilingBlobTable()->Add(newEntry);
13279 // Return the external signature entry that we found or the new one that we just created
13281 _ASSERTE(pEntry->kind() == ExternalSignatureDef);
13282 return static_cast<const ExternalSignatureBlobEntry *>(pEntry);
13285 bool ExternalMethodBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
13287 WRAPPER_NO_CONTRACT;
13289 if (this->kind() != other->kind())
13292 const ExternalMethodBlobEntry * other2 = static_cast<const ExternalMethodBlobEntry *>(other);
13294 if (this->nestedClass() != other2->nestedClass())
13297 if (this->signature() != other2->signature())
13300 if (this->cbName() != other2->cbName())
13303 LPCSTR p1 = this->pName();
13304 LPCSTR p2 = other2->pName();
13306 for (DWORD i=0; (i < this->cbName()); i++)
13307 if (p1[i] != p2[i])
13313 size_t ExternalMethodBlobEntry::Hash() const
13315 WRAPPER_NO_CONTRACT;
13317 size_t hashValue = HashInit();
13319 hashValue = HashCombine(hashValue, nestedClass());
13320 hashValue = HashCombine(hashValue, signature());
13322 LPCSTR p1 = pName();
13324 for (DWORD i=0; (i < cbName()); i++)
13325 hashValue = HashCombine(hashValue, p1[i]);
13330 ExternalMethodBlobEntry::ExternalMethodBlobEntry(mdToken _nestedClass,
13331 mdToken _signature,
13338 PRECONDITION(CheckPointer(_pName));
13342 m_token = idExternalMethodNil;
13343 m_nestedClass = idExternalTypeNil;
13344 m_signature = idExternalSignatureNil;
13347 DWORD _cbName = (DWORD) strlen(_pName) + 1;
13348 LPSTR * pName = (LPSTR *) new (nothrow) CHAR[_cbName];
13351 m_nestedClass = _nestedClass;
13352 m_signature = _signature;
13353 m_cbName = _cbName;
13354 memcpy(pName, _pName, _cbName);
13355 m_pName = (LPSTR) pName;
13359 /* static */ const ExternalMethodBlobEntry * ExternalMethodBlobEntry::FindOrAdd(
13360 PTR_Module pModule,
13361 mdToken _nestedClass,
13362 mdToken _signature,
13369 PRECONDITION(CheckPointer(_pName));
13373 if ((_pName == NULL) || (::strlen(_pName) == 0))
13376 ExternalMethodBlobEntry sEntry(_nestedClass, _signature, _pName);
13378 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
13379 if (pEntry == NULL)
13382 // Not Found, add a new external type blob entry
13384 ExternalMethodBlobEntry * newEntry;
13385 newEntry = new (nothrow) ExternalMethodBlobEntry(_nestedClass, _signature, _pName);
13386 if (newEntry == NULL)
13389 newEntry->newToken(); // Assign a new ibc external method token
13390 CONTRACT_VIOLATION(ThrowsViolation);
13391 pModule->GetProfilingBlobTable()->Add(newEntry);
13396 // Return the external method entry that we found or the new one that we just created
13398 _ASSERTE(pEntry->kind() == ExternalMethodDef);
13399 return static_cast<const ExternalMethodBlobEntry *>(pEntry);
13403 static bool GetBasename(LPCWSTR _src, __out_ecount(dstlen) __out_z LPWSTR _dst, int dstlen)
13405 LIMITED_METHOD_CONTRACT;
13406 LPCWSTR src = _src;
13409 if ((src == NULL) || (dstlen <= 0))
13412 bool inQuotes = false;
13413 LPWSTR dstLast = dst + (dstlen - 1);
13414 while (dst < dstLast)
13416 WCHAR wch = *src++;
13419 inQuotes = !inQuotes;
13430 if ((wch == W('\\')) || (wch == W(':')))
13434 else if (wch == W(' '))
13445 static void ProfileDataAllocateScenarioInfo(ProfileEmitter * pEmitter, LPCSTR scopeName, GUID* pMvid)
13452 INJECT_FAULT(COMPlusThrowOM());
13456 ProfileMap *profileMap = pEmitter->EmitNewSection(ScenarioInfo);
13459 // Allocate and initialize the scenario info section
13462 CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *siHeader;
13463 siHeader = (CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *) profileMap->Allocate(sizeof(CORBBTPROF_SCENARIO_INFO_SECTION_HEADER));
13465 siHeader->NumScenarios = 1;
13466 siHeader->TotalNumRuns = 1;
13470 // Allocate and initialize the scenario header section
13473 LPCWSTR pCmdLine = GetCommandLineW();
13474 S_SIZE_T cCmdLine = S_SIZE_T(wcslen(pCmdLine));
13476 if (cCmdLine.IsOverflow())
13478 ThrowHR(COR_E_OVERFLOW);
13481 LPCWSTR pSystemInfo = W("<machine,OS>");
13482 S_SIZE_T cSystemInfo = S_SIZE_T(wcslen(pSystemInfo));
13484 if (cSystemInfo.IsOverflow())
13486 ThrowHR(COR_E_OVERFLOW);
13489 FILETIME runTime, unused1, unused2, unused3;
13490 GetProcessTimes(GetCurrentProcess(), &runTime, &unused1, &unused2, &unused3);
13492 WCHAR scenarioName[256];
13493 GetBasename(pCmdLine, &scenarioName[0], 256);
13495 LPCWSTR pName = &scenarioName[0];
13496 S_SIZE_T cName = S_SIZE_T(wcslen(pName));
13498 if (cName.IsOverflow())
13500 ThrowHR(COR_E_OVERFLOW);
13503 S_SIZE_T sizeHeader = S_SIZE_T(sizeof(CORBBTPROF_SCENARIO_HEADER));
13504 sizeHeader += cName * S_SIZE_T(sizeof(WCHAR));
13505 if (sizeHeader.IsOverflow())
13507 ThrowHR(COR_E_OVERFLOW);
13510 S_SIZE_T sizeRun = S_SIZE_T(sizeof(CORBBTPROF_SCENARIO_RUN));
13511 sizeRun += cCmdLine * S_SIZE_T(sizeof(WCHAR));
13512 sizeRun += cSystemInfo * S_SIZE_T(sizeof(WCHAR));
13513 if (sizeRun.IsOverflow())
13515 ThrowHR(COR_E_OVERFLOW);
13519 // Allocate the Scenario Header struct
13521 SIZE_T sHeaderOffset;
13523 CORBBTPROF_SCENARIO_HEADER *sHeader;
13524 S_SIZE_T sHeaderSize = sizeHeader + sizeRun;
13525 if (sHeaderSize.IsOverflow())
13527 ThrowHR(COR_E_OVERFLOW);
13530 sHeaderOffset = profileMap->getCurrentOffset();
13531 sHeader = (CORBBTPROF_SCENARIO_HEADER *) profileMap->Allocate(sizeHeader.Value());
13533 sHeader->size = sHeaderSize.Value();
13534 sHeader->scenario.ordinal = 1;
13535 sHeader->scenario.mask = 1;
13536 sHeader->scenario.priority = 0;
13537 sHeader->scenario.numRuns = 1;
13538 sHeader->scenario.cName = cName.Value();
13539 wcscpy_s(sHeader->scenario.name, cName.Value(), pName);
13543 // Allocate the Scenario Run struct
13546 CORBBTPROF_SCENARIO_RUN *sRun;
13547 sRun = (CORBBTPROF_SCENARIO_RUN *) profileMap->Allocate(sizeRun.Value());
13549 sRun->runTime = runTime;
13550 sRun->mvid = *pMvid;
13551 sRun->cCmdLine = cCmdLine.Value();
13552 sRun->cSystemInfo = cSystemInfo.Value();
13553 wcscpy_s(sRun->cmdLine, cCmdLine.Value(), pCmdLine);
13554 wcscpy_s(sRun->cmdLine+cCmdLine.Value(), cSystemInfo.Value(), pSystemInfo);
13558 CORBBTPROF_SCENARIO_HEADER * sHeader;
13559 sHeader = (CORBBTPROF_SCENARIO_HEADER *) profileMap->getOffsetPtr(sHeaderOffset);
13560 assert(sHeader->size == sHeader->Size());
13566 static void ProfileDataAllocateMethodBlockCounts(ProfileEmitter * pEmitter, CORCOMPILE_METHOD_PROFILE_LIST * pMethodProfileListHead)
13573 INJECT_FAULT(COMPlusThrowOM());
13577 ProfileMap *profileMap = pEmitter->EmitNewSection(MethodBlockCounts);
13580 // Allocate and initialize the method block count section
13582 SIZE_T mbcHeaderOffset;
13584 CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *mbcHeader;
13585 mbcHeaderOffset = profileMap->getCurrentOffset();
13586 mbcHeader = (CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *)
13587 profileMap->Allocate(sizeof(CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER));
13588 mbcHeader->NumMethods = 0; // This gets filled in later
13591 ULONG numMethods = 0; // We count the number of methods that were executed
13593 for (CORCOMPILE_METHOD_PROFILE_LIST * methodProfileList = pMethodProfileListHead;
13595 methodProfileList = methodProfileList->next)
13597 CORBBTPROF_METHOD_HEADER * pInfo = methodProfileList->GetInfo();
13599 assert(pInfo->size == pInfo->Size());
13602 // We set methodWasExecuted based upon the ExecutionCount of the very first block
13604 bool methodWasExecuted = (pInfo->method.block[0].ExecutionCount > 0);
13607 // If the method was not executed then we don't need to output this methods block counts
13609 SIZE_T methodHeaderOffset;
13610 if (methodWasExecuted)
13612 DWORD profileDataSize = pInfo->size;
13613 methodHeaderOffset = profileMap->getCurrentOffset();
13614 CORBBTPROF_METHOD_HEADER *methodHeader = (CORBBTPROF_METHOD_HEADER *) profileMap->Allocate(profileDataSize);
13615 memcpy(methodHeader, pInfo, profileDataSize);
13619 // Reset all of the basic block counts to zero
13620 for (ULONG i=0; (i < pInfo->method.cBlock); i++ )
13623 // If methodWasExecuted is false then every block's ExecutionCount should also be zero
13625 _ASSERTE(methodWasExecuted || (pInfo->method.block[i].ExecutionCount == 0));
13627 pInfo->method.block[i].ExecutionCount = 0;
13632 CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *mbcHeader;
13633 // We have to refetch the mbcHeader as calls to Allocate will resize and thus move the mbcHeader
13634 mbcHeader = (CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *) profileMap->getOffsetPtr(mbcHeaderOffset);
13635 mbcHeader->NumMethods = numMethods;
13639 /*static*/ void Module::ProfileDataAllocateTokenLists(ProfileEmitter * pEmitter, Module::TokenProfileData* pTokenProfileData)
13646 INJECT_FAULT(COMPlusThrowOM());
13651 // Allocate and initialize the token list sections
13653 if (pTokenProfileData)
13655 for (int format = 0; format < (int)SectionFormatCount; format++)
13657 CQuickArray<CORBBTPROF_TOKEN_INFO> *pTokenArray = &(pTokenProfileData->m_formats[format].tokenArray);
13659 if (pTokenArray->Size() != 0)
13661 ProfileMap * profileMap = pEmitter->EmitNewSection((SectionFormat) format);
13663 CORBBTPROF_TOKEN_LIST_SECTION_HEADER *header;
13664 header = (CORBBTPROF_TOKEN_LIST_SECTION_HEADER *)
13665 profileMap->Allocate(sizeof(CORBBTPROF_TOKEN_LIST_SECTION_HEADER) +
13666 pTokenArray->Size() * sizeof(CORBBTPROF_TOKEN_INFO));
13668 header->NumTokens = pTokenArray->Size();
13669 memcpy( (header + 1), &((*pTokenArray)[0]), pTokenArray->Size() * sizeof(CORBBTPROF_TOKEN_INFO));
13671 // Reset the collected tokens
13672 for (unsigned i = 0; i < CORBBTPROF_TOKEN_MAX_NUM_FLAGS; i++)
13674 pTokenProfileData->m_formats[format].tokenBitmaps[i].Reset();
13676 pTokenProfileData->m_formats[format].tokenArray.ReSizeNoThrow(0);
13682 static void ProfileDataAllocateTokenDefinitions(ProfileEmitter * pEmitter, Module * pModule)
13689 INJECT_FAULT(COMPlusThrowOM());
13694 // Allocate and initialize the ibc token definition section (aka the Blob stream)
13696 ProfileMap * profileMap = pEmitter->EmitNewSection(BlobStream);
13698 // Compute the size of the metadata section:
13699 // It is the sum of all of the Metadata Profile pool entries
13700 // plus the sum of all of the Param signature entries
13702 size_t totalSize = 0;
13704 for (ProfilingBlobTable::Iterator cur = pModule->GetProfilingBlobTable()->Begin(),
13705 end = pModule->GetProfilingBlobTable()->End();
13709 const ProfilingBlobEntry * pEntry = *cur;
13710 size_t blobElementSize = pEntry->varSize();
13711 switch (pEntry->kind()) {
13712 case ParamTypeSpec:
13713 case ParamMethodSpec:
13714 blobElementSize += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
13717 case ExternalNamespaceDef:
13718 blobElementSize += sizeof(CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY);
13721 case ExternalTypeDef:
13722 blobElementSize += sizeof(CORBBTPROF_BLOB_TYPE_DEF_ENTRY);
13725 case ExternalSignatureDef:
13726 blobElementSize += sizeof(CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY);
13729 case ExternalMethodDef:
13730 blobElementSize += sizeof(CORBBTPROF_BLOB_METHOD_DEF_ENTRY);
13734 _ASSERTE(!"Unexpected blob type");
13737 totalSize += blobElementSize;
13740 profileMap->Allocate(totalSize);
13742 size_t currentPos = 0;
13744 // Traverse each element and record it
13745 size_t blobElementSize = 0;
13746 for (ProfilingBlobTable::Iterator cur = pModule->GetProfilingBlobTable()->Begin(),
13747 end = pModule->GetProfilingBlobTable()->End();
13749 cur++, currentPos += blobElementSize)
13751 const ProfilingBlobEntry * pEntry = *cur;
13752 blobElementSize = pEntry->varSize();
13753 void *profileData = profileMap->getOffsetPtr(currentPos);
13755 switch (pEntry->kind()) {
13756 case ParamTypeSpec:
13758 CORBBTPROF_BLOB_PARAM_SIG_ENTRY * bProfileData = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY*) profileData;
13759 const TypeSpecBlobEntry * typeSpecBlobEntry = static_cast<const TypeSpecBlobEntry *>(pEntry);
13761 blobElementSize += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
13762 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
13763 bProfileData->blob.type = typeSpecBlobEntry->kind();
13764 bProfileData->blob.token = typeSpecBlobEntry->token();
13765 _ASSERTE(typeSpecBlobEntry->cbSig() > 0);
13766 bProfileData->cSig = typeSpecBlobEntry->cbSig();
13767 memcpy(&bProfileData->sig[0], typeSpecBlobEntry->pSig(), typeSpecBlobEntry->cbSig());
13771 case ParamMethodSpec:
13773 CORBBTPROF_BLOB_PARAM_SIG_ENTRY * bProfileData = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY*) profileData;
13774 const MethodSpecBlobEntry * methodSpecBlobEntry = static_cast<const MethodSpecBlobEntry *>(pEntry);
13776 blobElementSize += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
13777 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
13778 bProfileData->blob.type = methodSpecBlobEntry->kind();
13779 bProfileData->blob.token = methodSpecBlobEntry->token();
13780 _ASSERTE(methodSpecBlobEntry->cbSig() > 0);
13781 bProfileData->cSig = methodSpecBlobEntry->cbSig();
13782 memcpy(&bProfileData->sig[0], methodSpecBlobEntry->pSig(), methodSpecBlobEntry->cbSig());
13786 case ExternalNamespaceDef:
13788 CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY*) profileData;
13789 const ExternalNamespaceBlobEntry * namespaceBlobEntry = static_cast<const ExternalNamespaceBlobEntry *>(pEntry);
13791 blobElementSize += sizeof(CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY);
13792 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
13793 bProfileData->blob.type = namespaceBlobEntry->kind();
13794 bProfileData->blob.token = namespaceBlobEntry->token();
13795 _ASSERTE(namespaceBlobEntry->cbName() > 0);
13796 bProfileData->cName = namespaceBlobEntry->cbName();
13797 memcpy(&bProfileData->name[0], namespaceBlobEntry->pName(), namespaceBlobEntry->cbName());
13801 case ExternalTypeDef:
13803 CORBBTPROF_BLOB_TYPE_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_TYPE_DEF_ENTRY*) profileData;
13804 const ExternalTypeBlobEntry * typeBlobEntry = static_cast<const ExternalTypeBlobEntry *>(pEntry);
13806 blobElementSize += sizeof(CORBBTPROF_BLOB_TYPE_DEF_ENTRY);
13807 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
13808 bProfileData->blob.type = typeBlobEntry->kind();
13809 bProfileData->blob.token = typeBlobEntry->token();
13810 bProfileData->assemblyRefToken = typeBlobEntry->assemblyRef();
13811 bProfileData->nestedClassToken = typeBlobEntry->nestedClass();
13812 bProfileData->nameSpaceToken = typeBlobEntry->nameSpace();
13813 _ASSERTE(typeBlobEntry->cbName() > 0);
13814 bProfileData->cName = typeBlobEntry->cbName();
13815 memcpy(&bProfileData->name[0], typeBlobEntry->pName(), typeBlobEntry->cbName());
13819 case ExternalSignatureDef:
13821 CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY*) profileData;
13822 const ExternalSignatureBlobEntry * signatureBlobEntry = static_cast<const ExternalSignatureBlobEntry *>(pEntry);
13824 blobElementSize += sizeof(CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY);
13825 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
13826 bProfileData->blob.type = signatureBlobEntry->kind();
13827 bProfileData->blob.token = signatureBlobEntry->token();
13828 _ASSERTE(signatureBlobEntry->cbSig() > 0);
13829 bProfileData->cSig = signatureBlobEntry->cbSig();
13830 memcpy(&bProfileData->sig[0], signatureBlobEntry->pSig(), signatureBlobEntry->cbSig());
13834 case ExternalMethodDef:
13836 CORBBTPROF_BLOB_METHOD_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_METHOD_DEF_ENTRY*) profileData;
13837 const ExternalMethodBlobEntry * methodBlobEntry = static_cast<const ExternalMethodBlobEntry *>(pEntry);
13839 blobElementSize += sizeof(CORBBTPROF_BLOB_METHOD_DEF_ENTRY);
13840 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
13841 bProfileData->blob.type = methodBlobEntry->kind();
13842 bProfileData->blob.token = methodBlobEntry->token();
13843 bProfileData->nestedClassToken = methodBlobEntry->nestedClass();
13844 bProfileData->signatureToken = methodBlobEntry->signature();
13845 _ASSERTE(methodBlobEntry->cbName() > 0);
13846 bProfileData->cName = methodBlobEntry->cbName();
13847 memcpy(&bProfileData->name[0], methodBlobEntry->pName(), methodBlobEntry->cbName());
13852 _ASSERTE(!"Unexpected blob type");
13857 _ASSERTE(currentPos == totalSize);
13859 // Emit a terminating entry with type EndOfBlobStream to mark the end
13860 DWORD mdElementSize = sizeof(CORBBTPROF_BLOB_ENTRY);
13861 void *profileData = profileMap->Allocate(mdElementSize);
13862 memset(profileData, 0, mdElementSize);
13864 CORBBTPROF_BLOB_ENTRY* mdProfileData = (CORBBTPROF_BLOB_ENTRY*) profileData;
13865 mdProfileData->type = EndOfBlobStream;
13866 mdProfileData->size = sizeof(CORBBTPROF_BLOB_ENTRY);
13869 // Responsible for writing out the profile data if the COMPlus_BBInstr
13870 // environment variable is set. This is called when the module is unloaded
13871 // (usually at shutdown).
13872 HRESULT Module::WriteMethodProfileDataLogFile(bool cleanup)
13880 INJECT_FAULT(return E_OUTOFMEMORY;);
13891 if (GetAssembly()->IsInstrumented() && (m_pProfilingBlobTable != NULL) && (m_tokenProfileData != NULL))
13893 ProfileEmitter * pEmitter = new ProfileEmitter();
13895 // Get this ahead of time - metadata access may be logged, which will
13896 // take the m_tokenProfileData->crst, which we take a couple lines below
13899 IfFailThrow(GetMDImport()->GetScopeProps(&pszName, &mvid));
13901 CrstHolder ch(&m_tokenProfileData->crst);
13904 // Create the scenario info section
13906 ProfileDataAllocateScenarioInfo(pEmitter, pszName, &mvid);
13909 // Create the method block count section
13911 ProfileDataAllocateMethodBlockCounts(pEmitter, m_methodProfileList);
13914 // Create the token list sections
13916 ProfileDataAllocateTokenLists(pEmitter, m_tokenProfileData);
13919 // Create the ibc token definition section (aka the Blob stream)
13921 ProfileDataAllocateTokenDefinitions(pEmitter, this);
13924 // Now store the profile data in the ibc file
13926 ProfileMap profileImage;
13927 pEmitter->Serialize(&profileImage, mvid);
13929 HandleHolder profileDataFile(OpenMethodProfileDataLogFile(mvid));
13932 BOOL result = WriteFile(profileDataFile, profileImage.getOffsetPtr(0), profileImage.getCurrentOffset(), &count, NULL);
13933 if (!result || (count != profileImage.getCurrentOffset()))
13935 DWORD lasterror = GetLastError();
13936 _ASSERTE(!"Error writing ibc profile data to file");
13937 hr = HRESULT_FROM_WIN32(lasterror);
13943 DeleteProfilingData();
13950 EX_END_CATCH(SwallowAllExceptions)
13957 void Module::WriteAllModuleProfileData(bool cleanup)
13967 // Iterate over all the app domains; for each one iterator over its
13968 // assemblies; for each one iterate over its modules.
13971 AppDomainIterator appDomainIterator(FALSE);
13972 while(appDomainIterator.Next())
13974 AppDomain * appDomain = appDomainIterator.GetDomain();
13975 AppDomain::AssemblyIterator assemblyIterator = appDomain->IterateAssembliesEx(
13976 (AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution));
13977 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
13979 while (assemblyIterator.Next(pDomainAssembly.This()))
13981 DomainModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
13984 /*hr=*/i.GetModule()->WriteMethodProfileDataLogFile(cleanup);
13991 EX_END_CATCH(SwallowAllExceptions);
13994 PTR_ProfilingBlobTable Module::GetProfilingBlobTable()
13996 LIMITED_METHOD_CONTRACT;
13997 return m_pProfilingBlobTable;
14000 void Module::CreateProfilingData()
14002 TokenProfileData *tpd = TokenProfileData::CreateNoThrow();
14004 PVOID pv = InterlockedCompareExchangeT(&m_tokenProfileData, tpd, NULL);
14010 PTR_ProfilingBlobTable ppbt = new (nothrow) ProfilingBlobTable();
14014 pv = InterlockedCompareExchangeT(&m_pProfilingBlobTable, ppbt, NULL);
14022 void Module::DeleteProfilingData()
14024 if (m_pProfilingBlobTable != NULL)
14026 for (ProfilingBlobTable::Iterator cur = m_pProfilingBlobTable->Begin(),
14027 end = m_pProfilingBlobTable->End();
14031 const ProfilingBlobEntry * pCurrentEntry = *cur;
14032 delete pCurrentEntry;
14034 delete m_pProfilingBlobTable;
14035 m_pProfilingBlobTable = NULL;
14038 if (m_tokenProfileData != NULL)
14040 delete m_tokenProfileData;
14041 m_tokenProfileData = NULL;
14044 // the metadataProfileData is free'ed in destructor of the corresponding MetaDataTracker
14046 #endif //FEATURE_PREJIT
14048 #ifdef FEATURE_MIXEDMODE
14049 void Module::SetIsIJWFixedUp()
14051 LIMITED_METHOD_CONTRACT;
14052 FastInterlockOr(&m_dwTransientFlags, IS_IJW_FIXED_UP);
14057 #ifdef FEATURE_PREJIT
14059 Module::TokenProfileData *Module::TokenProfileData::CreateNoThrow(void)
14061 STATIC_CONTRACT_NOTHROW;
14063 TokenProfileData *tpd = NULL;
14068 // This constructor calls crst.Init(), which may throw. So putting (nothrow) doesn't
14069 // do what we would want it to. Thus I wrap it here in a TRY/CATCH and revert to NULL
14072 tpd = new TokenProfileData();
14078 EX_END_CATCH(SwallowAllExceptions);
14083 #endif // FEATURE_PREJIT
14085 #endif // !DACCESS_COMPILE
14087 #ifndef DACCESS_COMPILE
14088 void Module::SetBeingUnloaded()
14090 LIMITED_METHOD_CONTRACT;
14091 FastInterlockOr((ULONG*)&m_dwTransientFlags, IS_BEING_UNLOADED);
14095 #ifdef FEATURE_PREJIT
14096 void Module::LogTokenAccess(mdToken token, SectionFormat format, ULONG flagnum)
14104 PRECONDITION(g_IBCLogger.InstrEnabled());
14105 PRECONDITION(flagnum < CORBBTPROF_TOKEN_MAX_NUM_FLAGS);
14109 #ifndef DACCESS_COMPILE
14112 // If we are in ngen instrumentation mode, then we should record this token.
14115 if (!m_nativeImageProfiling)
14118 mdToken rid = RidFromToken(token);
14119 CorTokenType tkType = (CorTokenType) TypeFromToken(token);
14120 SectionFormat tkKind = (SectionFormat) (tkType >> 24);
14122 if ((rid == 0) && (tkKind < (SectionFormat) TBL_COUNT))
14127 _ASSERTE(TypeProfilingData == FirstTokenFlagSection + TBL_TypeDef);
14128 _ASSERTE(MethodProfilingData == FirstTokenFlagSection + TBL_Method);
14129 _ASSERTE(SectionFormatCount >= FirstTokenFlagSection + TBL_COUNT + 4);
14131 if (!m_tokenProfileData)
14133 CreateProfilingData();
14136 if (!m_tokenProfileData)
14141 if (tkKind == (SectionFormat) (ibcTypeSpec >> 24))
14142 tkKind = IbcTypeSpecSection;
14143 else if (tkKind == (SectionFormat) (ibcMethodSpec >> 24))
14144 tkKind = IbcMethodSpecSection;
14146 _ASSERTE(tkKind < SectionFormatCount);
14147 if (tkKind >= SectionFormatCount)
14152 CQuickArray<CORBBTPROF_TOKEN_INFO> * pTokenArray = &m_tokenProfileData->m_formats[format].tokenArray;
14153 RidBitmap * pTokenBitmap = &m_tokenProfileData->m_formats[tkKind].tokenBitmaps[flagnum];
14155 // Have we seen this token with this flag already?
14156 if (pTokenBitmap->IsTokenInBitmap(token))
14161 // Insert the token to the bitmap
14162 if (FAILED(pTokenBitmap->InsertToken(token)))
14167 ULONG flag = 1 << flagnum;
14169 // [ToDo] Fix: this is a sequential search and can be very slow
14170 for (unsigned int i = 0; i < pTokenArray->Size(); i++)
14172 if ((*pTokenArray)[i].token == token)
14174 _ASSERTE(! ((*pTokenArray)[i].flags & flag));
14175 (*pTokenArray)[i].flags |= flag;
14180 if (FAILED(pTokenArray->ReSizeNoThrow(pTokenArray->Size() + 1)))
14185 (*pTokenArray)[pTokenArray->Size() - 1].token = token;
14186 (*pTokenArray)[pTokenArray->Size() - 1].flags = flag;
14187 (*pTokenArray)[pTokenArray->Size() - 1].scenarios = 0;
14189 #endif // !DACCESS_COMPILE
14192 void Module::LogTokenAccess(mdToken token, ULONG flagNum)
14194 WRAPPER_NO_CONTRACT;
14195 SectionFormat format = (SectionFormat)((TypeFromToken(token)>>24) + FirstTokenFlagSection);
14196 if (FirstTokenFlagSection <= format && format < SectionFormatCount)
14198 LogTokenAccess(token, format, flagNum);
14201 #endif // FEATURE_PREJIT
14203 #ifndef DACCESS_COMPILE
14204 #ifdef FEATURE_PREJIT
14207 // Encoding callbacks
14210 /*static*/ DWORD Module::EncodeModuleHelper(void * pModuleContext, Module *pReferencedModule)
14212 Module* pReferencingModule = (Module *) pModuleContext;
14213 _ASSERTE(pReferencingModule != pReferencedModule);
14215 Assembly *pReferencingAssembly = pReferencingModule->GetAssembly();
14216 Assembly *pReferencedAssembly = pReferencedModule->GetAssembly();
14218 _ASSERTE(pReferencingAssembly != pReferencedAssembly);
14220 if (pReferencedAssembly == pReferencingAssembly)
14225 mdAssemblyRef token = pReferencingModule->FindAssemblyRef(pReferencedAssembly);
14227 if (IsNilToken(token))
14229 return ENCODE_MODULE_FAILED;
14232 return RidFromToken(token);
14235 /*static*/ void Module::TokenDefinitionHelper(void* pModuleContext, Module *pReferencedModule, DWORD index, mdToken* pToken)
14237 LIMITED_METHOD_CONTRACT;
14239 Module * pReferencingModule = (Module *) pModuleContext;
14240 mdAssemblyRef mdAssemblyRef = TokenFromRid(index, mdtAssemblyRef);
14241 IMDInternalImport * pImport = pReferencedModule->GetMDImport();
14242 LPCUTF8 szName = NULL;
14244 if (TypeFromToken(*pToken) == mdtTypeDef)
14247 // Compute nested type (if any)
14249 mdTypeDef mdEnclosingType = idExternalTypeNil;
14250 hr = pImport->GetNestedClassProps(*pToken, &mdEnclosingType);
14251 // If there's not enclosing type, then hr=CLDB_E_RECORD_NOTFOUND and mdEnclosingType is unchanged
14252 _ASSERTE((hr == S_OK) || (hr == CLDB_E_RECORD_NOTFOUND));
14254 if (!IsNilToken(mdEnclosingType))
14256 _ASSERT(TypeFromToken(mdEnclosingType) == mdtTypeDef);
14257 TokenDefinitionHelper(pModuleContext, pReferencedModule, index, &mdEnclosingType);
14259 _ASSERT(TypeFromToken(mdEnclosingType) == ibcExternalType);
14262 // Compute type name and namespace.
14264 LPCUTF8 szNamespace = NULL;
14265 hr = pImport->GetNameOfTypeDef(*pToken, &szName, &szNamespace);
14266 _ASSERTE(hr == S_OK);
14269 // Transform namespace string into ibc external namespace token
14271 idExternalNamespace idNamespace = idExternalNamespaceNil;
14272 if (szNamespace != NULL)
14274 const ExternalNamespaceBlobEntry * pNamespaceEntry;
14275 pNamespaceEntry = ExternalNamespaceBlobEntry::FindOrAdd(pReferencingModule, szNamespace);
14276 if (pNamespaceEntry != NULL)
14278 idNamespace = pNamespaceEntry->token();
14281 _ASSERTE(TypeFromToken(idNamespace) == ibcExternalNamespace);
14284 // Transform type name into ibc external type token
14286 idExternalType idType = idExternalTypeNil;
14287 _ASSERTE(szName != NULL);
14288 const ExternalTypeBlobEntry * pTypeEntry = NULL;
14289 pTypeEntry = ExternalTypeBlobEntry::FindOrAdd(pReferencingModule,
14294 if (pTypeEntry != NULL)
14296 idType = pTypeEntry->token();
14298 _ASSERTE(TypeFromToken(idType) == ibcExternalType);
14300 *pToken = idType; // Remap pToken to our idExternalType token
14302 else if (TypeFromToken(*pToken) == mdtMethodDef)
14305 // Compute nested type (if any)
14307 mdTypeDef mdEnclosingType = idExternalTypeNil;
14308 hr = pImport->GetParentToken(*pToken, &mdEnclosingType);
14309 _ASSERTE(!FAILED(hr));
14311 if (!IsNilToken(mdEnclosingType))
14313 _ASSERT(TypeFromToken(mdEnclosingType) == mdtTypeDef);
14314 TokenDefinitionHelper(pModuleContext, pReferencedModule, index, &mdEnclosingType);
14316 _ASSERT(TypeFromToken(mdEnclosingType) == ibcExternalType);
14319 // Compute the method name and signature
14321 PCCOR_SIGNATURE pSig = NULL;
14323 hr = pImport->GetNameAndSigOfMethodDef(*pToken, &pSig, &cbSig, &szName);
14324 _ASSERTE(hr == S_OK);
14327 // Transform signature into ibc external signature token
14329 idExternalSignature idSignature = idExternalSignatureNil;
14332 const ExternalSignatureBlobEntry * pSignatureEntry;
14333 pSignatureEntry = ExternalSignatureBlobEntry::FindOrAdd(pReferencingModule, cbSig, pSig);
14334 if (pSignatureEntry != NULL)
14336 idSignature = pSignatureEntry->token();
14339 _ASSERTE(TypeFromToken(idSignature) == ibcExternalSignature);
14342 // Transform method name into ibc external method token
14344 idExternalMethod idMethod = idExternalMethodNil;
14345 _ASSERTE(szName != NULL);
14346 const ExternalMethodBlobEntry * pMethodEntry = NULL;
14347 pMethodEntry = ExternalMethodBlobEntry::FindOrAdd(pReferencingModule,
14351 if (pMethodEntry != NULL)
14353 idMethod = pMethodEntry->token();
14355 _ASSERTE(TypeFromToken(idMethod) == ibcExternalMethod);
14357 *pToken = idMethod; // Remap pToken to our idMethodSpec token
14361 _ASSERTE(!"Unexpected token type");
14365 idTypeSpec Module::LogInstantiatedType(TypeHandle typeHnd, ULONG flagNum)
14367 CONTRACT(idTypeSpec)
14372 PRECONDITION(g_IBCLogger.InstrEnabled());
14373 PRECONDITION(!typeHnd.HasUnrestoredTypeKey());
14374 // We want to report the type only in its own loader module as a type's
14375 // MethodTable can only live in its own loader module.
14376 // We can relax this if we allow a (duplicate) MethodTable to live
14377 // in any module (which might be needed for ngen of generics)
14378 #ifdef FEATURE_PREJIT
14379 PRECONDITION(this == GetPreferredZapModuleForTypeHandle(typeHnd));
14384 idTypeSpec result = idTypeSpecNil;
14386 if (m_nativeImageProfiling)
14388 CONTRACT_VIOLATION(ThrowsViolation|FaultViolation|GCViolation);
14390 SigBuilder sigBuilder;
14392 ZapSig zapSig(this, this, ZapSig::IbcTokens,
14393 Module::EncodeModuleHelper, Module::TokenDefinitionHelper);
14394 BOOL fSuccess = zapSig.GetSignatureForTypeHandle(typeHnd, &sigBuilder);
14396 // a return value of 0 indicates a failure to create the signature
14400 PCCOR_SIGNATURE pSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cbSig);
14402 ULONG flag = (1 << flagNum);
14403 TypeSpecBlobEntry * pEntry = const_cast<TypeSpecBlobEntry *>(TypeSpecBlobEntry::FindOrAdd(this, cbSig, pSig));
14404 if (pEntry != NULL)
14406 // Update the flags with any new bits
14407 pEntry->orFlag(flag);
14408 result = pEntry->token();
14412 _ASSERTE(TypeFromToken(result) == ibcTypeSpec);
14417 idMethodSpec Module::LogInstantiatedMethod(const MethodDesc * md, ULONG flagNum)
14419 CONTRACT(idMethodSpec)
14424 PRECONDITION( md != NULL );
14428 idMethodSpec result = idMethodSpecNil;
14430 if (m_nativeImageProfiling)
14432 CONTRACT_VIOLATION(ThrowsViolation|FaultViolation|GCViolation);
14435 SigBuilder sigBuilder;
14438 fSuccess = ZapSig::EncodeMethod(const_cast<MethodDesc *>(md), this, &sigBuilder,
14440 (ENCODEMODULE_CALLBACK) Module::EncodeModuleHelper,
14441 (DEFINETOKEN_CALLBACK) Module::TokenDefinitionHelper);
14446 BYTE * pBlob = (BYTE *)sigBuilder.GetSignature(&dataSize);
14448 ULONG flag = (1 << flagNum);
14449 MethodSpecBlobEntry * pEntry = const_cast<MethodSpecBlobEntry *>(MethodSpecBlobEntry::FindOrAdd(this, dataSize, pBlob));
14450 if (pEntry != NULL)
14452 // Update the flags with any new bits
14453 pEntry->orFlag(flag);
14454 result = pEntry->token();
14459 _ASSERTE(TypeFromToken(result) == ibcMethodSpec);
14462 #endif // DACCESS_COMPILE
14463 #endif //FEATURE_PREJIT
14465 #ifndef DACCESS_COMPILE
14467 #ifndef CROSSGEN_COMPILE
14468 // ===========================================================================
14469 // ReflectionModule
14470 // ===========================================================================
14473 ReflectionModule *ReflectionModule::Create(Assembly *pAssembly, PEFile *pFile, AllocMemTracker *pamTracker, LPCWSTR szName, BOOL fIsTransient)
14475 CONTRACT(ReflectionModule *)
14478 PRECONDITION(CheckPointer(pAssembly));
14479 PRECONDITION(CheckPointer(pFile));
14480 PRECONDITION(pFile->IsDynamic());
14481 POSTCONDITION(CheckPointer(RETVAL));
14485 // Hoist CONTRACT into separate routine because of EX incompatibility
14488 #ifdef FEATURE_MULTIMODULE_ASSEMBLIES
14489 if (pFile->IsAssembly())
14492 token = ((PEModule *)pFile)->GetToken();
14494 _ASSERTE(pFile->IsAssembly());
14498 // Initial memory block for Modules must be zero-initialized (to make it harder
14499 // to introduce Destruct crashes arising from OOM's during initialization.)
14501 void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(ReflectionModule))));
14502 ReflectionModuleHolder pModule(new (pMemory) ReflectionModule(pAssembly, token, pFile));
14504 pModule->DoInit(pamTracker, szName);
14506 // Set this at module creation time. The m_fIsTransient field should never change during the lifetime of this ReflectionModule.
14507 pModule->SetIsTransient(fIsTransient ? true : false);
14509 RETURN pModule.Extract();
14513 // Module initialization occurs in two phases: the constructor phase and the Initialize phase.
14515 // The constructor phase initializes just enough so that Destruct() can be safely called.
14516 // It cannot throw or fail.
14518 ReflectionModule::ReflectionModule(Assembly *pAssembly, mdFile token, PEFile *pFile)
14519 : Module(pAssembly, token, pFile)
14529 m_pInMemoryWriter = NULL;
14530 m_sdataSection = NULL;
14531 m_pISymUnmanagedWriter = NULL;
14532 m_pCreatingAssembly = NULL;
14533 m_pCeeFileGen = NULL;
14534 m_pDynamicMetadata = NULL;
14535 m_fSuppressMetadataCapture = false;
14536 m_fIsTransient = false;
14539 HRESULT STDMETHODCALLTYPE CreateICeeGen(REFIID riid, void **pCeeGen);
14541 // Module initialization occurs in two phases: the constructor phase and the Initialize phase.
14543 // The Initialize() phase completes the initialization after the constructor has run.
14544 // It can throw exceptions but whether it throws or succeeds, it must leave the Module
14545 // in a state where Destruct() can be safely called.
14547 void ReflectionModule::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
14553 PRECONDITION(szName != NULL);
14557 Module::Initialize(pamTracker);
14559 IfFailThrow(CreateICeeGen(IID_ICeeGen, (void **)&m_pCeeFileGen));
14561 // Collectible modules should try to limit the growth of their associate IL section, as common scenarios for collectible
14562 // modules include single type modules
14563 if (IsCollectible())
14565 ReleaseHolder<ICeeGenInternal> pCeeGenInternal(NULL);
14566 IfFailThrow(m_pCeeFileGen->QueryInterface(IID_ICeeGenInternal, (void **)&pCeeGenInternal));
14567 IfFailThrow(pCeeGenInternal->SetInitialGrowth(CEE_FILE_GEN_GROWTH_COLLECTIBLE));
14570 m_pInMemoryWriter = new RefClassWriter();
14572 IfFailThrow(m_pInMemoryWriter->Init(GetCeeGen(), GetEmitter(), szName));
14574 m_CrstLeafLock.Init(CrstLeafLock);
14577 void ReflectionModule::Destruct()
14587 delete m_pInMemoryWriter;
14589 if (m_pISymUnmanagedWriter)
14591 m_pISymUnmanagedWriter->Close();
14592 m_pISymUnmanagedWriter->Release();
14593 m_pISymUnmanagedWriter = NULL;
14597 m_pCeeFileGen->Release();
14599 Module::Destruct();
14601 delete m_pDynamicMetadata;
14602 m_pDynamicMetadata = NULL;
14604 m_CrstLeafLock.Destroy();
14607 // Returns true iff metadata capturing is suppressed.
14610 // This is during the window after code:ReflectionModule.SuppressMetadataCapture and before
14611 // code:ReflectionModule.ResumeMetadataCapture.
14613 // If metadata updates are suppressed, then class-load notifications should be suppressed too.
14614 bool ReflectionModule::IsMetadataCaptureSuppressed()
14616 return m_fSuppressMetadataCapture;
14619 // Holder of changed value of MDUpdateMode via IMDInternalEmit::SetMDUpdateMode.
14620 // Returns back the original value on release.
14622 class MDUpdateModeHolder
14625 MDUpdateModeHolder()
14627 m_pInternalEmitter = NULL;
14628 m_OriginalMDUpdateMode = ULONG_MAX;
14630 ~MDUpdateModeHolder()
14632 WRAPPER_NO_CONTRACT;
14635 HRESULT SetMDUpdateMode(IMetaDataEmit *pEmitter, ULONG updateMode)
14637 LIMITED_METHOD_CONTRACT;
14640 _ASSERTE(updateMode != ULONG_MAX);
14642 IfFailRet(pEmitter->QueryInterface(IID_IMDInternalEmit, (void **)&m_pInternalEmitter));
14643 _ASSERTE(m_pInternalEmitter != NULL);
14645 IfFailRet(m_pInternalEmitter->SetMDUpdateMode(updateMode, &m_OriginalMDUpdateMode));
14646 _ASSERTE(m_OriginalMDUpdateMode != ULONG_MAX);
14650 HRESULT Release(ULONG expectedPreviousUpdateMode = ULONG_MAX)
14654 if (m_OriginalMDUpdateMode != ULONG_MAX)
14656 _ASSERTE(m_pInternalEmitter != NULL);
14657 ULONG previousUpdateMode;
14658 // Ignore the error when releasing
14659 hr = m_pInternalEmitter->SetMDUpdateMode(m_OriginalMDUpdateMode, &previousUpdateMode);
14660 m_OriginalMDUpdateMode = ULONG_MAX;
14662 if (expectedPreviousUpdateMode != ULONG_MAX)
14664 if ((hr == S_OK) && (expectedPreviousUpdateMode != previousUpdateMode))
14670 if (m_pInternalEmitter != NULL)
14672 (void)m_pInternalEmitter->Release();
14673 m_pInternalEmitter = NULL;
14677 ULONG GetOriginalMDUpdateMode()
14679 WRAPPER_NO_CONTRACT;
14680 _ASSERTE(m_OriginalMDUpdateMode != LONG_MAX);
14681 return m_OriginalMDUpdateMode;
14684 IMDInternalEmit *m_pInternalEmitter;
14685 ULONG m_OriginalMDUpdateMode;
14688 // Called in live paths to fetch metadata for dynamic modules. This makes the metadata available to the
14689 // debugger from out-of-process.
14692 // This buffer can be retrieved by the debugger via code:ReflectionModule.GetDynamicMetadataBuffer
14695 // - Callers must ensure nobody else is adding to the metadata.
14696 // - This function still takes its own locks to cooperate with the Debugger's out-of-process access.
14697 // The debugger can slip this thread outside the locks to ensure the data is consistent.
14699 // This does not raise a debug notification to invalidate the metadata. Reasoning is that this only
14700 // happens in two cases:
14701 // 1) manifest module is updated with the name of a new dynamic module.
14702 // 2) on each class load, in which case we already send a debug event. In this case, we already send a
14703 // class-load notification, so sending a separate "metadata-refresh" would make the eventing twice as
14704 // chatty. Class-load events are high-volume and events are slow.
14705 // Thus we can avoid the chatiness by ensuring the debugger knows that Class-load also means "refresh
14708 void ReflectionModule::CaptureModuleMetaDataToMemory()
14717 // If we've suppresed metadata capture, then skip this. We'll recapture when we enable it. This allows
14718 // for batching up capture.
14719 // If a debugger is attached, then the CLR will still send ClassLoad notifications for dynamic modules,
14720 // which mean we still need to keep the metadata available. This is the same as Whidbey.
14721 // An alternative (and better) design would be to suppress ClassLoad notifications too, but then we'd
14722 // need some way of sending a "catchup" notification to the debugger after we re-enable notifications.
14723 if (IsMetadataCaptureSuppressed() && !CORDebuggerAttached())
14728 // Do not release the emitter. This is a weak reference.
14729 IMetaDataEmit *pEmitter = this->GetEmitter();
14730 _ASSERTE(pEmitter != NULL);
14734 MDUpdateModeHolder hMDUpdateMode;
14735 IfFailThrow(hMDUpdateMode.SetMDUpdateMode(pEmitter, MDUpdateExtension));
14736 _ASSERTE(hMDUpdateMode.GetOriginalMDUpdateMode() == MDUpdateFull);
14739 hr = pEmitter->GetSaveSize(cssQuick, &numBytes);
14742 // Operate on local data, and then persist it into the module once we know it's valid.
14743 NewHolder<SBuffer> pBuffer(new SBuffer());
14744 _ASSERTE(pBuffer != NULL); // allocation would throw first
14746 // ReflectionModule is still in a consistent state, and now we're just operating on local data to
14747 // assemble the new metadata buffer. If this fails, then worst case is that metadata does not include
14748 // recently generated classes.
14750 // Caller ensures serialization that guarantees that the metadata doesn't grow underneath us.
14751 BYTE * pRawData = pBuffer->OpenRawBuffer(numBytes);
14752 hr = pEmitter->SaveToMemory(pRawData, numBytes);
14753 pBuffer->CloseRawBuffer();
14757 // Now that we're successful, transfer ownership back into the module.
14759 CrstHolder ch(&m_CrstLeafLock);
14761 delete m_pDynamicMetadata;
14763 m_pDynamicMetadata = pBuffer.Extract();
14768 hr = hMDUpdateMode.Release(MDUpdateExtension);
14769 // Will be S_FALSE if someone changed the MDUpdateMode (from MDUpdateExtension) meanwhile
14770 _ASSERTE(hr == S_OK);
14773 // Suppress the eager metadata serialization.
14776 // This casues code:ReflectionModule.CaptureModuleMetaDataToMemory to be a nop.
14777 // This is not nestable.
14778 // This exists purely for performance reasons.
14780 // Don't call this directly. Use a SuppressMetadataCaptureHolder holder to ensure it's
14781 // balanced with code:ReflectionModule.ResumeMetadataCapture
14783 // Types generating while eager metadata-capture is suppressed should not actually be executed until
14784 // after metadata capture is restored.
14785 void ReflectionModule::SuppressMetadataCapture()
14787 LIMITED_METHOD_CONTRACT;
14788 // If this fires, then you probably missed a call to ResumeMetadataCapture.
14789 CONSISTENCY_CHECK_MSG(!m_fSuppressMetadataCapture, "SuppressMetadataCapture is not nestable");
14790 m_fSuppressMetadataCapture = true;
14793 // Resumes eager metadata serialization.
14796 // This casues code:ReflectionModule.CaptureModuleMetaDataToMemory to resume eagerly serializing metadata.
14797 // This must be called after code:ReflectionModule.SuppressMetadataCapture.
14799 void ReflectionModule::ResumeMetadataCapture()
14801 WRAPPER_NO_CONTRACT;
14802 _ASSERTE(m_fSuppressMetadataCapture);
14803 m_fSuppressMetadataCapture = false;
14805 CaptureModuleMetaDataToMemory();
14808 void ReflectionModule::ReleaseILData()
14810 WRAPPER_NO_CONTRACT;
14812 if (m_pISymUnmanagedWriter)
14814 m_pISymUnmanagedWriter->Release();
14815 m_pISymUnmanagedWriter = NULL;
14818 Module::ReleaseILData();
14820 #endif // !CROSSGEN_COMPILE
14822 #endif // !DACCESS_COMPILE
14824 #ifdef DACCESS_COMPILE
14825 // Accessor to expose m_pDynamicMetadata to debugger.
14828 // Pointer to SBuffer containing metadata buffer. May be null.
14831 // Only used by the debugger, so only accessible via DAC.
14832 // The buffer is updated via code:ReflectionModule.CaptureModuleMetaDataToMemory
14833 PTR_SBuffer ReflectionModule::GetDynamicMetadataBuffer() const
14837 // If we ask for metadata, but have been suppressing capture, then we're out of date.
14838 // However, the debugger may be debugging already baked types in the module and so may need the metadata
14839 // for that. So we return what we do have.
14841 // Debugger will get the next metadata update:
14842 // 1) with the next load class
14843 // 2) or if this is right after the last class, see code:ReflectionModule.CaptureModuleMetaDataToMemory
14845 return m_pDynamicMetadata;
14849 TADDR ReflectionModule::GetIL(RVA il) // virtual
14851 #ifndef DACCESS_COMPILE
14852 WRAPPER_NO_CONTRACT;
14854 BYTE* pByte = NULL;
14855 m_pCeeFileGen->GetMethodBuffer(il, &pByte);
14856 return TADDR(pByte);
14857 #else // DACCESS_COMPILE
14861 #endif // DACCESS_COMPILE
14864 PTR_VOID ReflectionModule::GetRvaField(RVA field, BOOL fZapped) // virtual
14866 _ASSERTE(!fZapped);
14867 #ifndef DACCESS_COMPILE
14868 WRAPPER_NO_CONTRACT;
14869 // This function should be call only if the target is a field or a field with RVA.
14870 PTR_BYTE pByte = NULL;
14871 m_pCeeFileGen->ComputePointer(m_sdataSection, field, &pByte);
14872 return dac_cast<PTR_VOID>(pByte);
14873 #else // DACCESS_COMPILE
14877 #endif // DACCESS_COMPILE
14880 #ifndef DACCESS_COMPILE
14882 // ===========================================================================
14884 // ===========================================================================
14886 //==========================================================================
14887 // Enregisters a VASig.
14888 //==========================================================================
14889 VASigCookie *Module::GetVASigCookie(Signature vaSignature)
14891 CONTRACT(VASigCookie*)
14897 POSTCONDITION(CheckPointer(RETVAL));
14898 INJECT_FAULT(COMPlusThrowOM());
14902 VASigCookieBlock *pBlock;
14903 VASigCookie *pCookie;
14907 // First, see if we already enregistered this sig.
14908 // Note that we're outside the lock here, so be a bit careful with our logic
14909 for (pBlock = m_pVASigCookieBlock; pBlock != NULL; pBlock = pBlock->m_Next)
14911 for (UINT i = 0; i < pBlock->m_numcookies; i++)
14913 if (pBlock->m_cookies[i].signature.GetRawSig() == vaSignature.GetRawSig())
14915 pCookie = &(pBlock->m_cookies[i]);
14923 // If not, time to make a new one.
14925 // Compute the size of args first, outside of the lock.
14927 // @TODO GENERICS: We may be calling a varargs method from a
14928 // generic type/method. Using an empty context will make such a
14929 // case cause an unexpected exception. To make this work,
14930 // we need to create a specialized signature for every instantiation
14931 SigTypeContext typeContext;
14933 MetaSig metasig(vaSignature, this, &typeContext);
14934 ArgIterator argit(&metasig);
14936 // Upper estimate of the vararg size
14937 DWORD sizeOfArgs = argit.SizeOfArgStack();
14939 // enable gc before taking lock
14941 CrstHolder ch(&m_Crst);
14943 // Note that we were possibly racing to create the cookie, and another thread
14944 // may have already created it. We could put another check
14945 // here, but it's probably not worth the effort, so we'll just take an
14946 // occasional duplicate cookie instead.
14948 // Is the first block in the list full?
14949 if (m_pVASigCookieBlock && m_pVASigCookieBlock->m_numcookies
14950 < VASigCookieBlock::kVASigCookieBlockSize)
14952 // Nope, reserve a new slot in the existing block.
14953 pCookie = &(m_pVASigCookieBlock->m_cookies[m_pVASigCookieBlock->m_numcookies]);
14957 // Yes, create a new block.
14958 VASigCookieBlock *pNewBlock = new VASigCookieBlock();
14960 pNewBlock->m_Next = m_pVASigCookieBlock;
14961 pNewBlock->m_numcookies = 0;
14962 m_pVASigCookieBlock = pNewBlock;
14963 pCookie = &(pNewBlock->m_cookies[0]);
14966 // Now, fill in the new cookie (assuming we had enough memory to create one.)
14967 pCookie->pModule = this;
14968 pCookie->pNDirectILStub = NULL;
14969 pCookie->sizeOfArgs = sizeOfArgs;
14970 pCookie->signature = vaSignature;
14972 // Finally, now that it's safe for ansynchronous readers to see it,
14973 // update the count.
14974 m_pVASigCookieBlock->m_numcookies++;
14981 // ===========================================================================
14983 // ===========================================================================
14984 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
14986 int __cdecl LookupMapBase::HotItem::Cmp(const void* a_, const void* b_)
14988 LIMITED_METHOD_CONTRACT;
14989 const HotItem *a = (const HotItem *)a_;
14990 const HotItem *b = (const HotItem *)b_;
14992 if (a->rid < b->rid)
14994 else if (a->rid > b->rid)
15000 void LookupMapBase::CreateHotItemList(DataImage *image, CorProfileData *profileData, int table, BOOL fSkipNullEntries /*= FALSE*/)
15002 STANDARD_VM_CONTRACT;
15003 _ASSERTE(!MapIsCompressed());
15007 DWORD numInTokenList = profileData->GetHotTokens(table, 1<<RidMap, 1<<RidMap, NULL, 0);
15009 if (numInTokenList > 0)
15011 HotItem *itemList = (HotItem*)(void*)image->GetModule()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(HotItem)) * S_SIZE_T(numInTokenList));
15012 mdToken *tokenList = (mdToken*)(void*)image->GetModule()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(mdToken)) * S_SIZE_T(numInTokenList));
15014 profileData->GetHotTokens(table, 1<<RidMap, 1<<RidMap, tokenList, numInTokenList);
15015 DWORD numItems = 0;
15016 for (DWORD i = 0; i < numInTokenList; i++)
15018 DWORD rid = RidFromToken(tokenList[i]);
15019 TADDR value = RelativePointer<TADDR>::GetValueMaybeNullAtPtr(dac_cast<TADDR>(GetElementPtr(RidFromToken(tokenList[i]))));
15020 if (!fSkipNullEntries || value != NULL)
15022 itemList[numItems].rid = rid;
15023 itemList[numItems].value = value;
15030 qsort(itemList, // start of array
15031 numItems, // array size in elements
15032 sizeof(HotItem), // element size in bytes
15033 HotItem::Cmp); // comparer function
15035 // Eliminate any duplicates in the list. Due to the qsort, they must be adjacent now.
15036 // We do this by walking the array and copying entries that are not duplicates of the previous one.
15037 // We can start the loop at +1, because 0 is not a duplicate of the previous entry, and does not
15038 // need to be copied either.
15040 for (DWORD i = 1; i < numItems; i++)
15042 if (itemList[i].rid != itemList[i-1].rid)
15044 itemList[j].rid = itemList[i].rid;
15045 itemList[j].value = itemList[i].value;
15049 _ASSERTE(j <= numItems);
15052 // We have treated the values as normal TADDRs to let qsort move them around freely.
15053 // Fix them up to be the relative pointers now.
15054 for (DWORD ii = 0; ii < numItems; ii++)
15056 if (itemList[ii].value != NULL)
15057 RelativePointer<TADDR>::SetValueMaybeNullAtPtr(dac_cast<TADDR>(&itemList[ii].value), itemList[ii].value);
15060 if (itemList != NULL)
15061 image->StoreStructure(itemList, sizeof(HotItem)*numItems,
15062 DataImage::ITEM_RID_MAP_HOT);
15064 hotItemList = itemList;
15065 dwNumHotItems = numItems;
15071 void LookupMapBase::Save(DataImage *image, DataImage::ItemKind kind, CorProfileData *profileData, int table, BOOL fCopyValues /*= FALSE*/)
15073 STANDARD_VM_CONTRACT;
15075 // 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
15079 hotItemList = NULL;
15083 // Because we use the same IBC encoding to record a touch to the m_GenericTypeDefToCanonMethodTableMap as
15084 // to the m_TypeDefToMethodTableMap, the hot items we get in both will be the union of the touches. This limitation
15085 // in the IBC infrastructure does not hurt us much because touching an entry for a generic type in one map often if
15086 // not always implies touching the corresponding entry in the other. But when saving the GENERICTYPEDEF_MAP it
15087 // does mean that we need to be prepared to see "hot" items whose data is NULL in this map (specifically, the non-
15088 // generic types). We don't want the hot list to be unnecessarily big with these entries, so tell CreateHotItemList to
15090 BOOL fSkipNullEntries = (kind == DataImage::ITEM_GENERICTYPEDEF_MAP);
15091 CreateHotItemList(image, profileData, table, fSkipNullEntries);
15094 // Determine whether we want to compress this lookup map (to improve density of cold pages in the map on
15095 // hot item cache misses). We only enable this optimization for the TypeDefToMethodTable, the
15096 // GenericTypeDefToCanonMethodTable, and the MethodDefToDesc maps since (a) they're the largest and
15097 // as a result reap the most space savings and (b) these maps are fully populated in an ngen image and immutable
15098 // at runtime, something that's important when dealing with a compressed version of the table.
15099 if (kind == DataImage::ITEM_TYPEDEF_MAP || kind == DataImage::ITEM_GENERICTYPEDEF_MAP || kind == DataImage::ITEM_METHODDEF_MAP)
15101 // The bulk of the compression work is done in the later stages of ngen image generation (since it
15102 // relies on knowing the final RVAs of each value stored in the table). So we create a specialzed
15103 // ZapNode that knows how to perform the compression for us.
15104 image->StoreCompressedLayoutMap(this, DataImage::ITEM_COMPRESSED_MAP);
15106 // We need to know we decided to compress during the Fixup stage but the table kind is not available
15107 // there. So we use the cIndexEntryBits field as a flag (this will be initialized to zero and is only
15108 // set to a meaningful value near the end of ngen image generation, during the compression of the
15110 cIndexEntryBits = 1;
15112 // The ZapNode we allocated above takes care of all the rest of the processing for this map, so we're
15117 SaveUncompressedMap(image, kind, fCopyValues);
15120 void LookupMapBase::SaveUncompressedMap(DataImage *image, DataImage::ItemKind kind, BOOL fCopyValues /*= FALSE*/)
15122 STANDARD_VM_CONTRACT;
15124 // We should only be calling this once per map
15125 _ASSERTE(!image->IsStored(pTable));
15128 // We will only store one (big) node instead of the full list,
15129 // and make the one node large enough to fit all the RIDs
15132 ZapStoredStructure * pTableNode = image->StoreStructure(NULL, GetSize() * sizeof(TADDR), kind);
15134 LookupMapBase *map = this;
15135 DWORD offsetIntoCombo = 0;
15136 while (map != NULL)
15138 DWORD len = map->dwCount * sizeof(void*);
15141 image->CopyDataToOffset(pTableNode, offsetIntoCombo, map->pTable, len);
15143 image->BindPointer(map->pTable,pTableNode,offsetIntoCombo);
15144 offsetIntoCombo += len;
15149 void LookupMapBase::ConvertSavedMapToUncompressed(DataImage *image, DataImage::ItemKind kind)
15151 STANDARD_VM_CONTRACT;
15153 // Check whether we decided to compress this map (see Save() above).
15154 if (cIndexEntryBits == 0)
15157 cIndexEntryBits = 0;
15158 SaveUncompressedMap(image, kind);
15161 void LookupMapBase::Fixup(DataImage *image, BOOL fFixupEntries /*=TRUE*/)
15163 STANDARD_VM_CONTRACT;
15165 if (hotItemList != NULL)
15166 image->FixupPointerField(this, offsetof(LookupMapBase, hotItemList));
15168 // Find the biggest RID supported by the entire list of LookupMaps.
15169 // We will only store one LookupMap node instead of the full list,
15170 // and make it big enough to fit all RIDs.
15171 *(DWORD *)image->GetImagePointer(this, offsetof(LookupMapBase, dwCount)) = GetSize();
15173 // Persist the supportedFlags that this particular instance was created with.
15174 *(TADDR *)image->GetImagePointer(this, offsetof(LookupMapBase, supportedFlags)) = supportedFlags;
15176 image->ZeroPointerField(this, offsetof(LookupMapBase, pNext));
15178 // Check whether we've decided to compress this map (see Save() above).
15179 if (cIndexEntryBits == 1)
15181 // In the compressed case most of the Fixup logic is performed by the specialized ZapNode we allocated
15182 // during Save(). But we still have to record fixups for any hot items we've cached (these aren't
15184 for (DWORD i = 0; i < dwNumHotItems; i++)
15186 TADDR *pHotValueLoc = &hotItemList[i].value;
15187 TADDR pHotValue = RelativePointer<TADDR>::GetValueMaybeNullAtPtr((TADDR)pHotValueLoc);
15188 TADDR flags = pHotValue & supportedFlags;
15189 pHotValue -= flags;
15191 if (image->IsStored((PVOID)pHotValue))
15193 image->FixupField(hotItemList,
15194 (BYTE *)pHotValueLoc - (BYTE *)hotItemList,
15195 (PVOID)pHotValue, flags, IMAGE_REL_BASED_RelativePointer);
15199 image->ZeroPointerField(hotItemList, (BYTE *)pHotValueLoc - (BYTE *)hotItemList);
15203 // The ZapNode will handle everything else so we're done.
15207 // Note that the caller is responsible for calling FixupPointerField()
15208 // or zeroing out the contents of pTable as appropriate
15209 image->FixupPointerField(this, offsetof(LookupMapBase, pTable));
15213 LookupMap<PVOID>::Iterator iter((LookupMap<PVOID> *)this);
15216 while (iter.Next())
15219 PVOID p = iter.GetElementAndFlags(&flags);
15220 PTR_TADDR hotItemValuePtr = FindHotItemValuePtr(rid);
15222 if (image->IsStored(p))
15224 image->FixupField(pTable, rid * sizeof(TADDR),
15225 p, flags, IMAGE_REL_BASED_RelativePointer);
15227 // In case this item is also in the hot item subtable, fix it up there as well
15228 if (hotItemValuePtr != NULL)
15229 image->FixupField(hotItemList,
15230 (BYTE *)hotItemValuePtr - (BYTE *)hotItemList,
15231 p, flags, IMAGE_REL_BASED_RelativePointer);
15235 image->ZeroPointerField(pTable, rid * sizeof(TADDR));
15236 // In case this item is also in the hot item subtable, zero it there as well
15237 if (hotItemValuePtr != NULL)
15238 image->ZeroPointerField(hotItemList,
15239 (BYTE *)hotItemValuePtr - (BYTE *)hotItemList);
15246 #endif // FEATURE_NATIVE_IMAGE_GENERATION
15248 #endif // !DACCESS_COMPILE
15250 #ifdef DACCESS_COMPILE
15253 LookupMapBase::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
15269 DacEnumHostDPtrMem(this);
15271 if (pTable.IsValid())
15273 #ifdef FEATURE_PREJIT
15274 if (MapIsCompressed())
15276 // Compressed maps have tables whose size cannot be calculated cheaply. Plus they have an
15277 // additional index blob.
15278 DacEnumMemoryRegion(dac_cast<TADDR>(pTable),
15280 DacEnumMemoryRegion(dac_cast<TADDR>(pIndex),
15284 #endif // FEATURE_PREJIT
15285 DacEnumMemoryRegion(dac_cast<TADDR>(pTable),
15286 dwCount * sizeof(TADDR));
15288 #ifdef FEATURE_PREJIT
15289 if (dwNumHotItems && hotItemList.IsValid())
15291 DacEnumMemoryRegion(dac_cast<TADDR>(hotItemList),
15292 dwNumHotItems * sizeof(HotItem));
15294 #endif // FEATURE_PREJIT
15300 LookupMapBase::ListEnumMemoryRegions(CLRDataEnumMemoryFlags flags)
15312 LookupMapBase * headMap = this;
15313 bool enumHead = false;
15316 headMap->EnumMemoryRegions(flags, enumHead);
15318 if (!headMap->pNext.IsValid())
15323 headMap = headMap->pNext;
15328 #endif // DACCESS_COMPILE
15331 // Optimization intended for Module::IsIntrospectionOnly and Module::EnsureActive only
15332 #include <optsmallperfcritical.h>
15334 BOOL Module::IsIntrospectionOnly()
15336 WRAPPER_NO_CONTRACT;
15337 return GetAssembly()->IsIntrospectionOnly();
15340 #ifndef DACCESS_COMPILE
15341 VOID Module::EnsureActive()
15350 GetDomainFile()->EnsureActive();
15352 #endif // DACCESS_COMPILE
15354 #include <optdefault.h>
15357 #ifndef DACCESS_COMPILE
15359 VOID Module::EnsureAllocated()
15369 GetDomainFile()->EnsureAllocated();
15372 VOID Module::EnsureLibraryLoaded()
15374 STANDARD_VM_CONTRACT;
15375 GetDomainFile()->EnsureLibraryLoaded();
15377 #endif // !DACCESS_COMPILE
15379 CHECK Module::CheckActivated()
15389 #ifndef DACCESS_COMPILE
15390 DomainFile *pDomainFile = FindDomainFile(GetAppDomain());
15391 CHECK(pDomainFile != NULL);
15392 PREFIX_ASSUME(pDomainFile != NULL);
15393 CHECK(pDomainFile->CheckActivated());
15398 #ifdef DACCESS_COMPILE
15401 ModuleCtorInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
15405 // This class is contained so do not enumerate 'this'.
15406 DacEnumMemoryRegion(dac_cast<TADDR>(ppMT), numElements *
15408 DacEnumMemoryRegion(dac_cast<TADDR>(cctorInfoHot), numElementsHot *
15409 sizeof(ClassCtorInfoEntry));
15410 DacEnumMemoryRegion(dac_cast<TADDR>(cctorInfoCold),
15411 (numElements - numElementsHot) *
15412 sizeof(ClassCtorInfoEntry));
15413 DacEnumMemoryRegion(dac_cast<TADDR>(hotHashOffsets), numHotHashes *
15415 DacEnumMemoryRegion(dac_cast<TADDR>(coldHashOffsets), numColdHashes *
15419 void Module::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
15436 EMEM_OUT(("MEM: %p Module\n", dac_cast<TADDR>(this)));
15439 //Save module id data only if it a real pointer, not a tagged sugestion to use ModuleIndex.
15440 if (!Module::IsEncodedModuleIndex(GetModuleID()))
15442 if (m_ModuleID.IsValid())
15444 m_ModuleID->EnumMemoryRegions(flags);
15448 // TODO: Enumerate DomainLocalModules? It's not clear if we need all AppDomains
15449 // in the multi-domain case (where m_ModuleID has it's low-bit set).
15450 if (m_file.IsValid())
15452 m_file->EnumMemoryRegions(flags);
15454 if (m_pAssembly.IsValid())
15456 m_pAssembly->EnumMemoryRegions(flags);
15459 m_TypeRefToMethodTableMap.ListEnumMemoryRegions(flags);
15460 m_TypeDefToMethodTableMap.ListEnumMemoryRegions(flags);
15462 if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
15464 if (m_pAvailableClasses.IsValid())
15466 m_pAvailableClasses->EnumMemoryRegions(flags);
15468 if (m_pAvailableParamTypes.IsValid())
15470 m_pAvailableParamTypes->EnumMemoryRegions(flags);
15472 if (m_pInstMethodHashTable.IsValid())
15474 m_pInstMethodHashTable->EnumMemoryRegions(flags);
15476 if (m_pAvailableClassesCaseIns.IsValid())
15478 m_pAvailableClassesCaseIns->EnumMemoryRegions(flags);
15480 #ifdef FEATURE_PREJIT
15481 if (m_pStubMethodHashTable.IsValid())
15483 m_pStubMethodHashTable->EnumMemoryRegions(flags);
15485 #endif // FEATURE_PREJIT
15486 #ifdef FEATURE_MIXEDMODE
15487 if (m_pThunkHeap.IsValid())
15489 m_pThunkHeap->EnumMemoryRegions(flags);
15491 #endif // FEATURE_MIXEDMODE
15492 if (m_pBinder.IsValid())
15494 m_pBinder->EnumMemoryRegions(flags);
15496 m_ModuleCtorInfo.EnumMemoryRegions(flags);
15498 // Save the LookupMap structures.
15499 m_MethodDefToDescMap.ListEnumMemoryRegions(flags);
15500 m_FieldDefToDescMap.ListEnumMemoryRegions(flags);
15501 m_pMemberRefToDescHashTable->EnumMemoryRegions(flags);
15502 m_GenericParamToDescMap.ListEnumMemoryRegions(flags);
15503 m_GenericTypeDefToCanonMethodTableMap.ListEnumMemoryRegions(flags);
15504 m_FileReferencesMap.ListEnumMemoryRegions(flags);
15505 m_ManifestModuleReferencesMap.ListEnumMemoryRegions(flags);
15506 m_MethodDefToPropertyInfoMap.ListEnumMemoryRegions(flags);
15508 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
15509 while (typeDefIter.Next())
15511 if (typeDefIter.GetElement())
15513 typeDefIter.GetElement()->EnumMemoryRegions(flags);
15517 LookupMap<PTR_TypeRef>::Iterator typeRefIter(&m_TypeRefToMethodTableMap);
15518 while (typeRefIter.Next())
15520 if (typeRefIter.GetElement())
15522 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(typeRefIter.GetElement()));
15523 th.EnumMemoryRegions(flags);
15527 LookupMap<PTR_MethodDesc>::Iterator methodDefIter(&m_MethodDefToDescMap);
15528 while (methodDefIter.Next())
15530 if (methodDefIter.GetElement())
15532 methodDefIter.GetElement()->EnumMemoryRegions(flags);
15536 LookupMap<PTR_FieldDesc>::Iterator fieldDefIter(&m_FieldDefToDescMap);
15537 while (fieldDefIter.Next())
15539 if (fieldDefIter.GetElement())
15541 fieldDefIter.GetElement()->EnumMemoryRegions(flags);
15545 LookupMap<PTR_TypeVarTypeDesc>::Iterator genericParamIter(&m_GenericParamToDescMap);
15546 while (genericParamIter.Next())
15548 if (genericParamIter.GetElement())
15550 genericParamIter.GetElement()->EnumMemoryRegions(flags);
15554 LookupMap<PTR_MethodTable>::Iterator genericTypeDefIter(&m_GenericTypeDefToCanonMethodTableMap);
15555 while (genericTypeDefIter.Next())
15557 if (genericTypeDefIter.GetElement())
15559 genericTypeDefIter.GetElement()->EnumMemoryRegions(flags);
15563 } // !CLRDATA_ENUM_MEM_MINI && !CLRDATA_ENUM_MEM_TRIAGE
15566 LookupMap<PTR_Module>::Iterator fileRefIter(&m_FileReferencesMap);
15567 while (fileRefIter.Next())
15569 if (fileRefIter.GetElement())
15571 fileRefIter.GetElement()->EnumMemoryRegions(flags, true);
15575 LookupMap<PTR_Module>::Iterator asmRefIter(&m_ManifestModuleReferencesMap);
15576 while (asmRefIter.Next())
15578 if (asmRefIter.GetElement())
15580 asmRefIter.GetElement()->GetAssembly()->EnumMemoryRegions(flags);
15584 ECall::EnumFCallMethods();
15587 FieldDesc *Module::LookupFieldDef(mdFieldDef token)
15589 WRAPPER_NO_CONTRACT;
15590 _ASSERTE(TypeFromToken(token) == mdtFieldDef);
15591 g_IBCLogger.LogRidMapAccess( MakePair( this, token ) );
15592 return m_FieldDefToDescMap.GetElement(RidFromToken(token));
15595 #endif // DACCESS_COMPILE
15598 #if !defined(DACCESS_COMPILE) && defined(FEATURE_CER)
15600 // Access to CerPrepInfo, the structure used to track CERs prepared at runtime (as opposed to ngen time). GetCerPrepInfo will
15601 // return the structure associated with the given method desc if it exists or NULL otherwise. CreateCerPrepInfo will get the
15602 // structure if it exists or allocate and return a new struct otherwise. Creation of CerPrepInfo structures is automatically
15603 // synchronized by the CerCrst (lazily allocated as needed).
15604 CerPrepInfo *Module::GetCerPrepInfo(MethodDesc *pMD)
15612 PRECONDITION(CheckPointer(pMD));
15616 if (m_pCerPrepInfo == NULL)
15619 // Don't need a crst for read only access to the hash table.
15621 if (m_pCerPrepInfo->GetValue(pMD, &sDatum))
15622 return (CerPrepInfo*)sDatum;
15627 CerPrepInfo *Module::CreateCerPrepInfo(MethodDesc *pMD)
15634 PRECONDITION(CheckPointer(pMD));
15638 // Lazily allocate a Crst to serialize update access to the info structure.
15639 // Carefully synchronize to ensure we don't leak a Crst in race conditions.
15640 if (m_pCerCrst == NULL)
15642 Crst *pCrst = new Crst(CrstCer);
15643 if (InterlockedCompareExchangeT(&m_pCerCrst, pCrst, NULL) != NULL)
15647 CrstHolder sCrstHolder(m_pCerCrst);
15649 // Lazily allocate the info structure.
15650 if (m_pCerPrepInfo == NULL)
15652 LockOwner sLock = {m_pCerCrst, IsOwnerOfCrst};
15653 NewHolder <EEPtrHashTable> tempCerPrepInfo (new EEPtrHashTable());
15654 if (!tempCerPrepInfo->Init(CER_DEFAULT_HASH_SIZE, &sLock))
15656 m_pCerPrepInfo = tempCerPrepInfo.Extract ();
15660 // Try getting an existing value first.
15662 if (m_pCerPrepInfo->GetValue(pMD, &sDatum))
15663 return (CerPrepInfo*)sDatum;
15666 // We get here if there was no info structure or no existing method desc entry. Either way we now have an info structure and
15667 // need to create a new method desc entry.
15668 NewHolder<CerPrepInfo> pInfo(new CerPrepInfo());
15670 m_pCerPrepInfo->InsertValue(pMD, (HashDatum)pInfo);
15672 return pInfo.Extract();
15675 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
15676 // Access to CerNgenRootTable which holds holds information for all the CERs rooted at a method in this module (that were
15677 // discovered during an ngen).
15679 // Add a list of MethodContextElements representing a CER to the root table keyed by the MethodDesc* of the root method. Creates
15680 // or expands the root table as necessary. This should only be called during ngen (at runtime we only read the table).
15681 void Module::AddCerListToRootTable(MethodDesc *pRootMD, MethodContextElement *pList)
15686 PRECONDITION(IsCompilationProcess());
15690 // Although this is only called during ngen we still get cases where a module comes through here already ngen'd (because of
15691 // ngen's habit of letting code execute during compilation). Until that's fixed we'll just back out if the module has already
15692 // fixed the root table into unwriteable storage.
15693 if (m_pCerNgenRootTable && !(m_dwTransientFlags & M_CER_ROOT_TABLE_ON_HEAP))
15696 // Lazily allocate a Crst to serialize update access to the info structure.
15697 // Carefully synchronize to ensure we don't leak a Crst in race conditions.
15698 if (m_pCerCrst == NULL)
15700 Crst *pCrst = new Crst(CrstCer);
15701 if (InterlockedCompareExchangeT(&m_pCerCrst, pCrst, NULL) != NULL)
15705 CrstHolder sCrstHolder(m_pCerCrst);
15707 // Lazily allocate the root table structure.
15708 if (m_pCerNgenRootTable == NULL)
15710 FastInterlockOr(&m_dwTransientFlags, M_CER_ROOT_TABLE_ON_HEAP);
15711 m_pCerNgenRootTable = new CerNgenRootTable();
15714 _ASSERTE(m_dwTransientFlags & M_CER_ROOT_TABLE_ON_HEAP);
15716 // And add the new element.
15717 m_pCerNgenRootTable->AddRoot(pRootMD, pList);
15719 #endif // FEATURE_NATIVE_IMAGE_GENERATION
15721 #ifdef FEATURE_PREJIT
15722 // Returns true if the given method is a CER root detected at ngen time.
15723 bool Module::IsNgenCerRootMethod(MethodDesc *pMD)
15733 _ASSERTE(pMD->GetModule() == this);
15734 if (m_pCerNgenRootTable)
15735 return m_pCerNgenRootTable->IsNgenRootMethod(pMD);
15739 // Restores the CER rooted at this method (no-op if this method isn't a CER root).
15740 void Module::RestoreCer(MethodDesc *pMD)
15742 STANDARD_VM_CONTRACT;
15743 _ASSERTE(pMD->GetModule() == this);
15744 if (m_pCerNgenRootTable)
15745 m_pCerNgenRootTable->Restore(pMD);
15748 #endif // FEATURE_PREJIT
15750 #endif // !DACCESS_COMPILE && FEATURE_CER
15754 //-------------------------------------------------------------------------------
15755 // Make best-case effort to obtain an image name for use in an error message.
15757 // This routine must expect to be called before the this object is fully loaded.
15758 // It can return an empty if the name isn't available or the object isn't initialized
15759 // enough to get a name, but it mustn't crash.
15760 //-------------------------------------------------------------------------------
15761 LPCWSTR Module::GetPathForErrorMessages()
15767 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
15771 PEFile *pFile = GetFile();
15775 return pFile->GetPathForErrorMessages();
15783 #ifndef DACCESS_COMPILE
15784 BOOL IsVerifiableWrapper(MethodDesc* pMD)
15787 //EX_TRY contains _alloca, so I can't use this inside of a loop. 4wesome.
15790 ret = pMD->IsVerifiable();
15794 //if the method has a security exception, it will fly through IsVerifiable. Shunt
15795 //to the unverifiable path below.
15797 EX_END_CATCH(RethrowTerminalExceptions)
15800 #endif //DACCESS_COMPILE
15801 void Module::VerifyAllMethods()
15810 #ifndef DACCESS_COMPILE
15811 //If the EE isn't started yet, it's not safe to jit. We fail in COM jitting a p/invoke.
15817 static bool VerifyMethodsForTypeDef(Module * pModule, mdTypeDef td)
15820 TypeHandle th = ClassLoader::LoadTypeDefThrowing(pModule, td, ClassLoader::ThrowIfNotFound,
15821 ClassLoader::PermitUninstDefOrRef);
15823 MethodTable * pMT = th.GetMethodTable();
15824 MethodTable::MethodIterator it(pMT);
15825 for (; it.IsValid(); it.Next())
15827 MethodDesc * pMD = it.GetMethodDesc();
15828 if (pMD->HasILHeader() && Security::IsMethodTransparent(pMD)
15829 && (g_pObjectCtorMD != pMD))
15831 if (!IsVerifiableWrapper(pMD))
15835 if (LoggingOn(LF_VERIFIER, LL_ERROR))
15836 TypeString::AppendMethodDebug(s, pMD);
15837 LOG((LF_VERIFIER, LL_ERROR, "Transparent Method (0x%p), %S is unverifiable\n",
15838 pMD, s.GetUnicode()));
15847 //Verify all methods in a module eagerly, forcing them to get loaded.
15849 /* XXX Thu 4/26/2007
15850 * This code is lifted mostly from Validator.cpp
15852 IMDInternalImport * pMDI = GetMDImport();
15853 HENUMTypeDefInternalHolder hEnum(pMDI);
15855 hEnum.EnumTypeDefInit();
15857 bool isAllVerifiable = true;
15858 //verify global methods
15859 if (GetGlobalMethodTable())
15861 //verify everything in the MT.
15862 if (!Local::VerifyMethodsForTypeDef(this, COR_GLOBAL_PARENT_TOKEN))
15863 isAllVerifiable = false;
15865 while (pMDI->EnumTypeDefNext(&hEnum, &td))
15867 //verify everything
15868 if (!Local::VerifyMethodsForTypeDef(this, td))
15869 isAllVerifiable = false;
15871 if (!isAllVerifiable)
15872 EEFileLoadException::Throw(GetFile(), COR_E_VERIFICATION);
15873 #endif //DACCESS_COMPILE
15877 #if defined(_DEBUG) && !defined(DACCESS_COMPILE) && !defined(CROSS_COMPILE)
15878 void Module::ExpandAll()
15888 //This is called from inside EEStartupHelper, so it breaks the SO rules. However, this is debug only
15889 //(and only supported for limited jit testing), so it's ok here.
15890 CONTRACT_VIOLATION(SOToleranceViolation);
15892 //If the EE isn't started yet, it's not safe to jit. We fail in COM jitting a p/invoke.
15897 static void CompileMethodDesc(MethodDesc * pMD)
15899 //Must have a method body
15900 if (pMD->HasILHeader()
15901 //Can't jit open instantiations
15902 && !pMD->IsGenericMethodDefinition()
15903 //These are the only methods we can jit
15904 && (pMD->IsStatic() || pMD->GetNumGenericMethodArgs() == 0
15905 || pMD->HasClassInstantiation())
15906 && (pMD->MayHaveNativeCode() && !pMD->IsFCallOrIntrinsic()))
15908 COR_ILMETHOD * ilHeader = pMD->GetILHeader();
15909 COR_ILMETHOD_DECODER::DecoderStatus ignored;
15910 NewHolder<COR_ILMETHOD_DECODER> pHeader(new COR_ILMETHOD_DECODER(ilHeader,
15911 pMD->GetMDImport(),
15913 #ifdef FEATURE_INTERPRETER
15914 pMD->MakeJitWorker(pHeader, CORJIT_FLAGS(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE));
15916 pMD->MakeJitWorker(pHeader, CORJIT_FLAGS());
15920 static void CompileMethodsForMethodTable(MethodTable * pMT)
15922 MethodTable::MethodIterator it(pMT);
15923 for (; it.IsValid(); it.Next())
15925 MethodDesc * pMD = it.GetMethodDesc();
15926 CompileMethodDesc(pMD);
15930 static void CompileMethodsForTypeDef(Module * pModule, mdTypeDef td)
15932 TypeHandle th = ClassLoader::LoadTypeDefThrowing(pModule, td, ClassLoader::ThrowIfNotFound,
15933 ClassLoader::PermitUninstDefOrRef);
15935 MethodTable * pMT = th.GetMethodTable();
15936 CompileMethodsForMethodTable(pMT);
15939 static void CompileMethodsForTypeDefRefSpec(Module * pModule, mdToken tok)
15946 th = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
15949 NULL /*SigTypeContext*/);
15953 hr = GET_EXCEPTION()->GetHR();
15955 EX_END_CATCH(SwallowAllExceptions);
15957 //Only do this for non-generic types and unshared generic types
15958 //(canonical generics and value type generic instantiations).
15959 if (SUCCEEDED(hr) && !th.IsTypeDesc()
15960 && th.AsMethodTable()->IsCanonicalMethodTable())
15962 CompileMethodsForMethodTable(th.AsMethodTable());
15965 static void CompileMethodsForMethodDefRefSpec(Module * pModule, mdToken tok)
15971 MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(pModule, tok,
15972 /*SigTypeContext*/NULL,
15974 CompileMethodDesc(pMD);
15978 hr = GET_EXCEPTION()->GetHR();
15979 //@telesto what should we do with this HR? the Silverlight code doesn't seem
15980 //to do anything...but that doesn't seem safe...
15982 EX_END_CATCH(SwallowAllExceptions);
15985 //Jit all methods eagerly
15987 /* XXX Thu 4/26/2007
15988 * This code is lifted mostly from code:Module::VerifyAllMethods
15990 IMDInternalImport * pMDI = GetMDImport();
15991 HENUMTypeDefInternalHolder hEnum(pMDI);
15993 hEnum.EnumTypeDefInit();
15995 //verify global methods
15996 if (GetGlobalMethodTable())
15998 //jit everything in the MT.
15999 Local::CompileMethodsForTypeDefRefSpec(this, COR_GLOBAL_PARENT_TOKEN);
16001 while (pMDI->EnumTypeDefNext(&hEnum, &td))
16004 Local::CompileMethodsForTypeDefRefSpec(this, td);
16007 //Get the type refs. They're always awesome.
16008 HENUMInternalHolder hEnumTypeRefs(pMDI);
16011 hEnumTypeRefs.EnumAllInit(mdtTypeRef);
16012 while (hEnumTypeRefs.EnumNext(&tr))
16014 Local::CompileMethodsForTypeDefRefSpec(this, tr);
16017 //make sure to get the type specs
16018 HENUMInternalHolder hEnumTypeSpecs(pMDI);
16021 hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
16022 while (hEnumTypeSpecs.EnumNext(&ts))
16024 Local::CompileMethodsForTypeDefRefSpec(this, ts);
16028 //And now for the interesting generic methods
16029 HENUMInternalHolder hEnumMethodSpecs(pMDI);
16032 hEnumMethodSpecs.EnumAllInit(mdtMethodSpec);
16033 while (hEnumMethodSpecs.EnumNext(&ms))
16035 Local::CompileMethodsForMethodDefRefSpec(this, ms);
16038 #endif //_DEBUG && !DACCESS_COMPILE && !CROSS_COMPILE
16040 //-------------------------------------------------------------------------------
16042 // Verify consistency of asmconstants.h
16044 // Wrap all C_ASSERT's in asmconstants.h with a class definition. Many of the
16045 // fields referenced below are private, and this class is a friend of the
16046 // enclosing type. (A C_ASSERT isn't a compiler intrinsic, just a magic
16047 // typedef that produces a compiler error when the condition is false.)
16048 #include "clrvarargs.h" /* for VARARG C_ASSERTs in asmconstants.h */
16049 class CheckAsmOffsets
16051 #define ASMCONSTANTS_C_ASSERT(cond) \
16052 typedef char UNIQUE_LABEL(__C_ASSERT__)[(cond) ? 1 : -1];
16053 #include "asmconstants.h"
16056 //-------------------------------------------------------------------------------
16058 #ifndef DACCESS_COMPILE
16060 void Module::CreateAssemblyRefByNameTable(AllocMemTracker *pamTracker)
16066 INJECT_FAULT(COMPlusThrowOM(););
16070 LoaderHeap * pHeap = GetLoaderAllocator()->GetLowFrequencyHeap();
16071 IMDInternalImport * pImport = GetMDImport();
16073 DWORD dwMaxRid = pImport->GetCountWithTokenKind(mdtAssemblyRef);
16077 S_SIZE_T dwAllocSize = S_SIZE_T(sizeof(LPWSTR)) * S_SIZE_T(dwMaxRid);
16078 m_AssemblyRefByNameTable = (LPCSTR *) pamTracker->Track( pHeap->AllocMem(dwAllocSize) );
16081 for (DWORD rid=1; rid <= dwMaxRid; rid++)
16083 mdAssemblyRef mdToken = TokenFromRid(rid,mdtAssemblyRef);
16087 hr = pImport->GetAssemblyRefProps(mdToken, NULL, NULL, &szName, NULL, NULL, NULL, NULL);
16091 m_AssemblyRefByNameTable[dwCount++] = szName;
16094 m_AssemblyRefByNameCount = dwCount;
16097 bool Module::HasReferenceByName(LPCUTF8 pModuleName)
16099 LIMITED_METHOD_CONTRACT;
16101 for (DWORD i=0; i < m_AssemblyRefByNameCount; i++)
16103 if (0 == strcmp(pModuleName, m_AssemblyRefByNameTable[i]))
16112 #pragma warning(pop)
16113 #endif // _MSC_VER: warning C4244
16115 #if defined(_DEBUG) && !defined(DACCESS_COMPILE)
16116 NOINLINE void NgenForceFailure_AV()
16118 LIMITED_METHOD_CONTRACT;
16119 static int* alwaysNull = 0;
16123 NOINLINE void NgenForceFailure_TypeLoadException()
16125 WRAPPER_NO_CONTRACT;
16126 ::ThrowTypeLoadException("ForceIBC", "Failure", W("Assembly"), NULL, IDS_CLASSLOAD_BADFORMAT);
16129 void EEConfig::DebugCheckAndForceIBCFailure(BitForMask bitForMask)
16138 static DWORD s_ibcCheckCount = 0;
16140 // Both of these must be set to non-zero values for us to force a failure
16142 if ((NgenForceFailureCount() == 0) || (NgenForceFailureKind() == 0))
16145 // The bitForMask value must also beset in the FailureMask
16147 if ((((DWORD) bitForMask) & NgenForceFailureMask()) == 0)
16151 if (s_ibcCheckCount < NgenForceFailureCount())
16154 // We force one failure every NgenForceFailureCount()
16156 s_ibcCheckCount = 0;
16157 switch (NgenForceFailureKind())
16160 NgenForceFailure_TypeLoadException();
16163 NgenForceFailure_AV();
16167 #endif // defined(_DEBUG) && !defined(DACCESS_COMPILE)