1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4// ===========================================================================
5// File: CEELOAD.CPP
6//
7
8//
9
10// CEELOAD reads in the PE file format using LoadLibrary
11// ===========================================================================
12
13
14#include "common.h"
15
16#include "array.h"
17#include "ceeload.h"
18#include "hash.h"
19#include "vars.hpp"
20#include "reflectclasswriter.h"
21#include "method.hpp"
22#include "stublink.h"
23#include "cgensys.h"
24#include "excep.h"
25#include "dbginterface.h"
26#include "dllimport.h"
27#include "eeprofinterfaces.h"
28#include "perfcounters.h"
29#include "encee.h"
30#include "jitinterface.h"
31#include "eeconfig.h"
32#include "dllimportcallback.h"
33#include "contractimpl.h"
34#include "typehash.h"
35#include "instmethhash.h"
36#include "virtualcallstub.h"
37#include "typestring.h"
38#include "stringliteralmap.h"
39#include <formattype.h>
40#include "fieldmarshaler.h"
41#include "sigbuilder.h"
42#include "metadataexports.h"
43#include "inlinetracking.h"
44#include "threads.h"
45
46#ifdef FEATURE_PREJIT
47#include "exceptionhandling.h"
48#include "corcompile.h"
49#include "compile.h"
50#include "nibblestream.h"
51#include "zapsig.h"
52#endif //FEATURE_PREJIT
53
54#ifdef FEATURE_COMINTEROP
55#include "runtimecallablewrapper.h"
56#include "comcallablewrapper.h"
57#endif //FEATURE_COMINTEROP
58
59#ifdef _MSC_VER
60#pragma warning(push)
61#pragma warning(disable:4724)
62#endif // _MSC_VER
63
64#include "ngenhash.inl"
65
66#ifdef _MSC_VER
67#pragma warning(pop)
68#endif // _MSC_VER
69
70
71#include "perflog.h"
72#include "ecall.h"
73#include "../md/compiler/custattr.h"
74#include "typekey.h"
75#include "peimagelayout.inl"
76#include "ildbsymlib.h"
77
78
79#if defined(PROFILING_SUPPORTED)
80#include "profilermetadataemitvalidator.h"
81#endif
82
83#ifdef _MSC_VER
84#pragma warning(push)
85#pragma warning(disable:4244)
86#endif // _MSC_VER
87
88#ifdef _TARGET_64BIT_
89#define COR_VTABLE_PTRSIZED COR_VTABLE_64BIT
90#define COR_VTABLE_NOT_PTRSIZED COR_VTABLE_32BIT
91#else // !_TARGET_64BIT_
92#define COR_VTABLE_PTRSIZED COR_VTABLE_32BIT
93#define COR_VTABLE_NOT_PTRSIZED COR_VTABLE_64BIT
94#endif // !_TARGET_64BIT_
95
96#define CEE_FILE_GEN_GROWTH_COLLECTIBLE 2048
97
98#define NGEN_STATICS_ALLCLASSES_WERE_LOADED -1
99
100BOOL Module::HasInlineTrackingMap()
101{
102 LIMITED_METHOD_DAC_CONTRACT;
103#ifdef FEATURE_READYTORUN
104 if (IsReadyToRun() && GetReadyToRunInfo()->GetInlineTrackingMap() != NULL)
105 {
106 return TRUE;
107 }
108#endif
109 return (m_pPersistentInlineTrackingMapNGen != NULL);
110}
111
112COUNT_T Module::GetInliners(PTR_Module inlineeOwnerMod, mdMethodDef inlineeTkn, COUNT_T inlinersSize, MethodInModule inliners[], BOOL *incompleteData)
113{
114 WRAPPER_NO_CONTRACT;
115#ifdef FEATURE_READYTORUN
116 if(IsReadyToRun() && GetReadyToRunInfo()->GetInlineTrackingMap() != NULL)
117 {
118 return GetReadyToRunInfo()->GetInlineTrackingMap()->GetInliners(inlineeOwnerMod, inlineeTkn, inlinersSize, inliners, incompleteData);
119 }
120#endif
121 if(m_pPersistentInlineTrackingMapNGen != NULL)
122 {
123 return m_pPersistentInlineTrackingMapNGen->GetInliners(inlineeOwnerMod, inlineeTkn, inlinersSize, inliners, incompleteData);
124 }
125 return 0;
126}
127
128
129#ifndef DACCESS_COMPILE
130
131
132
133// ===========================================================================
134// Module
135// ===========================================================================
136
137//---------------------------------------------------------------------------------------------------
138// This wrapper just invokes the real initialization inside a try/hook.
139// szName is not null only for dynamic modules
140//---------------------------------------------------------------------------------------------------
141void Module::DoInit(AllocMemTracker *pamTracker, LPCWSTR szName)
142{
143 CONTRACTL
144 {
145 INSTANCE_CHECK;
146 STANDARD_VM_CHECK;
147 }
148 CONTRACTL_END;
149
150#ifdef PROFILING_SUPPORTED
151 {
152 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
153 GCX_COOP();
154 g_profControlBlock.pProfInterface->ModuleLoadStarted((ModuleID) this);
155 END_PIN_PROFILER();
156 }
157 // Need TRY/HOOK instead of holder so we can get HR of exception thrown for profiler callback
158 EX_TRY
159#endif
160 {
161 Initialize(pamTracker, szName);
162 }
163#ifdef PROFILING_SUPPORTED
164
165
166 EX_HOOK
167 {
168 {
169 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
170 g_profControlBlock.pProfInterface->ModuleLoadFinished((ModuleID) this, GET_EXCEPTION()->GetHR());
171 END_PIN_PROFILER();
172 }
173 }
174 EX_END_HOOK;
175
176#endif
177}
178
179// Set the given bit on m_dwTransientFlags. Return true if we won the race to set the bit.
180BOOL Module::SetTransientFlagInterlocked(DWORD dwFlag)
181{
182 LIMITED_METHOD_CONTRACT;
183
184 for (;;)
185 {
186 DWORD dwTransientFlags = m_dwTransientFlags;
187 if ((dwTransientFlags & dwFlag) != 0)
188 return FALSE;
189 if ((DWORD)FastInterlockCompareExchange((LONG*)&m_dwTransientFlags, dwTransientFlags | dwFlag, dwTransientFlags) == dwTransientFlags)
190 return TRUE;
191 }
192}
193
194#if PROFILING_SUPPORTED
195void Module::NotifyProfilerLoadFinished(HRESULT hr)
196{
197 CONTRACTL
198 {
199 INSTANCE_CHECK;
200 THROWS;
201 GC_TRIGGERS;
202 INJECT_FAULT(COMPlusThrowOM());
203 MODE_ANY;
204 }
205 CONTRACTL_END;
206
207 // Note that in general we wil reuse shared modules. So we need to make sure we only notify
208 // the profiler once.
209 if (SetTransientFlagInterlocked(IS_PROFILER_NOTIFIED))
210 {
211 // Record how many types are already present
212 DWORD countTypesOrig = 0;
213 DWORD countExportedTypesOrig = 0;
214 if (!IsResource())
215 {
216 countTypesOrig = GetMDImport()->GetCountWithTokenKind(mdtTypeDef);
217 countExportedTypesOrig = GetMDImport()->GetCountWithTokenKind(mdtExportedType);
218 }
219
220 // Notify the profiler, this may cause metadata to be updated
221 {
222 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
223 {
224 GCX_PREEMP();
225 g_profControlBlock.pProfInterface->ModuleLoadFinished((ModuleID) this, hr);
226
227 if (SUCCEEDED(hr))
228 {
229 g_profControlBlock.pProfInterface->ModuleAttachedToAssembly((ModuleID) this,
230 (AssemblyID)m_pAssembly);
231 }
232 }
233 END_PIN_PROFILER();
234 }
235
236 // If there are more types than before, add these new types to the
237 // assembly
238 if (!IsResource())
239 {
240 DWORD countTypesAfterProfilerUpdate = GetMDImport()->GetCountWithTokenKind(mdtTypeDef);
241 DWORD countExportedTypesAfterProfilerUpdate = GetMDImport()->GetCountWithTokenKind(mdtExportedType);
242 // typeDefs rids 0 and 1 aren't included in the count, thus X typeDefs before means rid X+1 was valid and our incremental addition should start at X+2
243 for (DWORD typeDefRid = countTypesOrig + 2; typeDefRid < countTypesAfterProfilerUpdate + 2; typeDefRid++)
244 {
245 GetAssembly()->AddType(this, TokenFromRid(typeDefRid, mdtTypeDef));
246 }
247 // exportedType rid 0 isn't included in the count, thus X exportedTypes before means rid X was valid and our incremental addition should start at X+1
248 for (DWORD exportedTypeDef = countExportedTypesOrig + 1; exportedTypeDef < countExportedTypesAfterProfilerUpdate + 1; exportedTypeDef++)
249 {
250 GetAssembly()->AddExportedType(TokenFromRid(exportedTypeDef, mdtExportedType));
251 }
252 }
253
254 {
255 BEGIN_PIN_PROFILER(CORProfilerTrackAssemblyLoads());
256 if (IsManifest())
257 {
258 GCX_COOP();
259 g_profControlBlock.pProfInterface->AssemblyLoadFinished((AssemblyID) m_pAssembly, hr);
260 }
261 END_PIN_PROFILER();
262 }
263 }
264}
265
266#ifndef CROSSGEN_COMPILE
267IMetaDataEmit *Module::GetValidatedEmitter()
268{
269 CONTRACTL
270 {
271 INSTANCE_CHECK;
272 THROWS;
273 GC_NOTRIGGER;
274 INJECT_FAULT(COMPlusThrowOM());
275 MODE_ANY;
276 }
277 CONTRACTL_END;
278
279 if (m_pValidatedEmitter.Load() == NULL)
280 {
281 // In the past profilers could call any API they wanted on the the IMetaDataEmit interface and we didn't
282 // verify anything. To ensure we don't break back-compat the verifications are not enabled by default.
283 // Right now I have only added verifications for NGEN images, but in the future we might want verifications
284 // for all modules.
285 IMetaDataEmit* pEmit = NULL;
286 if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_ProfAPI_ValidateNGENInstrumentation) && HasNativeImage())
287 {
288 ProfilerMetadataEmitValidator* pValidator = new ProfilerMetadataEmitValidator(GetEmitter());
289 pValidator->QueryInterface(IID_IMetaDataEmit, (void**)&pEmit);
290 }
291 else
292 {
293 pEmit = GetEmitter();
294 pEmit->AddRef();
295 }
296 // Atomically swap it into the field (release it if we lose the race)
297 if (FastInterlockCompareExchangePointer(&m_pValidatedEmitter, pEmit, NULL) != NULL)
298 {
299 pEmit->Release();
300 }
301 }
302 return m_pValidatedEmitter.Load();
303}
304#endif // CROSSGEN_COMPILE
305#endif // PROFILING_SUPPORTED
306
307void Module::NotifyEtwLoadFinished(HRESULT hr)
308{
309 CONTRACTL
310 {
311 NOTHROW;
312 GC_TRIGGERS;
313 }
314 CONTRACTL_END
315
316 // we report only successful loads
317 if (SUCCEEDED(hr) &&
318 ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
319 TRACE_LEVEL_INFORMATION,
320 KEYWORDZERO))
321 {
322 BOOL fSharedModule = !SetTransientFlagInterlocked(IS_ETW_NOTIFIED);
323 ETW::LoaderLog::ModuleLoad(this, fSharedModule);
324 }
325}
326
327// Module initialization occurs in two phases: the constructor phase and the Initialize phase.
328//
329// The constructor phase initializes just enough so that Destruct() can be safely called.
330// It cannot throw or fail.
331//
332Module::Module(Assembly *pAssembly, mdFile moduleRef, PEFile *file)
333{
334 CONTRACTL
335 {
336 NOTHROW;
337 GC_TRIGGERS;
338 FORBID_FAULT;
339 }
340 CONTRACTL_END
341
342 PREFIX_ASSUME(pAssembly != NULL);
343
344 m_pAssembly = pAssembly;
345 m_moduleRef = moduleRef;
346 m_file = file;
347 m_dwTransientFlags = CLASSES_FREED;
348
349 if (!m_file->HasNativeImage())
350 {
351 // Memory allocated on LoaderHeap is zero-filled. Spot-check it here.
352 _ASSERTE(m_pBinder == NULL);
353 _ASSERTE(m_symbolFormat == eSymbolFormatNone);
354 }
355
356 file->AddRef();
357}
358
359void Module::InitializeForProfiling()
360{
361 CONTRACTL
362 {
363 INSTANCE_CHECK;
364 THROWS;
365 GC_TRIGGERS;
366 MODE_PREEMPTIVE;
367 PRECONDITION(HasNativeOrReadyToRunImage());
368 }
369 CONTRACTL_END;
370
371 COUNT_T cbProfileList = 0;
372
373 m_nativeImageProfiling = FALSE;
374
375 if (HasNativeImage())
376 {
377 PEImageLayout * pNativeImage = GetNativeImage();
378 CORCOMPILE_VERSION_INFO * pNativeVersionInfo = pNativeImage->GetNativeVersionInfoMaybeNull();
379 if ((pNativeVersionInfo != NULL) && (pNativeVersionInfo->wConfigFlags & CORCOMPILE_CONFIG_INSTRUMENTATION))
380 {
381 m_nativeImageProfiling = GetAssembly()->IsInstrumented();
382 }
383
384 // Link the module to the profile data list if available.
385 m_methodProfileList = pNativeImage->GetNativeProfileDataList(&cbProfileList);
386 }
387 else // ReadyToRun image
388 {
389#ifdef FEATURE_READYTORUN
390 // We already setup the m_methodProfileList in the ReadyToRunInfo constructor
391 if (m_methodProfileList != nullptr)
392 {
393 ReadyToRunInfo * pInfo = GetReadyToRunInfo();
394 PEImageLayout * pImage = pInfo->GetImage();
395
396 // Enable profiling if the ZapBBInstr value says to
397 m_nativeImageProfiling = GetAssembly()->IsInstrumented();
398 }
399#endif
400 }
401
402#ifdef FEATURE_LAZY_COW_PAGES
403 // When running a IBC tuning image to gather profile data
404 // we increment the block counts contained in this area.
405 //
406 if (cbProfileList)
407 EnsureWritablePages(m_methodProfileList, cbProfileList);
408#endif
409}
410
411#ifdef FEATURE_PREJIT
412
413void Module::InitializeNativeImage(AllocMemTracker* pamTracker)
414{
415 CONTRACTL
416 {
417 INSTANCE_CHECK;
418 THROWS;
419 GC_TRIGGERS;
420 MODE_PREEMPTIVE;
421 PRECONDITION(HasNativeImage());
422 }
423 CONTRACTL_END;
424
425 PEImageLayout * pNativeImage = GetNativeImage();
426
427 ExecutionManager::AddNativeImageRange(dac_cast<TADDR>(pNativeImage->GetBase()), pNativeImage->GetVirtualSize(), this);
428
429#ifndef CROSSGEN_COMPILE
430 LoadTokenTables();
431 LoadHelperTable();
432#endif // CROSSGEN_COMPILE
433
434#if defined(HAVE_GCCOVER)
435 if (GCStress<cfg_instr_ngen>::IsEnabled())
436 {
437 // Setting up gc coverage requires the base system classes
438 // to be initialized. So we must defer this for mscorlib.
439 if(!IsSystem())
440 {
441 SetupGcCoverageForNativeImage(this);
442 }
443 }
444#endif // defined(HAVE_GCCOVER)
445}
446
447void Module::SetNativeMetadataAssemblyRefInCache(DWORD rid, PTR_Assembly pAssembly)
448{
449 CONTRACTL
450 {
451 THROWS;
452 GC_TRIGGERS;
453 MODE_ANY;
454 }
455 CONTRACTL_END;
456
457 if (m_NativeMetadataAssemblyRefMap == NULL)
458 {
459 IMDInternalImport* pImport = GetNativeAssemblyImport();
460 DWORD dwMaxRid = pImport->GetCountWithTokenKind(mdtAssemblyRef);
461 _ASSERTE(dwMaxRid > 0);
462
463 S_SIZE_T dwAllocSize = S_SIZE_T(sizeof(PTR_Assembly)) * S_SIZE_T(dwMaxRid);
464
465 AllocMemTracker amTracker;
466 PTR_Assembly * NativeMetadataAssemblyRefMap = (PTR_Assembly *) amTracker.Track( GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(dwAllocSize) );
467
468 // Note: Memory allocated on loader heap is zero filled
469
470 if (InterlockedCompareExchangeT<PTR_Assembly *>(&m_NativeMetadataAssemblyRefMap, NativeMetadataAssemblyRefMap, NULL) == NULL)
471 amTracker.SuppressRelease();
472 }
473 _ASSERTE(m_NativeMetadataAssemblyRefMap != NULL);
474
475 _ASSERTE(rid <= GetNativeAssemblyImport()->GetCountWithTokenKind(mdtAssemblyRef));
476 m_NativeMetadataAssemblyRefMap[rid-1] = pAssembly;
477}
478#else // FEATURE_PREJIT
479BOOL Module::IsPersistedObject(void *address)
480{
481 LIMITED_METHOD_CONTRACT;
482 return FALSE;
483}
484
485#endif // FEATURE_PREJIT
486
487// Module initialization occurs in two phases: the constructor phase and the Initialize phase.
488//
489// The Initialize() phase completes the initialization after the constructor has run.
490// It can throw exceptions but whether it throws or succeeds, it must leave the Module
491// in a state where Destruct() can be safely called.
492//
493// szName is only used by dynamic modules, see ReflectionModule::Initialize
494//
495//
496void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
497{
498 CONTRACTL
499 {
500 INSTANCE_CHECK;
501 STANDARD_VM_CHECK;
502 PRECONDITION(szName == NULL);
503 }
504 CONTRACTL_END;
505
506 m_pSimpleName = m_file->GetSimpleName();
507
508 m_Crst.Init(CrstModule);
509 m_LookupTableCrst.Init(CrstModuleLookupTable, CrstFlags(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD));
510 m_FixupCrst.Init(CrstModuleFixup, (CrstFlags)(CRST_HOST_BREAKABLE|CRST_REENTRANCY));
511 m_InstMethodHashTableCrst.Init(CrstInstMethodHashTable, CRST_REENTRANCY);
512 m_ISymUnmanagedReaderCrst.Init(CrstISymUnmanagedReader, CRST_DEBUGGER_THREAD);
513
514 if (!m_file->HasNativeImage())
515 {
516 AllocateMaps();
517
518 if (IsSystem() ||
519 (strcmp(m_pSimpleName, "System") == 0) ||
520 (strcmp(m_pSimpleName, "System.Core") == 0) ||
521 (strcmp(m_pSimpleName, "Windows.Foundation") == 0))
522 {
523 FastInterlockOr(&m_dwPersistedFlags, LOW_LEVEL_SYSTEM_ASSEMBLY_BY_NAME);
524 }
525 }
526
527 m_dwTransientFlags &= ~((DWORD)CLASSES_FREED); // Set flag indicating LookupMaps are now in a consistent and destructable state
528
529#ifdef FEATURE_COLLECTIBLE_TYPES
530 if (GetAssembly()->IsCollectible())
531 {
532 FastInterlockOr(&m_dwPersistedFlags, COLLECTIBLE_MODULE);
533 }
534#endif // FEATURE_COLLECTIBLE_TYPES
535
536#ifdef FEATURE_READYTORUN
537 if (!HasNativeImage() && !IsResource())
538 m_pReadyToRunInfo = ReadyToRunInfo::Initialize(this, pamTracker);
539#endif
540
541 // Initialize the instance fields that we need for all non-Resource Modules
542 if (!IsResource())
543 {
544 if (m_pAvailableClasses == NULL && !IsReadyToRun())
545 {
546 m_pAvailableClasses = EEClassHashTable::Create(this,
547 GetAssembly()->IsCollectible() ? AVAILABLE_CLASSES_HASH_BUCKETS_COLLECTIBLE : AVAILABLE_CLASSES_HASH_BUCKETS,
548 FALSE /* bCaseInsensitive */, pamTracker);
549 }
550
551 if (m_pAvailableParamTypes == NULL)
552 {
553 m_pAvailableParamTypes = EETypeHashTable::Create(GetLoaderAllocator(), this, PARAMTYPES_HASH_BUCKETS, pamTracker);
554 }
555
556 if (m_pInstMethodHashTable == NULL)
557 {
558 m_pInstMethodHashTable = InstMethodHashTable::Create(GetLoaderAllocator(), this, PARAMMETHODS_HASH_BUCKETS, pamTracker);
559 }
560
561 if(m_pMemberRefToDescHashTable == NULL)
562 {
563 if (IsReflection())
564 {
565 m_pMemberRefToDescHashTable = MemberRefToDescHashTable::Create(this, MEMBERREF_MAP_INITIAL_SIZE, pamTracker);
566 }
567 else
568 {
569 IMDInternalImport * pImport = GetMDImport();
570
571 // Get #MemberRefs and create memberrefToDesc hash table
572 m_pMemberRefToDescHashTable = MemberRefToDescHashTable::Create(this, pImport->GetCountWithTokenKind(mdtMemberRef)+1, pamTracker);
573 }
574 }
575
576#ifdef FEATURE_COMINTEROP
577 if (IsCompilationProcess() && m_pGuidToTypeHash == NULL)
578 {
579 // only allocate this during NGEN-ing
580 m_pGuidToTypeHash = GuidToMethodTableHashTable::Create(this, GUID_TO_TYPE_HASH_BUCKETS, pamTracker);
581 }
582#endif // FEATURE_COMINTEROP
583 }
584
585 // this will be initialized a bit later.
586 m_ModuleID = NULL;
587 m_ModuleIndex.m_dwIndex = (SIZE_T)-1;
588
589 // Prepare statics that are known at module load time
590 AllocateStatics(pamTracker);
591
592#ifdef FEATURE_PREJIT
593 // Set up native image
594 if (HasNativeImage())
595 {
596 InitializeNativeImage(pamTracker);
597 }
598#endif // FEATURE_PREJIT
599
600 if (HasNativeOrReadyToRunImage())
601 {
602 InitializeForProfiling();
603 }
604
605#ifdef FEATURE_NATIVE_IMAGE_GENERATION
606 if (g_CorCompileVerboseLevel)
607 m_pNgenStats = new NgenStats();
608#endif
609
610 if (!IsResource() && (m_AssemblyRefByNameTable == NULL))
611 {
612 Module::CreateAssemblyRefByNameTable(pamTracker);
613 }
614
615 // If the program has the "ForceEnc" env variable set we ensure every eligible
616 // module has EnC turned on.
617 if (g_pConfig->ForceEnc() && IsEditAndContinueCapable())
618 EnableEditAndContinue();
619
620 LOG((LF_CLASSLOADER, LL_INFO10, "Loaded pModule: \"%ws\".\n", GetDebugName()));
621
622}
623
624#endif // DACCESS_COMPILE
625
626
627#ifdef FEATURE_COMINTEROP
628
629#ifndef DACCESS_COMPILE
630
631// static
632GuidToMethodTableHashTable* GuidToMethodTableHashTable::Create(Module* pModule, DWORD cInitialBuckets,
633 AllocMemTracker *pamTracker)
634{
635 CONTRACTL
636 {
637 THROWS;
638 GC_TRIGGERS;
639 MODE_ANY;
640 INJECT_FAULT(COMPlusThrowOM(););
641 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
642 }
643 CONTRACTL_END;
644
645 LoaderHeap *pHeap = pModule->GetAssembly()->GetLowFrequencyHeap();
646 GuidToMethodTableHashTable *pThis = (GuidToMethodTableHashTable*)pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(GuidToMethodTableHashTable)));
647
648 // The base class get initialized through chaining of constructors. We allocated the hash instance via the
649 // loader heap instead of new so use an in-place new to call the constructors now.
650 new (pThis) GuidToMethodTableHashTable(pModule, pHeap, cInitialBuckets);
651
652 return pThis;
653}
654
655GuidToMethodTableEntry *GuidToMethodTableHashTable::InsertValue(PTR_GUID pGuid, PTR_MethodTable pMT,
656 BOOL bReplaceIfFound, AllocMemTracker *pamTracker)
657{
658 CONTRACTL
659 {
660 THROWS;
661 GC_NOTRIGGER;
662 MODE_ANY;
663 INJECT_FAULT(COMPlusThrowOM(););
664 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
665 }
666 CONTRACTL_END;
667
668 GuidToMethodTableEntry *pEntry = NULL;
669
670 if (bReplaceIfFound)
671 {
672 pEntry = FindItem(pGuid, NULL);
673 }
674
675 if (pEntry != NULL)
676 {
677 pEntry->m_pMT = pMT;
678 }
679 else
680 {
681 pEntry = BaseAllocateEntry(pamTracker);
682 pEntry->m_Guid = pGuid;
683 pEntry->m_pMT = pMT;
684
685 DWORD hash = Hash(pGuid);
686 BaseInsertEntry(hash, pEntry);
687 }
688
689 return pEntry;
690}
691
692#endif // !DACCESS_COMPILE
693
694PTR_MethodTable GuidToMethodTableHashTable::GetValue(const GUID * pGuid, LookupContext *pContext)
695{
696 CONTRACTL
697 {
698 NOTHROW;
699 GC_NOTRIGGER;
700 MODE_ANY;
701 SUPPORTS_DAC;
702 PRECONDITION(CheckPointer(pGuid));
703 }
704 CONTRACTL_END;
705
706 GuidToMethodTableEntry * pEntry = FindItem(pGuid, pContext);
707 if (pEntry != NULL)
708 {
709 return pEntry->m_pMT;
710 }
711
712 return NULL;
713}
714
715GuidToMethodTableEntry *GuidToMethodTableHashTable::FindItem(const GUID * pGuid, LookupContext *pContext)
716{
717 CONTRACTL
718 {
719 NOTHROW;
720 GC_NOTRIGGER;
721 MODE_ANY;
722 SUPPORTS_DAC;
723 PRECONDITION(CheckPointer(pGuid));
724 }
725 CONTRACTL_END;
726
727 // It's legal for the caller not to pass us a LookupContext, but we might need to iterate
728 // internally (since we lookup via hash and hashes may collide). So substitute our own
729 // private context if one was not provided.
730 LookupContext sAltContext;
731 if (pContext == NULL)
732 pContext = &sAltContext;
733
734 // The base class provides the ability to enumerate all entries with the same hash code.
735 // We further check which of these entries actually match the full key.
736 PTR_GuidToMethodTableEntry pSearch = BaseFindFirstEntryByHash(Hash(pGuid), pContext);
737 while (pSearch)
738 {
739 if (CompareKeys(pSearch, pGuid))
740 {
741 return pSearch;
742 }
743
744 pSearch = BaseFindNextEntryByHash(pContext);
745 }
746
747 return NULL;
748}
749
750BOOL GuidToMethodTableHashTable::CompareKeys(PTR_GuidToMethodTableEntry pEntry, const GUID * pGuid)
751{
752 LIMITED_METHOD_DAC_CONTRACT;
753 return *pGuid == *(pEntry->m_Guid);
754}
755
756DWORD GuidToMethodTableHashTable::Hash(const GUID * pGuid)
757{
758 LIMITED_METHOD_DAC_CONTRACT;
759 static_assert_no_msg(sizeof(GUID) % sizeof(DWORD) == 0);
760 static_assert_no_msg(sizeof(GUID) / sizeof(DWORD) == 4);
761 DWORD * pSlice = (DWORD*) pGuid;
762 return pSlice[0] ^ pSlice[1] ^ pSlice[2] ^ pSlice[3];
763}
764
765
766BOOL GuidToMethodTableHashTable::FindNext(Iterator *it, GuidToMethodTableEntry **ppEntry)
767{
768 LIMITED_METHOD_DAC_CONTRACT;
769
770 if (!it->m_fIterating)
771 {
772 BaseInitIterator(&it->m_sIterator);
773 it->m_fIterating = true;
774 }
775
776 *ppEntry = it->m_sIterator.Next();
777 return *ppEntry ? TRUE : FALSE;
778}
779
780DWORD GuidToMethodTableHashTable::GetCount()
781{
782 LIMITED_METHOD_DAC_CONTRACT;
783 return BaseGetElementCount();
784}
785
786#if defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
787
788void GuidToMethodTableHashTable::Save(DataImage *pImage, CorProfileData *pProfileData)
789{
790 WRAPPER_NO_CONTRACT;
791 Base_t::BaseSave(pImage, pProfileData);
792}
793
794void GuidToMethodTableHashTable::Fixup(DataImage *pImage)
795{
796 WRAPPER_NO_CONTRACT;
797 Base_t::BaseFixup(pImage);
798}
799
800bool GuidToMethodTableHashTable::SaveEntry(DataImage *pImage, CorProfileData *pProfileData,
801 GuidToMethodTableEntry *pOldEntry, GuidToMethodTableEntry *pNewEntry,
802 EntryMappingTable *pMap)
803{
804 LIMITED_METHOD_CONTRACT;
805 return false;
806}
807
808void GuidToMethodTableHashTable::FixupEntry(DataImage *pImage, GuidToMethodTableEntry *pEntry, void *pFixupBase, DWORD cbFixupOffset)
809{
810 WRAPPER_NO_CONTRACT;
811 pImage->FixupField(pFixupBase, cbFixupOffset + offsetof(GuidToMethodTableEntry, m_pMT), pEntry->m_pMT);
812 pImage->FixupField(pFixupBase, cbFixupOffset + offsetof(GuidToMethodTableEntry, m_Guid), pEntry->m_Guid);
813}
814
815#endif // FEATURE_NATIVE_IMAGE_GENERATION && !DACCESS_COMPILE
816
817
818#ifdef FEATURE_PREJIT
819
820#ifndef DACCESS_COMPILE
821BOOL Module::CanCacheWinRTTypeByGuid(MethodTable *pMT)
822{
823 CONTRACTL
824 {
825 THROWS;
826 GC_NOTRIGGER;
827 MODE_ANY;
828 PRECONDITION(IsCompilationProcess());
829 }
830 CONTRACTL_END;
831
832 // Don't cache WinRT types in collectible modules.
833 if (IsCollectible())
834 {
835 return FALSE;
836 }
837
838 // Don't cache mscorlib-internal declarations of WinRT types.
839 if (IsSystem() && pMT->IsProjectedFromWinRT())
840 return FALSE;
841
842 // Don't cache redirected WinRT types.
843 if (WinRTTypeNameConverter::IsRedirectedWinRTSourceType(pMT))
844 return FALSE;
845
846#ifdef FEATURE_NATIVE_IMAGE_GENERATION
847 // Don't cache in a module that's not the NGen target, since the result
848 // won't be saved, and since the such a module might be read-only.
849 if (GetAppDomain()->ToCompilationDomain()->GetTargetModule() != this)
850 return FALSE;
851#endif
852
853 return TRUE;
854}
855
856void Module::CacheWinRTTypeByGuid(PTR_MethodTable pMT, PTR_GuidInfo pgi /*= NULL*/)
857{
858 CONTRACTL
859 {
860 STANDARD_VM_CHECK;
861 PRECONDITION(CheckPointer(pMT));
862 PRECONDITION(pMT->IsLegalNonArrayWinRTType());
863 PRECONDITION(pgi != NULL || pMT->GetGuidInfo() != NULL);
864 PRECONDITION(IsCompilationProcess());
865 }
866 CONTRACTL_END;
867
868 if (pgi == NULL)
869 {
870 pgi = pMT->GetGuidInfo();
871 }
872
873 AllocMemTracker amt;
874 m_pGuidToTypeHash->InsertValue(&pgi->m_Guid, pMT, TRUE, &amt);
875 amt.SuppressRelease();
876}
877
878#endif // !DACCESS_COMPILE
879
880PTR_MethodTable Module::LookupTypeByGuid(const GUID & guid)
881{
882 WRAPPER_NO_CONTRACT;
883 // Triton ni images do not have this hash.
884 if (m_pGuidToTypeHash != NULL)
885 return m_pGuidToTypeHash->GetValue(&guid, NULL);
886 else
887 return NULL;
888}
889
890void Module::GetCachedWinRTTypes(SArray<PTR_MethodTable> * pTypes, SArray<GUID> * pGuids)
891{
892 CONTRACTL
893 {
894 STANDARD_VM_CHECK;
895 SUPPORTS_DAC;
896 }
897 CONTRACTL_END;
898
899 // Triton ni images do not have this hash.
900 if (m_pGuidToTypeHash != NULL)
901 {
902 GuidToMethodTableHashTable::Iterator it(m_pGuidToTypeHash);
903 GuidToMethodTableEntry *pEntry;
904 while (m_pGuidToTypeHash->FindNext(&it, &pEntry))
905 {
906 pTypes->Append(pEntry->m_pMT);
907 pGuids->Append(*pEntry->m_Guid);
908 }
909 }
910}
911
912#endif // FEATURE_PREJIT
913
914#endif // FEATURE_COMINTEROP
915
916#ifndef DACCESS_COMPILE
917MemberRefToDescHashTable* MemberRefToDescHashTable::Create(Module *pModule, DWORD cInitialBuckets, AllocMemTracker *pamTracker)
918{
919 CONTRACTL
920 {
921 THROWS;
922 GC_TRIGGERS;
923 MODE_ANY;
924 INJECT_FAULT(COMPlusThrowOM(););
925 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
926 }
927 CONTRACTL_END;
928
929 LoaderHeap *pHeap = pModule->GetAssembly()->GetLowFrequencyHeap();
930 MemberRefToDescHashTable *pThis = (MemberRefToDescHashTable*)pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(MemberRefToDescHashTable)));
931
932 // The base class get initialized through chaining of constructors. We allocated the hash instance via the
933 // loader heap instead of new so use an in-place new to call the constructors now.
934 new (pThis) MemberRefToDescHashTable(pModule, pHeap, cInitialBuckets);
935
936 return pThis;
937}
938
939//Inserts FieldRef
940MemberRefToDescHashEntry* MemberRefToDescHashTable::Insert(mdMemberRef token , FieldDesc *value)
941{
942 CONTRACTL
943 {
944 THROWS;
945 GC_NOTRIGGER;
946 MODE_ANY;
947 INJECT_FAULT(COMPlusThrowOM(););
948 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
949 }
950 CONTRACTL_END;
951
952 LookupContext sAltContext;
953
954 _ASSERTE((dac_cast<TADDR>(value) & IS_FIELD_MEMBER_REF) == 0);
955
956 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(token), &sAltContext);
957 if (pEntry != NULL)
958 {
959 // 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.
960 // However its value will be null. We need to set its actual value.
961 if(pEntry->m_value == dac_cast<TADDR>(NULL))
962 {
963 EnsureWritablePages(&(pEntry->m_value));
964 pEntry->m_value = dac_cast<TADDR>(value)|IS_FIELD_MEMBER_REF;
965 }
966
967 _ASSERTE(pEntry->m_value == (dac_cast<TADDR>(value)|IS_FIELD_MEMBER_REF));
968 return pEntry;
969 }
970
971 // For non hot tokens insert new entry in hashtable
972 pEntry = BaseAllocateEntry(NULL);
973 pEntry->m_value = dac_cast<TADDR>(value)|IS_FIELD_MEMBER_REF;
974 BaseInsertEntry(RidFromToken(token), pEntry);
975
976 return pEntry;
977}
978
979// Insert MethodRef
980MemberRefToDescHashEntry* MemberRefToDescHashTable::Insert(mdMemberRef token , MethodDesc *value)
981{
982 CONTRACTL
983 {
984 THROWS;
985 GC_NOTRIGGER;
986 MODE_ANY;
987 INJECT_FAULT(COMPlusThrowOM(););
988 PRECONDITION(!FORBIDGC_LOADER_USE_ENABLED());
989 }
990 CONTRACTL_END;
991
992 LookupContext sAltContext;
993
994 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(token), &sAltContext);
995 if (pEntry != NULL)
996 {
997 // 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.
998 // However its value will be null. We need to set its actual value.
999 if(pEntry->m_value == dac_cast<TADDR>(NULL))
1000 {
1001 EnsureWritablePages(&(pEntry->m_value));
1002 pEntry->m_value = dac_cast<TADDR>(value);
1003 }
1004
1005 _ASSERTE(pEntry->m_value == dac_cast<TADDR>(value));
1006 return pEntry;
1007 }
1008
1009 // For non hot tokens insert new entry in hashtable
1010 pEntry = BaseAllocateEntry(NULL);
1011 pEntry->m_value = dac_cast<TADDR>(value);
1012 BaseInsertEntry(RidFromToken(token), pEntry);
1013
1014 return pEntry;
1015}
1016
1017#if defined(FEATURE_NATIVE_IMAGE_GENERATION)
1018void MemberRefToDescHashTable::Save(DataImage *pImage, CorProfileData *pProfileData)
1019{
1020 STANDARD_VM_CONTRACT;
1021
1022 // Mark if the tokens are hot
1023 if (pProfileData)
1024 {
1025 DWORD numInTokenList = pProfileData->GetHotTokens(mdtMemberRef>>24, 1<<RidMap, 1<<RidMap, NULL, 0);
1026
1027 if (numInTokenList > 0)
1028 {
1029 LookupContext sAltContext;
1030
1031 mdToken *tokenList = (mdToken*)(void*)pImage->GetModule()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(mdToken)) * S_SIZE_T(numInTokenList));
1032
1033 pProfileData->GetHotTokens(mdtMemberRef>>24, 1<<RidMap, 1<<RidMap, tokenList, numInTokenList);
1034 for (DWORD i = 0; i < numInTokenList; i++)
1035 {
1036 DWORD rid = RidFromToken(tokenList[i]);
1037 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(tokenList[i]), &sAltContext);
1038 if (pEntry != NULL)
1039 {
1040 _ASSERTE((pEntry->m_value & 0x1) == 0);
1041 pEntry->m_value |= 0x1;
1042 }
1043 }
1044 }
1045 }
1046
1047 BaseSave(pImage, pProfileData);
1048}
1049
1050void MemberRefToDescHashTable::FixupEntry(DataImage *pImage, MemberRefToDescHashEntry *pEntry, void *pFixupBase, DWORD cbFixupOffset)
1051{
1052 //As there is no more hard binding initialize MemberRef* to NULL
1053 pImage->ZeroPointerField(pFixupBase, cbFixupOffset + offsetof(MemberRefToDescHashEntry, m_value));
1054}
1055
1056#endif // FEATURE_NATIVE_IMAGE_GENERATION
1057
1058#endif // !DACCESS_COMPILE
1059
1060PTR_MemberRef MemberRefToDescHashTable::GetValue(mdMemberRef token, BOOL *pfIsMethod)
1061{
1062 CONTRACTL
1063 {
1064 NOTHROW;
1065 GC_NOTRIGGER;
1066 MODE_ANY;
1067 SUPPORTS_DAC;
1068 }
1069 CONTRACTL_END;
1070
1071 LookupContext sAltContext;
1072
1073 MemberRefToDescHashEntry *pEntry = (PTR_MemberRefToDescHashEntry) BaseFindFirstEntryByHash(RidFromToken(token), &sAltContext);
1074 if (pEntry != NULL)
1075 {
1076 if(pEntry->m_value & IS_FIELD_MEMBER_REF)
1077 *pfIsMethod = FALSE;
1078 else
1079 *pfIsMethod = TRUE;
1080 return (PTR_MemberRef)(pEntry->m_value & (~MEMBER_REF_MAP_ALL_FLAGS));
1081 }
1082
1083 return NULL;
1084}
1085
1086
1087void Module::SetDebuggerInfoBits(DebuggerAssemblyControlFlags newBits)
1088{
1089 LIMITED_METHOD_CONTRACT;
1090 SUPPORTS_DAC;
1091
1092 _ASSERTE(((newBits << DEBUGGER_INFO_SHIFT_PRIV) &
1093 ~DEBUGGER_INFO_MASK_PRIV) == 0);
1094
1095 m_dwTransientFlags &= ~DEBUGGER_INFO_MASK_PRIV;
1096 m_dwTransientFlags |= (newBits << DEBUGGER_INFO_SHIFT_PRIV);
1097
1098#ifdef DEBUGGING_SUPPORTED
1099 BOOL setEnC = ((newBits & DACF_ENC_ENABLED) != 0) && IsEditAndContinueCapable();
1100
1101 // The only way can change Enc is through debugger override.
1102 if (setEnC)
1103 {
1104 EnableEditAndContinue();
1105 }
1106 else
1107 {
1108 if (!g_pConfig->ForceEnc())
1109 DisableEditAndContinue();
1110 }
1111#endif // DEBUGGING_SUPPORTED
1112
1113#if defined(DACCESS_COMPILE)
1114 // Now that we've changed m_dwTransientFlags, update that in the target too.
1115 // This will fail for read-only target.
1116 // If this fails, it will throw an exception.
1117 // @dbgtodo dac write: finalize on plans for how DAC writes to the target.
1118 HRESULT hrDac;
1119 hrDac = DacWriteHostInstance(this, true);
1120 _ASSERTE(SUCCEEDED(hrDac)); // would throw if there was an error.
1121#endif // DACCESS_COMPILE
1122}
1123
1124#ifndef DACCESS_COMPILE
1125/* static */
1126Module *Module::Create(Assembly *pAssembly, mdFile moduleRef, PEFile *file, AllocMemTracker *pamTracker)
1127{
1128 CONTRACT(Module *)
1129 {
1130 STANDARD_VM_CHECK;
1131 PRECONDITION(CheckPointer(pAssembly));
1132 PRECONDITION(CheckPointer(file));
1133 PRECONDITION(!IsNilToken(moduleRef) || file->IsAssembly());
1134 POSTCONDITION(CheckPointer(RETVAL));
1135 POSTCONDITION(RETVAL->GetFile() == file);
1136 }
1137 CONTRACT_END;
1138
1139 // Hoist CONTRACT into separate routine because of EX incompatibility
1140
1141 Module *pModule = NULL;
1142
1143 // Create the module
1144
1145#ifdef FEATURE_PREJIT
1146
1147 if (file->HasNativeImage())
1148 {
1149 pModule = file->GetLoadedNative()->GetPersistedModuleImage();
1150 PREFIX_ASSUME(pModule != NULL);
1151 CONSISTENCY_CHECK_MSG(pModule->m_pAssembly == NULL || !pModule->IsTenured(), // if the module is not tenured it could be our previous attempt
1152 "Native image can only be used once per process\n");
1153 EnsureWritablePages(pModule);
1154 pModule = new ((void*) pModule) Module(pAssembly, moduleRef, file);
1155 PREFIX_ASSUME(pModule != NULL);
1156 }
1157
1158#endif // FEATURE_PREJIT
1159
1160 if (pModule == NULL)
1161 {
1162#ifdef EnC_SUPPORTED
1163 if (IsEditAndContinueCapable(pAssembly, file))
1164 {
1165 // if file is EnCCapable, always create an EnC-module, but EnC won't necessarily be enabled.
1166 // Debugger enables this by calling SetJITCompilerFlags on LoadModule callback.
1167
1168 void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(EditAndContinueModule))));
1169 pModule = new (pMemory) EditAndContinueModule(pAssembly, moduleRef, file);
1170 }
1171 else
1172#endif // EnC_SUPPORTED
1173 {
1174 void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(Module))));
1175 pModule = new (pMemory) Module(pAssembly, moduleRef, file);
1176 }
1177 }
1178
1179 PREFIX_ASSUME(pModule != NULL);
1180 ModuleHolder pModuleSafe(pModule);
1181 pModuleSafe->DoInit(pamTracker, NULL);
1182
1183 RETURN pModuleSafe.Extract();
1184}
1185
1186void Module::ApplyMetaData()
1187{
1188 CONTRACTL
1189 {
1190 THROWS;
1191 GC_NOTRIGGER;
1192 MODE_ANY;
1193 }
1194 CONTRACTL_END;
1195
1196 LOG((LF_CLASSLOADER, LL_INFO100, "Module::ApplyNewMetaData %x\n", this));
1197
1198 HRESULT hr = S_OK;
1199 ULONG ulCount;
1200
1201 // Ensure for TypeRef
1202 ulCount = GetMDImport()->GetCountWithTokenKind(mdtTypeRef) + 1;
1203 EnsureTypeRefCanBeStored(TokenFromRid(ulCount, mdtTypeRef));
1204
1205 // Ensure for AssemblyRef
1206 ulCount = GetMDImport()->GetCountWithTokenKind(mdtAssemblyRef) + 1;
1207 EnsureAssemblyRefCanBeStored(TokenFromRid(ulCount, mdtAssemblyRef));
1208}
1209
1210//
1211// Destructor for Module
1212//
1213
1214void Module::Destruct()
1215{
1216 CONTRACTL
1217 {
1218 INSTANCE_CHECK;
1219 NOTHROW;
1220 GC_TRIGGERS;
1221 MODE_PREEMPTIVE;
1222 }
1223 CONTRACTL_END;
1224
1225 LOG((LF_EEMEM, INFO3, "Deleting module %x\n", this));
1226#ifdef PROFILING_SUPPORTED
1227 {
1228 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
1229 if (!IsBeingUnloaded())
1230 {
1231 // Profiler is causing some peripheral class loads. Probably this just needs
1232 // to be turned into a Fault_not_fatal and moved to a specific place inside the profiler.
1233 EX_TRY
1234 {
1235 GCX_PREEMP();
1236 g_profControlBlock.pProfInterface->ModuleUnloadStarted((ModuleID) this);
1237 }
1238 EX_CATCH
1239 {
1240 }
1241 EX_END_CATCH(SwallowAllExceptions);
1242 }
1243 END_PIN_PROFILER();
1244 }
1245#endif // PROFILING_SUPPORTED
1246
1247
1248 DACNotify::DoModuleUnloadNotification(this);
1249
1250 // Free classes in the class table
1251 FreeClassTables();
1252
1253
1254
1255#ifdef DEBUGGING_SUPPORTED
1256 if (g_pDebugInterface)
1257 {
1258 GCX_PREEMP();
1259 g_pDebugInterface->DestructModule(this);
1260 }
1261
1262#endif // DEBUGGING_SUPPORTED
1263
1264 ReleaseISymUnmanagedReader();
1265
1266 // Clean up sig cookies
1267 VASigCookieBlock *pVASigCookieBlock = m_pVASigCookieBlock;
1268 while (pVASigCookieBlock)
1269 {
1270 VASigCookieBlock *pNext = pVASigCookieBlock->m_Next;
1271 delete pVASigCookieBlock;
1272
1273 pVASigCookieBlock = pNext;
1274 }
1275
1276 // Clean up the IL stub cache
1277 if (m_pILStubCache != NULL)
1278 {
1279 delete m_pILStubCache;
1280 }
1281
1282
1283
1284#ifdef PROFILING_SUPPORTED
1285 {
1286 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
1287 // Profiler is causing some peripheral class loads. Probably this just needs
1288 // to be turned into a Fault_not_fatal and moved to a specific place inside the profiler.
1289 EX_TRY
1290 {
1291 GCX_PREEMP();
1292 g_profControlBlock.pProfInterface->ModuleUnloadFinished((ModuleID) this, S_OK);
1293 }
1294 EX_CATCH
1295 {
1296 }
1297 EX_END_CATCH(SwallowAllExceptions);
1298 END_PIN_PROFILER();
1299 }
1300
1301 if (m_pValidatedEmitter.Load() != NULL)
1302 {
1303 m_pValidatedEmitter->Release();
1304 }
1305#endif // PROFILING_SUPPORTED
1306
1307 //
1308 // Warning - deleting the zap file will cause the module to be unmapped
1309 //
1310 ClearInMemorySymbolStream();
1311
1312 m_Crst.Destroy();
1313 m_FixupCrst.Destroy();
1314 m_LookupTableCrst.Destroy();
1315 m_InstMethodHashTableCrst.Destroy();
1316 m_ISymUnmanagedReaderCrst.Destroy();
1317
1318
1319 if (m_debuggerSpecificData.m_pDynamicILCrst)
1320 {
1321 delete m_debuggerSpecificData.m_pDynamicILCrst;
1322 }
1323
1324 if (m_debuggerSpecificData.m_pDynamicILBlobTable)
1325 {
1326 delete m_debuggerSpecificData.m_pDynamicILBlobTable;
1327 }
1328
1329 if (m_debuggerSpecificData.m_pTemporaryILBlobTable)
1330 {
1331 delete m_debuggerSpecificData.m_pTemporaryILBlobTable;
1332 }
1333
1334 if (m_debuggerSpecificData.m_pILOffsetMappingTable)
1335 {
1336 for (ILOffsetMappingTable::Iterator pCurElem = m_debuggerSpecificData.m_pILOffsetMappingTable->Begin(),
1337 pEndElem = m_debuggerSpecificData.m_pILOffsetMappingTable->End();
1338 pCurElem != pEndElem;
1339 pCurElem++)
1340 {
1341 ILOffsetMappingEntry entry = *pCurElem;
1342 entry.m_mapping.Clear();
1343 }
1344 delete m_debuggerSpecificData.m_pILOffsetMappingTable;
1345 }
1346
1347#ifdef FEATURE_PREJIT
1348
1349 if (HasNativeImage())
1350 {
1351 m_file->Release();
1352 }
1353 else
1354#endif // FEATURE_PREJIT
1355 {
1356 m_file->Release();
1357 }
1358
1359 // If this module was loaded as domain-specific, then
1360 // we must free its ModuleIndex so that it can be reused
1361 FreeModuleIndex();
1362}
1363
1364#ifdef FEATURE_PREJIT
1365void Module::DeleteNativeCodeRanges()
1366{
1367 CONTRACTL
1368 {
1369 NOTHROW;
1370 GC_NOTRIGGER;
1371 MODE_PREEMPTIVE;
1372 FORBID_FAULT;
1373 }
1374 CONTRACTL_END;
1375
1376 if (HasNativeImage())
1377 {
1378 PEImageLayout * pNativeImage = GetNativeImage();
1379
1380 ExecutionManager::DeleteRange(dac_cast<TADDR>(pNativeImage->GetBase()));
1381 }
1382}
1383#endif
1384
1385bool Module::NeedsGlobalMethodTable()
1386{
1387 CONTRACTL
1388 {
1389 INSTANCE_CHECK;
1390 THROWS;
1391 GC_TRIGGERS;
1392 MODE_ANY;
1393 }
1394 CONTRACTL_END;
1395
1396 IMDInternalImport * pImport = GetMDImport();
1397 if (!IsResource() && pImport->IsValidToken(COR_GLOBAL_PARENT_TOKEN))
1398 {
1399 {
1400 HENUMInternalHolder funcEnum(pImport);
1401 funcEnum.EnumGlobalFunctionsInit();
1402 if (pImport->EnumGetCount(&funcEnum) != 0)
1403 return true;
1404 }
1405
1406 {
1407 HENUMInternalHolder fieldEnum(pImport);
1408 fieldEnum.EnumGlobalFieldsInit();
1409 if (pImport->EnumGetCount(&fieldEnum) != 0)
1410 return true;
1411 }
1412 }
1413
1414 // resource module or no global statics nor global functions
1415 return false;
1416}
1417
1418
1419MethodTable *Module::GetGlobalMethodTable()
1420{
1421 CONTRACT (MethodTable *)
1422 {
1423 INSTANCE_CHECK;
1424 THROWS;
1425 GC_TRIGGERS;
1426 MODE_ANY;
1427 INJECT_FAULT(CONTRACT_RETURN NULL;);
1428 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1429 }
1430 CONTRACT_END;
1431
1432
1433 if ((m_dwPersistedFlags & COMPUTED_GLOBAL_CLASS) == 0)
1434 {
1435 MethodTable *pMT = NULL;
1436
1437 if (NeedsGlobalMethodTable())
1438 {
1439 pMT = ClassLoader::LoadTypeDefThrowing(this, COR_GLOBAL_PARENT_TOKEN,
1440 ClassLoader::ThrowIfNotFound,
1441 ClassLoader::FailIfUninstDefOrRef).AsMethodTable();
1442 }
1443
1444 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_GLOBAL_CLASS);
1445 RETURN pMT;
1446 }
1447 else
1448 {
1449 RETURN LookupTypeDef(COR_GLOBAL_PARENT_TOKEN).AsMethodTable();
1450 }
1451}
1452
1453
1454#endif // !DACCESS_COMPILE
1455
1456#ifdef FEATURE_PREJIT
1457
1458/*static*/
1459BOOL Module::IsAlwaysSavedInPreferredZapModule(Instantiation classInst, // the type arguments to the type (if any)
1460 Instantiation methodInst) // the type arguments to the method (if any)
1461{
1462 LIMITED_METHOD_CONTRACT;
1463
1464 return ClassLoader::IsTypicalSharedInstantiation(classInst) &&
1465 ClassLoader::IsTypicalSharedInstantiation(methodInst);
1466}
1467
1468//this gets called recursively for generics, so do a probe.
1469PTR_Module Module::ComputePreferredZapModule(Module * pDefinitionModule,
1470 Instantiation classInst,
1471 Instantiation methodInst)
1472{
1473 CONTRACTL
1474 {
1475 NOTHROW;
1476 GC_NOTRIGGER;
1477 MODE_ANY;
1478 SO_TOLERANT;
1479 SUPPORTS_DAC;
1480 }
1481 CONTRACTL_END;
1482
1483 PTR_Module ret = NULL;
1484 INTERIOR_STACK_PROBE_NOTHROW_CHECK_THREAD(DontCallDirectlyForceStackOverflow());
1485
1486 ret = Module::ComputePreferredZapModuleHelper( pDefinitionModule,
1487 classInst,
1488 methodInst );
1489 END_INTERIOR_STACK_PROBE;
1490 return ret;
1491}
1492
1493//
1494// Is pModule likely a dependency of pOtherModule? Heuristic used by preffered zap module algorithm.
1495// It can return both false positives and negatives.
1496//
1497static bool IsLikelyDependencyOf(Module * pModule, Module * pOtherModule)
1498{
1499 CONTRACTL
1500 {
1501 NOTHROW;
1502 GC_NOTRIGGER;
1503 FORBID_FAULT;
1504 MODE_ANY;
1505 SUPPORTS_DAC;
1506 PRECONDITION(CheckPointer(pOtherModule));
1507 }
1508 CONTRACTL_END
1509
1510 // Every module has a dependency with itself
1511 if (pModule == pOtherModule)
1512 return true;
1513
1514 //
1515 // Explicit check for low level system assemblies is working around Win8P facades introducing extra layer between low level system assemblies
1516 // (System.dll or System.Core.dll) and the app assemblies. Because of this extra layer, the check below won't see the direct
1517 // reference between these low level system assemblies and the app assemblies. The prefererred zap module for instantiations of generic
1518 // collections from these low level system assemblies (like LinkedList<AppType>) should be module of AppType. It would be module of the generic
1519 // collection without this check.
1520 //
1521 // Similar problem exists for Windows.Foundation.winmd. There is a cycle between Windows.Foundation.winmd and Windows.Storage.winmd. This cycle
1522 // would cause prefererred zap module for instantiations of foundation types (like IAsyncOperation<StorageFolder>) to be Windows.Foundation.winmd.
1523 // It is a bad choice. It should be Windows.Storage.winmd instead. We explicitly push Windows.Foundation to lower level by treating it as
1524 // low level system assembly to avoid this problem.
1525 //
1526 if (pModule->IsLowLevelSystemAssemblyByName())
1527 {
1528 if (!pOtherModule->IsLowLevelSystemAssemblyByName())
1529 return true;
1530
1531 // Every module depends upon mscorlib
1532 if (pModule->IsSystem())
1533 return true;
1534
1535 // mscorlib does not depend upon any other module
1536 if (pOtherModule->IsSystem())
1537 return false;
1538 }
1539 else
1540 {
1541 if (pOtherModule->IsLowLevelSystemAssemblyByName())
1542 return false;
1543 }
1544
1545 // At this point neither pModule or pOtherModule is mscorlib
1546
1547#ifndef DACCESS_COMPILE
1548 //
1549 // We will check to see if the pOtherModule has a reference to pModule
1550 //
1551
1552 // If we can match the assembly ref in the ManifestModuleReferencesMap we can early out.
1553 // This early out kicks in less than half of the time. It hurts performance on average.
1554 // if (!IsNilToken(pOtherModule->FindAssemblyRef(pModule->GetAssembly())))
1555 // return true;
1556
1557 if (pOtherModule->HasReferenceByName(pModule->GetSimpleName()))
1558 return true;
1559#endif // DACCESS_COMPILE
1560
1561 return false;
1562}
1563
1564// Determine the "preferred ngen home" for an instantiated type or method
1565// * This is the first ngen module that the loader will look in;
1566// * Also, we only hard bind to a type or method that lives in its preferred module
1567// The following properties must hold of the preferred module:
1568// - it must be one of the component type's declaring modules
1569// - if the type or method is open then the preferred module must be that of one of the type parameters
1570// (this ensures that we can always hard bind to open types and methods created during ngen)
1571// - for always-saved instantiations it must be the declaring module of the generic definition
1572// Otherwise, we try to pick a module that is likely to reference the type or method
1573//
1574/* static */
1575PTR_Module Module::ComputePreferredZapModuleHelper(
1576 Module * pDefinitionModule, // the module that declares the generic type or method
1577 Instantiation classInst, // the type arguments to the type (if any)
1578 Instantiation methodInst) // the type arguments to the method (if any)
1579{
1580 CONTRACT(PTR_Module)
1581 {
1582 NOTHROW;
1583 GC_NOTRIGGER;
1584 FORBID_FAULT;
1585 MODE_ANY;
1586 PRECONDITION(CheckPointer(pDefinitionModule, NULL_OK));
1587 // One of them will be non-null... Note we don't use CheckPointer
1588 // because that raises a breakpoint in the debugger
1589 PRECONDITION(pDefinitionModule != NULL || !classInst.IsEmpty() || !methodInst.IsEmpty());
1590 POSTCONDITION(CheckPointer(RETVAL));
1591 SUPPORTS_DAC;
1592 }
1593 CONTRACT_END
1594
1595 DWORD totalArgs = classInst.GetNumArgs() + methodInst.GetNumArgs();
1596
1597 // The open type parameters takes precendence over closed type parameters since
1598 // we always hardbind to open types.
1599 for (DWORD i = 0; i < totalArgs; i++)
1600 {
1601 TypeHandle thArg = (i < classInst.GetNumArgs()) ? classInst[i] : methodInst[i - classInst.GetNumArgs()];
1602
1603 // Encoded types are never open
1604 _ASSERTE(!thArg.IsEncodedFixup());
1605 Module * pOpenModule = thArg.GetDefiningModuleForOpenType();
1606 if (pOpenModule != NULL)
1607 RETURN dac_cast<PTR_Module>(pOpenModule);
1608 }
1609
1610 // The initial value of pCurrentPZM is the pDefinitionModule or mscorlib
1611 Module* pCurrentPZM = (pDefinitionModule != NULL) ? pDefinitionModule : MscorlibBinder::GetModule();
1612 bool preferredZapModuleBasedOnValueType = false;
1613
1614 for (DWORD i = 0; i < totalArgs; i++)
1615 {
1616 TypeHandle pTypeParam = (i < classInst.GetNumArgs()) ? classInst[i] : methodInst[i - classInst.GetNumArgs()];
1617
1618 _ASSERTE(pTypeParam != NULL);
1619 _ASSERTE(!pTypeParam.IsEncodedFixup());
1620
1621 Module * pParamPZM = GetPreferredZapModuleForTypeHandle(pTypeParam);
1622
1623 //
1624 // If pCurrentPZM is not a dependency of pParamPZM
1625 // then we aren't going to update pCurrentPZM
1626 //
1627 if (IsLikelyDependencyOf(pCurrentPZM, pParamPZM))
1628 {
1629 // If we have a type parameter that is a value type
1630 // and we don't yet have a value type based pCurrentPZM
1631 // then we will select it's module as the new pCurrentPZM.
1632 //
1633 if (pTypeParam.IsValueType() && !preferredZapModuleBasedOnValueType)
1634 {
1635 pCurrentPZM = pParamPZM;
1636 preferredZapModuleBasedOnValueType = true;
1637 }
1638 else
1639 {
1640 // The normal rule is to replace the pCurrentPZM only when
1641 // both of the following are true:
1642 // pCurrentPZM is a dependency of pParamPZM
1643 // and pParamPZM is not a dependency of pCurrentPZM
1644 //
1645 // note that the second condition is alway true when pCurrentPZM is mscorlib
1646 //
1647 if (!IsLikelyDependencyOf(pParamPZM, pCurrentPZM))
1648 {
1649 pCurrentPZM = pParamPZM;
1650 }
1651 }
1652 }
1653 }
1654
1655 RETURN dac_cast<PTR_Module>(pCurrentPZM);
1656}
1657
1658PTR_Module Module::ComputePreferredZapModule(TypeKey *pKey)
1659{
1660 CONTRACTL
1661 {
1662 NOTHROW;
1663 GC_NOTRIGGER;
1664 SO_TOLERANT;
1665 MODE_ANY;
1666 SUPPORTS_DAC;
1667 }
1668 CONTRACTL_END;
1669
1670 if (pKey->GetKind() == ELEMENT_TYPE_CLASS)
1671 {
1672 return Module::ComputePreferredZapModule(pKey->GetModule(),
1673 pKey->GetInstantiation());
1674 }
1675 else if (pKey->GetKind() != ELEMENT_TYPE_FNPTR)
1676 return Module::GetPreferredZapModuleForTypeHandle(pKey->GetElementType());
1677 else
1678 return NULL;
1679
1680}
1681
1682/* see code:Module::ComputePreferredZapModuleHelper for more */
1683/*static*/
1684PTR_Module Module::GetPreferredZapModuleForMethodTable(MethodTable *pMT)
1685{
1686 CONTRACTL
1687 {
1688 NOTHROW;
1689 GC_NOTRIGGER;
1690 SO_TOLERANT;
1691 MODE_ANY;
1692 SUPPORTS_DAC;
1693 }
1694 CONTRACTL_END;
1695
1696 PTR_Module pRet=NULL;
1697
1698 INTERIOR_STACK_PROBE_FOR_NOTHROW_CHECK_THREAD(10, NO_FORBIDGC_LOADER_USE_ThrowSO(););
1699
1700 if (pMT->IsArray())
1701 {
1702 TypeHandle elemTH = pMT->GetApproxArrayElementTypeHandle();
1703 pRet= ComputePreferredZapModule(NULL, Instantiation(&elemTH, 1));
1704 }
1705 else if (pMT->HasInstantiation() && !pMT->IsGenericTypeDefinition())
1706 {
1707 pRet= ComputePreferredZapModule(pMT->GetModule(),
1708 pMT->GetInstantiation());
1709 }
1710 else
1711 {
1712 // If it is uninstantiated or it is the generic type definition itself
1713 // then its loader module is simply the module containing its TypeDef
1714 pRet= pMT->GetModule();
1715 }
1716 END_INTERIOR_STACK_PROBE;
1717 return pRet;
1718}
1719
1720
1721/*static*/
1722PTR_Module Module::GetPreferredZapModuleForTypeDesc(PTR_TypeDesc pTD)
1723{
1724 CONTRACTL
1725 {
1726 NOTHROW;
1727 GC_NOTRIGGER;
1728 SO_TOLERANT;
1729 MODE_ANY;
1730 }
1731 CONTRACTL_END;
1732 SUPPORTS_DAC;
1733 if (pTD->HasTypeParam())
1734 return GetPreferredZapModuleForTypeHandle(pTD->GetTypeParam());
1735 else if (pTD->IsGenericVariable())
1736 return pTD->GetModule();
1737
1738 _ASSERTE(pTD->GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
1739 PTR_FnPtrTypeDesc pFnPtrTD = dac_cast<PTR_FnPtrTypeDesc>(pTD);
1740
1741 // Result type of function type is used for preferred zap module
1742 return GetPreferredZapModuleForTypeHandle(pFnPtrTD->GetRetAndArgTypesPointer()[0]);
1743}
1744
1745/*static*/
1746PTR_Module Module::GetPreferredZapModuleForTypeHandle(TypeHandle t)
1747{
1748 CONTRACTL
1749 {
1750 NOTHROW;
1751 GC_NOTRIGGER;
1752 SO_TOLERANT;
1753 MODE_ANY;
1754 }
1755 CONTRACTL_END;
1756 SUPPORTS_DAC;
1757 if (t.IsTypeDesc())
1758 return GetPreferredZapModuleForTypeDesc(t.AsTypeDesc());
1759 else
1760 return GetPreferredZapModuleForMethodTable(t.AsMethodTable());
1761}
1762
1763/*static*/
1764PTR_Module Module::GetPreferredZapModuleForMethodDesc(const MethodDesc *pMD)
1765{
1766 CONTRACTL
1767 {
1768 NOTHROW;
1769 GC_NOTRIGGER;
1770 SO_TOLERANT;
1771 MODE_ANY;
1772 }
1773 CONTRACTL_END;
1774
1775 if (pMD->IsTypicalMethodDefinition())
1776 {
1777 return PTR_Module(pMD->GetModule());
1778 }
1779 else if (pMD->IsGenericMethodDefinition())
1780 {
1781 return GetPreferredZapModuleForMethodTable(pMD->GetMethodTable());
1782 }
1783 else
1784 {
1785 return ComputePreferredZapModule(pMD->GetModule(),
1786 pMD->GetClassInstantiation(),
1787 pMD->GetMethodInstantiation());
1788 }
1789}
1790
1791/* see code:Module::ComputePreferredZapModuleHelper for more */
1792/*static*/
1793PTR_Module Module::GetPreferredZapModuleForFieldDesc(FieldDesc * pFD)
1794{
1795 CONTRACTL
1796 {
1797 NOTHROW;
1798 GC_NOTRIGGER;
1799 SO_TOLERANT;
1800 MODE_ANY;
1801 }
1802 CONTRACTL_END;
1803
1804 // The approx MT is sufficient: it's always the one that owns the FieldDesc
1805 // data structure
1806 return GetPreferredZapModuleForMethodTable(pFD->GetApproxEnclosingMethodTable());
1807}
1808#endif // FEATURE_PREJIT
1809
1810/*static*/
1811BOOL Module::IsEditAndContinueCapable(Assembly *pAssembly, PEFile *file)
1812{
1813 CONTRACTL
1814 {
1815 NOTHROW;
1816 GC_NOTRIGGER;
1817 SO_TOLERANT;
1818 MODE_ANY;
1819 SUPPORTS_DAC;
1820 }
1821 CONTRACTL_END;
1822
1823 _ASSERTE(pAssembly != NULL && file != NULL);
1824
1825 // Some modules are never EnC-capable
1826 return ! (pAssembly->GetDebuggerInfoBits() & DACF_ALLOW_JIT_OPTS ||
1827 file->IsSystem() ||
1828 file->IsResource() ||
1829 file->HasNativeImage() ||
1830 file->IsDynamic());
1831}
1832
1833BOOL Module::IsManifest()
1834{
1835 WRAPPER_NO_CONTRACT;
1836 return dac_cast<TADDR>(GetAssembly()->GetManifestModule()) ==
1837 dac_cast<TADDR>(this);
1838}
1839
1840DomainAssembly* Module::GetDomainAssembly(AppDomain *pDomain)
1841{
1842 CONTRACT(DomainAssembly *)
1843 {
1844 INSTANCE_CHECK;
1845 PRECONDITION(CheckPointer(pDomain, NULL_OK));
1846 POSTCONDITION(CheckPointer(RETVAL));
1847 THROWS;
1848 GC_TRIGGERS;
1849 MODE_ANY;
1850 }
1851 CONTRACT_END;
1852
1853 if (IsManifest())
1854 RETURN (DomainAssembly *) GetDomainFile(pDomain);
1855 else
1856 RETURN (DomainAssembly *) m_pAssembly->GetDomainAssembly(pDomain);
1857}
1858
1859DomainFile *Module::GetDomainFile(AppDomain *pDomain)
1860{
1861 CONTRACT(DomainFile *)
1862 {
1863 INSTANCE_CHECK;
1864 PRECONDITION(CheckPointer(pDomain));
1865 POSTCONDITION(CheckPointer(RETVAL));
1866 GC_TRIGGERS;
1867 THROWS;
1868 MODE_ANY;
1869 SUPPORTS_DAC;
1870 }
1871 CONTRACT_END;
1872
1873 if (Module::IsEncodedModuleIndex(GetModuleID()))
1874 {
1875 DomainLocalBlock *pLocalBlock = pDomain->GetDomainLocalBlock();
1876 DomainFile *pDomainFile = pLocalBlock->TryGetDomainFile(GetModuleIndex());
1877
1878 RETURN (PTR_DomainFile) pDomainFile;
1879 }
1880 else
1881 {
1882 RETURN dac_cast<PTR_DomainFile>(m_ModuleID->GetDomainFile());
1883 }
1884}
1885
1886DomainAssembly* Module::FindDomainAssembly(AppDomain *pDomain)
1887{
1888 CONTRACT(DomainAssembly *)
1889 {
1890 INSTANCE_CHECK;
1891 PRECONDITION(CheckPointer(pDomain));
1892 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1893 NOTHROW;
1894 GC_NOTRIGGER;
1895 MODE_ANY;
1896 SO_TOLERANT;
1897 SUPPORTS_DAC;
1898 }
1899 CONTRACT_END;
1900
1901 if (IsManifest())
1902 RETURN dac_cast<PTR_DomainAssembly>(FindDomainFile(pDomain));
1903 else
1904 RETURN m_pAssembly->FindDomainAssembly(pDomain);
1905}
1906
1907DomainModule *Module::GetDomainModule(AppDomain *pDomain)
1908{
1909 CONTRACT(DomainModule *)
1910 {
1911 INSTANCE_CHECK;
1912 PRECONDITION(CheckPointer(pDomain));
1913 PRECONDITION(!IsManifest());
1914 POSTCONDITION(CheckPointer(RETVAL));
1915
1916 THROWS;
1917 GC_TRIGGERS;
1918 MODE_ANY;
1919 }
1920 CONTRACT_END;
1921
1922 RETURN (DomainModule *) GetDomainFile(pDomain);
1923}
1924
1925DomainFile *Module::FindDomainFile(AppDomain *pDomain)
1926{
1927 CONTRACT(DomainFile *)
1928 {
1929 INSTANCE_CHECK;
1930 PRECONDITION(CheckPointer(pDomain));
1931 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1932 NOTHROW;
1933 GC_NOTRIGGER;
1934 MODE_ANY;
1935 SO_TOLERANT;
1936 SUPPORTS_DAC;
1937 }
1938 CONTRACT_END;
1939
1940 if (Module::IsEncodedModuleIndex(GetModuleID()))
1941 {
1942 DomainLocalBlock *pLocalBlock = pDomain->GetDomainLocalBlock();
1943 RETURN pLocalBlock->TryGetDomainFile(GetModuleIndex());
1944 }
1945 else
1946 {
1947 RETURN m_ModuleID->GetDomainFile();
1948 }
1949}
1950
1951DomainModule *Module::FindDomainModule(AppDomain *pDomain)
1952{
1953 CONTRACT(DomainModule *)
1954 {
1955 INSTANCE_CHECK;
1956 PRECONDITION(CheckPointer(pDomain));
1957 PRECONDITION(!IsManifest());
1958 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1959 GC_NOTRIGGER;
1960 NOTHROW;
1961 MODE_ANY;
1962 }
1963 CONTRACT_END;
1964
1965 RETURN (DomainModule *) FindDomainFile(pDomain);
1966}
1967
1968#ifndef DACCESS_COMPILE
1969#include "staticallocationhelpers.inl"
1970
1971// Parses metadata and initializes offsets of per-class static blocks.
1972void Module::BuildStaticsOffsets(AllocMemTracker *pamTracker)
1973{
1974 STANDARD_VM_CONTRACT;
1975
1976 // Trade off here. We want a slot for each type. That way we can get to 2 bits per class and
1977 // index directly and not need a mapping from ClassID to MethodTable (we will use the RID
1978 // as the mapping)
1979 IMDInternalImport *pImport = GetMDImport();
1980
1981 DWORD * pRegularStaticOffsets = NULL;
1982 DWORD * pThreadStaticOffsets = NULL;
1983
1984 // Get the number of types/classes defined in this module. Add 1 to count the module itself
1985 DWORD dwNumTypes = pImport->GetCountWithTokenKind(mdtTypeDef) + 1; // +1 for module type
1986
1987 // [0] covers regular statics, [1] covers thread statics
1988 DWORD dwGCHandles[2] = { 0, 0 };
1989
1990 // Organization in memory of the static block
1991 //
1992 //
1993 // | GC Statics |
1994 // |
1995 // |
1996 // | Class Data (one byte per class) | pointer to gc statics | primitive type statics |
1997 //
1998 //
1999#ifndef CROSSBITNESS_COMPILE
2000 // The assertions must hold in every non-crossbitness scenario
2001 _ASSERTE(OFFSETOF__DomainLocalModule__m_pDataBlob_ == DomainLocalModule::OffsetOfDataBlob());
2002 _ASSERTE(OFFSETOF__ThreadLocalModule__m_pDataBlob == ThreadLocalModule::OffsetOfDataBlob());
2003#endif
2004
2005 DWORD dwNonGCBytes[2] = {
2006 DomainLocalModule::OffsetOfDataBlob() + sizeof(BYTE)*dwNumTypes,
2007 ThreadLocalModule::OffsetOfDataBlob() + sizeof(BYTE)*dwNumTypes
2008 };
2009
2010 HENUMInternalHolder hTypeEnum(pImport);
2011 hTypeEnum.EnumAllInit(mdtTypeDef);
2012
2013 mdTypeDef type;
2014 // Parse each type of the class
2015 while (pImport->EnumNext(&hTypeEnum, &type))
2016 {
2017 // Set offset for this type
2018 DWORD dwIndex = RidFromToken(type) - 1;
2019
2020 // [0] covers regular statics, [1] covers thread statics
2021 DWORD dwAlignment[2] = { 1, 1 };
2022 DWORD dwClassNonGCBytes[2] = { 0, 0 };
2023 DWORD dwClassGCHandles[2] = { 0, 0 };
2024
2025 // need to check if the type is generic and if so exclude it from iteration as we don't know the size
2026 HENUMInternalHolder hGenericEnum(pImport);
2027 hGenericEnum.EnumInit(mdtGenericParam, type);
2028 ULONG cGenericParams = pImport->EnumGetCount(&hGenericEnum);
2029 if (cGenericParams == 0)
2030 {
2031 HENUMInternalHolder hFieldEnum(pImport);
2032 hFieldEnum.EnumInit(mdtFieldDef, type);
2033
2034 mdFieldDef field;
2035 // Parse each field of the type
2036 while (pImport->EnumNext(&hFieldEnum, &field))
2037 {
2038 BOOL fSkip = FALSE;
2039
2040 CorElementType ElementType = ELEMENT_TYPE_END;
2041 mdToken tkValueTypeToken = 0;
2042 int kk; // Use one set of variables for regular statics, and the other set for thread statics
2043
2044 fSkip = GetStaticFieldElementTypeForFieldDef(this, pImport, field, &ElementType, &tkValueTypeToken, &kk);
2045 if (fSkip)
2046 continue;
2047
2048 // We account for "regular statics" and "thread statics" separately.
2049 // Currently we are lumping RVA into "regular statics",
2050 // but we probably shouldn't.
2051 switch (ElementType)
2052 {
2053 case ELEMENT_TYPE_I1:
2054 case ELEMENT_TYPE_U1:
2055 case ELEMENT_TYPE_BOOLEAN:
2056 dwClassNonGCBytes[kk] += 1;
2057 break;
2058 case ELEMENT_TYPE_I2:
2059 case ELEMENT_TYPE_U2:
2060 case ELEMENT_TYPE_CHAR:
2061 dwAlignment[kk] = max(2, dwAlignment[kk]);
2062 dwClassNonGCBytes[kk] += 2;
2063 break;
2064 case ELEMENT_TYPE_I4:
2065 case ELEMENT_TYPE_U4:
2066 case ELEMENT_TYPE_R4:
2067 dwAlignment[kk] = max(4, dwAlignment[kk]);
2068 dwClassNonGCBytes[kk] += 4;
2069 break;
2070 case ELEMENT_TYPE_FNPTR:
2071 case ELEMENT_TYPE_PTR:
2072 case ELEMENT_TYPE_I:
2073 case ELEMENT_TYPE_U:
2074 dwAlignment[kk] = max((1 << LOG2_PTRSIZE), dwAlignment[kk]);
2075 dwClassNonGCBytes[kk] += (1 << LOG2_PTRSIZE);
2076 break;
2077 case ELEMENT_TYPE_I8:
2078 case ELEMENT_TYPE_U8:
2079 case ELEMENT_TYPE_R8:
2080 dwAlignment[kk] = max(8, dwAlignment[kk]);
2081 dwClassNonGCBytes[kk] += 8;
2082 break;
2083 case ELEMENT_TYPE_VAR:
2084 case ELEMENT_TYPE_MVAR:
2085 case ELEMENT_TYPE_STRING:
2086 case ELEMENT_TYPE_SZARRAY:
2087 case ELEMENT_TYPE_ARRAY:
2088 case ELEMENT_TYPE_CLASS:
2089 case ELEMENT_TYPE_OBJECT:
2090 dwClassGCHandles[kk] += 1;
2091 break;
2092 case ELEMENT_TYPE_VALUETYPE:
2093 // Statics for valuetypes where the valuetype is defined in this module are handled here. Other valuetype statics utilize the pessimistic model below.
2094 dwClassGCHandles[kk] += 1;
2095 break;
2096 case ELEMENT_TYPE_END:
2097 default:
2098 // The actual element type was ELEMENT_TYPE_VALUETYPE, but the as we don't want to load additional assemblies
2099 // to determine these static offsets, we've fallen back to a pessimistic model.
2100 if (tkValueTypeToken != 0)
2101 {
2102 // We'll have to be pessimistic here
2103 dwClassNonGCBytes[kk] += MAX_PRIMITIVE_FIELD_SIZE;
2104 dwAlignment[kk] = max(MAX_PRIMITIVE_FIELD_SIZE, dwAlignment[kk]);
2105
2106 dwClassGCHandles[kk] += 1;
2107 break;
2108 }
2109 else
2110 {
2111 // field has an unexpected type
2112 ThrowHR(VER_E_FIELD_SIG);
2113 break;
2114 }
2115 }
2116 }
2117
2118 if (pRegularStaticOffsets == NULL && (dwClassGCHandles[0] != 0 || dwClassNonGCBytes[0] != 0))
2119 {
2120 // Lazily allocate table for offsets. We need offsets for GC and non GC areas. We add +1 to use as a sentinel.
2121 pRegularStaticOffsets = (PTR_DWORD)pamTracker->Track(
2122 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
2123 (S_SIZE_T(2 * sizeof(DWORD))*(S_SIZE_T(dwNumTypes)+S_SIZE_T(1)))));
2124
2125 for (DWORD i = 0; i < dwIndex; i++) {
2126 pRegularStaticOffsets[i * 2 ] = dwGCHandles[0]*TARGET_POINTER_SIZE;
2127 pRegularStaticOffsets[i * 2 + 1] = dwNonGCBytes[0];
2128 }
2129 }
2130
2131 if (pThreadStaticOffsets == NULL && (dwClassGCHandles[1] != 0 || dwClassNonGCBytes[1] != 0))
2132 {
2133 // Lazily allocate table for offsets. We need offsets for GC and non GC areas. We add +1 to use as a sentinel.
2134 pThreadStaticOffsets = (PTR_DWORD)pamTracker->Track(
2135 GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
2136 (S_SIZE_T(2 * sizeof(DWORD))*(S_SIZE_T(dwNumTypes)+S_SIZE_T(1)))));
2137
2138 for (DWORD i = 0; i < dwIndex; i++) {
2139 pThreadStaticOffsets[i * 2 ] = dwGCHandles[1]*TARGET_POINTER_SIZE;
2140 pThreadStaticOffsets[i * 2 + 1] = dwNonGCBytes[1];
2141 }
2142 }
2143 }
2144
2145 if (pRegularStaticOffsets != NULL)
2146 {
2147 // Align the offset of non gc statics
2148 dwNonGCBytes[0] = (DWORD) ALIGN_UP(dwNonGCBytes[0], dwAlignment[0]);
2149
2150 // Save current offsets
2151 pRegularStaticOffsets[dwIndex*2] = dwGCHandles[0]*TARGET_POINTER_SIZE;
2152 pRegularStaticOffsets[dwIndex*2 + 1] = dwNonGCBytes[0];
2153
2154 // Increment for next class
2155 dwGCHandles[0] += dwClassGCHandles[0];
2156 dwNonGCBytes[0] += dwClassNonGCBytes[0];
2157 }
2158
2159 if (pThreadStaticOffsets != NULL)
2160 {
2161 // Align the offset of non gc statics
2162 dwNonGCBytes[1] = (DWORD) ALIGN_UP(dwNonGCBytes[1], dwAlignment[1]);
2163
2164 // Save current offsets
2165 pThreadStaticOffsets[dwIndex*2] = dwGCHandles[1]*TARGET_POINTER_SIZE;
2166 pThreadStaticOffsets[dwIndex*2 + 1] = dwNonGCBytes[1];
2167
2168 // Increment for next class
2169 dwGCHandles[1] += dwClassGCHandles[1];
2170 dwNonGCBytes[1] += dwClassNonGCBytes[1];
2171 }
2172 }
2173
2174 m_maxTypeRidStaticsAllocated = dwNumTypes;
2175
2176 if (pRegularStaticOffsets != NULL)
2177 {
2178 pRegularStaticOffsets[dwNumTypes*2] = dwGCHandles[0]*TARGET_POINTER_SIZE;
2179 pRegularStaticOffsets[dwNumTypes*2 + 1] = dwNonGCBytes[0];
2180 }
2181
2182 if (pThreadStaticOffsets != NULL)
2183 {
2184 pThreadStaticOffsets[dwNumTypes*2] = dwGCHandles[1]*TARGET_POINTER_SIZE;
2185 pThreadStaticOffsets[dwNumTypes*2 + 1] = dwNonGCBytes[1];
2186 }
2187
2188 m_pRegularStaticOffsets = pRegularStaticOffsets;
2189 m_pThreadStaticOffsets = pThreadStaticOffsets;
2190
2191 m_dwMaxGCRegularStaticHandles = dwGCHandles[0];
2192 m_dwMaxGCThreadStaticHandles = dwGCHandles[1];
2193
2194 m_dwRegularStaticsBlockSize = dwNonGCBytes[0];
2195 m_dwThreadStaticsBlockSize = dwNonGCBytes[1];
2196}
2197
2198void Module::GetOffsetsForRegularStaticData(
2199 mdToken cl,
2200 BOOL bDynamic, DWORD dwGCStaticHandles,
2201 DWORD dwNonGCStaticBytes,
2202 DWORD * pOutStaticHandleOffset,
2203 DWORD * pOutNonGCStaticOffset)
2204{
2205 CONTRACTL
2206 {
2207 THROWS;
2208 GC_TRIGGERS;
2209 INJECT_FAULT(COMPlusThrowOM());
2210 }
2211 CONTRACTL_END
2212
2213 *pOutStaticHandleOffset = 0;
2214 *pOutNonGCStaticOffset = 0;
2215
2216 if (!dwGCStaticHandles && !dwNonGCStaticBytes)
2217 {
2218 return;
2219 }
2220
2221#ifndef CROSSBITNESS_COMPILE
2222 _ASSERTE(OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob == DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob());
2223#endif
2224 // Statics for instantiated types are allocated dynamically per-instantiation
2225 if (bDynamic)
2226 {
2227 // Non GC statics are embedded in the Dynamic Entry.
2228 *pOutNonGCStaticOffset = OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob;
2229 return;
2230 }
2231
2232 if (m_pRegularStaticOffsets == NULL)
2233 {
2234 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2235 }
2236 _ASSERTE(m_pRegularStaticOffsets != (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED);
2237
2238 // We allocate in the big blob.
2239 DWORD index = RidFromToken(cl) - 1;
2240
2241 *pOutStaticHandleOffset = m_pRegularStaticOffsets[index*2];
2242
2243 *pOutNonGCStaticOffset = m_pRegularStaticOffsets[index*2 + 1];
2244#ifdef CROSSBITNESS_COMPILE
2245 *pOutNonGCStaticOffset += OFFSETOF__DomainLocalModule__m_pDataBlob_ - DomainLocalModule::OffsetOfDataBlob();
2246#endif
2247
2248 // Check we didnt go out of what we predicted we would need for the class
2249 if (*pOutStaticHandleOffset + TARGET_POINTER_SIZE*dwGCStaticHandles >
2250 m_pRegularStaticOffsets[(index+1)*2] ||
2251 *pOutNonGCStaticOffset + dwNonGCStaticBytes >
2252 m_pRegularStaticOffsets[(index+1)*2 + 1])
2253 { // It's most likely that this is due to bad metadata, thus the exception. However, the
2254 // previous comments for this bit of code mentioned that this could be a corner case bug
2255 // with static field size estimation, though this is entirely unlikely since the code has
2256 // been this way for at least two releases.
2257 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2258 }
2259}
2260
2261
2262void Module::GetOffsetsForThreadStaticData(
2263 mdToken cl,
2264 BOOL bDynamic, DWORD dwGCStaticHandles,
2265 DWORD dwNonGCStaticBytes,
2266 DWORD * pOutStaticHandleOffset,
2267 DWORD * pOutNonGCStaticOffset)
2268{
2269 CONTRACTL
2270 {
2271 THROWS;
2272 GC_TRIGGERS;
2273 INJECT_FAULT(COMPlusThrowOM());
2274 }
2275 CONTRACTL_END
2276
2277 *pOutStaticHandleOffset = 0;
2278 *pOutNonGCStaticOffset = 0;
2279
2280 if (!dwGCStaticHandles && !dwNonGCStaticBytes)
2281 {
2282 return;
2283 }
2284
2285#ifndef CROSSBITNESS_COMPILE
2286 _ASSERTE(OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob == ThreadLocalModule::DynamicEntry::GetOffsetOfDataBlob());
2287#endif
2288 // Statics for instantiated types are allocated dynamically per-instantiation
2289 if (bDynamic)
2290 {
2291 // Non GC thread statics are embedded in the Dynamic Entry.
2292 *pOutNonGCStaticOffset = OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob;
2293 return;
2294 }
2295
2296 if (m_pThreadStaticOffsets == NULL)
2297 {
2298 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2299 }
2300 _ASSERTE(m_pThreadStaticOffsets != (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED);
2301
2302 // We allocate in the big blob.
2303 DWORD index = RidFromToken(cl) - 1;
2304
2305 *pOutStaticHandleOffset = m_pThreadStaticOffsets[index*2];
2306
2307 *pOutNonGCStaticOffset = m_pThreadStaticOffsets[index*2 + 1];
2308#ifdef CROSSBITNESS_COMPILE
2309 *pOutNonGCStaticOffset += OFFSETOF__ThreadLocalModule__m_pDataBlob - ThreadLocalModule::GetOffsetOfDataBlob();
2310#endif
2311
2312 // Check we didnt go out of what we predicted we would need for the class
2313 if (*pOutStaticHandleOffset + TARGET_POINTER_SIZE*dwGCStaticHandles >
2314 m_pThreadStaticOffsets[(index+1)*2] ||
2315 *pOutNonGCStaticOffset + dwNonGCStaticBytes >
2316 m_pThreadStaticOffsets[(index+1)*2 + 1])
2317 {
2318 // It's most likely that this is due to bad metadata, thus the exception. However, the
2319 // previous comments for this bit of code mentioned that this could be a corner case bug
2320 // with static field size estimation, though this is entirely unlikely since the code has
2321 // been this way for at least two releases.
2322 THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this);
2323 }
2324}
2325
2326
2327// initialize Crst controlling the Dynamic IL hashtable
2328void Module::InitializeDynamicILCrst()
2329{
2330 Crst * pCrst = new Crst(CrstDynamicIL, CrstFlags(CRST_UNSAFE_ANYMODE | CRST_DEBUGGER_THREAD));
2331 if (InterlockedCompareExchangeT(
2332 &m_debuggerSpecificData.m_pDynamicILCrst, pCrst, NULL) != NULL)
2333 {
2334 delete pCrst;
2335 }
2336}
2337
2338// Add a (token, address) pair to the table of IL blobs for reflection/dynamics
2339// Arguments:
2340// Input:
2341// token method token
2342// blobAddress address of the start of the IL blob address, including the header
2343// fTemporaryOverride
2344// is this a permanent override that should go in the
2345// DynamicILBlobTable, or a temporary one?
2346// Output: not explicit, but if the pair was not already in the table it will be added.
2347// Does not add duplicate tokens to the table.
2348
2349void Module::SetDynamicIL(mdToken token, TADDR blobAddress, BOOL fTemporaryOverride)
2350{
2351 DynamicILBlobEntry entry = {mdToken(token), TADDR(blobAddress)};
2352
2353 // Lazily allocate a Crst to serialize update access to the info structure.
2354 // Carefully synchronize to ensure we don't leak a Crst in race conditions.
2355 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2356 {
2357 InitializeDynamicILCrst();
2358 }
2359
2360 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2361
2362 // Figure out which table to fill in
2363 PTR_DynamicILBlobTable &table(fTemporaryOverride ? m_debuggerSpecificData.m_pTemporaryILBlobTable
2364 : m_debuggerSpecificData.m_pDynamicILBlobTable);
2365
2366 // Lazily allocate the hash table.
2367 if (table == NULL)
2368 {
2369 table = PTR_DynamicILBlobTable(new DynamicILBlobTable);
2370 }
2371 table->AddOrReplace(entry);
2372}
2373
2374#endif // !DACCESS_COMPILE
2375
2376// Get the stored address of the IL blob for reflection/dynamics
2377// Arguments:
2378// Input:
2379// token method token
2380// fAllowTemporary also check the temporary overrides
2381// Return Value: starting (target) address of the IL blob corresponding to the input token
2382
2383TADDR Module::GetDynamicIL(mdToken token, BOOL fAllowTemporary)
2384{
2385 SUPPORTS_DAC;
2386
2387#ifndef DACCESS_COMPILE
2388 // The Crst to serialize update access to the info structure is lazily allocated.
2389 // If it hasn't been allocated yet, then we don't have any IL blobs (temporary or otherwise)
2390 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2391 {
2392 return TADDR(NULL);
2393 }
2394
2395 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2396#endif
2397
2398 // Both hash tables are lazily allocated, so if they're NULL
2399 // then we have no IL blobs
2400
2401 if (fAllowTemporary && m_debuggerSpecificData.m_pTemporaryILBlobTable != NULL)
2402 {
2403 DynamicILBlobEntry entry = m_debuggerSpecificData.m_pTemporaryILBlobTable->Lookup(token);
2404
2405 // Only return a value if the lookup succeeded
2406 if (!DynamicILBlobTraits::IsNull(entry))
2407 {
2408 return entry.m_il;
2409 }
2410 }
2411
2412 if (m_debuggerSpecificData.m_pDynamicILBlobTable == NULL)
2413 {
2414 return TADDR(NULL);
2415 }
2416
2417 DynamicILBlobEntry entry = m_debuggerSpecificData.m_pDynamicILBlobTable->Lookup(token);
2418 // If the lookup fails, it returns the 'NULL' entry
2419 // The 'NULL' entry has m_il set to NULL, so either way we're safe
2420 return entry.m_il;
2421}
2422
2423#if !defined(DACCESS_COMPILE)
2424//---------------------------------------------------------------------------------------
2425//
2426// Add instrumented IL offset mapping for the specified method.
2427//
2428// Arguments:
2429// token - the MethodDef token of the method in question
2430// mapping - the mapping information between original IL offsets and instrumented IL offsets
2431//
2432// Notes:
2433// * Once added, the mapping stays valid until the Module containing the method is destructed.
2434// * The profiler may potentially update the mapping more than once.
2435//
2436
2437void Module::SetInstrumentedILOffsetMapping(mdMethodDef token, InstrumentedILOffsetMapping mapping)
2438{
2439 ILOffsetMappingEntry entry(token, mapping);
2440
2441 // Lazily allocate a Crst to serialize update access to the hash table.
2442 // Carefully synchronize to ensure we don't leak a Crst in race conditions.
2443 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2444 {
2445 InitializeDynamicILCrst();
2446 }
2447
2448 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2449
2450 // Lazily allocate the hash table.
2451 if (m_debuggerSpecificData.m_pILOffsetMappingTable == NULL)
2452 {
2453 m_debuggerSpecificData.m_pILOffsetMappingTable = PTR_ILOffsetMappingTable(new ILOffsetMappingTable);
2454 }
2455
2456 ILOffsetMappingEntry currentEntry = m_debuggerSpecificData.m_pILOffsetMappingTable->Lookup(ILOffsetMappingTraits::GetKey(entry));
2457 if (!ILOffsetMappingTraits::IsNull(currentEntry))
2458 currentEntry.m_mapping.Clear();
2459
2460 m_debuggerSpecificData.m_pILOffsetMappingTable->AddOrReplace(entry);
2461}
2462#endif // DACCESS_COMPILE
2463
2464//---------------------------------------------------------------------------------------
2465//
2466// Retrieve the instrumented IL offset mapping for the specified method.
2467//
2468// Arguments:
2469// token - the MethodDef token of the method in question
2470//
2471// Return Value:
2472// Return the mapping information between original IL offsets and instrumented IL offsets.
2473// Check InstrumentedILOffsetMapping::IsNull() to see if any mapping is available.
2474//
2475// Notes:
2476// * Once added, the mapping stays valid until the Module containing the method is destructed.
2477// * The profiler may potentially update the mapping more than once.
2478//
2479
2480InstrumentedILOffsetMapping Module::GetInstrumentedILOffsetMapping(mdMethodDef token)
2481{
2482 CONTRACTL
2483 {
2484 THROWS;
2485 GC_NOTRIGGER;
2486 MODE_ANY;
2487 SUPPORTS_DAC;
2488 }
2489 CONTRACTL_END;
2490
2491 // Lazily allocate a Crst to serialize update access to the hash table.
2492 // If the Crst is NULL, then we couldn't possibly have added any mapping yet, so just return NULL.
2493 if (m_debuggerSpecificData.m_pDynamicILCrst == NULL)
2494 {
2495 InstrumentedILOffsetMapping emptyMapping;
2496 return emptyMapping;
2497 }
2498
2499 CrstHolder ch(m_debuggerSpecificData.m_pDynamicILCrst);
2500
2501 // If the hash table hasn't been created, then we couldn't possibly have added any mapping yet,
2502 // so just return NULL.
2503 if (m_debuggerSpecificData.m_pILOffsetMappingTable == NULL)
2504 {
2505 InstrumentedILOffsetMapping emptyMapping;
2506 return emptyMapping;
2507 }
2508
2509 ILOffsetMappingEntry entry = m_debuggerSpecificData.m_pILOffsetMappingTable->Lookup(token);
2510 return entry.m_mapping;
2511}
2512
2513#undef DECODE_TYPEID
2514#undef ENCODE_TYPEID
2515#undef IS_ENCODED_TYPEID
2516
2517
2518
2519#ifndef DACCESS_COMPILE
2520
2521
2522BOOL Module::IsNoStringInterning()
2523{
2524 CONTRACTL
2525 {
2526 THROWS;
2527 GC_TRIGGERS;
2528 }
2529 CONTRACTL_END
2530
2531 if (!(m_dwPersistedFlags & COMPUTED_STRING_INTERNING))
2532 {
2533 // The flags should be precomputed in native images
2534 _ASSERTE(!HasNativeImage());
2535
2536 // Default is string interning
2537 BOOL fNoStringInterning = FALSE;
2538
2539 HRESULT hr;
2540
2541 // This flag applies to assembly, but it is stored on module so it can be cached in ngen image
2542 // Thus, we should ever need it for manifest module only.
2543 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2544 _ASSERTE(mdImport);
2545
2546 mdToken token;
2547 IfFailThrow(mdImport->GetAssemblyFromScope(&token));
2548
2549 const BYTE *pVal;
2550 ULONG cbVal;
2551
2552 hr = mdImport->GetCustomAttributeByName(token,
2553 COMPILATIONRELAXATIONS_TYPE,
2554 (const void**)&pVal, &cbVal);
2555
2556 // Parse the attribute
2557 if (hr == S_OK)
2558 {
2559 CustomAttributeParser cap(pVal, cbVal);
2560 IfFailThrow(cap.SkipProlog());
2561
2562 // Get Flags
2563 UINT32 flags;
2564 IfFailThrow(cap.GetU4(&flags));
2565
2566 if (flags & CompilationRelaxations_NoStringInterning)
2567 {
2568 fNoStringInterning = TRUE;
2569 }
2570 }
2571
2572#ifdef _DEBUG
2573 static ConfigDWORD g_NoStringInterning;
2574 DWORD dwOverride = g_NoStringInterning.val(CLRConfig::INTERNAL_NoStringInterning);
2575
2576 if (dwOverride == 0)
2577 {
2578 // Disabled
2579 fNoStringInterning = FALSE;
2580 }
2581 else if (dwOverride == 2)
2582 {
2583 // Always true (testing)
2584 fNoStringInterning = TRUE;
2585 }
2586#endif // _DEBUG
2587
2588 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_STRING_INTERNING |
2589 (fNoStringInterning ? NO_STRING_INTERNING : 0));
2590 }
2591
2592 return !!(m_dwPersistedFlags & NO_STRING_INTERNING);
2593}
2594
2595BOOL Module::GetNeutralResourcesLanguage(LPCUTF8 * cultureName, ULONG * cultureNameLength, INT16 * fallbackLocation, BOOL cacheAttribute)
2596{
2597 STANDARD_VM_CONTRACT;
2598
2599 BOOL retVal = FALSE;
2600 if (!(m_dwPersistedFlags & NEUTRAL_RESOURCES_LANGUAGE_IS_CACHED))
2601 {
2602 const BYTE *pVal = NULL;
2603 ULONG cbVal = 0;
2604
2605 // This flag applies to assembly, but it is stored on module so it can be cached in ngen image
2606 // Thus, we should ever need it for manifest module only.
2607 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2608 _ASSERTE(mdImport);
2609
2610 mdToken token;
2611 IfFailThrow(mdImport->GetAssemblyFromScope(&token));
2612
2613 // Check for the existance of the attribute.
2614 HRESULT hr = mdImport->GetCustomAttributeByName(token,"System.Resources.NeutralResourcesLanguageAttribute",(const void **)&pVal, &cbVal);
2615 if (hr == S_OK) {
2616
2617 // we should not have a native image (it would have been cached at ngen time)
2618 _ASSERTE(!HasNativeImage());
2619
2620 CustomAttributeParser cap(pVal, cbVal);
2621 IfFailThrow(cap.SkipProlog());
2622 IfFailThrow(cap.GetString(cultureName, cultureNameLength));
2623 IfFailThrow(cap.GetI2(fallbackLocation));
2624 // Should only be true on Module.Save(). Update flag to show we have the attribute cached
2625 if (cacheAttribute)
2626 FastInterlockOr(&m_dwPersistedFlags, NEUTRAL_RESOURCES_LANGUAGE_IS_CACHED);
2627
2628 retVal = TRUE;
2629 }
2630 }
2631 else
2632 {
2633 *cultureName = m_pszCultureName;
2634 *cultureNameLength = m_CultureNameLength;
2635 *fallbackLocation = m_FallbackLocation;
2636 retVal = TRUE;
2637
2638#ifdef _DEBUG
2639 // confirm that the NGENed attribute is correct
2640 LPCUTF8 pszCultureNameCheck = NULL;
2641 ULONG cultureNameLengthCheck = 0;
2642 INT16 fallbackLocationCheck = 0;
2643 const BYTE *pVal = NULL;
2644 ULONG cbVal = 0;
2645
2646 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2647 _ASSERTE(mdImport);
2648 mdToken token;
2649 IfFailThrow(mdImport->GetAssemblyFromScope(&token));
2650
2651 // Confirm that the attribute exists, and has the save value as when we ngen'd it
2652 HRESULT hr = mdImport->GetCustomAttributeByName(token,"System.Resources.NeutralResourcesLanguageAttribute",(const void **)&pVal, &cbVal);
2653 _ASSERTE(hr == S_OK);
2654 CustomAttributeParser cap(pVal, cbVal);
2655 IfFailThrow(cap.SkipProlog());
2656 IfFailThrow(cap.GetString(&pszCultureNameCheck, &cultureNameLengthCheck));
2657 IfFailThrow(cap.GetI2(&fallbackLocationCheck));
2658 _ASSERTE(cultureNameLengthCheck == m_CultureNameLength);
2659 _ASSERTE(fallbackLocationCheck == m_FallbackLocation);
2660 _ASSERTE(strncmp(pszCultureNameCheck,m_pszCultureName,m_CultureNameLength) == 0);
2661#endif // _DEBUG
2662 }
2663
2664 return retVal;
2665}
2666
2667
2668BOOL Module::HasDefaultDllImportSearchPathsAttribute()
2669{
2670 CONTRACTL
2671 {
2672 THROWS;
2673 GC_NOTRIGGER;
2674 MODE_ANY;
2675 }
2676 CONTRACTL_END;
2677
2678 if(IsDefaultDllImportSearchPathsAttributeCached())
2679 {
2680 return (m_dwPersistedFlags & DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS) != 0 ;
2681 }
2682 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2683
2684 BOOL attributeIsFound = FALSE;
2685 attributeIsFound = GetDefaultDllImportSearchPathsAttributeValue(mdImport, TokenFromRid(1, mdtAssembly),&m_DefaultDllImportSearchPathsAttributeValue);
2686 if(attributeIsFound)
2687 {
2688 FastInterlockOr(&m_dwPersistedFlags, DEFAULT_DLL_IMPORT_SEARCH_PATHS_IS_CACHED | DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS);
2689 }
2690 else
2691 {
2692 FastInterlockOr(&m_dwPersistedFlags, DEFAULT_DLL_IMPORT_SEARCH_PATHS_IS_CACHED);
2693 }
2694
2695 return (m_dwPersistedFlags & DEFAULT_DLL_IMPORT_SEARCH_PATHS_STATUS) != 0 ;
2696}
2697
2698// Returns a BOOL to indicate if we have computed whether compiler has instructed us to
2699// wrap the non-CLS compliant exceptions or not.
2700BOOL Module::IsRuntimeWrapExceptionsStatusComputed()
2701{
2702 LIMITED_METHOD_CONTRACT;
2703
2704 return (m_dwPersistedFlags & COMPUTED_WRAP_EXCEPTIONS);
2705}
2706
2707BOOL Module::IsRuntimeWrapExceptions()
2708{
2709 CONTRACTL
2710 {
2711 THROWS;
2712 if (IsRuntimeWrapExceptionsStatusComputed()) GC_NOTRIGGER; else GC_TRIGGERS;
2713 MODE_ANY;
2714 }
2715 CONTRACTL_END
2716
2717 if (!(IsRuntimeWrapExceptionsStatusComputed()))
2718 {
2719 // The flags should be precomputed in native images
2720 _ASSERTE(!HasNativeImage());
2721
2722 HRESULT hr;
2723 BOOL fRuntimeWrapExceptions = FALSE;
2724
2725 // This flag applies to assembly, but it is stored on module so it can be cached in ngen image
2726 // Thus, we should ever need it for manifest module only.
2727 IMDInternalImport *mdImport = GetAssembly()->GetManifestImport();
2728
2729 mdToken token;
2730 IfFailGo(mdImport->GetAssemblyFromScope(&token));
2731
2732 const BYTE *pVal;
2733 ULONG cbVal;
2734
2735 hr = mdImport->GetCustomAttributeByName(token,
2736 RUNTIMECOMPATIBILITY_TYPE,
2737 (const void**)&pVal, &cbVal);
2738
2739 // Parse the attribute
2740 if (hr == S_OK)
2741 {
2742 CustomAttributeParser ca(pVal, cbVal);
2743 CaNamedArg namedArgs[1] = {{0}};
2744
2745 // First, the void constructor:
2746 IfFailGo(ParseKnownCaArgs(ca, NULL, 0));
2747
2748 // Then, find the named argument
2749 namedArgs[0].InitBoolField("WrapNonExceptionThrows");
2750
2751 IfFailGo(ParseKnownCaNamedArgs(ca, namedArgs, lengthof(namedArgs)));
2752
2753 if (namedArgs[0].val.boolean)
2754 fRuntimeWrapExceptions = TRUE;
2755 }
2756ErrExit:
2757 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_WRAP_EXCEPTIONS |
2758 (fRuntimeWrapExceptions ? WRAP_EXCEPTIONS : 0));
2759 }
2760
2761 return !!(m_dwPersistedFlags & WRAP_EXCEPTIONS);
2762}
2763
2764BOOL Module::IsPreV4Assembly()
2765{
2766 CONTRACTL
2767 {
2768 THROWS;
2769 GC_NOTRIGGER;
2770 SO_TOLERANT;
2771 }
2772 CONTRACTL_END
2773
2774 if (!(m_dwPersistedFlags & COMPUTED_IS_PRE_V4_ASSEMBLY))
2775 {
2776 // The flags should be precomputed in native images
2777 _ASSERTE(!HasNativeImage());
2778
2779 IMDInternalImport *pImport = GetAssembly()->GetManifestImport();
2780 _ASSERTE(pImport);
2781
2782 BOOL fIsPreV4Assembly = FALSE;
2783 LPCSTR szVersion = NULL;
2784 if (SUCCEEDED(pImport->GetVersionString(&szVersion)))
2785 {
2786 if (szVersion != NULL && strlen(szVersion) > 2)
2787 {
2788 fIsPreV4Assembly = (szVersion[0] == 'v' || szVersion[0] == 'V') &&
2789 (szVersion[1] == '1' || szVersion[1] == '2');
2790 }
2791 }
2792
2793 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_IS_PRE_V4_ASSEMBLY |
2794 (fIsPreV4Assembly ? IS_PRE_V4_ASSEMBLY : 0));
2795 }
2796
2797 return !!(m_dwPersistedFlags & IS_PRE_V4_ASSEMBLY);
2798}
2799
2800
2801ArrayDPTR(RelativeFixupPointer<PTR_MethodTable>) ModuleCtorInfo::GetGCStaticMTs(DWORD index)
2802{
2803 LIMITED_METHOD_CONTRACT;
2804
2805 if (index < numHotGCStaticsMTs)
2806 {
2807 _ASSERTE(ppHotGCStaticsMTs != NULL);
2808
2809 return ppHotGCStaticsMTs + index;
2810 }
2811 else
2812 {
2813 _ASSERTE(ppColdGCStaticsMTs != NULL);
2814
2815 // shift the start of the cold table because all cold offsets are also shifted
2816 return ppColdGCStaticsMTs + (index - numHotGCStaticsMTs);
2817 }
2818}
2819
2820DWORD Module::AllocateDynamicEntry(MethodTable *pMT)
2821{
2822 CONTRACTL
2823 {
2824 THROWS;
2825 GC_TRIGGERS;
2826 PRECONDITION(pMT->GetModuleForStatics() == this);
2827 PRECONDITION(pMT->IsDynamicStatics());
2828 PRECONDITION(!pMT->ContainsGenericVariables());
2829 }
2830 CONTRACTL_END;
2831
2832 DWORD newId = FastInterlockExchangeAdd((LONG*)&m_cDynamicEntries, 1);
2833
2834 if (newId >= m_maxDynamicEntries)
2835 {
2836 CrstHolder ch(&m_Crst);
2837
2838 if (newId >= m_maxDynamicEntries)
2839 {
2840 SIZE_T maxDynamicEntries = max(16, m_maxDynamicEntries);
2841 while (maxDynamicEntries <= newId)
2842 {
2843 maxDynamicEntries *= 2;
2844 }
2845
2846 DynamicStaticsInfo* pNewDynamicStaticsInfo = (DynamicStaticsInfo*)
2847 (void*)GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(DynamicStaticsInfo)) * S_SIZE_T(maxDynamicEntries));
2848
2849 if (m_pDynamicStaticsInfo)
2850 memcpy(pNewDynamicStaticsInfo, m_pDynamicStaticsInfo, sizeof(DynamicStaticsInfo) * m_maxDynamicEntries);
2851
2852 m_pDynamicStaticsInfo = pNewDynamicStaticsInfo;
2853 m_maxDynamicEntries = maxDynamicEntries;
2854 }
2855 }
2856
2857 EnsureWritablePages(&(m_pDynamicStaticsInfo[newId]))->pEnclosingMT = pMT;
2858
2859 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Assigned dynamic ID %d to %s\n", newId, pMT->GetDebugClassName()));
2860
2861 return newId;
2862}
2863
2864void Module::FreeModuleIndex()
2865{
2866 CONTRACTL
2867 {
2868 NOTHROW;
2869 GC_NOTRIGGER;
2870 MODE_ANY;
2871 }
2872 CONTRACTL_END;
2873 if (m_ModuleID != NULL)
2874 {
2875 // Module's m_ModuleID should not contain the ID, it should
2876 // contain a pointer to the DLM
2877 _ASSERTE(!Module::IsEncodedModuleIndex((SIZE_T)m_ModuleID));
2878 _ASSERTE(m_ModuleIndex == m_ModuleID->GetModuleIndex());
2879
2880#ifndef CROSSGEN_COMPILE
2881 if (IsCollectible())
2882 {
2883 ThreadStoreLockHolder tsLock;
2884 Thread *pThread = NULL;
2885 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
2886 {
2887 pThread->DeleteThreadStaticData(m_ModuleIndex);
2888 }
2889 }
2890#endif // CROSSGEN_COMPILE
2891
2892 // Get the ModuleIndex from the DLM and free it
2893 Module::FreeModuleIndex(m_ModuleIndex);
2894 }
2895 else
2896 {
2897 // This was an empty, short-lived Module object that
2898 // was never assigned a ModuleIndex...
2899 }
2900}
2901
2902
2903
2904
2905ModuleIndex Module::AllocateModuleIndex()
2906{
2907 DWORD val;
2908 g_pModuleIndexDispenser->NewId(NULL, val);
2909
2910 // For various reasons, the IDs issued by the IdDispenser start at 1.
2911 // Domain neutral module IDs have historically started at 0, and we
2912 // have always assigned ID 0 to mscorlib. Thus, to make it so that
2913 // domain neutral module IDs start at 0, we will subtract 1 from the
2914 // ID that we got back from the ID dispenser.
2915 ModuleIndex index((SIZE_T)(val-1));
2916
2917 return index;
2918}
2919
2920void Module::FreeModuleIndex(ModuleIndex index)
2921{
2922 WRAPPER_NO_CONTRACT;
2923 // We subtracted 1 after we allocated this ID, so we need to
2924 // add 1 before we free it.
2925 DWORD val = index.m_dwIndex + 1;
2926
2927 g_pModuleIndexDispenser->DisposeId(val);
2928}
2929
2930
2931void Module::AllocateRegularStaticHandles(AppDomain* pDomain)
2932{
2933 CONTRACTL
2934 {
2935 THROWS;
2936 GC_TRIGGERS;
2937 }
2938 CONTRACTL_END;
2939
2940#ifndef CROSSGEN_COMPILE
2941 if (NingenEnabled())
2942 return;
2943
2944 // Allocate the handles we will need. Note that AllocateStaticFieldObjRefPtrs will only
2945 // allocate if pModuleData->GetGCStaticsBasePointerAddress(pMT) != 0, avoiding creating
2946 // handles more than once for a given MT or module
2947
2948 DomainLocalModule *pModuleData = GetDomainLocalModule(pDomain);
2949
2950 _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointerAddress() != NULL);
2951 if (this->m_dwMaxGCRegularStaticHandles > 0)
2952 {
2953 // If we're setting up a non-default domain, we want the allocation to look like it's
2954 // coming from the created domain.
2955
2956 // REVISIT_TODO: The comparison "pDomain != GetDomain()" will always be true for domain-neutral
2957 // modules, since GetDomain() will return the SharedDomain, which is NOT an AppDomain.
2958 // Was this intended? If so, there should be a clarifying comment. If not, then we should
2959 // probably do "pDomain != GetAppDomain()" instead.
2960
2961 if (pDomain != GetDomain() &&
2962 pDomain != SystemDomain::System()->DefaultDomain() &&
2963 IsSystem())
2964 {
2965 pDomain->AllocateStaticFieldObjRefPtrsCrossDomain(this->m_dwMaxGCRegularStaticHandles,
2966 pModuleData->GetPrecomputedGCStaticsBasePointerAddress());
2967 }
2968 else
2969 {
2970 pDomain->AllocateStaticFieldObjRefPtrs(this->m_dwMaxGCRegularStaticHandles,
2971 pModuleData->GetPrecomputedGCStaticsBasePointerAddress());
2972 }
2973
2974 // We should throw if we fail to allocate and never hit this assert
2975 _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointer() != NULL);
2976 }
2977#endif // CROSSGEN_COMPILE
2978}
2979
2980BOOL Module::IsStaticStoragePrepared(mdTypeDef tkType)
2981{
2982 LIMITED_METHOD_CONTRACT;
2983
2984 // Right now the design is that we do one static allocation pass during NGEN,
2985 // and a 2nd pass for it at module init time for modules that weren't NGENed or the NGEN
2986 // pass was unsucessful. If we are loading types after that then we must use dynamic
2987 // static storage. These dynamic statics require an additional indirection so they
2988 // don't perform quite as well.
2989 //
2990 // This check was created for the scenario where a profiler adds additional types
2991 // however it seems likely this check would also accurately handle other dynamic
2992 // scenarios such as ref.emit and EnC as long as they are adding new types and
2993 // not new statics to existing types.
2994 _ASSERTE(TypeFromToken(tkType) == mdtTypeDef);
2995 return m_maxTypeRidStaticsAllocated >= RidFromToken(tkType);
2996}
2997
2998void Module::AllocateStatics(AllocMemTracker *pamTracker)
2999{
3000 STANDARD_VM_CONTRACT;
3001
3002 if (IsResource())
3003 {
3004 m_dwRegularStaticsBlockSize = DomainLocalModule::OffsetOfDataBlob();
3005 m_dwThreadStaticsBlockSize = ThreadLocalModule::OffsetOfDataBlob();
3006
3007 // If it has no code, we don't have to allocate anything
3008 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Resource module %s. No statics neeeded\n", GetSimpleName()));
3009 _ASSERTE(m_maxTypeRidStaticsAllocated == 0);
3010 return;
3011 }
3012#ifdef FEATURE_PREJIT
3013 if (m_pRegularStaticOffsets == (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED)
3014 {
3015 _ASSERTE(HasNativeImage());
3016
3017 // This is an ngen image and all the classes were loaded at ngen time, so we're done.
3018 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: 'Complete' Native image found, no statics parsing needed for module %s.\n", GetSimpleName()));
3019 // typeDefs rids 0 and 1 aren't included in the count, thus X typeDefs means rid X+1 is valid
3020 _ASSERTE(m_maxTypeRidStaticsAllocated == GetMDImport()->GetCountWithTokenKind(mdtTypeDef) + 1);
3021 return;
3022 }
3023#endif
3024 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Allocating statics for module %s\n", GetSimpleName()));
3025
3026 // 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
3027 // for non gc types)
3028 BuildStaticsOffsets(pamTracker);
3029}
3030
3031// This method will report GC static refs of the module. It doesn't have to be complete (ie, it's
3032// currently used to opportunistically get more concurrency in the marking of statics), so it currently
3033// ignores any statics that are not preallocated (ie: won't report statics from IsDynamicStatics() MT)
3034// The reason this function is in Module and not in DomainFile (together with DomainLocalModule is because
3035// for shared modules we need a very fast way of getting to the DomainLocalModule. For that we use
3036// a table in DomainLocalBlock that's indexed with a module ID
3037//
3038// This method is a secondary way for the GC to find statics, and it is only used when we are on
3039// a multiproc machine and we are using the ServerHeap. The primary way used by the GC to find
3040// statics is through the handle table. Module::AllocateRegularStaticHandles() allocates a GC handle
3041// from the handle table, and the GC will trace this handle and find the statics.
3042
3043void Module::EnumRegularStaticGCRefs(AppDomain* pAppDomain, promote_func* fn, ScanContext* sc)
3044{
3045 CONTRACT_VOID
3046 {
3047 NOTHROW;
3048 GC_NOTRIGGER;
3049 }
3050 CONTRACT_END;
3051
3052 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
3053 GCHeapUtilities::IsServerHeap() &&
3054 IsGCSpecialThread());
3055
3056
3057 DomainLocalModule *pModuleData = GetDomainLocalModule(pAppDomain);
3058 DWORD dwHandles = m_dwMaxGCRegularStaticHandles;
3059
3060 if (IsResource())
3061 {
3062 RETURN;
3063 }
3064
3065 LOG((LF_GC, LL_INFO100, "Scanning statics for module %s\n", GetSimpleName()));
3066
3067 OBJECTREF* ppObjectRefs = pModuleData->GetPrecomputedGCStaticsBasePointer();
3068 for (DWORD i = 0 ; i < dwHandles ; i++)
3069 {
3070 // Handles are allocated in SetDomainFile (except for bootstrapped mscorlib). In any
3071 // case, we shouldnt get called if the module hasn't had it's handles allocated (as we
3072 // only get here if IsActive() is true, which only happens after SetDomainFile(), which
3073 // is were we allocate handles.
3074 _ASSERTE(ppObjectRefs);
3075 fn((Object **)(ppObjectRefs+i), sc, 0);
3076 }
3077
3078 LOG((LF_GC, LL_INFO100, "Done scanning statics for module %s\n", GetSimpleName()));
3079
3080 RETURN;
3081}
3082
3083void Module::SetDomainFile(DomainFile *pDomainFile)
3084{
3085 CONTRACTL
3086 {
3087 INSTANCE_CHECK;
3088 PRECONDITION(CheckPointer(pDomainFile));
3089 PRECONDITION(IsManifest() == pDomainFile->IsAssembly());
3090 THROWS;
3091 GC_TRIGGERS;
3092 MODE_ANY;
3093 }
3094 CONTRACTL_END;
3095
3096 DomainLocalModule* pModuleData = 0;
3097
3098 // Do we need to allocate memory for the non GC statics?
3099 if (m_ModuleID == NULL)
3100 {
3101 // Allocate memory for the module statics.
3102 LoaderAllocator *pLoaderAllocator = NULL;
3103 if (GetAssembly()->IsCollectible())
3104 {
3105 pLoaderAllocator = GetAssembly()->GetLoaderAllocator();
3106 }
3107 else
3108 {
3109 pLoaderAllocator = pDomainFile->GetAppDomain()->GetLoaderAllocator();
3110 }
3111
3112 SIZE_T size = GetDomainLocalModuleSize();
3113
3114 LOG((LF_CLASSLOADER, LL_INFO10, "STATICS: Allocating %i bytes for precomputed statics in module %S in LoaderAllocator %p\n",
3115 size, this->GetDebugName(), pLoaderAllocator));
3116
3117 // We guarantee alignment for 64-bit regular statics on 32-bit platforms even without FEATURE_64BIT_ALIGNMENT for performance reasons.
3118
3119 _ASSERTE(size >= DomainLocalModule::OffsetOfDataBlob());
3120
3121 pModuleData = (DomainLocalModule*)(void*)
3122 pLoaderAllocator->GetHighFrequencyHeap()->AllocAlignedMem(
3123 size, MAX_PRIMITIVE_FIELD_SIZE);
3124
3125 // Note: Memory allocated on loader heap is zero filled
3126 // memset(pModuleData, 0, size);
3127
3128 // Verify that the space is really zero initialized
3129 _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointer() == NULL);
3130
3131 // If the module was loaded as domain-specific, then we need to assign
3132 // this module a domain-neutral module ID.
3133 pModuleData->m_ModuleIndex = Module::AllocateModuleIndex();
3134 m_ModuleIndex = pModuleData->m_ModuleIndex;
3135 }
3136 else
3137 {
3138 pModuleData = this->m_ModuleID;
3139 LOG((LF_CLASSLOADER, LL_INFO10, "STATICS: Allocation not needed for ngened non shared module %s in Appdomain %08x\n"));
3140 }
3141
3142 // Non shared case, module points directly to the statics. In ngen case
3143 // m_pDomainModule is already set for the non shared case
3144 if (m_ModuleID == NULL)
3145 {
3146 m_ModuleID = pModuleData;
3147 }
3148
3149 m_ModuleID->SetDomainFile(pDomainFile);
3150
3151 // Allocate static handles now.
3152 // NOTE: Bootstrapping issue with mscorlib - we will manually allocate later
3153 // If the assembly is collectible, we don't initialize static handles for them
3154 // as it is currently initialized through the DomainLocalModule::PopulateClass in MethodTable::CheckRunClassInitThrowing
3155 // (If we don't do this, it would allocate here unused regular static handles that will be overridden later)
3156 if (g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] != NULL && !GetAssembly()->IsCollectible())
3157 AllocateRegularStaticHandles(pDomainFile->GetAppDomain());
3158}
3159
3160#ifndef CROSSGEN_COMPILE
3161OBJECTREF Module::GetExposedObject()
3162{
3163 CONTRACT(OBJECTREF)
3164 {
3165 INSTANCE_CHECK;
3166 POSTCONDITION(RETVAL != NULL);
3167 THROWS;
3168 GC_TRIGGERS;
3169 MODE_COOPERATIVE;
3170 }
3171 CONTRACT_END;
3172
3173 RETURN GetDomainFile()->GetExposedModuleObject();
3174}
3175#endif // CROSSGEN_COMPILE
3176
3177//
3178// AllocateMap allocates the RID maps based on the size of the current
3179// metadata (if any)
3180//
3181
3182void Module::AllocateMaps()
3183{
3184 CONTRACTL
3185 {
3186 INSTANCE_CHECK;
3187 THROWS;
3188 GC_NOTRIGGER;
3189 MODE_ANY;
3190 }
3191 CONTRACTL_END;
3192
3193 enum
3194 {
3195 TYPEDEF_MAP_INITIAL_SIZE = 5,
3196 TYPEREF_MAP_INITIAL_SIZE = 5,
3197 MEMBERDEF_MAP_INITIAL_SIZE = 10,
3198 GENERICPARAM_MAP_INITIAL_SIZE = 5,
3199 GENERICTYPEDEF_MAP_INITIAL_SIZE = 5,
3200 FILEREFERENCES_MAP_INITIAL_SIZE = 5,
3201 ASSEMBLYREFERENCES_MAP_INITIAL_SIZE = 5,
3202 };
3203
3204 PTR_TADDR pTable = NULL;
3205
3206 if (IsResource())
3207 return;
3208
3209 if (IsReflection())
3210 {
3211 // For dynamic modules, it is essential that we at least have a TypeDefToMethodTable
3212 // map with an initial block. Otherwise, all the iterators will abort on an
3213 // initial empty table and we will e.g. corrupt the backpatching chains during
3214 // an appdomain unload.
3215 m_TypeDefToMethodTableMap.dwCount = TYPEDEF_MAP_INITIAL_SIZE;
3216
3217 // The above is essential. The following ones are precautionary.
3218 m_TypeRefToMethodTableMap.dwCount = TYPEREF_MAP_INITIAL_SIZE;
3219 m_MethodDefToDescMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE;
3220 m_FieldDefToDescMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE;
3221 m_GenericParamToDescMap.dwCount = GENERICPARAM_MAP_INITIAL_SIZE;
3222 m_GenericTypeDefToCanonMethodTableMap.dwCount = TYPEDEF_MAP_INITIAL_SIZE;
3223 m_FileReferencesMap.dwCount = FILEREFERENCES_MAP_INITIAL_SIZE;
3224 m_ManifestModuleReferencesMap.dwCount = ASSEMBLYREFERENCES_MAP_INITIAL_SIZE;
3225 m_MethodDefToPropertyInfoMap.dwCount = MEMBERDEF_MAP_INITIAL_SIZE;
3226 }
3227 else
3228 {
3229 IMDInternalImport * pImport = GetMDImport();
3230
3231 // Get # TypeDefs (add 1 for COR_GLOBAL_PARENT_TOKEN)
3232 m_TypeDefToMethodTableMap.dwCount = pImport->GetCountWithTokenKind(mdtTypeDef)+2;
3233
3234 // Get # TypeRefs
3235 m_TypeRefToMethodTableMap.dwCount = pImport->GetCountWithTokenKind(mdtTypeRef)+1;
3236
3237 // Get # MethodDefs
3238 m_MethodDefToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtMethodDef)+1;
3239
3240 // Get # FieldDefs
3241 m_FieldDefToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtFieldDef)+1;
3242
3243 // Get # GenericParams
3244 m_GenericParamToDescMap.dwCount = pImport->GetCountWithTokenKind(mdtGenericParam)+1;
3245
3246 // Get the number of FileReferences in the map
3247 m_FileReferencesMap.dwCount = pImport->GetCountWithTokenKind(mdtFile)+1;
3248
3249 // Get the number of AssemblyReferences in the map
3250 m_ManifestModuleReferencesMap.dwCount = pImport->GetCountWithTokenKind(mdtAssemblyRef)+1;
3251
3252 // These maps are only added to during NGen, so for other scenarios leave them empty
3253 if (IsCompilationProcess())
3254 {
3255 m_GenericTypeDefToCanonMethodTableMap.dwCount = m_TypeDefToMethodTableMap.dwCount;
3256 m_MethodDefToPropertyInfoMap.dwCount = m_MethodDefToDescMap.dwCount;
3257 }
3258 else
3259 {
3260 m_GenericTypeDefToCanonMethodTableMap.dwCount = 0;
3261 m_MethodDefToPropertyInfoMap.dwCount = 0;
3262 }
3263 }
3264
3265 S_SIZE_T nTotal;
3266
3267 nTotal += m_TypeDefToMethodTableMap.dwCount;
3268 nTotal += m_TypeRefToMethodTableMap.dwCount;
3269 nTotal += m_MethodDefToDescMap.dwCount;
3270 nTotal += m_FieldDefToDescMap.dwCount;
3271 nTotal += m_GenericParamToDescMap.dwCount;
3272 nTotal += m_GenericTypeDefToCanonMethodTableMap.dwCount;
3273 nTotal += m_FileReferencesMap.dwCount;
3274 nTotal += m_ManifestModuleReferencesMap.dwCount;
3275 nTotal += m_MethodDefToPropertyInfoMap.dwCount;
3276
3277 _ASSERTE (m_pAssembly && m_pAssembly->GetLowFrequencyHeap());
3278 pTable = (PTR_TADDR)(void*)m_pAssembly->GetLowFrequencyHeap()->AllocMem(nTotal * S_SIZE_T(sizeof(TADDR)));
3279
3280 // Note: Memory allocated on loader heap is zero filled
3281 // memset(pTable, 0, nTotal * sizeof(void*));
3282
3283 m_TypeDefToMethodTableMap.pNext = NULL;
3284 m_TypeDefToMethodTableMap.supportedFlags = TYPE_DEF_MAP_ALL_FLAGS;
3285 m_TypeDefToMethodTableMap.pTable = pTable;
3286
3287 m_TypeRefToMethodTableMap.pNext = NULL;
3288 m_TypeRefToMethodTableMap.supportedFlags = TYPE_REF_MAP_ALL_FLAGS;
3289 m_TypeRefToMethodTableMap.pTable = &pTable[m_TypeDefToMethodTableMap.dwCount];
3290
3291 m_MethodDefToDescMap.pNext = NULL;
3292 m_MethodDefToDescMap.supportedFlags = METHOD_DEF_MAP_ALL_FLAGS;
3293 m_MethodDefToDescMap.pTable = &m_TypeRefToMethodTableMap.pTable[m_TypeRefToMethodTableMap.dwCount];
3294
3295 m_FieldDefToDescMap.pNext = NULL;
3296 m_FieldDefToDescMap.supportedFlags = FIELD_DEF_MAP_ALL_FLAGS;
3297 m_FieldDefToDescMap.pTable = &m_MethodDefToDescMap.pTable[m_MethodDefToDescMap.dwCount];
3298
3299 m_GenericParamToDescMap.pNext = NULL;
3300 m_GenericParamToDescMap.supportedFlags = GENERIC_PARAM_MAP_ALL_FLAGS;
3301 m_GenericParamToDescMap.pTable = &m_FieldDefToDescMap.pTable[m_FieldDefToDescMap.dwCount];
3302
3303 m_GenericTypeDefToCanonMethodTableMap.pNext = NULL;
3304 m_GenericTypeDefToCanonMethodTableMap.supportedFlags = GENERIC_TYPE_DEF_MAP_ALL_FLAGS;
3305 m_GenericTypeDefToCanonMethodTableMap.pTable = &m_GenericParamToDescMap.pTable[m_GenericParamToDescMap.dwCount];
3306
3307 m_FileReferencesMap.pNext = NULL;
3308 m_FileReferencesMap.supportedFlags = FILE_REF_MAP_ALL_FLAGS;
3309 m_FileReferencesMap.pTable = &m_GenericTypeDefToCanonMethodTableMap.pTable[m_GenericTypeDefToCanonMethodTableMap.dwCount];
3310
3311 m_ManifestModuleReferencesMap.pNext = NULL;
3312 m_ManifestModuleReferencesMap.supportedFlags = MANIFEST_MODULE_MAP_ALL_FLAGS;
3313 m_ManifestModuleReferencesMap.pTable = &m_FileReferencesMap.pTable[m_FileReferencesMap.dwCount];
3314
3315 m_MethodDefToPropertyInfoMap.pNext = NULL;
3316 m_MethodDefToPropertyInfoMap.supportedFlags = PROPERTY_INFO_MAP_ALL_FLAGS;
3317 m_MethodDefToPropertyInfoMap.pTable = &m_ManifestModuleReferencesMap.pTable[m_ManifestModuleReferencesMap.dwCount];
3318}
3319
3320
3321//
3322// FreeClassTables frees the classes in the module
3323//
3324
3325void Module::FreeClassTables()
3326{
3327 CONTRACTL
3328 {
3329 INSTANCE_CHECK;
3330 NOTHROW;
3331 GC_TRIGGERS;
3332 MODE_ANY;
3333 }
3334 CONTRACTL_END;
3335
3336 if (m_dwTransientFlags & CLASSES_FREED)
3337 return;
3338
3339 FastInterlockOr(&m_dwTransientFlags, CLASSES_FREED);
3340
3341 // disable ibc here because it can cause errors during the destruction of classes
3342 IBCLoggingDisabler disableLogging;
3343
3344#if _DEBUG
3345 DebugLogRidMapOccupancy();
3346#endif
3347
3348 //
3349 // Free the types filled out in the TypeDefToEEClass map
3350 //
3351
3352 // Go through each linked block
3353 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
3354 while (typeDefIter.Next())
3355 {
3356 MethodTable * pMT = typeDefIter.GetElement();
3357
3358 if (pMT != NULL && pMT->IsRestored())
3359 {
3360 pMT->GetClass()->Destruct(pMT);
3361 }
3362 }
3363
3364 // Now do the same for constructed types (arrays and instantiated generic types)
3365 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
3366 { // separate AllocMemTracker. Though you're supposed to destruct everything else before destructing the AllocMemTracker, this is an easy invariant to break so
3367 // we'll play extra safe on this end.
3368 if (m_pAvailableParamTypes != NULL)
3369 {
3370 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
3371 EETypeHashEntry *pEntry;
3372 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
3373 {
3374 TypeHandle th = pEntry->GetTypeHandle();
3375
3376 if (!th.IsRestored())
3377 continue;
3378
3379#ifdef FEATURE_COMINTEROP
3380 // Some MethodTables/TypeDescs have COM interop goo attached to them which must be released
3381 if (!th.IsTypeDesc())
3382 {
3383 MethodTable *pMT = th.AsMethodTable();
3384 if (pMT->HasCCWTemplate() && (!pMT->IsZapped() || pMT->GetZapModule() == this))
3385 {
3386 // code:MethodTable::GetComCallWrapperTemplate() may go through canonical methodtable indirection cell.
3387 // The module load could be aborted before completing code:FILE_LOAD_EAGER_FIXUPS phase that's responsible
3388 // for resolving pre-restored indirection cells, so we have to check for it here explicitly.
3389 if (CORCOMPILE_IS_POINTER_TAGGED(pMT->GetCanonicalMethodTableFixup()))
3390 continue;
3391
3392 ComCallWrapperTemplate *pTemplate = pMT->GetComCallWrapperTemplate();
3393 if (pTemplate != NULL)
3394 {
3395 pTemplate->Release();
3396 }
3397 }
3398 }
3399 else if (th.IsArray())
3400 {
3401 ComCallWrapperTemplate *pTemplate = th.AsArray()->GetComCallWrapperTemplate();
3402 if (pTemplate != NULL)
3403 {
3404 pTemplate->Release();
3405 }
3406 }
3407#endif // FEATURE_COMINTEROP
3408
3409 // We need to call destruct on instances of EEClass whose "canonical" dependent lives in this table
3410 // There is nothing interesting to destruct on array EEClass
3411 if (!th.IsTypeDesc())
3412 {
3413 MethodTable * pMT = th.AsMethodTable();
3414 if (pMT->IsCanonicalMethodTable() && (!pMT->IsZapped() || pMT->GetZapModule() == this))
3415 pMT->GetClass()->Destruct(pMT);
3416 }
3417 }
3418 }
3419 }
3420}
3421
3422#endif // !DACCESS_COMPILE
3423
3424ClassLoader *Module::GetClassLoader()
3425{
3426 WRAPPER_NO_CONTRACT;
3427 SUPPORTS_DAC;
3428 _ASSERTE(m_pAssembly != NULL);
3429 return m_pAssembly->GetLoader();
3430}
3431
3432PTR_BaseDomain Module::GetDomain()
3433{
3434 WRAPPER_NO_CONTRACT;
3435 SUPPORTS_DAC;
3436 _ASSERTE(m_pAssembly != NULL);
3437 return m_pAssembly->GetDomain();
3438}
3439
3440#ifndef DACCESS_COMPILE
3441
3442#ifndef CROSSGEN_COMPILE
3443void Module::StartUnload()
3444{
3445 WRAPPER_NO_CONTRACT;
3446#ifdef PROFILING_SUPPORTED
3447 {
3448 BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads());
3449 if (!IsBeingUnloaded())
3450 {
3451 // Profiler is causing some peripheral class loads. Probably this just needs
3452 // to be turned into a Fault_not_fatal and moved to a specific place inside the profiler.
3453 EX_TRY
3454 {
3455 GCX_PREEMP();
3456 g_profControlBlock.pProfInterface->ModuleUnloadStarted((ModuleID) this);
3457 }
3458 EX_CATCH
3459 {
3460 }
3461 EX_END_CATCH(SwallowAllExceptions);
3462 }
3463 END_PIN_PROFILER();
3464 }
3465#endif // PROFILING_SUPPORTED
3466#ifdef FEATURE_PREJIT
3467 if (g_IBCLogger.InstrEnabled())
3468 {
3469 Thread * pThread = GetThread();
3470 ThreadLocalIBCInfo* pInfo = pThread->GetIBCInfo();
3471
3472 // Acquire the Crst lock before creating the IBCLoggingDisabler object.
3473 // Only one thread at a time can be processing an IBC logging event.
3474 CrstHolder lock(IBCLogger::GetSync());
3475 {
3476 IBCLoggingDisabler disableLogging( pInfo ); // runs IBCLoggingDisabler::DisableLogging
3477
3478 // Write out the method profile data
3479 /*hr=*/WriteMethodProfileDataLogFile(true);
3480 }
3481 }
3482#endif // FEATURE_PREJIT
3483 SetBeingUnloaded();
3484}
3485#endif // CROSSGEN_COMPILE
3486
3487void Module::ReleaseILData(void)
3488{
3489 WRAPPER_NO_CONTRACT;
3490
3491 ReleaseISymUnmanagedReader();
3492}
3493
3494
3495
3496//---------------------------------------------------------------------------------------
3497//
3498// Simple wrapper around calling IsAfContentType_WindowsRuntime() against the flags
3499// returned from the PEAssembly's GetFlagsNoTrigger()
3500//
3501// Return Value:
3502// nonzero iff we successfully determined pModule is a WinMD. FALSE if pModule is not
3503// a WinMD, or we fail trying to find out.
3504//
3505BOOL Module::IsWindowsRuntimeModule()
3506{
3507 CONTRACTL
3508 {
3509 NOTHROW;
3510 GC_NOTRIGGER;
3511 CAN_TAKE_LOCK; // Accesses metadata directly, which takes locks
3512 MODE_ANY;
3513 }
3514 CONTRACTL_END;
3515
3516 BOOL fRet = FALSE;
3517
3518 DWORD dwFlags;
3519
3520 if (FAILED(GetAssembly()->GetManifestFile()->GetFlagsNoTrigger(&dwFlags)))
3521 return FALSE;
3522
3523 return IsAfContentType_WindowsRuntime(dwFlags);
3524}
3525
3526BOOL Module::IsInCurrentVersionBubble()
3527{
3528 LIMITED_METHOD_CONTRACT;
3529
3530#ifdef FEATURE_NATIVE_IMAGE_GENERATION
3531 if (!IsCompilationProcess())
3532 return TRUE;
3533
3534 // The module being compiled is always part of the current version bubble
3535 AppDomain * pAppDomain = GetAppDomain();
3536 if (pAppDomain->IsCompilationDomain() && pAppDomain->ToCompilationDomain()->GetTargetModule() == this)
3537 return TRUE;
3538
3539 if (IsReadyToRunCompilation())
3540 return FALSE;
3541
3542#ifdef FEATURE_COMINTEROP
3543 if (g_fNGenWinMDResilient)
3544 return !GetAssembly()->IsWinMD();
3545#endif
3546
3547 return TRUE;
3548#else // FEATURE_NATIVE_IMAGE_GENERATION
3549 return TRUE;
3550#endif // FEATURE_NATIVE_IMAGE_GENERATION
3551}
3552
3553//---------------------------------------------------------------------------------------
3554//
3555// WinMD-aware helper to grab a readable public metadata interface. Any place that thinks
3556// it wants to use Module::GetRWImporter + QI now should use this wrapper instead.
3557//
3558// Arguments:
3559// * dwOpenFlags - Combo from CorOpenFlags. Better not contain ofWrite!
3560// * riid - Public IID requested
3561// * ppvInterface - [out] Requested interface. On success, *ppvInterface is returned
3562// refcounted; caller responsible for Release.
3563//
3564// Return Value:
3565// HRESULT indicating success or failure.
3566//
3567HRESULT Module::GetReadablePublicMetaDataInterface(DWORD dwOpenFlags, REFIID riid, LPVOID * ppvInterface)
3568{
3569 CONTRACTL
3570 {
3571 NOTHROW;
3572 GC_NOTRIGGER;
3573 CAN_TAKE_LOCK; // IsWindowsRuntimeModule accesses metadata directly, which takes locks
3574 MODE_ANY;
3575 }
3576 CONTRACTL_END;
3577
3578 _ASSERTE((dwOpenFlags & ofWrite) == 0);
3579
3580 // Temporary place to store public, AddRef'd interface pointers
3581 ReleaseHolder<IUnknown> pIUnkPublic;
3582
3583 // Temporary place to store the IUnknown from which we'll do the final QI to get the
3584 // requested public interface. Any assignment to pIUnk assumes pIUnk does not need
3585 // to do a Release() (either the interface was internal and not AddRef'd, or was
3586 // public and will be released by the above holder).
3587 IUnknown * pIUnk = NULL;
3588
3589 HRESULT hr = S_OK;
3590
3591 // Normally, we just get an RWImporter to do the QI on, and we're on our way.
3592 EX_TRY
3593 {
3594 pIUnk = GetRWImporter();
3595 }
3596 EX_CATCH_HRESULT_NO_ERRORINFO(hr);
3597
3598 if (FAILED(hr) && IsWindowsRuntimeModule())
3599 {
3600 // WinMD modules don't like creating RW importers. They also (currently)
3601 // have no plumbing to get to their public metadata interfaces from the
3602 // Module. So we actually have to start from scratch at the dispenser.
3603
3604 // To start with, get a dispenser, and get the metadata memory blob we've
3605 // already loaded. If either of these fail, just return the error HRESULT
3606 // from the above GetRWImporter() call.
3607
3608 // We'll get an addref'd IMetaDataDispenser, so use a holder to release it
3609 ReleaseHolder<IMetaDataDispenser> pDispenser;
3610 if (FAILED(InternalCreateMetaDataDispenser(IID_IMetaDataDispenser, &pDispenser)))
3611 {
3612 _ASSERTE(FAILED(hr));
3613 return hr;
3614 }
3615
3616 COUNT_T cbMetadata = 0;
3617 PTR_CVOID pvMetadata = GetAssembly()->GetManifestFile()->GetLoadedMetadata(&cbMetadata);
3618 if ((pvMetadata == NULL) || (cbMetadata == 0))
3619 {
3620 _ASSERTE(FAILED(hr));
3621 return hr;
3622 }
3623
3624 // Now that the pieces are ready, we can use the riid specified by the
3625 // profiler in this call to the dispenser to get the requested interface. If
3626 // this fails, then this is the interesting HRESULT for the caller to see.
3627 //
3628 // We'll get an AddRef'd public interface, so use a holder to release it
3629 hr = pDispenser->OpenScopeOnMemory(
3630 pvMetadata,
3631 cbMetadata,
3632 (dwOpenFlags | ofReadOnly), // Force ofReadOnly on behalf of the profiler
3633 riid,
3634 &pIUnkPublic);
3635 if (FAILED(hr))
3636 return hr;
3637
3638 // Set pIUnk so we can do the final QI from it below as we do in the other
3639 // cases.
3640 pIUnk = pIUnkPublic;
3641 }
3642
3643 // Get the requested interface
3644 if (SUCCEEDED(hr) && (ppvInterface != NULL))
3645 {
3646 _ASSERTE(pIUnk != NULL);
3647 hr = pIUnk->QueryInterface(riid, (void **) ppvInterface);
3648 }
3649
3650 return hr;
3651}
3652
3653// a special token that indicates no reader could be created - don't try again
3654static ISymUnmanagedReader* const k_pInvalidSymReader = (ISymUnmanagedReader*)0x1;
3655
3656#if defined(FEATURE_ISYM_READER) && !defined(CROSSGEN_COMPILE)
3657ISymUnmanagedReader *Module::GetISymUnmanagedReaderNoThrow(void)
3658{
3659 CONTRACT(ISymUnmanagedReader *)
3660 {
3661 INSTANCE_CHECK;
3662 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
3663 NOTHROW;
3664 WRAPPER(GC_TRIGGERS);
3665 MODE_ANY;
3666 }
3667 CONTRACT_END;
3668
3669 ISymUnmanagedReader *ret = NULL;
3670
3671 EX_TRY
3672 {
3673 ret = GetISymUnmanagedReader();
3674 }
3675 EX_CATCH
3676 {
3677 // We swallow any exception and say that we simply couldn't get a reader by returning NULL.
3678 // The only type of error that should be possible here is OOM.
3679 /* DISABLED due to Dev10 bug 619495
3680 CONSISTENCY_CHECK_MSG(
3681 GET_EXCEPTION()->GetHR() == E_OUTOFMEMORY,
3682 "Exception from GetISymUnmanagedReader");
3683 */
3684 }
3685 EX_END_CATCH(RethrowTerminalExceptions);
3686
3687 RETURN (ret);
3688}
3689
3690ISymUnmanagedReader *Module::GetISymUnmanagedReader(void)
3691{
3692 CONTRACT(ISymUnmanagedReader *)
3693 {
3694 INSTANCE_CHECK;
3695 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
3696 THROWS;
3697 WRAPPER(GC_TRIGGERS);
3698 MODE_ANY;
3699 }
3700 CONTRACT_END;
3701
3702 // No symbols for resource modules
3703 if (IsResource())
3704 RETURN NULL;
3705
3706 if (g_fEEShutDown)
3707 RETURN NULL;
3708
3709 // Verify that symbol reading is permitted for this module.
3710 // If we know we've already created a symbol reader, don't bother checking. There is
3711 // no advantage to allowing symbol reading to be turned off if we've already created the reader.
3712 // Note that we can't just put this code in the creation block below because we might have to
3713 // call managed code to resolve security policy, and we can't do that while holding a lock.
3714 // There is no disadvantage other than a minor perf cost to calling this unnecessarily, so the
3715 // race on m_pISymUnmanagedReader here is OK. The perf cost is minor because the only real
3716 // work is done by the security system which caches the result.
3717 if( m_pISymUnmanagedReader == NULL && !IsSymbolReadingEnabled() )
3718 RETURN NULL;
3719
3720 // Take the lock for the m_pISymUnmanagedReader
3721 // This ensures that we'll only ever attempt to create one reader at a time, and we won't
3722 // create a reader if we're in the middle of destroying one that has become stale.
3723 // Actual access to the reader can safely occur outside the lock as long as it has its own
3724 // AddRef which we take inside the lock at the bottom of this method.
3725 CrstHolder holder(&m_ISymUnmanagedReaderCrst);
3726
3727 UINT lastErrorMode = 0;
3728
3729 // If we haven't created a reader yet, do so now
3730 if (m_pISymUnmanagedReader == NULL)
3731 {
3732 // Mark our reader as invalid so that if we fail to create the reader
3733 // (including if an exception is thrown), we won't keep trying.
3734 m_pISymUnmanagedReader = k_pInvalidSymReader;
3735
3736 // There are 4 main cases here:
3737 // 1. Assembly is on disk and we'll get the symbols from a file next to the assembly
3738 // 2. Assembly is provided by the host and we'll get the symbols from the host
3739 // 3. Assembly was loaded in-memory (by byte array or ref-emit), and symbols were
3740 // provided along with it.
3741 // 4. Assembly was loaded in-memory but no symbols were provided.
3742
3743 // Determine whether we should be looking in memory for the symbols (cases 2 & 3)
3744 bool fInMemorySymbols = ( m_file->IsIStream() || GetInMemorySymbolStream() );
3745 if( !fInMemorySymbols && m_file->GetPath().IsEmpty() )
3746 {
3747 // Case 4. We don't have a module path, an IStream or an in memory symbol stream,
3748 // so there is no-where to try and get symbols from.
3749 RETURN (NULL);
3750 }
3751
3752 // Create a binder to find the reader.
3753 //
3754 // <REVISIT_TODO>@perf: this is slow, creating and destroying the binder every
3755 // time. We should cache this somewhere, but I'm not 100% sure
3756 // where right now...</REVISIT_TODO>
3757 HRESULT hr = S_OK;
3758
3759 SafeComHolder<ISymUnmanagedBinder> pBinder;
3760
3761 if (g_pDebugInterface == NULL)
3762 {
3763 // @TODO: this is reachable when debugging!
3764 UNREACHABLE_MSG("About to CoCreateInstance! This code should not be "
3765 "reachable or needs to be reimplemented for CoreCLR!");
3766 }
3767
3768 if (this->GetInMemorySymbolStreamFormat() == eSymbolFormatILDB)
3769 {
3770 // We've got in-memory ILDB symbols, create the ILDB symbol binder
3771 // Note that in this case, we must be very careful not to use diasymreader.dll
3772 // at all - we don't trust it, and shouldn't run any code in it
3773 IfFailThrow(IldbSymbolsCreateInstance(CLSID_CorSymBinder_SxS, IID_ISymUnmanagedBinder, (void**)&pBinder));
3774 }
3775 else
3776 {
3777 // We're going to be working with Windows PDB format symbols. Attempt to CoCreate the symbol binder.
3778 // CoreCLR supports not having a symbol reader installed, so CoCreate searches the PATH env var
3779 // and then tries coreclr dll location.
3780 // On desktop, the framework installer is supposed to install diasymreader.dll as well
3781 // and so this shouldn't happen.
3782 hr = FakeCoCreateInstanceEx(CLSID_CorSymBinder_SxS, NATIVE_SYMBOL_READER_DLL, IID_ISymUnmanagedBinder, (void**)&pBinder, NULL);
3783 if (FAILED(hr))
3784 {
3785 PathString symbolReaderPath;
3786 hr = GetHModuleDirectory(GetModuleInst(), symbolReaderPath);
3787 if (FAILED(hr))
3788 {
3789 RETURN (NULL);
3790 }
3791 symbolReaderPath.Append(NATIVE_SYMBOL_READER_DLL);
3792 hr = FakeCoCreateInstanceEx(CLSID_CorSymBinder_SxS, symbolReaderPath.GetUnicode(), IID_ISymUnmanagedBinder, (void**)&pBinder, NULL);
3793 if (FAILED(hr))
3794 {
3795 RETURN (NULL);
3796 }
3797 }
3798 }
3799
3800 LOG((LF_CORDB, LL_INFO10, "M::GISUR: Created binder\n"));
3801
3802 // Note: we change the error mode here so we don't get any popups as the PDB symbol reader attempts to search the
3803 // hard disk for files.
3804 lastErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
3805
3806 SafeComHolder<ISymUnmanagedReader> pReader;
3807
3808 if (fInMemorySymbols)
3809 {
3810 SafeComHolder<IStream> pIStream( NULL );
3811
3812 // If debug stream is already specified, don't bother to go through fusion
3813 // This is the common case for case 2 (hosted modules) and case 3 (Ref.Emit).
3814 if (GetInMemorySymbolStream() )
3815 {
3816
3817 if( IsReflection() )
3818 {
3819 // If this is Reflection.Emit, we must clone the stream because another thread may
3820 // update it when someone is using the reader we create here leading to AVs.
3821 // Note that the symbol stream should be up to date since we flush the writer
3822 // after every addition in Module::AddClass.
3823 IfFailThrow(GetInMemorySymbolStream()->Clone(&pIStream));
3824 }
3825 else
3826 {
3827 // The stream is not changing. Just add-ref to it.
3828 pIStream = GetInMemorySymbolStream();
3829 pIStream->AddRef();
3830 }
3831 }
3832 if (SUCCEEDED(hr))
3833 {
3834 hr = pBinder->GetReaderFromStream(GetRWImporter(), pIStream, &pReader);
3835 }
3836 }
3837 else
3838 {
3839 // The assembly is on disk, so try and load symbols based on the path to the assembly (case 1)
3840 const SString &path = m_file->GetPath();
3841
3842 // Call Fusion to ensure that any PDB's are shadow copied before
3843 // trying to get a symbol reader. This has to be done once per
3844 // Assembly.
3845 // for this to work with winmds we cannot simply call GetRWImporter() as winmds are RO
3846 // and thus don't implement the RW interface. so we call this wrapper function which knows
3847 // how to get a IMetaDataImport interface regardless of the underlying module type.
3848 ReleaseHolder<IUnknown> pUnk = NULL;
3849 hr = GetReadablePublicMetaDataInterface(ofReadOnly, IID_IMetaDataImport, &pUnk);
3850 if (SUCCEEDED(hr))
3851 hr = pBinder->GetReaderForFile(pUnk, path, NULL, &pReader);
3852 }
3853
3854 SetErrorMode(lastErrorMode);
3855
3856 if (SUCCEEDED(hr))
3857 {
3858 m_pISymUnmanagedReader = pReader.Extract();
3859 LOG((LF_CORDB, LL_INFO10, "M::GISUR: Loaded symbols for module %S\n", GetDebugName()));
3860 }
3861 else
3862 {
3863 // We failed to create the reader, don't try again next time
3864 LOG((LF_CORDB, LL_INFO10, "M::GISUR: Failed to load symbols for module %S\n", GetDebugName()));
3865 _ASSERTE( m_pISymUnmanagedReader == k_pInvalidSymReader );
3866 }
3867
3868 } // if( m_pISymUnmanagedReader == NULL )
3869
3870 // If we previously failed to create the reader, return NULL
3871 if (m_pISymUnmanagedReader == k_pInvalidSymReader)
3872 {
3873 RETURN (NULL);
3874 }
3875
3876 // Success - return an AddRef'd copy of the reader
3877 m_pISymUnmanagedReader->AddRef();
3878 RETURN (m_pISymUnmanagedReader);
3879}
3880#endif // FEATURE_ISYM_READER && !CROSSGEN_COMPILE
3881
3882BOOL Module::IsSymbolReadingEnabled()
3883{
3884 CONTRACTL
3885 {
3886 INSTANCE_CHECK;
3887 THROWS;
3888 GC_TRIGGERS;
3889 MODE_ANY;
3890 }
3891 CONTRACTL_END;
3892
3893 // If the module has symbols in-memory (eg. RefEmit) that are in ILDB
3894 // format, then there isn't any reason not to supply them. The reader
3895 // code is always available, and we trust it's security.
3896 if (this->GetInMemorySymbolStreamFormat() == eSymbolFormatILDB)
3897 {
3898 return TRUE;
3899 }
3900
3901#ifdef DEBUGGING_SUPPORTED
3902 if (!g_pDebugInterface)
3903 {
3904 // if debugging is disabled (no debug pack installed), do not load symbols
3905 // This is done for two reasons. We don't completely trust the security of
3906 // the diasymreader.dll code, so we don't want to use it in mainline scenarios.
3907 // Secondly, there's not reason that diasymreader.dll will even necssarily be
3908 // be on the machine if the debug pack isn't installed.
3909 return FALSE;
3910 }
3911#endif // DEBUGGING_SUPPORTED
3912
3913
3914 return TRUE;
3915}
3916
3917// At this point, this is only called when we're creating an appdomain
3918// out of an array of bytes, so we'll keep the IStream that we create
3919// around in case the debugger attaches later (including detach & re-attach!)
3920void Module::SetSymbolBytes(LPCBYTE pbSyms, DWORD cbSyms)
3921{
3922 STANDARD_VM_CONTRACT;
3923
3924 // Create a IStream from the memory for the syms.
3925 SafeComHolder<CGrowableStream> pStream(new CGrowableStream());
3926
3927 // Do not need to AddRef the CGrowableStream because the constructor set it to 1
3928 // ref count already. The Module will keep a copy for its own use.
3929
3930 // Make sure to set the symbol stream on the module before
3931 // attempting to send UpdateModuleSyms messages up for it.
3932 SetInMemorySymbolStream(pStream, eSymbolFormatPDB);
3933
3934 // This can only be called when the module is being created. No-one should have
3935 // tried to use the symbols yet, and so there should not be a reader.
3936 // If instead, we wanted to call this when a reader could have been created, we need to
3937 // serialize access by taking the reader lock, and flush the old reader by calling
3938 // code:Module.ReleaseISymUnmanagedReader
3939 _ASSERTE( m_pISymUnmanagedReader == NULL );
3940
3941#ifdef LOGGING
3942 LPCWSTR pName = NULL;
3943 pName = GetDebugName();
3944#endif // LOGGING
3945
3946 ULONG cbWritten;
3947 DWORD dwError = pStream->Write((const void *)pbSyms,
3948 (ULONG)cbSyms,
3949 &cbWritten);
3950 IfFailThrow(HRESULT_FROM_WIN32(dwError));
3951
3952#if PROFILING_SUPPORTED && !defined(CROSSGEN_COMPILE)
3953 BEGIN_PIN_PROFILER(CORProfilerInMemorySymbolsUpdatesEnabled());
3954 {
3955 g_profControlBlock.pProfInterface->ModuleInMemorySymbolsUpdated((ModuleID) this);
3956 }
3957 END_PIN_PROFILER();
3958#endif //PROFILING_SUPPORTED && !defined(CROSSGEN_COMPILE)
3959
3960 ETW::CodeSymbolLog::EmitCodeSymbols(this);
3961
3962 // Tell the debugger that symbols have been loaded for this
3963 // module. We iterate through all domains which contain this
3964 // module's assembly, and send a debugger notify for each one.
3965 // <REVISIT_TODO>@perf: it would scale better if we directly knew which domains
3966 // the assembly was loaded in.</REVISIT_TODO>
3967 if (CORDebuggerAttached())
3968 {
3969 AppDomainIterator i(FALSE);
3970
3971 while (i.Next())
3972 {
3973 AppDomain *pDomain = i.GetDomain();
3974
3975 if (pDomain->IsDebuggerAttached() && (GetDomain() == SystemDomain::System() ||
3976 pDomain->ContainsAssembly(m_pAssembly)))
3977 {
3978 g_pDebugInterface->SendUpdateModuleSymsEventAndBlock(this, pDomain);
3979 }
3980 }
3981 }
3982}
3983
3984// Clear any cached symbol reader
3985void Module::ReleaseISymUnmanagedReader(void)
3986{
3987 CONTRACTL
3988 {
3989 NOTHROW;
3990 GC_NOTRIGGER;
3991 MODE_ANY;
3992 FORBID_FAULT;
3993 }
3994 CONTRACTL_END;
3995
3996 // Caller is responsible for taking the reader lock if the call could occur when
3997 // other threads are using or creating the reader
3998 if( m_pISymUnmanagedReader != NULL )
3999 {
4000 // If we previously failed to create a reader, don't attempt to release it
4001 // but do clear it out so that we can try again (eg. symbols may have changed)
4002 if( m_pISymUnmanagedReader != k_pInvalidSymReader )
4003 {
4004 m_pISymUnmanagedReader->Release();
4005 }
4006 m_pISymUnmanagedReader = NULL;
4007 }
4008}
4009
4010// Lazily creates a new IL stub cache for this module.
4011ILStubCache* Module::GetILStubCache()
4012{
4013 CONTRACTL
4014 {
4015 THROWS;
4016 GC_NOTRIGGER;
4017 MODE_ANY;
4018 INJECT_FAULT(COMPlusThrowOM(););
4019 }
4020 CONTRACTL_END;
4021
4022 // Use per-LoaderAllocator cache for modules when not NGENing
4023 BaseDomain *pDomain = GetDomain();
4024 if (!IsSystem() && !pDomain->IsSharedDomain() && !pDomain->AsAppDomain()->IsCompilationDomain())
4025 return GetLoaderAllocator()->GetILStubCache();
4026
4027 if (m_pILStubCache == NULL)
4028 {
4029 ILStubCache *pILStubCache = new ILStubCache(GetLoaderAllocator()->GetHighFrequencyHeap());
4030
4031 if (FastInterlockCompareExchangePointer(&m_pILStubCache, pILStubCache, NULL) != NULL)
4032 {
4033 // some thread swooped in and set the field
4034 delete pILStubCache;
4035 }
4036 }
4037 _ASSERTE(m_pILStubCache != NULL);
4038 return m_pILStubCache;
4039}
4040
4041// Called to finish the process of adding a new class with Reflection.Emit
4042void Module::AddClass(mdTypeDef classdef)
4043{
4044 CONTRACTL
4045 {
4046 INSTANCE_CHECK;
4047 THROWS;
4048 GC_TRIGGERS;
4049 MODE_PREEMPTIVE;
4050 PRECONDITION(!IsResource());
4051 }
4052 CONTRACTL_END;
4053
4054 // The fake class associated with the module (global fields & functions) needs to be initialized here
4055 // Normal classes are added to the available class hash when their typedef is first created.
4056 if (RidFromToken(classdef) == 0)
4057 {
4058 BuildClassForModule();
4059 }
4060
4061 // Since the module is being modified, the in-memory symbol stream
4062 // (if any) has probably also been modified. If we support reading the symbols
4063 // then we need to commit the changes to the writer and flush any old readers
4064 // However if we don't support reading then we can skip this which will give
4065 // a substantial perf improvement. See DDB 671107.
4066 if(IsSymbolReadingEnabled())
4067 {
4068 CONSISTENCY_CHECK(IsReflection()); // this is only used for dynamic modules
4069 ISymUnmanagedWriter * pWriter = GetReflectionModule()->GetISymUnmanagedWriter();
4070 if (pWriter != NULL)
4071 {
4072 // Serialize with any concurrent reader creations
4073 // Specifically, if we started creating a reader on one thread, and then updated the
4074 // symbols on another thread, we need to wait until the initial reader creation has
4075 // completed and release it so we don't get stuck with a stale reader.
4076 // Also, if we commit to the stream while we're in the process of creating a reader,
4077 // the reader will get corrupted/incomplete data.
4078 // Note that we must also be in co-operative mode here to ensure the debugger helper
4079 // thread can't be simultaneously reading this stream while the process is synchronized
4080 // (code:Debugger::GetSymbolBytes)
4081 CrstHolder holder(&m_ISymUnmanagedReaderCrst);
4082
4083 // Flush writes to the symbol store to the symbol stream
4084 // Note that we do this when finishing the addition of the class, instead of
4085 // on-demand in GetISymUnmanagedReader because the writer is not thread-safe.
4086 // Here, we're inside the lock of TypeBuilder.CreateType, and so it's safe to
4087 // manipulate the writer.
4088 SafeComHolderPreemp<ISymUnmanagedWriter3> pWriter3;
4089 HRESULT thr = pWriter->QueryInterface(IID_ISymUnmanagedWriter3, (void**)&pWriter3);
4090 CONSISTENCY_CHECK(SUCCEEDED(thr));
4091 if (SUCCEEDED(thr))
4092 {
4093 thr = pWriter3->Commit();
4094 if (SUCCEEDED(thr))
4095 {
4096 // Flush any cached symbol reader to ensure we pick up any new symbols
4097 ReleaseISymUnmanagedReader();
4098 }
4099 }
4100
4101 // If either the QI or Commit failed
4102 if (FAILED(thr))
4103 {
4104 // The only way we expect this might fail is out-of-memory. In that
4105 // case we silently fail to update the symbol stream with new data, but
4106 // we leave the existing reader intact.
4107 CONSISTENCY_CHECK(thr==E_OUTOFMEMORY);
4108 }
4109 }
4110 }
4111}
4112
4113//---------------------------------------------------------------------------
4114// For the global class this builds the table of MethodDescs an adds the rids
4115// to the MethodDef map.
4116//---------------------------------------------------------------------------
4117void Module::BuildClassForModule()
4118{
4119 CONTRACTL
4120 {
4121 INSTANCE_CHECK;
4122 THROWS;
4123 GC_TRIGGERS;
4124 MODE_ANY;
4125 }
4126 CONTRACTL_END;
4127
4128 IMDInternalImport * pImport = GetMDImport();
4129 DWORD cFunctions, cFields;
4130
4131 {
4132 // Obtain count of global functions
4133 HENUMInternalHolder hEnum(pImport);
4134 hEnum.EnumGlobalFunctionsInit();
4135 cFunctions = pImport->EnumGetCount(&hEnum);
4136 }
4137
4138 {
4139 // Obtain count of global fields
4140 HENUMInternalHolder hEnum(pImport);
4141 hEnum.EnumGlobalFieldsInit();
4142 cFields = pImport->EnumGetCount(&hEnum);
4143 }
4144
4145 // If we have any work to do...
4146 if (cFunctions > 0 || cFields > 0)
4147 {
4148 COUNTER_ONLY(size_t _HeapSize = 0);
4149
4150 TypeKey typeKey(this, COR_GLOBAL_PARENT_TOKEN);
4151 TypeHandle typeHnd = GetClassLoader()->LoadTypeHandleForTypeKeyNoLock(&typeKey);
4152
4153#ifdef ENABLE_PERF_COUNTERS
4154
4155 _HeapSize = GetLoaderAllocator()->GetHighFrequencyHeap()->GetSize();
4156
4157 GetPerfCounters().m_Loading.cbLoaderHeapSize = _HeapSize;
4158#endif // ENABLE_PERF_COUNTERS
4159
4160 }
4161}
4162
4163#endif // !DACCESS_COMPILE
4164
4165// Returns true iff the debugger should be notified about this module
4166//
4167// Notes:
4168// Debugger doesn't need to be notified about modules that can't be executed,
4169// like inspection and resource only. These are just pure data.
4170//
4171// This should be immutable for an instance of a module. That ensures that the debugger gets consistent
4172// notifications about it. It this value mutates, than the debugger may miss relevant notifications.
4173BOOL Module::IsVisibleToDebugger()
4174{
4175 WRAPPER_NO_CONTRACT;
4176 SUPPORTS_DAC;
4177
4178 if (IsResource())
4179 {
4180 return FALSE;
4181 }
4182
4183 return TRUE;
4184}
4185
4186BOOL Module::HasNativeOrReadyToRunImage()
4187{
4188#ifdef FEATURE_READYTORUN
4189 if (IsReadyToRun())
4190 return TRUE;
4191#endif
4192
4193 return HasNativeImage();
4194}
4195
4196PEImageLayout * Module::GetNativeOrReadyToRunImage()
4197{
4198 LIMITED_METHOD_CONTRACT;
4199
4200#ifdef FEATURE_READYTORUN
4201 if (IsReadyToRun())
4202 return GetReadyToRunInfo()->GetImage();
4203#endif
4204
4205 return GetNativeImage();
4206}
4207
4208PTR_CORCOMPILE_IMPORT_SECTION Module::GetImportSections(COUNT_T *pCount)
4209{
4210 CONTRACTL
4211 {
4212 NOTHROW;
4213 GC_NOTRIGGER;
4214 }
4215 CONTRACTL_END;
4216
4217#ifdef FEATURE_READYTORUN
4218 if (IsReadyToRun())
4219 return GetReadyToRunInfo()->GetImportSections(pCount);
4220#endif
4221
4222 return GetNativeImage()->GetNativeImportSections(pCount);
4223}
4224
4225PTR_CORCOMPILE_IMPORT_SECTION Module::GetImportSectionFromIndex(COUNT_T index)
4226{
4227 CONTRACTL
4228 {
4229 NOTHROW;
4230 GC_NOTRIGGER;
4231 }
4232 CONTRACTL_END;
4233
4234#ifdef FEATURE_READYTORUN
4235 if (IsReadyToRun())
4236 return GetReadyToRunInfo()->GetImportSectionFromIndex(index);
4237#endif
4238
4239 return GetNativeImage()->GetNativeImportSectionFromIndex(index);
4240}
4241
4242PTR_CORCOMPILE_IMPORT_SECTION Module::GetImportSectionForRVA(RVA rva)
4243{
4244 CONTRACTL
4245 {
4246 NOTHROW;
4247 GC_NOTRIGGER;
4248 }
4249 CONTRACTL_END;
4250
4251#ifdef FEATURE_READYTORUN
4252 if (IsReadyToRun())
4253 return GetReadyToRunInfo()->GetImportSectionForRVA(rva);
4254#endif
4255
4256 return GetNativeImage()->GetNativeImportSectionForRVA(rva);
4257}
4258
4259TADDR Module::GetIL(DWORD target)
4260{
4261 WRAPPER_NO_CONTRACT;
4262 SUPPORTS_DAC;
4263
4264 if (target == 0)
4265 return NULL;
4266
4267 return m_file->GetIL(target);
4268}
4269
4270PTR_VOID Module::GetRvaField(DWORD rva, BOOL fZapped)
4271{
4272 WRAPPER_NO_CONTRACT;
4273 SUPPORTS_DAC;
4274
4275#ifdef FEATURE_PREJIT
4276 if (fZapped && m_file->IsILOnly())
4277 {
4278 return dac_cast<PTR_VOID>(m_file->GetLoadedNative()->GetRvaData(rva,NULL_OK));
4279 }
4280#endif // FEATURE_PREJIT
4281
4282 return m_file->GetRvaField(rva);
4283}
4284
4285#ifndef DACCESS_COMPILE
4286
4287CHECK Module::CheckRvaField(RVA field)
4288{
4289 WRAPPER_NO_CONTRACT;
4290 if (!IsReflection())
4291 CHECK(m_file->CheckRvaField(field));
4292 CHECK_OK;
4293}
4294
4295CHECK Module::CheckRvaField(RVA field, COUNT_T size)
4296{
4297 CONTRACTL
4298 {
4299 STANDARD_VM_CHECK;
4300 CAN_TAKE_LOCK;
4301 }
4302 CONTRACTL_END;
4303
4304 if (!IsReflection())
4305 CHECK(m_file->CheckRvaField(field, size));
4306 CHECK_OK;
4307}
4308
4309#endif // !DACCESS_COMPILE
4310
4311BOOL Module::HasTls()
4312{
4313 WRAPPER_NO_CONTRACT;
4314
4315 return m_file->HasTls();
4316}
4317
4318BOOL Module::IsRvaFieldTls(DWORD rva)
4319{
4320 WRAPPER_NO_CONTRACT;
4321
4322 return m_file->IsRvaFieldTls(rva);
4323}
4324
4325UINT32 Module::GetFieldTlsOffset(DWORD rva)
4326{
4327 WRAPPER_NO_CONTRACT;
4328
4329 return m_file->GetFieldTlsOffset(rva);
4330}
4331
4332UINT32 Module::GetTlsIndex()
4333{
4334 WRAPPER_NO_CONTRACT;
4335
4336 return m_file->GetTlsIndex();
4337}
4338
4339
4340// In DAC builds this function was being called on host addresses which may or may not
4341// have been marshalled from the target. Such addresses can't be reliably mapped back to
4342// target addresses, which means we can't tell whether they came from the IL or not
4343//
4344// Security note: Any security which you might wish to gain by verifying the origin of
4345// a signature isn't available in DAC. The attacker can provide a dump which spoofs all
4346// module ranges. In other words the attacker can make the signature appear to come from
4347// anywhere, but still violate all the rules that a signature from that location would
4348// otherwise follow. I am removing this function from DAC in order to prevent anyone from
4349// getting a false sense of security (in addition to its functional shortcomings)
4350
4351#ifndef DACCESS_COMPILE
4352BOOL Module::IsSigInIL(PCCOR_SIGNATURE signature)
4353{
4354 CONTRACTL
4355 {
4356 INSTANCE_CHECK;
4357 FORBID_FAULT;
4358 MODE_ANY;
4359 NOTHROW;
4360 SO_TOLERANT;
4361 GC_NOTRIGGER;
4362 }
4363 CONTRACTL_END;
4364
4365 return m_file->IsPtrInILImage(signature);
4366}
4367
4368#ifdef FEATURE_PREJIT
4369StubMethodHashTable *Module::GetStubMethodHashTable()
4370{
4371 CONTRACTL
4372 {
4373 THROWS;
4374 GC_NOTRIGGER;
4375 }
4376 CONTRACTL_END
4377
4378 if (m_pStubMethodHashTable == NULL && SystemDomain::GetCurrentDomain()->IsCompilationDomain())
4379 {
4380 // we only need to create the hash table when NGENing, it is read-only at run-time
4381 AllocMemTracker amTracker;
4382 m_pStubMethodHashTable = StubMethodHashTable::Create(GetLoaderAllocator(), this, METHOD_STUBS_HASH_BUCKETS, &amTracker);
4383 amTracker.SuppressRelease();
4384 }
4385
4386 return m_pStubMethodHashTable;
4387}
4388#endif // FEATURE_PREJIT
4389
4390void Module::InitializeStringData(DWORD token, EEStringData *pstrData, CQuickBytes *pqb)
4391{
4392 CONTRACTL
4393 {
4394 INSTANCE_CHECK;
4395 THROWS;
4396 GC_TRIGGERS;
4397 MODE_ANY;
4398 INJECT_FAULT(COMPlusThrowOM());
4399 PRECONDITION(TypeFromToken(token) == mdtString);
4400 }
4401 CONTRACTL_END;
4402
4403 BOOL fIs80Plus;
4404 DWORD dwCharCount;
4405 LPCWSTR pString;
4406 if (FAILED(GetMDImport()->GetUserString(token, &dwCharCount, &fIs80Plus, &pString)) ||
4407 (pString == NULL))
4408 {
4409 THROW_BAD_FORMAT(BFA_BAD_STRING_TOKEN_RANGE, this);
4410 }
4411
4412#if !BIGENDIAN
4413 pstrData->SetStringBuffer(pString);
4414#else // !!BIGENDIAN
4415 _ASSERTE(pqb != NULL);
4416
4417 LPWSTR pSwapped;
4418
4419 pSwapped = (LPWSTR) pqb->AllocThrows(dwCharCount * sizeof(WCHAR));
4420 memcpy((void*)pSwapped, (void*)pString, dwCharCount*sizeof(WCHAR));
4421 SwapStringLength(pSwapped, dwCharCount);
4422
4423 pstrData->SetStringBuffer(pSwapped);
4424#endif // !!BIGENDIAN
4425
4426 // MD and String look at this bit in opposite ways. Here's where we'll do the conversion.
4427 // MD sets the bit to true if the string contains characters greater than 80.
4428 // String sets the bit to true if the string doesn't contain characters greater than 80.
4429
4430 pstrData->SetCharCount(dwCharCount);
4431 pstrData->SetIsOnlyLowChars(!fIs80Plus);
4432}
4433
4434#ifndef CROSSGEN_COMPILE
4435
4436#ifdef FEATURE_PREJIT
4437OBJECTHANDLE Module::ResolveStringRefHelper(DWORD token, BaseDomain *pDomain, PTR_CORCOMPILE_IMPORT_SECTION pSection, EEStringData *pStrData)
4438{
4439 PEImageLayout *pNativeImage = GetNativeImage();
4440
4441 // Get the table
4442 COUNT_T tableSize;
4443 TADDR tableBase = pNativeImage->GetDirectoryData(&pSection->Section, &tableSize);
4444
4445 // Walk the handle table.
4446 // @TODO: If we ever care about the perf of this function, we could sort the tokens
4447 // using as a key the string they point to, so we could do a binary search
4448 for (SIZE_T * pEntry = (SIZE_T *)tableBase ; pEntry < (SIZE_T *)(tableBase + tableSize); pEntry++)
4449 {
4450 // Ensure that the compiler won't fetch the value twice
4451 SIZE_T entry = VolatileLoadWithoutBarrier(pEntry);
4452
4453 if (CORCOMPILE_IS_POINTER_TAGGED(entry))
4454 {
4455 BYTE * pBlob = (BYTE *) pNativeImage->GetRvaData(CORCOMPILE_UNTAG_TOKEN(entry));
4456
4457 // Note that we only care about strings from current module, and so we do not check ENCODE_MODULE_OVERRIDE
4458 if (*pBlob++ == ENCODE_STRING_HANDLE &&
4459 TokenFromRid(CorSigUncompressData((PCCOR_SIGNATURE&) pBlob), mdtString) == token)
4460 {
4461 EnsureWritablePages(pEntry);
4462
4463 // This string hasn't been fixed up. Synchronize the update with the normal
4464 // fixup logic
4465 {
4466 CrstHolder ch(this->GetFixupCrst());
4467
4468 if (!CORCOMPILE_IS_POINTER_TAGGED(*pEntry))
4469 {
4470 // We lost the race, just return current entry
4471 }
4472 else
4473 {
4474 *pEntry = (SIZE_T) ResolveStringRef(token, pDomain, false);
4475 }
4476 }
4477
4478 return (OBJECTHANDLE) *pEntry;
4479 }
4480 }
4481 else
4482 {
4483 OBJECTREF* pRef = (OBJECTREF*) entry;
4484 _ASSERTE((*pRef)->GetMethodTable() == g_pStringClass);
4485
4486 STRINGREF stringRef = (STRINGREF) *pRef;
4487
4488 // Is this the string we are trying to resolve?
4489 if (pStrData->GetCharCount() == stringRef->GetStringLength() &&
4490 memcmp((void*)pStrData->GetStringBuffer(),
4491 (void*) stringRef->GetBuffer(),
4492 pStrData->GetCharCount()*sizeof(WCHAR)) == 0)
4493 {
4494 // We found it, so we just have to return this instance
4495 return (OBJECTHANDLE) entry;
4496 }
4497 }
4498 }
4499 return NULL;
4500}
4501#endif // FEATURE_PREJIT
4502
4503OBJECTHANDLE Module::ResolveStringRef(DWORD token, BaseDomain *pDomain, bool bNeedToSyncWithFixups)
4504{
4505 CONTRACTL
4506 {
4507 INSTANCE_CHECK;
4508 THROWS;
4509 GC_TRIGGERS;
4510 MODE_ANY;
4511 INJECT_FAULT(COMPlusThrowOM());
4512 PRECONDITION(TypeFromToken(token) == mdtString);
4513 }
4514 CONTRACTL_END;
4515
4516 EEStringData strData;
4517 OBJECTHANDLE string = NULL;
4518
4519#if !BIGENDIAN
4520 InitializeStringData(token, &strData, NULL);
4521#else // !!BIGENDIAN
4522 CQuickBytes qb;
4523 InitializeStringData(token, &strData, &qb);
4524#endif // !!BIGENDIAN
4525
4526 GCX_COOP();
4527
4528 // We can only do this for native images as they guarantee that resolvestringref will be
4529 // called only once per string from this module. @TODO: We really dont have any way of asserting
4530 // this, which would be nice... (and is needed to guarantee correctness)
4531#ifdef FEATURE_PREJIT
4532 if (HasNativeImage() && IsNoStringInterning())
4533 {
4534 if (bNeedToSyncWithFixups)
4535 {
4536 // In an ngen image, it is possible that we get here but not be coming from a fixup,
4537 // (FixupNativeEntry case). In that unfortunate case (ngen partial images, dynamic methods,
4538 // lazy string inits) we will have to troll through the fixup list, and in the case the string is there,
4539 // reuse it, if it's there but hasn't been fixed up, fix it up now, and in the case it isn't
4540 // there at all, then go to our old style string interning. Going through this code path is
4541 // guaranteed to be slow. If necessary, we can further optimize it by sorting the token table,
4542 // Another way of solving this would be having a token to string table (would require knowing
4543 // all our posible stings in the ngen case (this is possible by looking at the IL))
4544
4545 PEImageLayout * pNativeImage = GetNativeImage();
4546
4547 COUNT_T nSections;
4548 PTR_CORCOMPILE_IMPORT_SECTION pSections = pNativeImage->GetNativeImportSections(&nSections);
4549
4550 for (COUNT_T iSection = 0; iSection < nSections; iSection++)
4551 {
4552 PTR_CORCOMPILE_IMPORT_SECTION pSection = pSections + iSection;
4553
4554 if (pSection->Type != CORCOMPILE_IMPORT_TYPE_STRING_HANDLE)
4555 continue;
4556
4557 OBJECTHANDLE oh = ResolveStringRefHelper(token, pDomain, pSection, &strData);
4558 if (oh != NULL)
4559 return oh;
4560 }
4561
4562 // The string is not in our fixup list, so just intern it old style (using hashtable)
4563 goto INTERN_OLD_STYLE;
4564
4565 }
4566 /* Unfortunately, this assert won't work in some cases of generics, consider the following scenario:
4567
4568 1) Generic type in mscorlib.
4569 2) Instantiation of generic (1) (via valuetype) in another module
4570 3) other module now holds a copy of the code of the generic for that particular instantiation
4571 however, it is resolving the string literals against mscorlib, which breaks the invariant
4572 this assert was based on (no string fixups against other modules). In fact, with NoStringInterning,
4573 our behavior is not very intuitive.
4574 */
4575 /*
4576 _ASSERTE(pDomain == GetAssembly()->GetDomain() && "If your are doing ldstr for a string"
4577 "in another module, either the JIT is very smart or you have a bug, check INLINE_NO_CALLEE_LDSTR");
4578
4579 */
4580 /*
4581 Dev10 804385 bugfix -
4582 We should be using appdomain that the string token lives in (GetAssembly->GetDomain())
4583 to allocate the System.String object instead of the appdomain that first uses the ldstr <token> (pDomain).
4584
4585 Otherwise, it is possible to get into the situation that pDomain is unloaded but GetAssembly->GetDomain() is
4586 still kicking around. Anything else that is still using that string will now be pointing to an object
4587 that will be freed when the next GC happens.
4588 */
4589 pDomain = GetAssembly()->GetDomain();
4590
4591 // The caller is going to update an ngen fixup entry. The fixup entry
4592 // is used to reference the string and to ensure that the string is
4593 // allocated only once. Hence, this operation needs to be done under a lock.
4594 _ASSERTE(GetFixupCrst()->OwnedByCurrentThread());
4595
4596 // Allocate handle
4597 OBJECTREF* pRef = pDomain->AllocateObjRefPtrsInLargeTable(1);
4598
4599 STRINGREF str = AllocateStringObject(&strData);
4600 SetObjectReference(pRef, str, NULL);
4601
4602 #ifdef LOGGING
4603 int length = strData.GetCharCount();
4604 length = min(length, 100);
4605 WCHAR *szString = (WCHAR *)_alloca((length + 1) * sizeof(WCHAR));
4606 memcpyNoGCRefs((void*)szString, (void*)strData.GetStringBuffer(), length * sizeof(WCHAR));
4607 szString[length] = '\0';
4608 LOG((LF_APPDOMAIN, LL_INFO10000, "String literal \"%S\" won't be interned due to NoInterningAttribute\n", szString));
4609 #endif // LOGGING
4610
4611 return (OBJECTHANDLE) pRef;
4612 }
4613
4614
4615INTERN_OLD_STYLE:
4616#endif
4617 // Retrieve the string from the either the appropriate LoaderAllocator
4618 LoaderAllocator *pLoaderAllocator;
4619
4620 if (this->IsCollectible())
4621 pLoaderAllocator = this->GetLoaderAllocator();
4622 else
4623 pLoaderAllocator = pDomain->GetLoaderAllocator();
4624
4625 string = (OBJECTHANDLE)pLoaderAllocator->GetStringObjRefPtrFromUnicodeString(&strData);
4626
4627 return string;
4628}
4629#endif // CROSSGEN_COMPILE
4630
4631//
4632// Used by the verifier. Returns whether this stringref is valid.
4633//
4634CHECK Module::CheckStringRef(DWORD token)
4635{
4636 LIMITED_METHOD_CONTRACT;
4637 CHECK(TypeFromToken(token)==mdtString);
4638 CHECK(!IsNilToken(token));
4639 CHECK(GetMDImport()->IsValidToken(token));
4640 CHECK_OK;
4641}
4642
4643mdToken Module::GetEntryPointToken()
4644{
4645 WRAPPER_NO_CONTRACT;
4646
4647 return m_file->GetEntryPointToken();
4648}
4649
4650BYTE *Module::GetProfilerBase()
4651{
4652 CONTRACT(BYTE*)
4653 {
4654 NOTHROW;
4655 GC_NOTRIGGER;
4656 CANNOT_TAKE_LOCK;
4657 }
4658 CONTRACT_END;
4659
4660 if (m_file == NULL) // I'd rather assert this is not the case...
4661 {
4662 RETURN NULL;
4663 }
4664 else if (HasNativeImage())
4665 {
4666 RETURN (BYTE*)(GetNativeImage()->GetBase());
4667 }
4668 else if (m_file->IsLoaded())
4669 {
4670 RETURN (BYTE*)(m_file->GetLoadedIL()->GetBase());
4671 }
4672 else
4673 {
4674 RETURN NULL;
4675 }
4676}
4677
4678void Module::AddActiveDependency(Module *pModule, BOOL unconditional)
4679{
4680 CONTRACT_VOID
4681 {
4682 THROWS;
4683 GC_TRIGGERS;
4684 PRECONDITION(CheckPointer(pModule));
4685 PRECONDITION(pModule != this);
4686 PRECONDITION(!IsSystem());
4687 // Postcondition about activation
4688 }
4689 CONTRACT_END;
4690
4691 pModule->EnsureActive();
4692 RETURN;
4693}
4694
4695void Module::EnableModuleFailureTriggers(Module *pModuleTo, AppDomain *pDomain)
4696{
4697 CONTRACTL
4698 {
4699 THROWS;
4700 GC_TRIGGERS;
4701 MODE_ANY;
4702 }
4703 CONTRACTL_END;
4704 // At this point we need to enable failure triggers we have placed in the code for this module. However,
4705 // the failure trigger codegen logic is NYI. To keep correctness, we just allow the exception to propagate
4706 // here. Note that in general this will enforce the failure invariants, but will also result in some rude
4707 // behavior as these failures will be propagated too widely rather than constrained to the appropriate
4708 // assemblies/app domains.
4709 //
4710 // This should throw.
4711 STRESS_LOG2(LF_CLASSLOADER, LL_INFO100,"EnableModuleFailureTriggers for module %p in AppDomain %i\n",pModuleTo,pDomain->GetId().m_dwId);
4712 DomainFile *pDomainFileTo = pModuleTo->GetDomainFile(pDomain);
4713 pDomainFileTo->EnsureActive();
4714
4715 // @NYI: shouldn't get here yet since we propagate failures
4716 UNREACHABLE_MSG("Module failure triggers NYI");
4717}
4718
4719#endif //!DACCESS_COMPILE
4720
4721//
4722// an GetAssemblyIfLoadedAppDomainIterator is used to iterate over all domains that
4723// are known to be walkable at the time GetAssemblyIfLoaded is executed.
4724//
4725// The iteration is guaranteed to include all domains that exist at the
4726// start & end of the iteration that are safely accessible. This class is logically part
4727// of GetAssemblyIfLoaded and logically has the same set of contracts.
4728//
4729
4730class GetAssemblyIfLoadedAppDomainIterator
4731{
4732 enum IteratorType
4733 {
4734 StackwalkingThreadIterator,
4735 AllAppDomainWalkingIterator,
4736 CurrentAppDomainIterator
4737 } m_iterType;
4738
4739public:
4740 GetAssemblyIfLoadedAppDomainIterator() :
4741 m_adIteratorAll(TRUE),
4742 m_appDomainCurrent(NULL),
4743 m_pFrame(NULL),
4744 m_fNextCalledForCurrentADIterator(FALSE)
4745 {
4746 LIMITED_METHOD_CONTRACT;
4747#ifndef DACCESS_COMPILE
4748 if (IsStackWalkerThread())
4749 {
4750 Thread * pThread = (Thread *)ClrFlsGetValue(TlsIdx_StackWalkerWalkingThread);
4751 m_iterType = StackwalkingThreadIterator;
4752 m_pFrame = pThread->GetFrame();
4753 m_appDomainCurrent = pThread->GetDomain();
4754 }
4755 else if (IsGCThread())
4756 {
4757 m_iterType = AllAppDomainWalkingIterator;
4758 m_adIteratorAll.Init();
4759 }
4760 else
4761 {
4762 _ASSERTE(::GetAppDomain() != NULL);
4763 m_appDomainCurrent = ::GetAppDomain();
4764 m_iterType = CurrentAppDomainIterator;
4765 }
4766#else //!DACCESS_COMPILE
4767 // We have to walk all AppDomains in debugger
4768 m_iterType = AllAppDomainWalkingIterator;
4769 m_adIteratorAll.Init();
4770#endif //!DACCESS_COMPILE
4771 }
4772
4773 BOOL Next()
4774 {
4775 WRAPPER_NO_CONTRACT;
4776
4777 switch (m_iterType)
4778 {
4779#ifndef DACCESS_COMPILE
4780 case StackwalkingThreadIterator:
4781 if (!m_fNextCalledForCurrentADIterator)
4782 {
4783 m_fNextCalledForCurrentADIterator = TRUE;
4784
4785 // Try searching frame chain if the current domain is NULL
4786 if (m_appDomainCurrent == NULL)
4787 return Next();
4788
4789 return TRUE;
4790 }
4791 else
4792 {
4793 while (m_pFrame != FRAME_TOP)
4794 {
4795 AppDomain * pDomain = m_pFrame->GetReturnDomain();
4796 if ((pDomain != NULL) && (pDomain != m_appDomainCurrent))
4797 {
4798 m_appDomainCurrent = pDomain;
4799 return TRUE;
4800 }
4801 m_pFrame = m_pFrame->PtrNextFrame();
4802 }
4803
4804 return FALSE;
4805 }
4806#endif //!DACCESS_COMPILE
4807
4808 case AllAppDomainWalkingIterator:
4809 {
4810 BOOL fSuccess = m_adIteratorAll.Next();
4811 if (fSuccess)
4812 m_appDomainCurrent = m_adIteratorAll.GetDomain();
4813 return fSuccess;
4814 }
4815
4816#ifndef DACCESS_COMPILE
4817 case CurrentAppDomainIterator:
4818 {
4819 BOOL retVal;
4820 retVal = !m_fNextCalledForCurrentADIterator;
4821 m_fNextCalledForCurrentADIterator = TRUE;
4822 return retVal;
4823 }
4824#endif //!DACCESS_COMPILE
4825
4826 default:
4827 _ASSERTE(FALSE);
4828 return FALSE;
4829 }
4830 }
4831
4832 AppDomain * GetDomain()
4833 {
4834 LIMITED_METHOD_CONTRACT;
4835
4836 return m_appDomainCurrent;
4837 }
4838
4839 BOOL UsingCurrentAD()
4840 {
4841 LIMITED_METHOD_CONTRACT;
4842 return m_iterType == CurrentAppDomainIterator;
4843 }
4844
4845 private:
4846
4847 UnsafeAppDomainIterator m_adIteratorAll;
4848 AppDomain * m_appDomainCurrent;
4849 Frame * m_pFrame;
4850 BOOL m_fNextCalledForCurrentADIterator;
4851}; // class GetAssemblyIfLoadedAppDomainIterator
4852
4853#if !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
4854// This function, given an AssemblyRef into the ngen generated native metadata section, will find the assembly referenced if
4855// 1. The Assembly is defined with a different name than the AssemblyRef provides
4856// 2. The Assembly has reached the stage of being loaded.
4857// This function is used as a helper function to assist GetAssemblyIfLoaded with its tasks in the conditions
4858// where GetAssemblyIfLoaded must succeed (or we violate various invariants in the system required for
4859// correct implementation of GC, Stackwalking, and generic type loading.
4860Assembly * Module::GetAssemblyIfLoadedFromNativeAssemblyRefWithRefDefMismatch(mdAssemblyRef kAssemblyRef, BOOL *pfDiscoveredAssemblyRefMatchesTargetDefExactly)
4861{
4862 CONTRACT(Assembly *)
4863 {
4864 INSTANCE_CHECK;
4865 NOTHROW;
4866 GC_NOTRIGGER;
4867 FORBID_FAULT;
4868 MODE_ANY;
4869 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
4870 }
4871 CONTRACT_END;
4872
4873 _ASSERTE(HasNativeImage());
4874
4875 Assembly *pAssembly = NULL;
4876 IMDInternalImport *pImportFoundNativeImage = this->GetNativeAssemblyImport(FALSE);
4877
4878 if (!pImportFoundNativeImage)
4879 {
4880 RETURN NULL;
4881 }
4882
4883 if (kAssemblyRef != mdAssemblyRefNil)
4884 {
4885 // Scan CORCOMPILE_DEPENDENCIES tables
4886 PEImageLayout* pNativeLayout = this->GetNativeImage();
4887 COUNT_T dependencyCount;
4888 CORCOMPILE_DEPENDENCY *pDependencies = pNativeLayout->GetNativeDependencies(&dependencyCount);
4889
4890 // Find the assemblyDef that defines the exact target
4891 mdAssemblyRef foundAssemblyDef = mdAssemblyRefNil;
4892
4893 for (COUNT_T i = 0; i < dependencyCount; ++i)
4894 {
4895 CORCOMPILE_DEPENDENCY* pDependency = &(pDependencies[i]);
4896 if (pDependency->dwAssemblyRef == kAssemblyRef)
4897 {
4898 foundAssemblyDef = pDependency->dwAssemblyDef;
4899 break;
4900 }
4901 }
4902
4903 // In this case we know there is no assembly redirection involved. Skip any additional work.
4904 if (kAssemblyRef == foundAssemblyDef)
4905 {
4906 *pfDiscoveredAssemblyRefMatchesTargetDefExactly = true;
4907 RETURN NULL;
4908 }
4909
4910 if (foundAssemblyDef != mdAssemblyRefNil)
4911 {
4912 // Find out if THIS reference is satisfied
4913 // Specify fDoNotUtilizeExtraChecks to prevent recursion
4914 Assembly *pAssemblyCandidate = this->GetAssemblyIfLoaded(foundAssemblyDef, NULL, NULL, pImportFoundNativeImage, TRUE /*fDoNotUtilizeExtraChecks*/);
4915
4916 // This extended check is designed only to find assemblies loaded via an AssemblySpecBindingCache based binder. Verify that's what we found.
4917 if(pAssemblyCandidate != NULL)
4918 {
4919 if (!pAssemblyCandidate->GetManifestFile()->HasHostAssembly())
4920 {
4921 pAssembly = pAssemblyCandidate;
4922 }
4923 else
4924 {
4925 // This should only happen in the generic instantiation case when multiple threads are racing and
4926 // the assembly found is one which we will determine is the wrong assembly.
4927 //
4928 // 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.
4929 _ASSERTE("Non-AssemblySpecBindingCache based assembly found with extended search" && !(IsStackWalkerThread() || IsGCThread()) && IsGenericInstantiationLookupCompareThread());
4930 }
4931 }
4932 }
4933 }
4934
4935 RETURN pAssembly;
4936}
4937#endif // !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
4938
4939// Fills ppContainingWinRtAppDomain only if WinRT type name is passed and if the assembly is found (return value != NULL).
4940Assembly *
4941Module::GetAssemblyIfLoaded(
4942 mdAssemblyRef kAssemblyRef,
4943 LPCSTR szWinRtNamespace, // = NULL
4944 LPCSTR szWinRtClassName, // = NULL
4945 IMDInternalImport * pMDImportOverride, // = NULL
4946 BOOL fDoNotUtilizeExtraChecks, // = FALSE
4947 ICLRPrivBinder *pBindingContextForLoadedAssembly // = NULL
4948)
4949{
4950 CONTRACT(Assembly *)
4951 {
4952 INSTANCE_CHECK;
4953 NOTHROW;
4954 GC_NOTRIGGER;
4955 FORBID_FAULT;
4956 MODE_ANY;
4957 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
4958 SUPPORTS_DAC;
4959 }
4960 CONTRACT_END;
4961
4962 Assembly * pAssembly = NULL;
4963 BOOL fCanUseRidMap = ((pMDImportOverride == NULL) &&
4964 (szWinRtNamespace == NULL));
4965
4966#ifdef _DEBUG
4967 fCanUseRidMap = fCanUseRidMap && (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GetAssemblyIfLoadedIgnoreRidMap) == 0);
4968#endif
4969
4970 // 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.
4971#if !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
4972 _ASSERTE(!IsGenericInstantiationLookupCompareThread() || HasNativeImage());
4973#endif
4974
4975 // Don't do a lookup if an override IMDInternalImport is provided, since the lookup is for the
4976 // standard IMDInternalImport and might result in an incorrect result.
4977 // WinRT references also do not update RID map, so don't try to look it up
4978 if (fCanUseRidMap)
4979 {
4980 pAssembly = LookupAssemblyRef(kAssemblyRef);
4981 }
4982
4983#ifndef DACCESS_COMPILE
4984 // Check if actually loaded, unless a GC is in progress or the current thread is
4985 // walking the stack (either its own stack, or another thread's stack) as that works
4986 // only with loaded assemblies
4987 //
4988 // NOTE: The case where the current thread is walking a stack can be problematic for
4989 // other reasons, as the remaining code of this function uses "GetAppDomain()", when
4990 // in fact the right AppDomain to use is the one corresponding to the frame being
4991 // traversed on the walked thread. Dev10 TFS bug# 762348 tracks that issue.
4992 if ((pAssembly != NULL) && !IsGCThread() && !IsStackWalkerThread())
4993 {
4994 _ASSERTE(::GetAppDomain() != NULL);
4995 DomainAssembly * pDomainAssembly = pAssembly->FindDomainAssembly(::GetAppDomain());
4996 if ((pDomainAssembly == NULL) || !pDomainAssembly->IsLoaded())
4997 pAssembly = NULL;
4998 }
4999#endif //!DACCESS_COMPILE
5000
5001 if (pAssembly == NULL)
5002 {
5003 // If in stackwalking or gc mode
5004 // For each AppDomain that is on the stack being walked...
5005 // For each AppDomain in the process... if gc'ing
5006 // For the current AppDomain ... if none of the above
5007 GetAssemblyIfLoadedAppDomainIterator appDomainIter;
5008
5009 while (appDomainIter.Next())
5010 {
5011 AppDomain * pAppDomainExamine = appDomainIter.GetDomain();
5012
5013 DomainAssembly * pCurAssemblyInExamineDomain = GetAssembly()->FindDomainAssembly(pAppDomainExamine);
5014 if (pCurAssemblyInExamineDomain == NULL)
5015 {
5016 continue;
5017 }
5018
5019#ifdef FEATURE_COMINTEROP
5020 if (szWinRtNamespace != NULL)
5021 {
5022 _ASSERTE(szWinRtClassName != NULL);
5023
5024 CLRPrivBinderWinRT * pWinRtBinder = pAppDomainExamine->GetWinRtBinder();
5025 if (pWinRtBinder != nullptr)
5026 {
5027 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5028 pAssembly = pWinRtBinder->FindAssemblyForTypeIfLoaded(
5029 dac_cast<PTR_AppDomain>(pAppDomainExamine),
5030 szWinRtNamespace,
5031 szWinRtClassName);
5032 }
5033
5034 // Never store WinMD AssemblyRefs into the rid map.
5035 if (pAssembly != NULL)
5036 {
5037 break;
5038 }
5039
5040 // Never attemt to search the assembly spec binding cache for this form of WinRT assembly reference.
5041 continue;
5042 }
5043#endif // FEATURE_COMINTEROP
5044
5045#ifndef DACCESS_COMPILE
5046 {
5047 IMDInternalImport * pMDImport = (pMDImportOverride == NULL) ? (GetMDImport()) : (pMDImportOverride);
5048
5049 //we have to be very careful here.
5050 //we are using InitializeSpecInternal so we need to make sure that under no condition
5051 //the data we pass to it can outlive the assembly spec.
5052 AssemblySpec spec;
5053 if (FAILED(spec.InitializeSpecInternal(kAssemblyRef,
5054 pMDImport,
5055 pCurAssemblyInExamineDomain,
5056 FALSE /*fAllowAllocation*/)))
5057 {
5058 continue;
5059 }
5060
5061 // If we have been passed the binding context for the loaded assembly that is being looked up in the
5062 // cache, then set it up in the AssemblySpec for the cache lookup to use it below.
5063 if (pBindingContextForLoadedAssembly != NULL)
5064 {
5065 _ASSERTE(spec.GetBindingContext() == NULL);
5066 spec.SetBindingContext(pBindingContextForLoadedAssembly);
5067 }
5068 DomainAssembly * pDomainAssembly = nullptr;
5069
5070 {
5071 pDomainAssembly = pAppDomainExamine->FindCachedAssembly(&spec, FALSE /*fThrow*/);
5072 }
5073
5074 if (pDomainAssembly && pDomainAssembly->IsLoaded())
5075 pAssembly = pDomainAssembly->GetCurrentAssembly(); // <NOTE> Do not use GetAssembly - that may force the completion of a load
5076
5077 // Only store in the rid map if working with the current AppDomain.
5078 if (fCanUseRidMap && pAssembly && appDomainIter.UsingCurrentAD())
5079 StoreAssemblyRef(kAssemblyRef, pAssembly);
5080
5081 if (pAssembly != NULL)
5082 break;
5083 }
5084#endif //!DACCESS_COMPILE
5085 }
5086 }
5087
5088#if !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
5089 if (pAssembly == NULL && (IsStackWalkerThread() || IsGCThread() || IsGenericInstantiationLookupCompareThread()) && !fDoNotUtilizeExtraChecks)
5090 {
5091 // The GetAssemblyIfLoaded function must succeed in finding assemblies which have already been loaded in a series of interesting cases
5092 // (GC, Stackwalking, GenericInstantiationLookup). This logic is used to handle cases where the normal lookup done above
5093 // 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
5094 // run in cases which are not known to be problematic, or would not benefit from the logic here.
5095 //
5096 // 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
5097 // image depends on an assembly through some sort of binding version/public key token adjustment (due to binding policy, unification, or portability rules)
5098 // and the assembly depended on was loaded through a binder that utilizes the AssemblySpecBindingCache for binder caching. (The cache's in the other
5099 // binder's successfully answer the GetAssemblyIfLoaded question in the case of non-exact matches where the match was discovered during
5100 // ngen resolution.)
5101 // This restricts the scenario to a somewhat restricted case.
5102
5103 BOOL eligibleForAdditionalChecks = TRUE;
5104 if (szWinRtNamespace != NULL)
5105 eligibleForAdditionalChecks = FALSE; // WinRT binds do not support this scan
5106
5107 AssemblySpec specSearchAssemblyRef;
5108
5109 // Get the assembly ref information that we are attempting to satisfy.
5110 if (eligibleForAdditionalChecks)
5111 {
5112 IMDInternalImport * pMDImport = (pMDImportOverride == NULL) ? (GetMDImport()) : (pMDImportOverride);
5113
5114 if (FAILED(specSearchAssemblyRef.InitializeSpecInternal(kAssemblyRef,
5115 pMDImport,
5116 NULL,
5117 FALSE /*fAllowAllocation*/)))
5118 {
5119 eligibleForAdditionalChecks = FALSE; // If an assemblySpec can't be constructed then we're not going to succeed
5120 // This should not ever happen, due to the above checks, but this logic
5121 // is intended to be defensive against unexpected behavior.
5122 }
5123 else if (specSearchAssemblyRef.IsContentType_WindowsRuntime())
5124 {
5125 eligibleForAdditionalChecks = FALSE; // WinRT binds do not support this scan
5126 }
5127 }
5128
5129 if (eligibleForAdditionalChecks)
5130 {
5131 BOOL abortAdditionalChecks = false;
5132
5133 // When working with an ngenn'd assembly, as an optimization we can scan only that module for dependency info.
5134 bool onlyScanCurrentModule = HasNativeImage() && GetFile()->IsAssembly();
5135 mdAssemblyRef foundAssemblyRef = mdAssemblyRefNil;
5136
5137 GetAssemblyIfLoadedAppDomainIterator appDomainIter;
5138
5139 // In each AppDomain that might be interesting, scan for an ngen image that is loaded that has a dependency on the same
5140 // assembly that is now being looked up. If that ngen image has the same dependency, then we can use the CORCOMPILE_DEPENDENCIES
5141 // table to find the exact AssemblyDef that defines the assembly, and attempt a load based on that information.
5142 // As this logic is expected to be used only in exceedingly rare situations, this code has not been tuned for performance
5143 // in any way.
5144 while (!abortAdditionalChecks && appDomainIter.Next())
5145 {
5146 AppDomain * pAppDomainExamine = appDomainIter.GetDomain();
5147
5148 DomainAssembly * pCurAssemblyInExamineDomain = GetAssembly()->FindDomainAssembly(pAppDomainExamine);
5149 if (pCurAssemblyInExamineDomain == NULL)
5150 {
5151 continue;
5152 }
5153
5154 DomainFile *pDomainFileNativeImage;
5155
5156 if (onlyScanCurrentModule)
5157 {
5158 pDomainFileNativeImage = pCurAssemblyInExamineDomain;
5159 // Do not reset foundAssemblyRef.
5160 // This will allow us to avoid scanning for foundAssemblyRef in each domain we iterate through
5161 }
5162 else
5163 {
5164 foundAssemblyRef = mdAssemblyRefNil;
5165 pDomainFileNativeImage = pAppDomainExamine->GetDomainFilesWithNativeImagesList();
5166 }
5167
5168 while (!abortAdditionalChecks && (pDomainFileNativeImage != NULL) && (pAssembly == NULL))
5169 {
5170 Module *pNativeImageModule = pDomainFileNativeImage->GetCurrentModule();
5171 _ASSERTE(pNativeImageModule->HasNativeImage());
5172 IMDInternalImport *pImportFoundNativeImage = pNativeImageModule->GetNativeAssemblyImport(FALSE);
5173 if (pImportFoundNativeImage != NULL)
5174 {
5175 if (IsNilToken(foundAssemblyRef))
5176 {
5177 // Enumerate assembly refs in nmd space, and compare against held ref.
5178 HENUMInternalHolder hAssemblyRefEnum(pImportFoundNativeImage);
5179 if (FAILED(hAssemblyRefEnum.EnumInitNoThrow(mdtAssemblyRef, mdAssemblyRefNil)))
5180 {
5181 continue;
5182 }
5183
5184 mdAssemblyRef assemblyRef = mdAssemblyRefNil;
5185
5186 // Find if the native image has a matching assembly ref in its compile dependencies.
5187 while (pImportFoundNativeImage->EnumNext(&hAssemblyRefEnum, &assemblyRef) && (pAssembly == NULL))
5188 {
5189 AssemblySpec specFoundAssemblyRef;
5190 if (FAILED(specFoundAssemblyRef.InitializeSpecInternal(assemblyRef,
5191 pImportFoundNativeImage,
5192 NULL,
5193 FALSE /*fAllowAllocation*/)))
5194 {
5195 continue; // If the spec cannot be loaded, it isn't the one we're looking for
5196 }
5197
5198 // Check for AssemblyRef equality
5199 if (specSearchAssemblyRef.CompareEx(&specFoundAssemblyRef))
5200 {
5201 foundAssemblyRef = assemblyRef;
5202 break;
5203 }
5204 }
5205 }
5206
5207 pAssembly = pNativeImageModule->GetAssemblyIfLoadedFromNativeAssemblyRefWithRefDefMismatch(foundAssemblyRef, &abortAdditionalChecks);
5208
5209 if (fCanUseRidMap && pAssembly && appDomainIter.UsingCurrentAD())
5210 StoreAssemblyRef(kAssemblyRef, pAssembly);
5211 }
5212
5213 // If we're only scanning one module for accurate dependency information, break the loop here.
5214 if (onlyScanCurrentModule)
5215 break;
5216
5217 pDomainFileNativeImage = pDomainFileNativeImage->FindNextDomainFileWithNativeImage();
5218 }
5219 }
5220 }
5221 }
5222#endif // !defined(DACCESS_COMPILE) && defined(FEATURE_PREJIT)
5223
5224 // When walking the stack or computing GC information this function should never fail.
5225 _ASSERTE((pAssembly != NULL) || !(IsStackWalkerThread() || IsGCThread()));
5226
5227#ifdef DACCESS_COMPILE
5228
5229 // Note: In rare cases when debugger walks the stack, we could actually have pAssembly=NULL here.
5230 // To fix that we should DACize the AppDomain-iteration code above (especially AssemblySpec).
5231 _ASSERTE(pAssembly != NULL);
5232
5233#endif //DACCESS_COMPILE
5234
5235 RETURN pAssembly;
5236} // Module::GetAssemblyIfLoaded
5237
5238DWORD
5239Module::GetAssemblyRefFlags(
5240 mdAssemblyRef tkAssemblyRef)
5241{
5242 CONTRACTL
5243 {
5244 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
5245 GC_NOTRIGGER;
5246 MODE_ANY;
5247 }
5248 CONTRACTL_END;
5249
5250 _ASSERTE(TypeFromToken(tkAssemblyRef) == mdtAssemblyRef);
5251
5252 LPCSTR pszAssemblyName;
5253 const void *pbPublicKeyOrToken;
5254 DWORD cbPublicKeyOrToken;
5255
5256 DWORD dwAssemblyRefFlags;
5257 IfFailThrow(GetMDImport()->GetAssemblyRefProps(
5258 tkAssemblyRef,
5259 &pbPublicKeyOrToken,
5260 &cbPublicKeyOrToken,
5261 &pszAssemblyName,
5262 NULL,
5263 NULL,
5264 NULL,
5265 &dwAssemblyRefFlags));
5266
5267 return dwAssemblyRefFlags;
5268} // Module::GetAssemblyRefFlags
5269
5270#ifndef DACCESS_COMPILE
5271
5272// Arguments:
5273// szWinRtTypeNamespace ... Namespace of WinRT type.
5274// szWinRtTypeClassName ... Name of WinRT type, NULL for non-WinRT (classic) types.
5275DomainAssembly * Module::LoadAssembly(
5276 AppDomain * pDomain,
5277 mdAssemblyRef kAssemblyRef,
5278 LPCUTF8 szWinRtTypeNamespace,
5279 LPCUTF8 szWinRtTypeClassName)
5280{
5281 CONTRACT(DomainAssembly *)
5282 {
5283 INSTANCE_CHECK;
5284 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
5285 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
5286 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM();); }
5287 MODE_ANY;
5288 PRECONDITION(CheckPointer(pDomain));
5289 POSTCONDITION(CheckPointer(RETVAL, NULL_NOT_OK));
5290 //POSTCONDITION((CheckPointer(GetAssemblyIfLoaded(kAssemblyRef, szWinRtTypeNamespace, szWinRtTypeClassName)), NULL_NOT_OK));
5291 }
5292 CONTRACT_END;
5293
5294 ETWOnStartup (LoaderCatchCall_V1, LoaderCatchCallEnd_V1);
5295
5296 DomainAssembly * pDomainAssembly;
5297
5298 //
5299 // Early out quickly if the result is cached
5300 //
5301 Assembly * pAssembly = LookupAssemblyRef(kAssemblyRef);
5302 if (pAssembly != NULL)
5303 {
5304 _ASSERTE(HasBindableIdentity(kAssemblyRef));
5305
5306 pDomainAssembly = pAssembly->FindDomainAssembly(pDomain);
5307
5308 if (pDomainAssembly == NULL)
5309 pDomainAssembly = pAssembly->GetDomainAssembly(pDomain);
5310 pDomain->LoadDomainFile(pDomainAssembly, FILE_LOADED);
5311
5312 RETURN pDomainAssembly;
5313 }
5314
5315 bool fHasBindableIdentity = HasBindableIdentity(kAssemblyRef);
5316
5317 {
5318 PEAssemblyHolder pFile = GetDomainFile(GetAppDomain())->GetFile()->LoadAssembly(
5319 kAssemblyRef,
5320 NULL,
5321 szWinRtTypeNamespace,
5322 szWinRtTypeClassName);
5323 AssemblySpec spec;
5324 spec.InitializeSpec(kAssemblyRef, GetMDImport(), GetDomainFile(GetAppDomain())->GetDomainAssembly());
5325 // Set the binding context in the AssemblySpec if one is available. This can happen if the LoadAssembly ended up
5326 // invoking the custom AssemblyLoadContext implementation that returned a reference to an assembly bound to a different
5327 // AssemblyLoadContext implementation.
5328 ICLRPrivBinder *pBindingContext = pFile->GetBindingContext();
5329 if (pBindingContext != NULL)
5330 {
5331 spec.SetBindingContext(pBindingContext);
5332 }
5333 if (szWinRtTypeClassName != NULL)
5334 {
5335 spec.SetWindowsRuntimeType(szWinRtTypeNamespace, szWinRtTypeClassName);
5336 }
5337 pDomainAssembly = GetAppDomain()->LoadDomainAssembly(&spec, pFile, FILE_LOADED);
5338 }
5339
5340 if (pDomainAssembly != NULL)
5341 {
5342 _ASSERTE(
5343 !fHasBindableIdentity || // GetAssemblyIfLoaded will not find non-bindable assemblies
5344 pDomainAssembly->IsSystem() || // GetAssemblyIfLoaded will not find mscorlib (see AppDomain::FindCachedFile)
5345 !pDomainAssembly->IsLoaded() || // GetAssemblyIfLoaded will not find not-yet-loaded assemblies
5346 GetAssemblyIfLoaded(kAssemblyRef, NULL, NULL, NULL, FALSE, pDomainAssembly->GetFile()->GetHostAssembly()) != NULL); // GetAssemblyIfLoaded should find all remaining cases
5347
5348 // Note: We cannot cache WinRT AssemblyRef, because it is meaningless without the TypeRef context
5349 if (pDomainAssembly->GetCurrentAssembly() != NULL)
5350 {
5351 if (fHasBindableIdentity)
5352 {
5353 StoreAssemblyRef(kAssemblyRef, pDomainAssembly->GetCurrentAssembly());
5354 }
5355 }
5356 }
5357
5358 RETURN pDomainAssembly;
5359}
5360
5361#endif // !DACCESS_COMPILE
5362
5363Module *Module::GetModuleIfLoaded(mdFile kFile, BOOL onlyLoadedInAppDomain, BOOL permitResources)
5364{
5365 CONTRACT(Module *)
5366 {
5367 INSTANCE_CHECK;
5368 NOTHROW;
5369 GC_NOTRIGGER;
5370 MODE_ANY;
5371 PRECONDITION(TypeFromToken(kFile) == mdtFile
5372 || TypeFromToken(kFile) == mdtModuleRef);
5373 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5374 FORBID_FAULT;
5375 SUPPORTS_DAC;
5376 }
5377 CONTRACT_END;
5378
5379 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5380
5381 // Handle the module ref case
5382 if (TypeFromToken(kFile) == mdtModuleRef)
5383 {
5384 LPCSTR moduleName;
5385 if (FAILED(GetMDImport()->GetModuleRefProps(kFile, &moduleName)))
5386 {
5387 RETURN NULL;
5388 }
5389
5390 // This is required only because of some lower casing on the name
5391 kFile = GetAssembly()->GetManifestFileToken(moduleName);
5392 if (kFile == mdTokenNil)
5393 RETURN NULL;
5394
5395 RETURN GetAssembly()->GetManifestModule()->GetModuleIfLoaded(kFile, onlyLoadedInAppDomain, permitResources);
5396 }
5397
5398 Module *pModule = LookupFile(kFile);
5399 if (pModule == NULL)
5400 {
5401 if (IsManifest())
5402 {
5403 if (kFile == mdFileNil)
5404 pModule = GetAssembly()->GetManifestModule();
5405 }
5406 else
5407 {
5408 // If we didn't find it there, look at the "master rid map" in the manifest file
5409 Assembly *pAssembly = GetAssembly();
5410 mdFile kMatch;
5411
5412 // This is required only because of some lower casing on the name
5413 kMatch = pAssembly->GetManifestFileToken(GetMDImport(), kFile);
5414 if (IsNilToken(kMatch))
5415 {
5416 if (kMatch == mdFileNil)
5417 {
5418 pModule = pAssembly->GetManifestModule();
5419 }
5420 else
5421 {
5422 RETURN NULL;
5423 }
5424 }
5425 else
5426 pModule = pAssembly->GetManifestModule()->LookupFile(kMatch);
5427 }
5428
5429#ifndef DACCESS_COMPILE
5430 if (pModule != NULL)
5431 StoreFileNoThrow(kFile, pModule);
5432#endif
5433 }
5434
5435 // We may not want to return a resource module
5436 if (!permitResources && pModule && pModule->IsResource())
5437 pModule = NULL;
5438
5439#ifndef DACCESS_COMPILE
5440#endif // !DACCESS_COMPILE
5441 RETURN pModule;
5442}
5443
5444#ifndef DACCESS_COMPILE
5445
5446DomainFile *Module::LoadModule(AppDomain *pDomain, mdFile kFile,
5447 BOOL permitResources/*=TRUE*/, BOOL bindOnly/*=FALSE*/)
5448{
5449 CONTRACT(DomainFile *)
5450 {
5451 INSTANCE_CHECK;
5452 THROWS;
5453 GC_TRIGGERS;
5454 MODE_ANY;
5455 PRECONDITION(TypeFromToken(kFile) == mdtFile
5456 || TypeFromToken(kFile) == mdtModuleRef);
5457 POSTCONDITION(CheckPointer(RETVAL, !permitResources || bindOnly ? NULL_OK : NULL_NOT_OK));
5458 }
5459 CONTRACT_END;
5460
5461 if (bindOnly)
5462 {
5463 RETURN NULL;
5464 }
5465 else
5466 {
5467 LPCSTR psModuleName=NULL;
5468 if (TypeFromToken(kFile) == mdtModuleRef)
5469 {
5470 // This is a moduleRef
5471 IfFailThrow(GetMDImport()->GetModuleRefProps(kFile, &psModuleName));
5472 }
5473 else
5474 {
5475 // This is mdtFile
5476 IfFailThrow(GetAssembly()->GetManifestImport()->GetFileProps(kFile,
5477 &psModuleName,
5478 NULL,
5479 NULL,
5480 NULL));
5481 }
5482 SString name(SString::Utf8, psModuleName);
5483 EEFileLoadException::Throw(name, COR_E_MULTIMODULEASSEMBLIESDIALLOWED, NULL);
5484 }
5485}
5486#endif // !DACCESS_COMPILE
5487
5488PTR_Module Module::LookupModule(mdToken kFile,BOOL permitResources/*=TRUE*/)
5489{
5490 CONTRACT(PTR_Module)
5491 {
5492 INSTANCE_CHECK;
5493 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
5494 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
5495 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT;
5496 else { INJECT_FAULT(COMPlusThrowOM()); }
5497 MODE_ANY;
5498 PRECONDITION(TypeFromToken(kFile) == mdtFile
5499 || TypeFromToken(kFile) == mdtModuleRef);
5500 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5501 SUPPORTS_DAC;
5502 }
5503 CONTRACT_END;
5504
5505 if (TypeFromToken(kFile) == mdtModuleRef)
5506 {
5507 LPCSTR moduleName;
5508 IfFailThrow(GetMDImport()->GetModuleRefProps(kFile, &moduleName));
5509 mdFile kFileLocal = GetAssembly()->GetManifestFileToken(moduleName);
5510
5511 if (kFileLocal == mdTokenNil)
5512 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
5513
5514 RETURN GetAssembly()->GetManifestModule()->LookupModule(kFileLocal, permitResources);
5515 }
5516
5517 PTR_Module pModule = LookupFile(kFile);
5518 if (pModule == NULL && !IsManifest())
5519 {
5520 // If we didn't find it there, look at the "master rid map" in the manifest file
5521 Assembly *pAssembly = GetAssembly();
5522 mdFile kMatch = pAssembly->GetManifestFileToken(GetMDImport(), kFile);
5523 if (IsNilToken(kMatch)) {
5524 if (kMatch == mdFileNil)
5525 pModule = pAssembly->GetManifestModule();
5526 else
5527 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
5528 }
5529 else
5530 pModule = pAssembly->GetManifestModule()->LookupFile(kMatch);
5531 }
5532 RETURN pModule;
5533}
5534
5535
5536TypeHandle Module::LookupTypeRef(mdTypeRef token)
5537{
5538 STATIC_CONTRACT_NOTHROW;
5539 STATIC_CONTRACT_GC_NOTRIGGER;
5540 STATIC_CONTRACT_FORBID_FAULT;
5541 SUPPORTS_DAC;
5542
5543 _ASSERTE(TypeFromToken(token) == mdtTypeRef);
5544
5545 g_IBCLogger.LogRidMapAccess( MakePair( this, token ) );
5546
5547 TypeHandle entry = TypeHandle::FromTAddr(dac_cast<TADDR>(m_TypeRefToMethodTableMap.GetElement(RidFromToken(token))));
5548
5549 if (entry.IsNull())
5550 return TypeHandle();
5551
5552 // Cannot do this in a NOTHROW function.
5553 // Note that this could be called while doing GC from the prestub of
5554 // a method to resolve typerefs in a signature. We cannot THROW
5555 // during GC.
5556
5557 // @PERF: Enable this so that we do not need to touch metadata
5558 // to resolve typerefs
5559
5560#ifdef FIXUPS_ALL_TYPEREFS
5561
5562 if (CORCOMPILE_IS_POINTER_TAGGED((SIZE_T) entry.AsPtr()))
5563 {
5564#ifndef DACCESS_COMPILE
5565 Module::RestoreTypeHandlePointer(&entry, TRUE);
5566 m_TypeRefToMethodTableMap.SetElement(RidFromToken(token), dac_cast<PTR_TypeRef>(value.AsTAddr()));
5567#else // DACCESS_COMPILE
5568 DacNotImpl();
5569#endif // DACCESS_COMPILE
5570 }
5571
5572#endif // FIXUPS_ALL_TYPEREFS
5573
5574 return entry;
5575}
5576
5577#ifdef FEATURE_NATIVE_IMAGE_GENERATION
5578mdTypeRef Module::LookupTypeRefByMethodTable(MethodTable *pMT)
5579{
5580 STANDARD_VM_CONTRACT;
5581
5582 HENUMInternalHolder hEnumTypeRefs(GetMDImport());
5583 mdTypeRef token;
5584 hEnumTypeRefs.EnumAllInit(mdtTypeRef);
5585 while (hEnumTypeRefs.EnumNext(&token))
5586 {
5587 TypeHandle thRef = LookupTypeRef(token);
5588 if (thRef.IsNull() || thRef.IsTypeDesc())
5589 {
5590 continue;
5591 }
5592
5593 MethodTable *pMTRef = thRef.AsMethodTable();
5594 if (pMT->HasSameTypeDefAs(pMTRef))
5595 {
5596 _ASSERTE(pMTRef->IsTypicalTypeDefinition());
5597 return token;
5598 }
5599 }
5600
5601#ifdef FEATURE_READYTORUN_COMPILER
5602 if (IsReadyToRunCompilation())
5603 {
5604 if (pMT->GetClass()->IsEquivalentType())
5605 {
5606 GetSvcLogger()->Log(W("ReadyToRun: Type reference to equivalent type cannot be encoded\n"));
5607 ThrowHR(E_NOTIMPL);
5608 }
5609
5610 // FUTURE: Encoding of new cross-module references for ReadyToRun
5611 // This warning is hit for recursive cross-module inlining. It is commented out to avoid noise.
5612 // GetSvcLogger()->Log(W("ReadyToRun: Type reference outside of current version bubble cannot be encoded\n"));
5613 }
5614 else
5615#endif // FEATURE_READYTORUN_COMPILER
5616 {
5617 // FUTURE TODO: Version resilience
5618 _ASSERTE(!"Cross module type reference not found");
5619 }
5620 ThrowHR(E_FAIL);
5621}
5622
5623mdMemberRef Module::LookupMemberRefByMethodDesc(MethodDesc *pMD)
5624{
5625 STANDARD_VM_CONTRACT;
5626
5627 HENUMInternalHolder hEnumMemberRefs(GetMDImport());
5628 mdMemberRef token;
5629 hEnumMemberRefs.EnumAllInit(mdtMemberRef);
5630 while (hEnumMemberRefs.EnumNext(&token))
5631 {
5632 BOOL fIsMethod = FALSE;
5633 TADDR addr = LookupMemberRef(token, &fIsMethod);
5634 if (fIsMethod)
5635 {
5636 MethodDesc *pCurMD = dac_cast<PTR_MethodDesc>(addr);
5637 if (pCurMD == pMD)
5638 {
5639 return token;
5640 }
5641 }
5642 }
5643
5644 // FUTURE TODO: Version resilience
5645 _ASSERTE(!"Cross module method reference not found");
5646 ThrowHR(E_FAIL);
5647}
5648#endif // FEATURE_NATIVE_IMAGE_GENERATION
5649
5650#ifndef DACCESS_COMPILE
5651
5652//
5653// Increase the size of one of the maps, such that it can handle a RID of at least "rid".
5654//
5655// This function must also check that another thread didn't already add a LookupMap capable
5656// of containing the same RID.
5657//
5658PTR_TADDR LookupMapBase::GrowMap(Module * pModule, DWORD rid)
5659{
5660 CONTRACT(PTR_TADDR)
5661 {
5662 INSTANCE_CHECK;
5663 THROWS;
5664 GC_NOTRIGGER;
5665 MODE_ANY;
5666 INJECT_FAULT(ThrowOutOfMemory(););
5667 POSTCONDITION(CheckPointer(RETVAL));
5668 }
5669 CONTRACT_END;
5670
5671 LookupMapBase *pMap = this;
5672 LookupMapBase *pPrev = NULL;
5673 LookupMapBase *pNewMap = NULL;
5674
5675 // Initial block size
5676 DWORD dwIndex = rid;
5677 DWORD dwBlockSize = 16;
5678
5679 {
5680 CrstHolder ch(pModule->GetLookupTableCrst());
5681 // Check whether we can already handle this RID index
5682 do
5683 {
5684 if (dwIndex < pMap->dwCount)
5685 {
5686 // Already there - some other thread must have added it
5687 RETURN pMap->GetIndexPtr(dwIndex);
5688 }
5689
5690 dwBlockSize *= 2;
5691
5692 dwIndex -= pMap->dwCount;
5693
5694 pPrev = pMap;
5695 pMap = pMap->pNext;
5696 } while (pMap != NULL);
5697
5698 _ASSERTE(pPrev != NULL); // should never happen, because there's always at least one map
5699
5700 DWORD dwSizeToAllocate = max(dwIndex + 1, dwBlockSize);
5701
5702 pNewMap = (LookupMapBase *) (void*)pModule->GetLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(LookupMapBase)) + S_SIZE_T(dwSizeToAllocate)*S_SIZE_T(sizeof(TADDR)));
5703
5704 // Note: Memory allocated on loader heap is zero filled
5705 // memset(pNewMap, 0, sizeof(LookupMap) + dwSizeToAllocate*sizeof(void*));
5706
5707 pNewMap->pNext = NULL;
5708 pNewMap->dwCount = dwSizeToAllocate;
5709
5710 pNewMap->pTable = dac_cast<ArrayDPTR(TADDR)>(pNewMap + 1);
5711
5712 // Link ourselves in
5713 VolatileStore<LookupMapBase*>(&(pPrev->pNext), pNewMap);
5714 }
5715
5716 RETURN pNewMap->GetIndexPtr(dwIndex);
5717}
5718
5719#endif // DACCESS_COMPILE
5720
5721PTR_TADDR LookupMapBase::GetElementPtr(DWORD rid)
5722{
5723 CONTRACTL
5724 {
5725 INSTANCE_CHECK;
5726 NOTHROW;
5727 GC_NOTRIGGER;
5728 MODE_ANY;
5729 SO_TOLERANT;
5730 SUPPORTS_DAC;
5731 }
5732 CONTRACTL_END;
5733
5734 LookupMapBase * pMap = this;
5735
5736#ifdef FEATURE_PREJIT
5737 if (pMap->dwNumHotItems > 0)
5738 {
5739#ifdef _DEBUG_IMPL
5740 static DWORD counter = 0;
5741 counter++;
5742 if (counter >= pMap->dwNumHotItems)
5743 {
5744 CheckConsistentHotItemList();
5745 counter = 0;
5746 }
5747#endif // _DEBUG_IMPL
5748
5749 PTR_TADDR pHotItemValue = pMap->FindHotItemValuePtr(rid);
5750 if (pHotItemValue)
5751 {
5752 return pHotItemValue;
5753 }
5754 }
5755#endif // FEATURE_PREJIT
5756
5757 DWORD dwIndex = rid;
5758 do
5759 {
5760 if (dwIndex < pMap->dwCount)
5761 {
5762 return pMap->GetIndexPtr(dwIndex);
5763 }
5764
5765 dwIndex -= pMap->dwCount;
5766 pMap = pMap->pNext;
5767 } while (pMap != NULL);
5768
5769 return NULL;
5770}
5771
5772
5773#ifdef FEATURE_PREJIT
5774
5775// This method can only be called on a compressed map (MapIsCompressed() == true). Compressed rid maps store
5776// the array of values as packed deltas (each value is based on the accumulated of all the previous entries).
5777// So this method takes the bit stream of compressed data we're navigating and the value of the last entry
5778// retrieved allowing us to calculate the full value of the next entry. Note that the values passed in and out
5779// here aren't the final values the top-level caller sees. In order to avoid having to touch the compressed
5780// data on image base relocations we actually store a form of RVA (though relative to the map base rather than
5781// the module base).
5782INT32 LookupMapBase::GetNextCompressedEntry(BitStreamReader *pTableStream, INT32 iLastValue)
5783{
5784 CONTRACTL
5785 {
5786 INSTANCE_CHECK;
5787 NOTHROW;
5788 GC_NOTRIGGER;
5789 MODE_ANY;
5790 SO_TOLERANT;
5791 SUPPORTS_DAC;
5792 PRECONDITION(MapIsCompressed());
5793 }
5794 CONTRACTL_END;
5795
5796 // The next kLookupMapLengthBits bits in the stream are an index into a per-map table that tells us the
5797 // length of the encoded delta.
5798 DWORD dwValueLength = rgEncodingLengths[pTableStream->Read(kLookupMapLengthBits)];
5799
5800 // Then follows a single bit that indicates whether the delta should be added (1) or subtracted (0) from
5801 // the previous entry value to recover the current entry value.
5802 // Once we've read that bit we read the delta (encoded as an unsigned integer using the number of bits
5803 // that we read from the encoding lengths table above).
5804 if (pTableStream->ReadOneFast())
5805 return iLastValue + (INT32)(pTableStream->Read(dwValueLength));
5806 else
5807 return iLastValue - (INT32)(pTableStream->Read(dwValueLength));
5808}
5809
5810// This method can only be called on a compressed map (MapIsCompressed() == true). Retrieves the final value
5811// (e.g. MethodTable*, MethodDesc* etc. based on map type) given the rid of the entry.
5812TADDR LookupMapBase::GetValueFromCompressedMap(DWORD rid)
5813{
5814 CONTRACTL
5815 {
5816 INSTANCE_CHECK;
5817 NOTHROW;
5818 GC_NOTRIGGER;
5819 MODE_ANY;
5820 SO_TOLERANT;
5821 SUPPORTS_DAC;
5822 PRECONDITION(MapIsCompressed());
5823 }
5824 CONTRACTL_END;
5825
5826 // Normally to extract the nth entry in the table we have to linearly parse all (n - 1) preceding entries
5827 // (since entries are stored as the delta from the previous entry). Obviously this can yield exceptionally
5828 // poor performance for the later entries in large tables. So we also build an index of the compressed
5829 // stream. This index has an entry for every kLookupMapIndexStride entries in the compressed table. Each
5830 // index entry contains the full RVA (relative to the map) of the corresponding table entry plus the bit
5831 // offset in the stream from which to start parsing the next entry's data.
5832 // In this fashion we can get to within kLookupMapIndexStride entries of our target entry and then decode
5833 // our way to the final target.
5834
5835 // Ensure that index does not go beyond end of the saved table
5836 if (rid >= dwCount)
5837 return 0;
5838
5839 // Calculate the nearest entry in the index that is lower than our target index in the full table.
5840 DWORD dwIndexEntry = rid / kLookupMapIndexStride;
5841
5842 // Then calculate how many additional entries we'll need to decode from the compressed streams to recover
5843 // the target entry.
5844 DWORD dwSubIndex = rid % kLookupMapIndexStride;
5845
5846 // Open a bit stream reader on the index and skip all the entries prior to the one we're interested in.
5847 BitStreamReader sIndexStream(pIndex);
5848 sIndexStream.Skip(dwIndexEntry * cIndexEntryBits);
5849
5850 // The first kBitsPerRVA of the index entry contain the RVA of the corresponding entry in the compressed
5851 // table. If this is exactly the entry we want (dwSubIndex == 0) then we can use this RVA to recover the
5852 // value the caller wants. Our RVAs are based on the map address rather than the module base (simply
5853 // because we don't record the module base in LookupMapBase). A delta of zero encodes a null value,
5854 // otherwise we simply add the RVA to the our map address to recover the full pointer.
5855 // Note that most LookupMaps are embedded structures (in Module) so we can't directly dac_cast<TADDR> our
5856 // "this" pointer for DAC builds. Instead we have to use the slightly slower (in DAC) but more flexible
5857 // PTR_HOST_INT_TO_TADDR() which copes with interior host pointers.
5858 INT32 iValue = (INT32)sIndexStream.Read(kBitsPerRVA);
5859 if (dwSubIndex == 0)
5860 return iValue ? PTR_HOST_INT_TO_TADDR(this) + iValue : 0;
5861
5862 // Otherwise we must parse one or more entries in the compressed table to accumulate more deltas to the
5863 // base RVA we read above. The remaining portion of the index entry has the bit offset into the compressed
5864 // table at which to begin parsing.
5865 BitStreamReader sTableStream(dac_cast<PTR_CBYTE>(pTable));
5866 sTableStream.Skip(sIndexStream.Read(cIndexEntryBits - kBitsPerRVA));
5867
5868 // Parse all the entries up to our target entry. Each step takes the RVA from the previous cycle (or from
5869 // the index entry we read above) and applies the compressed delta of the next table entry to it.
5870 for (DWORD i = 0; i < dwSubIndex; i++)
5871 iValue = GetNextCompressedEntry(&sTableStream, iValue);
5872
5873 // We have the final RVA so recover the actual pointer from it (a zero RVA encodes a NULL pointer). Note
5874 // the use of PTR_HOST_INT_TO_TADDR() rather than dac_cast<TADDR>, see previous comment on
5875 // PTR_HOST_INT_TO_TADDR for an explanation.
5876 return iValue ? PTR_HOST_INT_TO_TADDR(this) + iValue : 0;
5877}
5878
5879PTR_TADDR LookupMapBase::FindHotItemValuePtr(DWORD rid)
5880{
5881 LIMITED_METHOD_DAC_CONTRACT;
5882
5883 if (dwNumHotItems < 5)
5884 {
5885 // do simple linear search if there are only a few hot items
5886 for (DWORD i = 0; i < dwNumHotItems; i++)
5887 {
5888 if (hotItemList[i].rid == rid)
5889 return dac_cast<PTR_TADDR>(
5890 dac_cast<TADDR>(hotItemList) + i * sizeof(HotItem) + offsetof(HotItem, value));
5891 }
5892 }
5893 else
5894 {
5895 // otherwise do binary search
5896 if (hotItemList[0].rid <= rid && rid <= hotItemList[dwNumHotItems-1].rid)
5897 {
5898 DWORD l = 0;
5899 DWORD r = dwNumHotItems;
5900 while (l + 1 < r)
5901 {
5902 // loop invariant:
5903 _ASSERTE(hotItemList[l].rid <= rid && (r >= dwNumHotItems || rid < hotItemList[r].rid));
5904
5905 DWORD m = (l + r)/2;
5906 // loop condition implies l < m < r, hence interval shrinks every iteration, hence loop terminates
5907 _ASSERTE(l < m && m < r);
5908 if (rid < hotItemList[m].rid)
5909 r = m;
5910 else
5911 l = m;
5912 }
5913 // now we know l + 1 == r && hotItemList[l].rid <= rid < hotItemList[r].rid
5914 // loop invariant:
5915 _ASSERTE(hotItemList[l].rid <= rid && (r >= dwNumHotItems || rid < hotItemList[r].rid));
5916 if (hotItemList[l].rid == rid)
5917 return dac_cast<PTR_TADDR>(
5918 dac_cast<TADDR>(hotItemList) + l * sizeof(HotItem) + offsetof(HotItem, value));
5919 }
5920 }
5921 return NULL;
5922}
5923
5924#ifdef _DEBUG
5925void LookupMapBase::CheckConsistentHotItemList()
5926{
5927 LIMITED_METHOD_DAC_CONTRACT;
5928
5929 for (DWORD i = 0; i < dwNumHotItems; i++)
5930 {
5931 DWORD rid = hotItemList[i].rid;
5932
5933 PTR_TADDR pHotValue = dac_cast<PTR_TADDR>(
5934 dac_cast<TADDR>(hotItemList) + i * sizeof(HotItem) + offsetof(HotItem, value));
5935 TADDR hotValue = RelativePointer<TADDR>::GetValueMaybeNullAtPtr(dac_cast<TADDR>(pHotValue));
5936
5937 TADDR value;
5938 if (MapIsCompressed())
5939 {
5940 value = GetValueFromCompressedMap(rid);
5941 }
5942 else
5943 {
5944 PTR_TADDR pValue = GetIndexPtr(rid);
5945 value = RelativePointer<TADDR>::GetValueMaybeNullAtPtr(dac_cast<TADDR>(pValue));
5946 }
5947
5948 _ASSERTE(hotValue == value || value == NULL);
5949 }
5950}
5951#endif // _DEBUG
5952
5953#endif // FEATURE_PREJIT
5954
5955// Get number of RIDs that this table can store
5956DWORD LookupMapBase::GetSize()
5957{
5958 CONTRACTL
5959 {
5960 INSTANCE_CHECK;
5961 NOTHROW;
5962 GC_NOTRIGGER;
5963 MODE_ANY;
5964 SUPPORTS_DAC;
5965 }
5966 CONTRACTL_END;
5967
5968 LookupMapBase * pMap = this;
5969 DWORD dwSize = 0;
5970 do
5971 {
5972 dwSize += pMap->dwCount;
5973 pMap = pMap->pNext;
5974 } while (pMap != NULL);
5975
5976 return dwSize;
5977}
5978
5979#ifndef DACCESS_COMPILE
5980
5981#ifdef _DEBUG
5982void LookupMapBase::DebugGetRidMapOccupancy(DWORD *pdwOccupied, DWORD *pdwSize)
5983{
5984 LIMITED_METHOD_CONTRACT;
5985
5986 *pdwOccupied = 0;
5987 *pdwSize = 0;
5988
5989 LookupMapBase * pMap = this;
5990
5991 // Go through each linked block
5992 for (; pMap != NULL; pMap = pMap->pNext)
5993 {
5994 DWORD dwIterCount = pMap->dwCount;
5995
5996 for (DWORD i = 0; i < dwIterCount; i++)
5997 {
5998#ifdef FEATURE_PREJIT
5999 if (pMap->MapIsCompressed())
6000 {
6001 if (pMap->GetValueFromCompressedMap(i))
6002 (*pdwOccupied)++;
6003 }
6004 else
6005#endif // FEATURE_PREJIT
6006 if (pMap->pTable[i] != NULL)
6007 (*pdwOccupied)++;
6008 }
6009
6010 (*pdwSize) += dwIterCount;
6011 }
6012}
6013
6014void Module::DebugLogRidMapOccupancy()
6015{
6016 WRAPPER_NO_CONTRACT;
6017
6018#define COMPUTE_RID_MAP_OCCUPANCY(var_suffix, map) \
6019 DWORD dwOccupied##var_suffix, dwSize##var_suffix, dwPercent##var_suffix; \
6020 map.DebugGetRidMapOccupancy(&dwOccupied##var_suffix, &dwSize##var_suffix); \
6021 dwPercent##var_suffix = dwOccupied##var_suffix ? ((dwOccupied##var_suffix * 100) / dwSize##var_suffix) : 0;
6022
6023 COMPUTE_RID_MAP_OCCUPANCY(1, m_TypeDefToMethodTableMap);
6024 COMPUTE_RID_MAP_OCCUPANCY(2, m_TypeRefToMethodTableMap);
6025 COMPUTE_RID_MAP_OCCUPANCY(3, m_MethodDefToDescMap);
6026 COMPUTE_RID_MAP_OCCUPANCY(4, m_FieldDefToDescMap);
6027 COMPUTE_RID_MAP_OCCUPANCY(5, m_GenericParamToDescMap);
6028 COMPUTE_RID_MAP_OCCUPANCY(6, m_GenericTypeDefToCanonMethodTableMap);
6029 COMPUTE_RID_MAP_OCCUPANCY(7, m_FileReferencesMap);
6030 COMPUTE_RID_MAP_OCCUPANCY(8, m_ManifestModuleReferencesMap);
6031 COMPUTE_RID_MAP_OCCUPANCY(9, m_MethodDefToPropertyInfoMap);
6032
6033 LOG((
6034 LF_EEMEM,
6035 INFO3,
6036 " Map occupancy:\n"
6037 " TypeDefToMethodTable map: %4d/%4d (%2d %%)\n"
6038 " TypeRefToMethodTable map: %4d/%4d (%2d %%)\n"
6039 " MethodDefToDesc map: %4d/%4d (%2d %%)\n"
6040 " FieldDefToDesc map: %4d/%4d (%2d %%)\n"
6041 " GenericParamToDesc map: %4d/%4d (%2d %%)\n"
6042 " GenericTypeDefToCanonMethodTable map: %4d/%4d (%2d %%)\n"
6043 " FileReferences map: %4d/%4d (%2d %%)\n"
6044 " AssemblyReferences map: %4d/%4d (%2d %%)\n"
6045 " MethodDefToPropInfo map: %4d/%4d (%2d %%)\n"
6046 ,
6047 dwOccupied1, dwSize1, dwPercent1,
6048 dwOccupied2, dwSize2, dwPercent2,
6049 dwOccupied3, dwSize3, dwPercent3,
6050 dwOccupied4, dwSize4, dwPercent4,
6051 dwOccupied5, dwSize5, dwPercent5,
6052 dwOccupied6, dwSize6, dwPercent6,
6053 dwOccupied7, dwSize7, dwPercent7,
6054 dwOccupied8, dwSize8, dwPercent8,
6055 dwOccupied9, dwSize9, dwPercent9
6056 ));
6057
6058#undef COMPUTE_RID_MAP_OCCUPANCY
6059}
6060#endif // _DEBUG
6061
6062//
6063// FindMethod finds a MethodDesc for a global function methoddef or ref
6064//
6065
6066MethodDesc *Module::FindMethodThrowing(mdToken pMethod)
6067{
6068 CONTRACT (MethodDesc *)
6069 {
6070 INSTANCE_CHECK;
6071 THROWS;
6072 GC_TRIGGERS;
6073 MODE_ANY;
6074 POSTCONDITION(CheckPointer(RETVAL));
6075 }
6076 CONTRACT_END
6077
6078 SigTypeContext typeContext; /* empty type context: methods will not be generic */
6079 RETURN MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(this, pMethod,
6080 &typeContext,
6081 TRUE, /* strictMetadataChecks */
6082 FALSE /* dont get code shared between generic instantiations */);
6083}
6084
6085//
6086// FindMethod finds a MethodDesc for a global function methoddef or ref
6087//
6088
6089MethodDesc *Module::FindMethod(mdToken pMethod)
6090{
6091 CONTRACT (MethodDesc *) {
6092 INSTANCE_CHECK;
6093 NOTHROW;
6094 GC_TRIGGERS;
6095 MODE_ANY;
6096 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6097 } CONTRACT_END;
6098
6099 MethodDesc *pMDRet = NULL;
6100
6101 EX_TRY
6102 {
6103 pMDRet = FindMethodThrowing(pMethod);
6104 }
6105 EX_CATCH
6106 {
6107#ifdef _DEBUG
6108 CONTRACT_VIOLATION(ThrowsViolation);
6109 char szMethodName [MAX_CLASSNAME_LENGTH];
6110 CEEInfo::findNameOfToken(this, pMethod, szMethodName, COUNTOF (szMethodName));
6111 // This used to be IJW, but changed to LW_INTEROP to reclaim a bit in our log facilities
6112 LOG((LF_INTEROP, LL_INFO10, "Failed to find Method: %s for Vtable Fixup\n", szMethodName));
6113#endif // _DEBUG
6114 }
6115 EX_END_CATCH(SwallowAllExceptions)
6116
6117 RETURN pMDRet;
6118}
6119
6120//
6121// PopulatePropertyInfoMap precomputes property information during NGen
6122// that is expensive to look up from metadata at runtime.
6123//
6124
6125void Module::PopulatePropertyInfoMap()
6126{
6127 CONTRACTL
6128 {
6129 INSTANCE_CHECK;
6130 THROWS;
6131 GC_NOTRIGGER;
6132 MODE_ANY;
6133 PRECONDITION(IsCompilationProcess());
6134 }
6135 CONTRACTL_END;
6136
6137 IMDInternalImport* mdImport = GetMDImport();
6138 HENUMInternalHolder hEnum(mdImport);
6139 hEnum.EnumAllInit(mdtMethodDef);
6140
6141 mdMethodDef md;
6142 while (hEnum.EnumNext(&md))
6143 {
6144 mdProperty prop = 0;
6145 ULONG semantic = 0;
6146 if (mdImport->GetPropertyInfoForMethodDef(md, &prop, NULL, &semantic) == S_OK)
6147 {
6148 // Store the Rid in the lower 24 bits and the semantic in the upper 8
6149 _ASSERTE((semantic & 0xFFFFFF00) == 0);
6150 SIZE_T value = RidFromToken(prop) | (semantic << 24);
6151
6152 // We need to make sure a value of zero indicates an empty LookupMap entry
6153 // Fortunately the semantic will prevent value from being zero
6154 _ASSERTE(value != 0);
6155
6156 m_MethodDefToPropertyInfoMap.AddElement(this, RidFromToken(md), value);
6157 }
6158 }
6159 FastInterlockOr(&m_dwPersistedFlags, COMPUTED_METHODDEF_TO_PROPERTYINFO_MAP);
6160}
6161
6162//
6163// GetPropertyInfoForMethodDef wraps the metadata function of the same name,
6164// first trying to use the information stored in m_MethodDefToPropertyInfoMap.
6165//
6166
6167HRESULT Module::GetPropertyInfoForMethodDef(mdMethodDef md, mdProperty *ppd, LPCSTR *pName, ULONG *pSemantic)
6168{
6169 CONTRACTL
6170 {
6171 INSTANCE_CHECK;
6172 NOTHROW;
6173 GC_NOTRIGGER;
6174 MODE_ANY;
6175 SO_TOLERANT;
6176 }
6177 CONTRACTL_END;
6178
6179 HRESULT hr;
6180
6181 if ((m_dwPersistedFlags & COMPUTED_METHODDEF_TO_PROPERTYINFO_MAP) != 0)
6182 {
6183 SIZE_T value = m_MethodDefToPropertyInfoMap.GetElement(RidFromToken(md));
6184 if (value == 0)
6185 {
6186 _ASSERTE(GetMDImport()->GetPropertyInfoForMethodDef(md, ppd, pName, pSemantic) == S_FALSE);
6187 return S_FALSE;
6188 }
6189 else
6190 {
6191 // Decode the value into semantic and mdProperty as described in PopulatePropertyInfoMap
6192 ULONG semantic = (value & 0xFF000000) >> 24;
6193 mdProperty prop = TokenFromRid(value & 0x00FFFFFF, mdtProperty);
6194
6195#ifdef _DEBUG
6196 mdProperty dbgPd;
6197 LPCSTR dbgName;
6198 ULONG dbgSemantic;
6199 _ASSERTE(GetMDImport()->GetPropertyInfoForMethodDef(md, &dbgPd, &dbgName, &dbgSemantic) == S_OK);
6200#endif
6201
6202 if (ppd != NULL)
6203 {
6204 *ppd = prop;
6205 _ASSERTE(*ppd == dbgPd);
6206 }
6207
6208 if (pSemantic != NULL)
6209 {
6210 *pSemantic = semantic;
6211 _ASSERTE(*pSemantic == dbgSemantic);
6212 }
6213
6214 if (pName != NULL)
6215 {
6216 IfFailRet(GetMDImport()->GetPropertyProps(prop, pName, NULL, NULL, NULL));
6217
6218#ifdef _DEBUG
6219 HRESULT hr = GetMDImport()->GetPropertyProps(prop, pName, NULL, NULL, NULL);
6220 _ASSERTE(hr == S_OK);
6221 _ASSERTE(strcmp(*pName, dbgName) == 0);
6222#endif
6223 }
6224
6225 return S_OK;
6226 }
6227 }
6228
6229 return GetMDImport()->GetPropertyInfoForMethodDef(md, ppd, pName, pSemantic);
6230}
6231
6232#ifdef FEATURE_NATIVE_IMAGE_GENERATION
6233// Fill the m_propertyNameSet hash filter with data that represents every
6234// property and its name in the module.
6235void Module::PrecomputeMatchingProperties(DataImage *image)
6236{
6237 CONTRACTL
6238 {
6239 STANDARD_VM_CHECK;
6240 PRECONDITION(IsCompilationProcess());
6241 }
6242 CONTRACTL_END;
6243
6244 IMDInternalImport* mdImport = GetMDImport();
6245
6246 m_nPropertyNameSet = mdImport->GetCountWithTokenKind(mdtProperty);
6247
6248 if (m_nPropertyNameSet == 0)
6249 {
6250 return;
6251 }
6252
6253 m_propertyNameSet = new (image->GetHeap()) BYTE[m_nPropertyNameSet];
6254
6255 DWORD nEnumeratedProperties = 0;
6256
6257 HENUMInternalHolder hEnumTypes(mdImport);
6258 hEnumTypes.EnumAllInit(mdtTypeDef);
6259
6260 // Enumerate all properties of all types
6261 mdTypeDef tkType;
6262 while (hEnumTypes.EnumNext(&tkType))
6263 {
6264 HENUMInternalHolder hEnumPropertiesForType(mdImport);
6265 hEnumPropertiesForType.EnumInit(mdtProperty, tkType);
6266
6267 mdProperty tkProperty;
6268 while (hEnumPropertiesForType.EnumNext(&tkProperty))
6269 {
6270 LPCSTR name;
6271 HRESULT hr = GetMDImport()->GetPropertyProps(tkProperty, &name, NULL, NULL, NULL);
6272 IfFailThrow(hr);
6273
6274 ++nEnumeratedProperties;
6275
6276 // Use a case-insensitive hash so that we can use this value for
6277 // both case-sensitive and case-insensitive name lookups
6278 SString ssName(SString::Utf8Literal, name);
6279 ULONG nameHashValue = ssName.HashCaseInsensitive();
6280
6281 // Set one bit in m_propertyNameSet per iteration
6282 // This will allow lookup to ensure that the bit from each iteration is set
6283 // and if any are not set, know that the (tkProperty,name) pair is not valid
6284 for (DWORD i = 0; i < NUM_PROPERTY_SET_HASHES; ++i)
6285 {
6286 DWORD currentHashValue = HashThreeToOne(tkProperty, nameHashValue, i);
6287 DWORD bitPos = currentHashValue % (m_nPropertyNameSet * 8);
6288 m_propertyNameSet[bitPos / 8] |= (1 << bitPos % 8);
6289 }
6290 }
6291 }
6292
6293 _ASSERTE(nEnumeratedProperties == m_nPropertyNameSet);
6294}
6295#endif // FEATURE_NATIVE_IMAGE_GENERATION
6296
6297// Check whether the module might possibly have a property with a name with
6298// the passed hash value without accessing the property's name. This is done
6299// by consulting a hash filter populated at NGen time.
6300BOOL Module::MightContainMatchingProperty(mdProperty tkProperty, ULONG nameHash)
6301{
6302 CONTRACTL
6303 {
6304 NOTHROW;
6305 GC_NOTRIGGER;
6306 SO_TOLERANT;
6307 MODE_ANY;
6308 }
6309 CONTRACTL_END;
6310
6311 if (m_propertyNameSet)
6312 {
6313 _ASSERTE(HasNativeImage());
6314
6315 // if this property was added after the name set was computed, conservatively
6316 // assume we might have it. This is known to occur in scenarios where a profiler
6317 // injects additional metadata at module load time for an NGEN'ed module. In the
6318 // future other dynamic additions to the module might produce a similar result.
6319 if (RidFromToken(tkProperty) > m_nPropertyNameSet)
6320 return TRUE;
6321
6322 // Check one bit per iteration, failing if any are not set
6323 // We know that all will have been set for any valid (tkProperty,name) pair
6324 for (DWORD i = 0; i < NUM_PROPERTY_SET_HASHES; ++i)
6325 {
6326 DWORD currentHashValue = HashThreeToOne(tkProperty, nameHash, i);
6327 DWORD bitPos = currentHashValue % (m_nPropertyNameSet * 8);
6328 if ((m_propertyNameSet[bitPos / 8] & (1 << bitPos % 8)) == 0)
6329 {
6330 return FALSE;
6331 }
6332 }
6333 }
6334
6335 return TRUE;
6336}
6337
6338#ifdef FEATURE_NATIVE_IMAGE_GENERATION
6339// Ensure that all elements and flags that we want persisted in the LookupMaps are present
6340void Module::FinalizeLookupMapsPreSave(DataImage *image)
6341{
6342 CONTRACTL
6343 {
6344 STANDARD_VM_CHECK;
6345 PRECONDITION(IsCompilationProcess());
6346 }
6347 CONTRACTL_END;
6348
6349 // For each typedef, if it does not need a restore, add the ZAPPED_TYPE_NEEDS_NO_RESTORE flag
6350 {
6351 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
6352
6353 while (typeDefIter.Next())
6354 {
6355 MethodTable * pMT = typeDefIter.GetElement();
6356
6357 if (pMT != NULL && !pMT->NeedsRestore(image))
6358 {
6359 m_TypeDefToMethodTableMap.AddFlag(RidFromToken(pMT->GetCl()), ZAPPED_TYPE_NEEDS_NO_RESTORE);
6360 }
6361 }
6362 }
6363
6364 // 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
6365 {
6366 LookupMap<PTR_MethodTable>::Iterator genericTypeDefIter(&m_GenericTypeDefToCanonMethodTableMap);
6367
6368 while (genericTypeDefIter.Next())
6369 {
6370 MethodTable * pMT = genericTypeDefIter.GetElement();
6371
6372 if (pMT != NULL && !pMT->NeedsRestore(image))
6373 {
6374 m_GenericTypeDefToCanonMethodTableMap.AddFlag(RidFromToken(pMT->GetCl()), ZAPPED_GENERIC_TYPE_NEEDS_NO_RESTORE);
6375 }
6376 }
6377 }
6378
6379}
6380#endif // FEATURE_NATIVE_IMAGE_GENERATION
6381
6382// Return true if this module has any live (jitted) JMC functions.
6383// If a module has no jitted JMC functions, then it's as if it's a
6384// non-user module.
6385bool Module::HasAnyJMCFunctions()
6386{
6387 LIMITED_METHOD_CONTRACT;
6388
6389 // If we have any live JMC funcs in us, then we're a JMC module.
6390 // We count JMC functions when we either explicitly toggle their status
6391 // or when we get the code:DebuggerMethodInfo for them (which happens in a jit-complete).
6392 // Since we don't get the jit-completes for ngen modules, we also check the module's
6393 // "default" status. This means we may err on the side of believing we have
6394 // JMC methods.
6395 return ((m_debuggerSpecificData.m_cTotalJMCFuncs > 0) || m_debuggerSpecificData.m_fDefaultJMCStatus);
6396}
6397
6398// Alter our module's count of JMC functions.
6399// Since these may be called on multiple threads (say 2 threads are jitting
6400// methods within a module), make it thread safe.
6401void Module::IncJMCFuncCount()
6402{
6403 LIMITED_METHOD_CONTRACT;
6404
6405 InterlockedIncrement(&m_debuggerSpecificData.m_cTotalJMCFuncs);
6406}
6407
6408void Module::DecJMCFuncCount()
6409{
6410 LIMITED_METHOD_CONTRACT;
6411
6412 InterlockedDecrement(&m_debuggerSpecificData.m_cTotalJMCFuncs);
6413}
6414
6415// code:DebuggerMethodInfo are lazily created. Let them lookup what the default is.
6416bool Module::GetJMCStatus()
6417{
6418 LIMITED_METHOD_CONTRACT;
6419
6420 return m_debuggerSpecificData.m_fDefaultJMCStatus;
6421}
6422
6423// Set the default JMC status of this module.
6424void Module::SetJMCStatus(bool fStatus)
6425{
6426 LIMITED_METHOD_CONTRACT;
6427
6428 m_debuggerSpecificData.m_fDefaultJMCStatus = fStatus;
6429}
6430
6431// Update the dynamic metadata if needed. Nop for non-dynamic modules
6432void Module::UpdateDynamicMetadataIfNeeded()
6433{
6434 CONTRACTL
6435 {
6436 NOTHROW;
6437 GC_TRIGGERS;
6438 }
6439 CONTRACTL_END;
6440
6441 // Only need to serializing metadata for dynamic modules. For non-dynamic modules, metadata is already available.
6442 if (!IsReflection())
6443 {
6444 return;
6445 }
6446
6447 // Since serializing metadata to an auxillary buffer is only needed by the debugger,
6448 // we should only be doing this for modules that the debugger can see.
6449 if (!IsVisibleToDebugger())
6450 {
6451 return;
6452 }
6453
6454
6455 HRESULT hr = S_OK;
6456 EX_TRY
6457 {
6458 GetReflectionModule()->CaptureModuleMetaDataToMemory();
6459 }
6460 EX_CATCH_HRESULT(hr);
6461
6462 // This Metadata buffer is only used for the debugger, so it's a non-fatal exception for regular CLR execution.
6463 // Just swallow it and keep going. However, with the exception of out-of-memory, we do expect it to
6464 // succeed, so assert on failures.
6465 if (hr != E_OUTOFMEMORY)
6466 {
6467 SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
6468 }
6469
6470}
6471
6472#ifdef DEBUGGING_SUPPORTED
6473
6474
6475#endif // DEBUGGING_SUPPORTED
6476
6477BOOL Module::NotifyDebuggerLoad(AppDomain *pDomain, DomainFile * pDomainFile, int flags, BOOL attaching)
6478{
6479 WRAPPER_NO_CONTRACT;
6480
6481 // We don't notify the debugger about modules that don't contain any code.
6482 if (!IsVisibleToDebugger())
6483 return FALSE;
6484
6485 // Always capture metadata, even if no debugger is attached. If a debugger later attaches, it will use
6486 // this data.
6487 {
6488 Module * pModule = pDomainFile->GetModule();
6489 pModule->UpdateDynamicMetadataIfNeeded();
6490 }
6491
6492
6493 //
6494 // Remaining work is only needed if a debugger is attached
6495 //
6496 if (!attaching && !pDomain->IsDebuggerAttached())
6497 return FALSE;
6498
6499
6500 BOOL result = FALSE;
6501
6502 if (flags & ATTACH_MODULE_LOAD)
6503 {
6504 g_pDebugInterface->LoadModule(this,
6505 m_file->GetPath(),
6506 m_file->GetPath().GetCount(),
6507 GetAssembly(),
6508 pDomain,
6509 pDomainFile,
6510 attaching);
6511
6512 result = TRUE;
6513 }
6514
6515 if (flags & ATTACH_CLASS_LOAD)
6516 {
6517 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
6518 while (typeDefIter.Next())
6519 {
6520 MethodTable * pMT = typeDefIter.GetElement();
6521
6522 if (pMT != NULL && pMT->IsRestored())
6523 {
6524 result = TypeHandle(pMT).NotifyDebuggerLoad(pDomain, attaching) || result;
6525 }
6526 }
6527 }
6528
6529 return result;
6530}
6531
6532void Module::NotifyDebuggerUnload(AppDomain *pDomain)
6533{
6534 LIMITED_METHOD_CONTRACT;
6535
6536 if (!pDomain->IsDebuggerAttached())
6537 return;
6538
6539 // We don't notify the debugger about modules that don't contain any code.
6540 if (!IsVisibleToDebugger())
6541 return;
6542
6543 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
6544 while (typeDefIter.Next())
6545 {
6546 MethodTable * pMT = typeDefIter.GetElement();
6547
6548 if (pMT != NULL && pMT->IsRestored())
6549 {
6550 TypeHandle(pMT).NotifyDebuggerUnload(pDomain);
6551 }
6552 }
6553
6554 g_pDebugInterface->UnloadModule(this, pDomain);
6555}
6556
6557#if !defined(CROSSGEN_COMPILE)
6558//=================================================================================
6559mdToken GetTokenForVTableEntry(HINSTANCE hInst, BYTE **ppVTEntry)
6560{
6561 CONTRACTL{
6562 NOTHROW;
6563 } CONTRACTL_END;
6564
6565 mdToken tok =(mdToken)(UINT_PTR)*ppVTEntry;
6566 _ASSERTE(TypeFromToken(tok) == mdtMethodDef || TypeFromToken(tok) == mdtMemberRef);
6567 return tok;
6568}
6569
6570//=================================================================================
6571void SetTargetForVTableEntry(HINSTANCE hInst, BYTE **ppVTEntry, BYTE *pTarget)
6572{
6573 CONTRACTL{
6574 THROWS;
6575 } CONTRACTL_END;
6576
6577 DWORD oldProtect;
6578 if (!ClrVirtualProtect(ppVTEntry, sizeof(BYTE*), PAGE_READWRITE, &oldProtect))
6579 {
6580
6581 // This is very bad. We are not going to be able to update header.
6582 _ASSERTE(!"SetTargetForVTableEntry(): VirtualProtect() changing IJW thunk vtable to R/W failed.\n");
6583 ThrowLastError();
6584 }
6585
6586 *ppVTEntry = pTarget;
6587
6588 DWORD ignore;
6589 if (!ClrVirtualProtect(ppVTEntry, sizeof(BYTE*), oldProtect, &ignore))
6590 {
6591 // This is not so bad, we're already done the update, we just didn't return the thunk table to read only
6592 _ASSERTE(!"SetTargetForVTableEntry(): VirtualProtect() changing IJW thunk vtable back to RO failed.\n");
6593 }
6594}
6595
6596//=================================================================================
6597BYTE * GetTargetForVTableEntry(HINSTANCE hInst, BYTE **ppVTEntry)
6598{
6599 CONTRACTL{
6600 NOTHROW;
6601 } CONTRACTL_END;
6602
6603 return *ppVTEntry;
6604}
6605
6606//======================================================================================
6607// Fixup vtables stored in the header to contain pointers to method desc
6608// prestubs rather than metadata method tokens.
6609void Module::FixupVTables()
6610{
6611 CONTRACTL{
6612 INSTANCE_CHECK;
6613 STANDARD_VM_CHECK;
6614 } CONTRACTL_END;
6615
6616
6617 // If we've already fixed up, or this is not an IJW module, just return.
6618 // NOTE: This relies on ILOnly files not having fixups. If this changes,
6619 // we need to change this conditional.
6620 if (IsIJWFixedUp() || m_file->IsILOnly()) {
6621 return;
6622 }
6623
6624 HINSTANCE hInstThis = GetFile()->GetIJWBase();
6625
6626 // <REVISIT_TODO>@todo: workaround!</REVISIT_TODO>
6627 // If we are compiling in-process, we don't want to fixup the vtables - as it
6628 // will have side effects on the other copy of the module!
6629 if (SystemDomain::GetCurrentDomain()->IsCompilationDomain()) {
6630 return;
6631 }
6632
6633#ifdef FEATURE_PREJIT
6634 // We delayed filling in this value until the LoadLibrary occurred
6635 if (HasTls() && HasNativeImage()) {
6636 CORCOMPILE_EE_INFO_TABLE *pEEInfo = GetNativeImage()->GetNativeEEInfoTable();
6637 pEEInfo->rvaStaticTlsIndex = GetTlsIndex();
6638 }
6639#endif
6640 // Get vtable fixup data
6641 COUNT_T cFixupRecords;
6642 IMAGE_COR_VTABLEFIXUP *pFixupTable = m_file->GetVTableFixups(&cFixupRecords);
6643
6644 // No records then return
6645 if (cFixupRecords == 0) {
6646 return;
6647 }
6648
6649 // Now, we need to take a lock to serialize fixup.
6650 PEImage::IJWFixupData *pData = PEImage::GetIJWData(m_file->GetIJWBase());
6651
6652 // If it's already been fixed (in some other appdomain), record the fact and return
6653 if (pData->IsFixedUp()) {
6654 SetIsIJWFixedUp();
6655 return;
6656 }
6657
6658 //////////////////////////////////////////////////////
6659 //
6660 // This is done in three stages:
6661 // 1. We enumerate the types we'll need to load
6662 // 2. We load the types
6663 // 3. We create and install the thunks
6664 //
6665
6666 COUNT_T cVtableThunks = 0;
6667 struct MethodLoadData
6668 {
6669 mdToken token;
6670 MethodDesc *pMD;
6671 };
6672 MethodLoadData *rgMethodsToLoad = NULL;
6673 COUNT_T cMethodsToLoad = 0;
6674
6675 //
6676 // Stage 1
6677 //
6678
6679 // Each fixup entry describes a vtable, so iterate the vtables and sum their counts
6680 {
6681 DWORD iFixup;
6682 for (iFixup = 0; iFixup < cFixupRecords; iFixup++)
6683 cVtableThunks += pFixupTable[iFixup].Count;
6684 }
6685
6686 Thread *pThread = GetThread();
6687 StackingAllocator *pAlloc = &pThread->m_MarshalAlloc;
6688 CheckPointHolder cph(pAlloc->GetCheckpoint());
6689
6690 // Allocate the working array of tokens.
6691 cMethodsToLoad = cVtableThunks;
6692
6693 rgMethodsToLoad = new (pAlloc) MethodLoadData[cMethodsToLoad];
6694 memset(rgMethodsToLoad, 0, cMethodsToLoad * sizeof(MethodLoadData));
6695
6696 // Now take the IJW module lock and get all the tokens
6697 {
6698 // Take the lock
6699 CrstHolder lockHolder(pData->GetLock());
6700
6701 // If someone has beaten us, just return
6702 if (pData->IsFixedUp())
6703 {
6704 SetIsIJWFixedUp();
6705 return;
6706 }
6707
6708 COUNT_T iCurMethod = 0;
6709
6710 if (cFixupRecords != 0)
6711 {
6712 for (COUNT_T iFixup = 0; iFixup < cFixupRecords; iFixup++)
6713 {
6714 // Vtables can be 32 or 64 bit.
6715 if ((pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED)) ||
6716 (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED | COR_VTABLE_FROM_UNMANAGED)) ||
6717 (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED | COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN)))
6718 {
6719 const BYTE** pPointers = (const BYTE **)m_file->GetVTable(pFixupTable[iFixup].RVA);
6720 for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++)
6721 {
6722 if (pData->IsMethodFixedUp(iFixup, iMethod))
6723 continue;
6724 mdToken mdTok = GetTokenForVTableEntry(hInstThis, (BYTE **)(pPointers + iMethod));
6725 CONSISTENCY_CHECK(mdTok != mdTokenNil);
6726 rgMethodsToLoad[iCurMethod++].token = mdTok;
6727 }
6728 }
6729 }
6730 }
6731
6732 }
6733
6734 //
6735 // Stage 2 - Load the types
6736 //
6737
6738 {
6739 for (COUNT_T iCurMethod = 0; iCurMethod < cMethodsToLoad; iCurMethod++)
6740 {
6741 mdToken curTok = rgMethodsToLoad[iCurMethod].token;
6742 if (!GetMDImport()->IsValidToken(curTok))
6743 {
6744 _ASSERTE(!"Invalid token in v-table fix-up table");
6745 ThrowHR(COR_E_BADIMAGEFORMAT);
6746 }
6747
6748
6749 // Find the method desc
6750 MethodDesc *pMD;
6751
6752 {
6753 CONTRACT_VIOLATION(LoadsTypeViolation);
6754 pMD = FindMethodThrowing(curTok);
6755 }
6756
6757 CONSISTENCY_CHECK(CheckPointer(pMD));
6758
6759 rgMethodsToLoad[iCurMethod].pMD = pMD;
6760 }
6761 }
6762
6763 //
6764 // Stage 3 - Create the thunk data
6765 //
6766 {
6767 // Take the lock
6768 CrstHolder lockHolder(pData->GetLock());
6769
6770 // If someone has beaten us, just return
6771 if (pData->IsFixedUp())
6772 {
6773 SetIsIJWFixedUp();
6774 return;
6775 }
6776
6777 // This phase assumes there is only one AppDomain and that thunks
6778 // can all safely point directly to the method in the current AppDomain
6779
6780 AppDomain *pAppDomain = GetAppDomain();
6781
6782 // Used to index into rgMethodsToLoad
6783 COUNT_T iCurMethod = 0;
6784
6785
6786 // Each fixup entry describes a vtable (each slot contains a metadata token
6787 // at this stage).
6788 DWORD iFixup;
6789 for (iFixup = 0; iFixup < cFixupRecords; iFixup++)
6790 cVtableThunks += pFixupTable[iFixup].Count;
6791
6792 DWORD dwIndex = 0;
6793 DWORD dwThunkIndex = 0;
6794
6795 // Now to fill in the thunk table.
6796 for (iFixup = 0; iFixup < cFixupRecords; iFixup++)
6797 {
6798 // Tables may contain zero fixups, in which case the RVA is null, which triggers an assert
6799 if (pFixupTable[iFixup].Count == 0)
6800 continue;
6801
6802 const BYTE** pPointers = (const BYTE **)
6803 m_file->GetVTable(pFixupTable[iFixup].RVA);
6804
6805 // Vtables can be 32 or 64 bit.
6806 if (pFixupTable[iFixup].Type == COR_VTABLE_PTRSIZED)
6807 {
6808 for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++)
6809 {
6810 if (pData->IsMethodFixedUp(iFixup, iMethod))
6811 continue;
6812
6813 mdToken mdTok = rgMethodsToLoad[iCurMethod].token;
6814 MethodDesc *pMD = rgMethodsToLoad[iCurMethod].pMD;
6815 iCurMethod++;
6816
6817#ifdef _DEBUG
6818 if (pMD->IsNDirect())
6819 {
6820 LOG((LF_INTEROP, LL_INFO10, "[0x%lx] <-- PINV thunk for \"%s\" (target = 0x%lx)\n",
6821 (size_t)&(pPointers[iMethod]), pMD->m_pszDebugMethodName,
6822 (size_t)(((NDirectMethodDesc*)pMD)->GetNDirectTarget())));
6823 }
6824#endif // _DEBUG
6825
6826 CONSISTENCY_CHECK(dwThunkIndex < cVtableThunks);
6827
6828 // Point the local vtable slot to the thunk we created
6829 SetTargetForVTableEntry(hInstThis, (BYTE **)&pPointers[iMethod], (BYTE *)pMD->GetMultiCallableAddrOfCode());
6830
6831 pData->MarkMethodFixedUp(iFixup, iMethod);
6832
6833 dwThunkIndex++;
6834 }
6835
6836 }
6837 else if (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED | COR_VTABLE_FROM_UNMANAGED) ||
6838 (pFixupTable[iFixup].Type == (COR_VTABLE_PTRSIZED | COR_VTABLE_FROM_UNMANAGED_RETAIN_APPDOMAIN)))
6839 {
6840 for (int iMethod = 0; iMethod < pFixupTable[iFixup].Count; iMethod++)
6841 {
6842 if (pData->IsMethodFixedUp(iFixup, iMethod))
6843 continue;
6844
6845 mdToken mdTok = rgMethodsToLoad[iCurMethod].token;
6846 MethodDesc *pMD = rgMethodsToLoad[iCurMethod].pMD;
6847 iCurMethod++;
6848 LOG((LF_INTEROP, LL_INFO10, "[0x%p] <-- VTable thunk for \"%s\" (pMD = 0x%p)\n",
6849 (UINT_PTR)&(pPointers[iMethod]), pMD->m_pszDebugMethodName, pMD));
6850
6851 UMEntryThunk *pUMEntryThunk = (UMEntryThunk*)(void*)(GetDllThunkHeap()->AllocAlignedMem(sizeof(UMEntryThunk), CODE_SIZE_ALIGN)); // UMEntryThunk contains code
6852 FillMemory(pUMEntryThunk, sizeof(*pUMEntryThunk), 0);
6853
6854 UMThunkMarshInfo *pUMThunkMarshInfo = (UMThunkMarshInfo*)(void*)(GetThunkHeap()->AllocAlignedMem(sizeof(UMThunkMarshInfo), CODE_SIZE_ALIGN));
6855 FillMemory(pUMThunkMarshInfo, sizeof(*pUMThunkMarshInfo), 0);
6856
6857 pUMThunkMarshInfo->LoadTimeInit(pMD);
6858 pUMEntryThunk->LoadTimeInit(NULL, NULL, pUMThunkMarshInfo, pMD, pAppDomain->GetId());
6859 SetTargetForVTableEntry(hInstThis, (BYTE **)&pPointers[iMethod], (BYTE *)pUMEntryThunk->GetCode());
6860
6861 pData->MarkMethodFixedUp(iFixup, iMethod);
6862 }
6863 }
6864 else if ((pFixupTable[iFixup].Type & COR_VTABLE_NOT_PTRSIZED) == COR_VTABLE_NOT_PTRSIZED)
6865 {
6866 // fixup type doesn't match the platform
6867 THROW_BAD_FORMAT(BFA_FIXUP_WRONG_PLATFORM, this);
6868 }
6869 else
6870 {
6871 _ASSERTE(!"Unknown vtable fixup type");
6872 }
6873 }
6874
6875 // Indicate that this module has been fixed before releasing the lock
6876 pData->SetIsFixedUp(); // On the data
6877 SetIsIJWFixedUp(); // On the module
6878 } // End of Stage 3
6879}
6880
6881// Self-initializing accessor for m_pThunkHeap
6882LoaderHeap *Module::GetDllThunkHeap()
6883{
6884 CONTRACTL
6885 {
6886 THROWS;
6887 GC_TRIGGERS;
6888 MODE_ANY;
6889 }
6890 CONTRACTL_END;
6891 return PEImage::GetDllThunkHeap(GetFile()->GetIJWBase());
6892
6893}
6894
6895LoaderHeap *Module::GetThunkHeap()
6896{
6897 CONTRACT(LoaderHeap *)
6898 {
6899 INSTANCE_CHECK;
6900 THROWS;
6901 GC_NOTRIGGER;
6902 MODE_ANY;
6903 INJECT_FAULT(COMPlusThrowOM());
6904 POSTCONDITION(CheckPointer(RETVAL));
6905 }
6906 CONTRACT_END
6907
6908 if (!m_pThunkHeap)
6909 {
6910 size_t * pPrivatePCLBytes = NULL;
6911 size_t * pGlobalPCLBytes = NULL;
6912
6913 COUNTER_ONLY(pPrivatePCLBytes = &(GetPerfCounters().m_Loading.cbLoaderHeapSize));
6914
6915 LoaderHeap *pNewHeap = new LoaderHeap(VIRTUAL_ALLOC_RESERVE_GRANULARITY, // DWORD dwReserveBlockSize
6916 0, // DWORD dwCommitBlockSize
6917 pPrivatePCLBytes,
6918 ThunkHeapStubManager::g_pManager->GetRangeList(),
6919 TRUE); // BOOL fMakeExecutable
6920
6921 if (FastInterlockCompareExchangePointer(&m_pThunkHeap, pNewHeap, 0) != 0)
6922 {
6923 delete pNewHeap;
6924 }
6925 }
6926
6927 RETURN m_pThunkHeap;
6928}
6929#endif // !CROSSGEN_COMPILE
6930
6931#ifdef FEATURE_NATIVE_IMAGE_GENERATION
6932
6933// These helpers are used in Module::ExpandAll
6934// to avoid EX_TRY/EX_CATCH in a loop (uses _alloca and guzzles stack)
6935
6936static TypeHandle LoadTypeDefOrRefHelper(DataImage * image, Module * pModule, mdToken tk)
6937{
6938 STANDARD_VM_CONTRACT;
6939
6940 TypeHandle th;
6941
6942 EX_TRY
6943 {
6944 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tk,
6945 ClassLoader::ThrowIfNotFound,
6946 ClassLoader::PermitUninstDefOrRef);
6947 }
6948 EX_CATCH
6949 {
6950 image->GetPreloader()->Error(tk, GET_EXCEPTION());
6951 }
6952 EX_END_CATCH(SwallowAllExceptions)
6953
6954 return th;
6955}
6956
6957static TypeHandle LoadTypeSpecHelper(DataImage * image, Module * pModule, mdToken tk,
6958 PCCOR_SIGNATURE pSig, ULONG cSig)
6959{
6960 STANDARD_VM_CONTRACT;
6961
6962 TypeHandle th;
6963
6964 EX_TRY
6965 {
6966 SigPointer p(pSig, cSig);
6967 SigTypeContext typeContext;
6968 th = p.GetTypeHandleThrowing(pModule, &typeContext);
6969 }
6970 EX_CATCH
6971 {
6972 image->GetPreloader()->Error(tk, GET_EXCEPTION());
6973 }
6974 EX_END_CATCH(SwallowAllExceptions)
6975
6976 return th;
6977}
6978
6979static TypeHandle LoadGenericInstantiationHelper(DataImage * image, Module * pModule, mdToken tk, Instantiation inst)
6980{
6981 STANDARD_VM_CONTRACT;
6982
6983 TypeHandle th;
6984
6985 EX_TRY
6986 {
6987 th = ClassLoader::LoadGenericInstantiationThrowing(pModule, tk, inst);
6988 }
6989 EX_CATCH
6990 {
6991 image->GetPreloader()->Error(tk, GET_EXCEPTION());
6992 }
6993 EX_END_CATCH(SwallowAllExceptions)
6994
6995 return th;
6996}
6997
6998static void GetDescFromMemberRefHelper(DataImage * image, Module * pModule, mdToken tk)
6999{
7000 STANDARD_VM_CONTRACT;
7001
7002 EX_TRY
7003 {
7004 MethodDesc * pMD = NULL;
7005 FieldDesc * pFD = NULL;
7006 TypeHandle th;
7007
7008 // Note: using an empty type context is now OK, because even though the token is a MemberRef
7009 // neither the token nor its parent will directly refer to type variables.
7010 // @TODO GENERICS: want to allow loads of generic methods here but need strict metadata checks on parent
7011 SigTypeContext typeContext;
7012 MemberLoader::GetDescFromMemberRef(pModule, tk, &pMD, &pFD,
7013 &typeContext,
7014 FALSE /* strict metadata checks */, &th);
7015 }
7016 EX_CATCH
7017 {
7018 image->GetPreloader()->Error(tk, GET_EXCEPTION());
7019 }
7020 EX_END_CATCH(SwallowAllExceptions)
7021}
7022
7023void Module::SetProfileData(CorProfileData * profileData)
7024{
7025 LIMITED_METHOD_CONTRACT;
7026 m_pProfileData = profileData;
7027}
7028
7029CorProfileData * Module::GetProfileData()
7030{
7031 LIMITED_METHOD_CONTRACT;
7032 return m_pProfileData;
7033}
7034
7035mdTypeDef Module::LookupIbcTypeToken(Module * pExternalModule, mdToken ibcToken, SString* optionalFullNameOut)
7036{
7037 CONTRACTL
7038 {
7039 THROWS;
7040 GC_TRIGGERS;
7041 MODE_ANY;
7042 }
7043 CONTRACTL_END
7044
7045 _ASSERTE(TypeFromToken(ibcToken) == ibcExternalType);
7046
7047 CorProfileData * profileData = this->GetProfileData();
7048
7049 CORBBTPROF_BLOB_TYPE_DEF_ENTRY * blobTypeDefEntry;
7050 blobTypeDefEntry = profileData->GetBlobExternalTypeDef(ibcToken);
7051
7052 if (blobTypeDefEntry == NULL)
7053 return mdTypeDefNil;
7054
7055 IbcNameHandle ibcName;
7056 ibcName.szName = &blobTypeDefEntry->name[0];
7057 ibcName.tkIbcNameSpace = blobTypeDefEntry->nameSpaceToken;
7058 ibcName.tkIbcNestedClass = blobTypeDefEntry->nestedClassToken;
7059 ibcName.szNamespace = NULL;
7060 ibcName.tkEnclosingClass = mdTypeDefNil;
7061
7062 if (!IsNilToken(blobTypeDefEntry->nameSpaceToken))
7063 {
7064 _ASSERTE(IsNilToken(blobTypeDefEntry->nestedClassToken));
7065
7066 idExternalNamespace nameSpaceToken = blobTypeDefEntry->nameSpaceToken;
7067 _ASSERTE(TypeFromToken(nameSpaceToken) == ibcExternalNamespace);
7068
7069 CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY * blobNamespaceDefEntry;
7070 blobNamespaceDefEntry = profileData->GetBlobExternalNamespaceDef(nameSpaceToken);
7071
7072 if (blobNamespaceDefEntry == NULL)
7073 return mdTypeDefNil;
7074
7075 ibcName.szNamespace = &blobNamespaceDefEntry->name[0];
7076
7077 if (optionalFullNameOut != NULL)
7078 {
7079 optionalFullNameOut->Append(W("["));
7080 optionalFullNameOut->AppendUTF8(pExternalModule->GetSimpleName());
7081 optionalFullNameOut->Append(W("]"));
7082
7083 if ((ibcName.szNamespace != NULL) && ((*ibcName.szNamespace) != W('\0')))
7084 {
7085 optionalFullNameOut->AppendUTF8(ibcName.szNamespace);
7086 optionalFullNameOut->Append(W("."));
7087 }
7088 optionalFullNameOut->AppendUTF8(ibcName.szName);
7089 }
7090 }
7091 else if (!IsNilToken(blobTypeDefEntry->nestedClassToken))
7092 {
7093 idExternalType nestedClassToken = blobTypeDefEntry->nestedClassToken;
7094 _ASSERTE(TypeFromToken(nestedClassToken) == ibcExternalType);
7095
7096 ibcName.tkEnclosingClass = LookupIbcTypeToken(pExternalModule, nestedClassToken, optionalFullNameOut);
7097
7098 if (optionalFullNameOut != NULL)
7099 {
7100 optionalFullNameOut->Append(W("+"));
7101 optionalFullNameOut->AppendUTF8(ibcName.szName);
7102 }
7103
7104 if (IsNilToken(ibcName.tkEnclosingClass))
7105 return mdTypeDefNil;
7106 }
7107
7108 //*****************************************
7109 // look up function for TypeDef
7110 //*****************************************
7111 // STDMETHOD(FindTypeDef)(
7112 // LPCSTR szNamespace, // [IN] Namespace for the TypeDef.
7113 // LPCSTR szName, // [IN] Name of the TypeDef.
7114 // mdToken tkEnclosingClass, // [IN] TypeRef/TypeDef Token for the enclosing class.
7115 // mdTypeDef *ptypedef) PURE; // [IN] return typedef
7116
7117 IMDInternalImport *pInternalImport = pExternalModule->GetMDImport();
7118
7119 mdTypeDef mdResult = mdTypeDefNil;
7120
7121 HRESULT hr = pInternalImport->FindTypeDef(ibcName.szNamespace, ibcName.szName, ibcName.tkEnclosingClass, &mdResult);
7122
7123 if(FAILED(hr))
7124 mdResult = mdTypeDefNil;
7125
7126 return mdResult;
7127}
7128
7129struct IbcCompareContext
7130{
7131 Module * pModule;
7132 TypeHandle enclosingType;
7133 DWORD cMatch; // count of methods that had a matching method name
7134 bool useBestSig; // if true we should use the BestSig when we don't find an exact match
7135 PCCOR_SIGNATURE pvBestSig; // Current Best matching signature
7136 DWORD cbBestSig; //
7137};
7138
7139//---------------------------------------------------------------------------------------
7140//
7141// Compare two signatures from the same scope.
7142//
7143BOOL
7144CompareIbcMethodSigs(
7145 PCCOR_SIGNATURE pvCandidateSig, // Candidate signature
7146 DWORD cbCandidateSig, //
7147 PCCOR_SIGNATURE pvIbcSignature, // The Ibc signature that we want to match
7148 DWORD cbIbcSignature, //
7149 void * pvContext) // void pointer to IbcCompareContext
7150{
7151 CONTRACTL
7152 {
7153 THROWS;
7154 GC_TRIGGERS;
7155 MODE_ANY;
7156 }
7157 CONTRACTL_END
7158
7159 //
7160 // Same pointer return TRUE
7161 //
7162 if (pvCandidateSig == pvIbcSignature)
7163 {
7164 _ASSERTE(cbCandidateSig == cbIbcSignature);
7165 return TRUE;
7166 }
7167
7168 //
7169 // Check for exact match
7170 //
7171 if (cbCandidateSig == cbIbcSignature)
7172 {
7173 if (memcmp(pvCandidateSig, pvIbcSignature, cbIbcSignature) == 0)
7174 {
7175 return TRUE;
7176 }
7177 }
7178
7179 IbcCompareContext * context = (IbcCompareContext *) pvContext;
7180
7181 //
7182 // No exact match, we will return FALSE and keep looking at other matching method names
7183 //
7184 // However since the method name was an exact match we will remember this signature,
7185 // so that if it is the best match we can look it up again and return it's methodDef token
7186 //
7187 if (context->cMatch == 0)
7188 {
7189 context->pvBestSig = pvCandidateSig;
7190 context->cbBestSig = cbCandidateSig;
7191 context->cMatch = 1;
7192 context->useBestSig = true;
7193 }
7194 else
7195 {
7196 context->cMatch++;
7197
7198 SigTypeContext emptyTypeContext;
7199 SigTypeContext ibcTypeContext = SigTypeContext(context->enclosingType);
7200 MetaSig ibcSignature (pvIbcSignature, cbIbcSignature, context->pModule, &ibcTypeContext);
7201
7202 MetaSig candidateSig (pvCandidateSig, cbCandidateSig, context->pModule, &emptyTypeContext);
7203 MetaSig bestSignature(context->pvBestSig, context->cbBestSig, context->pModule, &emptyTypeContext);
7204 //
7205 // Is candidateSig a better match than bestSignature?
7206 //
7207 // First check the calling convention
7208 //
7209 if (candidateSig.GetCallingConventionInfo() != bestSignature.GetCallingConventionInfo())
7210 {
7211 if (bestSignature.GetCallingConventionInfo() == ibcSignature.GetCallingConventionInfo())
7212 goto LEAVE_BEST;
7213 if (candidateSig.GetCallingConventionInfo() == ibcSignature.GetCallingConventionInfo())
7214 goto SELECT_CANDIDATE;
7215 //
7216 // Neither one is a match
7217 //
7218 goto USE_NEITHER;
7219 }
7220
7221 //
7222 // Next check the number of arguments
7223 //
7224 if (candidateSig.NumFixedArgs() != bestSignature.NumFixedArgs())
7225 {
7226 //
7227 // Does one of the two have the same number of args?
7228 //
7229 if (bestSignature.NumFixedArgs() == ibcSignature.NumFixedArgs())
7230 goto LEAVE_BEST;
7231 if (candidateSig.NumFixedArgs() == ibcSignature.NumFixedArgs())
7232 goto SELECT_CANDIDATE;
7233 //
7234 // Neither one is a match
7235 //
7236 goto USE_NEITHER;
7237 }
7238 else if (candidateSig.NumFixedArgs() != ibcSignature.NumFixedArgs())
7239 {
7240 //
7241 // Neither one is a match
7242 //
7243 goto USE_NEITHER;
7244 }
7245
7246 CorElementType etIbc;
7247 CorElementType etCandidate;
7248 CorElementType etBest;
7249 //
7250 // Next get the return element type
7251 //
7252 // etIbc = ibcSignature.GetReturnProps().PeekElemTypeClosed(ibcSignature.GetSigTypeContext());
7253 IfFailThrow(ibcSignature.GetReturnProps().PeekElemType(&etIbc));
7254 IfFailThrow(candidateSig.GetReturnProps().PeekElemType(&etCandidate));
7255 IfFailThrow(bestSignature.GetReturnProps().PeekElemType(&etBest));
7256 //
7257 // Do they have different return types?
7258 //
7259 if (etCandidate != etBest)
7260 {
7261 if (etBest == etIbc)
7262 goto LEAVE_BEST;
7263
7264 if (etCandidate == etIbc)
7265 goto SELECT_CANDIDATE;
7266 }
7267
7268 //
7269 // Now iterate over the method argument types to see which signature
7270 // is the better match
7271 //
7272 for (DWORD i = 0; (i < ibcSignature.NumFixedArgs()); i++)
7273 {
7274 ibcSignature.SkipArg();
7275 IfFailThrow(ibcSignature.GetArgProps().PeekElemType(&etIbc));
7276
7277 candidateSig.SkipArg();
7278 IfFailThrow(candidateSig.GetArgProps().PeekElemType(&etCandidate));
7279
7280 bestSignature.SkipArg();
7281 IfFailThrow(bestSignature.GetArgProps().PeekElemType(&etBest));
7282
7283 //
7284 // Do they have different argument types?
7285 //
7286 if (etCandidate != etBest)
7287 {
7288 if (etBest == etIbc)
7289 goto LEAVE_BEST;
7290
7291 if (etCandidate == etIbc)
7292 goto SELECT_CANDIDATE;
7293 }
7294 }
7295 // When we fall though to here we did not find any differences
7296 // that we could base a choice on
7297 //
7298 context->useBestSig = true;
7299
7300SELECT_CANDIDATE:
7301 context->pvBestSig = pvCandidateSig;
7302 context->cbBestSig = cbCandidateSig;
7303 context->useBestSig = true;
7304 return FALSE;
7305
7306USE_NEITHER:
7307 context->useBestSig = false;
7308 return FALSE;
7309 }
7310
7311LEAVE_BEST:
7312 return FALSE;
7313} // CompareIbcMethodSigs
7314
7315mdMethodDef Module::LookupIbcMethodToken(TypeHandle enclosingType, mdToken ibcToken, SString* optionalFullNameOut)
7316{
7317 CONTRACTL
7318 {
7319 THROWS;
7320 GC_TRIGGERS;
7321 MODE_ANY;
7322 }
7323 CONTRACTL_END
7324
7325 _ASSERTE(TypeFromToken(ibcToken) == ibcExternalMethod);
7326
7327 CorProfileData * profileData = this->GetProfileData();
7328
7329 CORBBTPROF_BLOB_METHOD_DEF_ENTRY * blobMethodDefEntry;
7330 blobMethodDefEntry = profileData->GetBlobExternalMethodDef(ibcToken);
7331
7332 if (blobMethodDefEntry == NULL)
7333 return mdMethodDefNil;
7334
7335 idExternalType signatureToken = blobMethodDefEntry->signatureToken;
7336 _ASSERTE(!IsNilToken(signatureToken));
7337 _ASSERTE(TypeFromToken(signatureToken) == ibcExternalSignature);
7338
7339 CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY * blobSignatureDefEntry;
7340 blobSignatureDefEntry = profileData->GetBlobExternalSignatureDef(signatureToken);
7341
7342 if (blobSignatureDefEntry == NULL)
7343 return mdMethodDefNil;
7344
7345 IbcNameHandle ibcName;
7346 ibcName.szName = &blobMethodDefEntry->name[0];
7347 ibcName.tkIbcNestedClass = blobMethodDefEntry->nestedClassToken;
7348 ibcName.tkIbcNameSpace = idExternalNamespaceNil;
7349 ibcName.szNamespace = NULL;
7350 ibcName.tkEnclosingClass = mdTypeDefNil;
7351
7352 Module * pExternalModule = enclosingType.GetModule();
7353 PCCOR_SIGNATURE pvSig = NULL;
7354 ULONG cbSig = 0;
7355
7356 _ASSERTE(!IsNilToken(ibcName.tkIbcNestedClass));
7357 _ASSERTE(TypeFromToken(ibcName.tkIbcNestedClass) == ibcExternalType);
7358
7359 ibcName.tkEnclosingClass = LookupIbcTypeToken(pExternalModule, ibcName.tkIbcNestedClass, optionalFullNameOut);
7360
7361 if (IsNilToken(ibcName.tkEnclosingClass))
7362 {
7363 COMPlusThrow(kTypeLoadException, IDS_IBC_MISSING_EXTERNAL_TYPE);
7364 }
7365
7366 if (optionalFullNameOut != NULL)
7367 {
7368 optionalFullNameOut->Append(W("."));
7369 optionalFullNameOut->AppendUTF8(ibcName.szName); // MethodName
7370 optionalFullNameOut->Append(W("()"));
7371 }
7372
7373 pvSig = blobSignatureDefEntry->sig;
7374 cbSig = blobSignatureDefEntry->cSig;
7375
7376 //*****************************************
7377 // look up functions for TypeDef
7378 //*****************************************
7379 // STDMETHOD(FindMethodDefUsingCompare)(
7380 // mdTypeDef classdef, // [IN] given typedef
7381 // LPCSTR szName, // [IN] member name
7382 // PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob value of CLR signature
7383 // ULONG cbSigBlob, // [IN] count of bytes in the signature blob
7384 // PSIGCOMPARE pSignatureCompare, // [IN] Routine to compare signatures
7385 // void* pSignatureArgs, // [IN] Additional info to supply the compare function
7386 // mdMethodDef *pmd) PURE; // [OUT] matching memberdef
7387 //
7388
7389 IMDInternalImport * pInternalImport = pExternalModule->GetMDImport();
7390
7391 IbcCompareContext context;
7392 memset(&context, 0, sizeof(IbcCompareContext));
7393 context.pModule = this;
7394 context.enclosingType = enclosingType;
7395 context.cMatch = 0;
7396 context.useBestSig = false;
7397
7398 mdMethodDef mdResult = mdMethodDefNil;
7399 HRESULT hr = pInternalImport->FindMethodDefUsingCompare(ibcName.tkEnclosingClass, ibcName.szName,
7400 pvSig, cbSig,
7401 CompareIbcMethodSigs, (void *) &context,
7402 &mdResult);
7403 if (SUCCEEDED(hr))
7404 {
7405 _ASSERTE(mdResult != mdMethodDefNil);
7406 }
7407 else if (context.useBestSig)
7408 {
7409 hr = pInternalImport->FindMethodDefUsingCompare(ibcName.tkEnclosingClass, ibcName.szName,
7410 context.pvBestSig, context.cbBestSig,
7411 CompareIbcMethodSigs, (void *) &context,
7412 &mdResult);
7413 _ASSERTE(SUCCEEDED(hr));
7414 _ASSERTE(mdResult != mdMethodDefNil);
7415 }
7416 else
7417 {
7418 mdResult = mdMethodDefNil;
7419 }
7420
7421 return mdResult;
7422}
7423
7424TypeHandle Module::LoadIBCTypeHelper(DataImage *image, CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry)
7425{
7426 CONTRACT(TypeHandle)
7427 {
7428 NOTHROW;
7429 GC_TRIGGERS;
7430 MODE_ANY;
7431 INJECT_FAULT(COMPlusThrowOM());
7432 PRECONDITION(CheckPointer(pBlobSigEntry));
7433 }
7434 CONTRACT_END
7435
7436 TypeHandle loadedType;
7437
7438 PCCOR_SIGNATURE pSig = pBlobSigEntry->sig;
7439 ULONG cSig = pBlobSigEntry->cSig;
7440
7441 SigPointer p(pSig, cSig);
7442
7443 ZapSig::Context zapSigContext(this, (void *)this, ZapSig::IbcTokens);
7444 ZapSig::Context * pZapSigContext = &zapSigContext;
7445
7446 EX_TRY
7447 {
7448 // This is what ZapSig::FindTypeHandleFromSignature does...
7449 //
7450 SigTypeContext typeContext; // empty type context
7451
7452 loadedType = p.GetTypeHandleThrowing( this,
7453 &typeContext,
7454 ClassLoader::LoadTypes,
7455 CLASS_LOADED,
7456 FALSE,
7457 NULL,
7458 pZapSigContext);
7459#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
7460 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_1);
7461#endif
7462 }
7463 EX_CATCH
7464 {
7465 image->GetPreloader()->Error(pBlobSigEntry->blob.token, GET_EXCEPTION());
7466 loadedType = TypeHandle();
7467 }
7468 EX_END_CATCH(SwallowAllExceptions)
7469
7470 RETURN loadedType;
7471}
7472
7473//---------------------------------------------------------------------------------------
7474//
7475MethodDesc* Module::LoadIBCMethodHelper(DataImage *image, CORBBTPROF_BLOB_PARAM_SIG_ENTRY * pBlobSigEntry)
7476{
7477 CONTRACT(MethodDesc*)
7478 {
7479 NOTHROW;
7480 GC_TRIGGERS;
7481 MODE_ANY;
7482 INJECT_FAULT(COMPlusThrowOM());
7483 PRECONDITION(CheckPointer(pBlobSigEntry));
7484 }
7485 CONTRACT_END
7486
7487 MethodDesc* pMethod = NULL;
7488
7489 PCCOR_SIGNATURE pSig = pBlobSigEntry->sig;
7490 ULONG cSig = pBlobSigEntry->cSig;
7491
7492 SigPointer p(pSig, cSig);
7493
7494 ZapSig::Context zapSigContext(this, (void *)this, ZapSig::IbcTokens);
7495 ZapSig::Context * pZapSigContext = &zapSigContext;
7496
7497 TypeHandle enclosingType;
7498
7499 //
7500 // First Decode and Load the enclosing type for this method
7501 //
7502 EX_TRY
7503 {
7504 // This is what ZapSig::FindTypeHandleFromSignature does...
7505 //
7506 SigTypeContext typeContext; // empty type context
7507
7508 enclosingType = p.GetTypeHandleThrowing( this,
7509 &typeContext,
7510 ClassLoader::LoadTypes,
7511 CLASS_LOADED,
7512 FALSE,
7513 NULL,
7514 pZapSigContext);
7515 IfFailThrow(p.SkipExactlyOne());
7516#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
7517 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_2);
7518#endif
7519 }
7520 EX_CATCH
7521 {
7522 image->GetPreloader()->Error(pBlobSigEntry->blob.token, GET_EXCEPTION());
7523 enclosingType = TypeHandle();
7524 }
7525 EX_END_CATCH(SwallowAllExceptions)
7526
7527 if (enclosingType.IsNull())
7528 return NULL;
7529
7530 //
7531 // Now Decode and Load the method
7532 //
7533 EX_TRY
7534 {
7535 MethodTable *pOwnerMT = enclosingType.GetMethodTable();
7536 _ASSERTE(pOwnerMT != NULL);
7537
7538 // decode flags
7539 DWORD methodFlags;
7540 IfFailThrow(p.GetData(&methodFlags));
7541 BOOL isInstantiatingStub = ((methodFlags & ENCODE_METHOD_SIG_InstantiatingStub) == ENCODE_METHOD_SIG_InstantiatingStub);
7542 BOOL isUnboxingStub = ((methodFlags & ENCODE_METHOD_SIG_UnboxingStub) == ENCODE_METHOD_SIG_UnboxingStub);
7543 BOOL fMethodNeedsInstantiation = ((methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) == ENCODE_METHOD_SIG_MethodInstantiation);
7544 BOOL fMethodUsesSlotEncoding = ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == ENCODE_METHOD_SIG_SlotInsteadOfToken);
7545
7546 if ( fMethodUsesSlotEncoding )
7547 {
7548 // get the method desc using slot number
7549 DWORD slot;
7550 IfFailThrow(p.GetData(&slot));
7551
7552 pMethod = pOwnerMT->GetMethodDescForSlot(slot);
7553 }
7554 else // otherwise we use the normal metadata MethodDef token encoding and we handle ibc tokens.
7555 {
7556 //
7557 // decode method token
7558 //
7559 RID methodRid;
7560 IfFailThrow(p.GetData(&methodRid));
7561
7562 mdMethodDef methodToken;
7563
7564 //
7565 // Is our enclosingType from another module?
7566 //
7567 if (this == enclosingType.GetModule())
7568 {
7569 //
7570 // The enclosing type is from our module
7571 // The method token is a normal MethodDef token
7572 //
7573 methodToken = TokenFromRid(methodRid, mdtMethodDef);
7574 }
7575 else
7576 {
7577 //
7578 // The enclosing type is from an external module
7579 // The method token is a ibcExternalMethod token
7580 //
7581 idExternalType ibcToken = RidToToken(methodRid, ibcExternalMethod);
7582 methodToken = this->LookupIbcMethodToken(enclosingType, ibcToken);
7583
7584 if (IsNilToken(methodToken))
7585 {
7586 COMPlusThrow(kTypeLoadException, IDS_IBC_MISSING_EXTERNAL_METHOD);
7587 }
7588 }
7589
7590 SigTypeContext methodTypeContext( enclosingType );
7591 pMethod = MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(
7592 pOwnerMT->GetModule(),
7593 methodToken,
7594 &methodTypeContext,
7595 FALSE,
7596 FALSE );
7597 }
7598
7599 Instantiation inst;
7600
7601 // Instantiate the method if needed, or create a stub to a static method in a generic class.
7602 if (fMethodNeedsInstantiation && pMethod->HasMethodInstantiation())
7603 {
7604 DWORD nargs = pMethod->GetNumGenericMethodArgs();
7605 SIZE_T cbMem;
7606
7607 if (!ClrSafeInt<SIZE_T>::multiply(nargs, sizeof(TypeHandle), cbMem/* passed by ref */))
7608 ThrowHR(COR_E_OVERFLOW);
7609
7610 TypeHandle * pInst = (TypeHandle*) _alloca(cbMem);
7611 SigTypeContext typeContext; // empty type context
7612
7613 for (DWORD i = 0; i < nargs; i++)
7614 {
7615 TypeHandle curInst;
7616
7617 curInst = p.GetTypeHandleThrowing( this,
7618 &typeContext,
7619 ClassLoader::LoadTypes,
7620 CLASS_LOADED,
7621 FALSE,
7622 NULL,
7623 pZapSigContext);
7624
7625 // curInst will be nullptr when the type fails the versioning bubble check
7626 if (curInst.IsNull() && IsReadyToRunCompilation())
7627 {
7628 COMPlusThrow(kTypeLoadException, IDS_IBC_MISSING_EXTERNAL_TYPE);
7629 }
7630
7631 pInst[i] = curInst;
7632 IfFailThrow(p.SkipExactlyOne());
7633 }
7634
7635 inst = Instantiation(pInst, nargs);
7636 }
7637 else
7638 {
7639 inst = pMethod->LoadMethodInstantiation();
7640 }
7641
7642 // We should now be able to create an instantiation for this generic method
7643
7644 // This must be called even if nargs == 0, in order to create an instantiating
7645 // stub for static methods in generic classees if needed, also for BoxedEntryPointStubs
7646 // in non-generic structs.
7647 const bool allowInstParam = !(isInstantiatingStub || isUnboxingStub);
7648
7649 pMethod = MethodDesc::FindOrCreateAssociatedMethodDesc(pMethod, pOwnerMT,
7650 isUnboxingStub,
7651 inst, allowInstParam);
7652
7653#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
7654 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_3);
7655#endif
7656 }
7657 EX_CATCH
7658 {
7659 // Catch any kTypeLoadException that we may have thrown above
7660 //
7661 image->GetPreloader()->Error(pBlobSigEntry->blob.token, GET_EXCEPTION());
7662 pMethod = NULL;
7663 }
7664 EX_END_CATCH(SwallowAllExceptions)
7665
7666 RETURN pMethod;
7667} // Module::LoadIBCMethodHelper
7668
7669#ifdef FEATURE_COMINTEROP
7670//---------------------------------------------------------------------------------------
7671//
7672// This function is a workaround for missing IBC data in WinRT assemblies and
7673// not-yet-implemented sharing of IL_STUB(__Canon arg) IL stubs for all interfaces.
7674//
7675static void ExpandWindowsRuntimeType(TypeHandle t, DataImage *image)
7676{
7677 CONTRACTL
7678 {
7679 STANDARD_VM_CHECK;
7680 PRECONDITION(!t.IsNull());
7681 }
7682 CONTRACTL_END
7683
7684 if (t.IsTypeDesc())
7685 return;
7686
7687 // This array contains our poor man's IBC data - instantiations that are known to
7688 // be used by other assemblies.
7689 static const struct
7690 {
7691 LPCUTF8 m_szTypeName;
7692 BinderClassID m_GenericBinderClassID;
7693 }
7694 rgForcedInstantiations[] = {
7695 { "Windows.UI.Xaml.Data.IGroupInfo", CLASS__IENUMERABLEGENERIC },
7696 { "Windows.UI.Xaml.UIElement", CLASS__ILISTGENERIC },
7697 { "Windows.UI.Xaml.Visibility", CLASS__CLRIREFERENCEIMPL },
7698 { "Windows.UI.Xaml.VerticalAlignment", CLASS__CLRIREFERENCEIMPL },
7699 { "Windows.UI.Xaml.HorizontalAlignment", CLASS__CLRIREFERENCEIMPL },
7700 // The following instantiations are used by Microsoft.PlayerFramework - http://playerframework.codeplex.com/
7701 { "Windows.UI.Xaml.Media.AudioCategory", CLASS__CLRIREFERENCEIMPL },
7702 { "Windows.UI.Xaml.Media.AudioDeviceType", CLASS__CLRIREFERENCEIMPL },
7703 { "Windows.UI.Xaml.Media.MediaElementState", CLASS__CLRIREFERENCEIMPL },
7704 { "Windows.UI.Xaml.Media.Stereo3DVideoRenderMode", CLASS__CLRIREFERENCEIMPL },
7705 { "Windows.UI.Xaml.Media.Stereo3DVideoPackingMode", CLASS__CLRIREFERENCEIMPL },
7706 };
7707
7708 DefineFullyQualifiedNameForClass();
7709 LPCUTF8 szTypeName = GetFullyQualifiedNameForClass(t.AsMethodTable());
7710
7711 for (SIZE_T i = 0; i < COUNTOF(rgForcedInstantiations); i++)
7712 {
7713 if (strcmp(szTypeName, rgForcedInstantiations[i].m_szTypeName) == 0)
7714 {
7715 EX_TRY
7716 {
7717 TypeHandle thGenericType = TypeHandle(MscorlibBinder::GetClass(rgForcedInstantiations[i].m_GenericBinderClassID));
7718
7719 Instantiation inst(&t, 1);
7720 thGenericType.Instantiate(inst);
7721 }
7722 EX_CATCH
7723 {
7724 image->GetPreloader()->Error(t.GetCl(), GET_EXCEPTION());
7725 }
7726 EX_END_CATCH(SwallowAllExceptions)
7727 }
7728 }
7729
7730 if (strcmp(szTypeName, "Windows.Foundation.Collections.IObservableVector`1") == 0)
7731 {
7732 EX_TRY
7733 {
7734 TypeHandle thArg = TypeHandle(g_pObjectClass);
7735
7736 Instantiation inst(&thArg, 1);
7737 t.Instantiate(inst);
7738 }
7739 EX_CATCH
7740 {
7741 image->GetPreloader()->Error(t.GetCl(), GET_EXCEPTION());
7742 }
7743 EX_END_CATCH(SwallowAllExceptions)
7744 }
7745}
7746#endif // FEATURE_COMINTEROP
7747
7748//---------------------------------------------------------------------------------------
7749//
7750void Module::ExpandAll(DataImage *image)
7751{
7752 CONTRACTL
7753 {
7754 STANDARD_VM_CHECK;
7755 PRECONDITION(!IsResource());
7756 }
7757 CONTRACTL_END
7758
7759 mdToken tk;
7760 DWORD assemblyFlags = GetAssembly()->GetFlags();
7761
7762 //
7763 // Explicitly load the global class.
7764 //
7765
7766 MethodTable *pGlobalMT = GetGlobalMethodTable();
7767
7768 //
7769 // Load all classes. This also fills out the
7770 // RID maps for the typedefs, method defs,
7771 // and field defs.
7772 //
7773
7774 IMDInternalImport *pInternalImport = GetMDImport();
7775 {
7776 HENUMInternalHolder hEnum(pInternalImport);
7777 hEnum.EnumTypeDefInit();
7778
7779 while (pInternalImport->EnumTypeDefNext(&hEnum, &tk))
7780 {
7781#ifdef FEATURE_COMINTEROP
7782 // Skip the non-managed WinRT types since they're only used by Javascript and C++
7783 //
7784 // With WinRT files, we want to exclude certain types that cause us problems:
7785 // * Attribute types defined in Windows.Foundation. The constructor's methodimpl flags
7786 // specify it is an internal runtime function and gets set as an FCALL when we parse
7787 // the type
7788 //
7789 if (IsAfContentType_WindowsRuntime(assemblyFlags))
7790 {
7791 mdToken tkExtends;
7792 pInternalImport->GetTypeDefProps(tk, NULL, &tkExtends);
7793
7794 if (TypeFromToken(tkExtends) == mdtTypeRef)
7795 {
7796 LPCSTR szNameSpace = NULL;
7797 LPCSTR szName = NULL;
7798 pInternalImport->GetNameOfTypeRef(tkExtends, &szNameSpace, &szName);
7799
7800 if (!strcmp(szNameSpace, "System") && !_stricmp((szName), "Attribute"))
7801 {
7802 continue;
7803 }
7804 }
7805 }
7806#endif // FEATURE_COMINTEROP
7807
7808 TypeHandle t = LoadTypeDefOrRefHelper(image, this, tk);
7809
7810 if (t.IsNull()) // Skip this type
7811 continue;
7812
7813 if (!t.HasInstantiation())
7814 {
7815 EEClassHashEntry_t *pBucket = NULL;
7816 HashDatum data;
7817 StackSString ssFullyQualifiedName;
7818 mdToken mdEncloser;
7819 EEClassHashTable *pTable = GetAvailableClassHash();
7820
7821 _ASSERTE(pTable != NULL);
7822
7823 t.GetName(ssFullyQualifiedName);
7824
7825 // Convert to UTF8
7826 StackScratchBuffer scratch;
7827 LPCUTF8 szFullyQualifiedName = ssFullyQualifiedName.GetUTF8(scratch);
7828
7829 BOOL isNested = ClassLoader::IsNested(this, tk, &mdEncloser);
7830 EEClassHashTable::LookupContext sContext;
7831 pBucket = pTable->GetValue(szFullyQualifiedName, &data, isNested, &sContext);
7832
7833 if (isNested)
7834 {
7835 while (pBucket != NULL)
7836 {
7837 _ASSERTE (TypeFromToken(tk) == mdtTypeDef);
7838 BOOL match = GetClassLoader()->CompareNestedEntryWithTypeDef( pInternalImport,
7839 mdEncloser,
7840 GetAvailableClassHash(),
7841 pBucket->GetEncloser());
7842 if (match)
7843 break;
7844
7845 pBucket = pTable->FindNextNestedClass(szFullyQualifiedName, &data, &sContext);
7846 }
7847 }
7848
7849 // Save the typehandle instead of the token in the hash entry so that ngen'ed images
7850 // don't have to lookup based on token and update this entry
7851 if ((pBucket != NULL) && !t.IsNull() && t.IsRestored())
7852 pBucket->SetData(t.AsPtr());
7853 }
7854
7855 DWORD nGenericClassParams = t.GetNumGenericArgs();
7856 if (nGenericClassParams != 0)
7857 {
7858 // For generic types, load the instantiation at Object
7859 SIZE_T cbMem;
7860 if (!ClrSafeInt<SIZE_T>::multiply(sizeof(TypeHandle), nGenericClassParams, cbMem/* passed by ref */))
7861 {
7862 ThrowHR(COR_E_OVERFLOW);
7863 }
7864 CQuickBytes qbGenericClassArgs;
7865 TypeHandle *genericClassArgs = reinterpret_cast<TypeHandle*>(qbGenericClassArgs.AllocThrows(cbMem));
7866 for (DWORD i = 0; i < nGenericClassParams; i++)
7867 {
7868 genericClassArgs[i] = TypeHandle(g_pCanonMethodTableClass);
7869 }
7870
7871 TypeHandle thCanonInst = LoadGenericInstantiationHelper(image, this, tk, Instantiation(genericClassArgs, nGenericClassParams));
7872
7873 // If successful, add the instantiation to the Module's map of generic types instantiated at Object
7874 if (!thCanonInst.IsNull() && !thCanonInst.IsTypeDesc())
7875 {
7876 MethodTable * pCanonMT = thCanonInst.AsMethodTable();
7877 m_GenericTypeDefToCanonMethodTableMap.AddElement(this, RidFromToken(pCanonMT->GetCl()), pCanonMT);
7878 }
7879 }
7880
7881#ifdef FEATURE_COMINTEROP
7882 if (IsAfContentType_WindowsRuntime(assemblyFlags))
7883 {
7884 ExpandWindowsRuntimeType(t, image);
7885 }
7886#endif // FEATURE_COMINTEROP
7887 }
7888 }
7889
7890 //
7891 // Fill out TypeRef RID map
7892 //
7893
7894 {
7895 HENUMInternalHolder hEnum(pInternalImport);
7896 hEnum.EnumAllInit(mdtTypeRef);
7897
7898 while (pInternalImport->EnumNext(&hEnum, &tk))
7899 {
7900 mdToken tkResolutionScope = mdTokenNil;
7901 pInternalImport->GetResolutionScopeOfTypeRef(tk, &tkResolutionScope);
7902
7903#ifdef FEATURE_COMINTEROP
7904 // WinRT first party files are authored with TypeRefs pointing to TypeDefs in the same module.
7905 // This causes us to load types we do not want to NGen such as custom attributes. We will not
7906 // expand any module local TypeRefs for WinMDs to prevent this.
7907 if(TypeFromToken(tkResolutionScope)==mdtModule && IsAfContentType_WindowsRuntime(assemblyFlags))
7908 continue;
7909#endif // FEATURE_COMINTEROP
7910 TypeHandle t = LoadTypeDefOrRefHelper(image, this, tk);
7911
7912 if (t.IsNull()) // Skip this type
7913 continue;
7914
7915#ifdef FEATURE_COMINTEROP
7916 if (!g_fNGenWinMDResilient && TypeFromToken(tkResolutionScope) == mdtAssemblyRef)
7917 {
7918 DWORD dwAssemblyRefFlags;
7919 IfFailThrow(pInternalImport->GetAssemblyRefProps(tkResolutionScope, NULL, NULL, NULL, NULL, NULL, NULL, &dwAssemblyRefFlags));
7920
7921 if (IsAfContentType_WindowsRuntime(dwAssemblyRefFlags))
7922 {
7923 Assembly *pAssembly = t.GetAssembly();
7924 PEAssembly *pPEAssembly = pAssembly->GetManifestFile();
7925 AssemblySpec refSpec;
7926 refSpec.InitializeSpec(tkResolutionScope, pInternalImport);
7927 LPCSTR psznamespace;
7928 LPCSTR pszname;
7929 pInternalImport->GetNameOfTypeRef(tk, &psznamespace, &pszname);
7930 refSpec.SetWindowsRuntimeType(psznamespace, pszname);
7931 GetAppDomain()->ToCompilationDomain()->AddDependency(&refSpec,pPEAssembly);
7932 }
7933 }
7934#endif // FEATURE_COMINTEROP
7935 }
7936 }
7937
7938 //
7939 // Load all type specs
7940 //
7941
7942 {
7943 HENUMInternalHolder hEnum(pInternalImport);
7944 hEnum.EnumAllInit(mdtTypeSpec);
7945
7946 while (pInternalImport->EnumNext(&hEnum, &tk))
7947 {
7948 ULONG cSig;
7949 PCCOR_SIGNATURE pSig;
7950
7951 IfFailThrow(pInternalImport->GetTypeSpecFromToken(tk, &pSig, &cSig));
7952
7953 // Load all types specs that do not contain variables
7954 if (SigPointer(pSig, cSig).IsPolyType(NULL) == hasNoVars)
7955 {
7956 LoadTypeSpecHelper(image, this, tk, pSig, cSig);
7957 }
7958 }
7959 }
7960
7961 //
7962 // Load all the reported parameterized types and methods
7963 //
7964 CorProfileData * profileData = this->GetProfileData();
7965 CORBBTPROF_BLOB_ENTRY *pBlobEntry = profileData->GetBlobStream();
7966
7967 if (pBlobEntry != NULL)
7968 {
7969 while (pBlobEntry->TypeIsValid())
7970 {
7971 if (TypeFromToken(pBlobEntry->token) == ibcTypeSpec)
7972 {
7973 _ASSERTE(pBlobEntry->type == ParamTypeSpec);
7974 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY *) pBlobEntry;
7975
7976 TypeHandle th = LoadIBCTypeHelper(image, pBlobSigEntry);
7977
7978 if (!th.IsNull())
7979 {
7980 image->GetPreloader()->TriageTypeForZap(th, TRUE);
7981 }
7982 }
7983 else if (TypeFromToken(pBlobEntry->token) == ibcMethodSpec)
7984 {
7985 _ASSERTE(pBlobEntry->type == ParamMethodSpec);
7986 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY *) pBlobEntry;
7987
7988 MethodDesc *pMD = LoadIBCMethodHelper(image, pBlobSigEntry);
7989 }
7990 pBlobEntry = pBlobEntry->GetNextEntry();
7991 }
7992 _ASSERTE(pBlobEntry->type == EndOfBlobStream);
7993 }
7994
7995 //
7996 // Record references to all of the hot methods specifiled by MethodProfilingData array
7997 // We call MethodReferencedByCompiledCode to indicate that we plan on compiling this method
7998 //
7999 CORBBTPROF_TOKEN_INFO * pMethodProfilingData = profileData->GetTokenFlagsData(MethodProfilingData);
8000 DWORD cMethodProfilingData = profileData->GetTokenFlagsCount(MethodProfilingData);
8001 for (unsigned int i = 0; (i < cMethodProfilingData); i++)
8002 {
8003 mdToken token = pMethodProfilingData[i].token;
8004 DWORD profilingFlags = pMethodProfilingData[i].flags;
8005
8006 // We call MethodReferencedByCompiledCode only when the profile data indicates that
8007 // we executed (i.e read) the code for the method
8008 //
8009 if (profilingFlags & (1 << ReadMethodCode))
8010 {
8011 if (TypeFromToken(token) == mdtMethodDef)
8012 {
8013 MethodDesc * pMD = LookupMethodDef(token);
8014 //
8015 // Record a reference to a hot non-generic method
8016 //
8017 image->GetPreloader()->MethodReferencedByCompiledCode((CORINFO_METHOD_HANDLE)pMD);
8018 }
8019 else if (TypeFromToken(token) == ibcMethodSpec)
8020 {
8021 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = profileData->GetBlobSigEntry(token);
8022
8023 if (pBlobSigEntry != NULL)
8024 {
8025 _ASSERTE(pBlobSigEntry->blob.token == token);
8026 MethodDesc * pMD = LoadIBCMethodHelper(image, pBlobSigEntry);
8027
8028 if (pMD != NULL)
8029 {
8030 // Occasionally a non-instantiated generic method shows up in the IBC data, we should NOT compile it.
8031 if (!pMD->IsTypicalMethodDefinition())
8032 {
8033 //
8034 // Record a reference to a hot instantiated generic method
8035 //
8036 image->GetPreloader()->MethodReferencedByCompiledCode((CORINFO_METHOD_HANDLE)pMD);
8037 }
8038 }
8039 }
8040 }
8041 }
8042 }
8043
8044 {
8045 //
8046 // Fill out MemberRef RID map and va sig cookies for
8047 // varargs member refs.
8048 //
8049
8050 HENUMInternalHolder hEnum(pInternalImport);
8051 hEnum.EnumAllInit(mdtMemberRef);
8052
8053 while (pInternalImport->EnumNext(&hEnum, &tk))
8054 {
8055 mdTypeRef parent;
8056 IfFailThrow(pInternalImport->GetParentOfMemberRef(tk, &parent));
8057
8058#ifdef FEATURE_COMINTEROP
8059 if (IsAfContentType_WindowsRuntime(assemblyFlags) && TypeFromToken(parent) == mdtTypeRef)
8060 {
8061 mdToken tkResolutionScope = mdTokenNil;
8062 pInternalImport->GetResolutionScopeOfTypeRef(parent, &tkResolutionScope);
8063 // WinRT first party files are authored with TypeRefs pointing to TypeDefs in the same module.
8064 // This causes us to load types we do not want to NGen such as custom attributes. We will not
8065 // expand any module local TypeRefs for WinMDs to prevent this.
8066 if(TypeFromToken(tkResolutionScope)==mdtModule)
8067 continue;
8068
8069 LPCSTR szNameSpace = NULL;
8070 LPCSTR szName = NULL;
8071 if (SUCCEEDED(pInternalImport->GetNameOfTypeRef(parent, &szNameSpace, &szName)))
8072 {
8073 if (WinMDAdapter::ConvertWellKnownTypeNameFromClrToWinRT(&szNameSpace, &szName))
8074 {
8075 //
8076 // This is a MemberRef from a redirected WinRT type
8077 // We should skip it as managed view will never see this MemberRef anyway
8078 // Not skipping this will result MissingMethodExceptions as members in redirected
8079 // types doesn't exactly match their redirected CLR type counter part
8080 //
8081 // Typically we only need to do this for interfaces as we should never see MemberRef
8082 // from non-interfaces, but here to keep things simple I'm skipping every memberref that
8083 // belongs to redirected WinRT type
8084 //
8085 continue;
8086 }
8087 }
8088
8089 }
8090#endif // FEATURE_COMINTEROP
8091
8092 // If the MethodRef has a TypeSpec as a parent (i.e. refers to a method on an array type
8093 // or on a generic class), then it could in turn refer to type variables of
8094 // an unknown class/method. So we don't preresolve any MemberRefs which have TypeSpecs as
8095 // parents. The RID maps are not filled out for such tokens anyway.
8096 if (TypeFromToken(parent) != mdtTypeSpec)
8097 {
8098 GetDescFromMemberRefHelper(image, this, tk);
8099 }
8100 }
8101 }
8102
8103 //
8104 // Fill out binder
8105 //
8106
8107 if (m_pBinder != NULL)
8108 {
8109 m_pBinder->BindAll();
8110 }
8111
8112} // Module::ExpandAll
8113
8114/* static */
8115void Module::SaveMethodTable(DataImage * image,
8116 MethodTable * pMT,
8117 DWORD profilingFlags)
8118{
8119 STANDARD_VM_CONTRACT;
8120
8121 if (image->IsStored(pMT))
8122 return;
8123
8124 pMT->Save(image, profilingFlags);
8125}
8126
8127
8128/* static */
8129void Module::SaveTypeHandle(DataImage * image,
8130 TypeHandle t,
8131 DWORD profilingFlags)
8132{
8133 STANDARD_VM_CONTRACT;
8134
8135 t.CheckRestore();
8136 if (t.IsTypeDesc())
8137 {
8138 TypeDesc *pTD = t.AsTypeDesc();
8139 if (!image->IsStored(pTD))
8140 {
8141 pTD->Save(image);
8142 }
8143 }
8144 else
8145 {
8146 MethodTable *pMT = t.AsMethodTable();
8147 if (pMT != NULL && !image->IsStored(pMT))
8148 {
8149 SaveMethodTable(image, pMT, profilingFlags);
8150 _ASSERTE(image->IsStored(pMT));
8151 }
8152 }
8153#ifdef _DEBUG
8154 if (LoggingOn(LF_JIT, LL_INFO100))
8155 {
8156 Module *pPrefModule = Module::GetPreferredZapModuleForTypeHandle(t);
8157 if (image->GetModule() != pPrefModule)
8158 {
8159 StackSString typeName;
8160 t.CheckRestore();
8161 TypeString::AppendTypeDebug(typeName, t);
8162 LOG((LF_ZAP, LL_INFO100, "The type %S was saved outside its preferred module %S\n", typeName.GetUnicode(), pPrefModule->GetPath().GetUnicode()));
8163 }
8164 }
8165#endif // _DEBUG
8166}
8167
8168#ifndef DACCESS_COMPILE
8169
8170void ModuleCtorInfo::Save(DataImage *image, CorProfileData *profileData)
8171{
8172 STANDARD_VM_CONTRACT;
8173
8174 if (!numElements)
8175 return;
8176
8177 DWORD i = 0;
8178 DWORD totalBoxedStatics = 0;
8179
8180 // sort the tables so that
8181 // - the hot ppMT entries are at the beginning of the ppMT table
8182 // - the hot cctor entries are at the beginning of the cctorInfoHot table
8183 // - the cold cctor entries are at the end, and we make cctorInfoCold point
8184 // the first cold entry
8185 //
8186 // the invariant in this loop is:
8187 // items 0...numElementsHot-1 are hot
8188 // items numElementsHot...i-1 are cold
8189 for (i = 0; i < numElements; i++)
8190 {
8191 MethodTable *ppMTTemp = ppMT[i].GetValue();
8192
8193 // Count the number of boxed statics along the way
8194 totalBoxedStatics += ppMTTemp->GetNumBoxedRegularStatics();
8195
8196 bool hot = true; // if there's no profiling data, assume the entries are all hot.
8197 if (profileData->GetTokenFlagsData(TypeProfilingData))
8198 {
8199 if ((profileData->GetTypeProfilingFlagsOfToken(ppMTTemp->GetCl()) & (1 << ReadCCtorInfo)) == 0)
8200 hot = false;
8201 }
8202 if (hot)
8203 {
8204 // swap ppMT[i] and ppMT[numElementsHot] to maintain the loop invariant
8205 ppMT[i].SetValue(ppMT[numElementsHot].GetValue());
8206 ppMT[numElementsHot].SetValue(ppMTTemp);
8207
8208 numElementsHot++;
8209 }
8210 }
8211
8212 numHotHashes = numElementsHot ? RoundUpToPower2((numElementsHot * sizeof(PTR_MethodTable)) / CACHE_LINE_SIZE) : 0;
8213 numColdHashes = (numElements - numElementsHot) ? RoundUpToPower2(((numElements - numElementsHot) *
8214 sizeof(PTR_MethodTable)) / CACHE_LINE_SIZE) : 0;
8215
8216 LOG((LF_ZAP, LL_INFO10, "ModuleCtorInfo::numHotHashes: 0x%4x\n", numHotHashes));
8217 if (numColdHashes != 0)
8218 {
8219 LOG((LF_ZAP, LL_INFO10, "ModuleCtorInfo::numColdHashes: 0x%4x\n", numColdHashes));
8220 }
8221
8222 // The "plus one" is so we can store the offset to the end of the array at the end of
8223 // the hashoffsets arrays, enabling faster lookups.
8224 hotHashOffsets = new DWORD[numHotHashes + 1];
8225 coldHashOffsets = new DWORD[numColdHashes + 1];
8226
8227 DWORD *hashArray = new DWORD[numElements];
8228
8229 for (i = 0; i < numElementsHot; i++)
8230 {
8231 hashArray[i] = GenerateHash(ppMT[i].GetValue(), HOT);
8232 }
8233 for (i = numElementsHot; i < numElements; i++)
8234 {
8235 hashArray[i] = GenerateHash(ppMT[i].GetValue(), COLD);
8236 }
8237
8238 // Sort the two arrays by hash values to create regions with the same hash values.
8239 ClassCtorInfoEntryArraySort cctorInfoHotSort(hashArray, ppMT, numElementsHot);
8240 ClassCtorInfoEntryArraySort cctorInfoColdSort(hashArray + numElementsHot, ppMT + numElementsHot,
8241 numElements - numElementsHot);
8242 cctorInfoHotSort.Sort();
8243 cctorInfoColdSort.Sort();
8244
8245 // Generate the indices that index into the correct "hash region" in the hot part of the ppMT array, and store
8246 // them in the hotHashOffests arrays.
8247 DWORD curHash = 0;
8248 i = 0;
8249 while (i < numElementsHot)
8250 {
8251 if (curHash < hashArray[i])
8252 {
8253 hotHashOffsets[curHash++] = i;
8254 }
8255 else if (curHash == hashArray[i])
8256 {
8257 hotHashOffsets[curHash++] = i++;
8258 }
8259 else
8260 {
8261 i++;
8262 }
8263 }
8264 while (curHash <= numHotHashes)
8265 {
8266 hotHashOffsets[curHash++] = numElementsHot;
8267 }
8268
8269 // Generate the indices that index into the correct "hash region" in the hot part of the ppMT array, and store
8270 // them in the coldHashOffsets arrays.
8271 curHash = 0;
8272 i = numElementsHot;
8273 while (i < numElements)
8274 {
8275 if (curHash < hashArray[i])
8276 {
8277 coldHashOffsets[curHash++] = i;
8278 }
8279 else if (curHash == hashArray[i])
8280 {
8281 coldHashOffsets[curHash++] = i++;
8282 }
8283 else i++;
8284 }
8285 while (curHash <= numColdHashes)
8286 {
8287 coldHashOffsets[curHash++] = numElements;
8288 }
8289
8290 delete[] hashArray;
8291
8292
8293 cctorInfoHot = new ClassCtorInfoEntry[numElements];
8294
8295 // make cctorInfoCold point to the first cold element
8296 cctorInfoCold = cctorInfoHot + numElementsHot;
8297
8298 ppHotGCStaticsMTs = (totalBoxedStatics != 0) ? new RelativeFixupPointer<PTR_MethodTable>[totalBoxedStatics] : NULL;
8299 numHotGCStaticsMTs = totalBoxedStatics;
8300
8301 DWORD iGCStaticMT = 0;
8302
8303 for (i = 0; i < numElements; i++)
8304 {
8305 if (numElements == numElementsHot)
8306 {
8307 numHotGCStaticsMTs = iGCStaticMT;
8308 numColdGCStaticsMTs = (totalBoxedStatics - iGCStaticMT);
8309
8310 // make ppColdGCStaticsMTs point to the first cold element
8311 ppColdGCStaticsMTs = ppHotGCStaticsMTs + numHotGCStaticsMTs;
8312 }
8313
8314 MethodTable* pMT = ppMT[i].GetValue();
8315 ClassCtorInfoEntry* pEntry = &cctorInfoHot[i];
8316
8317 WORD numBoxedStatics = pMT->GetNumBoxedRegularStatics();
8318 pEntry->numBoxedStatics = numBoxedStatics;
8319 pEntry->hasFixedAddressVTStatics = !!pMT->HasFixedAddressVTStatics();
8320
8321 FieldDesc *pField = pMT->HasGenericsStaticsInfo() ?
8322 pMT->GetGenericsStaticFieldDescs() : (pMT->GetApproxFieldDescListRaw() + pMT->GetNumIntroducedInstanceFields());
8323 FieldDesc *pFieldEnd = pField + pMT->GetNumStaticFields();
8324
8325 pEntry->firstBoxedStaticOffset = (DWORD)-1;
8326 pEntry->firstBoxedStaticMTIndex = (DWORD)-1;
8327
8328 DWORD numFoundBoxedStatics = 0;
8329 while (pField < pFieldEnd)
8330 {
8331 _ASSERTE(pField->IsStatic());
8332
8333 if (!pField->IsSpecialStatic() && pField->IsByValue())
8334 {
8335 if (pEntry->firstBoxedStaticOffset == (DWORD)-1)
8336 {
8337 pEntry->firstBoxedStaticOffset = pField->GetOffset();
8338 pEntry->firstBoxedStaticMTIndex = iGCStaticMT;
8339 }
8340 _ASSERTE(pField->GetOffset() - pEntry->firstBoxedStaticOffset
8341 == (iGCStaticMT - pEntry->firstBoxedStaticMTIndex) * sizeof(MethodTable*));
8342
8343 TypeHandle th = pField->GetFieldTypeHandleThrowing();
8344 ppHotGCStaticsMTs[iGCStaticMT++].SetValueMaybeNull(th.GetMethodTable());
8345
8346 numFoundBoxedStatics++;
8347 }
8348 pField++;
8349 }
8350 _ASSERTE(numBoxedStatics == numFoundBoxedStatics);
8351 }
8352 _ASSERTE(iGCStaticMT == totalBoxedStatics);
8353
8354 if (numElementsHot > 0)
8355 {
8356 image->StoreStructure(cctorInfoHot,
8357 sizeof(ClassCtorInfoEntry) * numElementsHot,
8358 DataImage::ITEM_MODULE_CCTOR_INFO_HOT);
8359
8360 image->StoreStructure(hotHashOffsets,
8361 sizeof(DWORD) * (numHotHashes + 1),
8362 DataImage::ITEM_MODULE_CCTOR_INFO_HOT);
8363 }
8364
8365 if (numElements > 0)
8366 image->StoreStructure(ppMT,
8367 sizeof(RelativePointer<MethodTable *>) * numElements,
8368 DataImage::ITEM_MODULE_CCTOR_INFO_HOT);
8369
8370 if (numElements > numElementsHot)
8371 {
8372 image->StoreStructure(cctorInfoCold,
8373 sizeof(ClassCtorInfoEntry) * (numElements - numElementsHot),
8374 DataImage::ITEM_MODULE_CCTOR_INFO_COLD);
8375
8376 image->StoreStructure(coldHashOffsets,
8377 sizeof(DWORD) * (numColdHashes + 1),
8378 DataImage::ITEM_MODULE_CCTOR_INFO_COLD);
8379 }
8380
8381 if ( numHotGCStaticsMTs )
8382 {
8383 // Save the mt templates
8384 image->StoreStructure( ppHotGCStaticsMTs, numHotGCStaticsMTs * sizeof(RelativeFixupPointer<MethodTable*>),
8385 DataImage::ITEM_GC_STATIC_HANDLES_HOT);
8386 }
8387 else
8388 {
8389 ppHotGCStaticsMTs = NULL;
8390 }
8391
8392 if ( numColdGCStaticsMTs )
8393 {
8394 // Save the hot mt templates
8395 image->StoreStructure( ppColdGCStaticsMTs, numColdGCStaticsMTs * sizeof(RelativeFixupPointer<MethodTable*>),
8396 DataImage::ITEM_GC_STATIC_HANDLES_COLD);
8397 }
8398 else
8399 {
8400 ppColdGCStaticsMTs = NULL;
8401 }
8402}
8403
8404#endif // !DACCESS_COMPILE
8405
8406bool Module::AreAllClassesFullyLoaded()
8407{
8408 STANDARD_VM_CONTRACT;
8409
8410 // Adjust for unused space
8411 IMDInternalImport *pImport = GetMDImport();
8412
8413 HENUMInternalHolder hEnum(pImport);
8414 hEnum.EnumAllInit(mdtTypeDef);
8415
8416 mdTypeDef token;
8417 while (pImport->EnumNext(&hEnum, &token))
8418 {
8419 _ASSERTE(TypeFromToken(token) == mdtTypeDef);
8420
8421 // Special care has to been taken with COR_GLOBAL_PARENT_TOKEN, as the class
8422 // may not be needed, (but we have to distinguish between not needed and threw error).
8423 if (token == COR_GLOBAL_PARENT_TOKEN &&
8424 !NeedsGlobalMethodTable())
8425 {
8426 // No EEClass for this token if there was no need for a global method table
8427 continue;
8428 }
8429
8430 TypeHandle th = LookupTypeDef(token);
8431 if (th.IsNull())
8432 return false;
8433
8434 if (!th.AsMethodTable()->IsFullyLoaded())
8435 return false;
8436 }
8437
8438 return true;
8439}
8440
8441void Module::PrepareTypesForSave(DataImage *image)
8442{
8443 STANDARD_VM_CONTRACT;
8444
8445 //
8446 // Prepare typedefs
8447 //
8448 {
8449 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
8450 while (typeDefIter.Next())
8451 {
8452 MethodTable * pMT = typeDefIter.GetElement();
8453
8454 if (pMT == NULL || !pMT->IsFullyLoaded())
8455 continue;
8456
8457
8458 }
8459 }
8460
8461 //
8462 // Prepare typespecs
8463 //
8464 {
8465 // Create a local copy in case the new elements are added to the hashtable during population
8466 InlineSArray<TypeHandle, 20> pTypes;
8467
8468 // Make sure the iterator is destroyed before there is a chance of loading new types
8469 {
8470 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
8471 EETypeHashEntry *pEntry;
8472 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
8473 {
8474 TypeHandle t = pEntry->GetTypeHandle();
8475
8476 if (t.IsTypeDesc())
8477 continue;
8478
8479 if (!image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(t.AsPtr())))
8480 continue;
8481
8482 pTypes.Append(t);
8483 }
8484 }
8485
8486 }
8487
8488 image->GetPreloader()->TriageForZap(FALSE, FALSE);
8489}
8490
8491static const char* const MethodTableRestoreReasonDescription[TotalMethodTables + 1] =
8492{
8493 #undef RESTORE_REASON_FUNC
8494 #define RESTORE_REASON_FUNC(s) #s,
8495
8496 METHODTABLE_RESTORE_REASON()
8497
8498 #undef RESTORE_REASON
8499
8500 "TotalMethodTablesEvaluated"
8501};
8502
8503
8504// MethodDescByMethodTableTraits could be a local class in Module::Save(), but g++ doesn't like
8505// instantiating templates with private classes.
8506class MethodDescByMethodTableTraits : public NoRemoveSHashTraits< DefaultSHashTraits<MethodDesc *> >
8507{
8508public:
8509 typedef MethodTable * key_t;
8510 static MethodDesc * Null() { return NULL; }
8511 static bool IsNull(MethodDesc * pMD) { return pMD == NULL; }
8512 static MethodTable * GetKey(MethodDesc * pMD) { return pMD->GetMethodTable_NoLogging(); }
8513 static count_t Hash(MethodTable * pMT) { LIMITED_METHOD_CONTRACT; return (count_t) (UINT_PTR) pMT->GetTypeDefRid_NoLogging(); }
8514 static BOOL Equals(MethodTable * pMT1, MethodTable * pMT2)
8515 {
8516 return pMT1 == pMT2;
8517 }
8518};
8519
8520void Module::Save(DataImage *image)
8521{
8522 STANDARD_VM_CONTRACT;
8523
8524 // Precompute type specific auxiliary information saved into NGen image
8525 // Note that this operation can load new types.
8526 PrepareTypesForSave(image);
8527
8528 // Cache values of all persisted flags computed from custom attributes
8529 IsNoStringInterning();
8530 IsRuntimeWrapExceptions();
8531 IsPreV4Assembly();
8532
8533 HasDefaultDllImportSearchPathsAttribute();
8534
8535 // Precompute property information to avoid runtime metadata lookup
8536 PopulatePropertyInfoMap();
8537
8538 // Any any elements and compute values of any LookupMap flags that were not available previously
8539 FinalizeLookupMapsPreSave(image);
8540
8541 //
8542 // Save the module
8543 //
8544
8545 ZapStoredStructure * pModuleNode = image->StoreStructure(this, sizeof(Module),
8546 DataImage::ITEM_MODULE);
8547
8548 m_pNGenLayoutInfo = (NGenLayoutInfo *)(void *)image->GetModule()->GetLoaderAllocator()->
8549 GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(NGenLayoutInfo)));
8550 image->StoreStructure(m_pNGenLayoutInfo, sizeof(NGenLayoutInfo), DataImage::ITEM_BINDER_ITEMS);
8551
8552 //
8553 // If we are NGening, we don't need to keep a list of va
8554 // sig cookies, as we already have a complete set (of course we do
8555 // have to persist the cookies themselves, though.
8556 //
8557
8558 //
8559 // Initialize maps of child data structures. Note that each tables's blocks are
8560 // concantentated to a single block in the process.
8561 //
8562 CorProfileData * profileData = GetProfileData();
8563
8564 // ngen the neutral resources culture
8565 if(GetNeutralResourcesLanguage(&m_pszCultureName, &m_CultureNameLength, &m_FallbackLocation, TRUE)) {
8566 image->StoreStructure((void *) m_pszCultureName,
8567 (ULONG)(m_CultureNameLength + 1),
8568 DataImage::ITEM_BINDER_ITEMS,
8569 1);
8570 }
8571
8572
8573 m_TypeRefToMethodTableMap.Save(image, DataImage::ITEM_TYPEREF_MAP, profileData, mdtTypeRef);
8574 image->BindPointer(&m_TypeRefToMethodTableMap, pModuleNode, offsetof(Module, m_TypeRefToMethodTableMap));
8575
8576 if(m_pMemberRefToDescHashTable)
8577 m_pMemberRefToDescHashTable->Save(image, profileData);
8578
8579 m_TypeDefToMethodTableMap.Save(image, DataImage::ITEM_TYPEDEF_MAP, profileData, mdtTypeDef);
8580 image->BindPointer(&m_TypeDefToMethodTableMap, pModuleNode, offsetof(Module, m_TypeDefToMethodTableMap));
8581
8582 m_MethodDefToDescMap.Save(image, DataImage::ITEM_METHODDEF_MAP, profileData, mdtMethodDef);
8583 image->BindPointer(&m_MethodDefToDescMap, pModuleNode, offsetof(Module, m_MethodDefToDescMap));
8584
8585 m_FieldDefToDescMap.Save(image, DataImage::ITEM_FIELDDEF_MAP, profileData, mdtFieldDef);
8586 image->BindPointer(&m_FieldDefToDescMap, pModuleNode, offsetof(Module, m_FieldDefToDescMap));
8587
8588 m_GenericParamToDescMap.Save(image, DataImage::ITEM_GENERICPARAM_MAP, profileData, mdtGenericParam);
8589 image->BindPointer(&m_GenericParamToDescMap, pModuleNode, offsetof(Module, m_GenericParamToDescMap));
8590
8591 m_GenericTypeDefToCanonMethodTableMap.Save(image, DataImage::ITEM_GENERICTYPEDEF_MAP, profileData, mdtTypeDef);
8592 image->BindPointer(&m_GenericTypeDefToCanonMethodTableMap, pModuleNode, offsetof(Module, m_GenericTypeDefToCanonMethodTableMap));
8593
8594 if (m_pAvailableClasses)
8595 m_pAvailableClasses->Save(image, profileData);
8596
8597 //
8598 // Also save the parent maps; the contents will
8599 // need to be rewritten, but we can allocate the
8600 // space in the image.
8601 //
8602
8603 // these items have no hot list and no attribution
8604 m_FileReferencesMap.Save(image, DataImage::ITEM_FILEREF_MAP, profileData, 0);
8605 image->BindPointer(&m_FileReferencesMap, pModuleNode, offsetof(Module, m_FileReferencesMap));
8606
8607 m_ManifestModuleReferencesMap.Save(image, DataImage::ITEM_ASSEMREF_MAP, profileData, 0);
8608 image->BindPointer(&m_ManifestModuleReferencesMap, pModuleNode, offsetof(Module, m_ManifestModuleReferencesMap));
8609
8610 m_MethodDefToPropertyInfoMap.Save(image, DataImage::ITEM_PROPERTYINFO_MAP, profileData, 0, TRUE /*fCopyValues*/);
8611 image->BindPointer(&m_MethodDefToPropertyInfoMap, pModuleNode, offsetof(Module, m_MethodDefToPropertyInfoMap));
8612
8613 if (m_pBinder != NULL)
8614 m_pBinder->Save(image);
8615
8616 if (profileData)
8617 {
8618 // Store types.
8619
8620 // Saving hot things first is a very good thing, because we place items
8621 // in the order they are saved and things that have hot items are also
8622 // more likely to have their other structures touched, hence these should
8623 // also be placed together, at least if we don't have any further information to go on.
8624 // Note we place particular hot items with more care in the Arrange phase.
8625 //
8626 CORBBTPROF_TOKEN_INFO * pTypeProfilingData = profileData->GetTokenFlagsData(TypeProfilingData);
8627 DWORD cTypeProfilingData = profileData->GetTokenFlagsCount(TypeProfilingData);
8628
8629 for (unsigned int i = 0; i < cTypeProfilingData; i++)
8630 {
8631 CORBBTPROF_TOKEN_INFO *entry = &pTypeProfilingData[i];
8632 mdToken token = entry->token;
8633 DWORD flags = entry->flags;
8634#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
8635 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_4);
8636#endif
8637
8638 if ((flags & (1 << ReadMethodTable)) == 0)
8639 continue;
8640
8641 if (TypeFromToken(token) == mdtTypeDef)
8642 {
8643 MethodTable *pMT = LookupTypeDef(token).GetMethodTable();
8644 if (pMT && pMT->IsFullyLoaded())
8645 {
8646 SaveMethodTable(image, pMT, flags);
8647 }
8648 }
8649 else if (TypeFromToken(token) == ibcTypeSpec)
8650 {
8651 CORBBTPROF_BLOB_ENTRY *pBlobEntry = profileData->GetBlobStream();
8652 if (pBlobEntry)
8653 {
8654 while (pBlobEntry->TypeIsValid())
8655 {
8656 if (TypeFromToken(pBlobEntry->token) == ibcTypeSpec)
8657 {
8658 _ASSERTE(pBlobEntry->type == ParamTypeSpec);
8659
8660 if (pBlobEntry->token == token)
8661 {
8662 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY *) pBlobEntry;
8663 TypeHandle th = LoadIBCTypeHelper(image, pBlobSigEntry);
8664
8665 if (!th.IsNull())
8666 {
8667 // When we have stale IBC data the type could have been rejected from this image.
8668 if (image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(th.AsPtr())))
8669 {
8670 SaveTypeHandle(image, th, flags);
8671 }
8672 }
8673 }
8674 }
8675 pBlobEntry = pBlobEntry->GetNextEntry();
8676 }
8677 _ASSERTE(pBlobEntry->type == EndOfBlobStream);
8678 }
8679 }
8680 }
8681
8682 if (m_pAvailableParamTypes != NULL)
8683 {
8684 // If we have V1 IBC data then we save the hot
8685 // out-of-module generic instantiations here
8686
8687 CORBBTPROF_TOKEN_INFO * tokens_begin = profileData->GetTokenFlagsData(GenericTypeProfilingData);
8688 CORBBTPROF_TOKEN_INFO * tokens_end = tokens_begin + profileData->GetTokenFlagsCount(GenericTypeProfilingData);
8689
8690 if (tokens_begin != tokens_end)
8691 {
8692 SArray<CORBBTPROF_TOKEN_INFO> tokens(tokens_begin, tokens_end);
8693 tokens_begin = &tokens[0];
8694 tokens_end = tokens_begin + tokens.GetCount();
8695
8696 util::sort(tokens_begin, tokens_end);
8697
8698 // enumerate AvailableParamTypes map and find all hot generic instantiations
8699 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
8700 EETypeHashEntry *pEntry;
8701 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
8702 {
8703 TypeHandle t = pEntry->GetTypeHandle();
8704#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
8705 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_5);
8706#endif
8707
8708 if (t.HasInstantiation())
8709 {
8710 SString tokenName;
8711 t.GetName(tokenName);
8712 unsigned cur_token = tokenName.Hash() & 0xffff;
8713
8714 CORBBTPROF_TOKEN_INFO * found = util::lower_bound(tokens_begin, tokens_end, CORBBTPROF_TOKEN_INFO(cur_token));
8715 if (found != tokens_end && found->token == cur_token && (found->flags & (1 << ReadMethodTable)))
8716 {
8717 // When we have stale IBC data the type could have been rejected from this image.
8718 if (image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(t.AsPtr())))
8719 SaveTypeHandle(image, t, found->flags);
8720 }
8721 }
8722 }
8723 }
8724 }
8725 }
8726
8727 //
8728 // Now save any types in the TypeDefToMethodTableMap map
8729
8730 {
8731 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
8732
8733 while (typeDefIter.Next())
8734 {
8735 MethodTable * pMT = typeDefIter.GetElement();
8736
8737 if (pMT != NULL &&
8738 !image->IsStored(pMT) && pMT->IsFullyLoaded())
8739 {
8740 image->BeginAssociatingStoredObjectsWithMethodTable(pMT);
8741 SaveMethodTable(image, pMT, 0);
8742 image->EndAssociatingStoredObjectsWithMethodTable();
8743 }
8744 }
8745 }
8746
8747 //
8748 // Now save any TypeDescs in m_GenericParamToDescMap map
8749
8750 {
8751 LookupMap<PTR_TypeVarTypeDesc>::Iterator genericParamIter(&m_GenericParamToDescMap);
8752
8753 while (genericParamIter.Next())
8754 {
8755 TypeVarTypeDesc *pTD = genericParamIter.GetElement();
8756
8757 if (pTD != NULL)
8758 {
8759 pTD->Save(image);
8760 }
8761 }
8762 }
8763
8764#ifdef _DEBUG
8765 SealGenericTypesAndMethods();
8766#endif
8767
8768 //
8769 // Now save any types in the AvailableParamTypes map
8770 //
8771 if (m_pAvailableParamTypes != NULL)
8772 {
8773 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
8774 EETypeHashEntry *pEntry;
8775 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
8776 {
8777 TypeHandle t = pEntry->GetTypeHandle();
8778
8779 if (image->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(t.AsPtr())))
8780 {
8781 if (t.GetCanonicalMethodTable() != NULL)
8782 {
8783 image->BeginAssociatingStoredObjectsWithMethodTable(t.GetCanonicalMethodTable());
8784 SaveTypeHandle(image, t, 0);
8785 image->EndAssociatingStoredObjectsWithMethodTable();
8786 }
8787 else
8788 {
8789 SaveTypeHandle(image, t, 0);
8790 }
8791 }
8792 }
8793 }
8794
8795 //
8796 // Now save any methods in the InstMethodHashTable
8797 //
8798 if (m_pInstMethodHashTable != NULL)
8799 {
8800 //
8801 // Find all MethodDescs that we are going to save, and hash them with MethodTable as the key
8802 //
8803
8804 typedef SHash<MethodDescByMethodTableTraits> MethodDescByMethodTableHash;
8805
8806 MethodDescByMethodTableHash methodDescs;
8807
8808 InstMethodHashTable::Iterator it(m_pInstMethodHashTable);
8809 InstMethodHashEntry *pEntry;
8810 while (m_pInstMethodHashTable->FindNext(&it, &pEntry))
8811 {
8812 MethodDesc *pMD = pEntry->GetMethod();
8813
8814 _ASSERTE(!pMD->IsTightlyBoundToMethodTable());
8815
8816 if (!image->IsStored(pMD) &&
8817 image->GetPreloader()->IsMethodInTransitiveClosureOfInstantiations(CORINFO_METHOD_HANDLE(pMD)))
8818 {
8819 methodDescs.Add(pMD);
8820 }
8821 }
8822
8823 //
8824 // Save all MethodDescs on the same MethodTable using one chunk builder
8825 //
8826
8827 for (MethodDescByMethodTableHash::Iterator i1 = methodDescs.Begin(), end1 = methodDescs.End(); i1 != end1; i1++)
8828 {
8829 MethodDesc * pMD = *(i1);
8830 if (image->IsStored(pMD))
8831 continue;
8832
8833 MethodTable * pMT = pMD->GetMethodTable();
8834
8835 MethodDesc::SaveChunk methodDescSaveChunk(image);
8836
8837 for (MethodDescByMethodTableHash::KeyIterator i2 = methodDescs.Begin(pMT), end2 = methodDescs.End(pMT); i2 != end2; i2++)
8838 {
8839 _ASSERTE(!image->IsStored(*i2));
8840 methodDescSaveChunk.Append(*i2);
8841 }
8842
8843 methodDescSaveChunk.Save();
8844 }
8845 }
8846
8847 // Now save the tables themselves
8848 if (m_pAvailableParamTypes != NULL)
8849 {
8850 m_pAvailableParamTypes->Save(image, this, profileData);
8851 }
8852
8853 if (m_pInstMethodHashTable != NULL)
8854 {
8855 m_pInstMethodHashTable->Save(image, profileData);
8856 }
8857
8858 {
8859 MethodTable * pStubMT = GetILStubCache()->GetStubMethodTable();
8860 if (pStubMT != NULL)
8861 {
8862 SaveMethodTable(image, pStubMT, 0);
8863 }
8864 }
8865
8866 if (m_pStubMethodHashTable != NULL)
8867 {
8868 m_pStubMethodHashTable->Save(image, profileData);
8869 }
8870
8871#ifdef FEATURE_COMINTEROP
8872 // the type saving operations above had the side effect of populating m_pGuidToTypeHash
8873 if (m_pGuidToTypeHash != NULL)
8874 {
8875 m_pGuidToTypeHash->Save(image, profileData);
8876 }
8877#endif // FEATURE_COMINTEROP
8878
8879 // Compute and save the property name set
8880 PrecomputeMatchingProperties(image);
8881 image->StoreStructure(m_propertyNameSet,
8882 m_nPropertyNameSet * sizeof(BYTE),
8883 DataImage::ITEM_PROPERTY_NAME_SET);
8884
8885
8886 // Sort the list of RVA statics in an ascending order wrt the RVA
8887 // and save them.
8888 image->SaveRvaStructure();
8889
8890 // Save static data
8891 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Saving module static data\n"));
8892
8893 // We have this scenario where ngen will fail to load some classes but will generate
8894 // a valid exe, or it will choose not to save some loaded classes due to some error
8895 // conditions, where statics will be committed at runtime for the classes that ngen
8896 // wasn't able to load or save. So we can't cut down the static block size blindly if we've
8897 // failed to load or save any class. We don't think this scenario deserves complicated code
8898 // paths to get the extra working set perf (you would be pulling in the jitter if
8899 // you need any of these classes), So we are basically simplifying this down, if we failed
8900 // to load or save any class we won't compress the statics block and will persist the original
8901 // estimation.
8902
8903 // All classes were loaded and saved, cut down the block
8904 if (AreAllClassesFullyLoaded())
8905 {
8906 // Set a mark indicating we had all our classes loaded
8907 m_pRegularStaticOffsets = (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED;
8908 m_pThreadStaticOffsets = (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED;
8909 }
8910 else
8911 {
8912 // Since not all of the classes loaded we want to zero the pointers to the offset tables so they'll be
8913 // recalculated at runtime. But we can't do that here since we might try to reload some of the failed
8914 // types during the arrange phase (as the result of trying to parse profiling data). So we'll defer
8915 // zero'ing anything until the fixup phase.
8916
8917 // Not all classes were stored, revert to uncompressed maps to support run-time changes
8918 m_TypeDefToMethodTableMap.ConvertSavedMapToUncompressed(image, DataImage::ITEM_TYPEDEF_MAP);
8919 m_MethodDefToDescMap.ConvertSavedMapToUncompressed(image, DataImage::ITEM_METHODDEF_MAP);
8920 }
8921
8922 m_ModuleCtorInfo.Save(image, profileData);
8923 image->BindPointer(&m_ModuleCtorInfo, pModuleNode, offsetof(Module, m_ModuleCtorInfo));
8924
8925 if (m_pDynamicStaticsInfo)
8926 {
8927 image->StoreStructure(m_pDynamicStaticsInfo, m_maxDynamicEntries*sizeof(DynamicStaticsInfo),
8928 DataImage::ITEM_DYNAMIC_STATICS_INFO_TABLE);
8929 }
8930
8931 InlineTrackingMap *inlineTrackingMap = image->GetInlineTrackingMap();
8932 if (inlineTrackingMap)
8933 {
8934 m_pPersistentInlineTrackingMapNGen = new (image->GetHeap()) PersistentInlineTrackingMapNGen(this);
8935 m_pPersistentInlineTrackingMapNGen->Save(image, inlineTrackingMap);
8936 }
8937
8938 if (m_pNgenStats && g_CorCompileVerboseLevel >= CORCOMPILE_STATS)
8939 {
8940 GetSvcLogger()->Printf ("%-35s: %s\n", "MethodTable Restore Reason", "Count");
8941 DWORD dwTotal = 0;
8942 for (int i=0; i<TotalMethodTables; i++)
8943 {
8944 GetSvcLogger()->Printf ("%-35s: %d\n", MethodTableRestoreReasonDescription[i], m_pNgenStats->MethodTableRestoreNumReasons[i]);
8945 dwTotal += m_pNgenStats->MethodTableRestoreNumReasons[i];
8946 }
8947 GetSvcLogger()->Printf ("%-35s: %d\n", "TotalMethodTablesNeedRestore", dwTotal);
8948 GetSvcLogger()->Printf ("%-35s: %d\n", MethodTableRestoreReasonDescription[TotalMethodTables], m_pNgenStats->MethodTableRestoreNumReasons[TotalMethodTables]);
8949 }
8950}
8951
8952
8953#ifdef _DEBUG
8954//
8955// We call these methods to seal the
8956// lists: m_pAvailableClasses and m_pAvailableParamTypes
8957//
8958void Module::SealGenericTypesAndMethods()
8959{
8960 LIMITED_METHOD_CONTRACT;
8961 // Enforce that after this point in ngen that no more types or methods will be loaded.
8962 //
8963 // We increment the seal count here and only decrement it after we have completed the ngen image
8964 //
8965 if (m_pAvailableParamTypes != NULL)
8966 {
8967 m_pAvailableParamTypes->Seal();
8968 }
8969 if (m_pInstMethodHashTable != NULL)
8970 {
8971 m_pInstMethodHashTable->Seal();
8972 }
8973}
8974//
8975// We call these methods to unseal the
8976// lists: m_pAvailableClasses and m_pAvailableParamTypes
8977//
8978void Module::UnsealGenericTypesAndMethods()
8979{
8980 LIMITED_METHOD_CONTRACT;
8981 // Allow us to create generic types and methods again
8982 //
8983 // We only decrement it after we have completed the ngen image
8984 //
8985 if (m_pAvailableParamTypes != NULL)
8986 {
8987 m_pAvailableParamTypes->Unseal();
8988 }
8989 if (m_pInstMethodHashTable != NULL)
8990 {
8991 m_pInstMethodHashTable->Unseal();
8992 }
8993}
8994#endif
8995
8996
8997void Module::PrepopulateDictionaries(DataImage *image, BOOL nonExpansive)
8998{
8999 STANDARD_VM_CONTRACT;
9000
9001 // Prepopulating the dictionaries for instantiated types
9002 // is in theory an iteraive process, i.e. filling in
9003 // a dictionary slot may result in a class load of a new type whose
9004 // dictionary may itself need to be prepopulated. The type expressions
9005 // involved can get larger, so there's no a-priori reason to expect this
9006 // process to terminate.
9007 //
9008 // Given a starting set of instantiated types, several strategies are
9009 // thus possible - no prepopulation (call this PP0), or
9010 // prepopulate only the dictionaries of the types that are in the initial
9011 // set (call this PP1), or do two iterations (call this PP2) etc. etc.
9012 // Whichever strategy we choose we can always afford to do
9013 // one round of prepopulation where we populate slots
9014 // whose corresponding resulting method/types are already loaded.
9015 // Call this PPn+PP-FINAL.
9016 //
9017 // Below we implement PP1+PP-FINAL for instantiated types and PP0+PP-FINAL
9018 // for instantiations of generic methods. We use PP1 because most collection
9019 // classes (List, Dictionary etc.) only require one pass of prepopulation in order
9020 // to fully prepopulate the dictionary.
9021
9022 // Do PP1 for instantiated types... Do one iteration where we force type loading...
9023 // Because this phase may cause new entries to appear in the hash table we
9024 // copy the array of types to the stack before we do anything else.
9025 if (!nonExpansive && CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Prepopulate1))
9026 {
9027 if (m_pAvailableParamTypes != NULL)
9028 {
9029 // Create a local copy in case the new elements are added to the hashtable during population
9030 InlineSArray<TypeHandle, 20> pTypes;
9031
9032 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
9033 EETypeHashEntry *pEntry;
9034 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
9035 {
9036 TypeHandle th = pEntry->GetTypeHandle();
9037 if (th.IsTypeDesc())
9038 continue;
9039
9040 // Don't do prepopulation for open types - they shouldn't really have dictionaries anyway.
9041 MethodTable * pMT = th.AsMethodTable();
9042 if (pMT->ContainsGenericVariables())
9043 continue;
9044
9045 // Only do PP1 on things that land in their preferred Zap module.
9046 // Forcing the load of dictionary entries in the case where we are
9047 // speculatively saving a copy of an instantiation outside its preferred
9048 // zap module is too expensive for the common collection class cases.
9049 ///
9050 // Invalid generic instantiations will not be fully loaded.
9051 // We want to ignore them as touching them will re-raise the TypeLoadException
9052 if (pMT->IsFullyLoaded() && image->GetModule() == GetPreferredZapModuleForMethodTable(pMT))
9053 {
9054 pTypes.Append(th);
9055 }
9056 }
9057 it.Reset();
9058
9059 for(COUNT_T i = 0; i < pTypes.GetCount(); i ++)
9060 {
9061 TypeHandle th = pTypes[i];
9062 _ASSERTE(image->GetModule() == GetPreferredZapModuleForTypeHandle(th) );
9063 _ASSERTE(!th.IsTypeDesc() && !th.ContainsGenericVariables());
9064 th.AsMethodTable()->PrepopulateDictionary(image, FALSE /* not nonExpansive, i.e. can load types */);
9065 }
9066 }
9067 }
9068
9069 // PP-FINAL for instantiated types.
9070 // This is the final stage where we hardbind any remaining entries that map
9071 // to results that have already been loaded...
9072 // Thus we set the "nonExpansive" flag on PrepopulateDictionary
9073 // below, which may in turn greatly limit the amount of prepopulating we do
9074 // (partly because it's quite difficult to determine if some potential entries
9075 // in the dictionary are already loaded)
9076
9077 if (m_pAvailableParamTypes != NULL)
9078 {
9079 INDEBUG(DWORD nTypes = m_pAvailableParamTypes->GetCount());
9080
9081 EETypeHashTable::Iterator it(m_pAvailableParamTypes);
9082 EETypeHashEntry *pEntry;
9083 while (m_pAvailableParamTypes->FindNext(&it, &pEntry))
9084 {
9085 TypeHandle th = pEntry->GetTypeHandle();
9086 if (th.IsTypeDesc())
9087 continue;
9088
9089 MethodTable * pMT = th.AsMethodTable();
9090 if (pMT->ContainsGenericVariables())
9091 continue;
9092
9093 pMT->PrepopulateDictionary(image, TRUE /* nonExpansive */);
9094 }
9095
9096 // No new instantiations should be added by nonExpansive prepopulation
9097 _ASSERTE(nTypes == m_pAvailableParamTypes->GetCount());
9098 }
9099
9100 // PP-FINAL for instantiations of generic methods.
9101 if (m_pInstMethodHashTable != NULL)
9102 {
9103 INDEBUG(DWORD nMethods = m_pInstMethodHashTable->GetCount());
9104
9105 InstMethodHashTable::Iterator it(m_pInstMethodHashTable);
9106 InstMethodHashEntry *pEntry;
9107 while (m_pInstMethodHashTable->FindNext(&it, &pEntry))
9108 {
9109 MethodDesc *pMD = pEntry->GetMethod();
9110 if (!pMD->ContainsGenericVariables())
9111 {
9112 pMD->PrepopulateDictionary(image, TRUE /* nonExpansive */);
9113 }
9114 }
9115
9116 // No new instantiations should be added by nonExpansive prepopulation
9117 _ASSERTE(nMethods == m_pInstMethodHashTable->GetCount());
9118 }
9119}
9120
9121void Module::PlaceType(DataImage *image, TypeHandle th, DWORD profilingFlags)
9122{
9123 STANDARD_VM_CONTRACT;
9124
9125 if (th.IsNull())
9126 return;
9127
9128 MethodTable *pMT = th.GetMethodTable();
9129
9130 if (pMT && pMT->GetLoaderModule() == this)
9131 {
9132 EEClass *pClass = pMT->GetClass();
9133
9134 if (profilingFlags & (1 << WriteMethodTableWriteableData))
9135 {
9136 image->PlaceStructureForAddress(pMT->GetWriteableData(),CORCOMPILE_SECTION_WRITE);
9137 }
9138
9139 if (profilingFlags & (1 << ReadMethodTable))
9140 {
9141 CorCompileSection section = CORCOMPILE_SECTION_READONLY_HOT;
9142 if (pMT->IsWriteable())
9143 section = CORCOMPILE_SECTION_HOT_WRITEABLE;
9144 image->PlaceStructureForAddress(pMT, section);
9145
9146 if (pMT->HasInterfaceMap())
9147 image->PlaceInternedStructureForAddress(pMT->GetInterfaceMap(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9148
9149 MethodTable::VtableIndirectionSlotIterator it = pMT->IterateVtableIndirectionSlots();
9150 while (it.Next())
9151 {
9152 image->PlaceInternedStructureForAddress(it.GetIndirectionSlot(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9153 }
9154
9155 image->PlaceStructureForAddress(pMT->GetWriteableData(), CORCOMPILE_SECTION_HOT);
9156 }
9157
9158 if (profilingFlags & (1 << ReadNonVirtualSlots))
9159 {
9160 if (pMT->HasNonVirtualSlotsArray())
9161 image->PlaceStructureForAddress(pMT->GetNonVirtualSlotsArray(), CORCOMPILE_SECTION_READONLY_HOT);
9162 }
9163
9164 if (profilingFlags & (1 << ReadDispatchMap) && pMT->HasDispatchMapSlot())
9165 {
9166 image->PlaceInternedStructureForAddress(pMT->GetDispatchMap(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9167 }
9168
9169 if (profilingFlags & (1 << WriteEEClass))
9170 {
9171 image->PlaceStructureForAddress(pClass, CORCOMPILE_SECTION_WRITE);
9172
9173 if (pClass->HasOptionalFields())
9174 image->PlaceStructureForAddress(pClass->GetOptionalFields(), CORCOMPILE_SECTION_WRITE);
9175 }
9176
9177 else if (profilingFlags & (1 << ReadEEClass))
9178 {
9179 image->PlaceStructureForAddress(pClass, CORCOMPILE_SECTION_HOT);
9180
9181 if (pClass->HasOptionalFields())
9182 image->PlaceStructureForAddress(pClass->GetOptionalFields(), CORCOMPILE_SECTION_HOT);
9183
9184 if (pClass->GetVarianceInfo() != NULL)
9185 image->PlaceInternedStructureForAddress(pClass->GetVarianceInfo(), CORCOMPILE_SECTION_READONLY_WARM, CORCOMPILE_SECTION_READONLY_WARM);
9186
9187#ifdef FEATURE_COMINTEROP
9188 if (pClass->GetSparseCOMInteropVTableMap() != NULL)
9189 {
9190 image->PlaceStructureForAddress(pClass->GetSparseCOMInteropVTableMap(), CORCOMPILE_SECTION_WARM);
9191 image->PlaceInternedStructureForAddress(pClass->GetSparseCOMInteropVTableMap()->GetMapList(), CORCOMPILE_SECTION_READONLY_WARM, CORCOMPILE_SECTION_READONLY_WARM);
9192 }
9193#endif
9194 }
9195
9196 if (profilingFlags & (1 << ReadFieldDescs))
9197 {
9198 image->PlaceStructureForAddress(pMT->GetApproxFieldDescListRaw(), CORCOMPILE_SECTION_READONLY_HOT);
9199 }
9200
9201 if (profilingFlags != 0)
9202 {
9203 if (pMT->HasPerInstInfo())
9204 {
9205 DPTR(MethodTable::PerInstInfoElem_t) pPerInstInfo = pMT->GetPerInstInfo();
9206
9207 BOOL fIsEagerBound = pMT->CanEagerBindToParentDictionaries(image, NULL);
9208
9209 if (fIsEagerBound)
9210 {
9211 if (MethodTable::PerInstInfoElem_t::isRelative)
9212 {
9213 image->PlaceStructureForAddress(pPerInstInfo, CORCOMPILE_SECTION_READONLY_HOT);
9214 }
9215 else
9216 {
9217 image->PlaceInternedStructureForAddress(pPerInstInfo, CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9218 }
9219 }
9220 else
9221 {
9222 image->PlaceStructureForAddress(pPerInstInfo, CORCOMPILE_SECTION_WRITE);
9223 }
9224 }
9225
9226 Dictionary * pDictionary = pMT->GetDictionary();
9227 if (pDictionary != NULL)
9228 {
9229 BOOL fIsWriteable;
9230
9231 if (!pMT->IsCanonicalMethodTable())
9232 {
9233 // CanEagerBindToMethodTable would not work for targeted patching here. The dictionary
9234 // layout is sensitive to compilation order that can be changed by TP compatible changes.
9235 BOOL canSaveSlots = (image->GetModule() == pMT->GetCanonicalMethodTable()->GetLoaderModule());
9236
9237 fIsWriteable = pDictionary->IsWriteable(image, canSaveSlots,
9238 pMT->GetNumGenericArgs(),
9239 pMT->GetModule(),
9240 pClass->GetDictionaryLayout());
9241 }
9242 else
9243 {
9244 fIsWriteable = FALSE;
9245 }
9246
9247 if (fIsWriteable)
9248 {
9249 image->PlaceStructureForAddress(pDictionary, CORCOMPILE_SECTION_HOT_WRITEABLE);
9250 image->PlaceStructureForAddress(pClass->GetDictionaryLayout(), CORCOMPILE_SECTION_WARM);
9251 }
9252 else
9253 {
9254 image->PlaceInternedStructureForAddress(pDictionary, CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9255 }
9256 }
9257 }
9258
9259 if (profilingFlags & (1 << ReadFieldMarshalers))
9260 {
9261 if (pClass->HasLayout() && pClass->GetLayoutInfo()->GetNumCTMFields() > 0)
9262 {
9263 image->PlaceStructureForAddress((void *)pClass->GetLayoutInfo()->GetFieldMarshalers(), CORCOMPILE_SECTION_HOT);
9264 }
9265 }
9266 }
9267 if (th.IsTypeDesc())
9268 {
9269 if (profilingFlags & (1 << WriteTypeDesc))
9270 image->PlaceStructureForAddress(th.AsTypeDesc(), CORCOMPILE_SECTION_WRITE);
9271 else if (profilingFlags & (1 << ReadTypeDesc))
9272 image->PlaceStructureForAddress(th.AsTypeDesc(), CORCOMPILE_SECTION_HOT);
9273 else
9274 image->PlaceStructureForAddress(th.AsTypeDesc(), CORCOMPILE_SECTION_WARM);
9275 }
9276}
9277
9278void Module::PlaceMethod(DataImage *image, MethodDesc *pMD, DWORD profilingFlags)
9279{
9280 STANDARD_VM_CONTRACT;
9281
9282 if (pMD == NULL)
9283 return;
9284
9285 if (pMD->GetLoaderModule() != this)
9286 return;
9287
9288 if (profilingFlags & (1 << ReadMethodCode))
9289 {
9290 if (pMD->IsNDirect())
9291 {
9292 NDirectMethodDesc *pNMD = (NDirectMethodDesc *)pMD;
9293 image->PlaceStructureForAddress((void*) pNMD->GetWriteableData(), CORCOMPILE_SECTION_WRITE);
9294
9295#ifdef HAS_NDIRECT_IMPORT_PRECODE
9296 // The NDirect import thunk glue is used only if no marshaling is required
9297 if (!pNMD->MarshalingRequired())
9298 {
9299 image->PlaceStructureForAddress((void*) pNMD->GetNDirectImportThunkGlue(), CORCOMPILE_SECTION_METHOD_PRECODE_HOT);
9300 }
9301#endif // HAS_NDIRECT_IMPORT_PRECODE
9302
9303 // Late bound NDirect methods require their LibName at startup.
9304 if (!pNMD->IsQCall())
9305 {
9306 image->PlaceStructureForAddress((void*) pNMD->GetLibName(), CORCOMPILE_SECTION_READONLY_HOT);
9307 image->PlaceStructureForAddress((void*) pNMD->GetEntrypointName(), CORCOMPILE_SECTION_READONLY_HOT);
9308 }
9309 }
9310
9311#ifdef FEATURE_COMINTEROP
9312 if (pMD->IsComPlusCall())
9313 {
9314 ComPlusCallMethodDesc *pCMD = (ComPlusCallMethodDesc *)pMD;
9315
9316 // If the ComPlusCallMethodDesc was actually used for interop, its ComPlusCallInfo should be hot.
9317 image->PlaceStructureForAddress((void*) pCMD->m_pComPlusCallInfo, CORCOMPILE_SECTION_HOT);
9318 }
9319#endif // FEATURE_COMINTEROP
9320
9321 // Stubs-as-IL have writeable signatures sometimes, so can't place them
9322 // into read-only section. We should not get here for stubs-as-il anyway,
9323 // but we will filter them out just to be sure.
9324 if (pMD->HasStoredSig() && !pMD->IsILStub())
9325 {
9326 StoredSigMethodDesc *pSMD = (StoredSigMethodDesc*) pMD;
9327
9328 if (pSMD->HasStoredMethodSig())
9329 {
9330 image->PlaceInternedStructureForAddress((void*) pSMD->GetStoredMethodSig(), CORCOMPILE_SECTION_READONLY_SHARED_HOT, CORCOMPILE_SECTION_READONLY_HOT);
9331 }
9332 }
9333 }
9334
9335 // We store the entire hot chunk in the SECTION_WRITE section
9336 if (profilingFlags & (1 << WriteMethodDesc))
9337 {
9338 image->PlaceStructureForAddress(pMD, CORCOMPILE_SECTION_WRITE);
9339 }
9340
9341
9342 if (profilingFlags & (1 << WriteMethodPrecode))
9343 {
9344 Precode* pPrecode = pMD->GetSavedPrecodeOrNull(image);
9345 // protect against stale IBC data
9346 if (pPrecode != NULL)
9347 {
9348 CorCompileSection section = CORCOMPILE_SECTION_METHOD_PRECODE_WRITE;
9349 if (pPrecode->IsPrebound(image))
9350 section = CORCOMPILE_SECTION_METHOD_PRECODE_HOT;
9351 // Note: This is going to place the entire PRECODE_FIXUP chunk if we have one
9352 image->PlaceStructureForAddress(pPrecode, section);
9353 }
9354 }
9355 else if (profilingFlags & (1 << ReadMethodPrecode))
9356 {
9357 Precode* pPrecode = pMD->GetSavedPrecodeOrNull(image);
9358 // protect against stale IBC data
9359 if (pPrecode != NULL)
9360 {
9361 // Note: This is going to place the entire PRECODE_FIXUP chunk if we have one
9362 image->PlaceStructureForAddress(pPrecode, CORCOMPILE_SECTION_METHOD_PRECODE_HOT);
9363 }
9364 }
9365}
9366
9367void Module::Arrange(DataImage *image)
9368{
9369 STANDARD_VM_CONTRACT;
9370
9371 // We collect IBC logging profiling data and use that to guide the layout of the image.
9372 image->PlaceStructureForAddress(this, CORCOMPILE_SECTION_MODULE);
9373
9374 // The stub method table is shared by all IL stubs in the module, so place it into the hot section
9375 MethodTable * pStubMT = GetILStubCache()->GetStubMethodTable();
9376 if (pStubMT != NULL)
9377 PlaceType(image, pStubMT, ReadMethodTable);
9378
9379 CorProfileData * profileData = GetProfileData();
9380 if (profileData)
9381 {
9382 //
9383 // Place hot type structues in the order specifiled by TypeProfilingData array
9384 //
9385 CORBBTPROF_TOKEN_INFO * pTypeProfilingData = profileData->GetTokenFlagsData(TypeProfilingData);
9386 DWORD cTypeProfilingData = profileData->GetTokenFlagsCount(TypeProfilingData);
9387 for (unsigned int i = 0; (i < cTypeProfilingData); i++)
9388 {
9389 CORBBTPROF_TOKEN_INFO * entry = &pTypeProfilingData[i];
9390 mdToken token = entry->token;
9391 DWORD flags = entry->flags;
9392#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
9393 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_6);
9394#endif
9395
9396 if (TypeFromToken(token) == mdtTypeDef)
9397 {
9398 TypeHandle th = LookupTypeDef(token);
9399 //
9400 // Place a hot normal type and it's data
9401 //
9402 PlaceType(image, th, flags);
9403 }
9404 else if (TypeFromToken(token) == ibcTypeSpec)
9405 {
9406 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = profileData->GetBlobSigEntry(token);
9407
9408 if (pBlobSigEntry == NULL)
9409 {
9410 //
9411 // Print an error message for the type load failure
9412 //
9413 StackSString msg(W("Did not find definition for type token "));
9414
9415 char buff[16];
9416 sprintf_s(buff, COUNTOF(buff), "%08x", token);
9417 StackSString szToken(SString::Ascii, &buff[0]);
9418 msg += szToken;
9419 msg += W(" in profile data.\n");
9420
9421 GetSvcLogger()->Log(msg, LogLevel_Info);
9422 }
9423 else // (pBlobSigEntry != NULL)
9424 {
9425 _ASSERTE(pBlobSigEntry->blob.token == token);
9426 //
9427 // decode generic type signature
9428 //
9429 TypeHandle th = LoadIBCTypeHelper(image, pBlobSigEntry);
9430
9431 //
9432 // Place a hot instantiated type and it's data
9433 //
9434 PlaceType(image, th, flags);
9435 }
9436 }
9437 else if (TypeFromToken(token) == mdtFieldDef)
9438 {
9439 FieldDesc *pFD = LookupFieldDef(token);
9440 if (pFD && pFD->IsRVA())
9441 {
9442 if (entry->flags & (1 << RVAFieldData))
9443 {
9444 BYTE *pRVAData = (BYTE*) pFD->GetStaticAddressHandle(NULL);
9445 //
9446 // Place a hot RVA static field
9447 //
9448 image->PlaceStructureForAddress(pRVAData, CORCOMPILE_SECTION_RVA_STATICS_HOT);
9449 }
9450 }
9451 }
9452 }
9453
9454 //
9455 // Place hot methods and method data in the order specifiled by MethodProfilingData array
9456 //
9457 CORBBTPROF_TOKEN_INFO * pMethodProfilingData = profileData->GetTokenFlagsData(MethodProfilingData);
9458 DWORD cMethodProfilingData = profileData->GetTokenFlagsCount(MethodProfilingData);
9459 for (unsigned int i = 0; (i < cMethodProfilingData); i++)
9460 {
9461 mdToken token = pMethodProfilingData[i].token;
9462 DWORD profilingFlags = pMethodProfilingData[i].flags;
9463#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
9464 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_7);
9465#endif
9466
9467 if (TypeFromToken(token) == mdtMethodDef)
9468 {
9469 MethodDesc * pMD = LookupMethodDef(token);
9470 //
9471 // Place a hot normal method and it's data
9472 //
9473 PlaceMethod(image, pMD, profilingFlags);
9474 }
9475 else if (TypeFromToken(token) == ibcMethodSpec)
9476 {
9477 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = profileData->GetBlobSigEntry(token);
9478
9479 if (pBlobSigEntry == NULL)
9480 {
9481 //
9482 // Print an error message for the type load failure
9483 //
9484 StackSString msg(W("Did not find definition for method token "));
9485
9486 char buff[16];
9487 sprintf_s(buff, COUNTOF(buff), "%08x", token);
9488 StackSString szToken(SString::Ascii, &buff[0]);
9489 msg += szToken;
9490 msg += W(" in profile data.\n");
9491
9492 GetSvcLogger()->Log(msg, LogLevel_Info);
9493 }
9494 else // (pBlobSigEntry != NULL)
9495 {
9496 _ASSERTE(pBlobSigEntry->blob.token == token);
9497 MethodDesc * pMD = LoadIBCMethodHelper(image, pBlobSigEntry);
9498
9499 if (pMD != NULL)
9500 {
9501 //
9502 // Place a hot instantiated method and it's data
9503 //
9504 PlaceMethod(image, pMD, profilingFlags);
9505 }
9506 }
9507 }
9508 }
9509 }
9510
9511 // Now place all remaining items
9512 image->PlaceRemainingStructures();
9513}
9514
9515void ModuleCtorInfo::Fixup(DataImage *image)
9516{
9517 STANDARD_VM_CONTRACT;
9518
9519 if (numElementsHot > 0)
9520 {
9521 image->FixupPointerField(this, offsetof(ModuleCtorInfo, cctorInfoHot));
9522 image->FixupPointerField(this, offsetof(ModuleCtorInfo, hotHashOffsets));
9523 }
9524 else
9525 {
9526 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, cctorInfoHot));
9527 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, hotHashOffsets));
9528 }
9529
9530 _ASSERTE(numElements > numElementsHot || numElements == numElementsHot);
9531 if (numElements > numElementsHot)
9532 {
9533 image->FixupPointerField(this, offsetof(ModuleCtorInfo, cctorInfoCold));
9534 image->FixupPointerField(this, offsetof(ModuleCtorInfo, coldHashOffsets));
9535 }
9536 else
9537 {
9538 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, cctorInfoCold));
9539 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, coldHashOffsets));
9540 }
9541
9542 if (numElements > 0)
9543 {
9544 image->FixupPointerField(this, offsetof(ModuleCtorInfo, ppMT));
9545
9546 for (DWORD i=0; i<numElements; i++)
9547 {
9548 image->FixupRelativePointerField(ppMT, i * sizeof(ppMT[0]));
9549 }
9550 }
9551 else
9552 {
9553 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, ppMT));
9554 }
9555
9556 if (numHotGCStaticsMTs > 0)
9557 {
9558 image->FixupPointerField(this, offsetof(ModuleCtorInfo, ppHotGCStaticsMTs));
9559
9560 image->BeginRegion(CORINFO_REGION_HOT);
9561 for (DWORD i=0; i < numHotGCStaticsMTs; i++)
9562 {
9563 image->FixupMethodTablePointer(ppHotGCStaticsMTs, &ppHotGCStaticsMTs[i]);
9564 }
9565 image->EndRegion(CORINFO_REGION_HOT);
9566 }
9567 else
9568 {
9569 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, ppHotGCStaticsMTs));
9570 }
9571
9572 if (numColdGCStaticsMTs > 0)
9573 {
9574 image->FixupPointerField(this, offsetof(ModuleCtorInfo, ppColdGCStaticsMTs));
9575
9576 image->BeginRegion(CORINFO_REGION_COLD);
9577 for (DWORD i=0; i < numColdGCStaticsMTs; i++)
9578 {
9579 image->FixupMethodTablePointer(ppColdGCStaticsMTs, &ppColdGCStaticsMTs[i]);
9580 }
9581 image->EndRegion(CORINFO_REGION_COLD);
9582 }
9583 else
9584 {
9585 image->ZeroPointerField(this, offsetof(ModuleCtorInfo, ppColdGCStaticsMTs));
9586 }
9587}
9588
9589#ifdef _PREFAST_
9590#pragma warning(push)
9591#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
9592#endif
9593void Module::Fixup(DataImage *image)
9594{
9595 STANDARD_VM_CONTRACT;
9596
9597 // Propagate all changes to the image copy
9598 memcpy(image->GetImagePointer(this), (void*)this, sizeof(Module));
9599
9600 //
9601 // Zero out VTable
9602 //
9603
9604 image->ZeroPointerField(this, 0);
9605
9606 image->FixupPointerField(this, offsetof(Module, m_pNGenLayoutInfo));
9607
9608 image->ZeroField(this, offsetof(Module, m_pSimpleName), sizeof(m_pSimpleName));
9609
9610 image->ZeroField(this, offsetof(Module, m_file), sizeof(m_file));
9611
9612 image->FixupPointerField(this, offsetof(Module, m_pDllMain));
9613
9614 image->ZeroField(this, offsetof(Module, m_dwTransientFlags), sizeof(m_dwTransientFlags));
9615
9616 image->ZeroField(this, offsetof(Module, m_pVASigCookieBlock), sizeof(m_pVASigCookieBlock));
9617 image->ZeroField(this, offsetof(Module, m_pAssembly), sizeof(m_pAssembly));
9618 image->ZeroField(this, offsetof(Module, m_moduleRef), sizeof(m_moduleRef));
9619
9620 image->ZeroField(this, offsetof(Module, m_Crst), sizeof(m_Crst));
9621 image->ZeroField(this, offsetof(Module, m_FixupCrst), sizeof(m_FixupCrst));
9622
9623 image->ZeroField(this, offsetof(Module, m_pProfilingBlobTable), sizeof(m_pProfilingBlobTable));
9624 image->ZeroField(this, offsetof(Module, m_pProfileData), sizeof(m_pProfileData));
9625
9626 image->ZeroPointerField(this, offsetof(Module, m_pNgenStats));
9627
9628 // fixup the pointer for NeutralResourcesLanguage, if we have it cached
9629 if(!!(m_dwPersistedFlags & NEUTRAL_RESOURCES_LANGUAGE_IS_CACHED)) {
9630 image->FixupPointerField(this, offsetof(Module, m_pszCultureName));
9631 }
9632
9633 // Fixup the property name set
9634 image->FixupPointerField(this, offsetof(Module, m_propertyNameSet));
9635
9636 //
9637 // Fixup the method table
9638 //
9639
9640 image->ZeroField(this, offsetof(Module, m_pISymUnmanagedReader), sizeof(m_pISymUnmanagedReader));
9641 image->ZeroField(this, offsetof(Module, m_ISymUnmanagedReaderCrst), sizeof(m_ISymUnmanagedReaderCrst));
9642
9643 image->ZeroField(this, offsetof(Module, m_LookupTableCrst), sizeof(m_LookupTableCrst));
9644
9645 m_TypeDefToMethodTableMap.Fixup(image);
9646 m_TypeRefToMethodTableMap.Fixup(image, FALSE);
9647 m_MethodDefToDescMap.Fixup(image);
9648 m_FieldDefToDescMap.Fixup(image);
9649 if(m_pMemberRefToDescHashTable != NULL)
9650 {
9651 image->FixupPointerField(this, offsetof(Module, m_pMemberRefToDescHashTable));
9652 m_pMemberRefToDescHashTable->Fixup(image);
9653 }
9654 m_GenericParamToDescMap.Fixup(image);
9655 m_GenericTypeDefToCanonMethodTableMap.Fixup(image);
9656 m_FileReferencesMap.Fixup(image, FALSE);
9657 m_ManifestModuleReferencesMap.Fixup(image, FALSE);
9658 m_MethodDefToPropertyInfoMap.Fixup(image, FALSE);
9659
9660 image->ZeroPointerField(this, offsetof(Module, m_pILStubCache));
9661
9662 if (m_pAvailableClasses != NULL) {
9663 image->FixupPointerField(this, offsetof(Module, m_pAvailableClasses));
9664 m_pAvailableClasses->Fixup(image);
9665 }
9666
9667 image->ZeroField(this, offsetof(Module, m_pAvailableClassesCaseIns), sizeof(m_pAvailableClassesCaseIns));
9668 image->ZeroField(this, offsetof(Module, m_InstMethodHashTableCrst), sizeof(m_InstMethodHashTableCrst));
9669
9670 image->BeginRegion(CORINFO_REGION_COLD);
9671
9672 if (m_pAvailableParamTypes) {
9673 image->FixupPointerField(this, offsetof(Module, m_pAvailableParamTypes));
9674 m_pAvailableParamTypes->Fixup(image);
9675 }
9676
9677 if (m_pInstMethodHashTable) {
9678 image->FixupPointerField(this, offsetof(Module, m_pInstMethodHashTable));
9679 m_pInstMethodHashTable->Fixup(image);
9680 }
9681
9682 {
9683 MethodTable * pStubMT = GetILStubCache()->GetStubMethodTable();
9684 if (pStubMT != NULL)
9685 pStubMT->Fixup(image);
9686 }
9687
9688 if (m_pStubMethodHashTable) {
9689 image->FixupPointerField(this, offsetof(Module, m_pStubMethodHashTable));
9690 m_pStubMethodHashTable->Fixup(image);
9691 }
9692
9693#ifdef FEATURE_COMINTEROP
9694 if (m_pGuidToTypeHash) {
9695 image->FixupPointerField(this, offsetof(Module, m_pGuidToTypeHash));
9696 m_pGuidToTypeHash->Fixup(image);
9697 }
9698#endif // FEATURE_COMINTEROP
9699
9700 image->EndRegion(CORINFO_REGION_COLD);
9701
9702#ifdef _DEBUG
9703 //
9704 // Unseal the generic tables:
9705 //
9706 // - We need to run managed code to serialize the Security attributes of the ngen image
9707 // and we are now using generic types in the Security/Reflection code.
9708 // - Compilation of other modules of multimodule assemblies may add more types
9709 // to the generic tables.
9710 //
9711 UnsealGenericTypesAndMethods();
9712#endif
9713
9714 m_ModuleCtorInfo.Fixup(image);
9715
9716 //
9717 // Fixup binder
9718 //
9719
9720 if (m_pBinder != NULL)
9721 {
9722 image->FixupPointerField(this, offsetof(Module, m_pBinder));
9723 m_pBinder->Fixup(image);
9724 }
9725
9726
9727 //
9728 // Fixup classes
9729 //
9730
9731 {
9732 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
9733
9734 image->BeginRegion(CORINFO_REGION_COLD);
9735 while (typeDefIter.Next())
9736 {
9737 MethodTable * t = typeDefIter.GetElement();
9738 if (image->IsStored(t))
9739 t->Fixup(image);
9740 }
9741 image->EndRegion(CORINFO_REGION_COLD);
9742 }
9743
9744 {
9745 LookupMap<PTR_TypeRef>::Iterator typeRefIter(&m_TypeRefToMethodTableMap);
9746 DWORD rid = 0;
9747
9748 image->BeginRegion(CORINFO_REGION_HOT);
9749 while (typeRefIter.Next())
9750 {
9751 TADDR flags;
9752 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(typeRefIter.GetElementAndFlags(&flags)));
9753
9754 if (!th.IsNull())
9755 {
9756 if (th.GetLoaderModule() != this || image->IsStored(th.AsPtr()))
9757 {
9758 PTR_TADDR hotItemValuePtr = m_TypeRefToMethodTableMap.FindHotItemValuePtr(rid);
9759 BOOL fSet = FALSE;
9760
9761 if (image->CanEagerBindToTypeHandle(th))
9762 {
9763 if (image->CanHardBindToZapModule(th.GetLoaderModule()))
9764 {
9765 PVOID pTarget = th.IsTypeDesc() ? th.AsTypeDesc() : th.AsPtr();
9766 SSIZE_T offset = th.IsTypeDesc() ? 2 : 0;
9767
9768 _ASSERTE((flags & offset) == 0);
9769
9770 image->FixupField(m_TypeRefToMethodTableMap.pTable, rid * sizeof(TADDR),
9771 pTarget, flags | offset, IMAGE_REL_BASED_RelativePointer);
9772
9773 // In case this item is also in the hot item subtable, fix it up there as well
9774 if (hotItemValuePtr != NULL)
9775 {
9776 image->FixupField(m_TypeRefToMethodTableMap.hotItemList,
9777 (BYTE *)hotItemValuePtr - (BYTE *)m_TypeRefToMethodTableMap.hotItemList,
9778 pTarget, flags | offset, IMAGE_REL_BASED_RelativePointer);
9779 }
9780 fSet = TRUE;
9781 }
9782 else
9783 // Create the indirection only if the entry is hot or we do have indirection cell already
9784 if (hotItemValuePtr != NULL || image->GetExistingTypeHandleImport(th) != NULL)
9785 {
9786 _ASSERTE((flags & FIXUP_POINTER_INDIRECTION) == 0);
9787
9788 ZapNode * pImport = image->GetTypeHandleImport(th);
9789 image->FixupFieldToNode(m_TypeRefToMethodTableMap.pTable, rid * sizeof(TADDR),
9790 pImport, flags | FIXUP_POINTER_INDIRECTION, IMAGE_REL_BASED_RelativePointer);
9791 if (hotItemValuePtr != NULL)
9792 {
9793 image->FixupFieldToNode(m_TypeRefToMethodTableMap.hotItemList,
9794 (BYTE *)hotItemValuePtr - (BYTE *)m_TypeRefToMethodTableMap.hotItemList,
9795 pImport, flags | FIXUP_POINTER_INDIRECTION, IMAGE_REL_BASED_RelativePointer);
9796 }
9797 fSet = TRUE;
9798 }
9799 }
9800
9801 if (!fSet)
9802 {
9803 image->ZeroPointerField(m_TypeRefToMethodTableMap.pTable, rid * sizeof(TADDR));
9804 // In case this item is also in the hot item subtable, fix it up there as well
9805 if (hotItemValuePtr != NULL)
9806 {
9807 image->ZeroPointerField(m_TypeRefToMethodTableMap.hotItemList,
9808 (BYTE *)hotItemValuePtr - (BYTE *)m_TypeRefToMethodTableMap.hotItemList);
9809 }
9810 }
9811 }
9812 }
9813
9814 rid++;
9815 }
9816 image->EndRegion(CORINFO_REGION_HOT);
9817 }
9818
9819 {
9820 LookupMap<PTR_TypeVarTypeDesc>::Iterator genericParamIter(&m_GenericParamToDescMap);
9821
9822 while (genericParamIter.Next())
9823 {
9824 TypeVarTypeDesc * pTypeDesc = genericParamIter.GetElement();
9825
9826 if (pTypeDesc != NULL)
9827 {
9828 _ASSERTE(image->IsStored(pTypeDesc));
9829 pTypeDesc->Fixup(image);
9830 }
9831 }
9832 }
9833
9834 //
9835 // Fixup the assembly reference map table
9836 //
9837
9838 {
9839 LookupMap<PTR_Module>::Iterator manifestModuleIter(&m_ManifestModuleReferencesMap);
9840 DWORD rid = 0;
9841
9842 while (manifestModuleIter.Next())
9843 {
9844 TADDR flags;
9845 Module * pModule = manifestModuleIter.GetElementAndFlags(&flags);
9846
9847 if (pModule != NULL)
9848 {
9849 if (image->CanEagerBindToModule(pModule))
9850 {
9851 if (image->CanHardBindToZapModule(pModule))
9852 {
9853 image->FixupField(m_ManifestModuleReferencesMap.pTable, rid * sizeof(TADDR),
9854 pModule, flags, IMAGE_REL_BASED_RelativePointer);
9855 }
9856 else
9857 {
9858 image->ZeroPointerField(m_ManifestModuleReferencesMap.pTable, rid * sizeof(TADDR));
9859 }
9860 }
9861 else
9862 {
9863 image->ZeroPointerField(m_ManifestModuleReferencesMap.pTable, rid * sizeof(TADDR));
9864 }
9865 }
9866
9867 rid++;
9868 }
9869 }
9870
9871 //
9872 // Zero out file references table.
9873 //
9874 image->ZeroField(m_FileReferencesMap.pTable, 0,
9875 m_FileReferencesMap.GetSize() * sizeof(void*));
9876
9877
9878 image->ZeroField(this, offsetof(Module, m_debuggerSpecificData), sizeof(m_debuggerSpecificData));
9879
9880 image->ZeroField(this, offsetof(Module, m_AssemblyRefByNameCount), sizeof(m_AssemblyRefByNameCount));
9881 image->ZeroPointerField(this, offsetof(Module, m_AssemblyRefByNameTable));
9882
9883 image->ZeroPointerField(this,offsetof(Module, m_NativeMetadataAssemblyRefMap));
9884
9885 //
9886 // Fixup statics
9887 //
9888 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: fixing up module static data\n"));
9889
9890 image->ZeroPointerField(this, offsetof(Module, m_ModuleID));
9891 image->ZeroField(this, offsetof(Module, m_ModuleIndex), sizeof(m_ModuleIndex));
9892
9893 image->FixupPointerField(this, offsetof(Module, m_pDynamicStaticsInfo));
9894
9895 DynamicStaticsInfo* pDSI = m_pDynamicStaticsInfo;
9896 for (DWORD i = 0; i < m_cDynamicEntries; i++, pDSI++)
9897 {
9898 if (pDSI->pEnclosingMT->GetLoaderModule() == this &&
9899 // CEEPreloader::TriageTypeForZap() could have rejected this type
9900 image->IsStored(pDSI->pEnclosingMT))
9901 {
9902 image->FixupPointerField(m_pDynamicStaticsInfo, (BYTE *)&pDSI->pEnclosingMT - (BYTE *)m_pDynamicStaticsInfo);
9903 }
9904 else
9905 {
9906 // Some other (mutually-recursive) dependency must have loaded
9907 // a generic instantiation whose static were pumped into the
9908 // assembly being ngenned.
9909 image->ZeroPointerField(m_pDynamicStaticsInfo, (BYTE *)&pDSI->pEnclosingMT - (BYTE *)m_pDynamicStaticsInfo);
9910 }
9911 }
9912
9913 // If we failed to load some types we need to reset the pointers to the static offset tables so they'll be
9914 // rebuilt at runtime.
9915 if (m_pRegularStaticOffsets != (PTR_DWORD)NGEN_STATICS_ALLCLASSES_WERE_LOADED)
9916 {
9917 _ASSERTE(m_pThreadStaticOffsets != (PTR_DWORD)NGEN_STATICS_ALLCLASSES_WERE_LOADED);
9918 image->ZeroPointerField(this, offsetof(Module, m_pRegularStaticOffsets));
9919 image->ZeroPointerField(this, offsetof(Module, m_pThreadStaticOffsets));
9920 }
9921
9922 // Fix up inlining data
9923 if(m_pPersistentInlineTrackingMapNGen)
9924 {
9925 image->FixupPointerField(this, offsetof(Module, m_pPersistentInlineTrackingMapNGen));
9926 m_pPersistentInlineTrackingMapNGen->Fixup(image);
9927 }
9928 else
9929 {
9930 image->ZeroPointerField(this, offsetof(Module, m_pPersistentInlineTrackingMapNGen));
9931 }
9932
9933 SetIsModuleSaved();
9934}
9935#ifdef _PREFAST_
9936#pragma warning(pop)
9937#endif
9938
9939#endif // FEATURE_NATIVE_IMAGE_GENERATION
9940
9941#ifdef FEATURE_PREJIT
9942//
9943// Is "address" a data-structure in the native image?
9944//
9945
9946BOOL Module::IsPersistedObject(void *address)
9947{
9948 CONTRACTL
9949 {
9950 INSTANCE_CHECK;
9951 NOTHROW;
9952 GC_NOTRIGGER;
9953 MODE_ANY;
9954 FORBID_FAULT;
9955 }
9956 CONTRACTL_END;
9957
9958 if (!HasNativeImage())
9959 return FALSE;
9960
9961 PEImageLayout *pLayout = GetNativeImage();
9962 _ASSERTE(pLayout->IsMapped());
9963
9964 return (address >= pLayout->GetBase()
9965 && address < (BYTE*)pLayout->GetBase() + pLayout->GetVirtualSize());
9966}
9967
9968Module *Module::GetModuleFromIndex(DWORD ix)
9969{
9970 CONTRACT(Module*)
9971 {
9972 INSTANCE_CHECK;
9973 THROWS;
9974 GC_TRIGGERS;
9975 MODE_ANY;
9976 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9977 }
9978 CONTRACT_END;
9979
9980 if (HasNativeImage())
9981 {
9982 RETURN ZapSig::DecodeModuleFromIndex(this, ix);
9983 }
9984 else
9985 {
9986 mdAssemblyRef mdAssemblyRefToken = TokenFromRid(ix, mdtAssemblyRef);
9987 Assembly *pAssembly = this->LookupAssemblyRef(mdAssemblyRefToken);
9988 if (pAssembly)
9989 {
9990 RETURN pAssembly->GetManifestModule();
9991 }
9992 else
9993 {
9994 // GetModuleFromIndex failed
9995 RETURN NULL;
9996 }
9997 }
9998}
9999#endif // FEATURE_PREJIT
10000
10001#endif // !DACCESS_COMPILE
10002
10003#ifdef FEATURE_PREJIT
10004
10005Module *Module::GetModuleFromIndexIfLoaded(DWORD ix)
10006{
10007 CONTRACT(Module*)
10008 {
10009 INSTANCE_CHECK;
10010 NOTHROW;
10011 GC_NOTRIGGER;
10012 MODE_ANY;
10013 PRECONDITION(HasNativeImage());
10014 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
10015 }
10016 CONTRACT_END;
10017
10018#ifndef DACCESS_COMPILE
10019 RETURN ZapSig::DecodeModuleFromIndexIfLoaded(this, ix);
10020#else // DACCESS_COMPILE
10021 DacNotImpl();
10022 RETURN NULL;
10023#endif // DACCESS_COMPILE
10024}
10025
10026#ifndef DACCESS_COMPILE
10027
10028BYTE *Module::GetNativeFixupBlobData(RVA rva)
10029{
10030 CONTRACT(BYTE *)
10031 {
10032 INSTANCE_CHECK;
10033 NOTHROW;
10034 GC_NOTRIGGER;
10035 MODE_ANY;
10036 SO_TOLERANT;
10037 POSTCONDITION(CheckPointer(RETVAL));
10038 }
10039 CONTRACT_END;
10040
10041 RETURN (BYTE *) GetNativeOrReadyToRunImage()->GetRvaData(rva);
10042}
10043
10044IMDInternalImport *Module::GetNativeAssemblyImport(BOOL loadAllowed)
10045{
10046 CONTRACT(IMDInternalImport *)
10047 {
10048 INSTANCE_CHECK;
10049 if (loadAllowed) GC_TRIGGERS; else GC_NOTRIGGER;
10050 if (loadAllowed) THROWS; else NOTHROW;
10051 if (loadAllowed) INJECT_FAULT(COMPlusThrowOM()); else FORBID_FAULT;
10052 MODE_ANY;
10053 PRECONDITION(HasNativeImage());
10054 POSTCONDITION(CheckPointer(RETVAL));
10055 }
10056 CONTRACT_END;
10057
10058 RETURN GetFile()->GetPersistentNativeImage()->GetNativeMDImport(loadAllowed);
10059}
10060
10061
10062/*static*/
10063void Module::RestoreMethodTablePointerRaw(MethodTable ** ppMT,
10064 Module *pContainingModule,
10065 ClassLoadLevel level)
10066{
10067 CONTRACTL
10068 {
10069 THROWS;
10070 GC_TRIGGERS;
10071 MODE_ANY;
10072 }
10073 CONTRACTL_END;
10074
10075 // Ensure that the compiler won't fetch the value twice
10076 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppMT);
10077
10078#ifdef _DEBUG
10079 if (pContainingModule != NULL)
10080 {
10081 Module * dbg_pZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMT));
10082 _ASSERTE((dbg_pZapModule == NULL) || (pContainingModule == dbg_pZapModule));
10083 }
10084#endif //_DEBUG
10085
10086 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10087 {
10088#ifdef _WIN64
10089 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10090#endif
10091
10092 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10093
10094 if (pContainingModule == NULL)
10095 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMT));
10096 PREFIX_ASSUME(pContainingModule != NULL);
10097
10098 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_TYPE_HANDLE);
10099
10100 Module * pInfoModule;
10101 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
10102
10103 TypeHandle th = ZapSig::DecodeType(pContainingModule,
10104 pInfoModule,
10105 pBlobData,
10106 level);
10107 *EnsureWritablePages(ppMT) = th.AsMethodTable();
10108 }
10109 else if (*ppMT)
10110 {
10111 ClassLoader::EnsureLoaded(*ppMT, level);
10112 }
10113}
10114
10115/*static*/
10116void Module::RestoreMethodTablePointer(FixupPointer<PTR_MethodTable> * ppMT,
10117 Module *pContainingModule,
10118 ClassLoadLevel level)
10119{
10120 CONTRACTL
10121 {
10122 THROWS;
10123 GC_TRIGGERS;
10124 MODE_ANY;
10125 }
10126 CONTRACTL_END;
10127
10128 if (ppMT->IsNull())
10129 return;
10130
10131 if (ppMT->IsTagged())
10132 {
10133 RestoreMethodTablePointerRaw(ppMT->GetValuePtr(), pContainingModule, level);
10134 }
10135 else
10136 {
10137 ClassLoader::EnsureLoaded(ppMT->GetValue(), level);
10138 }
10139}
10140
10141/*static*/
10142void Module::RestoreMethodTablePointer(RelativeFixupPointer<PTR_MethodTable> * ppMT,
10143 Module *pContainingModule,
10144 ClassLoadLevel level)
10145{
10146 CONTRACTL
10147 {
10148 THROWS;
10149 GC_TRIGGERS;
10150 MODE_ANY;
10151 }
10152 CONTRACTL_END;
10153
10154 if (ppMT->IsNull())
10155 return;
10156
10157 if (ppMT->IsTagged((TADDR)ppMT))
10158 {
10159 RestoreMethodTablePointerRaw(ppMT->GetValuePtr(), pContainingModule, level);
10160 }
10161 else
10162 {
10163 ClassLoader::EnsureLoaded(ppMT->GetValue(), level);
10164 }
10165}
10166
10167#endif // !DACCESS_COMPILE
10168
10169BOOL Module::IsZappedCode(PCODE code)
10170{
10171 CONTRACTL
10172 {
10173 NOTHROW;
10174 GC_NOTRIGGER;
10175 SO_TOLERANT;
10176 SUPPORTS_DAC;
10177 }
10178 CONTRACTL_END;
10179
10180 if (!HasNativeImage())
10181 return FALSE;
10182
10183 PEImageLayout *pNativeImage = GetNativeImage();
10184
10185 UINT32 cCode = 0;
10186 PCODE pCodeSection;
10187
10188 pCodeSection = pNativeImage->GetNativeHotCode(&cCode);
10189 if ((pCodeSection <= code) && (code < pCodeSection + cCode))
10190 {
10191 return TRUE;
10192 }
10193
10194 pCodeSection = pNativeImage->GetNativeCode(&cCode);
10195 if ((pCodeSection <= code) && (code < pCodeSection + cCode))
10196 {
10197 return TRUE;
10198 }
10199
10200 return FALSE;
10201}
10202
10203BOOL Module::IsZappedPrecode(PCODE code)
10204{
10205 CONTRACTL
10206 {
10207 NOTHROW;
10208 GC_NOTRIGGER;
10209 SUPPORTS_DAC;
10210 SO_TOLERANT;
10211 }
10212 CONTRACTL_END;
10213
10214 if (m_pNGenLayoutInfo == NULL)
10215 return FALSE;
10216
10217 for (SIZE_T i = 0; i < COUNTOF(m_pNGenLayoutInfo->m_Precodes); i++)
10218 {
10219 if (m_pNGenLayoutInfo->m_Precodes[i].IsInRange(code))
10220 return TRUE;
10221 }
10222
10223 return FALSE;
10224}
10225
10226PCCOR_SIGNATURE Module::GetEncodedSig(RVA fixupRva, Module **ppDefiningModule)
10227{
10228 CONTRACT(PCCOR_SIGNATURE)
10229 {
10230 INSTANCE_CHECK;
10231 THROWS;
10232 GC_TRIGGERS;
10233 MODE_ANY;
10234 SO_INTOLERANT;
10235 POSTCONDITION(CheckPointer(RETVAL));
10236 SUPPORTS_DAC;
10237 }
10238 CONTRACT_END;
10239
10240#ifndef DACCESS_COMPILE
10241 PCCOR_SIGNATURE pBuffer = GetNativeFixupBlobData(fixupRva);
10242
10243 BYTE kind = *pBuffer++;
10244
10245 *ppDefiningModule = (kind & ENCODE_MODULE_OVERRIDE) ? GetModuleFromIndex(CorSigUncompressData(pBuffer)) : this;
10246
10247 RETURN pBuffer;
10248#else
10249 RETURN NULL;
10250#endif // DACCESS_COMPILE
10251}
10252
10253PCCOR_SIGNATURE Module::GetEncodedSigIfLoaded(RVA fixupRva, Module **ppDefiningModule)
10254{
10255 CONTRACT(PCCOR_SIGNATURE)
10256 {
10257 INSTANCE_CHECK;
10258 NOTHROW;
10259 GC_NOTRIGGER;
10260 MODE_ANY;
10261 SO_INTOLERANT;
10262 POSTCONDITION(CheckPointer(RETVAL));
10263 SUPPORTS_DAC;
10264 }
10265 CONTRACT_END;
10266
10267#ifndef DACCESS_COMPILE
10268 PCCOR_SIGNATURE pBuffer = GetNativeFixupBlobData(fixupRva);
10269
10270 BYTE kind = *pBuffer++;
10271
10272 *ppDefiningModule = (kind & ENCODE_MODULE_OVERRIDE) ? GetModuleFromIndexIfLoaded(CorSigUncompressData(pBuffer)) : this;
10273
10274 RETURN pBuffer;
10275#else
10276 *ppDefiningModule = NULL;
10277 RETURN NULL;
10278#endif // DACCESS_COMPILE
10279}
10280
10281/*static*/
10282PTR_Module Module::RestoreModulePointerIfLoaded(DPTR(RelativeFixupPointer<PTR_Module>) ppModule, Module *pContainingModule)
10283{
10284 CONTRACTL
10285 {
10286 NOTHROW;
10287 GC_NOTRIGGER;
10288 MODE_ANY;
10289 FORBID_FAULT;
10290 SUPPORTS_DAC;
10291 }
10292 CONTRACTL_END;
10293
10294 if (!ppModule->IsTagged(dac_cast<TADDR>(ppModule)))
10295 return ppModule->GetValue(dac_cast<TADDR>(ppModule));
10296
10297#ifndef DACCESS_COMPILE
10298 PTR_Module * ppValue = ppModule->GetValuePtr();
10299
10300 // Ensure that the compiler won't fetch the value twice
10301 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppValue);
10302
10303 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10304 {
10305
10306#ifdef _WIN64
10307 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10308#endif
10309
10310 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10311
10312 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_MODULE_HANDLE);
10313
10314 Module * pInfoModule;
10315 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSigIfLoaded(fixupRva, &pInfoModule);
10316
10317 if (pInfoModule)
10318 {
10319 if (EnsureWritablePagesNoThrow(ppValue, sizeof(*ppValue)))
10320 *ppValue = pInfoModule;
10321 }
10322 return pInfoModule;
10323 }
10324 else
10325 {
10326 return PTR_Module(fixup);
10327 }
10328#else
10329 DacNotImpl();
10330 return NULL;
10331#endif
10332}
10333
10334#ifndef DACCESS_COMPILE
10335
10336/*static*/
10337void Module::RestoreModulePointer(RelativeFixupPointer<PTR_Module> * ppModule, Module *pContainingModule)
10338{
10339 CONTRACTL
10340 {
10341 THROWS;
10342 GC_TRIGGERS;
10343 MODE_ANY;
10344 INJECT_FAULT(COMPlusThrowOM());
10345 }
10346 CONTRACTL_END;
10347
10348 if (!ppModule->IsTagged((TADDR)ppModule))
10349 return;
10350
10351 PTR_Module * ppValue = ppModule->GetValuePtr();
10352
10353 // Ensure that the compiler won't fetch the value twice
10354 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppValue);
10355
10356 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10357 {
10358#ifdef _WIN64
10359 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10360#endif
10361
10362 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10363
10364 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_MODULE_HANDLE);
10365
10366 Module * pInfoModule;
10367 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
10368
10369 *EnsureWritablePages(ppValue) = pInfoModule;
10370 }
10371}
10372
10373/*static*/
10374void Module::RestoreTypeHandlePointerRaw(TypeHandle *pHandle, Module* pContainingModule, ClassLoadLevel level)
10375{
10376 CONTRACTL
10377 {
10378 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
10379 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
10380 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else {INJECT_FAULT(COMPlusThrowOM(););}
10381 MODE_ANY;
10382 }
10383 CONTRACTL_END;
10384
10385#ifdef _DEBUG
10386 if (pContainingModule != NULL)
10387 {
10388 Module * dbg_pZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(pHandle));
10389 _ASSERTE((dbg_pZapModule == NULL) || (pContainingModule == dbg_pZapModule));
10390 }
10391#endif //_DEBUG
10392
10393 TADDR fixup;
10394
10395 if (IS_ALIGNED(pHandle, sizeof(TypeHandle)))
10396 {
10397 // Ensure that the compiler won't fetch the value twice
10398 fixup = VolatileLoadWithoutBarrier((TADDR *)pHandle);
10399 }
10400 else
10401 {
10402 // This is necessary to handle in-place fixups (see by FixupTypeHandlePointerInplace)
10403 // in stubs-as-il signatures.
10404
10405 //
10406 // protect this unaligned read with the Module Crst for the rare case that
10407 // the TypeHandle to fixup is in a signature and unaligned.
10408 //
10409 if (NULL == pContainingModule)
10410 {
10411 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(pHandle));
10412 }
10413 CrstHolder ch(&pContainingModule->m_Crst);
10414 fixup = *(TADDR UNALIGNED *)pHandle;
10415 }
10416
10417 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10418 {
10419#ifdef _WIN64
10420 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10421#endif
10422
10423 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10424
10425 if (NULL == pContainingModule)
10426 {
10427 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(pHandle));
10428 }
10429 PREFIX_ASSUME(pContainingModule != NULL);
10430
10431 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_TYPE_HANDLE);
10432
10433 Module * pInfoModule;
10434 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
10435
10436 TypeHandle thResolved = ZapSig::DecodeType(pContainingModule,
10437 pInfoModule,
10438 pBlobData,
10439 level);
10440 EnsureWritablePages(pHandle);
10441 if (IS_ALIGNED(pHandle, sizeof(TypeHandle)))
10442 {
10443 *pHandle = thResolved;
10444 }
10445 else
10446 {
10447 //
10448 // protect this unaligned write with the Module Crst for the rare case that
10449 // the TypeHandle to fixup is in a signature and unaligned.
10450 //
10451 CrstHolder ch(&pContainingModule->m_Crst);
10452 *(TypeHandle UNALIGNED *)pHandle = thResolved;
10453 }
10454 }
10455 else if (fixup != NULL)
10456 {
10457 ClassLoader::EnsureLoaded(TypeHandle::FromTAddr(fixup), level);
10458 }
10459}
10460
10461/*static*/
10462void Module::RestoreTypeHandlePointer(FixupPointer<TypeHandle> * pHandle,
10463 Module *pContainingModule,
10464 ClassLoadLevel level)
10465{
10466 CONTRACTL
10467 {
10468 THROWS;
10469 GC_TRIGGERS;
10470 MODE_ANY;
10471 }
10472 CONTRACTL_END;
10473
10474 if (pHandle->IsNull())
10475 return;
10476
10477 if (pHandle->IsTagged())
10478 {
10479 RestoreTypeHandlePointerRaw(pHandle->GetValuePtr(), pContainingModule, level);
10480 }
10481 else
10482 {
10483 ClassLoader::EnsureLoaded(pHandle->GetValue(), level);
10484 }
10485}
10486
10487/*static*/
10488void Module::RestoreTypeHandlePointer(RelativeFixupPointer<TypeHandle> * pHandle,
10489 Module *pContainingModule,
10490 ClassLoadLevel level)
10491{
10492 CONTRACTL
10493 {
10494 THROWS;
10495 GC_TRIGGERS;
10496 MODE_ANY;
10497 }
10498 CONTRACTL_END;
10499
10500 if (pHandle->IsNull())
10501 return;
10502
10503 if (pHandle->IsTagged((TADDR)pHandle))
10504 {
10505 RestoreTypeHandlePointerRaw(pHandle->GetValuePtr(), pContainingModule, level);
10506 }
10507 else
10508 {
10509 ClassLoader::EnsureLoaded(pHandle->GetValue((TADDR)pHandle), level);
10510 }
10511}
10512
10513/*static*/
10514void Module::RestoreMethodDescPointerRaw(PTR_MethodDesc * ppMD, Module *pContainingModule, ClassLoadLevel level)
10515{
10516 CONTRACTL
10517 {
10518 THROWS;
10519 GC_TRIGGERS;
10520 MODE_ANY;
10521 }
10522 CONTRACTL_END;
10523
10524 // Ensure that the compiler won't fetch the value twice
10525 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppMD);
10526
10527#ifdef _DEBUG
10528 if (pContainingModule != NULL)
10529 {
10530 Module * dbg_pZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMD));
10531 _ASSERTE((dbg_pZapModule == NULL) || (pContainingModule == dbg_pZapModule));
10532 }
10533#endif //_DEBUG
10534
10535 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10536 {
10537 GCX_PREEMP();
10538
10539#ifdef _WIN64
10540 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10541#endif
10542
10543 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10544
10545 if (pContainingModule == NULL)
10546 pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(ppMD));
10547 PREFIX_ASSUME(pContainingModule != NULL);
10548
10549 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_METHOD_HANDLE);
10550
10551 Module * pInfoModule;
10552 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
10553
10554 *EnsureWritablePages(ppMD) = ZapSig::DecodeMethod(pContainingModule,
10555 pInfoModule,
10556 pBlobData);
10557 }
10558 else if (*ppMD) {
10559 (*ppMD)->CheckRestore(level);
10560 }
10561}
10562
10563/*static*/
10564void Module::RestoreMethodDescPointer(FixupPointer<PTR_MethodDesc> * ppMD,
10565 Module *pContainingModule,
10566 ClassLoadLevel level)
10567{
10568 CONTRACTL
10569 {
10570 THROWS;
10571 GC_TRIGGERS;
10572 MODE_ANY;
10573 }
10574 CONTRACTL_END;
10575
10576 if (ppMD->IsNull())
10577 return;
10578
10579 if (ppMD->IsTagged())
10580 {
10581 RestoreMethodDescPointerRaw(ppMD->GetValuePtr(), pContainingModule, level);
10582 }
10583 else
10584 {
10585 ppMD->GetValue()->CheckRestore(level);
10586 }
10587}
10588
10589/*static*/
10590void Module::RestoreMethodDescPointer(RelativeFixupPointer<PTR_MethodDesc> * ppMD,
10591 Module *pContainingModule,
10592 ClassLoadLevel level)
10593{
10594 CONTRACTL
10595 {
10596 THROWS;
10597 GC_TRIGGERS;
10598 MODE_ANY;
10599 }
10600 CONTRACTL_END;
10601
10602 if (ppMD->IsNull())
10603 return;
10604
10605 if (ppMD->IsTagged((TADDR)ppMD))
10606 {
10607 RestoreMethodDescPointerRaw(ppMD->GetValuePtr(), pContainingModule, level);
10608 }
10609 else
10610 {
10611 ppMD->GetValue((TADDR)ppMD)->CheckRestore(level);
10612 }
10613}
10614
10615/*static*/
10616void Module::RestoreFieldDescPointer(RelativeFixupPointer<PTR_FieldDesc> * ppFD)
10617{
10618 CONTRACTL
10619 {
10620 THROWS;
10621 GC_TRIGGERS;
10622 MODE_ANY;
10623 }
10624 CONTRACTL_END;
10625
10626 if (!ppFD->IsTagged())
10627 return;
10628
10629 PTR_FieldDesc * ppValue = ppFD->GetValuePtr();
10630
10631 // Ensure that the compiler won't fetch the value twice
10632 TADDR fixup = VolatileLoadWithoutBarrier((TADDR *)ppValue);
10633
10634 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
10635 {
10636#ifdef _WIN64
10637 CONSISTENCY_CHECK((CORCOMPILE_UNTAG_TOKEN(fixup)>>32) == 0);
10638#endif
10639
10640 Module * pContainingModule = ExecutionManager::FindZapModule((TADDR)ppValue);
10641 PREFIX_ASSUME(pContainingModule != NULL);
10642
10643 RVA fixupRva = (RVA) CORCOMPILE_UNTAG_TOKEN(fixup);
10644
10645 _ASSERTE((*pContainingModule->GetNativeFixupBlobData(fixupRva) & ~ENCODE_MODULE_OVERRIDE) == ENCODE_FIELD_HANDLE);
10646
10647 Module * pInfoModule;
10648 PCCOR_SIGNATURE pBlobData = pContainingModule->GetEncodedSig(fixupRva, &pInfoModule);
10649
10650 *EnsureWritablePages(ppValue) = ZapSig::DecodeField(pContainingModule,
10651 pInfoModule,
10652 pBlobData);
10653 }
10654}
10655
10656
10657//-----------------------------------------------------------------------------
10658
10659#if 0
10660
10661 This diagram illustrates the layout of fixups in the ngen image.
10662 This is the case where function foo2 has a class-restore fixup
10663 for class C1 in b.dll.
10664
10665 zapBase+curTableVA+rva / FixupList (see Fixup Encoding below)
10666 m_pFixupBlobs
10667 +-------------------+
10668 pEntry->VA +--------------------+ | non-NULL | foo1
10669 |Handles | +-------------------+
10670ZapHeader.ImportTable | | | non-NULL |
10671 | | +-------------------+
10672 +------------+ +--------------------+ | non-NULL |
10673 |a.dll | |Class cctors |<---+ +-------------------+
10674 | | | | \ | 0 |
10675 | | p->VA/ | |<---+ \ +===================+
10676 | | blobs +--------------------+ \ +-------non-NULL | foo2
10677 +------------+ |Class restore | \ +-------------------+
10678 |b.dll | | | +-------non-NULL |
10679 | | | | +-------------------+
10680 | token_C1 |<--------------blob(=>fixedUp/0) |<--pBlob--------index |
10681 | | \ | | +-------------------+
10682 | | \ +--------------------+ | non-NULL |
10683 | | \ | | +-------------------+
10684 | | \ | . | | 0 |
10685 | | \ | . | +===================+
10686 +------------+ \ | . | | 0 | foo3
10687 \ | | +===================+
10688 \ +--------------------+ | non-NULL | foo4
10689 \ |Various fixups that | +-------------------+
10690 \ |need too happen | | 0 |
10691 \| | +===================+
10692 |(CorCompileTokenTable)
10693 | |
10694 pEntryEnd->VA +--------------------+
10695
10696
10697
10698#endif // 0
10699
10700//-----------------------------------------------------------------------------
10701
10702BOOL Module::FixupNativeEntry(CORCOMPILE_IMPORT_SECTION * pSection, SIZE_T fixupIndex, SIZE_T *fixupCell)
10703{
10704 CONTRACTL
10705 {
10706 STANDARD_VM_CHECK;
10707 PRECONDITION(CheckPointer(fixupCell));
10708 }
10709 CONTRACTL_END;
10710
10711 // Ensure that the compiler won't fetch the value twice
10712 SIZE_T fixup = VolatileLoadWithoutBarrier(fixupCell);
10713
10714 if (pSection->Signatures != NULL)
10715 {
10716 if (fixup == NULL)
10717 {
10718 PTR_DWORD pSignatures = dac_cast<PTR_DWORD>(GetNativeOrReadyToRunImage()->GetRvaData(pSection->Signatures));
10719
10720 if (!LoadDynamicInfoEntry(this, pSignatures[fixupIndex], fixupCell))
10721 return FALSE;
10722
10723 _ASSERTE(*fixupCell != NULL);
10724 }
10725 }
10726 else
10727 {
10728 if (CORCOMPILE_IS_FIXUP_TAGGED(fixup, pSection))
10729 {
10730 // Fixup has not been fixed up yet
10731 if (!LoadDynamicInfoEntry(this, (RVA)CORCOMPILE_UNTAG_TOKEN(fixup), fixupCell))
10732 return FALSE;
10733
10734 _ASSERTE(!CORCOMPILE_IS_FIXUP_TAGGED(*fixupCell, pSection));
10735 }
10736 else
10737 {
10738 //
10739 // Handle tables are special. We may need to restore static handle or previous
10740 // attempts to load handle could have been partial.
10741 //
10742 if (pSection->Type == CORCOMPILE_IMPORT_TYPE_TYPE_HANDLE)
10743 {
10744 TypeHandle::FromPtr((void *)fixup).CheckRestore();
10745 }
10746 else
10747 if (pSection->Type == CORCOMPILE_IMPORT_TYPE_METHOD_HANDLE)
10748 {
10749 ((MethodDesc *)(fixup))->CheckRestore();
10750 }
10751 }
10752 }
10753
10754 return TRUE;
10755}
10756
10757//-----------------------------------------------------------------------------
10758
10759void Module::RunEagerFixups()
10760{
10761 STANDARD_VM_CONTRACT;
10762
10763 COUNT_T nSections;
10764 PTR_CORCOMPILE_IMPORT_SECTION pSections = GetImportSections(&nSections);
10765
10766 if (nSections == 0)
10767 return;
10768
10769#ifdef _DEBUG
10770 // Loading types during eager fixup is not a tested scenario. Make bugs out of any attempts to do so in a
10771 // debug build. Use holder to recover properly in case of exception.
10772 class ForbidTypeLoadHolder
10773 {
10774 public:
10775 ForbidTypeLoadHolder()
10776 {
10777 BEGIN_FORBID_TYPELOAD();
10778 }
10779
10780 ~ForbidTypeLoadHolder()
10781 {
10782 END_FORBID_TYPELOAD();
10783 }
10784 }
10785 forbidTypeLoad;
10786#endif
10787
10788 // TODO: Verify that eager fixup dependency graphs can contain no cycles
10789 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
10790
10791 PEImageLayout *pNativeImage = GetNativeOrReadyToRunImage();
10792
10793 for (COUNT_T iSection = 0; iSection < nSections; iSection++)
10794 {
10795 PTR_CORCOMPILE_IMPORT_SECTION pSection = pSections + iSection;
10796
10797 if ((pSection->Flags & CORCOMPILE_IMPORT_FLAGS_EAGER) == 0)
10798 continue;
10799
10800 COUNT_T tableSize;
10801 TADDR tableBase = pNativeImage->GetDirectoryData(&pSection->Section, &tableSize);
10802
10803 if (pSection->Signatures != NULL)
10804 {
10805 PTR_DWORD pSignatures = dac_cast<PTR_DWORD>(pNativeImage->GetRvaData(pSection->Signatures));
10806
10807 for (SIZE_T * fixupCell = (SIZE_T *)tableBase; fixupCell < (SIZE_T *)(tableBase + tableSize); fixupCell++)
10808 {
10809 SIZE_T fixupIndex = fixupCell - (SIZE_T *)tableBase;
10810 if (!LoadDynamicInfoEntry(this, pSignatures[fixupIndex], fixupCell))
10811 {
10812 _ASSERTE(!"LoadDynamicInfoEntry failed");
10813 ThrowHR(COR_E_BADIMAGEFORMAT);
10814 }
10815 _ASSERTE(*fixupCell != NULL);
10816 }
10817 }
10818 else
10819 {
10820 for (SIZE_T * fixupCell = (SIZE_T *)tableBase; fixupCell < (SIZE_T *)(tableBase + tableSize); fixupCell++)
10821 {
10822 // Ensure that the compiler won't fetch the value twice
10823 SIZE_T fixup = VolatileLoadWithoutBarrier(fixupCell);
10824
10825 // This method may execute multiple times in multi-domain scenarios. Check that the fixup has not been
10826 // fixed up yet.
10827 if (CORCOMPILE_IS_FIXUP_TAGGED(fixup, pSection))
10828 {
10829 if (!LoadDynamicInfoEntry(this, (RVA)CORCOMPILE_UNTAG_TOKEN(fixup), fixupCell))
10830 {
10831 _ASSERTE(!"LoadDynamicInfoEntry failed");
10832 ThrowHR(COR_E_BADIMAGEFORMAT);
10833 }
10834 _ASSERTE(!CORCOMPILE_IS_FIXUP_TAGGED(*fixupCell, pSection));
10835 }
10836 }
10837 }
10838 }
10839}
10840
10841void Module::LoadTokenTables()
10842{
10843 CONTRACTL
10844 {
10845 INSTANCE_CHECK;
10846 THROWS;
10847 GC_TRIGGERS;
10848 MODE_ANY;
10849 PRECONDITION(HasNativeImage());
10850 }
10851 CONTRACTL_END;
10852
10853#ifndef CROSSGEN_COMPILE
10854 if (NingenEnabled())
10855 return;
10856
10857 CORCOMPILE_EE_INFO_TABLE *pEEInfo = GetNativeImage()->GetNativeEEInfoTable();
10858 PREFIX_ASSUME(pEEInfo != NULL);
10859
10860 pEEInfo->inlinedCallFrameVptr = InlinedCallFrame::GetMethodFrameVPtr();
10861 pEEInfo->addrOfCaptureThreadGlobal = (LONG *)&g_TrapReturningThreads;
10862
10863 //CoreClr doesn't always have the debugger loaded
10864 //patch up the ngen image to point to this address so that the JIT bypasses JMC if there is no debugger
10865 static DWORD g_dummyJMCFlag = 0;
10866 pEEInfo->addrOfJMCFlag = g_pDebugInterface ? g_pDebugInterface->GetJMCFlagAddr(this) : &g_dummyJMCFlag;
10867
10868 pEEInfo->gsCookie = GetProcessGSCookie();
10869
10870 if (!IsSystem())
10871 {
10872 pEEInfo->emptyString = (CORINFO_Object **)StringObject::GetEmptyStringRefPtr();
10873 }
10874
10875 pEEInfo->threadTlsIndex = TLS_OUT_OF_INDEXES;
10876 pEEInfo->rvaStaticTlsIndex = NULL;
10877#endif // CROSSGEN_COMPILE
10878}
10879
10880#endif // !DACCESS_COMPILE
10881
10882// Returns the RVA to the compressed debug information blob for the given method
10883
10884CORCOMPILE_DEBUG_ENTRY Module::GetMethodDebugInfoOffset(MethodDesc *pMD)
10885{
10886 CONTRACT(CORCOMPILE_DEBUG_ENTRY)
10887 {
10888 INSTANCE_CHECK;
10889 PRECONDITION(HasNativeImage());
10890 PRECONDITION(CheckPointer(pMD) && pMD->IsPreImplemented());
10891 POSTCONDITION(GetNativeImage()->CheckRva(RETVAL, NULL_OK));
10892 NOTHROW;
10893 GC_NOTRIGGER;
10894 MODE_ANY;
10895 SUPPORTS_DAC;
10896 }
10897 CONTRACT_END;
10898
10899 if (!GetNativeImage()->HasNativeDebugMap() || pMD->IsRuntimeSupplied())
10900 RETURN 0;
10901
10902 COUNT_T size;
10903 PTR_CORCOMPILE_DEBUG_RID_ENTRY ridTable =
10904 dac_cast<PTR_CORCOMPILE_DEBUG_RID_ENTRY>(GetNativeImage()->GetNativeDebugMap(&size));
10905
10906 COUNT_T count = size / sizeof(CORCOMPILE_DEBUG_RID_ENTRY);
10907 // The size should be odd for better hashing
10908 _ASSERTE((count & 1) != 0);
10909
10910 CORCOMPILE_DEBUG_RID_ENTRY ridEntry = ridTable[GetDebugRidEntryHash(pMD->GetMemberDef()) % count];
10911
10912 // Do we have multiple code corresponding to the same RID
10913 if (!IsMultipleLabelledEntries(ridEntry))
10914 {
10915 RETURN(ridEntry);
10916 }
10917
10918 PTR_CORCOMPILE_DEBUG_LABELLED_ENTRY pLabelledEntry =
10919 PTR_CORCOMPILE_DEBUG_LABELLED_ENTRY
10920 (GetNativeImage()->GetRvaData(ridEntry &
10921 ~CORCOMPILE_DEBUG_MULTIPLE_ENTRIES));
10922
10923 DWORD codeRVA = GetNativeImage()->
10924 GetDataRva((const TADDR)pMD->GetNativeCode());
10925#if defined(_TARGET_ARM_)
10926 // Since the Thumb Bit is set on ARM, the RVA calculated above will have it set as well
10927 // and will result in the failure of checks in the loop below. Hence, mask off the
10928 // bit before proceeding ahead.
10929 codeRVA = ThumbCodeToDataPointer<DWORD, DWORD>(codeRVA);
10930#endif // _TARGET_ARM_
10931
10932 for (;;)
10933 {
10934 if (pLabelledEntry->nativeCodeRVA == codeRVA)
10935 {
10936 RETURN (pLabelledEntry->debugInfoOffset & ~CORCOMPILE_DEBUG_MULTIPLE_ENTRIES);
10937 }
10938
10939 if (!IsMultipleLabelledEntries(pLabelledEntry->debugInfoOffset))
10940 {
10941 break;
10942 }
10943
10944 pLabelledEntry++;
10945 }
10946
10947 _ASSERTE(!"Debug info not found - corrupted ngen image?");
10948 RETURN (0);
10949}
10950
10951PTR_BYTE Module::GetNativeDebugInfo(MethodDesc * pMD)
10952{
10953 CONTRACTL
10954 {
10955 INSTANCE_CHECK;
10956 PRECONDITION(HasNativeImage());
10957 PRECONDITION(CheckPointer(pMD));
10958 PRECONDITION(pMD->GetZapModule() == this);
10959 THROWS;
10960 GC_NOTRIGGER;
10961 MODE_ANY;
10962 SUPPORTS_DAC;
10963 }
10964 CONTRACTL_END;
10965
10966 CORCOMPILE_DEBUG_ENTRY debugInfoOffset = GetMethodDebugInfoOffset(pMD);
10967
10968 if (debugInfoOffset == 0)
10969 return NULL;
10970
10971 return dac_cast<PTR_BYTE>(GetNativeImage()->GetRvaData(debugInfoOffset));
10972}
10973#endif //FEATURE_PREJIT
10974
10975
10976
10977#ifndef DACCESS_COMPILE
10978
10979#ifdef FEATURE_PREJIT
10980//
10981// Profile data management
10982//
10983
10984ICorJitInfo::ProfileBuffer * Module::AllocateProfileBuffer(mdToken _token, DWORD _count, DWORD _ILSize)
10985{
10986 CONTRACT (ICorJitInfo::ProfileBuffer*)
10987 {
10988 INSTANCE_CHECK;
10989 THROWS;
10990 GC_NOTRIGGER;
10991 MODE_ANY;
10992 INJECT_FAULT(CONTRACT_RETURN NULL;);
10993 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
10994 }
10995 CONTRACT_END;
10996
10997 assert(_ILSize != 0);
10998
10999 DWORD listSize = sizeof(CORCOMPILE_METHOD_PROFILE_LIST);
11000 DWORD headerSize = sizeof(CORBBTPROF_METHOD_HEADER);
11001 DWORD blockSize = _count * sizeof(CORBBTPROF_BLOCK_DATA);
11002 DWORD totalSize = listSize + headerSize + blockSize;
11003
11004 BYTE * memory = (BYTE *) (void *) this->m_pAssembly->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(totalSize));
11005
11006 CORCOMPILE_METHOD_PROFILE_LIST * methodProfileList = (CORCOMPILE_METHOD_PROFILE_LIST *) (memory + 0);
11007 CORBBTPROF_METHOD_HEADER * methodProfileData = (CORBBTPROF_METHOD_HEADER *) (memory + listSize);
11008
11009 // Note: Memory allocated on the LowFrequencyHeap is zero filled
11010
11011 methodProfileData->size = headerSize + blockSize;
11012 methodProfileData->method.token = _token;
11013 methodProfileData->method.ILSize = _ILSize;
11014 methodProfileData->method.cBlock = _count;
11015
11016 assert(methodProfileData->size == methodProfileData->Size());
11017
11018 // Link it to the per module list of profile data buffers
11019
11020 methodProfileList->next = m_methodProfileList;
11021 m_methodProfileList = methodProfileList;
11022
11023 RETURN ((ICorJitInfo::ProfileBuffer *) &methodProfileData->method.block[0]);
11024}
11025
11026HANDLE Module::OpenMethodProfileDataLogFile(GUID mvid)
11027{
11028 CONTRACTL
11029 {
11030 INSTANCE_CHECK;
11031 THROWS;
11032 GC_NOTRIGGER;
11033 MODE_ANY;
11034 }
11035 CONTRACTL_END;
11036
11037 HANDLE profileDataFile = INVALID_HANDLE_VALUE;
11038
11039 SString path;
11040 LPCWSTR assemblyPath = m_file->GetPath();
11041 LPCWSTR ibcDir = g_pConfig->GetZapBBInstrDir(); // should we put the ibc data into a particular directory?
11042 if (ibcDir == 0) {
11043 path.Set(assemblyPath); // no, then put it beside the IL dll
11044 }
11045 else {
11046 LPCWSTR assemblyFileName = wcsrchr(assemblyPath, DIRECTORY_SEPARATOR_CHAR_W);
11047 if (assemblyFileName)
11048 assemblyFileName++; // skip past the \ char
11049 else
11050 assemblyFileName = assemblyPath;
11051
11052 path.Set(ibcDir); // yes, put it in the directory, named with the assembly name.
11053 path.Append(DIRECTORY_SEPARATOR_CHAR_W);
11054 path.Append(assemblyFileName);
11055 }
11056
11057 SString::Iterator ext = path.End(); // remove the extension
11058 if (path.FindBack(ext, '.'))
11059 path.Truncate(ext);
11060 path.Append(W(".ibc")); // replace with .ibc extension
11061
11062 profileDataFile = WszCreateFile(path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
11063 OPEN_ALWAYS,
11064 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
11065 NULL);
11066
11067 if (profileDataFile == INVALID_HANDLE_VALUE) COMPlusThrowWin32();
11068
11069 DWORD count;
11070 CORBBTPROF_FILE_HEADER fileHeader;
11071
11072 SetFilePointer(profileDataFile, 0, NULL, FILE_BEGIN);
11073 BOOL result = ReadFile(profileDataFile, &fileHeader, sizeof(fileHeader), &count, NULL);
11074 if (result &&
11075 (count == sizeof(fileHeader)) &&
11076 (fileHeader.HeaderSize == sizeof(CORBBTPROF_FILE_HEADER)) &&
11077 (fileHeader.Magic == CORBBTPROF_MAGIC) &&
11078 (fileHeader.Version == CORBBTPROF_CURRENT_VERSION) &&
11079 (fileHeader.MVID == mvid))
11080 {
11081 //
11082 // The existing file was from the same assembly version - just append to it.
11083 //
11084
11085 SetFilePointer(profileDataFile, 0, NULL, FILE_END);
11086 }
11087 else
11088 {
11089 //
11090 // Either this is a new file, or it's from a previous version. Replace the contents.
11091 //
11092
11093 SetFilePointer(profileDataFile, 0, NULL, FILE_BEGIN);
11094 }
11095
11096 return profileDataFile;
11097}
11098
11099// Note that this method cleans up the profile buffers, so it's crucial that
11100// no managed code in the module is allowed to run once this method has
11101// been called!
11102
11103class ProfileMap
11104{
11105public:
11106 SIZE_T getCurrentOffset() {WRAPPER_NO_CONTRACT; return buffer.Size();}
11107
11108 void * getOffsetPtr(SIZE_T offset)
11109 {
11110 LIMITED_METHOD_CONTRACT;
11111 _ASSERTE(offset <= buffer.Size());
11112 return ((void *) (((char *) buffer.Ptr()) + offset));
11113 }
11114
11115 void *Allocate(SIZE_T size)
11116 {
11117 CONTRACT(void *)
11118 {
11119 INSTANCE_CHECK;
11120 THROWS;
11121 GC_NOTRIGGER;
11122 MODE_ANY;
11123 INJECT_FAULT(CONTRACT_RETURN NULL;);
11124 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
11125 }
11126 CONTRACT_END;
11127
11128 SIZE_T oldSize = buffer.Size();
11129 buffer.ReSizeThrows(oldSize + size);
11130 RETURN getOffsetPtr(oldSize);
11131 }
11132
11133private:
11134 CQuickBytes buffer;
11135};
11136
11137class ProfileEmitter
11138{
11139public:
11140
11141 ProfileEmitter()
11142 {
11143 LIMITED_METHOD_CONTRACT;
11144 pSectionList = NULL;
11145 }
11146
11147 ~ProfileEmitter()
11148 {
11149 WRAPPER_NO_CONTRACT;
11150 while (pSectionList)
11151 {
11152 SectionList *temp = pSectionList->next;
11153 delete pSectionList;
11154 pSectionList = temp;
11155 }
11156 }
11157
11158 ProfileMap *EmitNewSection(SectionFormat format)
11159 {
11160 WRAPPER_NO_CONTRACT;
11161 SectionList *s = new SectionList();
11162
11163 s->format = format;
11164 s->next = pSectionList;
11165 pSectionList = s;
11166
11167 return &s->profileMap;
11168 }
11169
11170 //
11171 // Serialize the profile sections into pMap
11172 //
11173
11174 void Serialize(ProfileMap *profileMap, GUID mvid)
11175 {
11176 CONTRACTL
11177 {
11178 INSTANCE_CHECK;
11179 THROWS;
11180 GC_NOTRIGGER;
11181 MODE_ANY;
11182 INJECT_FAULT(COMPlusThrowOM());
11183 }
11184 CONTRACTL_END;
11185
11186 //
11187 // Allocate the file header
11188 //
11189 {
11190 CORBBTPROF_FILE_HEADER *fileHeader;
11191 fileHeader = (CORBBTPROF_FILE_HEADER *) profileMap->Allocate(sizeof(CORBBTPROF_FILE_HEADER));
11192
11193 fileHeader->HeaderSize = sizeof(CORBBTPROF_FILE_HEADER);
11194 fileHeader->Magic = CORBBTPROF_MAGIC;
11195 fileHeader->Version = CORBBTPROF_CURRENT_VERSION;
11196 fileHeader->MVID = mvid;
11197 }
11198
11199 //
11200 // Count the number of sections
11201 //
11202 ULONG32 numSections = 0;
11203 for (SectionList *p = pSectionList; p; p = p->next)
11204 {
11205 numSections++;
11206 }
11207
11208 //
11209 // Allocate the section table
11210 //
11211 SIZE_T tableEntryOffset;
11212 {
11213 CORBBTPROF_SECTION_TABLE_HEADER *tableHeader;
11214 tableHeader = (CORBBTPROF_SECTION_TABLE_HEADER *)
11215 profileMap->Allocate(sizeof(CORBBTPROF_SECTION_TABLE_HEADER));
11216
11217 tableHeader->NumEntries = numSections;
11218 tableEntryOffset = profileMap->getCurrentOffset();
11219
11220 CORBBTPROF_SECTION_TABLE_ENTRY *tableEntry;
11221 tableEntry = (CORBBTPROF_SECTION_TABLE_ENTRY *)
11222 profileMap->Allocate(sizeof(CORBBTPROF_SECTION_TABLE_ENTRY) * numSections);
11223 }
11224
11225 //
11226 // Allocate the data sections
11227 //
11228 {
11229 ULONG secCount = 0;
11230 for (SectionList *pSec = pSectionList; pSec; pSec = pSec->next, secCount++)
11231 {
11232 SIZE_T offset = profileMap->getCurrentOffset();
11233 assert((offset & 0x3) == 0);
11234
11235 SIZE_T actualSize = pSec->profileMap.getCurrentOffset();
11236 SIZE_T alignUpSize = AlignUp(actualSize, sizeof(DWORD));
11237
11238 profileMap->Allocate(alignUpSize);
11239
11240 memcpy(profileMap->getOffsetPtr(offset), pSec->profileMap.getOffsetPtr(0), actualSize);
11241 if (alignUpSize > actualSize)
11242 {
11243 memset(((BYTE*)profileMap->getOffsetPtr(offset))+actualSize, 0, (alignUpSize - actualSize));
11244 }
11245
11246 CORBBTPROF_SECTION_TABLE_ENTRY *tableEntry;
11247 tableEntry = (CORBBTPROF_SECTION_TABLE_ENTRY *) profileMap->getOffsetPtr(tableEntryOffset);
11248 tableEntry += secCount;
11249 tableEntry->FormatID = pSec->format;
11250 tableEntry->Data.Offset = offset;
11251 tableEntry->Data.Size = alignUpSize;
11252 }
11253 }
11254
11255 //
11256 // Allocate the end token marker
11257 //
11258 {
11259 ULONG *endToken;
11260 endToken = (ULONG *) profileMap->Allocate(sizeof(ULONG));
11261
11262 *endToken = CORBBTPROF_END_TOKEN;
11263 }
11264 }
11265
11266private:
11267 struct SectionList
11268 {
11269 SectionFormat format;
11270 ProfileMap profileMap;
11271 SectionList *next;
11272 };
11273 SectionList * pSectionList;
11274};
11275
11276
11277/*static*/ idTypeSpec TypeSpecBlobEntry::s_lastTypeSpecToken = idTypeSpecNil;
11278/*static*/ idMethodSpec MethodSpecBlobEntry::s_lastMethodSpecToken = idMethodSpecNil;
11279/*static*/ idExternalNamespace ExternalNamespaceBlobEntry::s_lastExternalNamespaceToken = idExternalNamespaceNil;
11280/*static*/ idExternalType ExternalTypeBlobEntry::s_lastExternalTypeToken = idExternalTypeNil;
11281/*static*/ idExternalSignature ExternalSignatureBlobEntry::s_lastExternalSignatureToken = idExternalSignatureNil;
11282/*static*/ idExternalMethod ExternalMethodBlobEntry::s_lastExternalMethodToken = idExternalMethodNil;
11283
11284
11285inline static size_t HashCombine(size_t h1, size_t h2)
11286{
11287 LIMITED_METHOD_CONTRACT;
11288
11289 size_t result = (h1 * 129) ^ h2;
11290 return result;
11291}
11292
11293bool TypeSpecBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11294{
11295 WRAPPER_NO_CONTRACT;
11296
11297 if (this->kind() != other->kind())
11298 return false;
11299
11300 const TypeSpecBlobEntry * other2 = static_cast<const TypeSpecBlobEntry *>(other);
11301
11302 if (this->cbSig() != other2->cbSig())
11303 return false;
11304
11305 PCCOR_SIGNATURE p1 = this->pSig();
11306 PCCOR_SIGNATURE p2 = other2->pSig();
11307
11308 for (DWORD i=0; (i < this->cbSig()); i++)
11309 if (p1[i] != p2[i])
11310 return false;
11311
11312 return true;
11313}
11314
11315size_t TypeSpecBlobEntry::Hash() const
11316{
11317 WRAPPER_NO_CONTRACT;
11318
11319 size_t hashValue = HashInit();
11320
11321 PCCOR_SIGNATURE p1 = pSig();
11322 for (DWORD i=0; (i < cbSig()); i++)
11323 hashValue = HashCombine(hashValue, p1[i]);
11324
11325 return hashValue;
11326}
11327
11328TypeSpecBlobEntry::TypeSpecBlobEntry(DWORD _cbSig, PCCOR_SIGNATURE _pSig)
11329{
11330 CONTRACTL
11331 {
11332 NOTHROW;
11333 GC_NOTRIGGER;
11334 PRECONDITION(_cbSig > 0);
11335 PRECONDITION(CheckPointer(_pSig));
11336 }
11337 CONTRACTL_END;
11338
11339 m_token = idTypeSpecNil;
11340 m_flags = 0;
11341 m_cbSig = 0;
11342
11343 COR_SIGNATURE * pNewSig = (COR_SIGNATURE *) new (nothrow) BYTE[_cbSig];
11344 if (pNewSig != NULL)
11345 {
11346 m_flags = 0;
11347 m_cbSig = _cbSig;
11348 memcpy(pNewSig, _pSig, _cbSig);
11349 }
11350 m_pSig = const_cast<PCCOR_SIGNATURE>(pNewSig);
11351}
11352
11353/* static */ const TypeSpecBlobEntry * TypeSpecBlobEntry::FindOrAdd(PTR_Module pModule,
11354 DWORD _cbSig,
11355 PCCOR_SIGNATURE _pSig)
11356{
11357 CONTRACTL
11358 {
11359 NOTHROW;
11360 GC_NOTRIGGER;
11361 }
11362 CONTRACTL_END;
11363
11364 if ((_cbSig == 0) || (_pSig == NULL))
11365 return NULL;
11366
11367 TypeSpecBlobEntry sEntry(_cbSig, _pSig);
11368
11369 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11370 if (pEntry == NULL)
11371 {
11372 //
11373 // Not Found, add a new type spec profiling blob entry
11374 //
11375 TypeSpecBlobEntry * newEntry = new (nothrow) TypeSpecBlobEntry(_cbSig, _pSig);
11376 if (newEntry == NULL)
11377 return NULL;
11378
11379 newEntry->newToken(); // Assign a new ibc type spec token
11380 CONTRACT_VIOLATION(ThrowsViolation);
11381 pModule->GetProfilingBlobTable()->Add(newEntry);
11382 pEntry = newEntry;
11383 }
11384
11385 //
11386 // Return the type spec entry that we found or the new one that we just created
11387 //
11388 _ASSERTE(pEntry->kind() == ParamTypeSpec);
11389 return static_cast<const TypeSpecBlobEntry *>(pEntry);
11390}
11391
11392bool MethodSpecBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11393{
11394 WRAPPER_NO_CONTRACT;
11395
11396 if (this->kind() != other->kind())
11397 return false;
11398
11399 const MethodSpecBlobEntry * other2 = static_cast<const MethodSpecBlobEntry *>(other);
11400
11401 if (this->cbSig() != other2->cbSig())
11402 return false;
11403
11404 PCCOR_SIGNATURE p1 = this->pSig();
11405 PCCOR_SIGNATURE p2 = other2->pSig();
11406
11407 for (DWORD i=0; (i < this->cbSig()); i++)
11408 if (p1[i] != p2[i])
11409 return false;
11410
11411 return true;
11412}
11413
11414size_t MethodSpecBlobEntry::Hash() const
11415{
11416 WRAPPER_NO_CONTRACT;
11417
11418 size_t hashValue = HashInit();
11419
11420 PCCOR_SIGNATURE p1 = pSig();
11421 for (DWORD i=0; (i < cbSig()); i++)
11422 hashValue = HashCombine(hashValue, p1[i]);
11423
11424 return hashValue;
11425}
11426
11427MethodSpecBlobEntry::MethodSpecBlobEntry(DWORD _cbSig, PCCOR_SIGNATURE _pSig)
11428{
11429 CONTRACTL
11430 {
11431 NOTHROW;
11432 GC_NOTRIGGER;
11433 PRECONDITION(_cbSig > 0);
11434 PRECONDITION(CheckPointer(_pSig));
11435 }
11436 CONTRACTL_END;
11437
11438 m_token = idMethodSpecNil;
11439 m_flags = 0;
11440 m_cbSig = 0;
11441
11442 COR_SIGNATURE * pNewSig = (COR_SIGNATURE *) new (nothrow) BYTE[_cbSig];
11443 if (pNewSig != NULL)
11444 {
11445 m_flags = 0;
11446 m_cbSig = _cbSig;
11447 memcpy(pNewSig, _pSig, _cbSig);
11448 }
11449 m_pSig = const_cast<PCCOR_SIGNATURE>(pNewSig);
11450}
11451
11452/* static */ const MethodSpecBlobEntry * MethodSpecBlobEntry::FindOrAdd(PTR_Module pModule,
11453 DWORD _cbSig,
11454 PCCOR_SIGNATURE _pSig)
11455{
11456 CONTRACTL
11457 {
11458 NOTHROW;
11459 GC_NOTRIGGER;
11460 }
11461 CONTRACTL_END;
11462
11463 if ((_cbSig == 0) || (_pSig == NULL))
11464 return NULL;
11465
11466 MethodSpecBlobEntry sEntry(_cbSig, _pSig);
11467
11468 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11469 if (pEntry == NULL)
11470 {
11471 //
11472 // Not Found, add a new method spec profiling blob entry
11473 //
11474 MethodSpecBlobEntry * newEntry = new (nothrow) MethodSpecBlobEntry(_cbSig, _pSig);
11475 if (newEntry == NULL)
11476 return NULL;
11477
11478 newEntry->newToken(); // Assign a new ibc method spec token
11479 CONTRACT_VIOLATION(ThrowsViolation);
11480 pModule->GetProfilingBlobTable()->Add(newEntry);
11481 pEntry = newEntry;
11482 }
11483
11484 //
11485 // Return the method spec entry that we found or the new one that we just created
11486 //
11487 _ASSERTE(pEntry->kind() == ParamMethodSpec);
11488 return static_cast<const MethodSpecBlobEntry *>(pEntry);
11489}
11490
11491bool ExternalNamespaceBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11492{
11493 WRAPPER_NO_CONTRACT;
11494
11495 if (this->kind() != other->kind())
11496 return false;
11497
11498 const ExternalNamespaceBlobEntry * other2 = static_cast<const ExternalNamespaceBlobEntry *>(other);
11499
11500 if (this->cbName() != other2->cbName())
11501 return false;
11502
11503 LPCSTR p1 = this->pName();
11504 LPCSTR p2 = other2->pName();
11505
11506 for (DWORD i=0; (i < this->cbName()); i++)
11507 if (p1[i] != p2[i])
11508 return false;
11509
11510 return true;
11511}
11512
11513size_t ExternalNamespaceBlobEntry::Hash() const
11514{
11515 WRAPPER_NO_CONTRACT;
11516
11517 size_t hashValue = HashInit();
11518
11519 LPCSTR p1 = pName();
11520 for (DWORD i=0; (i < cbName()); i++)
11521 hashValue = HashCombine(hashValue, p1[i]);
11522
11523 return hashValue;
11524}
11525
11526ExternalNamespaceBlobEntry::ExternalNamespaceBlobEntry(LPCSTR _pName)
11527{
11528 CONTRACTL
11529 {
11530 NOTHROW;
11531 GC_NOTRIGGER;
11532 PRECONDITION(CheckPointer(_pName));
11533 }
11534 CONTRACTL_END;
11535
11536 m_token = idExternalNamespaceNil;
11537 m_cbName = 0;
11538 m_pName = NULL;
11539
11540 DWORD _cbName = (DWORD) strlen(_pName) + 1;
11541 LPSTR * pName = (LPSTR *) new (nothrow) CHAR[_cbName];
11542 if (pName != NULL)
11543 {
11544 m_cbName = _cbName;
11545 memcpy(pName, _pName, _cbName);
11546 m_pName = (LPCSTR) pName;
11547 }
11548}
11549
11550/* static */ const ExternalNamespaceBlobEntry * ExternalNamespaceBlobEntry::FindOrAdd(PTR_Module pModule, LPCSTR _pName)
11551{
11552 CONTRACTL
11553 {
11554 NOTHROW;
11555 GC_NOTRIGGER;
11556 }
11557 CONTRACTL_END;
11558
11559 if ((_pName == NULL) || (::strlen(_pName) == 0))
11560 return NULL;
11561
11562 ExternalNamespaceBlobEntry sEntry(_pName);
11563
11564 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11565 if (pEntry == NULL)
11566 {
11567 //
11568 // Not Found, add a new external namespace blob entry
11569 //
11570 ExternalNamespaceBlobEntry * newEntry = new (nothrow) ExternalNamespaceBlobEntry(_pName);
11571 if (newEntry == NULL)
11572 return NULL;
11573
11574 newEntry->newToken(); // Assign a new ibc external namespace token
11575 CONTRACT_VIOLATION(ThrowsViolation);
11576 pModule->GetProfilingBlobTable()->Add(newEntry);
11577 pEntry = newEntry;
11578 }
11579
11580 //
11581 // Return the external namespace entry that we found or the new one that we just created
11582 //
11583 _ASSERTE(pEntry->kind() == ExternalNamespaceDef);
11584 return static_cast<const ExternalNamespaceBlobEntry *>(pEntry);
11585}
11586
11587bool ExternalTypeBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11588{
11589 WRAPPER_NO_CONTRACT;
11590
11591 if (this->kind() != other->kind())
11592 return false;
11593
11594 const ExternalTypeBlobEntry * other2 = static_cast<const ExternalTypeBlobEntry *>(other);
11595
11596 if (this->assemblyRef() != other2->assemblyRef())
11597 return false;
11598
11599 if (this->nestedClass() != other2->nestedClass())
11600 return false;
11601
11602 if (this->nameSpace() != other2->nameSpace())
11603 return false;
11604
11605 if (this->cbName() != other2->cbName())
11606 return false;
11607
11608 LPCSTR p1 = this->pName();
11609 LPCSTR p2 = other2->pName();
11610
11611 for (DWORD i=0; (i < this->cbName()); i++)
11612 if (p1[i] != p2[i])
11613 return false;
11614
11615 return true;
11616}
11617
11618size_t ExternalTypeBlobEntry::Hash() const
11619{
11620 WRAPPER_NO_CONTRACT;
11621
11622 size_t hashValue = HashInit();
11623
11624 hashValue = HashCombine(hashValue, assemblyRef());
11625 hashValue = HashCombine(hashValue, nestedClass());
11626 hashValue = HashCombine(hashValue, nameSpace());
11627
11628 LPCSTR p1 = pName();
11629
11630 for (DWORD i=0; (i < cbName()); i++)
11631 hashValue = HashCombine(hashValue, p1[i]);
11632
11633 return hashValue;
11634}
11635
11636ExternalTypeBlobEntry::ExternalTypeBlobEntry(mdToken _assemblyRef,
11637 mdToken _nestedClass,
11638 mdToken _nameSpace,
11639 LPCSTR _pName)
11640{
11641 CONTRACTL
11642 {
11643 NOTHROW;
11644 GC_NOTRIGGER;
11645 PRECONDITION(CheckPointer(_pName));
11646 }
11647 CONTRACTL_END;
11648
11649 m_token = idExternalTypeNil;
11650 m_assemblyRef = mdAssemblyRefNil;
11651 m_nestedClass = idExternalTypeNil;
11652 m_nameSpace = idExternalNamespaceNil;
11653 m_cbName = 0;
11654 m_pName = NULL;
11655
11656 DWORD _cbName = (DWORD) strlen(_pName) + 1;
11657 LPSTR * pName = (LPSTR *) new (nothrow) CHAR[_cbName];
11658 if (pName != NULL)
11659 {
11660 m_assemblyRef = _assemblyRef;
11661 m_nestedClass = _nestedClass;
11662 m_nameSpace = _nameSpace;
11663 m_cbName = _cbName;
11664 memcpy(pName, _pName, _cbName);
11665 m_pName = (LPCSTR) pName;
11666 }
11667}
11668
11669/* static */ const ExternalTypeBlobEntry * ExternalTypeBlobEntry::FindOrAdd(PTR_Module pModule,
11670 mdToken _assemblyRef,
11671 mdToken _nestedClass,
11672 mdToken _nameSpace,
11673 LPCSTR _pName)
11674{
11675 CONTRACTL
11676 {
11677 NOTHROW;
11678 GC_NOTRIGGER;
11679 }
11680 CONTRACTL_END;
11681
11682 if ((_pName == NULL) || (::strlen(_pName) == 0))
11683 return NULL;
11684
11685 ExternalTypeBlobEntry sEntry(_assemblyRef, _nestedClass, _nameSpace, _pName);
11686
11687 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11688 if (pEntry == NULL)
11689 {
11690 //
11691 // Not Found, add a new external type blob entry
11692 //
11693 ExternalTypeBlobEntry * newEntry = new (nothrow) ExternalTypeBlobEntry(_assemblyRef, _nestedClass, _nameSpace, _pName);
11694 if (newEntry == NULL)
11695 return NULL;
11696
11697 newEntry->newToken(); // Assign a new ibc external type token
11698 CONTRACT_VIOLATION(ThrowsViolation);
11699 pModule->GetProfilingBlobTable()->Add(newEntry);
11700 pEntry = newEntry;
11701 }
11702
11703 //
11704 // Return the external type entry that we found or the new one that we just created
11705 //
11706 _ASSERTE(pEntry->kind() == ExternalTypeDef);
11707 return static_cast<const ExternalTypeBlobEntry *>(pEntry);
11708}
11709
11710bool ExternalSignatureBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11711{
11712 WRAPPER_NO_CONTRACT;
11713
11714 if (this->kind() != other->kind())
11715 return false;
11716
11717 const ExternalSignatureBlobEntry * other2 = static_cast<const ExternalSignatureBlobEntry *>(other);
11718
11719 if (this->cbSig() != other2->cbSig())
11720 return false;
11721
11722 PCCOR_SIGNATURE p1 = this->pSig();
11723 PCCOR_SIGNATURE p2 = other2->pSig();
11724
11725 for (DWORD i=0; (i < this->cbSig()); i++)
11726 if (p1[i] != p2[i])
11727 return false;
11728
11729 return true;
11730}
11731
11732size_t ExternalSignatureBlobEntry::Hash() const
11733{
11734 WRAPPER_NO_CONTRACT;
11735
11736 size_t hashValue = HashInit();
11737
11738 hashValue = HashCombine(hashValue, cbSig());
11739
11740 PCCOR_SIGNATURE p1 = pSig();
11741
11742 for (DWORD i=0; (i < cbSig()); i++)
11743 hashValue = HashCombine(hashValue, p1[i]);
11744
11745 return hashValue;
11746}
11747
11748ExternalSignatureBlobEntry::ExternalSignatureBlobEntry(DWORD _cbSig, PCCOR_SIGNATURE _pSig)
11749{
11750 CONTRACTL
11751 {
11752 NOTHROW;
11753 GC_NOTRIGGER;
11754 PRECONDITION(_cbSig > 0);
11755 PRECONDITION(CheckPointer(_pSig));
11756 }
11757 CONTRACTL_END;
11758
11759 m_token = idExternalSignatureNil;
11760 m_cbSig = 0;
11761
11762 COR_SIGNATURE * pNewSig = (COR_SIGNATURE *) new (nothrow) BYTE[_cbSig];
11763 if (pNewSig != NULL)
11764 {
11765 m_cbSig = _cbSig;
11766 memcpy(pNewSig, _pSig, _cbSig);
11767 }
11768 m_pSig = const_cast<PCCOR_SIGNATURE>(pNewSig);
11769}
11770
11771/* static */ const ExternalSignatureBlobEntry * ExternalSignatureBlobEntry::FindOrAdd(PTR_Module pModule,
11772 DWORD _cbSig,
11773 PCCOR_SIGNATURE _pSig)
11774{
11775 CONTRACTL
11776 {
11777 NOTHROW;
11778 GC_NOTRIGGER;
11779 }
11780 CONTRACTL_END;
11781
11782 if ((_cbSig == 0) || (_pSig == NULL))
11783 return NULL;
11784
11785 ExternalSignatureBlobEntry sEntry(_cbSig, _pSig);
11786
11787 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11788 if (pEntry == NULL)
11789 {
11790 //
11791 // Not Found, add a new external signature blob entry
11792 //
11793 ExternalSignatureBlobEntry * newEntry = new (nothrow) ExternalSignatureBlobEntry(_cbSig, _pSig);
11794 if (newEntry == NULL)
11795 return NULL;
11796
11797 newEntry->newToken(); // Assign a new ibc external signature token
11798 CONTRACT_VIOLATION(ThrowsViolation);
11799 pModule->GetProfilingBlobTable()->Add(newEntry);
11800 pEntry = newEntry;
11801 }
11802
11803 //
11804 // Return the external signature entry that we found or the new one that we just created
11805 //
11806 _ASSERTE(pEntry->kind() == ExternalSignatureDef);
11807 return static_cast<const ExternalSignatureBlobEntry *>(pEntry);
11808}
11809
11810bool ExternalMethodBlobEntry::IsEqual(const ProfilingBlobEntry * other) const
11811{
11812 WRAPPER_NO_CONTRACT;
11813
11814 if (this->kind() != other->kind())
11815 return false;
11816
11817 const ExternalMethodBlobEntry * other2 = static_cast<const ExternalMethodBlobEntry *>(other);
11818
11819 if (this->nestedClass() != other2->nestedClass())
11820 return false;
11821
11822 if (this->signature() != other2->signature())
11823 return false;
11824
11825 if (this->cbName() != other2->cbName())
11826 return false;
11827
11828 LPCSTR p1 = this->pName();
11829 LPCSTR p2 = other2->pName();
11830
11831 for (DWORD i=0; (i < this->cbName()); i++)
11832 if (p1[i] != p2[i])
11833 return false;
11834
11835 return true;
11836}
11837
11838size_t ExternalMethodBlobEntry::Hash() const
11839{
11840 WRAPPER_NO_CONTRACT;
11841
11842 size_t hashValue = HashInit();
11843
11844 hashValue = HashCombine(hashValue, nestedClass());
11845 hashValue = HashCombine(hashValue, signature());
11846
11847 LPCSTR p1 = pName();
11848
11849 for (DWORD i=0; (i < cbName()); i++)
11850 hashValue = HashCombine(hashValue, p1[i]);
11851
11852 return hashValue;
11853}
11854
11855ExternalMethodBlobEntry::ExternalMethodBlobEntry(mdToken _nestedClass,
11856 mdToken _signature,
11857 LPCSTR _pName)
11858{
11859 CONTRACTL
11860 {
11861 NOTHROW;
11862 GC_NOTRIGGER;
11863 PRECONDITION(CheckPointer(_pName));
11864 }
11865 CONTRACTL_END;
11866
11867 m_token = idExternalMethodNil;
11868 m_nestedClass = idExternalTypeNil;
11869 m_signature = idExternalSignatureNil;
11870 m_cbName = 0;
11871
11872 DWORD _cbName = (DWORD) strlen(_pName) + 1;
11873 LPSTR * pName = (LPSTR *) new (nothrow) CHAR[_cbName];
11874 if (pName != NULL)
11875 {
11876 m_nestedClass = _nestedClass;
11877 m_signature = _signature;
11878 m_cbName = _cbName;
11879 memcpy(pName, _pName, _cbName);
11880 m_pName = (LPSTR) pName;
11881 }
11882 }
11883
11884/* static */ const ExternalMethodBlobEntry * ExternalMethodBlobEntry::FindOrAdd(
11885 PTR_Module pModule,
11886 mdToken _nestedClass,
11887 mdToken _signature,
11888 LPCSTR _pName)
11889{
11890 CONTRACTL
11891 {
11892 NOTHROW;
11893 GC_NOTRIGGER;
11894 PRECONDITION(CheckPointer(_pName));
11895 }
11896 CONTRACTL_END;
11897
11898 if ((_pName == NULL) || (::strlen(_pName) == 0))
11899 return NULL;
11900
11901 ExternalMethodBlobEntry sEntry(_nestedClass, _signature, _pName);
11902
11903 const ProfilingBlobEntry * pEntry = pModule->GetProfilingBlobTable()->Lookup(&sEntry);
11904 if (pEntry == NULL)
11905 {
11906 //
11907 // Not Found, add a new external type blob entry
11908 //
11909 ExternalMethodBlobEntry * newEntry;
11910 newEntry = new (nothrow) ExternalMethodBlobEntry(_nestedClass, _signature, _pName);
11911 if (newEntry == NULL)
11912 return NULL;
11913
11914 newEntry->newToken(); // Assign a new ibc external method token
11915 CONTRACT_VIOLATION(ThrowsViolation);
11916 pModule->GetProfilingBlobTable()->Add(newEntry);
11917 pEntry = newEntry;
11918 }
11919
11920 //
11921 // Return the external method entry that we found or the new one that we just created
11922 //
11923 _ASSERTE(pEntry->kind() == ExternalMethodDef);
11924 return static_cast<const ExternalMethodBlobEntry *>(pEntry);
11925}
11926
11927
11928static bool GetBasename(LPCWSTR _src, __out_ecount(dstlen) __out_z LPWSTR _dst, int dstlen)
11929{
11930 LIMITED_METHOD_CONTRACT;
11931 LPCWSTR src = _src;
11932 LPWSTR dst = _dst;
11933
11934 if ((src == NULL) || (dstlen <= 0))
11935 return false;
11936
11937 bool inQuotes = false;
11938 LPWSTR dstLast = dst + (dstlen - 1);
11939 while (dst < dstLast)
11940 {
11941 WCHAR wch = *src++;
11942 if (wch == W('"'))
11943 {
11944 inQuotes = !inQuotes;
11945 continue;
11946 }
11947
11948 if (wch == 0)
11949 break;
11950
11951 *dst++ = wch;
11952
11953 if (!inQuotes)
11954 {
11955 if ((wch == W('\\')) || (wch == W(':')))
11956 {
11957 dst = _dst;
11958 }
11959 else if (wch == W(' '))
11960 {
11961 dst--;
11962 break;
11963 }
11964 }
11965 }
11966 *dst++ = 0;
11967 return true;
11968}
11969
11970static void ProfileDataAllocateScenarioInfo(ProfileEmitter * pEmitter, LPCSTR scopeName, GUID* pMvid)
11971{
11972 CONTRACTL
11973 {
11974 THROWS;
11975 GC_NOTRIGGER;
11976 MODE_ANY;
11977 INJECT_FAULT(COMPlusThrowOM());
11978 }
11979 CONTRACTL_END;
11980
11981 ProfileMap *profileMap = pEmitter->EmitNewSection(ScenarioInfo);
11982
11983 //
11984 // Allocate and initialize the scenario info section
11985 //
11986 {
11987 CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *siHeader;
11988 siHeader = (CORBBTPROF_SCENARIO_INFO_SECTION_HEADER *) profileMap->Allocate(sizeof(CORBBTPROF_SCENARIO_INFO_SECTION_HEADER));
11989
11990 siHeader->NumScenarios = 1;
11991 siHeader->TotalNumRuns = 1;
11992 }
11993
11994 //
11995 // Allocate and initialize the scenario header section
11996 //
11997 {
11998 LPCWSTR pCmdLine = GetCommandLineW();
11999 S_SIZE_T cCmdLine = S_SIZE_T(wcslen(pCmdLine));
12000 cCmdLine += 1;
12001 if (cCmdLine.IsOverflow())
12002 {
12003 ThrowHR(COR_E_OVERFLOW);
12004 }
12005
12006 LPCWSTR pSystemInfo = W("<machine,OS>");
12007 S_SIZE_T cSystemInfo = S_SIZE_T(wcslen(pSystemInfo));
12008 cSystemInfo += 1;
12009 if (cSystemInfo.IsOverflow())
12010 {
12011 ThrowHR(COR_E_OVERFLOW);
12012 }
12013
12014 FILETIME runTime, unused1, unused2, unused3;
12015 GetProcessTimes(GetCurrentProcess(), &runTime, &unused1, &unused2, &unused3);
12016
12017 WCHAR scenarioName[256];
12018 GetBasename(pCmdLine, &scenarioName[0], 256);
12019
12020 LPCWSTR pName = &scenarioName[0];
12021 S_SIZE_T cName = S_SIZE_T(wcslen(pName));
12022 cName += 1;
12023 if (cName.IsOverflow())
12024 {
12025 ThrowHR(COR_E_OVERFLOW);
12026 }
12027
12028 S_SIZE_T sizeHeader = S_SIZE_T(sizeof(CORBBTPROF_SCENARIO_HEADER));
12029 sizeHeader += cName * S_SIZE_T(sizeof(WCHAR));
12030 if (sizeHeader.IsOverflow())
12031 {
12032 ThrowHR(COR_E_OVERFLOW);
12033 }
12034
12035 S_SIZE_T sizeRun = S_SIZE_T(sizeof(CORBBTPROF_SCENARIO_RUN));
12036 sizeRun += cCmdLine * S_SIZE_T(sizeof(WCHAR));
12037 sizeRun += cSystemInfo * S_SIZE_T(sizeof(WCHAR));
12038 if (sizeRun.IsOverflow())
12039 {
12040 ThrowHR(COR_E_OVERFLOW);
12041 }
12042
12043 //
12044 // Allocate the Scenario Header struct
12045 //
12046 SIZE_T sHeaderOffset;
12047 {
12048 CORBBTPROF_SCENARIO_HEADER *sHeader;
12049 S_SIZE_T sHeaderSize = sizeHeader + sizeRun;
12050 if (sHeaderSize.IsOverflow())
12051 {
12052 ThrowHR(COR_E_OVERFLOW);
12053 }
12054
12055 sHeaderOffset = profileMap->getCurrentOffset();
12056 sHeader = (CORBBTPROF_SCENARIO_HEADER *) profileMap->Allocate(sizeHeader.Value());
12057
12058 sHeader->size = sHeaderSize.Value();
12059 sHeader->scenario.ordinal = 1;
12060 sHeader->scenario.mask = 1;
12061 sHeader->scenario.priority = 0;
12062 sHeader->scenario.numRuns = 1;
12063 sHeader->scenario.cName = cName.Value();
12064 wcscpy_s(sHeader->scenario.name, cName.Value(), pName);
12065 }
12066
12067 //
12068 // Allocate the Scenario Run struct
12069 //
12070 {
12071 CORBBTPROF_SCENARIO_RUN *sRun;
12072 sRun = (CORBBTPROF_SCENARIO_RUN *) profileMap->Allocate(sizeRun.Value());
12073
12074 sRun->runTime = runTime;
12075 sRun->mvid = *pMvid;
12076 sRun->cCmdLine = cCmdLine.Value();
12077 sRun->cSystemInfo = cSystemInfo.Value();
12078 wcscpy_s(sRun->cmdLine, cCmdLine.Value(), pCmdLine);
12079 wcscpy_s(sRun->cmdLine+cCmdLine.Value(), cSystemInfo.Value(), pSystemInfo);
12080 }
12081#ifdef _DEBUG
12082 {
12083 CORBBTPROF_SCENARIO_HEADER * sHeader;
12084 sHeader = (CORBBTPROF_SCENARIO_HEADER *) profileMap->getOffsetPtr(sHeaderOffset);
12085 assert(sHeader->size == sHeader->Size());
12086 }
12087#endif
12088 }
12089}
12090
12091static void ProfileDataAllocateMethodBlockCounts(ProfileEmitter * pEmitter, CORCOMPILE_METHOD_PROFILE_LIST * pMethodProfileListHead)
12092{
12093 CONTRACTL
12094 {
12095 THROWS;
12096 GC_NOTRIGGER;
12097 MODE_ANY;
12098 INJECT_FAULT(COMPlusThrowOM());
12099 }
12100 CONTRACTL_END;
12101
12102 ProfileMap *profileMap = pEmitter->EmitNewSection(MethodBlockCounts);
12103
12104 //
12105 // Allocate and initialize the method block count section
12106 //
12107 SIZE_T mbcHeaderOffset;
12108 {
12109 CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *mbcHeader;
12110 mbcHeaderOffset = profileMap->getCurrentOffset();
12111 mbcHeader = (CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *)
12112 profileMap->Allocate(sizeof(CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER));
12113 mbcHeader->NumMethods = 0; // This gets filled in later
12114 }
12115
12116 ULONG numMethods = 0; // We count the number of methods that were executed
12117
12118 for (CORCOMPILE_METHOD_PROFILE_LIST * methodProfileList = pMethodProfileListHead;
12119 methodProfileList;
12120 methodProfileList = methodProfileList->next)
12121 {
12122 CORBBTPROF_METHOD_HEADER * pInfo = methodProfileList->GetInfo();
12123
12124 assert(pInfo->size == pInfo->Size());
12125
12126 //
12127 // We set methodWasExecuted based upon the ExecutionCount of the very first block
12128 //
12129 bool methodWasExecuted = (pInfo->method.block[0].ExecutionCount > 0);
12130
12131 //
12132 // If the method was not executed then we don't need to output this methods block counts
12133 //
12134 SIZE_T methodHeaderOffset;
12135 if (methodWasExecuted)
12136 {
12137 DWORD profileDataSize = pInfo->size;
12138 methodHeaderOffset = profileMap->getCurrentOffset();
12139 CORBBTPROF_METHOD_HEADER *methodHeader = (CORBBTPROF_METHOD_HEADER *) profileMap->Allocate(profileDataSize);
12140 memcpy(methodHeader, pInfo, profileDataSize);
12141 numMethods++;
12142 }
12143
12144 // Reset all of the basic block counts to zero
12145 for (ULONG i=0; (i < pInfo->method.cBlock); i++ )
12146 {
12147 //
12148 // If methodWasExecuted is false then every block's ExecutionCount should also be zero
12149 //
12150 _ASSERTE(methodWasExecuted || (pInfo->method.block[i].ExecutionCount == 0));
12151
12152 pInfo->method.block[i].ExecutionCount = 0;
12153 }
12154 }
12155
12156 {
12157 CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *mbcHeader;
12158 // We have to refetch the mbcHeader as calls to Allocate will resize and thus move the mbcHeader
12159 mbcHeader = (CORBBTPROF_METHOD_BLOCK_COUNTS_SECTION_HEADER *) profileMap->getOffsetPtr(mbcHeaderOffset);
12160 mbcHeader->NumMethods = numMethods;
12161 }
12162}
12163
12164/*static*/ void Module::ProfileDataAllocateTokenLists(ProfileEmitter * pEmitter, Module::TokenProfileData* pTokenProfileData)
12165{
12166 CONTRACTL
12167 {
12168 THROWS;
12169 GC_NOTRIGGER;
12170 MODE_ANY;
12171 INJECT_FAULT(COMPlusThrowOM());
12172 }
12173 CONTRACTL_END;
12174
12175 //
12176 // Allocate and initialize the token list sections
12177 //
12178 if (pTokenProfileData)
12179 {
12180 for (int format = 0; format < (int)SectionFormatCount; format++)
12181 {
12182 CQuickArray<CORBBTPROF_TOKEN_INFO> *pTokenArray = &(pTokenProfileData->m_formats[format].tokenArray);
12183
12184 if (pTokenArray->Size() != 0)
12185 {
12186 ProfileMap * profileMap = pEmitter->EmitNewSection((SectionFormat) format);
12187
12188 CORBBTPROF_TOKEN_LIST_SECTION_HEADER *header;
12189 header = (CORBBTPROF_TOKEN_LIST_SECTION_HEADER *)
12190 profileMap->Allocate(sizeof(CORBBTPROF_TOKEN_LIST_SECTION_HEADER) +
12191 pTokenArray->Size() * sizeof(CORBBTPROF_TOKEN_INFO));
12192
12193 header->NumTokens = pTokenArray->Size();
12194 memcpy( (header + 1), &((*pTokenArray)[0]), pTokenArray->Size() * sizeof(CORBBTPROF_TOKEN_INFO));
12195
12196 // Reset the collected tokens
12197 for (unsigned i = 0; i < CORBBTPROF_TOKEN_MAX_NUM_FLAGS; i++)
12198 {
12199 pTokenProfileData->m_formats[format].tokenBitmaps[i].Reset();
12200 }
12201 pTokenProfileData->m_formats[format].tokenArray.ReSizeNoThrow(0);
12202 }
12203 }
12204 }
12205}
12206
12207static void ProfileDataAllocateTokenDefinitions(ProfileEmitter * pEmitter, Module * pModule)
12208{
12209 CONTRACTL
12210 {
12211 THROWS;
12212 GC_NOTRIGGER;
12213 MODE_ANY;
12214 INJECT_FAULT(COMPlusThrowOM());
12215 }
12216 CONTRACTL_END;
12217
12218 //
12219 // Allocate and initialize the ibc token definition section (aka the Blob stream)
12220 //
12221 ProfileMap * profileMap = pEmitter->EmitNewSection(BlobStream);
12222
12223 // Compute the size of the metadata section:
12224 // It is the sum of all of the Metadata Profile pool entries
12225 // plus the sum of all of the Param signature entries
12226 //
12227 size_t totalSize = 0;
12228
12229 for (ProfilingBlobTable::Iterator cur = pModule->GetProfilingBlobTable()->Begin(),
12230 end = pModule->GetProfilingBlobTable()->End();
12231 (cur != end);
12232 cur++)
12233 {
12234 const ProfilingBlobEntry * pEntry = *cur;
12235 size_t blobElementSize = pEntry->varSize();
12236 switch (pEntry->kind()) {
12237 case ParamTypeSpec:
12238 case ParamMethodSpec:
12239 blobElementSize += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
12240 break;
12241
12242 case ExternalNamespaceDef:
12243 blobElementSize += sizeof(CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY);
12244 break;
12245
12246 case ExternalTypeDef:
12247 blobElementSize += sizeof(CORBBTPROF_BLOB_TYPE_DEF_ENTRY);
12248 break;
12249
12250 case ExternalSignatureDef:
12251 blobElementSize += sizeof(CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY);
12252 break;
12253
12254 case ExternalMethodDef:
12255 blobElementSize += sizeof(CORBBTPROF_BLOB_METHOD_DEF_ENTRY);
12256 break;
12257
12258 default:
12259 _ASSERTE(!"Unexpected blob type");
12260 break;
12261 }
12262 totalSize += blobElementSize;
12263 }
12264
12265 profileMap->Allocate(totalSize);
12266
12267 size_t currentPos = 0;
12268
12269 // Traverse each element and record it
12270 size_t blobElementSize = 0;
12271 for (ProfilingBlobTable::Iterator cur = pModule->GetProfilingBlobTable()->Begin(),
12272 end = pModule->GetProfilingBlobTable()->End();
12273 (cur != end);
12274 cur++, currentPos += blobElementSize)
12275 {
12276 const ProfilingBlobEntry * pEntry = *cur;
12277 blobElementSize = pEntry->varSize();
12278 void *profileData = profileMap->getOffsetPtr(currentPos);
12279
12280 switch (pEntry->kind()) {
12281 case ParamTypeSpec:
12282 {
12283 CORBBTPROF_BLOB_PARAM_SIG_ENTRY * bProfileData = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY*) profileData;
12284 const TypeSpecBlobEntry * typeSpecBlobEntry = static_cast<const TypeSpecBlobEntry *>(pEntry);
12285
12286 blobElementSize += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
12287 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12288 bProfileData->blob.type = typeSpecBlobEntry->kind();
12289 bProfileData->blob.token = typeSpecBlobEntry->token();
12290 _ASSERTE(typeSpecBlobEntry->cbSig() > 0);
12291 bProfileData->cSig = typeSpecBlobEntry->cbSig();
12292 memcpy(&bProfileData->sig[0], typeSpecBlobEntry->pSig(), typeSpecBlobEntry->cbSig());
12293 break;
12294 }
12295
12296 case ParamMethodSpec:
12297 {
12298 CORBBTPROF_BLOB_PARAM_SIG_ENTRY * bProfileData = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY*) profileData;
12299 const MethodSpecBlobEntry * methodSpecBlobEntry = static_cast<const MethodSpecBlobEntry *>(pEntry);
12300
12301 blobElementSize += sizeof(CORBBTPROF_BLOB_PARAM_SIG_ENTRY);
12302 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12303 bProfileData->blob.type = methodSpecBlobEntry->kind();
12304 bProfileData->blob.token = methodSpecBlobEntry->token();
12305 _ASSERTE(methodSpecBlobEntry->cbSig() > 0);
12306 bProfileData->cSig = methodSpecBlobEntry->cbSig();
12307 memcpy(&bProfileData->sig[0], methodSpecBlobEntry->pSig(), methodSpecBlobEntry->cbSig());
12308 break;
12309 }
12310
12311 case ExternalNamespaceDef:
12312 {
12313 CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY*) profileData;
12314 const ExternalNamespaceBlobEntry * namespaceBlobEntry = static_cast<const ExternalNamespaceBlobEntry *>(pEntry);
12315
12316 blobElementSize += sizeof(CORBBTPROF_BLOB_NAMESPACE_DEF_ENTRY);
12317 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12318 bProfileData->blob.type = namespaceBlobEntry->kind();
12319 bProfileData->blob.token = namespaceBlobEntry->token();
12320 _ASSERTE(namespaceBlobEntry->cbName() > 0);
12321 bProfileData->cName = namespaceBlobEntry->cbName();
12322 memcpy(&bProfileData->name[0], namespaceBlobEntry->pName(), namespaceBlobEntry->cbName());
12323 break;
12324 }
12325
12326 case ExternalTypeDef:
12327 {
12328 CORBBTPROF_BLOB_TYPE_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_TYPE_DEF_ENTRY*) profileData;
12329 const ExternalTypeBlobEntry * typeBlobEntry = static_cast<const ExternalTypeBlobEntry *>(pEntry);
12330
12331 blobElementSize += sizeof(CORBBTPROF_BLOB_TYPE_DEF_ENTRY);
12332 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12333 bProfileData->blob.type = typeBlobEntry->kind();
12334 bProfileData->blob.token = typeBlobEntry->token();
12335 bProfileData->assemblyRefToken = typeBlobEntry->assemblyRef();
12336 bProfileData->nestedClassToken = typeBlobEntry->nestedClass();
12337 bProfileData->nameSpaceToken = typeBlobEntry->nameSpace();
12338 _ASSERTE(typeBlobEntry->cbName() > 0);
12339 bProfileData->cName = typeBlobEntry->cbName();
12340 memcpy(&bProfileData->name[0], typeBlobEntry->pName(), typeBlobEntry->cbName());
12341 break;
12342 }
12343
12344 case ExternalSignatureDef:
12345 {
12346 CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY*) profileData;
12347 const ExternalSignatureBlobEntry * signatureBlobEntry = static_cast<const ExternalSignatureBlobEntry *>(pEntry);
12348
12349 blobElementSize += sizeof(CORBBTPROF_BLOB_SIGNATURE_DEF_ENTRY);
12350 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12351 bProfileData->blob.type = signatureBlobEntry->kind();
12352 bProfileData->blob.token = signatureBlobEntry->token();
12353 _ASSERTE(signatureBlobEntry->cbSig() > 0);
12354 bProfileData->cSig = signatureBlobEntry->cbSig();
12355 memcpy(&bProfileData->sig[0], signatureBlobEntry->pSig(), signatureBlobEntry->cbSig());
12356 break;
12357 }
12358
12359 case ExternalMethodDef:
12360 {
12361 CORBBTPROF_BLOB_METHOD_DEF_ENTRY * bProfileData = (CORBBTPROF_BLOB_METHOD_DEF_ENTRY*) profileData;
12362 const ExternalMethodBlobEntry * methodBlobEntry = static_cast<const ExternalMethodBlobEntry *>(pEntry);
12363
12364 blobElementSize += sizeof(CORBBTPROF_BLOB_METHOD_DEF_ENTRY);
12365 bProfileData->blob.size = static_cast<DWORD>(blobElementSize);
12366 bProfileData->blob.type = methodBlobEntry->kind();
12367 bProfileData->blob.token = methodBlobEntry->token();
12368 bProfileData->nestedClassToken = methodBlobEntry->nestedClass();
12369 bProfileData->signatureToken = methodBlobEntry->signature();
12370 _ASSERTE(methodBlobEntry->cbName() > 0);
12371 bProfileData->cName = methodBlobEntry->cbName();
12372 memcpy(&bProfileData->name[0], methodBlobEntry->pName(), methodBlobEntry->cbName());
12373 break;
12374 }
12375
12376 default:
12377 _ASSERTE(!"Unexpected blob type");
12378 break;
12379 }
12380 }
12381
12382 _ASSERTE(currentPos == totalSize);
12383
12384 // Emit a terminating entry with type EndOfBlobStream to mark the end
12385 DWORD mdElementSize = sizeof(CORBBTPROF_BLOB_ENTRY);
12386 void *profileData = profileMap->Allocate(mdElementSize);
12387 memset(profileData, 0, mdElementSize);
12388
12389 CORBBTPROF_BLOB_ENTRY* mdProfileData = (CORBBTPROF_BLOB_ENTRY*) profileData;
12390 mdProfileData->type = EndOfBlobStream;
12391 mdProfileData->size = sizeof(CORBBTPROF_BLOB_ENTRY);
12392}
12393
12394// Responsible for writing out the profile data if the COMPlus_BBInstr
12395// environment variable is set. This is called when the module is unloaded
12396// (usually at shutdown).
12397HRESULT Module::WriteMethodProfileDataLogFile(bool cleanup)
12398{
12399 CONTRACTL
12400 {
12401 INSTANCE_CHECK;
12402 NOTHROW;
12403 GC_TRIGGERS;
12404 MODE_ANY;
12405 INJECT_FAULT(return E_OUTOFMEMORY;);
12406 }
12407 CONTRACTL_END;
12408
12409 HRESULT hr = S_OK;
12410
12411 if (IsResource())
12412 return S_OK;
12413
12414 EX_TRY
12415 {
12416 if (GetAssembly()->IsInstrumented() && (m_pProfilingBlobTable != NULL) && (m_tokenProfileData != NULL))
12417 {
12418 ProfileEmitter * pEmitter = new ProfileEmitter();
12419
12420 // Get this ahead of time - metadata access may be logged, which will
12421 // take the m_tokenProfileData->crst, which we take a couple lines below
12422 LPCSTR pszName;
12423 GUID mvid;
12424 IfFailThrow(GetMDImport()->GetScopeProps(&pszName, &mvid));
12425
12426 CrstHolder ch(&m_tokenProfileData->crst);
12427
12428 //
12429 // Create the scenario info section
12430 //
12431 ProfileDataAllocateScenarioInfo(pEmitter, pszName, &mvid);
12432
12433 //
12434 // Create the method block count section
12435 //
12436 ProfileDataAllocateMethodBlockCounts(pEmitter, m_methodProfileList);
12437
12438 //
12439 // Create the token list sections
12440 //
12441 ProfileDataAllocateTokenLists(pEmitter, m_tokenProfileData);
12442
12443 //
12444 // Create the ibc token definition section (aka the Blob stream)
12445 //
12446 ProfileDataAllocateTokenDefinitions(pEmitter, this);
12447
12448 //
12449 // Now store the profile data in the ibc file
12450 //
12451 ProfileMap profileImage;
12452 pEmitter->Serialize(&profileImage, mvid);
12453
12454 HandleHolder profileDataFile(OpenMethodProfileDataLogFile(mvid));
12455
12456 ULONG count;
12457 BOOL result = WriteFile(profileDataFile, profileImage.getOffsetPtr(0), profileImage.getCurrentOffset(), &count, NULL);
12458 if (!result || (count != profileImage.getCurrentOffset()))
12459 {
12460 DWORD lasterror = GetLastError();
12461 _ASSERTE(!"Error writing ibc profile data to file");
12462 hr = HRESULT_FROM_WIN32(lasterror);
12463 }
12464 }
12465
12466 if (cleanup)
12467 {
12468 DeleteProfilingData();
12469 }
12470 }
12471 EX_CATCH
12472 {
12473 hr = E_FAIL;
12474 }
12475 EX_END_CATCH(SwallowAllExceptions)
12476
12477 return hr;
12478}
12479
12480
12481/* static */
12482void Module::WriteAllModuleProfileData(bool cleanup)
12483{
12484 CONTRACTL
12485 {
12486 NOTHROW;
12487 GC_TRIGGERS;
12488 MODE_ANY;
12489 }
12490 CONTRACTL_END;
12491
12492 // Iterate over all the app domains; for each one iterator over its
12493 // assemblies; for each one iterate over its modules.
12494 EX_TRY
12495 {
12496 AppDomainIterator appDomainIterator(FALSE);
12497 while(appDomainIterator.Next())
12498 {
12499 AppDomain * appDomain = appDomainIterator.GetDomain();
12500 AppDomain::AssemblyIterator assemblyIterator = appDomain->IterateAssembliesEx(
12501 (AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution));
12502 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
12503
12504 while (assemblyIterator.Next(pDomainAssembly.This()))
12505 {
12506 DomainModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
12507 while (i.Next())
12508 {
12509 /*hr=*/i.GetModule()->WriteMethodProfileDataLogFile(cleanup);
12510 }
12511 }
12512 }
12513 }
12514 EX_CATCH
12515 { }
12516 EX_END_CATCH(SwallowAllExceptions);
12517}
12518
12519PTR_ProfilingBlobTable Module::GetProfilingBlobTable()
12520{
12521 LIMITED_METHOD_CONTRACT;
12522 return m_pProfilingBlobTable;
12523}
12524
12525void Module::CreateProfilingData()
12526{
12527 TokenProfileData *tpd = TokenProfileData::CreateNoThrow();
12528
12529 PVOID pv = InterlockedCompareExchangeT(&m_tokenProfileData, tpd, NULL);
12530 if (pv != NULL)
12531 {
12532 delete tpd;
12533 }
12534
12535 PTR_ProfilingBlobTable ppbt = new (nothrow) ProfilingBlobTable();
12536
12537 if (ppbt != NULL)
12538 {
12539 pv = InterlockedCompareExchangeT(&m_pProfilingBlobTable, ppbt, NULL);
12540 if (pv != NULL)
12541 {
12542 delete ppbt;
12543 }
12544 }
12545}
12546
12547void Module::DeleteProfilingData()
12548{
12549 if (m_pProfilingBlobTable != NULL)
12550 {
12551 for (ProfilingBlobTable::Iterator cur = m_pProfilingBlobTable->Begin(),
12552 end = m_pProfilingBlobTable->End();
12553 (cur != end);
12554 cur++)
12555 {
12556 const ProfilingBlobEntry * pCurrentEntry = *cur;
12557 delete pCurrentEntry;
12558 }
12559 delete m_pProfilingBlobTable;
12560 m_pProfilingBlobTable = NULL;
12561 }
12562
12563 if (m_tokenProfileData != NULL)
12564 {
12565 delete m_tokenProfileData;
12566 m_tokenProfileData = NULL;
12567 }
12568
12569 // the metadataProfileData is free'ed in destructor of the corresponding MetaDataTracker
12570}
12571#endif //FEATURE_PREJIT
12572
12573void Module::SetIsIJWFixedUp()
12574{
12575 LIMITED_METHOD_CONTRACT;
12576 FastInterlockOr(&m_dwTransientFlags, IS_IJW_FIXED_UP);
12577}
12578
12579#ifdef FEATURE_PREJIT
12580/* static */
12581Module::TokenProfileData *Module::TokenProfileData::CreateNoThrow(void)
12582{
12583 STATIC_CONTRACT_NOTHROW;
12584
12585 TokenProfileData *tpd = NULL;
12586
12587 EX_TRY
12588 {
12589 //
12590 // This constructor calls crst.Init(), which may throw. So putting (nothrow) doesn't
12591 // do what we would want it to. Thus I wrap it here in a TRY/CATCH and revert to NULL
12592 // if it fails.
12593 //
12594 tpd = new TokenProfileData();
12595 }
12596 EX_CATCH
12597 {
12598 tpd = NULL;
12599 }
12600 EX_END_CATCH(SwallowAllExceptions);
12601
12602 return tpd;
12603}
12604
12605#endif // FEATURE_PREJIT
12606
12607#endif // !DACCESS_COMPILE
12608
12609#ifndef DACCESS_COMPILE
12610void Module::SetBeingUnloaded()
12611{
12612 LIMITED_METHOD_CONTRACT;
12613 FastInterlockOr((ULONG*)&m_dwTransientFlags, IS_BEING_UNLOADED);
12614}
12615#endif
12616
12617#ifdef FEATURE_PREJIT
12618void Module::LogTokenAccess(mdToken token, SectionFormat format, ULONG flagnum)
12619{
12620 CONTRACTL
12621 {
12622 INSTANCE_CHECK;
12623 NOTHROW;
12624 GC_NOTRIGGER;
12625 MODE_ANY;
12626 PRECONDITION(g_IBCLogger.InstrEnabled());
12627 PRECONDITION(flagnum < CORBBTPROF_TOKEN_MAX_NUM_FLAGS);
12628 }
12629 CONTRACTL_END;
12630
12631#ifndef DACCESS_COMPILE
12632
12633 //
12634 // If we are in ngen instrumentation mode, then we should record this token.
12635 //
12636
12637 if (!m_nativeImageProfiling)
12638 return;
12639
12640 if (flagnum >= CORBBTPROF_TOKEN_MAX_NUM_FLAGS)
12641 {
12642 return;
12643 }
12644
12645 mdToken rid = RidFromToken(token);
12646 CorTokenType tkType = (CorTokenType) TypeFromToken(token);
12647 SectionFormat tkKind = (SectionFormat) (tkType >> 24);
12648
12649 if ((rid == 0) && (tkKind < (SectionFormat) TBL_COUNT))
12650 return;
12651
12652 FAULT_NOT_FATAL();
12653
12654 _ASSERTE(TypeProfilingData == FirstTokenFlagSection + TBL_TypeDef);
12655 _ASSERTE(MethodProfilingData == FirstTokenFlagSection + TBL_Method);
12656 _ASSERTE(SectionFormatCount >= FirstTokenFlagSection + TBL_COUNT + 4);
12657
12658 if (!m_tokenProfileData)
12659 {
12660 CreateProfilingData();
12661 }
12662
12663 if (!m_tokenProfileData)
12664 {
12665 return;
12666 }
12667
12668 if (tkKind == (SectionFormat) (ibcTypeSpec >> 24))
12669 tkKind = IbcTypeSpecSection;
12670 else if (tkKind == (SectionFormat) (ibcMethodSpec >> 24))
12671 tkKind = IbcMethodSpecSection;
12672
12673 _ASSERTE(tkKind >= 0);
12674 _ASSERTE(tkKind < SectionFormatCount);
12675 if (tkKind < 0 || tkKind >= SectionFormatCount)
12676 {
12677 return;
12678 }
12679
12680 CQuickArray<CORBBTPROF_TOKEN_INFO> * pTokenArray = &m_tokenProfileData->m_formats[format].tokenArray;
12681 RidBitmap * pTokenBitmap = &m_tokenProfileData->m_formats[tkKind].tokenBitmaps[flagnum];
12682
12683 // Have we seen this token with this flag already?
12684 if (pTokenBitmap->IsTokenInBitmap(token))
12685 {
12686 return;
12687 }
12688
12689 // Insert the token to the bitmap
12690 if (FAILED(pTokenBitmap->InsertToken(token)))
12691 {
12692 return;
12693 }
12694
12695 ULONG flag = 1 << flagnum;
12696
12697 // [ToDo] Fix: this is a sequential search and can be very slow
12698 for (unsigned int i = 0; i < pTokenArray->Size(); i++)
12699 {
12700 if ((*pTokenArray)[i].token == token)
12701 {
12702 _ASSERTE(! ((*pTokenArray)[i].flags & flag));
12703 (*pTokenArray)[i].flags |= flag;
12704 return;
12705 }
12706 }
12707
12708 if (FAILED(pTokenArray->ReSizeNoThrow(pTokenArray->Size() + 1)))
12709 {
12710 return;
12711 }
12712
12713 (*pTokenArray)[pTokenArray->Size() - 1].token = token;
12714 (*pTokenArray)[pTokenArray->Size() - 1].flags = flag;
12715 (*pTokenArray)[pTokenArray->Size() - 1].scenarios = 0;
12716
12717#endif // !DACCESS_COMPILE
12718}
12719
12720void Module::LogTokenAccess(mdToken token, ULONG flagNum)
12721{
12722 WRAPPER_NO_CONTRACT;
12723 SectionFormat format = (SectionFormat)((TypeFromToken(token)>>24) + FirstTokenFlagSection);
12724 if (FirstTokenFlagSection <= format && format < SectionFormatCount)
12725 {
12726 LogTokenAccess(token, format, flagNum);
12727 }
12728}
12729#endif // FEATURE_PREJIT
12730
12731#ifndef DACCESS_COMPILE
12732#ifdef FEATURE_PREJIT
12733
12734//
12735// Encoding callbacks
12736//
12737
12738/*static*/ DWORD Module::EncodeModuleHelper(void * pModuleContext, Module *pReferencedModule)
12739{
12740 Module* pReferencingModule = (Module *) pModuleContext;
12741 _ASSERTE(pReferencingModule != pReferencedModule);
12742
12743 Assembly *pReferencingAssembly = pReferencingModule->GetAssembly();
12744 Assembly *pReferencedAssembly = pReferencedModule->GetAssembly();
12745
12746 _ASSERTE(pReferencingAssembly != pReferencedAssembly);
12747
12748 if (pReferencedAssembly == pReferencingAssembly)
12749 {
12750 return 0;
12751 }
12752
12753 mdAssemblyRef token = pReferencingModule->FindAssemblyRef(pReferencedAssembly);
12754
12755 if (IsNilToken(token))
12756 {
12757 return ENCODE_MODULE_FAILED;
12758 }
12759
12760 return RidFromToken(token);
12761}
12762
12763/*static*/ void Module::TokenDefinitionHelper(void* pModuleContext, Module *pReferencedModule, DWORD index, mdToken* pToken)
12764{
12765 LIMITED_METHOD_CONTRACT;
12766 HRESULT hr;
12767 Module * pReferencingModule = (Module *) pModuleContext;
12768 mdAssemblyRef mdAssemblyRef = TokenFromRid(index, mdtAssemblyRef);
12769 IMDInternalImport * pImport = pReferencedModule->GetMDImport();
12770 LPCUTF8 szName = NULL;
12771
12772 if (TypeFromToken(*pToken) == mdtTypeDef)
12773 {
12774 //
12775 // Compute nested type (if any)
12776 //
12777 mdTypeDef mdEnclosingType = idExternalTypeNil;
12778 hr = pImport->GetNestedClassProps(*pToken, &mdEnclosingType);
12779 // If there's not enclosing type, then hr=CLDB_E_RECORD_NOTFOUND and mdEnclosingType is unchanged
12780 _ASSERTE((hr == S_OK) || (hr == CLDB_E_RECORD_NOTFOUND));
12781
12782 if (!IsNilToken(mdEnclosingType))
12783 {
12784 _ASSERT(TypeFromToken(mdEnclosingType) == mdtTypeDef);
12785 TokenDefinitionHelper(pModuleContext, pReferencedModule, index, &mdEnclosingType);
12786 }
12787 _ASSERT(TypeFromToken(mdEnclosingType) == ibcExternalType);
12788
12789 //
12790 // Compute type name and namespace.
12791 //
12792 LPCUTF8 szNamespace = NULL;
12793 hr = pImport->GetNameOfTypeDef(*pToken, &szName, &szNamespace);
12794 _ASSERTE(hr == S_OK);
12795
12796 //
12797 // Transform namespace string into ibc external namespace token
12798 //
12799 idExternalNamespace idNamespace = idExternalNamespaceNil;
12800 if (szNamespace != NULL)
12801 {
12802 const ExternalNamespaceBlobEntry * pNamespaceEntry;
12803 pNamespaceEntry = ExternalNamespaceBlobEntry::FindOrAdd(pReferencingModule, szNamespace);
12804 if (pNamespaceEntry != NULL)
12805 {
12806 idNamespace = pNamespaceEntry->token();
12807 }
12808 }
12809 _ASSERTE(TypeFromToken(idNamespace) == ibcExternalNamespace);
12810
12811 //
12812 // Transform type name into ibc external type token
12813 //
12814 idExternalType idType = idExternalTypeNil;
12815 _ASSERTE(szName != NULL);
12816 const ExternalTypeBlobEntry * pTypeEntry = NULL;
12817 pTypeEntry = ExternalTypeBlobEntry::FindOrAdd(pReferencingModule,
12818 mdAssemblyRef,
12819 mdEnclosingType,
12820 idNamespace,
12821 szName);
12822 if (pTypeEntry != NULL)
12823 {
12824 idType = pTypeEntry->token();
12825 }
12826 _ASSERTE(TypeFromToken(idType) == ibcExternalType);
12827
12828 *pToken = idType; // Remap pToken to our idExternalType token
12829 }
12830 else if (TypeFromToken(*pToken) == mdtMethodDef)
12831 {
12832 //
12833 // Compute nested type (if any)
12834 //
12835 mdTypeDef mdEnclosingType = idExternalTypeNil;
12836 hr = pImport->GetParentToken(*pToken, &mdEnclosingType);
12837 _ASSERTE(!FAILED(hr));
12838
12839 if (!IsNilToken(mdEnclosingType))
12840 {
12841 _ASSERT(TypeFromToken(mdEnclosingType) == mdtTypeDef);
12842 TokenDefinitionHelper(pModuleContext, pReferencedModule, index, &mdEnclosingType);
12843 }
12844 _ASSERT(TypeFromToken(mdEnclosingType) == ibcExternalType);
12845
12846 //
12847 // Compute the method name and signature
12848 //
12849 PCCOR_SIGNATURE pSig = NULL;
12850 DWORD cbSig = 0;
12851 hr = pImport->GetNameAndSigOfMethodDef(*pToken, &pSig, &cbSig, &szName);
12852 _ASSERTE(hr == S_OK);
12853
12854 //
12855 // Transform signature into ibc external signature token
12856 //
12857 idExternalSignature idSignature = idExternalSignatureNil;
12858 if (pSig != NULL)
12859 {
12860 const ExternalSignatureBlobEntry * pSignatureEntry;
12861 pSignatureEntry = ExternalSignatureBlobEntry::FindOrAdd(pReferencingModule, cbSig, pSig);
12862 if (pSignatureEntry != NULL)
12863 {
12864 idSignature = pSignatureEntry->token();
12865 }
12866 }
12867 _ASSERTE(TypeFromToken(idSignature) == ibcExternalSignature);
12868
12869 //
12870 // Transform method name into ibc external method token
12871 //
12872 idExternalMethod idMethod = idExternalMethodNil;
12873 _ASSERTE(szName != NULL);
12874 const ExternalMethodBlobEntry * pMethodEntry = NULL;
12875 pMethodEntry = ExternalMethodBlobEntry::FindOrAdd(pReferencingModule,
12876 mdEnclosingType,
12877 idSignature,
12878 szName);
12879 if (pMethodEntry != NULL)
12880 {
12881 idMethod = pMethodEntry->token();
12882 }
12883 _ASSERTE(TypeFromToken(idMethod) == ibcExternalMethod);
12884
12885 *pToken = idMethod; // Remap pToken to our idMethodSpec token
12886 }
12887 else
12888 {
12889 _ASSERTE(!"Unexpected token type");
12890 }
12891}
12892
12893idTypeSpec Module::LogInstantiatedType(TypeHandle typeHnd, ULONG flagNum)
12894{
12895 CONTRACT(idTypeSpec)
12896 {
12897 NOTHROW;
12898 GC_NOTRIGGER;
12899 MODE_ANY;
12900 PRECONDITION(g_IBCLogger.InstrEnabled());
12901 PRECONDITION(!typeHnd.HasUnrestoredTypeKey());
12902 // We want to report the type only in its own loader module as a type's
12903 // MethodTable can only live in its own loader module.
12904 // We can relax this if we allow a (duplicate) MethodTable to live
12905 // in any module (which might be needed for ngen of generics)
12906#ifdef FEATURE_PREJIT
12907 // All callsites already do this...
12908 // PRECONDITION(this == GetPreferredZapModuleForTypeHandle(typeHnd));
12909#endif
12910 }
12911 CONTRACT_END;
12912
12913 idTypeSpec result = idTypeSpecNil;
12914
12915 if (m_nativeImageProfiling)
12916 {
12917 CONTRACT_VIOLATION(ThrowsViolation|FaultViolation|GCViolation);
12918
12919 SigBuilder sigBuilder;
12920
12921 ZapSig zapSig(this, this, ZapSig::IbcTokens,
12922 Module::EncodeModuleHelper, Module::TokenDefinitionHelper);
12923 BOOL fSuccess = zapSig.GetSignatureForTypeHandle(typeHnd, &sigBuilder);
12924
12925 // a return value of 0 indicates a failure to create the signature
12926 if (fSuccess)
12927 {
12928 DWORD cbSig;
12929 PCCOR_SIGNATURE pSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cbSig);
12930
12931 ULONG flag = (1 << flagNum);
12932 TypeSpecBlobEntry * pEntry = const_cast<TypeSpecBlobEntry *>(TypeSpecBlobEntry::FindOrAdd(this, cbSig, pSig));
12933 if (pEntry != NULL)
12934 {
12935 // Update the flags with any new bits
12936 pEntry->orFlag(flag);
12937 result = pEntry->token();
12938 }
12939 }
12940 }
12941 _ASSERTE(TypeFromToken(result) == ibcTypeSpec);
12942
12943 RETURN result;
12944}
12945
12946idMethodSpec Module::LogInstantiatedMethod(const MethodDesc * md, ULONG flagNum)
12947{
12948 CONTRACT(idMethodSpec)
12949 {
12950 NOTHROW;
12951 GC_NOTRIGGER;
12952 MODE_ANY;
12953 PRECONDITION( md != NULL );
12954 }
12955 CONTRACT_END;
12956
12957 idMethodSpec result = idMethodSpecNil;
12958
12959 if (m_nativeImageProfiling)
12960 {
12961 CONTRACT_VIOLATION(ThrowsViolation|FaultViolation|GCViolation);
12962
12963 // get data
12964 SigBuilder sigBuilder;
12965
12966 BOOL fSuccess;
12967 fSuccess = ZapSig::EncodeMethod(const_cast<MethodDesc *>(md), this, &sigBuilder,
12968 (LPVOID) this,
12969 (ENCODEMODULE_CALLBACK) Module::EncodeModuleHelper,
12970 (DEFINETOKEN_CALLBACK) Module::TokenDefinitionHelper);
12971
12972 if (fSuccess)
12973 {
12974 DWORD dataSize;
12975 BYTE * pBlob = (BYTE *)sigBuilder.GetSignature(&dataSize);
12976
12977 ULONG flag = (1 << flagNum);
12978 MethodSpecBlobEntry * pEntry = const_cast<MethodSpecBlobEntry *>(MethodSpecBlobEntry::FindOrAdd(this, dataSize, pBlob));
12979 if (pEntry != NULL)
12980 {
12981 // Update the flags with any new bits
12982 pEntry->orFlag(flag);
12983 result = pEntry->token();
12984 }
12985 }
12986 }
12987
12988 _ASSERTE(TypeFromToken(result) == ibcMethodSpec);
12989 RETURN result;
12990}
12991#endif // DACCESS_COMPILE
12992#endif //FEATURE_PREJIT
12993
12994#ifndef DACCESS_COMPILE
12995
12996#ifndef CROSSGEN_COMPILE
12997// ===========================================================================
12998// ReflectionModule
12999// ===========================================================================
13000
13001/* static */
13002ReflectionModule *ReflectionModule::Create(Assembly *pAssembly, PEFile *pFile, AllocMemTracker *pamTracker, LPCWSTR szName, BOOL fIsTransient)
13003{
13004 CONTRACT(ReflectionModule *)
13005 {
13006 STANDARD_VM_CHECK;
13007 PRECONDITION(CheckPointer(pAssembly));
13008 PRECONDITION(CheckPointer(pFile));
13009 PRECONDITION(pFile->IsDynamic());
13010 POSTCONDITION(CheckPointer(RETVAL));
13011 }
13012 CONTRACT_END;
13013
13014 // Hoist CONTRACT into separate routine because of EX incompatibility
13015
13016 mdFile token;
13017 _ASSERTE(pFile->IsAssembly());
13018 token = mdFileNil;
13019
13020 // Initial memory block for Modules must be zero-initialized (to make it harder
13021 // to introduce Destruct crashes arising from OOM's during initialization.)
13022
13023 void* pMemory = pamTracker->Track(pAssembly->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(ReflectionModule))));
13024 ReflectionModuleHolder pModule(new (pMemory) ReflectionModule(pAssembly, token, pFile));
13025
13026 pModule->DoInit(pamTracker, szName);
13027
13028 // Set this at module creation time. The m_fIsTransient field should never change during the lifetime of this ReflectionModule.
13029 pModule->SetIsTransient(fIsTransient ? true : false);
13030
13031 RETURN pModule.Extract();
13032}
13033
13034
13035// Module initialization occurs in two phases: the constructor phase and the Initialize phase.
13036//
13037// The constructor phase initializes just enough so that Destruct() can be safely called.
13038// It cannot throw or fail.
13039//
13040ReflectionModule::ReflectionModule(Assembly *pAssembly, mdFile token, PEFile *pFile)
13041 : Module(pAssembly, token, pFile)
13042{
13043 CONTRACTL
13044 {
13045 NOTHROW;
13046 GC_TRIGGERS;
13047 FORBID_FAULT;
13048 }
13049 CONTRACTL_END
13050
13051 m_pInMemoryWriter = NULL;
13052 m_sdataSection = NULL;
13053 m_pISymUnmanagedWriter = NULL;
13054 m_pCreatingAssembly = NULL;
13055 m_pCeeFileGen = NULL;
13056 m_pDynamicMetadata = NULL;
13057 m_fSuppressMetadataCapture = false;
13058 m_fIsTransient = false;
13059}
13060
13061HRESULT STDMETHODCALLTYPE CreateICeeGen(REFIID riid, void **pCeeGen);
13062
13063// Module initialization occurs in two phases: the constructor phase and the Initialize phase.
13064//
13065// The Initialize() phase completes the initialization after the constructor has run.
13066// It can throw exceptions but whether it throws or succeeds, it must leave the Module
13067// in a state where Destruct() can be safely called.
13068//
13069void ReflectionModule::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
13070{
13071 CONTRACTL
13072 {
13073 INSTANCE_CHECK;
13074 STANDARD_VM_CHECK;
13075 PRECONDITION(szName != NULL);
13076 }
13077 CONTRACTL_END;
13078
13079 Module::Initialize(pamTracker);
13080
13081 IfFailThrow(CreateICeeGen(IID_ICeeGen, (void **)&m_pCeeFileGen));
13082
13083 // Collectible modules should try to limit the growth of their associate IL section, as common scenarios for collectible
13084 // modules include single type modules
13085 if (IsCollectible())
13086 {
13087 ReleaseHolder<ICeeGenInternal> pCeeGenInternal(NULL);
13088 IfFailThrow(m_pCeeFileGen->QueryInterface(IID_ICeeGenInternal, (void **)&pCeeGenInternal));
13089 IfFailThrow(pCeeGenInternal->SetInitialGrowth(CEE_FILE_GEN_GROWTH_COLLECTIBLE));
13090 }
13091
13092 m_pInMemoryWriter = new RefClassWriter();
13093
13094 IfFailThrow(m_pInMemoryWriter->Init(GetCeeGen(), GetEmitter(), szName));
13095
13096 m_CrstLeafLock.Init(CrstLeafLock);
13097}
13098
13099void ReflectionModule::Destruct()
13100{
13101 CONTRACTL
13102 {
13103 NOTHROW;
13104 GC_TRIGGERS;
13105 MODE_PREEMPTIVE;
13106 }
13107 CONTRACTL_END;
13108
13109 delete m_pInMemoryWriter;
13110
13111 if (m_pISymUnmanagedWriter)
13112 {
13113 m_pISymUnmanagedWriter->Close();
13114 m_pISymUnmanagedWriter->Release();
13115 m_pISymUnmanagedWriter = NULL;
13116 }
13117
13118 if (m_pCeeFileGen)
13119 m_pCeeFileGen->Release();
13120
13121 Module::Destruct();
13122
13123 delete m_pDynamicMetadata;
13124 m_pDynamicMetadata = NULL;
13125
13126 m_CrstLeafLock.Destroy();
13127}
13128
13129// Returns true iff metadata capturing is suppressed.
13130//
13131// Notes:
13132// This is during the window after code:ReflectionModule.SuppressMetadataCapture and before
13133// code:ReflectionModule.ResumeMetadataCapture.
13134//
13135// If metadata updates are suppressed, then class-load notifications should be suppressed too.
13136bool ReflectionModule::IsMetadataCaptureSuppressed()
13137{
13138 return m_fSuppressMetadataCapture;
13139}
13140//
13141// Holder of changed value of MDUpdateMode via IMDInternalEmit::SetMDUpdateMode.
13142// Returns back the original value on release.
13143//
13144class MDUpdateModeHolder
13145{
13146public:
13147 MDUpdateModeHolder()
13148 {
13149 m_pInternalEmitter = NULL;
13150 m_OriginalMDUpdateMode = ULONG_MAX;
13151 }
13152 ~MDUpdateModeHolder()
13153 {
13154 WRAPPER_NO_CONTRACT;
13155 (void)Release();
13156 }
13157 HRESULT SetMDUpdateMode(IMetaDataEmit *pEmitter, ULONG updateMode)
13158 {
13159 LIMITED_METHOD_CONTRACT;
13160 HRESULT hr = S_OK;
13161
13162 _ASSERTE(updateMode != ULONG_MAX);
13163
13164 IfFailRet(pEmitter->QueryInterface(IID_IMDInternalEmit, (void **)&m_pInternalEmitter));
13165 _ASSERTE(m_pInternalEmitter != NULL);
13166
13167 IfFailRet(m_pInternalEmitter->SetMDUpdateMode(updateMode, &m_OriginalMDUpdateMode));
13168 _ASSERTE(m_OriginalMDUpdateMode != ULONG_MAX);
13169
13170 return hr;
13171 }
13172 HRESULT Release(ULONG expectedPreviousUpdateMode = ULONG_MAX)
13173 {
13174 HRESULT hr = S_OK;
13175
13176 if (m_OriginalMDUpdateMode != ULONG_MAX)
13177 {
13178 _ASSERTE(m_pInternalEmitter != NULL);
13179 ULONG previousUpdateMode;
13180 // Ignore the error when releasing
13181 hr = m_pInternalEmitter->SetMDUpdateMode(m_OriginalMDUpdateMode, &previousUpdateMode);
13182 m_OriginalMDUpdateMode = ULONG_MAX;
13183
13184 if (expectedPreviousUpdateMode != ULONG_MAX)
13185 {
13186 if ((hr == S_OK) && (expectedPreviousUpdateMode != previousUpdateMode))
13187 {
13188 hr = S_FALSE;
13189 }
13190 }
13191 }
13192 if (m_pInternalEmitter != NULL)
13193 {
13194 (void)m_pInternalEmitter->Release();
13195 m_pInternalEmitter = NULL;
13196 }
13197 return hr;
13198 }
13199 ULONG GetOriginalMDUpdateMode()
13200 {
13201 WRAPPER_NO_CONTRACT;
13202 _ASSERTE(m_OriginalMDUpdateMode != LONG_MAX);
13203 return m_OriginalMDUpdateMode;
13204 }
13205private:
13206 IMDInternalEmit *m_pInternalEmitter;
13207 ULONG m_OriginalMDUpdateMode;
13208};
13209
13210// Called in live paths to fetch metadata for dynamic modules. This makes the metadata available to the
13211// debugger from out-of-process.
13212//
13213// Notes:
13214// This buffer can be retrieved by the debugger via code:ReflectionModule.GetDynamicMetadataBuffer
13215//
13216// Threading:
13217// - Callers must ensure nobody else is adding to the metadata.
13218// - This function still takes its own locks to cooperate with the Debugger's out-of-process access.
13219// The debugger can slip this thread outside the locks to ensure the data is consistent.
13220//
13221// This does not raise a debug notification to invalidate the metadata. Reasoning is that this only
13222// happens in two cases:
13223// 1) manifest module is updated with the name of a new dynamic module.
13224// 2) on each class load, in which case we already send a debug event. In this case, we already send a
13225// class-load notification, so sending a separate "metadata-refresh" would make the eventing twice as
13226// chatty. Class-load events are high-volume and events are slow.
13227// Thus we can avoid the chatiness by ensuring the debugger knows that Class-load also means "refresh
13228// metadata".
13229//
13230void ReflectionModule::CaptureModuleMetaDataToMemory()
13231{
13232 CONTRACTL
13233 {
13234 THROWS;
13235 GC_TRIGGERS;
13236 }
13237 CONTRACTL_END;
13238
13239 // If we've suppresed metadata capture, then skip this. We'll recapture when we enable it. This allows
13240 // for batching up capture.
13241 // If a debugger is attached, then the CLR will still send ClassLoad notifications for dynamic modules,
13242 // which mean we still need to keep the metadata available. This is the same as Whidbey.
13243 // An alternative (and better) design would be to suppress ClassLoad notifications too, but then we'd
13244 // need some way of sending a "catchup" notification to the debugger after we re-enable notifications.
13245 if (IsMetadataCaptureSuppressed() && !CORDebuggerAttached())
13246 {
13247 return;
13248 }
13249
13250 // Do not release the emitter. This is a weak reference.
13251 IMetaDataEmit *pEmitter = this->GetEmitter();
13252 _ASSERTE(pEmitter != NULL);
13253
13254 HRESULT hr;
13255
13256 MDUpdateModeHolder hMDUpdateMode;
13257 IfFailThrow(hMDUpdateMode.SetMDUpdateMode(pEmitter, MDUpdateExtension));
13258 _ASSERTE(hMDUpdateMode.GetOriginalMDUpdateMode() == MDUpdateFull);
13259
13260 DWORD numBytes;
13261 hr = pEmitter->GetSaveSize(cssQuick, &numBytes);
13262 IfFailThrow(hr);
13263
13264 // Operate on local data, and then persist it into the module once we know it's valid.
13265 NewHolder<SBuffer> pBuffer(new SBuffer());
13266 _ASSERTE(pBuffer != NULL); // allocation would throw first
13267
13268 // ReflectionModule is still in a consistent state, and now we're just operating on local data to
13269 // assemble the new metadata buffer. If this fails, then worst case is that metadata does not include
13270 // recently generated classes.
13271
13272 // Caller ensures serialization that guarantees that the metadata doesn't grow underneath us.
13273 BYTE * pRawData = pBuffer->OpenRawBuffer(numBytes);
13274 hr = pEmitter->SaveToMemory(pRawData, numBytes);
13275 pBuffer->CloseRawBuffer();
13276
13277 IfFailThrow(hr);
13278
13279 // Now that we're successful, transfer ownership back into the module.
13280 {
13281 CrstHolder ch(&m_CrstLeafLock);
13282
13283 delete m_pDynamicMetadata;
13284
13285 m_pDynamicMetadata = pBuffer.Extract();
13286 }
13287
13288 //
13289
13290 hr = hMDUpdateMode.Release(MDUpdateExtension);
13291 // Will be S_FALSE if someone changed the MDUpdateMode (from MDUpdateExtension) meanwhile
13292 _ASSERTE(hr == S_OK);
13293}
13294
13295// Suppress the eager metadata serialization.
13296//
13297// Notes:
13298// This casues code:ReflectionModule.CaptureModuleMetaDataToMemory to be a nop.
13299// This is not nestable.
13300// This exists purely for performance reasons.
13301//
13302// Don't call this directly. Use a SuppressMetadataCaptureHolder holder to ensure it's
13303// balanced with code:ReflectionModule.ResumeMetadataCapture
13304//
13305// Types generating while eager metadata-capture is suppressed should not actually be executed until
13306// after metadata capture is restored.
13307void ReflectionModule::SuppressMetadataCapture()
13308{
13309 LIMITED_METHOD_CONTRACT;
13310 // If this fires, then you probably missed a call to ResumeMetadataCapture.
13311 CONSISTENCY_CHECK_MSG(!m_fSuppressMetadataCapture, "SuppressMetadataCapture is not nestable");
13312 m_fSuppressMetadataCapture = true;
13313}
13314
13315// Resumes eager metadata serialization.
13316//
13317// Notes:
13318// This casues code:ReflectionModule.CaptureModuleMetaDataToMemory to resume eagerly serializing metadata.
13319// This must be called after code:ReflectionModule.SuppressMetadataCapture.
13320//
13321void ReflectionModule::ResumeMetadataCapture()
13322{
13323 WRAPPER_NO_CONTRACT;
13324 _ASSERTE(m_fSuppressMetadataCapture);
13325 m_fSuppressMetadataCapture = false;
13326
13327 CaptureModuleMetaDataToMemory();
13328}
13329
13330void ReflectionModule::ReleaseILData()
13331{
13332 WRAPPER_NO_CONTRACT;
13333
13334 if (m_pISymUnmanagedWriter)
13335 {
13336 m_pISymUnmanagedWriter->Release();
13337 m_pISymUnmanagedWriter = NULL;
13338 }
13339
13340 Module::ReleaseILData();
13341}
13342#endif // !CROSSGEN_COMPILE
13343
13344#endif // !DACCESS_COMPILE
13345
13346#ifdef DACCESS_COMPILE
13347// Accessor to expose m_pDynamicMetadata to debugger.
13348//
13349// Returns:
13350// Pointer to SBuffer containing metadata buffer. May be null.
13351//
13352// Notes:
13353// Only used by the debugger, so only accessible via DAC.
13354// The buffer is updated via code:ReflectionModule.CaptureModuleMetaDataToMemory
13355PTR_SBuffer ReflectionModule::GetDynamicMetadataBuffer() const
13356{
13357 SUPPORTS_DAC;
13358
13359 // If we ask for metadata, but have been suppressing capture, then we're out of date.
13360 // However, the debugger may be debugging already baked types in the module and so may need the metadata
13361 // for that. So we return what we do have.
13362 //
13363 // Debugger will get the next metadata update:
13364 // 1) with the next load class
13365 // 2) or if this is right after the last class, see code:ReflectionModule.CaptureModuleMetaDataToMemory
13366
13367 return m_pDynamicMetadata;
13368}
13369#endif
13370
13371TADDR ReflectionModule::GetIL(RVA il) // virtual
13372{
13373#ifndef DACCESS_COMPILE
13374 WRAPPER_NO_CONTRACT;
13375
13376 BYTE* pByte = NULL;
13377 m_pCeeFileGen->GetMethodBuffer(il, &pByte);
13378 return TADDR(pByte);
13379#else // DACCESS_COMPILE
13380 SUPPORTS_DAC;
13381 DacNotImpl();
13382 return NULL;
13383#endif // DACCESS_COMPILE
13384}
13385
13386PTR_VOID ReflectionModule::GetRvaField(RVA field, BOOL fZapped) // virtual
13387{
13388 _ASSERTE(!fZapped);
13389#ifndef DACCESS_COMPILE
13390 WRAPPER_NO_CONTRACT;
13391 // This function should be call only if the target is a field or a field with RVA.
13392 PTR_BYTE pByte = NULL;
13393 m_pCeeFileGen->ComputePointer(m_sdataSection, field, &pByte);
13394 return dac_cast<PTR_VOID>(pByte);
13395#else // DACCESS_COMPILE
13396 SUPPORTS_DAC;
13397 DacNotImpl();
13398 return NULL;
13399#endif // DACCESS_COMPILE
13400}
13401
13402#ifndef DACCESS_COMPILE
13403
13404// ===========================================================================
13405// VASigCookies
13406// ===========================================================================
13407
13408//==========================================================================
13409// Enregisters a VASig.
13410//==========================================================================
13411VASigCookie *Module::GetVASigCookie(Signature vaSignature)
13412{
13413 CONTRACT(VASigCookie*)
13414 {
13415 INSTANCE_CHECK;
13416 THROWS;
13417 GC_TRIGGERS;
13418 MODE_ANY;
13419 POSTCONDITION(CheckPointer(RETVAL));
13420 INJECT_FAULT(COMPlusThrowOM());
13421 }
13422 CONTRACT_END;
13423
13424 VASigCookieBlock *pBlock;
13425 VASigCookie *pCookie;
13426
13427 pCookie = NULL;
13428
13429 // First, see if we already enregistered this sig.
13430 // Note that we're outside the lock here, so be a bit careful with our logic
13431 for (pBlock = m_pVASigCookieBlock; pBlock != NULL; pBlock = pBlock->m_Next)
13432 {
13433 for (UINT i = 0; i < pBlock->m_numcookies; i++)
13434 {
13435 if (pBlock->m_cookies[i].signature.GetRawSig() == vaSignature.GetRawSig())
13436 {
13437 pCookie = &(pBlock->m_cookies[i]);
13438 break;
13439 }
13440 }
13441 }
13442
13443 if (!pCookie)
13444 {
13445 // If not, time to make a new one.
13446
13447 // Compute the size of args first, outside of the lock.
13448
13449 // @TODO GENERICS: We may be calling a varargs method from a
13450 // generic type/method. Using an empty context will make such a
13451 // case cause an unexpected exception. To make this work,
13452 // we need to create a specialized signature for every instantiation
13453 SigTypeContext typeContext;
13454
13455 MetaSig metasig(vaSignature, this, &typeContext);
13456 ArgIterator argit(&metasig);
13457
13458 // Upper estimate of the vararg size
13459 DWORD sizeOfArgs = argit.SizeOfArgStack();
13460
13461 // enable gc before taking lock
13462 {
13463 CrstHolder ch(&m_Crst);
13464
13465 // Note that we were possibly racing to create the cookie, and another thread
13466 // may have already created it. We could put another check
13467 // here, but it's probably not worth the effort, so we'll just take an
13468 // occasional duplicate cookie instead.
13469
13470 // Is the first block in the list full?
13471 if (m_pVASigCookieBlock && m_pVASigCookieBlock->m_numcookies
13472 < VASigCookieBlock::kVASigCookieBlockSize)
13473 {
13474 // Nope, reserve a new slot in the existing block.
13475 pCookie = &(m_pVASigCookieBlock->m_cookies[m_pVASigCookieBlock->m_numcookies]);
13476 }
13477 else
13478 {
13479 // Yes, create a new block.
13480 VASigCookieBlock *pNewBlock = new VASigCookieBlock();
13481
13482 pNewBlock->m_Next = m_pVASigCookieBlock;
13483 pNewBlock->m_numcookies = 0;
13484 m_pVASigCookieBlock = pNewBlock;
13485 pCookie = &(pNewBlock->m_cookies[0]);
13486 }
13487
13488 // Now, fill in the new cookie (assuming we had enough memory to create one.)
13489 pCookie->pModule = this;
13490 pCookie->pNDirectILStub = NULL;
13491 pCookie->sizeOfArgs = sizeOfArgs;
13492 pCookie->signature = vaSignature;
13493
13494 // Finally, now that it's safe for asynchronous readers to see it,
13495 // update the count.
13496 m_pVASigCookieBlock->m_numcookies++;
13497 }
13498 }
13499
13500 RETURN pCookie;
13501}
13502
13503// ===========================================================================
13504// LookupMap
13505// ===========================================================================
13506#ifdef FEATURE_NATIVE_IMAGE_GENERATION
13507
13508int __cdecl LookupMapBase::HotItem::Cmp(const void* a_, const void* b_)
13509{
13510 LIMITED_METHOD_CONTRACT;
13511 const HotItem *a = (const HotItem *)a_;
13512 const HotItem *b = (const HotItem *)b_;
13513
13514 if (a->rid < b->rid)
13515 return -1;
13516 else if (a->rid > b->rid)
13517 return 1;
13518 else
13519 return 0;
13520}
13521
13522void LookupMapBase::CreateHotItemList(DataImage *image, CorProfileData *profileData, int table, BOOL fSkipNullEntries /*= FALSE*/)
13523{
13524 STANDARD_VM_CONTRACT;
13525 _ASSERTE(!MapIsCompressed());
13526
13527 if (profileData)
13528 {
13529 DWORD numInTokenList = profileData->GetHotTokens(table, 1<<RidMap, 1<<RidMap, NULL, 0);
13530
13531 if (numInTokenList > 0)
13532 {
13533 HotItem *itemList = (HotItem*)(void*)image->GetModule()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(HotItem)) * S_SIZE_T(numInTokenList));
13534 mdToken *tokenList = (mdToken*)(void*)image->GetModule()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(mdToken)) * S_SIZE_T(numInTokenList));
13535
13536 profileData->GetHotTokens(table, 1<<RidMap, 1<<RidMap, tokenList, numInTokenList);
13537 DWORD numItems = 0;
13538 for (DWORD i = 0; i < numInTokenList; i++)
13539 {
13540 DWORD rid = RidFromToken(tokenList[i]);
13541 TADDR value = RelativePointer<TADDR>::GetValueMaybeNullAtPtr(dac_cast<TADDR>(GetElementPtr(RidFromToken(tokenList[i]))));
13542 if (!fSkipNullEntries || value != NULL)
13543 {
13544 itemList[numItems].rid = rid;
13545 itemList[numItems].value = value;
13546 ++numItems;
13547 }
13548 }
13549
13550 if (numItems > 0)
13551 {
13552 qsort(itemList, // start of array
13553 numItems, // array size in elements
13554 sizeof(HotItem), // element size in bytes
13555 HotItem::Cmp); // comparer function
13556
13557 // Eliminate any duplicates in the list. Due to the qsort, they must be adjacent now.
13558 // We do this by walking the array and copying entries that are not duplicates of the previous one.
13559 // We can start the loop at +1, because 0 is not a duplicate of the previous entry, and does not
13560 // need to be copied either.
13561 DWORD j = 1;
13562 for (DWORD i = 1; i < numItems; i++)
13563 {
13564 if (itemList[i].rid != itemList[i-1].rid)
13565 {
13566 itemList[j].rid = itemList[i].rid;
13567 itemList[j].value = itemList[i].value;
13568 j++;
13569 }
13570 }
13571 _ASSERTE(j <= numItems);
13572 numItems = j;
13573
13574 // We have treated the values as normal TADDRs to let qsort move them around freely.
13575 // Fix them up to be the relative pointers now.
13576 for (DWORD ii = 0; ii < numItems; ii++)
13577 {
13578 if (itemList[ii].value != NULL)
13579 {
13580 RelativePointer<TADDR> *pRelPtr = (RelativePointer<TADDR> *)&itemList[ii].value;
13581 pRelPtr->SetValueMaybeNull(itemList[ii].value);
13582 }
13583 }
13584
13585 if (itemList != NULL)
13586 image->StoreStructure(itemList, sizeof(HotItem)*numItems,
13587 DataImage::ITEM_RID_MAP_HOT);
13588
13589 hotItemList = itemList;
13590 dwNumHotItems = numItems;
13591 }
13592 }
13593 }
13594}
13595
13596void LookupMapBase::Save(DataImage *image, DataImage::ItemKind kind, CorProfileData *profileData, int table, BOOL fCopyValues /*= FALSE*/)
13597{
13598 STANDARD_VM_CONTRACT;
13599
13600 // 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
13601 table >>= 24;
13602
13603 dwNumHotItems = 0;
13604 hotItemList = NULL;
13605
13606 if (table != 0)
13607 {
13608 // Because we use the same IBC encoding to record a touch to the m_GenericTypeDefToCanonMethodTableMap as
13609 // to the m_TypeDefToMethodTableMap, the hot items we get in both will be the union of the touches. This limitation
13610 // in the IBC infrastructure does not hurt us much because touching an entry for a generic type in one map often if
13611 // not always implies touching the corresponding entry in the other. But when saving the GENERICTYPEDEF_MAP it
13612 // does mean that we need to be prepared to see "hot" items whose data is NULL in this map (specifically, the non-
13613 // generic types). We don't want the hot list to be unnecessarily big with these entries, so tell CreateHotItemList to
13614 // skip them.
13615 BOOL fSkipNullEntries = (kind == DataImage::ITEM_GENERICTYPEDEF_MAP);
13616 CreateHotItemList(image, profileData, table, fSkipNullEntries);
13617 }
13618
13619 // Determine whether we want to compress this lookup map (to improve density of cold pages in the map on
13620 // hot item cache misses). We only enable this optimization for the TypeDefToMethodTable, the
13621 // GenericTypeDefToCanonMethodTable, and the MethodDefToDesc maps since (a) they're the largest and
13622 // as a result reap the most space savings and (b) these maps are fully populated in an ngen image and immutable
13623 // at runtime, something that's important when dealing with a compressed version of the table.
13624 if (kind == DataImage::ITEM_TYPEDEF_MAP || kind == DataImage::ITEM_GENERICTYPEDEF_MAP || kind == DataImage::ITEM_METHODDEF_MAP)
13625 {
13626 // The bulk of the compression work is done in the later stages of ngen image generation (since it
13627 // relies on knowing the final RVAs of each value stored in the table). So we create a specialzed
13628 // ZapNode that knows how to perform the compression for us.
13629 image->StoreCompressedLayoutMap(this, DataImage::ITEM_COMPRESSED_MAP);
13630
13631 // We need to know we decided to compress during the Fixup stage but the table kind is not available
13632 // there. So we use the cIndexEntryBits field as a flag (this will be initialized to zero and is only
13633 // set to a meaningful value near the end of ngen image generation, during the compression of the
13634 // table itself).
13635 cIndexEntryBits = 1;
13636
13637 // The ZapNode we allocated above takes care of all the rest of the processing for this map, so we're
13638 // done here.
13639 return;
13640 }
13641
13642 SaveUncompressedMap(image, kind, fCopyValues);
13643}
13644
13645void LookupMapBase::SaveUncompressedMap(DataImage *image, DataImage::ItemKind kind, BOOL fCopyValues /*= FALSE*/)
13646{
13647 STANDARD_VM_CONTRACT;
13648
13649 // We should only be calling this once per map
13650 _ASSERTE(!image->IsStored(pTable));
13651
13652 //
13653 // We will only store one (big) node instead of the full list,
13654 // and make the one node large enough to fit all the RIDs
13655 //
13656
13657 ZapStoredStructure * pTableNode = image->StoreStructure(NULL, GetSize() * sizeof(TADDR), kind);
13658
13659 LookupMapBase *map = this;
13660 DWORD offsetIntoCombo = 0;
13661 while (map != NULL)
13662 {
13663 DWORD len = map->dwCount * sizeof(void*);
13664
13665 if (fCopyValues)
13666 image->CopyDataToOffset(pTableNode, offsetIntoCombo, map->pTable, len);
13667
13668 image->BindPointer(map->pTable,pTableNode,offsetIntoCombo);
13669 offsetIntoCombo += len;
13670 map = map->pNext;
13671 }
13672}
13673
13674void LookupMapBase::ConvertSavedMapToUncompressed(DataImage *image, DataImage::ItemKind kind)
13675{
13676 STANDARD_VM_CONTRACT;
13677
13678 // Check whether we decided to compress this map (see Save() above).
13679 if (cIndexEntryBits == 0)
13680 return;
13681
13682 cIndexEntryBits = 0;
13683 SaveUncompressedMap(image, kind);
13684}
13685
13686void LookupMapBase::Fixup(DataImage *image, BOOL fFixupEntries /*=TRUE*/)
13687{
13688 STANDARD_VM_CONTRACT;
13689
13690 if (hotItemList != NULL)
13691 image->FixupPointerField(this, offsetof(LookupMapBase, hotItemList));
13692
13693 // Find the biggest RID supported by the entire list of LookupMaps.
13694 // We will only store one LookupMap node instead of the full list,
13695 // and make it big enough to fit all RIDs.
13696 *(DWORD *)image->GetImagePointer(this, offsetof(LookupMapBase, dwCount)) = GetSize();
13697
13698 // Persist the supportedFlags that this particular instance was created with.
13699 *(TADDR *)image->GetImagePointer(this, offsetof(LookupMapBase, supportedFlags)) = supportedFlags;
13700
13701 image->ZeroPointerField(this, offsetof(LookupMapBase, pNext));
13702
13703 // Check whether we've decided to compress this map (see Save() above).
13704 if (cIndexEntryBits == 1)
13705 {
13706 // In the compressed case most of the Fixup logic is performed by the specialized ZapNode we allocated
13707 // during Save(). But we still have to record fixups for any hot items we've cached (these aren't
13708 // compressed).
13709 for (DWORD i = 0; i < dwNumHotItems; i++)
13710 {
13711 TADDR *pHotValueLoc = &hotItemList[i].value;
13712 TADDR pHotValue = RelativePointer<TADDR>::GetValueMaybeNullAtPtr((TADDR)pHotValueLoc);
13713 TADDR flags = pHotValue & supportedFlags;
13714 pHotValue -= flags;
13715
13716 if (image->IsStored((PVOID)pHotValue))
13717 {
13718 image->FixupField(hotItemList,
13719 (BYTE *)pHotValueLoc - (BYTE *)hotItemList,
13720 (PVOID)pHotValue, flags, IMAGE_REL_BASED_RelativePointer);
13721 }
13722 else
13723 {
13724 image->ZeroPointerField(hotItemList, (BYTE *)pHotValueLoc - (BYTE *)hotItemList);
13725 }
13726 }
13727
13728 // The ZapNode will handle everything else so we're done.
13729 return;
13730 }
13731
13732 // Note that the caller is responsible for calling FixupPointerField()
13733 // or zeroing out the contents of pTable as appropriate
13734 image->FixupPointerField(this, offsetof(LookupMapBase, pTable));
13735
13736 if (fFixupEntries)
13737 {
13738 LookupMap<PVOID>::Iterator iter((LookupMap<PVOID> *)this);
13739 DWORD rid = 0;
13740
13741 while (iter.Next())
13742 {
13743 TADDR flags;
13744 PVOID p = iter.GetElementAndFlags(&flags);
13745 PTR_TADDR hotItemValuePtr = FindHotItemValuePtr(rid);
13746
13747 if (image->IsStored(p))
13748 {
13749 image->FixupField(pTable, rid * sizeof(TADDR),
13750 p, flags, IMAGE_REL_BASED_RelativePointer);
13751
13752 // In case this item is also in the hot item subtable, fix it up there as well
13753 if (hotItemValuePtr != NULL)
13754 image->FixupField(hotItemList,
13755 (BYTE *)hotItemValuePtr - (BYTE *)hotItemList,
13756 p, flags, IMAGE_REL_BASED_RelativePointer);
13757 }
13758 else
13759 {
13760 image->ZeroPointerField(pTable, rid * sizeof(TADDR));
13761 // In case this item is also in the hot item subtable, zero it there as well
13762 if (hotItemValuePtr != NULL)
13763 image->ZeroPointerField(hotItemList,
13764 (BYTE *)hotItemValuePtr - (BYTE *)hotItemList);
13765 }
13766
13767 rid++;
13768 }
13769 }
13770}
13771#endif // FEATURE_NATIVE_IMAGE_GENERATION
13772
13773#endif // !DACCESS_COMPILE
13774
13775#ifdef DACCESS_COMPILE
13776
13777void
13778LookupMapBase::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
13779 bool enumThis)
13780{
13781 CONTRACTL
13782 {
13783 INSTANCE_CHECK;
13784 NOTHROW;
13785 GC_NOTRIGGER;
13786 MODE_ANY;
13787 FORBID_FAULT;
13788 SUPPORTS_DAC;
13789 }
13790 CONTRACTL_END;
13791
13792 if (enumThis)
13793 {
13794 DacEnumHostDPtrMem(this);
13795 }
13796 if (pTable.IsValid())
13797 {
13798#ifdef FEATURE_PREJIT
13799 if (MapIsCompressed())
13800 {
13801 // Compressed maps have tables whose size cannot be calculated cheaply. Plus they have an
13802 // additional index blob.
13803 DacEnumMemoryRegion(dac_cast<TADDR>(pTable),
13804 cbTable);
13805 DacEnumMemoryRegion(dac_cast<TADDR>(pIndex),
13806 cbIndex);
13807 }
13808 else
13809#endif // FEATURE_PREJIT
13810 DacEnumMemoryRegion(dac_cast<TADDR>(pTable),
13811 dwCount * sizeof(TADDR));
13812 }
13813#ifdef FEATURE_PREJIT
13814 if (dwNumHotItems && hotItemList.IsValid())
13815 {
13816 DacEnumMemoryRegion(dac_cast<TADDR>(hotItemList),
13817 dwNumHotItems * sizeof(HotItem));
13818 }
13819#endif // FEATURE_PREJIT
13820}
13821
13822
13823/* static */
13824void
13825LookupMapBase::ListEnumMemoryRegions(CLRDataEnumMemoryFlags flags)
13826{
13827 CONTRACTL
13828 {
13829 NOTHROW;
13830 GC_NOTRIGGER;
13831 MODE_ANY;
13832 FORBID_FAULT;
13833 SUPPORTS_DAC;
13834 }
13835 CONTRACTL_END;
13836
13837 LookupMapBase * headMap = this;
13838 bool enumHead = false;
13839 while (headMap)
13840 {
13841 headMap->EnumMemoryRegions(flags, enumHead);
13842
13843 if (!headMap->pNext.IsValid())
13844 {
13845 break;
13846 }
13847
13848 headMap = headMap->pNext;
13849 enumHead = true;
13850 }
13851}
13852
13853#endif // DACCESS_COMPILE
13854
13855
13856// Optimization intended for Module::EnsureActive only
13857#include <optsmallperfcritical.h>
13858
13859#ifndef DACCESS_COMPILE
13860VOID Module::EnsureActive()
13861{
13862 CONTRACTL
13863 {
13864 THROWS;
13865 GC_TRIGGERS;
13866 MODE_ANY;
13867 }
13868 CONTRACTL_END;
13869 GetDomainFile()->EnsureActive();
13870}
13871#endif // DACCESS_COMPILE
13872
13873#include <optdefault.h>
13874
13875
13876#ifndef DACCESS_COMPILE
13877
13878VOID Module::EnsureAllocated()
13879{
13880 CONTRACTL
13881 {
13882 THROWS;
13883 GC_TRIGGERS;
13884 MODE_ANY;
13885 }
13886 CONTRACTL_END;
13887
13888 GetDomainFile()->EnsureAllocated();
13889}
13890
13891VOID Module::EnsureLibraryLoaded()
13892{
13893 STANDARD_VM_CONTRACT;
13894 GetDomainFile()->EnsureLibraryLoaded();
13895}
13896#endif // !DACCESS_COMPILE
13897
13898CHECK Module::CheckActivated()
13899{
13900 CONTRACTL
13901 {
13902 NOTHROW;
13903 GC_NOTRIGGER;
13904 MODE_ANY;
13905 }
13906 CONTRACTL_END;
13907
13908#ifndef DACCESS_COMPILE
13909 DomainFile *pDomainFile = FindDomainFile(GetAppDomain());
13910 CHECK(pDomainFile != NULL);
13911 PREFIX_ASSUME(pDomainFile != NULL);
13912 CHECK(pDomainFile->CheckActivated());
13913#endif
13914 CHECK_OK;
13915}
13916
13917#ifdef DACCESS_COMPILE
13918
13919void
13920ModuleCtorInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
13921{
13922 SUPPORTS_DAC;
13923
13924 // This class is contained so do not enumerate 'this'.
13925 DacEnumMemoryRegion(dac_cast<TADDR>(ppMT), numElements *
13926 sizeof(RelativePointer<MethodTable *>));
13927 DacEnumMemoryRegion(dac_cast<TADDR>(cctorInfoHot), numElementsHot *
13928 sizeof(ClassCtorInfoEntry));
13929 DacEnumMemoryRegion(dac_cast<TADDR>(cctorInfoCold),
13930 (numElements - numElementsHot) *
13931 sizeof(ClassCtorInfoEntry));
13932 DacEnumMemoryRegion(dac_cast<TADDR>(hotHashOffsets), numHotHashes *
13933 sizeof(DWORD));
13934 DacEnumMemoryRegion(dac_cast<TADDR>(coldHashOffsets), numColdHashes *
13935 sizeof(DWORD));
13936}
13937
13938void Module::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
13939 bool enumThis)
13940{
13941 CONTRACTL
13942 {
13943 INSTANCE_CHECK;
13944 NOTHROW;
13945 GC_NOTRIGGER;
13946 MODE_ANY;
13947 FORBID_FAULT;
13948 SUPPORTS_DAC;
13949 }
13950 CONTRACTL_END;
13951
13952 if (enumThis)
13953 {
13954 DAC_ENUM_VTHIS();
13955 EMEM_OUT(("MEM: %p Module\n", dac_cast<TADDR>(this)));
13956 }
13957
13958 //Save module id data only if it a real pointer, not a tagged sugestion to use ModuleIndex.
13959 if (!Module::IsEncodedModuleIndex(GetModuleID()))
13960 {
13961 if (m_ModuleID.IsValid())
13962 {
13963 m_ModuleID->EnumMemoryRegions(flags);
13964 }
13965 }
13966
13967 // TODO: Enumerate DomainLocalModules? It's not clear if we need all AppDomains
13968 // in the multi-domain case (where m_ModuleID has it's low-bit set).
13969 if (m_file.IsValid())
13970 {
13971 m_file->EnumMemoryRegions(flags);
13972 }
13973 if (m_pAssembly.IsValid())
13974 {
13975 m_pAssembly->EnumMemoryRegions(flags);
13976 }
13977
13978 m_TypeRefToMethodTableMap.ListEnumMemoryRegions(flags);
13979 m_TypeDefToMethodTableMap.ListEnumMemoryRegions(flags);
13980
13981 if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
13982 {
13983 if (m_pAvailableClasses.IsValid())
13984 {
13985 m_pAvailableClasses->EnumMemoryRegions(flags);
13986 }
13987 if (m_pAvailableParamTypes.IsValid())
13988 {
13989 m_pAvailableParamTypes->EnumMemoryRegions(flags);
13990 }
13991 if (m_pInstMethodHashTable.IsValid())
13992 {
13993 m_pInstMethodHashTable->EnumMemoryRegions(flags);
13994 }
13995 if (m_pAvailableClassesCaseIns.IsValid())
13996 {
13997 m_pAvailableClassesCaseIns->EnumMemoryRegions(flags);
13998 }
13999#ifdef FEATURE_PREJIT
14000 if (m_pStubMethodHashTable.IsValid())
14001 {
14002 m_pStubMethodHashTable->EnumMemoryRegions(flags);
14003 }
14004#endif // FEATURE_PREJIT
14005 if (m_pBinder.IsValid())
14006 {
14007 m_pBinder->EnumMemoryRegions(flags);
14008 }
14009 m_ModuleCtorInfo.EnumMemoryRegions(flags);
14010
14011 // Save the LookupMap structures.
14012 m_MethodDefToDescMap.ListEnumMemoryRegions(flags);
14013 m_FieldDefToDescMap.ListEnumMemoryRegions(flags);
14014 m_pMemberRefToDescHashTable->EnumMemoryRegions(flags);
14015 m_GenericParamToDescMap.ListEnumMemoryRegions(flags);
14016 m_GenericTypeDefToCanonMethodTableMap.ListEnumMemoryRegions(flags);
14017 m_FileReferencesMap.ListEnumMemoryRegions(flags);
14018 m_ManifestModuleReferencesMap.ListEnumMemoryRegions(flags);
14019 m_MethodDefToPropertyInfoMap.ListEnumMemoryRegions(flags);
14020
14021 LookupMap<PTR_MethodTable>::Iterator typeDefIter(&m_TypeDefToMethodTableMap);
14022 while (typeDefIter.Next())
14023 {
14024 if (typeDefIter.GetElement())
14025 {
14026 typeDefIter.GetElement()->EnumMemoryRegions(flags);
14027 }
14028 }
14029
14030 LookupMap<PTR_TypeRef>::Iterator typeRefIter(&m_TypeRefToMethodTableMap);
14031 while (typeRefIter.Next())
14032 {
14033 if (typeRefIter.GetElement())
14034 {
14035 TypeHandle th = TypeHandle::FromTAddr(dac_cast<TADDR>(typeRefIter.GetElement()));
14036 th.EnumMemoryRegions(flags);
14037 }
14038 }
14039
14040 LookupMap<PTR_MethodDesc>::Iterator methodDefIter(&m_MethodDefToDescMap);
14041 while (methodDefIter.Next())
14042 {
14043 if (methodDefIter.GetElement())
14044 {
14045 methodDefIter.GetElement()->EnumMemoryRegions(flags);
14046 }
14047 }
14048
14049 LookupMap<PTR_FieldDesc>::Iterator fieldDefIter(&m_FieldDefToDescMap);
14050 while (fieldDefIter.Next())
14051 {
14052 if (fieldDefIter.GetElement())
14053 {
14054 fieldDefIter.GetElement()->EnumMemoryRegions(flags);
14055 }
14056 }
14057
14058 LookupMap<PTR_TypeVarTypeDesc>::Iterator genericParamIter(&m_GenericParamToDescMap);
14059 while (genericParamIter.Next())
14060 {
14061 if (genericParamIter.GetElement())
14062 {
14063 genericParamIter.GetElement()->EnumMemoryRegions(flags);
14064 }
14065 }
14066
14067 LookupMap<PTR_MethodTable>::Iterator genericTypeDefIter(&m_GenericTypeDefToCanonMethodTableMap);
14068 while (genericTypeDefIter.Next())
14069 {
14070 if (genericTypeDefIter.GetElement())
14071 {
14072 genericTypeDefIter.GetElement()->EnumMemoryRegions(flags);
14073 }
14074 }
14075
14076 } // !CLRDATA_ENUM_MEM_MINI && !CLRDATA_ENUM_MEM_TRIAGE
14077
14078
14079 LookupMap<PTR_Module>::Iterator fileRefIter(&m_FileReferencesMap);
14080 while (fileRefIter.Next())
14081 {
14082 if (fileRefIter.GetElement())
14083 {
14084 fileRefIter.GetElement()->EnumMemoryRegions(flags, true);
14085 }
14086 }
14087
14088 LookupMap<PTR_Module>::Iterator asmRefIter(&m_ManifestModuleReferencesMap);
14089 while (asmRefIter.Next())
14090 {
14091 if (asmRefIter.GetElement())
14092 {
14093 asmRefIter.GetElement()->GetAssembly()->EnumMemoryRegions(flags);
14094 }
14095 }
14096
14097 ECall::EnumFCallMethods();
14098}
14099
14100FieldDesc *Module::LookupFieldDef(mdFieldDef token)
14101{
14102 WRAPPER_NO_CONTRACT;
14103 _ASSERTE(TypeFromToken(token) == mdtFieldDef);
14104 g_IBCLogger.LogRidMapAccess( MakePair( this, token ) );
14105 return m_FieldDefToDescMap.GetElement(RidFromToken(token));
14106}
14107
14108#endif // DACCESS_COMPILE
14109
14110
14111
14112
14113
14114//-------------------------------------------------------------------------------
14115// Make best-case effort to obtain an image name for use in an error message.
14116//
14117// This routine must expect to be called before the this object is fully loaded.
14118// It can return an empty if the name isn't available or the object isn't initialized
14119// enough to get a name, but it mustn't crash.
14120//-------------------------------------------------------------------------------
14121LPCWSTR Module::GetPathForErrorMessages()
14122{
14123 CONTRACTL
14124 {
14125 THROWS;
14126 GC_TRIGGERS;
14127 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
14128 }
14129 CONTRACTL_END
14130
14131 PEFile *pFile = GetFile();
14132
14133 if (pFile)
14134 {
14135 return pFile->GetPathForErrorMessages();
14136 }
14137 else
14138 {
14139 return W("");
14140 }
14141}
14142
14143#if defined(_DEBUG) && !defined(DACCESS_COMPILE) && !defined(CROSS_COMPILE)
14144void Module::ExpandAll()
14145{
14146 CONTRACTL
14147 {
14148 THROWS;
14149 GC_TRIGGERS;
14150 MODE_ANY;
14151 }
14152 CONTRACTL_END;
14153
14154 //This is called from inside EEStartupHelper, so it breaks the SO rules. However, this is debug only
14155 //(and only supported for limited jit testing), so it's ok here.
14156 CONTRACT_VIOLATION(SOToleranceViolation);
14157
14158 //If the EE isn't started yet, it's not safe to jit. We fail in COM jitting a p/invoke.
14159 if (!g_fEEStarted)
14160 return;
14161 struct Local
14162 {
14163 static void CompileMethodDesc(MethodDesc * pMD)
14164 {
14165 //Must have a method body
14166 if (pMD->HasILHeader()
14167 //Can't jit open instantiations
14168 && !pMD->IsGenericMethodDefinition()
14169 //These are the only methods we can jit
14170 && (pMD->IsStatic() || pMD->GetNumGenericMethodArgs() == 0
14171 || pMD->HasClassInstantiation())
14172 && (pMD->MayHaveNativeCode() && !pMD->IsFCallOrIntrinsic()))
14173 {
14174 pMD->PrepareInitialCode();
14175 }
14176 }
14177 static void CompileMethodsForMethodTable(MethodTable * pMT)
14178 {
14179 MethodTable::MethodIterator it(pMT);
14180 for (; it.IsValid(); it.Next())
14181 {
14182 MethodDesc * pMD = it.GetMethodDesc();
14183 CompileMethodDesc(pMD);
14184 }
14185 }
14186#if 0
14187 static void CompileMethodsForTypeDef(Module * pModule, mdTypeDef td)
14188 {
14189 TypeHandle th = ClassLoader::LoadTypeDefThrowing(pModule, td, ClassLoader::ThrowIfNotFound,
14190 ClassLoader::PermitUninstDefOrRef);
14191
14192 MethodTable * pMT = th.GetMethodTable();
14193 CompileMethodsForMethodTable(pMT);
14194 }
14195#endif
14196 static void CompileMethodsForTypeDefRefSpec(Module * pModule, mdToken tok)
14197 {
14198 TypeHandle th;
14199 HRESULT hr = S_OK;
14200
14201 EX_TRY
14202 {
14203 th = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(
14204 pModule,
14205 tok,
14206 NULL /*SigTypeContext*/);
14207 }
14208 EX_CATCH
14209 {
14210 hr = GET_EXCEPTION()->GetHR();
14211 }
14212 EX_END_CATCH(SwallowAllExceptions);
14213
14214 //Only do this for non-generic types and unshared generic types
14215 //(canonical generics and value type generic instantiations).
14216 if (SUCCEEDED(hr) && !th.IsTypeDesc()
14217 && th.AsMethodTable()->IsCanonicalMethodTable())
14218 {
14219 CompileMethodsForMethodTable(th.AsMethodTable());
14220 }
14221 }
14222 static void CompileMethodsForMethodDefRefSpec(Module * pModule, mdToken tok)
14223 {
14224 HRESULT hr = S_OK;
14225 EX_TRY
14226 {
14227 MethodDesc * pMD =
14228 MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(pModule, tok,
14229 /*SigTypeContext*/NULL,
14230 TRUE, TRUE);
14231 CompileMethodDesc(pMD);
14232 }
14233 EX_CATCH
14234 {
14235 hr = GET_EXCEPTION()->GetHR();
14236 //@telesto what should we do with this HR? the Silverlight code doesn't seem
14237 //to do anything...but that doesn't seem safe...
14238 }
14239 EX_END_CATCH(SwallowAllExceptions);
14240 }
14241 };
14242 //Jit all methods eagerly
14243
14244 IMDInternalImport * pMDI = GetMDImport();
14245 HENUMTypeDefInternalHolder hEnum(pMDI);
14246 mdTypeDef td;
14247 hEnum.EnumTypeDefInit();
14248
14249 //verify global methods
14250 if (GetGlobalMethodTable())
14251 {
14252 //jit everything in the MT.
14253 Local::CompileMethodsForTypeDefRefSpec(this, COR_GLOBAL_PARENT_TOKEN);
14254 }
14255 while (pMDI->EnumTypeDefNext(&hEnum, &td))
14256 {
14257 //jit everything
14258 Local::CompileMethodsForTypeDefRefSpec(this, td);
14259 }
14260
14261 //Get the type refs. They're always awesome.
14262 HENUMInternalHolder hEnumTypeRefs(pMDI);
14263 mdToken tr;
14264
14265 hEnumTypeRefs.EnumAllInit(mdtTypeRef);
14266 while (hEnumTypeRefs.EnumNext(&tr))
14267 {
14268 Local::CompileMethodsForTypeDefRefSpec(this, tr);
14269 }
14270
14271 //make sure to get the type specs
14272 HENUMInternalHolder hEnumTypeSpecs(pMDI);
14273 mdToken ts;
14274
14275 hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
14276 while (hEnumTypeSpecs.EnumNext(&ts))
14277 {
14278 Local::CompileMethodsForTypeDefRefSpec(this, ts);
14279 }
14280
14281
14282 //And now for the interesting generic methods
14283 HENUMInternalHolder hEnumMethodSpecs(pMDI);
14284 mdToken ms;
14285
14286 hEnumMethodSpecs.EnumAllInit(mdtMethodSpec);
14287 while (hEnumMethodSpecs.EnumNext(&ms))
14288 {
14289 Local::CompileMethodsForMethodDefRefSpec(this, ms);
14290 }
14291}
14292#endif //_DEBUG && !DACCESS_COMPILE && !CROSS_COMPILE
14293
14294//-------------------------------------------------------------------------------
14295
14296// Verify consistency of asmconstants.h
14297
14298// Wrap all C_ASSERT's in asmconstants.h with a class definition. Many of the
14299// fields referenced below are private, and this class is a friend of the
14300// enclosing type. (A C_ASSERT isn't a compiler intrinsic, just a magic
14301// typedef that produces a compiler error when the condition is false.)
14302#include "clrvarargs.h" /* for VARARG C_ASSERTs in asmconstants.h */
14303class CheckAsmOffsets
14304{
14305#ifndef CROSSBITNESS_COMPILE
14306#define ASMCONSTANTS_C_ASSERT(cond) static_assert(cond, #cond);
14307#include "asmconstants.h"
14308#endif // CROSSBITNESS_COMPILE
14309};
14310
14311//-------------------------------------------------------------------------------
14312
14313#ifndef DACCESS_COMPILE
14314
14315void Module::CreateAssemblyRefByNameTable(AllocMemTracker *pamTracker)
14316{
14317 CONTRACTL
14318 {
14319 THROWS;
14320 GC_NOTRIGGER;
14321 INJECT_FAULT(COMPlusThrowOM(););
14322 }
14323 CONTRACTL_END
14324
14325 LoaderHeap * pHeap = GetLoaderAllocator()->GetLowFrequencyHeap();
14326 IMDInternalImport * pImport = GetMDImport();
14327
14328 DWORD dwMaxRid = pImport->GetCountWithTokenKind(mdtAssemblyRef);
14329 if (dwMaxRid == 0)
14330 return;
14331
14332 S_SIZE_T dwAllocSize = S_SIZE_T(sizeof(LPWSTR)) * S_SIZE_T(dwMaxRid);
14333 m_AssemblyRefByNameTable = (LPCSTR *) pamTracker->Track( pHeap->AllocMem(dwAllocSize) );
14334
14335 DWORD dwCount = 0;
14336 for (DWORD rid=1; rid <= dwMaxRid; rid++)
14337 {
14338 mdAssemblyRef mdToken = TokenFromRid(rid,mdtAssemblyRef);
14339 LPCSTR szName;
14340 HRESULT hr;
14341
14342 hr = pImport->GetAssemblyRefProps(mdToken, NULL, NULL, &szName, NULL, NULL, NULL, NULL);
14343
14344 if (SUCCEEDED(hr))
14345 {
14346 m_AssemblyRefByNameTable[dwCount++] = szName;
14347 }
14348 }
14349 m_AssemblyRefByNameCount = dwCount;
14350}
14351
14352bool Module::HasReferenceByName(LPCUTF8 pModuleName)
14353{
14354 LIMITED_METHOD_CONTRACT;
14355
14356 for (DWORD i=0; i < m_AssemblyRefByNameCount; i++)
14357 {
14358 if (0 == strcmp(pModuleName, m_AssemblyRefByNameTable[i]))
14359 return true;
14360 }
14361
14362 return false;
14363}
14364#endif
14365
14366#ifdef _MSC_VER
14367#pragma warning(pop)
14368#endif // _MSC_VER: warning C4244
14369
14370#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
14371NOINLINE void NgenForceFailure_AV()
14372{
14373 LIMITED_METHOD_CONTRACT;
14374 static int* alwaysNull = 0;
14375 *alwaysNull = 0;
14376}
14377
14378NOINLINE void NgenForceFailure_TypeLoadException()
14379{
14380 WRAPPER_NO_CONTRACT;
14381 ::ThrowTypeLoadException("ForceIBC", "Failure", W("Assembly"), NULL, IDS_CLASSLOAD_BADFORMAT);
14382}
14383
14384void EEConfig::DebugCheckAndForceIBCFailure(BitForMask bitForMask)
14385{
14386 CONTRACTL
14387 {
14388 THROWS;
14389 GC_NOTRIGGER;
14390 MODE_ANY;
14391 }
14392 CONTRACTL_END;
14393 static DWORD s_ibcCheckCount = 0;
14394
14395 // Both of these must be set to non-zero values for us to force a failure
14396 //
14397 if ((NgenForceFailureCount() == 0) || (NgenForceFailureKind() == 0))
14398 return;
14399
14400 // The bitForMask value must also beset in the FailureMask
14401 //
14402 if ((((DWORD) bitForMask) & NgenForceFailureMask()) == 0)
14403 return;
14404
14405 s_ibcCheckCount++;
14406 if (s_ibcCheckCount < NgenForceFailureCount())
14407 return;
14408
14409 // We force one failure every NgenForceFailureCount()
14410 //
14411 s_ibcCheckCount = 0;
14412 switch (NgenForceFailureKind())
14413 {
14414 case 1:
14415 NgenForceFailure_TypeLoadException();
14416 break;
14417 case 2:
14418 NgenForceFailure_AV();
14419 break;
14420 }
14421}
14422#endif // defined(_DEBUG) && !defined(DACCESS_COMPILE)
14423
14424